@mistflow-ai/mcp 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{a as pt,c as ut,d as Pe}from"./chunk-C2TTUQ4F.js";import{b as Xa,e as Za}from"./chunk-5TUJQOFD.js";import{A as Fa,B as Ee,C as _t,D as Na,E as Ua,F as Ea,G as Ha,H as Ga,I as Wa,J as _a,K as et,L as Oa,M as ja,N as za,O as $a,P as gt,Q as Va,R as qa,S as Ka,T as Ja,U as Ya,W as Qa,b as Ta,c as Ca,d as ct,e as Pa,f as Gt,g as Ba,h as le,i as we,j as Ue,k as ve,l as Ia,m as ce,n as Aa,r as Da,s as Ma,t as ht,v as Ra,w as Be,x as La,y as Wt}from"./chunk-VQN2JJRZ.js";import{Server as Is}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as As}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Ds,ListToolsRequestSchema as Ms}from"@modelcontextprotocol/sdk/types.js";import{zodToJsonSchema as Rs}from"zod-to-json-schema";function c(r,e=!1){let t=r;try{let a=Ca();a&&(t=r+a)}catch{}return{content:[{type:"text",text:t}],isError:e}}function ge(r){return c(`This is not a Mistflow project (no mistflow.json found at ${r}).
1
+ import{a as ut,d as ht,e as Te}from"./chunk-ANYHR4WA.js";import{b as er,e as tr}from"./chunk-ZRRSZS7A.js";import{A as Na,B as Ue,C as zt,D as Fa,E as Ea,F as Ua,G as Ha,H as Ga,I as Wa,J as Oa,K as _a,L as ja,M as et,N as za,O as $a,P as Va,Q as qa,R as mt,S as Ka,T as Ja,U as Ya,V as Qa,W as Xa,Y as Za,b as Ca,c as Ta,d as pt,e as Pa,f as _t,g as Ba,h as se,i as we,j as Fe,k as Ee,l as Da,m as ce,n as Ia,r as Aa,s as Ma,t as gt,v as Ra,w as Pe,x as La,y as jt}from"./chunk-5IQGENNI.js";import{Server as Gs}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Ws}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Os,ListToolsRequestSchema as _s}from"@modelcontextprotocol/sdk/types.js";import{zodToJsonSchema as js}from"zod-to-json-schema";function c(r,e=!1){let t=r;try{let a=Ta();a&&(t=r+a)}catch{}return{content:[{type:"text",text:t}],isError:e}}function ge(r){return c(`This is not a Mistflow project (no mistflow.json found at ${r}).
2
2
 
3
3
  Mistflow creates new projects from scratch \u2014 it doesn't work inside existing codebases.
4
4
 
@@ -7,2017 +7,447 @@ To get started:
7
7
  2. Run mist_build (action: 'init') to create a new project in a subdirectory
8
8
  3. Run mist_build (action: 'implement') to build each step
9
9
 
10
- If you want to deploy an existing project, use your framework's deploy tools directly.`,!0)}async function Ie(r,e){try{let{getPage:t,takeScreenshot:a}=await import("./browser-manager-CZ7GKZMO.js"),n=await t();await n.goto(r,{waitUntil:"domcontentloaded",timeout:15e3}),await n.waitForLoadState("networkidle").catch(()=>{});let o=await a(n,!1);return{content:[{type:"text",text:e},{type:"image",data:o.toString("base64"),mimeType:"image/png"}]}}catch{return c(e)}}import{z as Ot}from"zod";import{platform as Di}from"os";import{execFile as er}from"child_process";var Mi=Ot.object({apiKey:Ot.string().optional().describe("API key (mist_...) for headless auth. Skips the device code flow entirely. Generate one at app.mistflow.ai/mcp-keys."),deviceCode:Ot.string().optional().describe("Resume polling for a pending device code. Returned by a previous mist_setup call with status 'pending'. Call mist_setup again with this value after ~15 seconds to check if the user approved.")});function Ri(r){return"error"in r}function Li(r){return new Promise(e=>setTimeout(e,r))}function Fi(r){return new Promise(e=>{let t=Di();t==="win32"?er("cmd.exe",["/c","start","",r],a=>{a&&console.error("Could not open browser:",a.message),e(!a)}):er(t==="darwin"?"open":"xdg-open",[r],n=>{n&&console.error("Could not open browser:",n.message),e(!n)}),setTimeout(()=>e(!1),5e3)})}var Ni={fetch:globalThis.fetch,openBrowser:Fi};async function Ui(r,e,t,a){let n=t;for(let o=0;o<e;o++){await Li(n);let i;try{let l=await a.fetch(`${Ue()}/auth/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:r})});if(!l.ok)continue;i=await l.json()}catch{continue}if(Ri(i))switch(i.error){case"authorization_pending":continue;case"slow_down":n+=5e3;continue;case"expired_token":return c("The sign-in link expired. Run mist_setup again to get a new code.",!0);case"access_denied":return c("Sign-in was cancelled. Run mist_setup again to try again.",!0);case"already_exchanged":return c("This sign-in link was already used. Run mist_setup again to get a new code.",!0)}return Gt({apiKey:i.api_key,apiKeyId:i.api_key_id,apiKeyName:i.api_key_name,orgId:i.org_id,orgSlug:i.org_slug,email:i.email}),c(`Connected to Mistflow as ${i.org_slug}. You are ready to build and deploy.`)}return null}async function Ei(r,e=Ni){let t=r;if(t?.apiKey)try{let o=await e.fetch(`${Ue()}/api/org`,{headers:{Authorization:`ApiKey ${t.apiKey}`}});if(!o.ok)return c("Invalid API key. Check the key and try again.",!0);let i=await o.json();return Gt({apiKey:t.apiKey,orgId:i.id,orgSlug:i.slug}),c(`Connected to Mistflow as ${i.slug} via API key. You are ready to build and deploy.`)}catch{return c("Cannot reach Mistflow servers. Check your internet connection.",!0)}if(t?.deviceCode){let o=await Ui(t.deviceCode,6,5e3,e);return o||c(JSON.stringify({status:"pending",deviceCode:t.deviceCode,instruction:"The user hasn't approved yet. Wait ~15 seconds and call mist_setup again with the same deviceCode."}))}let a;try{let o=await e.fetch(`${Ue()}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!o.ok)return c("Cannot reach Mistflow servers. Check your internet connection.",!0);a=await o.json()}catch{return c("Cannot reach Mistflow servers. Check your internet connection.",!0)}let n=`${a.verification_uri}?code=${a.user_code}`;console.error(`
10
+ If you want to deploy an existing project, use your framework's deploy tools directly.`,!0)}async function Be(r,e){try{let{getPage:t,takeScreenshot:a}=await import("./browser-manager-K5BT5YXO.js"),n=await t();await n.goto(r,{waitUntil:"domcontentloaded",timeout:15e3}),await n.waitForLoadState("networkidle").catch(()=>{});let o=await a(n,!1);return{content:[{type:"text",text:e},{type:"image",data:o.toString("base64"),mimeType:"image/png"}]}}catch{return c(e)}}import{z as $t}from"zod";import{platform as Fi}from"os";import{execFile as ar}from"child_process";var Ei=$t.object({apiKey:$t.string().optional().describe("API key (mist_...) for headless auth. Skips the device code flow entirely. Generate one at app.mistflow.ai/mcp-keys."),deviceCode:$t.string().optional().describe("Resume polling for a pending device code. Returned by a previous mist_setup call with status 'pending'. Call mist_setup again with this value after ~15 seconds to check if the user approved.")});function Ui(r){return"error"in r}function Hi(r){return new Promise(e=>setTimeout(e,r))}function Gi(r){return new Promise(e=>{let t=Fi();t==="win32"?ar("cmd.exe",["/c","start","",r],a=>{a&&console.error("Could not open browser:",a.message),e(!a)}):ar(t==="darwin"?"open":"xdg-open",[r],n=>{n&&console.error("Could not open browser:",n.message),e(!n)}),setTimeout(()=>e(!1),5e3)})}var Wi={fetch:globalThis.fetch,openBrowser:Gi};async function rr(r,e,t,a){let n=t;for(let o=0;o<e;o++){await Hi(n);let i;try{let s=await a.fetch(`${Fe()}/auth/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:r})});if(!s.ok)continue;i=await s.json()}catch{continue}if(Ui(i))switch(i.error){case"authorization_pending":continue;case"slow_down":n+=5e3;continue;case"expired_token":return c("The sign-in link expired. Run mist_setup again to get a new code.",!0);case"access_denied":return c("Sign-in was cancelled. Run mist_setup again to try again.",!0);case"already_exchanged":return c("This sign-in link was already used. Run mist_setup again to get a new code.",!0)}return _t({apiKey:i.api_key,apiKeyId:i.api_key_id,apiKeyName:i.api_key_name,orgId:i.org_id,orgSlug:i.org_slug,email:i.email}),c(`Connected to Mistflow as ${i.org_slug}. You are ready to build and deploy.`)}return null}async function Oi(r,e=Wi){let t=r;if(t?.apiKey)try{let i=await e.fetch(`${Fe()}/api/org`,{headers:{Authorization:`ApiKey ${t.apiKey}`}});if(!i.ok)return c("Invalid API key. Check the key and try again.",!0);let s=await i.json();return _t({apiKey:t.apiKey,orgId:s.id,orgSlug:s.slug}),c(`Connected to Mistflow as ${s.slug} via API key. You are ready to build and deploy.`)}catch{return c("Cannot reach Mistflow servers. Check your internet connection.",!0)}if(t?.deviceCode){let i=await rr(t.deviceCode,6,5e3,e);return i||c(JSON.stringify({status:"pending",deviceCode:t.deviceCode,instruction:"The user hasn't approved yet. Wait ~15 seconds and call mist_setup again with the same deviceCode."}))}let a;try{let i=await e.fetch(`${Fe()}/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!i.ok)return c("Cannot reach Mistflow servers. Check your internet connection.",!0);a=await i.json()}catch{return c("Cannot reach Mistflow servers. Check your internet connection.",!0)}let n=`${a.verification_uri}?code=${a.user_code}`;console.error(`
11
11
  Sign in at: ${n}
12
12
  Your code: ${a.user_code}
13
- `);try{await e.openBrowser(n)}catch{}return c(JSON.stringify({status:"pending",deviceCode:a.device_code,signInUrl:n,userCode:a.user_code,instruction:"A browser window should have opened for the user to sign in. Tell the user: 'I've opened your browser to sign in to Mistflow. Your verification code is "+a.user_code+". Approve the sign-in in your browser, then I'll continue.' Wait ~15 seconds, then call mist_setup again with deviceCode='"+a.device_code+"' to check if they approved."}))}var tr={name:"mist_setup",description:"Connect the user's Mistflow account. Call this ONLY when: (a) the user has literally never signed in, or (b) a previous tool call returned error code 'auth_missing' or 'auth_revoked'. DO NOT call this tool in response to 500 errors, 404 errors, network errors, or any generic failure \u2014 those are backend issues, not auth issues. Running mist_setup when not needed wastes the user's time and creates login fatigue. Once signed in, the MCP persists a long-lived API key and never asks again. Two-phase device code flow: (1) Call without deviceCode \u2014 opens browser, returns status 'pending' with deviceCode and userCode. Tell the user the verification code and that they need to approve in the browser. (2) Call again with deviceCode after ~15 seconds \u2014 polls for approval. Also accepts an apiKey for headless auth (skips device code entirely).",inputSchema:Mi,handler:r=>Ei(r)};import{z as te}from"zod";import{existsSync as tt,mkdirSync as Zt,readFileSync as gr,readdirSync as _i,statSync as Oi,unlinkSync as ji,writeFileSync as ea}from"fs";import{dirname as zi,join as me}from"path";import{homedir as He}from"os";import{createHash as $i,createHmac as mr,randomBytes as Vi,randomUUID as hr,timingSafeEqual as qi}from"crypto";var jt={1:{description:"Bold uppercase typography over a cinematic video background with custom SVG button.",tags:["video","bold","uppercase","cinematic","rubik"],theme:"dark",colors:["#21346e","#ffffff"],style:"Bold & Cinematic",designLanguage:{headingFont:"Rubik",bodyFont:"Rubik",layout:"centered",background:"video",animationLib:"css",navStyle:"none",effects:["background-video","custom-svg-button"]}},10:{description:"Left-aligned AI hero with serif accent, staggered word animations, and badge pill.",tags:["ai","video","serif-accent","animations","badge","left-aligned"],theme:"dark",colors:["#070612","#ffffff"],style:"Tech & Professional",designLanguage:{headingFont:"System Serif",bodyFont:"System Sans",layout:"left-aligned",background:"video-hls",animationLib:"framer-motion",navStyle:"none",effects:["split-text-animation","blur-in","badge-pill"]}},12:{description:"High-end logistics hero with red accent, clipped-corner buttons, and glassmorphism card.",tags:["logistics","red-accent","glassmorphism","video","compact"],theme:"dark",colors:["#000000","#EE3F2C","#ffffff"],style:"Bold & Industrial",designLanguage:{headingFont:"Rubik",bodyFont:"Rubik",layout:"left-aligned",background:"video",animationLib:"css",navStyle:"transparent",effects:["clipped-corner-buttons","glassmorphism-card"]}},14:{description:"Minimal video agency hero with floating white nav, serif italic headline, and play CTA.",tags:["agency","video","minimal","serif-italic","floating-nav"],theme:"dark",colors:["#ffffff","#222222"],style:"Minimal & Elegant",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Barlow",layout:"centered",background:"video",animationLib:"css",navStyle:"floating",effects:["floating-white-nav","serif-italic-headline"]}},16:{description:"Clean minimalist SaaS hero with editorial spacing, gradient overlay, and motion animations.",tags:["saas","minimal","editorial","gradient","clean","motion"],theme:"light",colors:["#ffffff","#000000"],style:"Clean & Editorial",designLanguage:{headingFont:"System Sans",bodyFont:"System Sans",layout:"centered",background:"video",animationLib:"framer-motion",navStyle:"none",effects:["gradient-overlay","editorial-spacing"]}},18:{description:"Fullscreen loading animation with rotating words, counter, and progress bar.",tags:["animation","loading","counter","motion","portfolio"],theme:"dark",colors:["#0a0a0a","#f5f5f5","#89AACC"],style:"Cinematic Loader",designLanguage:{headingFont:"Instrument Serif",bodyFont:"System Sans",layout:"full-width",background:"solid",animationLib:"framer-motion",navStyle:"none",effects:["rotating-words","counter-animation","progress-bar"]}},21:{description:"Full-screen video agency hero with custom typography and high-impact layout.",tags:["agency","video","bold","custom-typography","fullscreen"],theme:"dark",colors:["#000000","#ffffff"],style:"Bold & Impactful",designLanguage:{headingFont:"Custom",bodyFont:"Custom",layout:"full-width",background:"video",animationLib:"css",navStyle:"none",effects:["background-video","custom-typography"]}},3:{description:"Minimalist SaaS invoicing hero with trust badges and clean centered layout.",tags:["saas","invoicing","minimal","trust-badges","centered"],theme:"light",colors:["#ffffff","#000000"],style:"Clean & Trustworthy",designLanguage:{headingFont:"System Sans",bodyFont:"System Sans",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["trust-badges","clean-layout"]}},5:{description:"Dark glassmorphism agency page with purple/pink gradients, video background, and logo cloud.",tags:["glassmorphism","purple","gradient","video","logo-cloud","agency"],theme:"dark",colors:["#010101","#FA93FA","#C967E8","#983AD6"],style:"Glass & Gradient",designLanguage:{headingFont:"System Sans",bodyFont:"System Sans",layout:"centered",background:"video-hls",animationLib:"framer-motion",navStyle:"none",effects:["glassmorphism","purple-pink-gradient","infinite-logo-slider"]}},7:{description:"Dark tech hero with glass-effect navbar, gradient CTA, and background video.",tags:["tech","glass","gradient","navbar","video","dark"],theme:"dark",colors:["#000000","#ffffff"],style:"Dark & Techy",designLanguage:{headingFont:"System Sans",bodyFont:"System Sans",layout:"centered",background:"video-hls",animationLib:"framer-motion",navStyle:"glassmorphic",effects:["glass-navbar","gradient-cta","staggered-fade"]}},9:{description:"Web3 landing with pure black background, General Sans font, and crypto-style layout.",tags:["web3","crypto","black","general-sans","video"],theme:"dark",colors:["#000000","#ffffff"],style:"Web3 & Crypto",designLanguage:{headingFont:"General Sans",bodyFont:"General Sans",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["background-video","black-overlay"]}},"aethera-hero":{description:"Light cinematic hero with Instrument Serif, video fade loop, and elegant minimalism.",tags:["cinematic","light","elegant","serif","fade-loop","video"],theme:"light",colors:["#ffffff","#000000","#6F6F6F"],style:"Cinematic & Elegant",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["video-fade-loop","fade-rise-animation","gradient-overlay"]}},"bloom-ai-hero":{description:"Split-panel liquid glass layout with grayscale palette over looping video background.",tags:["liquid-glass","split-panel","grayscale","video","ai","floral"],theme:"dark",colors:["#000000","#ffffff"],style:"Liquid Glass & Artistic",designLanguage:{headingFont:"Poppins",bodyFont:"Source Serif 4",layout:"split-panel",background:"video",animationLib:"css",navStyle:"transparent",effects:["liquid-glass","split-panel-layout","grayscale-palette"]}},"datacore-booking-hero":{description:"Purple-accented booking SaaS hero with glassmorphism pill, serif headline, and video background.",tags:["saas","booking","purple","glassmorphism","serif","video"],theme:"dark",colors:["#7b39fc","#2b2344","#ffffff"],style:"Purple & Premium",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["glassmorphism-pill","purple-accent","mobile-menu"]}},"designpro-hero":{description:"Dark education platform hero with shiny text gradient animation and video background.",tags:["education","shiny-text","gradient","animation","video","dark"],theme:"dark",colors:["#000000","#64CEFB","#ffffff"],style:"Dark & Animated",designLanguage:{headingFont:"Inter",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"framer-motion",navStyle:"transparent",effects:["shiny-text-gradient","animated-shine-sweep"]}},"digitwist-hero":{description:"Dark AI builder hero with blue accent, gradient headline, blurred decorative orbs.",tags:["ai","builder","blue-accent","gradient","video","dark"],theme:"dark",colors:["#000000","#3054ff","#b4c0ff","#ffffff"],style:"Dark & Futuristic",designLanguage:{headingFont:"Instrument Sans",bodyFont:"Instrument Sans",layout:"centered",background:"video-hls",animationLib:"framer-motion",navStyle:"transparent",effects:["gradient-headline","blurred-orbs","blue-accent-cta"]}},"grow-ai-hero":{description:"Dark talent platform with massive gradient headline, liquid glass, and logo marquee.",tags:["talent","gradient-headline","liquid-glass","marquee","video"],theme:"dark",colors:["#050208","#E8E8E9","#3A7BBF"],style:"Dark & Bold",designLanguage:{headingFont:"General Sans",bodyFont:"Geist Sans",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["massive-gradient-headline","liquid-glass","logo-marquee","video-fade-loop"]}},"liquid-glass-agency":{description:"Full landing page with multiple sections, liquid glass effects, HLS video, and premium dark aesthetic.",tags:["agency","liquid-glass","full-page","hls-video","premium","dark"],theme:"dark",colors:["#000000","#ffffff"],style:"Premium & Immersive",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Barlow",layout:"centered",background:"video-hls",animationLib:"framer-motion",navStyle:"glassmorphic",effects:["liquid-glass","blur-text-reveal","multi-section","partner-bar"]}},"mindloop-landing":{description:"Dark monochrome newsletter landing with scroll-driven word reveal and multiple video sections.",tags:["newsletter","monochrome","scroll-reveal","video","full-page"],theme:"dark",colors:["#000000","#ffffff"],style:"Monochrome & Editorial",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video-hls",animationLib:"framer-motion",navStyle:"transparent",effects:["scroll-word-reveal","liquid-glass","email-form","multi-section"]}},"neuralyn-hero":{description:"Dark analytics SaaS hero with parallax dashboard preview and word-reveal testimonial.",tags:["analytics","saas","parallax","dashboard-preview","dark"],theme:"dark",colors:["#000000","#ffffff"],style:"Dark & Data-Driven",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"framer-motion",navStyle:"transparent",effects:["parallax-scroll","dashboard-preview","word-reveal-testimonial"]}},"nexora-hero":{description:"Light SaaS hero with coded dashboard preview, Instrument Serif accent, and video background.",tags:["saas","light","dashboard-preview","serif-accent","video","fintech"],theme:"light",colors:["#ffffff","#6366f1","#000000"],style:"Light & Professional",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"framer-motion",navStyle:"transparent",effects:["coded-dashboard-preview","serif-accent","staggered-fade"]}},"portfolio-cosmic-hero":{description:"Dark portfolio with loading screen, GSAP parallax gallery, bento grid, and HLS video.",tags:["portfolio","loading-screen","gsap","parallax","bento","video"],theme:"dark",colors:["#0a0a0a","#89AACC","#4E85BF"],style:"Cosmic & Creative",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video-hls",animationLib:"gsap",navStyle:"glassmorphic",effects:["loading-screen","parallax-gallery","bento-grid","gsap-marquee"]}},"power-ai-hero":{description:"Dark AI hero with massive gradient headline (indigo-purple-amber), liquid glass marquee.",tags:["ai","gradient-headline","liquid-glass","marquee","video"],theme:"dark",colors:["#050208","#6366f1","#a855f7","#fcd34d"],style:"Dark & Vibrant",designLanguage:{headingFont:"General Sans",bodyFont:"Geist Sans",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["massive-gradient-headline","liquid-glass","logo-marquee","video-fade-loop"]}},"price-calculator":{description:"Interactive pricing calculator with slider, radio buttons, and side-by-side cost comparison.",tags:["pricing","calculator","interactive","comparison","dark"],theme:"dark",colors:["#0D0D0D","#FF5656","#ffffff"],style:"Dark & Interactive",designLanguage:{headingFont:"System Sans",bodyFont:"System Sans",layout:"split-panel",background:"solid",animationLib:"none",navStyle:"none",effects:["interactive-slider","radio-buttons","cost-comparison"]}},"skyelite-hero":{description:"Light premium hero with overlapping typography, muted gray palette, and video background.",tags:["luxury","light","premium","overlapping-text","video","jets"],theme:"light",colors:["#f9fafb","#202A36","#ffffff"],style:"Light & Luxurious",designLanguage:{headingFont:"Inter",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["overlapping-typography","muted-gray-palette","mobile-menu"]}},"taskly-hero":{description:"White hero with liquid glass navbar, glassy orb video, and blue CTA accent.",tags:["saas","light","liquid-glass","orb","blue-accent","task-management"],theme:"light",colors:["#ffffff","#0084ff","#FF801E"],style:"Light & Playful",designLanguage:{headingFont:"Fustat",bodyFont:"Inter",layout:"split-panel",background:"video",animationLib:"css",navStyle:"glassmorphic",effects:["liquid-glass-navbar","glassy-orb","mix-blend-screen","logo-cloud"]}},"velorah-hero":{description:"Navy cinematic hero with Instrument Serif, liquid glass buttons, and fade-rise animations.",tags:["agency","cinematic","navy","serif","liquid-glass","video"],theme:"dark",colors:["#003366","#ffffff"],style:"Cinematic & Refined",designLanguage:{headingFont:"Instrument Serif",bodyFont:"Inter",layout:"centered",background:"video",animationLib:"css",navStyle:"transparent",effects:["liquid-glass-buttons","fade-rise-animation","navy-cinematic"]}}},ze=[{id:"1",title:"Midnight Bold",category:"Creative",prompt:`Create a responsive, full-screen Hero section using React and Tailwind CSS with the following specifications:
14
-
15
- 1. Layout & Positioning:
16
-
17
- Set the container to at least screen height (min-h-screen) with a dark blue fallback background (#21346e).
18
- Align the main content to the top of the page (not centered), adding significant top padding (approx pt-32 on mobile, pt-48 on desktop).
19
- Use a standard container with horizontal padding.
20
-
21
- 2. Background Video:
22
-
23
- Implement a full-screen, absolute-positioned background video.
24
- The video must be set to autoPlay, loop, muted, and playsInline.
25
- Use object-cover to ensure it fills the screen without distortion.
26
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260206_044704_dd33cb15-c23f-4cfc-aa09-a0465d4dcb54.mp4
27
-
28
- 3. Typography (Main Headline):
29
-
30
- Font Family: Rubik (sans-serif).
31
- Style: Bold, Uppercase, White text.
32
- Layout: Display the text on three separate lines:
33
- Line 1: "NEW ERA"
34
- Line 2: "OF DESIGN"
35
- Line 3: "STARTS NOW"
36
- Sizing: Large and responsive (text-6xl mobile, text-8xl tablet, text-[100px] desktop).
37
- Spacing: Very tight line height (0.98) and negative letter spacing (-2px to -4px).
38
-
39
- 4. Custom CTA Button:
40
-
41
- Place a button below the headline with a fixed size of 184px wide by 65px high.
42
- Interaction: Add a hover effect that slightly scales up (scale-105) and an active press effect (scale-95).
43
- Background: Instead of a standard CSS background, use an SVG element that fills the button container (absolute inset-0). Use a custom path for the shape filled with white.
44
- Text: Centered label "GET STARTED".
45
- Text Style: Rubik, Bold, Uppercase, 20px size, dark text color (#161a20).`},{id:"10",title:"Neural Edge",category:"AI / SaaS",prompt:`Create a full-screen hero section with the following exact specifications:
46
-
47
- Layout & Structure:
48
- - Full viewport height (h-screen), full width, relative positioning with overflow-hidden
49
- - Background color: #070612 (dark purple-black)
50
- - Content aligned to the left side, vertically centered
51
- - Max-width container (max-w-7xl) with horizontal padding (px-6 lg:px-12)
52
-
53
- Background Video:
54
- Video Source: HLS stream from https://stream.mux.com/s8pMcOvMQXc4GD6AX4e1o01xFogFxipmuKltNfSYza0200.m3u8
55
- - Autoplaying, looping, muted video positioned absolutely behind content
56
- - Video shifted 200px to the right (margin-left: 200px)
57
- - Video scaled to 1.2x with origin-left, object-cover, full height
58
- - Bottom fade gradient (h-40) from background color to transparent (z-10)
59
-
60
- Badge (top element):
61
- - Pill-shaped badge with rounded-full, border border-white/20, backdrop-blur-sm
62
- - Contains a Sparkles icon (lucide-react, w-3 h-3, text-white/80)
63
- - Text: "New AI Automation Ally" in text-sm font-medium text-white/80
64
- - Animated with blur-in effect (0.6s duration, no delay)
65
-
66
- Main Heading:
67
- - Three lines of text:
68
- - Line 1: "Unlock the Power of AI" (block display)
69
- - Line 2: "for Your" (inline)
70
- - Line 3: "Business." in serif italic font (inline)
71
- - Font sizes: text-4xl md:text-5xl lg:text-6xl
72
- - Font weight: font-medium
73
- - Line height: leading-tight lg:leading-[1.2]
74
- - Color: white (text-foreground)
75
- - Each word animates in with staggered split-text animation (0.08s delay between words, 0.6s duration, y: 40px -> 0, opacity: 0 -> 1)
76
-
77
- Subtitle:
78
- - Text: "Our cutting-edge AI platform automates, analyzes, and accelerates your workflows so you can focus on what really matters."
79
- - Styling: text-white/80, text-lg, font-normal, leading-relaxed, max-w-xl
80
- - Animated with blur-in effect (0.4s delay, 0.6s duration)
81
-
82
- CTA Buttons (bottom):
83
- - Two buttons side by side with gap-4, flex-wrap
84
- - Primary button "Book A Free Call":
85
- - Solid white background (bg-foreground), dark text (text-background)
86
- - Rounded-full, px-5 py-3
87
- - Includes right arrow icon (ArrowRight from lucide-react)
88
- - Links to /book-call
89
- - Secondary button "Learn now":
90
- - Semi-transparent background (bg-white/20), backdrop-blur-sm
91
- - Rounded-full, px-8 py-3
92
- - White text
93
- - Both buttons animated with blur-in effect (0.6s delay, 0.6s duration)
94
-
95
- Animations (using framer-motion):
96
- - BlurIn component: opacity 0->1, blur 10px->0, y 20->0
97
- - SplitText component: splits text by words, staggers each word's animation
98
-
99
- Z-index layering:
100
- - Video: z-0
101
- - Bottom gradient: z-10
102
- - Content: z-20
103
-
104
- Spacing:
105
- - 12-unit gap (gap-12) between badge/heading group and CTA buttons
106
- - 6-unit gap (gap-6) between badge and heading, and between heading and subtitle`},{id:"12",title:"Crimson Fleet",category:"Automotive",prompt:`Design Prompt: Targo Hero Section
107
-
108
- Brand Identity: Create a high-end, dark-themed hero section for a logistics brand called "targo". Use a color palette of deep black (#000000), a vibrant brand red (#EE3F2C), and crisp white for primary text. The typography should use the Rubik font family, with headlines in bold, uppercase, and slightly tight letter-spacing (approx. -4%).
109
-
110
- Layout & Positioning:
111
-
112
- Header: A clean top navigation bar with a white SVG logo (abstract symbol + "targo" wordmark) on the left. Include "Home", "About", and "Contact Us" links, plus a small red "Contact Us" button with clipped corners on the right.
113
-
114
- Main Hero: The headline "Swift and Simple Transport" and a "Get Started" button should be left-aligned and positioned in the upper-third of the section (aligned toward the top rather than centered).
115
-
116
- Bottom Widget: A "Book a Free Consultation" card positioned at the bottom-left.
13
+ `);try{await e.openBrowser(n)}catch{}let o=await rr(a.device_code,6,5e3,e);return o||c(JSON.stringify({status:"pending",deviceCode:a.device_code,signInUrl:n,userCode:a.user_code,instruction:"The user hasn't approved yet. Wait ~15 seconds, then call mist_setup again with deviceCode='"+a.device_code+"' to check if they approved."}))}var ir={name:"mist_setup",description:"Connect the user's Mistflow account. Call this ONLY when: (a) the user has literally never signed in, or (b) a previous tool call returned error code 'auth_missing' or 'auth_revoked'. DO NOT call this tool in response to 500 errors, 404 errors, network errors, or any generic failure \u2014 those are backend issues, not auth issues. Running mist_setup when not needed wastes the user's time and creates login fatigue. Once signed in, the MCP persists a long-lived API key and never asks again. Two-phase device code flow: (1) Call without deviceCode \u2014 opens browser, returns status 'pending' with deviceCode and userCode. Tell the user the verification code and that they need to approve in the browser. (2) Call again with deviceCode after ~15 seconds \u2014 polls for approval. Also accepts an apiKey for headless auth (skips device code entirely).",inputSchema:Ei,handler:r=>Oi(r)};import{z as X}from"zod";import{existsSync as tt,mkdirSync as ta,readFileSync as xr,readdirSync as Vi,statSync as qi,unlinkSync as Ki,writeFileSync as aa}from"fs";import{dirname as Ji,join as fe}from"path";import{homedir as Ge}from"os";import{createHash as Yi,createHmac as yr,randomBytes as Qi,randomUUID as br,timingSafeEqual as Xi}from"crypto";var W=`
14
+ IMPORTANT \u2014 Visual identity rules:
15
+ - Use ONLY the project's CSS custom properties for all colors: var(--color-background), var(--color-foreground), var(--color-primary), var(--color-muted), var(--color-muted-foreground), var(--color-border), var(--color-card).
16
+ - Use the project's configured fonts from layout.tsx (font-sans for body, font-heading if available). NEVER hardcode font names.
17
+ - Use the project's --radius-md for border radius. Do not hardcode px values for radius.
18
+ - For dark sections, use bg-foreground text-background (inverted). For light sections, use bg-background text-foreground.
19
+ - For accent elements (CTAs, badges, highlights), use bg-primary text-primary-foreground.
20
+ - For muted/secondary text, use text-muted-foreground.
21
+ - For borders, use border-border.
22
+ - NEVER use hardcoded hex values, named Tailwind colors (blue-500, purple-600, etc.), or raw RGB/HSL.
23
+ `,Vt={1:{description:"Bold uppercase typography with stacked 3-line headline and custom SVG button shape.",tags:["bold","uppercase","cinematic"],theme:"dark",colors:[],style:"Bold & Cinematic",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"mesh",animationLib:"css",navStyle:"none",effects:["mesh-gradient-background","custom-svg-button"]}},10:{description:"Left-aligned AI hero with serif accent, staggered word animations, and badge pill.",tags:["ai","serif-accent","animations","badge","left-aligned"],theme:"dark",colors:[],style:"Tech & Professional",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"left-aligned",background:"mesh",animationLib:"framer-motion",navStyle:"none",effects:["split-text-animation","blur-in","badge-pill"]}},12:{description:"High-end logistics hero with accent-colored buttons, clipped-corner shapes, and glassmorphism card.",tags:["logistics","accent-color","glassmorphism","compact"],theme:"dark",colors:[],style:"Bold & Industrial",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"left-aligned",background:"gradient",animationLib:"css",navStyle:"transparent",effects:["clipped-corner-buttons","glassmorphism-card"]}},14:{description:"Minimal agency hero with floating white nav, serif italic headline, and play CTA.",tags:["agency","minimal","serif-italic","floating-nav"],theme:"dark",colors:[],style:"Minimal & Elegant",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"css",navStyle:"floating",effects:["floating-white-nav","serif-italic-headline"]}},16:{description:"Clean minimalist SaaS hero with editorial spacing, gradient background, and motion animations.",tags:["saas","minimal","editorial","gradient","clean","motion"],theme:"light",colors:[],style:"Clean & Editorial",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"framer-motion",navStyle:"none",effects:["gradient-overlay","editorial-spacing"]}},18:{description:"Animated loading screen with rotating words, counter, and progress bar intro sequence.",tags:["animation","loading","intro","counter"],theme:"dark",colors:[],style:"Cinematic Intro",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"full-width",background:"solid",animationLib:"framer-motion",navStyle:"none",effects:["word-cycle","counter-animation","progress-bar"]}},21:{description:"Full-screen agency hero with transparent nav, badge pill, mixed serif/sans headline, and corner accents.",tags:["agency","bold","transparent-nav"],theme:"dark",colors:[],style:"Bold & Agency",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"mesh",animationLib:"css",navStyle:"transparent",effects:["corner-accents","badge-pill","mixed-serif-sans"]}},3:{description:"Dark SaaS hero with gradient CTA button, glow effects, and social proof row.",tags:["saas","gradient","glow"],theme:"dark",colors:[],style:"SaaS & Glow",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"framer-motion",navStyle:"sticky",effects:["gradient-cta","glow-effect","social-proof"]}},5:{description:"Dark glassmorphism hero with purple/pink gradient accents, announcement pill, and logo cloud.",tags:["glassmorphism","gradient","logo-cloud","agency"],theme:"dark",colors:[],style:"Glass & Gradient",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"animated-gradient",animationLib:"framer-motion",navStyle:"none",effects:["glassmorphism","gradient-text","logo-marquee"]}},7:{description:"Dark tech hero with blurred glass navbar, integration badges, and staggered entrance animations.",tags:["tech","glass","gradient","navbar"],theme:"dark",colors:[],style:"Tech & Glass",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"solid",animationLib:"framer-motion",navStyle:"glassmorphic",effects:["glass-navbar","integration-badges","staggered-entrance"]}},9:{description:"Web3 hero with gradient text heading, waitlist pill button, and layered glow effects.",tags:["web3","crypto","gradient-text"],theme:"dark",colors:[],style:"Web3 & Minimal",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"css",navStyle:"transparent",effects:["gradient-text","glow-pill-button"]}},"aethera-hero":{description:"Light cinematic hero with serif headline, gray accent words, fade-rise animation sequence.",tags:["cinematic","light","elegant","serif"],theme:"light",colors:[],style:"Cinematic & Light",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"css",navStyle:"transparent",effects:["fade-rise-sequence","muted-accent-words"]}},"bloom-ai-hero":{description:"Split-panel layout with liquid glass panels, serif accent text, and social/community cards.",tags:["glassmorphism","split-panel"],theme:"dark",colors:[],style:"Glass & Split",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"split-panel",background:"mesh",animationLib:"css",navStyle:"none",effects:["liquid-glass","split-layout","community-cards"]}},"datacore-booking-hero":{description:"Booking SaaS hero with glassmorphism tag pill, serif headline, and dual CTA buttons.",tags:["saas","booking","glassmorphism"],theme:"dark",colors:[],style:"SaaS & Booking",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"css",navStyle:"transparent",effects:["glassmorphism-pill","serif-headline"]}},"designpro-hero":{description:"Education platform hero with shiny gradient text animation and enrollment CTA.",tags:["education","animation","gradient-text"],theme:"dark",colors:[],style:"Education & Animated",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"solid",animationLib:"framer-motion",navStyle:"glassmorphic",effects:["shiny-text-animation","staggered-entrance"]}},"digitwist-hero":{description:"AI website builder hero with pre-headline serif, large gradient headline, and pill CTA with arrow.",tags:["ai","saas","gradient"],theme:"dark",colors:[],style:"AI & Builder",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"mesh",animationLib:"framer-motion",navStyle:"transparent",effects:["gradient-headline","pill-cta-with-arrow","decorative-gradients"]}},"grow-ai-hero":{description:"Dark hero with massive gradient headline, liquid glass nav, fade-loop background, and logo marquee.",tags:["talent","gradient","liquid-glass","marquee"],theme:"dark",colors:[],style:"Gradient & Marquee",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"animated-gradient",animationLib:"css",navStyle:"transparent",effects:["gradient-headline","liquid-glass","logo-marquee","fade-loop"]}},"liquid-glass-agency":{description:"Multi-section landing page with liquid glass effects, blur-text reveal, feature chess layout, and stats.",tags:["agency","liquid-glass","multi-section"],theme:"dark",colors:[],style:"Glass & Premium",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"solid",animationLib:"framer-motion",navStyle:"glassmorphic",effects:["liquid-glass","blur-text-reveal","feature-chess","stats-grid"]}},"mindloop-landing":{description:"Multi-section monochrome landing with scroll-driven word reveal, email subscription, and content cards.",tags:["newsletter","monochrome","multi-section","scroll-reveal"],theme:"dark",colors:[],style:"Monochrome & Editorial",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"solid",animationLib:"framer-motion",navStyle:"transparent",effects:["scroll-word-reveal","email-subscribe","content-cards"]}},"neuralyn-hero":{description:"SaaS landing with coded dashboard preview, parallax scroll, liquid glass pill, and testimonial section.",tags:["saas","dashboard-preview","parallax","liquid-glass"],theme:"dark",colors:[],style:"SaaS & Dashboard",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"solid",animationLib:"framer-motion",navStyle:"transparent",effects:["dashboard-preview","parallax-scroll","liquid-glass-pill","word-reveal-testimonial"]}},"nexora-hero":{description:"Light SaaS hero with coded dashboard preview, badge pill, play button, and frosted glass wrapper.",tags:["saas","light","dashboard-preview"],theme:"light",colors:[],style:"Light & SaaS",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"framer-motion",navStyle:"transparent",effects:["dashboard-preview","frosted-glass","badge-pill"]}},"portfolio-cosmic-hero":{description:"Portfolio with loading screen, bento project grid, parallax gallery, GSAP marquee, and stats.",tags:["portfolio","bento-grid","parallax","loading-screen"],theme:"dark",colors:[],style:"Portfolio & Cinematic",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"mesh",animationLib:"gsap",navStyle:"glassmorphic",effects:["loading-screen","bento-grid","parallax-gallery","gsap-marquee"]}},"power-ai-hero":{description:"Dark hero with massive gradient headline, liquid glass elements, and logo marquee.",tags:["ai","gradient","liquid-glass","marquee"],theme:"dark",colors:[],style:"AI & Power",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"animated-gradient",animationLib:"css",navStyle:"transparent",effects:["gradient-headline","liquid-glass","logo-marquee"]}},"price-calculator":{description:"Interactive pricing calculator with slider, radio options, checkboxes, and 3-tier comparison cards.",tags:["pricing","calculator","interactive"],theme:"dark",colors:[],style:"Calculator & Pricing",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"full-width",background:"solid",animationLib:"none",navStyle:"none",effects:["pricing-slider","comparison-cards","radio-checkboxes"]}},"skyelite-hero":{description:"Light premium hero with overlapping headline lines, uppercase label, and dual pill CTAs.",tags:["luxury","light","premium"],theme:"light",colors:[],style:"Premium & Light",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"gradient",animationLib:"css",navStyle:"transparent",effects:["overlapping-headlines","dual-pill-ctas"]}},"taskly-hero":{description:"Light hero with gradient glow background, liquid glass navbar, glassy orb visual, and social proof.",tags:["task-management","light","liquid-glass","glow"],theme:"light",colors:[],style:"Glass & Glow",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"split-panel",background:"gradient",animationLib:"css",navStyle:"glassmorphic",effects:["gradient-glow-blobs","liquid-glass-navbar","social-proof"]}},"velorah-hero":{description:"Cinematic hero with serif headline, muted accent words, liquid glass buttons, and fade-rise animations.",tags:["agency","cinematic","serif","liquid-glass"],theme:"dark",colors:[],style:"Cinematic & Serif",designLanguage:{headingFont:"project-configured",bodyFont:"project-configured",layout:"centered",background:"mesh",animationLib:"css",navStyle:"transparent",effects:["liquid-glass","fade-rise-sequence","muted-accent-words"]}}},ze=[{id:"1",title:"Midnight Bold",category:"Creative",prompt:`Create a responsive, full-screen hero section using React and Tailwind CSS.
117
24
 
118
- Key Design Elements:
119
-
120
- Video Background: An auto-looping, muted background video using URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260227_042027_c4b2f2ea-1c7c-4d6e-9e3d-81a78063703f.mp4. Ensure it has 100% opacity with no dark overlay.
121
-
122
- Clipped-Corner Buttons: All primary buttons must feature a custom geometric shape using CSS clip-path (a 10-12px diagonal cut on the top-right and bottom-left corners). Use the brand red for "Get Started" and solid white for "Book a Call".
123
-
124
- Liquid Glass Effect: The consultation card must use advanced glassmorphism: backdrop-filter: blur(40px) saturate(180%), a 1px white border with 12% opacity, a subtle diagonal white-to-transparent shine gradient across the surface, and an inner box-shadow for depth.
125
-
126
- Scaled Proportions: The layout should feel refined and compact. Headlines should be roughly 64px on desktop, and the overall spacing should avoid excessive padding to maintain a "scaled-down" professional look.
127
-
128
- Technical Details:
129
-
130
- Frameworks: React & Tailwind CSS.
131
-
132
- Icons: Use the Phone icon from lucide-react inside the consultation button.
133
-
134
- Responsiveness: Ensure the headline scales down to ~42px on mobile and the padding adjusts from 64px (desktop) to 32px (mobile).`},{id:"14",title:"Studio Blanc",category:"Agency",prompt:`Build a premium, high-end hero section for a video editing agency named 'Logoisum' with the following specifications:
135
-
136
- Background: Implement a full-screen, looping video background using this URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260228_065522_522e2295-ba22-457e-8fdb-fbcd68109c73.mp4. The video must be muted, autoplaying, and set to object-cover to fill the section without any color overlays.
137
-
138
- Navigation Bar: A floating white navigation bar with rounded-[16px] and a subtle shadow.
139
-
140
- Left: The agency logo.
141
-
142
- Center: A menu with links for 'About', 'Works', 'Services', and 'Testimonial' using 14px Barlow Medium font.
143
-
144
- Right: A dark (#222) primary CTA button labeled 'Book A Free Meeting' featuring a unique 45-degree arrow icon in a circular housing.
145
-
146
- Typography & Hero Content:
147
-
148
- Primary Headline: Centered layout. The first line 'Agency that makes your' should use a bold/medium Barlow font with tight tracking (tracking-[-4px]). The second line 'videos & reels viral' must use a large, elegant 'Instrument Serif' italic font (text-[84px]).
149
-
150
- Subtext: Below the headline, add the text 'Short-form video editing for Influencers, Creators and Brands' in Barlow Medium, 18px, centered.
151
-
152
- Secondary CTA: A large white pill-shaped button below the subtext labeled 'See Our Workreel' with a small play icon on the left.
153
-
154
- Overall Aesthetic: The design should be minimal, ultra-modern, and responsive. Ensure all text and buttons are layered on top of the video background with clear visibility and proper spacing (min-h-[90vh]).`},{id:"16",title:"Paper Minimal",category:"SaaS",prompt:`Create a minimalist, high-end React hero section using Tailwind CSS v4 and the Motion library.
155
-
156
- Layout & Spacing:
157
-
158
- The section should have a min-h-screen height and be centered.
159
-
160
- Apply a heavy top padding of exactly 290px to the main content container to create an editorial, spacious feel.
161
-
162
- The content container should have a max-w-[1200px] and a vertical gap of 32px between elements.
163
-
164
- Background:
165
-
166
- Use this background video: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260302_085640_276ea93b-d7da-4418-a09b-2aa5b490e838.mp4.
167
-
168
- Critical: The video must be vertically flipped using scaleY(-1) and set to object-cover.
169
-
170
- Apply a white gradient overlay on top of the video: from-[26.416%] from-[rgba(255,255,255,0)] to-[66.943%] to-white to seamlessly blend the video into the background.
171
-
172
- Typography (Geist & Instrument Serif):
173
-
174
- Main Heading: Use the 'Geist' font, medium weight, tracking -0.04em.
175
-
176
- Text Content: 'Simple [management] for your remote team'.
177
-
178
- Sizes: The main heading should be 80px (desktop), while the word 'management' should be in 'Instrument Serif' italic at 100px.
179
-
180
- Description: Geist font, 18px, 80% opacity, slate color (#373a46), max-width 554px.
181
-
182
- Interactive Components:
183
-
184
- Email Navbar: Create a rounded (40px) input container with bg-[#fcfcfc], a thin border, and a soft shadow (0px 10px 40px 5px rgba(194,194,194,0.25)).
185
-
186
- CTA Button: A dark, multi-layered gradient button ('Create Free Account') with a complex inner shadow for a high-gloss tactile effect: shadow-[inset_-4px_-6px_25px_0px_rgba(201,201,201,0.08),inset_4px_4px_10px_0px_rgba(29,29,29,0.24)].
187
-
188
- Social Proof: Below the input, add a '1,020+ Reviews' badge with a row of star/brand icons.
189
-
190
- Animations:
191
-
192
- Use Motion to staggered 'fade and slide up' the heading, description, and the email input block for a smooth entrance.
193
-
194
- Key Technical Specs for Implementation:
195
-
196
- Video Class: className="w-full h-full object-cover [transform:scaleY(-1)]"
197
-
198
- Gradient Class: className="absolute inset-0 bg-gradient-to-b from-[26.416%] from-[rgba(255,255,255,0)] to-[66.943%] to-white"
199
-
200
- Button Shadow: shadow-[inset_-4px_-6px_25px_0px_rgba(201,201,201,0.08),inset_4px_4px_10px_0px_rgba(29,29,29,0.24)]`},{id:"18",title:"Typewriter Intro",category:"Animation",prompt:`Build a fullscreen loading screen component in React (Next.js 14, TypeScript). Uses Framer Motion for animations. Here is the exact specification:
201
-
202
- Theme
203
-
204
- css
205
-
206
- --bg: #0a0a0a;
207
- --text: #f5f5f5;
208
- --muted: #888888;
209
- --stroke: #1f1f1f;
210
-
211
- Fonts: font-display \u2192 Instrument Serif (Google Fonts, italic, weight 400).
212
-
213
- Component: LoadingScreen
214
-
215
- Receives one prop: onComplete: () => void.
216
-
217
- Container: <motion.div> \u2014 fixed inset-0 z-[9999] bg-bg. Exit animation: exit={{ opacity: 0 }}, duration 0.6s, ease [0.4, 0, 0.2, 1]. Wrap in <AnimatePresence mode="wait"> from the parent.
218
-
219
- Element 1: "Portfolio" Label (Top-Left)
220
-
221
- <motion.div> \u2014 absolute top-8 left-8 md:top-12 md:left-12.
222
- Text: "Portfolio"
223
- Class: text-xs md:text-sm text-muted uppercase tracking-[0.3em]
224
- Entrance animation: initial={{ opacity: 0, y: -20 }}, animate={{ opacity: 1, y: 0 }}, duration 0.6s, delay 0.1s
225
-
226
- Element 2: Rotating Words (Center)
227
-
228
- absolute inset-0 flex items-center justify-center.
229
- Three words cycle in sequence: "Design" \u2192 "Create" \u2192 "Inspire". A new word appears every 900ms. The word index increments via setInterval and stops at the last word (doesn't loop).
230
-
231
- Each word is a <motion.span> inside <AnimatePresence mode="wait">, keyed by wordIndex:
232
- Class: text-4xl md:text-6xl lg:text-7xl font-display italic text-text/80
233
- initial={{ opacity: 0, y: 20 }}
234
- animate={{ opacity: 1, y: 0 }}
235
- exit={{ opacity: 0, y: -20 }}
236
- transition={{ duration: 0.4, ease: [0.4, 0, 0.2, 1] }}
237
-
238
- Element 3: Counter (Bottom-Right)
239
-
240
- <motion.div> \u2014 absolute bottom-8 right-8 md:bottom-12 md:right-12.
241
- A number that counts from 000 \u2192 100 over exactly 2.7 seconds using requestAnimationFrame. Each frame calculates elapsed / 2700 * 100. The number is displayed zero-padded to 3 digits (e.g. 007, 042, 100):
242
-
243
- {Math.round(progress).toString().padStart(3, '0')}
25
+ Layout: min-h-screen container. Content aligned to the top (not centered), with generous top padding (pt-32 mobile, pt-48 desktop).
244
26
 
245
- Class: text-6xl md:text-8xl lg:text-9xl font-display text-text tabular-nums
246
- Entrance animation: initial={{ opacity: 0, y: 20 }}, animate={{ opacity: 1, y: 0 }}, duration 0.6s, delay 0.1s
27
+ Background: Dark mesh gradient using the project's color tokens. Use 2-3 radial-gradient layers with the project's primary color at low opacity, blended over bg-background. Add subtle grain texture via a CSS noise filter.
247
28
 
248
- When progress reaches 100: Wait 400ms, then call onComplete(). Use a ref for onComplete to avoid stale closures.
29
+ Headline: Bold, uppercase, displayed across 3 separate lines matching the app's tagline. Responsive sizing (text-6xl mobile, text-8xl tablet, text-[100px] desktop). Very tight line-height (0.98) and negative letter-spacing (-2px to -4px).
249
30
 
250
- Element 4: Progress Bar (Bottom Edge)
31
+ CTA Button: Fixed 184px x 65px button below the headline. Use a custom SVG path shape as the button background (filled with the project's foreground color). Hover: scale-105. Active: scale-95. Label text in uppercase, bold.
32
+ ${W}`},{id:"10",title:"Neural Edge",category:"AI / SaaS",prompt:`Create a full-screen hero section with left-aligned content.
251
33
 
252
- absolute bottom-0 left-0 right-0. A 3px tall track:
253
- Track: h-[3px] bg-stroke/50 (full width)
254
- Fill: <motion.div> inside the track:
255
- h-full origin-left
256
- Background: linear-gradient(90deg, #89AACC 0%, #4E85BF 100%)
257
- Glow: boxShadow: "0 0 8px rgba(137, 170, 204, 0.35)"
258
- initial={{ scaleX: 0 }}
259
- animate={{ scaleX: progress / 100 }}
260
- transition={{ duration: 0.1, ease: "linear" }}
34
+ Layout: h-screen, content aligned left, vertically centered. Max-width container (max-w-7xl) with px-6 lg:px-12.
261
35
 
262
- Parent Wrapper Behavior
36
+ Background: Dark mesh gradient. Use 2 radial-gradient blobs (primary color at 10% opacity, offset to the right) over bg-background.
263
37
 
264
- The parent component (AppWrapper) controls visibility:
265
- State: isLoading starts true
266
- Renders <LoadingScreen onComplete={() => setIsLoading(false)} /> inside <AnimatePresence mode="wait"> only when isLoading is true
267
- Main page content sits below with: style={{ opacity: isLoading ? 0 : 1, transition: "opacity 0.5s ease-out" }}
268
- When the loader calls onComplete, it triggers: loader fades out (0.6s) \u2192 page fades in (0.5s)
38
+ Badge: Pill-shaped (rounded-full) with border border-foreground/20, backdrop-blur-sm. Contains a Sparkles icon (lucide-react) + descriptive text. Animated with blur-in effect (opacity 0 to 1, blur 10px to 0, 0.6s).
269
39
 
270
- Timing Summary
40
+ Headline: 3 lines of text. First two lines use the body font (font-medium). Third line uses serif italic for emphasis. text-4xl md:text-5xl lg:text-6xl. Each word animates with staggered split-text animation (0.08s delay between words, y: 40px to 0, opacity: 0 to 1) using framer-motion.
271
41
 
272
- 0.0s \u2014 Loader appears, "Portfolio" slides in, counter starts at 000
273
- 0.0s \u2014 "Design" appears
274
- 0.9s \u2014 "Create" replaces "Design"
275
- 1.8s \u2014 "Inspire" replaces "Create"
276
- 2.7s \u2014 Counter hits 100, progress bar full
277
- 3.1s \u2014 onComplete fires (400ms delay)
278
- 3.1s \u2014 Loader fades out (0.6s exit animation)
279
- 3.7s \u2014 Page content fades in (0.5s opacity transition)`},{id:"21",title:"Volt Agency",category:"Agency",prompt:`Project Requirements: Build a high-impact, full-screen React hero section using Tailwind CSS v4 and custom typography.
42
+ Subtitle: text-foreground/80, text-lg, max-w-xl. Animated with blur-in (0.4s delay).
280
43
 
281
- 1. Background & Layout:
44
+ CTA Buttons: Two buttons side by side. Primary: solid bg-foreground text-background, rounded-full, with ArrowRight icon. Secondary: semi-transparent bg-foreground/20, backdrop-blur-sm, rounded-full.
282
45
 
283
- Full-Screen Video: Implement a background video that covers the entire viewport (object-cover).
46
+ Z-index layering: Background z-0, gradient overlays z-10, content z-20.
47
+ ${W}`},{id:"12",title:"Crimson Fleet",category:"Automotive",prompt:`Create a high-end, dark-themed hero section for a logistics/automotive brand.
284
48
 
285
- Video Source: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260306_074215_04640ca7-042c-45d6-bb56-58b1e8a42489.mp4
49
+ Layout: Left-aligned content positioned in the upper third (not centered). Clean top navigation bar.
286
50
 
287
- Video Settings: Auto-play, loop, muted, and playsInline with no color overlays or filters.
51
+ Background: Dark gradient using bg-background with a subtle radial glow of the primary color at low opacity in the center.
288
52
 
289
- Content Spacing: The main content block should have 250px of bottom padding to create breathing room above the fold.
53
+ Navigation: Logo (abstract symbol + wordmark) on the left. Nav links center. Small accent CTA button with clipped corners on the right.
290
54
 
291
- 2. Typography & Colors:
55
+ Headline: Bold, uppercase, tight letter-spacing (-4%). Left-aligned.
292
56
 
293
- Primary Font: "Barlow" (sans-serif) for general UI and body text.
294
-
295
- Accent Font: "Instrument Serif" (italic) for poetic emphasis.
296
-
297
- Color Palette: Primary text is pure white (#FFFFFF) or white at 75% opacity. CTA buttons and badges use a neutral off-white (#f8f8f8).
298
-
299
- 3. Specific UI Elements:
300
-
301
- Transparent Navigation: A floating navbar with no background fill and no border strokes. All navigation links and the brand logo must be white.
302
-
303
- Featured Badge: A "Featured in Fortune" badge centered at the top. It features a "liquid glass" effect using a white/10 background with backdrop-blur-sm on the outer ring and white/90 with backdrop-blur-md on the inner pill.
304
-
305
- Dynamic Headline:
306
-
307
- Line 1: "Agency that makes your" (Barlow, font-light, text-white, 64px).
308
-
309
- Line 2: "videos & reels viral" (Instrument Serif, italic, text-white, 64px).
310
-
311
- Sub-headline: A max-width paragraph in Barlow font, white at 75% opacity, explaining the agency's value proposition.
312
-
313
- Button Styling: Rectangular buttons with a very sharp 2px border radius, #f8f8f8 background, and #171717 medium Barlow text.
314
-
315
- Corner Accents: Four 7px x 7px solid white squares positioned exactly at the four corners of the central hero content container.
316
-
317
- 4. Interactions & Animations:
318
-
319
- All buttons and interactive badges should have smooth transition-colors on hover.
320
-
321
- Buttons should shift from #f8f8f8 to pure white on hover.
322
-
323
- Navigation items should have a subtle white/10 background highlight on hover.`},{id:"3",title:"Crystal Clear",category:"SaaS",prompt:`Create a high-fidelity, dark-mode Hero section for a SaaS product called "ClearInvoice" using React and Tailwind CSS.
324
-
325
- Tech Stack:
326
- Framework: React (Vite)
327
- Styling: Tailwind CSS
328
- Animation: motion/react (Framer Motion)
329
- Icons: lucide-react
330
- Video: Native HTML5 <video> with hls.js for streaming (Do NOT use react-player).
331
-
332
- 1. Background Video (Crucial):
333
- Source: https://stream.mux.com/hUT6X11m1Vkw1QMxPOLgI761x2cfpi9bHFbi5cNg4014.m3u8
334
- Behavior: Autoplay, Loop, Muted, PlaysInline.
335
- Opacity: 100% (No dark overlay).
336
- Implementation: Create a memoized BackgroundVideo component using hls.js to handle the .m3u8 stream natively. Ensure it cleans up properly on unmount to prevent "AbortError".
337
- Z-Index: It must sit behind all content (-z-10).
338
-
339
- 2. Layout & Styling:
340
- Font Family:
341
- Headings: "Switzer" (Medium weight, tight tracking).
342
- Body: "Geist" (Clean, legible).
343
-
344
- Top Bar: A 5px high gradient bar at the very top: from-[#ccf] via-[#e7d04c] to-[#31fb78].
345
- Navbar:
346
- Logo on left.
347
- Links (Features, Pricing, Reviews) centered.
348
- Auth buttons (Sign In, Sign Up) on right.
349
- Mobile: Hamburger menu that opens a full-width dropdown.
350
-
351
- 3. Hero Content:
352
- Headline: "Manage your online store while save 3x operating cost" (Large text: text-6xl, tight leading).
353
- Subhead: "ClearInvoice takes the hassle out of billing with easy-to-use tools." (White/90).
354
- Animations: Use motion/react to stagger the entrance of the Text, Buttons, and Social Proof (Fade Up + Slide).
355
-
356
- 4. Button Styles (Exact Recreation):
357
- Primary Button:
358
- Background: Gradient from-[#FF3300] to-[#EE7926].
359
- Glow: An absolute positioned div behind the button with bg-orange-600 blur-lg opacity-20.
360
- Inner Stroke: A 1.5px border overlay (border-white/20) inside the button for a "glassy" edge.
361
- Hover: scale: 1.05, glow increases to opacity-60, and an Arrow icon slides in from the left.
362
-
363
- Secondary Button:
364
- Background: bg-white/90 backdrop blur.
365
- Inner Stroke: 1.5px border (border-black/5).
366
- Hover: scale: 1.05, background becomes solid white.
367
-
368
- 5. Social Proof:
369
- Row of 3 user avatars (overlapping borders).
370
- Text: "Trusted by 210k+ stores worldwide".`},{id:"5",title:"Aurora Glass",category:"Agency",prompt:`Build a production-ready, responsive landing page using React, Tailwind CSS v4, and Vite. The design should feature a high-end, dark-mode "glassmorphism" aesthetic with specific purple/pink gradients.
371
-
372
- 1. Tech Stack & Libraries:
373
- Use hls.js for video streaming.
374
- Use motion/react (formerly Framer Motion) for animations.
375
- Use react-use-measure for sizing logic.
376
- Use clsx and tailwind-merge for class management.
377
- Use lucide-react for standard icons (if needed), but I will provide custom SVG paths for specific UI elements.
378
-
379
- 2. Global Styling:
380
- Background: Dark/Black (#010101).
381
- Primary Gradient: A diagonal gradient used for accents: from-[#FA93FA] via-[#C967E8] to-[#983AD6].
382
- Typography: Modern sans-serif, center-aligned hero text.
383
-
384
- 3. Hero Section Components:
385
- Announcement Pill:
386
- A pill-shaped top badge.
387
- Background: Semi-transparent dark (bg-[rgba(28,27,36,0.15)]) with a subtle border.
388
- Icon: A "Zap" icon inside a gradient-filled box with a glow effect.
389
- Text: "Used by founders. Loved by devs." in light grey.
390
-
391
- Main Headline (H1):
392
- Large text (responsive sizing: 48px mobile to 80px desktop).
393
- Text: "Your Vision" on line 1, "Our Digital Reality." on line 2.
394
- Style: Text should have a gradient fill (White to Purple/Pink).
395
-
396
- Subheadline:
397
- Text: "We turn bold ideas into modern designs that don't just look amazing, they grow your business fast."
398
- Color: text-white/80.
399
-
400
- CTA Button:
401
- "Book a 15-min call" text.
402
- Rounded full button with a white background and black text.
403
- Includes a circle icon with an arrow inside, styled with the primary purple gradient.
404
- Outer border wrapper with a glass effect.
405
-
406
- 4. Hero Video Integration (Critical Details):
407
- Source: HLS Stream URL: https://customer-cbeadsgr09pnsezs.cloudflarestream.com/697945ca6b876878dba3b23fbd2f1561/manifest/video.m3u8
408
- Fallback: If HLS fails, fallback to this MP4: /_videos/v1/f0c78f536d5f21a047fb7792723a36f9d647daa1
409
- Implementation: Do NOT use react-player. Use a native <video> tag with a custom useEffect hook implementation of hls.js.
410
- Styling:
411
- Blend Mode: Use mix-blend-screen so the video black background blends into the page.
412
- Positioning: The video should be at the bottom of the hero. Apply a negative top margin (-mt-[150px]) so it overlaps behind the text.
413
- Z-Index: Ensure the text content is z-20 (above) and video is z-10 (below).
414
- Layout: The video must be 100% width (w-full), auto height, and stretch edge-to-edge without being cropped (do not use object-contain or fixed heights).
415
- Overlay: Add a gradient fade (from-[#010101] via-transparent to-[#010101]) over the video container.
416
-
417
- 5. Logo Cloud Section (Animated):
418
- Place this section immediately below the video.
419
- Background: Semi-transparent glass (bg-black/20 backdrop-blur-sm) with a top border (border-white/5).
420
- Layout:
421
- Desktop: "Powering the best teams" text on the left, separated by a vertical divider. Animated logo slider on the right.
422
- Mobile: Stacked vertically.
423
- Animation: Create an InfiniteSlider component using motion/react that scrolls logos horizontally forever.
424
- Logos: Use these SVG URLs (OpenAI, Nvidia, GitHub, etc.) and apply brightness-0 invert to make them white.
425
- https://html.tailus.io/blocks/customers/openai.svg
426
- https://html.tailus.io/blocks/customers/nvidia.svg
427
- (Include others similarly)
428
-
429
- Please assemble these into a cohesive Hero.tsx, App.tsx, and components/ui/infinite-slider.tsx structure.`},{id:"7",title:"Obsidian Tech",category:"SaaS",prompt:`Build a high-fidelity, dark-themed Hero Section using React, Tailwind CSS, and Framer Motion. The background should be solid black (#000000).
430
-
431
- 1. Structure & Layout:
432
-
433
- Navbar: Fixed at the top with a blurred glass effect.
434
-
435
- Logo: Text "Synapse" (font-medium, tracking-tight, white).
436
-
437
- Links: Features (active state with gradient border), Insights, About, Case Studies (strikethrough style), Contact.
57
+ Key Design Elements:
58
+ - Clipped-corner buttons: All primary CTAs use CSS clip-path with 10-12px diagonal cuts on top-right and bottom-left corners. Primary CTA uses bg-primary. Secondary uses bg-foreground.
59
+ - Glassmorphism consultation card: backdrop-filter blur(40px) saturate(180%), 1px border at foreground/12 opacity, subtle diagonal shine gradient, inner box-shadow for depth.
60
+ - Compact proportions: Headlines ~64px desktop, refined spacing, no excessive padding.
61
+ ${W}`},{id:"14",title:"Studio Blanc",category:"Agency",prompt:`Build a premium hero section for a creative agency.
438
62
 
439
- CTA: "Get Started for Free" (White/Gray gradient button).
63
+ Background: Subtle animated gradient using the project's primary and background colors. Gentle CSS animation cycling gradient position over 8s.
440
64
 
441
- Hero Content: Centered text container (z-10, relative).
65
+ Navigation: Floating white/light nav bar with rounded-[16px] and subtle shadow. Logo left, nav links center (14px medium weight), dark CTA button right with a unique 45-degree arrow icon in a circular housing.
442
66
 
443
- Badges: Row of 3 glass-effect badges "Integrated with" + Icon.
67
+ Headline: Centered. First line uses bold/medium body font with tight tracking (tracking-[-4px]). Second line uses a large serif italic style (text-[84px]). Mixed font pairing creates visual contrast.
444
68
 
445
- Headline: "Where Innovation Meets Execution" (Large ~80px font, tight tracking, fade-in animation).
69
+ Subtext: Body font, 18px, centered below headline.
446
70
 
447
- Subtext: 2-line description about testing and deployment.
71
+ Secondary CTA: Large pill-shaped button below subtext with a small play icon on the left.
448
72
 
449
- Buttons:
73
+ Overall: Minimal, ultra-modern, responsive. min-h-[90vh].
74
+ ${W}`},{id:"16",title:"Paper Minimal",category:"SaaS",prompt:`Create a minimalist, high-end hero section using Tailwind CSS and framer-motion.
450
75
 
451
- "Get Started for Free" (Solid Black background, White border).
76
+ Layout: min-h-screen, centered content. Heavy top padding (290px) for editorial, spacious feel. Content container max-w-[1200px] with 32px vertical gap.
452
77
 
453
- "Let's Get Connected" (Transparent glass style).
78
+ Background: Light gradient overlay. Use a subtle radial gradient from the primary color at 5% opacity, blending into bg-background. Clean, editorial feel.
454
79
 
455
- Logo Marquee: A static row of grayscale, 40% opacity logos (use placeholder SVGs) at the bottom.
80
+ Headline: Medium weight, tracking -0.04em. Main text is body font. One keyword rendered in serif italic at slightly larger size (100px vs 80px). Responsive.
456
81
 
457
- 2. Background Video (Crucial):
82
+ Description: 18px, 80% opacity, muted color, max-width 554px.
458
83
 
459
- Source: https://stream.mux.com/9JXDljEVWYwWu01PUkAemafDugK89o01BR6zqJ3aS9u00A.m3u8
84
+ Email Input: Rounded (40px) input container with subtle border and soft shadow. Contains a dark gradient CTA button with complex inner shadow for a tactile effect.
460
85
 
461
- Implementation: Create a memoized VideoPlayer component using hls.js to handle the .m3u8 stream. Ensure proper cleanup on unmount.
86
+ Social Proof: Below the input, a reviews badge with star icons.
462
87
 
463
- Styling: 100% Opacity (no dark overlays), playing in loop/muted/autoplay.
88
+ Animations: Staggered fade-and-slide-up using framer-motion for heading, description, and input block.
89
+ ${W}`},{id:"18",title:"Typewriter Intro",category:"Animation",prompt:`Build a fullscreen loading screen component in React with framer-motion.
464
90
 
465
- Positioning: The video container should have a height of 80vh and be positioned absolute bottom-[35vh], sitting effectively "floating" behind the text content but pushed up from the bottom edge.
91
+ Component receives onComplete: () => void prop. Wrap in AnimatePresence mode="wait" from the parent.
466
92
 
467
- 3. Animations:
93
+ Container: fixed inset-0 z-[9999] bg-background. Exit animation: opacity 0, duration 0.6s.
468
94
 
469
- Use motion/react to apply staggered fade-in-up animations to the badges, headline, subtitle, and buttons on load.`},{id:"9",title:"Chain Zero",category:"Web3",prompt:`Build a full-screen hero section for a Web3 landing page. Use the font "General Sans" (from Fontshare) throughout. The entire section has a pure black (#000000) background with a fullscreen looping background video (muted, autoplay, playsInline) using this URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260217_030345_246c0224-10a4-422c-b324-070b7c0eceda.mp4. The video is covered by a 50% black overlay (bg-black/50) for readability. All content sits on top of the video.
95
+ Element 1 - "Portfolio" Label (Top-Left): absolute top-8 left-8. text-xs text-muted-foreground uppercase tracking-[0.3em]. Animates y:-20 to 0, opacity 0 to 1.
470
96
 
471
- Navbar:
97
+ Element 2 - Rotating Words (Center): Three words cycle every 900ms (e.g. "Design", "Create", "Inspire"). AnimatePresence mode="wait", keyed by index. text-4xl md:text-6xl lg:text-7xl, serif italic style, text-foreground/80. Each word: initial y:20, exit y:-20.
472
98
 
473
- Horizontally spread across the top with 120px horizontal padding and 20px vertical padding.
99
+ Element 3 - Counter (Bottom-Right): Counts 000 to 100 over 2.7s using requestAnimationFrame. Zero-padded to 3 digits. text-6xl md:text-8xl lg:text-9xl, tabular-nums.
474
100
 
475
- Left side: a placeholder logo wordmark (use "LOGOIPSUM" or similar) in white, 187px wide and 25px tall, followed by 4 nav links spaced 30px apart: "Get Started", "Developers", "Features", "Resources". Each nav link is white, 14px, font-medium, with a small white 14px chevron-down arrow icon to the right (14px gap between label and arrow). Nav links are hidden on mobile.
101
+ Element 4 - Progress Bar (Bottom Edge): 3px track with bg-border/50. Fill uses bg-primary with glow boxShadow. scaleX from 0 to progress/100.
476
102
 
477
- Right side: a "Join Waitlist" pill button. This button has a subtle layered construction \u2014 a fully rounded pill shape with a thin 0.6px solid white outer border, and inside that, a black-background pill with the text "Join Waitlist" in white, 14px, font-medium, centered with 29px horizontal and 11px vertical padding. There's also a subtle white glow/light streak effect along the top edge of the button (a blurred white-to-transparent gradient blob positioned at the top).
103
+ When progress hits 100: wait 400ms, call onComplete. Parent fades in main content.
104
+ ${W}`},{id:"21",title:"Volt Agency",category:"Agency",prompt:`Build a full-screen hero section for a creative agency.
478
105
 
479
- Hero Content (centered below the navbar):
106
+ Background: Dark mesh gradient. Use overlapping radial-gradient blobs with the primary color at 8% opacity over bg-background.
480
107
 
481
- Vertically centered in the remaining viewport space, pushed down with about 280px top padding on desktop (200px on mobile), 102px bottom padding.
108
+ Navigation: Fully transparent, no background, no border. All links and logo in text-foreground.
482
109
 
483
- All content is horizontally centered and stacked vertically with 40px gaps.
110
+ Featured Badge: Centered at top. "Liquid glass" effect: outer ring with foreground/10 bg + backdrop-blur-sm, inner pill with foreground/90 bg + backdrop-blur-md.
484
111
 
485
- Badge/pill: A small rounded pill (20px border-radius) with 10% white background and a 1px white/20% border. Inside: a tiny 4px white dot, then text reading "Early access available from" in white at 60% opacity, followed by " May 1, 2026" in solid white. Font is 13px, font-medium.
112
+ Headline: Two lines. Line 1: body font, font-light, 64px. Line 2: serif italic, 64px. Both text-foreground.
486
113
 
487
- Heading: Large text reading "Web3 at the Speed of Experience", max-width 613px, 56px on desktop / 36px on mobile, font-medium, line-height 1.28. The text has a gradient fill \u2014 a linear-gradient at ~144.5 degrees going from solid white (at ~28%) to fully transparent black (at ~115%), applied as a background-clip text effect so the text itself shows the gradient.
114
+ Sub-headline: Max-width paragraph, foreground at 75% opacity.
488
115
 
489
- Subtitle: Below the heading with a 24px gap. Text reads: "Powering seamless experiences and real-time connections, EOS is the base for creators who move with purpose, leveraging resilience, speed, and scale to shape the future." \u2014 15px, font-normal, white at 70% opacity, max-width 680px, centered.
116
+ Button Styling: Sharp 2px border-radius. bg-muted text-foreground. Hover: transition to bg-foreground text-background.
490
117
 
491
- CTA Button: A "Join Waitlist" pill button similar to the navbar button but with a white background and black text instead. Same layered construction: 0.6px white outer border, white glow streak on top, and inside the white pill the text is 14px font-medium black, with 29px horizontal and 11px vertical padding.
118
+ Corner Accents: Four 7px solid squares of bg-foreground positioned at the four corners of the hero content container. Purely decorative.
492
119
 
493
- The entire layout is responsive \u2014 nav links collapse on screens below md breakpoint, heading scales down, and padding adjusts.`},{id:"aethera-hero",title:"Ivory Cinema",category:"Hero Section",prompt:`Prompt: Cinematic Hero Section with Looping Video Background
120
+ Interactions: Smooth transition-colors on hover for all buttons and badges.
121
+ ${W}`},{id:"3",title:"Crystal Clear",category:"SaaS",prompt:`Create a dark-mode hero section for a SaaS product.
494
122
 
495
- Create a fullscreen single-page hero section using React + Vite + Tailwind CSS + TypeScript with the following specifications:
123
+ Background: Subtle animated gradient. A top gradient bar (5px) using primary-to-accent colors.
496
124
 
497
- Fonts:
498
- Display text (headings, logo): Instrument Serif
499
- Body text (navigation, descriptions): Inter
500
- Import both fonts in /src/styles/fonts.css
125
+ Navbar: Logo left, centered links (Features, Pricing, Reviews), auth buttons right. Mobile: hamburger dropdown.
501
126
 
502
- Video Background:
503
- URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260328_083109_283f3553-e28f-428b-a723-d639c617eb2b.mp4
504
- Position: top: '300px' with inset: 'auto 0 0 0'
505
- Implement custom fade-in/fade-out loop logic using React useEffect and useRef:
506
- Use requestAnimationFrame to continuously monitor currentTime and duration
507
- Fade in over 0.5s at the start (opacity 0 to 1)
508
- Fade out over 0.5s before the end (opacity 1 to 0)
509
- On ended event: set opacity to 0, wait 100ms, reset currentTime = 0, then play() again
510
- This creates a seamless manual loop with smooth fade transitions
511
- Add gradient overlays: absolute inset-0 bg-gradient-to-b from-background via-transparent to-background positioned over the video
127
+ Hero Content: Large headline (text-6xl, tight leading). Subhead at foreground/90. Staggered entrance animations using framer-motion (fade-up + slide).
512
128
 
513
- Navigation Bar:
514
- Logo: "Aethera\xAE" (with registered trademark symbol as superscript)
515
- Logo styling: text-3xl, tracking-tight, Instrument Serif, color #000000
516
- Menu items: Home (color #000000), Studio, About, Journal, Reach Us (all others #6F6F6F)
517
- Menu items: text-sm with transition-colors
518
- CTA button: "Begin Journey", rounded-full, px-6 py-2.5, text-sm, black background (#000000), white text, hover scale 1.03
519
- Layout: flex justify-between, px-8 py-6, max-w-7xl mx-auto
129
+ Primary CTA Button: Gradient background using primary color shades. Behind the button, an absolute-positioned glow div with bg-primary, blur-lg, opacity-20. Inner 1.5px border at foreground/20 for glassy edge. Hover: scale 1.05, glow increases to opacity-60, arrow slides in.
520
130
 
521
- Hero Section:
522
- Positioning: paddingTop: 'calc(8rem - 75px)', pb-40
523
- Layout: centered (flex flex-col items-center justify-center text-center), px-6
524
- Headline:
525
- Text: "Beyond silence, we build the eternal."
526
- Styling: text-5xl sm:text-7xl md:text-8xl, max-w-7xl, font-normal
527
- Font: Instrument Serif
528
- Line height: 0.95
529
- Letter spacing: -2.46px
530
- Color: #000000 for main text, #6F6F6F for italic emphasized words ("silence," and "the eternal.")
531
- Animation: animate-fade-rise
131
+ Secondary CTA: bg-foreground/90 with backdrop-blur. Inner border foreground/5. Hover: scale 1.05, solid foreground bg.
532
132
 
533
- Description:
534
- Text: "Building platforms for brilliant minds, fearless makers, and thoughtful souls. Through the noise, we craft digital havens for deep work and pure flows."
535
- Styling: text-base sm:text-lg, max-w-2xl, mt-8, leading-relaxed
536
- Color: #6F6F6F
537
- Animation: animate-fade-rise-delay
133
+ Social Proof: Row of 3 overlapping avatar circles + "Trusted by X+ users" text.
134
+ ${W}`},{id:"5",title:"Aurora Glass",category:"Agency",prompt:`Build a dark glassmorphism hero section for an agency.
538
135
 
539
- Hero CTA Button:
540
- Text: "Begin Journey"
541
- Styling: rounded-full, px-14 py-5, text-base, mt-12
542
- Colors: black background (#000000), white text (#FFFFFF)
543
- Hover: scale 1.03
544
- Animation: animate-fade-rise-delay-2
136
+ Background: Animated diagonal gradient using the primary color at varying opacities. CSS animation cycling gradient angle over 6s. Dark bg-background base.
545
137
 
546
- Colors:
547
- Background: white (#FFFFFF)
548
- Headlines/logos/buttons: black (#000000)
549
- Descriptions/menu items: gray (#6F6F6F)
550
- Button text: white (#FFFFFF)
138
+ Announcement Pill: Semi-transparent dark pill with subtle border. Zap icon inside a gradient-filled box with glow. Descriptive text in text-muted-foreground.
551
139
 
552
- Animations (in /src/styles/theme.css):
553
- fade-rise: opacity 0 to 1, translateY 20px to 0, duration 0.8s, ease-out
554
- fade-rise-delay: same as fade-rise but with 0.2s delay
555
- fade-rise-delay-2: same as fade-rise but with 0.4s delay
140
+ Headline: Large responsive text (48px to 80px). Text has a gradient fill (foreground to primary) using bg-clip-text text-transparent.
556
141
 
557
- Layout Structure:
558
- Container: relative min-h-screen w-full overflow-hidden
559
- Background video layer (z-0)
560
- Gradient overlay on video
561
- Navigation bar (z-10)
562
- Hero section (z-10)
563
- All elements should be responsive and maintain the glassmorphic aesthetic with the specified padding, positioning, and smooth animations.`},{id:"bloom-ai-hero",title:"Frost Bloom",category:"Hero Section",prompt:`Create a full-screen hero landing page for "Bloom" \u2014 an AI-powered plant/floral design platform. The design uses a liquid glass morphism aesthetic over a looping video background.
564
-
565
- Background
566
- Full-screen autoplaying, looping, muted video background: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260315_073750_51473149-4350-4920-ae24-c8214286f323.mp4
567
- Video covers entire viewport with object-cover, sits at z-0. All content floats above at z-10.
568
-
569
- Fonts
570
- Display/Body: Poppins (Google Fonts) \u2014 used for headings and body text
571
- Serif accent: Source Serif 4 (Google Fonts) \u2014 used only for italic/emphasis text inside headings (e.g., <em>, <i>, .italic inside h1-h3)
572
- Headings use font-weight: 500
573
-
574
- Color Palette
575
- Strict grayscale only \u2014 all CSS variables are 0 0% X% HSL values
576
- Text is text-white, text-white/80, text-white/60, text-white/50 for hierarchy
577
- No colored accents whatsoever
578
-
579
- Liquid Glass CSS (two tiers)
580
- Define under @layer components:
581
-
582
- .liquid-glass (light)
583
- background: rgba(255,255,255,0.01);
584
- background-blend-mode: luminosity;
585
- backdrop-filter: blur(4px);
586
- border: none;
587
- box-shadow: inset 0 1px 1px rgba(255,255,255,0.1);
588
- position: relative; overflow: hidden;
589
- ::before pseudo-element: gradient border using linear-gradient(180deg, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%, transparent 40%, transparent 60%, rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%) with padding: 1.4px, masked via -webkit-mask-composite: xor; mask-composite: exclude;
590
-
591
- .liquid-glass-strong (heavy, for CTA/panels)
592
- Same structure but backdrop-filter: blur(50px), box-shadow: 4px 4px 4px rgba(0,0,0,0.05), inset 0 1px 1px rgba(255,255,255,0.15), and ::before uses 0.5/0.2 alpha instead of 0.45/0.15.
593
-
594
- Layout \u2014 Two-Panel Split
595
- Flex row, min-h-screen. Left panel w-[52%], right panel w-[48%] (hidden on mobile lg:flex).
596
-
597
- Left Panel
598
- Has a liquid-glass-strong overlay (absolute inset-4 lg:inset-6 rounded-3xl)
599
- Nav: Logo image (/logo.png, 32\xD732) + "bloom" text (semibold, 2xl, tracking-tighter, white) on left. "Menu" button with Menu icon on right, liquid-glass pill.
600
- Hero center (flex-1, centered):
601
- Logo image again (80\xD780)
602
- h1: "Innovating the / spirit of bloom AI" \u2014 text-6xl lg:text-7xl, tracking-[-0.05em], white. The italic part uses font-serif text-white/80
603
- CTA button: "Explore Now" with Download icon in a w-7 h-7 rounded-full bg-white/15 circle. Button is liquid-glass-strong, rounded-full, hover:scale-105 active:scale-95
604
- Three pills: "Artistic Gallery", "AI Generation", "3D Structures" \u2014 liquid-glass, rounded-full, text-xs text-white/80
605
- Bottom quote:
606
- "VISIONARY DESIGN" label (text-xs tracking-widest uppercase text-white/50)
607
- Quote: "We imagined a realm with no ending." \u2014 mixed font-display/font-serif italic spans
608
- Author: "MARCUS AURELIO" with horizontal lines on each side
609
-
610
- Right Panel (desktop only)
611
- Top bar: Social icons (Twitter, LinkedIn, Instagram) in a liquid-glass pill with ArrowRight. Account button with Sparkles icon button, both liquid-glass.
612
- Community card: Small liquid-glass card (w-56), "Enter our ecosystem" title + description
613
- Bottom feature section (mt-auto): Outer liquid-glass container with rounded-[2.5rem]
614
- Two side-by-side cards: "Processing" (Wand2 icon) and "Growth Archive" (BookOpen icon), each liquid-glass rounded-3xl
615
- Bottom card: flower image thumbnail (from @/assets/hero-flowers.png, 96\xD764), "Advanced Plant Sculpting" title + description, and a "+" button. All liquid-glass.
616
-
617
- Icons
618
- All from lucide-react: Sparkles, Download, Wand2, BookOpen, ArrowRight, Twitter, Linkedin, Instagram, Menu
619
-
620
- Key Details
621
- All interactive elements: hover:scale-105 transition-transform
622
- Social icon links: text-white hover:text-white/80 transition-colors
623
- Icon containers: w-8 h-8 rounded-full bg-white/10 flex items-center justify-center
624
- No border classes anywhere \u2014 glass effect handles all borders via ::before
625
- border-radius token: --radius: 1rem`},{id:"datacore-booking-hero",title:"Amethyst Book",category:"SaaS",prompt:`Create a responsive, full-screen hero section for a web application using React and Tailwind CSS.
142
+ Subheadline: text-foreground/80, centered.
626
143
 
627
- Design System & Assets:
144
+ CTA Button: Rounded-full, bg-foreground text-background. Arrow icon in a circle styled with primary gradient. Outer border wrapper with glass effect.
628
145
 
629
- Fonts: Load and use 'Manrope' (for UI/Nav), 'Cabin' (for buttons/tags), 'Instrument Serif' (for headlines), and 'Inter' (for body text).
146
+ Logo Cloud (below hero): Semi-transparent glass bar (bg-background/20, backdrop-blur-sm, border-foreground/5). "Powering the best teams" text + infinite horizontal logo slider using framer-motion. Logos in grayscale (brightness-0 invert for white).
147
+ ${W}`},{id:"7",title:"Obsidian Tech",category:"SaaS",prompt:`Build a dark-themed hero section with glassmorphic navbar.
630
148
 
631
- Primary Color: Purple #7b39fc
632
- Secondary/Dark Color: Dark Purple #2b2344
633
- Background: Use a full-screen, absolute-positioned HTML5 video background. The video should autoplay, loop, mute, and play inline. Ensure it covers the viewport (min-h-screen, object-cover) without an overlay (keep it opaque).
149
+ Background: Solid bg-background.
634
150
 
635
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260210_031346_d87182fb-b0af-4273-84d1-c6fd17d6bf0f.mp4
151
+ Navbar: Fixed, blurred glass effect (backdrop-blur-md, bg-background/80, border-border). Logo "Synapse" (font-medium, tracking-tight). Active link has gradient border. CTA: gradient button (foreground/primary).
636
152
 
637
- 1. Navbar Component (Top Overlay)
153
+ Hero Content: Centered z-10.
154
+ - Badge row: 3 glass-effect badges with icons ("Integrated with...").
155
+ - Headline: ~80px, tight tracking, fade-in animation.
156
+ - Subtext: 2 lines about the product.
157
+ - Two buttons: solid bg-background with foreground border, and a transparent glass style.
638
158
 
639
- Layout: Full width, transparent background, z-20 relative positioning.
640
- Padding: px-6 (mobile) to px-[120px] (desktop), py-[16px].
159
+ Logo Marquee: Static row of grayscale logos at 40% opacity at the bottom.
641
160
 
642
- Logo (Left): Use this specific SVG path filled with white:
643
- Path: M1.04356 6.35771L13.6437 0.666504... (Future logo shape).
161
+ Animations: Staggered framer-motion fade-in-up for badges, headline, subtitle, and buttons.
162
+ ${W}`},{id:"9",title:"Chain Zero",category:"Web3",prompt:`Build a full-screen Web3 hero section.
644
163
 
645
- Navigation Links (Center-Left, Desktop Only):
646
- Items: "Home", "Services" (with a ChevronDown icon), "Reviews", "Contact us".
647
- Style: Manrope font, Medium weight, 14px size, White.
648
- Hover effect: opacity-80.
164
+ Background: Dark bg-background with a subtle mesh overlay. Use radial-gradient with primary color at 5% opacity for depth.
649
165
 
650
- Action Buttons (Right, Desktop Only):
651
- Sign In: White background, thin gray border (#d4d4d4), rounded 8px, Black text (#171717), Manrope Semibold 14px.
652
- Get Started: Primary Purple background (#7b39fc), rounded 8px, White text (#fafafa), Manrope Semibold 14px, subtle shadow.
166
+ Navbar: Full width with generous padding (120px horizontal). Logo wordmark left + 4 nav links with small chevron-down icons. "Join Waitlist" pill button right with layered construction: outer 0.6px border, inner dark pill, subtle glow/streak along top edge.
653
167
 
654
- Mobile: Hide links/buttons and show a White Menu icon (hamburger) that toggles a full-screen black overlay menu.
168
+ Hero Content: Centered below navbar, generous top padding (~280px).
169
+ - Badge pill: Rounded, 10% foreground bg, 1px border foreground/20. Small white dot + text at 60% opacity + emphasized date.
170
+ - Heading: 56px desktop / 36px mobile, font-medium, line-height 1.28. Gradient text fill: linear-gradient ~144.5deg from foreground to transparent, using bg-clip-text.
171
+ - Subtitle: 15px, foreground at 70% opacity, max-width 680px.
172
+ - CTA: Pill button with the same layered construction as nav but inverted (bg-foreground text-background).
655
173
 
656
- 2. Hero Content (Centered)
174
+ Responsive: Nav links collapse below md.
175
+ ${W}`},{id:"aethera-hero",title:"Ivory Cinema",category:"Hero Section",prompt:`Create a fullscreen hero section with cinematic typography on a light background.
657
176
 
658
- Container: Centered vertically and horizontally (flex-col items-center text-center), z-10 relative, top margin mt-32.
177
+ Background: Light gradient. Use a subtle radial gradient from the primary color at 3% opacity, fading into bg-background. Add a top-to-bottom gradient overlay for depth.
659
178
 
660
- Tagline Pill:
661
- Style: Glassmorphism effect (bg-[rgba(85,80,110,0.4)], backdrop-blur, border rgba(164,132,215,0.5)).
662
- Shape: Rounded 10px, Height 38px.
663
- Content: A small inner badge (#7b39fc bg, rounded 6px) saying "New" followed by text "Say Hello to Datacore v3.2".
664
- Font: Cabin, Medium, 14px, White.
179
+ Navigation: Logo with registered trademark symbol (text-3xl, tracking-tight, serif style). Menu items: first item uses text-foreground, rest use text-muted-foreground. CTA button: rounded-full, bg-foreground text-background, hover scale 1.03.
665
180
 
666
- Headline:
667
- Text: "Book your perfect stay instantly and hassle-free".
668
- Typography: Instrument Serif font, White.
669
- Size: 5xl (mobile) to 96px (desktop).
670
- Styling: Line-height 1.1. The word "and" should be italicized with specific spacing.
181
+ Hero Content: Centered, generous top padding.
182
+ - Headline: text-5xl to text-8xl. Serif font style. Line-height 0.95, letter-spacing -2.46px. Certain words (like "silence" and "the eternal") rendered in text-muted-foreground for contrast.
183
+ - Description: text-base to text-lg, text-muted-foreground, max-w-2xl, mt-8.
184
+ - CTA: rounded-full, bg-foreground text-background, px-14 py-5.
671
185
 
672
- Subtext:
673
- Text: "Discover handpicked hotels, resorts, and stays across your favorite destinations. Enjoy exclusive deals, fast booking, and 24/7 support."
674
- Typography: Inter font, Normal weight, 18px.
675
- Color: White with 70% opacity (text-white/70).
676
- Width: Max width 662px.
186
+ Animations (CSS keyframes):
187
+ - fade-rise: opacity 0 to 1, translateY 20px to 0, 0.8s ease-out
188
+ - Staggered delays: headline (0s), description (0.2s), CTA (0.4s)
189
+ ${W}`},{id:"bloom-ai-hero",title:"Frost Bloom",category:"Hero Section",prompt:`Create a split-panel hero landing page with a liquid glass aesthetic.
677
190
 
678
- Call to Action Buttons (Row):
679
- Button 1: "Book a Free Demo" \u2014 Primary Purple (#7b39fc), rounded 10px, Cabin Medium 16px, White.
680
- Button 2: "Get Started Now" \u2014 Dark Purple (#2b2344), rounded 10px, Cabin Medium 16px, Off-white (#f6f7f9).
681
- Hover effects: Slightly lighten backgrounds on hover.`},{id:"designpro-hero",title:"Neon Academy",category:"Hero Section",prompt:`Create a full-screen hero section for a product design education platform called "DesignPro" with the following exact specifications:
191
+ Layout: Flex row, min-h-screen. Left panel w-[52%], right panel w-[48%] (hidden on mobile, lg:flex).
682
192
 
683
- Background:
193
+ Background: Dark mesh gradient using primary color at low opacity.
684
194
 
685
- Full-screen looping video background using this exact CloudFront URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260328_105406_16f4600d-7a92-4292-b96e-b19156c7830a.mp4
195
+ Liquid Glass CSS: Define .liquid-glass and .liquid-glass-strong classes using backdrop-filter blur, subtle box-shadow, and a ::before pseudo-element with a gradient border mask (linear-gradient of foreground at varying opacities, masked with -webkit-mask-composite: xor).
686
196
 
687
- Video should autoplay, loop, be muted, and play inline
197
+ Left Panel: liquid-glass-strong overlay with absolute inset-4 rounded-3xl.
198
+ - Nav: Logo + brand text left. Glass pill menu button right.
199
+ - Hero center: Large h1 in body font. Italic portion uses serif style at foreground/80.
200
+ - CTA: liquid-glass-strong rounded-full with Download icon.
201
+ - Three feature pills below CTA.
202
+ - Bottom quote section with serif italic text.
688
203
 
689
- Background color: black (#000000)
204
+ Right Panel (desktop only): Social icons in glass pill. Community card. Bottom feature cards in glass containers.
690
205
 
691
- Navigation Bar:
206
+ Strict grayscale palette: text-foreground, text-foreground/80, text-foreground/60, text-foreground/50 for hierarchy. No accent colors except through the design system.
207
+ ${W}`},{id:"datacore-booking-hero",title:"Amethyst Book",category:"SaaS",prompt:`Create a full-screen booking/SaaS hero section.
692
208
 
693
- Logo: Circular design with a white border (2px), containing a smaller filled white circle inside, followed by "DesignPro" text
209
+ Background: Dark gradient using bg-background with subtle radial glow of primary color.
694
210
 
695
- Navigation links in a rounded pill container with gray-700 border: Home, About Us, Courses, Instructors, Testimonials, Blog, Contact us (with arrow icon)
211
+ Navbar: Transparent bg, z-20. Logo SVG left. Nav links center (14px, medium). Sign In + Get Started buttons right. Mobile: hamburger toggle.
696
212
 
697
- All nav links: white/80 opacity, hover to full white
213
+ Hero Content: Centered, mt-32.
214
+ - Tagline Pill: Glassmorphism (bg-muted/40, backdrop-blur, border-primary/50). Inner badge with bg-primary text "New" + descriptive text.
215
+ - Headline: Serif font style, text-5xl to 96px desktop. Line-height 1.1. The word "and" in italic.
216
+ - Subtext: Body font, 18px, text-foreground/70, max-w-[662px].
217
+ - CTA Buttons: "Book a Demo" in bg-primary, "Get Started" in bg-muted. Both rounded-[10px].
698
218
 
699
- Font size: text-sm
219
+ Hover effects: Slightly lighten backgrounds.
220
+ ${W}`},{id:"designpro-hero",title:"Neon Academy",category:"Hero Section",prompt:`Create a full-screen hero for a product education platform.
700
221
 
701
- Mobile: Show hamburger menu icon on screens smaller than lg
222
+ Background: Solid bg-background. Content sits on top with z-10.
702
223
 
703
- Max width: 7xl container with proper padding
224
+ Navigation: Logo (circle + text). Nav links in a rounded pill container with border. All links text-foreground/80, hover to full foreground.
704
225
 
705
226
  Content Layout:
227
+ - Top section below nav: Two-column on large screens. Left: mission statement. Right: stats ("8000+ Designers Launched"). Both text-foreground/80.
228
+ - Small uppercase text: tracking-tight, text-foreground/80.
229
+ - Main heading: text-5xl to text-9xl. Line 1 in text-foreground. Line 2 with ShinyText animation effect.
706
230
 
707
- Top Section (below nav):
231
+ ShinyText Component (framer-motion): Base color uses primary, shine uses foreground. Continuous gradient sweep (3s, 100deg spread) using backgroundClip: text and transparent fill.
708
232
 
709
- Two-column layout on large screens, stacked on mobile
233
+ CTA: bg-background (inverted) rounded-full with arrow icon that translates right on hover.
234
+ ${W}`},{id:"digitwist-hero",title:"Cobalt Builder",category:"SaaS",prompt:`Create a dark hero section for an AI website builder.
710
235
 
711
- Left column: "We deliver transformative programs that empower emerging product designers with cutting-edge expertise and vision to thrive globally."
236
+ Background: Solid bg-background with decorative gradient blobs. Top-left: primary color at 20% opacity, 600x600px, blur-[120px]. Bottom-right: similar.
712
237
 
713
- Right column (right-aligned on lg+): "8000+ Talented Designers Launched !"
238
+ Navbar: Fixed transparent. Logo left. Nav links center (with ChevronDown on some). "Get Started" pill button right (bg-foreground text-background).
714
239
 
715
- Both paragraphs: white/80 opacity, text-sm on mobile, text-base on desktop
240
+ Content: Centered, max-w-5xl, mt-20, space-y-12.
241
+ - Pre-headline: Serif font style, text-3xl to text-[48px]. Fade-up animation.
242
+ - Main headline: Bold body font, text-6xl to text-[136px], tracking-tighter. Gradient: bg-gradient-to-b from foreground via foreground to primary (lighter). bg-clip-text text-transparent. Scale animation.
243
+ - Subheadline: text-lg, foreground at 70% opacity, max-w-xl. Fade animation.
716
244
 
717
- Hero Section (center):
245
+ CTA Buttons:
246
+ - Primary: White pill with accent-colored arrow circle (40x40px, bg-primary). Hover: glow shadow, scale-105.
247
+ - Secondary: Text link with arrow, backdrop-blur-sm, hover bg-foreground/5.
248
+ ${W}`},{id:"grow-ai-hero",title:"Gradient Titan",category:"SaaS",prompt:`Build a dark hero section with a massive gradient headline and logo marquee.
718
249
 
719
- Small uppercase text above heading: "Seats for Next Program Opening Soon" (white/80 opacity, text-xs on mobile, text-sm on desktop, tight tracking)
250
+ Design Tokens: Set up dark theme CSS variables using the project's design system.
720
251
 
721
- Main heading with these exact specifications:
252
+ Liquid Glass: Define .liquid-glass utility class with backdrop-filter blur(4px), subtle box-shadow, and gradient border via ::before pseudo-element.
722
253
 
723
- Line 1: "Become" in white, font-medium
254
+ Navbar: Logo image left. Nav links center. "Sign Up" button right using glass styling.
724
255
 
725
- Line 2: "Product Leader." with animated shiny gradient effect
256
+ Hero Content:
257
+ - Headline: Massive text-[230px], font-normal, tracking-[-0.024em]. Gradient text using bg-clip-text with a diagonal gradient from foreground to primary.
258
+ - Subtext: text-muted-foreground, text-lg, max-w-md, opacity-80.
259
+ - CTA: Glass-styled button "Schedule a Consult".
726
260
 
727
- Font sizes: text-5xl (mobile) scaling up to text-9xl (xl screens)
261
+ Background Animation: Subtle CSS animation of gradient position. Use requestAnimationFrame for smooth fade-in/fade-out transitions on background elements.
728
262
 
729
- Line height: 0.85
263
+ Logo Marquee: Below hero. "Relied on by brands across the globe" text + horizontally scrolling marquee (20s linear infinite). Each logo: glass pill square + brand name.
264
+ ${W}`},{id:"liquid-glass-agency",title:"Onyx Studio",category:"Landing Page",prompt:`Build a multi-section landing page for an AI-powered design agency. Dark, premium, Apple-inspired with liquid glass morphism.
730
265
 
731
- Letter spacing: tracking-tighter
266
+ Liquid Glass CSS: Two variants (.liquid-glass subtle, .liquid-glass-strong heavy). Both use backdrop-filter blur, gradient border via ::before pseudo-element.
732
267
 
733
- ShinyText Component:
268
+ SECTION 1 - NAVBAR: Fixed, z-50. Logo left. Center: glass pill with nav links + solid bg-foreground "Get Started" button.
734
269
 
735
- Use framer-motion for animation
270
+ SECTION 2 - HERO (1000px height): Content centered, pt-150px.
271
+ - Badge pill with glass effect.
272
+ - Heading uses BlurText animation (word-by-word blur-to-clear reveal). text-6xl to text-[5.5rem], serif italic style.
273
+ - Subtext fades in with blur.
274
+ - CTA buttons with glass styling.
275
+ - Partner names at bottom in serif italic.
276
+ Background: Subtle mesh gradient using primary at low opacity.
736
277
 
737
- Base color: #64CEFB (light blue)
278
+ SECTION 3 - HOW IT WORKS: Badge + heading + subtext + CTA. Background: gradient with top/bottom fade overlays.
738
279
 
739
- Shine color: #ffffff (white)
280
+ SECTION 4 - FEATURES (alternating rows): Text left/image right, then reversed. Glass CTA buttons.
740
281
 
741
- Animation speed: 3 seconds
282
+ SECTION 5 - FEATURE GRID: 4-column grid. Each card: glass, rounded-2xl. Icon in glass circle + title + description.
742
283
 
743
- Gradient spread: 100 degrees
284
+ SECTION 6 - STATS: Glass container, 4-column grid. Large serif italic numbers + labels.
744
285
 
745
- Gradient should sweep across text continuously from left to right
286
+ SECTION 7 - TESTIMONIALS: 3-column grid. Glass cards with quote, name, role.
746
287
 
747
- Use CSS gradient with backgroundClip: text and transparent text fill
288
+ SECTION 8 - CTA FOOTER: Heading + subtext + two buttons. Copyright footer.
289
+ ${W}`},{id:"mindloop-landing",title:"Inkwell",category:"Landing Page",prompt:`Build a multi-section monochrome landing page for a newsletter/content platform. Pure monochrome theme (no accent colors beyond the design system).
748
290
 
749
- CTA Button:
291
+ Liquid Glass CSS: Define .liquid-glass with backdrop-filter blur, gradient border mask.
750
292
 
751
- Text: "Apply for Next Enrollment" with arrow icon (from lucide-react)
293
+ Animation Pattern: Reusable fadeUp helper with staggered delays using framer-motion whileInView.
752
294
 
753
- Black background, hover: gray-900
295
+ SECTION 1 - NAVBAR: Fixed transparent. Logo (concentric circles icon + brand text). Nav links separated by dots. Social icons in glass circular buttons.
754
296
 
755
- Rounded-full shape
297
+ SECTION 2 - HERO: Full viewport height.
298
+ - Background: Subtle mesh gradient with bottom fade (h-64) to bg-background.
299
+ - Avatar row: 3 overlapping circles + subscriber count.
300
+ - Heading: text-5xl to text-8xl, tracking-[-2px]. Key word in serif italic.
301
+ - Email subscription form: Glass pill container with email input + solid CTA button. Hover scale animations.
756
302
 
757
- Padding: px-6 md:px-8, py-3 md:py-4
303
+ SECTION 3 - "SEARCH HAS CHANGED": Large heading with serif italic word. 3 platform cards in grid. Bottom tagline.
758
304
 
759
- Arrow should translate right on hover
305
+ SECTION 4 - MISSION: Scroll-driven word-by-word reveal using useScroll and useTransform from framer-motion. Words transition opacity from 0.15 to 1 based on scroll progress.
760
306
 
761
- Group hover animation on arrow icon
307
+ SECTION 5 - SOLUTION: Label + heading + 4-column feature grid.
762
308
 
763
- Typography:
309
+ SECTION 6 - CTA: Background with overlay. Logo, heading, subtitle, two buttons.
764
310
 
765
- Font family: Inter (sans-serif)
311
+ SECTION 7 - FOOTER: Copyright + links.
312
+ ${W}`},{id:"neuralyn-hero",title:"Prism Dashboard",category:"SaaS",prompt:`Create a dark SaaS landing page with a coded dashboard preview.
766
313
 
767
- All text colors: white/80 opacity for body text, full white for headings and hover states
314
+ Liquid Glass CSS: Define .liquid-glass class.
768
315
 
769
- Technical Stack:
316
+ SECTION 1 - HERO (full viewport, overflow-hidden):
317
+ - Navbar: Logo + brand text + nav links left. "Sign In" button right (bg-foreground text-background).
318
+ - Tag pill: Liquid glass with inner "New" badge + descriptive text.
319
+ - Title: text-5xl to text-7xl, tracking-[-2px], font-medium. Key word in serif italic.
320
+ - Subtitle: text-lg, using muted color variable.
321
+ - CTA: bg-foreground text-background, rounded-full.
770
322
 
771
- React + TypeScript
323
+ Dashboard Preview Area: Full viewport width using w-screen trick. Dashboard screenshot/component with mixBlendMode: "luminosity", rounded-2xl. Has parallax scroll (y: 0 to -250) via framer-motion useTransform. Bottom gradient fade.
772
324
 
773
- Vite
325
+ Parallax Effects: Hero text fades over first 50% of scroll. Dashboard image moves with parallax.
774
326
 
775
- Tailwind CSS
327
+ Entrance Animations: Staggered fade-up (pill 0s, title 0.1s, subtitle 0.2s, CTA 0.3s, dashboard 0.4s).
776
328
 
777
- Framer Motion for animations
329
+ SECTION 2 - TESTIMONIAL: min-h-screen, centered.
330
+ - Large quote text with scroll-driven word reveal (each word maps to opacity range based on scroll progress).
331
+ - Author row: avatar + name + role.
332
+ ${W}`},{id:"nexora-hero",title:"Daylight SaaS",category:"SaaS",prompt:`Create a light SaaS landing page hero that fills exactly 100vh with no scroll.
778
333
 
779
- Lucide React for icons
334
+ Layout: h-screen flex flex-col bg-background overflow-hidden.
780
335
 
781
- Responsive Breakpoints:
336
+ Navbar: px-6 to px-20. Logo with decorative symbol + name. Nav links right (text-muted-foreground, hover:text-foreground). CTA: rounded-full primary button.
782
337
 
783
- Mobile-first design
338
+ Hero Content: Centered, flex-1.
339
+ - Badge: rounded-full, border-border, bg-background, text-muted-foreground. Fade-up animation.
340
+ - Headline: Serif display font, text-5xl to text-[5rem], leading-[0.95], tracking-tight. Key word in serif italic. Fade-up with delay.
341
+ - Subheadline: text-base to text-lg, text-muted-foreground, max-w-[650px].
342
+ - CTA buttons: Primary rounded-full + ghost play button (rounded-full with bg-background shadow).
784
343
 
785
- sm: 640px
344
+ Dashboard Preview (coded in React, not an image): Frosted glass wrapper (bg-foreground/40, 1px border foreground/50, shadow). Dashboard internals: top bar, sidebar with nav items, main content with balance card (SVG area chart), accounts list, and transactions table. All at text-[11px], select-none, pointer-events-none. Overflows bottom edge, clipped by parent.
345
+ ${W}`},{id:"portfolio-cosmic-hero",title:"Stellar Folio",category:"Portfolio",prompt:`Build a multi-section dark portfolio landing page using GSAP + framer-motion.
786
346
 
787
- md: 768px
347
+ LOADING SCREEN: Full-screen overlay (fixed, z-[9999]). Counter 000 to 100 over 2.7s. Rotating words. Progress bar with primary-colored glow. See preset "18" (Typewriter Intro) for full spec.
788
348
 
789
- lg: 1024px
349
+ HERO SECTION: Full viewport with background mesh gradient.
350
+ - Navbar: Fixed floating pill at top center. Logo circle with gradient border + initials. Nav links. "Say hi" button with gradient hover border.
351
+ - Eyebrow: text-xs text-muted-foreground uppercase tracking-[0.3em].
352
+ - Name: text-6xl to text-9xl, serif italic, leading-[0.9].
353
+ - Role line: Cycling words every 2s ("Creative", "Fullstack", etc.) with fade animation.
354
+ - CTA buttons with gradient hover borders. GSAP entrance timeline.
790
355
 
791
- xl: 1280px
356
+ SELECTED WORKS: Bento grid (grid-cols-12), alternating 7/5 and 5/7 column spans. Project cards with hover overlay (backdrop-blur + hover label pill).
792
357
 
793
- Key CSS Details:
358
+ JOURNAL: Horizontal pills with titles, read times, dates.
794
359
 
795
- Container max-width: max-w-7xl with centered margins
360
+ EXPLORATIONS: Parallax gallery. Pinned center content + parallax columns using GSAP ScrollTrigger.
796
361
 
797
- Section height: h-screen
362
+ STATS: 3-column grid with large numbers.
798
363
 
799
- Video: absolute positioning, inset-0, object-cover
364
+ CONTACT/FOOTER: GSAP text marquee. Email CTA. Social links + availability indicator.
365
+ ${W}`},{id:"power-ai-hero",title:"Spectrum AI",category:"Hero Section",prompt:`Create a dark hero section with massive gradient headline, background animation, and logo marquee.
800
366
 
801
- Content: relative z-10 positioning to appear above video
367
+ Background: Animated CSS gradient with custom fade logic. Use requestAnimationFrame for smooth opacity transitions. Gradient overlays for depth.
802
368
 
803
- Smooth transitions on all interactive elements
369
+ Navbar: Full-width, transparent. Logo left. Nav links center. Glass-styled "Sign Up" button right. Gradient divider line below navbar.
804
370
 
805
- Create the complete implementation including the ShinyText component with proper framer-motion animation logic.`},{id:"digitwist-hero",title:"Cobalt Builder",category:"SaaS",prompt:`Create a dark mode hero section for an AI website builder with the following exact specifications:
371
+ Hero:
372
+ - Headline: Massive text-[230px], font-normal. Gradient text using bg-clip-text with diagonal gradient from foreground to primary.
373
+ - Subtext: text-muted-foreground, text-lg, max-w-md.
374
+ - CTA: Glass-styled rounded-full button.
806
375
 
807
- ## Technical Setup
376
+ Logo Marquee: Below hero. Text + horizontally scrolling brand names with animate-marquee (20s linear infinite). Each: glass pill + brand name.
377
+ ${W}`},{id:"price-calculator",title:"Ember Pricing",category:"SaaS",prompt:`Create a full-width pricing calculator section.
808
378
 
809
- ### Required Packages
810
- Install these packages:
811
- - \`motion\` (version 12.23.24 or later) - for animations
812
- - \`hls.js\` (version 1.6.15 or later) - for video streaming
813
- - \`lucide-react\` (version 0.487.0 or later) - for icons
814
-
815
- ### Fonts
816
- Import these Google Fonts:
817
- \`\`\`css
818
- @import url('https://fonts.googleapis.com/css2?family=Instrument+Sans:ital,wght@0,400..700;1,400..700&family=Instrument+Serif:ital@0;1&display=swap');
819
- \`\`\`
820
-
821
- ## Layout Structure
822
-
823
- ### Navbar Component
824
- Create a fixed, transparent navbar with:
825
-
826
- **Position & Styling:**
827
- - Fixed to top, full width, z-index 50
828
- - Background: fully transparent (bg-transparent)
829
- - Padding: px-6 py-4
830
- - Flexbox layout: items-center justify-between
831
-
832
- **Left Section:**
833
- - Sunburst icon (24x24px SVG) in white color
834
-
835
- **Center Section** (hidden on mobile, visible md:flex):
836
- - Navigation links: "Products" (with ChevronDown icon), "Customer Stories", "Resources", "Pricing"
837
- - Font: Instrument Sans, text-sm, font-medium
838
- - Color: text-white/80, hover:text-white
839
- - Gap: gap-8
840
-
841
- **Right Section:**
842
- - "Book A Demo" link (hidden on small screens, sm:block)
843
- - "Get Started" button: white background, black text, rounded-full, px-5 py-2.5, font-semibold
844
-
845
- ### Hero Section Component
846
-
847
- **Container:**
848
- - Relative positioning, full width, min-h-screen
849
- - Background color: #000000 (pure black)
850
- - Text color: white
851
- - Overflow hidden
852
-
853
- **Background Video Layer:**
854
- - Video URL: https://stream.mux.com/T6oQJQ02cQ6N01TR6iHwZkKFkbepS34dkkIc9iukgy400g.m3u8
855
- - Video implementation using HLS.js with Safari fallback
856
- - Video properties: muted, loop, playsInline
857
- - Object-fit: cover, opacity: 60%
858
- - Poster image fallback: https://images.unsplash.com/photo-1647356191320-d7a1f80ca777?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxhYnN0cmFjdCUyMGRhcmslMjB0ZWNobm9sb2d5JTIwbmV1cmFsJTIwbmV0d29ya3xlbnwxfHx8fDE3Njg5NzIyNTV8MA&ixlib=rb-4.1.0&q=80&w=1080
859
-
860
- **Video Overlay:**
861
- - Black overlay: bg-black/60 with backdrop-blur-[2px]
862
-
863
- **Decorative Gradients:**
864
- - Top-left gradient: position top-[-20%] left-[20%], size 600x600px, bg-blue-900/20, blur-[120px], mix-blend-screen
865
- - Bottom-right gradient: position bottom-[-10%] right-[20%], size 500x500px, bg-indigo-900/20, blur-[120px], mix-blend-screen
866
-
867
- **Content Container:**
868
- - Max-width: 5xl (max-w-5xl)
869
- - Center aligned (mx-auto, items-center, text-center)
870
- - Z-index: 10, top margin: mt-20
871
- - Vertical spacing: space-y-12
872
-
873
- **Pre-headline:**
874
- - Text: "Design at the speed of thought"
875
- - Font: Instrument Serif
876
- - Size: text-3xl (mobile), sm:text-5xl, lg:text-[48px]
877
- - Line height: leading-[1.1]
878
- - Color: white
879
- - Animation: Motion fade up (opacity 0\u21921, y 20\u21920, duration 0.6s)
880
-
881
- **Main Headline:**
882
- - Text: "Build Faster"
883
- - Font: Instrument Sans, font-semibold
884
- - Size: text-6xl (mobile), sm:text-8xl, lg:text-[136px]
885
- - Line height: leading-[0.9], letter spacing: tracking-tighter
886
- - Gradient: bg-gradient-to-b from-white via-white to-[#b4c0ff]
887
- - Text effect: bg-clip-text text-transparent
888
- - Animation: Motion scale (opacity 0\u21921, scale 0.9\u21921, delay 0.2s, duration 0.6s)
889
-
890
- **Subheadline:**
891
- - Text: "Create fully functional, SEO-optimized websites in seconds with our advanced AI engine."
892
- - Font: Instrument Sans
893
- - Size: text-lg (mobile), sm:text-[20px]
894
- - Line height: leading-[1.65]
895
- - Color: white, opacity-70
896
- - Max width: max-w-xl
897
- - Animation: Motion fade (opacity 0\u21920.7, delay 0.4s, duration 0.6s)
898
-
899
- **CTA Buttons:**
900
-
901
- Primary Button:
902
- - Style: White pill-shaped with blue arrow
903
- - Layout: pl-6 pr-2 py-2, rounded-full
904
- - Background: white
905
- - Text: "Start Building Free" (font-medium, text-lg, Instrument Sans, color #0a0400)
906
- - Arrow container: 40x40px circle, bg-[#3054ff], hover:bg-[#2040e0]
907
- - Icon: ArrowRight (lucide-react), white, 20x20px
908
- - Hover effect: shadow-[0_0_20px_rgba(255,255,255,0.3)], scale-105
909
-
910
- Secondary Button:
911
- - Text: "See Examples"
912
- - Style: text link with arrow
913
- - Color: text-white/70, hover:text-white
914
- - Background: backdrop-blur-sm, hover:bg-white/5
915
- - Padding: px-4 py-2, rounded-lg
916
- - Icon: ArrowRight with group-hover:translate-x-1 transition
917
-
918
- Button Container:
919
- - Layout: flex-col (mobile), sm:flex-row
920
- - Gap: gap-6, items centered
921
- - Animation: Motion fade up (opacity 0\u21921, y 20\u21920, delay 0.6s, duration 0.5s)
922
-
923
- ## HLS.js Video Implementation
924
- \`\`\`tsx
925
- import { useEffect, useRef } from "react";
926
- import Hls from "hls.js";
927
-
928
- const videoRef = useRef<HTMLVideoElement>(null);
929
- const videoSrc = "https://stream.mux.com/T6oQJQ02cQ6N01TR6iHwZkKFkbepS34dkkIc9iukgy400g.m3u8";
930
-
931
- useEffect(() => {
932
- const video = videoRef.current;
933
- if (!video) return;
934
-
935
- if (Hls.isSupported()) {
936
- const hls = new Hls();
937
- hls.loadSource(videoSrc);
938
- hls.attachMedia(video);
939
- hls.on(Hls.Events.MANIFEST_PARSED, () => {
940
- video.play().catch((e) => console.log("Auto-play prevented:", e));
941
- });
942
- return () => {
943
- hls.destroy();
944
- };
945
- } else if (video.canPlayType("application/vnd.apple.mpegurl")) {
946
- video.src = videoSrc;
947
- video.addEventListener("loadedmetadata", () => {
948
- video.play().catch((e) => console.log("Auto-play prevented:", e));
949
- });
950
- }
951
- }, []);
952
- \`\`\`
379
+ Layout: bg-background, py-16 md:py-28, max-w-7xl centered. 2-column grid (rounded-2xl, overflow-hidden).
953
380
 
954
- ## Motion Animations
955
- Import: \`import { motion } from "motion/react"\`
956
-
957
- - Pre-headline: initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.6 }}
958
- - Main headline: initial={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1 }} transition={{ delay: 0.2, duration: 0.6 }}
959
- - Subheadline: initial={{ opacity: 0 }} animate={{ opacity: 0.7 }} transition={{ delay: 0.4, duration: 0.6 }}
960
- - Buttons: initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.6, duration: 0.5 }}
961
-
962
- ## Color Palette
963
- - Background: #000000
964
- - Primary text: white
965
- - Secondary text: white/80, white/70
966
- - Primary button background: white
967
- - Primary button text: #0a0400
968
- - Primary button accent: #3054ff, hover #2040e0
969
- - Gradient end color: #b4c0ff
970
- - Decorative gradients: blue-900/20, indigo-900/20`},{id:"grow-ai-hero",title:"Gradient Titan",category:"SaaS",prompt:`Build a dark-themed landing page hero section with a navbar, headline, CTA button, background video with fade-in/out loop, and a logo marquee. Use React + Vite + Tailwind CSS + TypeScript with shadcn/ui. Install @fontsource/geist-sans.
971
-
972
- 1. Theme & Design Tokens (index.css)
973
- Set up a single dark theme (no light mode toggle). All colors in HSL:
974
- :root {
975
- --background: 260 87% 3%;
976
- --foreground: 40 6% 95%;
977
- --card: 240 6% 9%;
978
- --card-foreground: 40 6% 95%;
979
- --popover: 240 6% 9%;
980
- --popover-foreground: 40 6% 95%;
981
- --primary: 262 83% 58%;
982
- --primary-foreground: 0 0% 100%;
983
- --secondary: 240 4% 16%;
984
- --secondary-foreground: 40 6% 95%;
985
- --muted: 240 4% 16%;
986
- --muted-foreground: 240 5% 65%;
987
- --accent: 262 83% 58%;
988
- --accent-foreground: 0 0% 100%;
989
- --destructive: 0 84.2% 60.2%;
990
- --destructive-foreground: 0 0% 100%;
991
- --border: 240 4% 20%;
992
- --input: 240 4% 20%;
993
- --ring: 262 83% 58%;
994
- --radius: 0.75rem;
995
- --hero-heading: 40 10% 96%;
996
- --hero-sub: 40 6% 82%;
997
- }
381
+ Header: Centered. Small mono uppercase label in text-muted-foreground. h2 in text-3xl to text-5xl.
998
382
 
999
- Body font: 'Geist Sans', 'Inter', system-ui, sans-serif
1000
- Import these font weights:
1001
- @import "@fontsource/geist-sans/400.css";
1002
- @import "@fontsource/geist-sans/500.css";
1003
- @import "@fontsource/geist-sans/600.css";
1004
- @import "@fontsource/geist-sans/700.css";
1005
-
1006
- 2. Liquid Glass Utility (index.css)
1007
- Add a .liquid-glass utility class in @layer utilities:
1008
- .liquid-glass {
1009
- background: rgba(255, 255, 255, 0.01);
1010
- background-blend-mode: luminosity;
1011
- backdrop-filter: blur(4px);
1012
- -webkit-backdrop-filter: blur(4px);
1013
- border: none;
1014
- box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);
1015
- position: relative;
1016
- overflow: hidden;
1017
- }
383
+ LEFT COLUMN (Calculator Form): bg-card, p-8 lg:p-12, sections divided by divide-y divide-border.
384
+ - Service Type: Radio buttons (3 options). Custom radio circles: active uses border-primary with inner bg-primary dot.
385
+ - Number of Pages: Slider (shadcn), min=1, max=30, default=5. Labels at ends.
386
+ - Add-ons: Two checkboxes with price labels in text-primary. Custom checkboxes: checked uses border-primary bg-primary with checkmark.
387
+ - Timeline: Radio buttons (3 speed options with price modifiers).
1018
388
 
1019
- .liquid-glass::before {
1020
- content: '';
1021
- position: absolute;
1022
- inset: 0;
1023
- border-radius: inherit;
1024
- padding: 1.4px;
1025
- background: linear-gradient(180deg,
1026
- rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%,
1027
- rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%,
1028
- rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%);
1029
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1030
- -webkit-mask-composite: xor;
1031
- mask-composite: exclude;
1032
- pointer-events: none;
1033
- }
389
+ RIGHT COLUMN (Cost Estimation): border border-border, p-8 lg:p-12.
390
+ - 3 stacked comparison cards:
391
+ - Agency card: bg-muted/50. Large price.
392
+ - Freelancer card: bg-muted/50. Large price.
393
+ - Your price card: bg-gradient-to-r using primary color shades. Highlighted as best value.
1034
394
 
1035
- 3. Tailwind Config
1036
- Add these to tailwind.config.ts:
1037
- All the semantic color tokens mapped to hsl(var(--token))
1038
- A hero color group: hero.heading and hero.sub
1039
- A marquee keyframe: 0% { transform: translateX(0%) } \u2192 100% { transform: translateX(-50%) }
1040
- Animation: marquee: "marquee 20s linear infinite"
1041
-
1042
- 4. Button Variants
1043
- In the shadcn button.tsx, add two custom variants:
1044
- hero: "bg-primary text-primary-foreground rounded-full px-6 py-3 text-base font-medium hover:bg-primary/90"
1045
- heroSecondary: "liquid-glass text-foreground rounded-full px-6 py-3 text-base font-normal hover:bg-white/5"
1046
-
1047
- 5. Navbar Component
1048
- Full-width, py-5 px-8, flex row, justify-between
1049
- Left: A logo image (32px height). Use a logo.png from src/assets/logo.png
1050
- Center: Nav items as plain buttons: "Features" (with ChevronDown icon), "Solutions", "Plans", "Learning" (with ChevronDown icon). Text is text-foreground/90 text-base, gap-1 between items
1051
- Right: "Sign Up" button using heroSecondary variant, size="sm", rounded-full px-4 py-2
1052
- Below the navbar, add a full-width 1px gradient divider: mt-[3px] w-full h-px bg-gradient-to-r from-transparent via-foreground/20 to-transparent
1053
-
1054
- 6. Hero Section
1055
- Section with bg-background relative overflow-hidden
1056
- Contains the Navbar at the top
1057
- Below navbar + divider, centered content with pt-20 px-4
1058
- Headline "Grow": text-[230px] font-normal leading-[1.02] tracking-[-0.024em], font-family 'General Sans', sans-serif, bg-clip-text text-transparent with background-image: linear-gradient(223deg, #E8E8E9 0%, #3A7BBF 104.15%)
1059
- Subtext: text-hero-sub text-center text-lg leading-8 max-w-md mt-4 opacity-80, two lines: "The most powerful AI ever deployed" / "in talent acquisition" (split with <br/>)
1060
- CTA Button: heroSecondary variant, text "Schedule a Consult", px-[29px] py-[24px], wrapped in a div with mt-8 mb-[66px]
1061
-
1062
- 7. Social Proof / Video Section
1063
- Immediately below the hero, a separate <section> with relative w-full overflow-hidden.
1064
- Background Video: <video> element: autoPlay muted playsInline, absolute inset-0 w-full h-full object-cover, initial style={{ opacity: 0 }}
1065
- Source URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260308_114720_3dabeb9e-2c39-4907-b747-bc3544e2d5b7.mp4
1066
- Fade logic (JavaScript): Use requestAnimationFrame to continuously read currentTime and duration. Fade in over 0.5s at the start, fade out over 0.5s at the end. On ended, set opacity to 0, wait 100ms, reset currentTime = 0, and play() again. This creates a seamless manual loop with fade transitions.
1067
- Gradient overlays: absolute inset-0 bg-gradient-to-b from-background via-transparent to-background
1068
- Content (z-10): flex flex-col items-center pt-16 pb-24 px-4 gap-20
1069
- A h-40 spacer div for video visibility
1070
-
1071
- Logo Marquee at max-w-5xl:
1072
- Left side: text "Relied on by brands / across the globe" in text-foreground/50 text-sm, with <br/>, whitespace-nowrap shrink-0
1073
- Right side: horizontally scrolling marquee using animate-marquee (the 20s infinite animation)
1074
- Logos are placeholder brands: Vortex, Nimbus, Prysma, Cirrus, Kynder, Halcyn \u2014 duplicated for seamless loop
1075
- Each logo: a small liquid-glass w-6 h-6 rounded-lg square with the first letter, plus the brand name in text-base font-semibold text-foreground
1076
- Gap between logos: gap-16
1077
-
1078
- 8. Page Composition
1079
- The Index page simply renders <HeroSection /> then <SocialProofSection /> sequentially with no wrapper styling.`},{id:"liquid-glass-agency",title:"Onyx Studio",category:"Landing Page",prompt:`Build a single-page landing page for an AI-powered web design agency using React + Vite + TypeScript + Tailwind CSS + shadcn/ui. The aesthetic is dark, premium, Apple-inspired with a custom "liquid glass" morphism effect. Pure black background throughout.
1080
-
1081
- FONTS & DESIGN SYSTEM
1082
- Google Fonts import:
1083
-
1084
- Instrument Serif (italic) \u2014 headings
1085
- Barlow (300, 400, 500, 600) \u2014 body text
1086
- Tailwind config \u2014 extend fontFamily:
1087
-
1088
- heading: ["'Instrument Serif'", "serif"]
1089
- body: ["'Barlow'", "sans-serif"]
1090
- CSS Variables (:root in index.css):
1091
-
1092
- --background: 213 45% 67%;
1093
- --foreground: 0 0% 100%;
1094
- --primary: 0 0% 100%;
1095
- --primary-foreground: 213 45% 67%;
1096
- --border: 0 0% 100% / 0.2;
1097
- --radius: 9999px;
1098
- --font-heading: 'Instrument Serif', serif;
1099
- --font-body: 'Barlow', sans-serif;
1100
-
1101
- All headings use: font-heading italic text-white tracking-tight leading-[0.9]
1102
- All body text uses: font-body font-light text-white/60 text-sm
1103
- All buttons use: font-body with rounded-full
1104
-
1105
- LIQUID GLASS CSS (in @layer components)
1106
- Two variants \u2014 .liquid-glass (subtle) and .liquid-glass-strong (more visible):
1107
-
1108
- .liquid-glass:
1109
- background: rgba(255, 255, 255, 0.01);
1110
- background-blend-mode: luminosity;
1111
- backdrop-filter: blur(4px);
1112
- border: none;
1113
- box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);
1114
- position: relative;
1115
- overflow: hidden;
1116
-
1117
- ::before pseudo-element \u2014 a gradient border mask:
1118
- content: '';
1119
- position: absolute; inset: 0;
1120
- border-radius: inherit;
1121
- padding: 1.4px;
1122
- background: linear-gradient(180deg,
1123
- rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%,
1124
- rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%,
1125
- rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%);
1126
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1127
- -webkit-mask-composite: xor;
1128
- mask-composite: exclude;
1129
- pointer-events: none;
1130
-
1131
- .liquid-glass-strong: Same but backdrop-filter: blur(50px), stronger box-shadow: 4px 4px 4px rgba(0,0,0,0.05), inset 0 1px 1px rgba(255,255,255,0.15), and slightly higher gradient opacity (0.5 / 0.2).
1132
-
1133
- SECTION 1 \u2014 NAVBAR (fixed)
1134
- Fixed at top-4, full-width, z-50. Left: logo image (48\xD748). Center: a liquid-glass rounded-full pill containing nav links ("Home", "Services", "Work", "Process", "Pricing") as text-sm font-medium text-foreground/90 + a solid white bg-white text-black rounded-full "Get Started" button with ArrowUpRight icon.
1135
-
1136
- SECTION 2 \u2014 HERO (1000px height)
1137
- Container: relative overflow-visible, height 1000px, black background.
1138
-
1139
- Background video:
1140
- src: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260307_083826_e938b29f-a43a-41ec-a153-3d4730578ab8.mp4
1141
- Position: absolute, top: 20%, w-full h-auto object-contain z-0
1142
- Autoplay, loop, muted, playsInline
1143
- Poster fallback image at /images/hero_bg.jpeg
1144
-
1145
- Overlays:
1146
- absolute inset-0 bg-black/5 z-0 (light darkening)
1147
- Bottom gradient: absolute bottom-0 left-0 right-0 z-[1], height 300px, linear-gradient(to bottom, transparent, black)
1148
-
1149
- Content (z-10, centered, paddingTop 150px):
1150
- Badge pill: liquid-glass rounded-full containing a white bg-white text-black rounded-full "New" tag + "Introducing AI-powered web design." text
1151
- Heading: Use a BlurText animation component \u2014 text: "The Website Your Brand Deserves" \u2014 text-6xl md:text-7xl lg:text-[5.5rem] font-heading italic text-foreground leading-[0.8] tracking-[-4px] \u2014 animates word-by-word from bottom with blur-to-clear effect (delay 100ms per word)
1152
- Subtext (motion.p): "Stunning design. Blazing performance. Built by AI, refined by experts. This is web design, wildly reimagined." \u2014 fades in with blur at 0.8s delay
1153
- CTA buttons (motion.div, 1.1s delay): liquid-glass-strong rounded-full "Get Started" + ArrowUpRight icon, and a text-only "Watch the Film" + Play icon
1154
- Partners bar at bottom (mt-auto pb-8 pt-16)
1155
-
1156
- BlurText component: Uses motion/react (framer-motion). Splits text by words, each word animates via IntersectionObserver with filter: blur(10px) \u2192 blur(5px) \u2192 blur(0px), opacity: 0 \u2192 0.5 \u2192 1, y: 50 \u2192 -5 \u2192 0. Step duration 0.35s.
1157
-
1158
- SECTION 3 \u2014 PARTNERS BAR
1159
- Centered column. Top: liquid-glass rounded-full badge "Trusted by the teams behind". Below: horizontal row of partner names ("Stripe", "Vercel", "Linear", "Notion", "Figma") rendered as text-2xl md:text-3xl font-heading italic text-white, gap-12.
1160
-
1161
- SECTION 4 \u2014 START SECTION ("How It Works")
1162
- Full-width section, min-height: 700px, py-32 px-6 md:px-16 lg:px-24.
1163
-
1164
- Background HLS video:
1165
- src: https://stream.mux.com/9JXDljEVWYwWu01PUkAemafDugK89o01BR6zqJ3aS9u00A.m3u8
1166
- Use hls.js library. Absolute, full cover, z-0. Top + bottom fade gradients (200px each, black \u2194 transparent).
1167
-
1168
- Content (z-10, centered, min-height 500px):
1169
- Badge: liquid-glass rounded-full \u2014 "How It Works"
1170
- Heading: "You dream it. We ship it." \u2014 text-4xl md:text-5xl lg:text-6xl font-heading italic
1171
- Subtext: "Share your vision. Our AI handles the rest\u2014wireframes, design, code, launch. All in days, not quarters."
1172
- Button: liquid-glass-strong rounded-full "Get Started" + ArrowUpRight
1173
-
1174
- SECTION 5 \u2014 FEATURES CHESS (alternating rows)
1175
- py-24 px-6 md:px-16 lg:px-24. Header: badge "Capabilities", heading "Pro features. Zero complexity."
1176
-
1177
- Row 1 (text left, image right):
1178
- H3: "Designed to convert. Built to perform."
1179
- P: "Every pixel is intentional. Our AI studies what works across thousands of top sites\u2014then builds yours to outperform them all."
1180
- Button: liquid-glass-strong rounded-full "Learn more"
1181
- Image: GIF in liquid-glass rounded-2xl overflow-hidden container
1182
-
1183
- Row 2 (image left, text right \u2014 using lg:flex-row-reverse):
1184
- H3: "It gets smarter. Automatically."
1185
- P: "Your site evolves on its own. AI monitors every click, scroll, and conversion\u2014then optimizes in real time. No manual updates. Ever."
1186
- Button: "See how it works"
1187
-
1188
- SECTION 6 \u2014 FEATURES GRID (4 columns)
1189
- Badge "Why Us", heading "The difference is everything."
1190
-
1191
- 4 cards in grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6. Each card: liquid-glass rounded-2xl p-6. Contains:
1192
- Icon in liquid-glass-strong rounded-full w-10 h-10 circle
1193
- Title: text-lg font-heading italic text-white
1194
- Description: text-white/60 font-body font-light text-sm
1195
-
1196
- Cards:
1197
- \u26A1 Zap \u2014 "Days, Not Months" \u2014 "Concept to launch at a pace that redefines fast."
1198
- \u{1F3A8} Palette \u2014 "Obsessively Crafted" \u2014 "Every detail considered. Every element refined."
1199
- \u{1F4CA} BarChart3 \u2014 "Built to Convert" \u2014 "Layouts informed by data. Decisions backed by performance."
1200
- \u{1F6E1}\uFE0F Shield \u2014 "Secure by Default" \u2014 "Enterprise-grade protection comes standard."
1201
-
1202
- SECTION 7 \u2014 STATS
1203
- Background HLS video:
1204
- src: https://stream.mux.com/NcU3HlHeF7CUL86azTTzpy3Tlb00d6iF3BmCdFslMJYM.m3u8
1205
- Desaturated: style={{ filter: 'saturate(0)' }}. Top + bottom black fades (200px).
1206
-
1207
- Content (z-10): liquid-glass rounded-3xl p-12 md:p-16, grid grid-cols-2 lg:grid-cols-4 gap-8 text-center:
1208
- "200+" \u2014 "Sites launched"
1209
- "98%" \u2014 "Client satisfaction"
1210
- "3.2x" \u2014 "More conversions"
1211
- "5 days" \u2014 "Average delivery"
1212
- Values: text-4xl md:text-5xl lg:text-6xl font-heading italic text-white
1213
- Labels: text-white/60 font-body font-light text-sm
1214
-
1215
- SECTION 8 \u2014 TESTIMONIALS
1216
- Badge "What They Say", heading "Don't take our word for it."
1217
-
1218
- 3-column grid. Each: liquid-glass rounded-2xl p-8. Quote in text-white/80 font-body font-light text-sm italic. Name: text-white font-body font-medium text-sm. Role: text-white/50 font-body font-light text-xs.
1219
-
1220
- Testimonials:
1221
- Sarah Chen, CEO Luminary \u2014 "A complete rebuild in five days..."
1222
- Marcus Webb, Head of Growth Arcline \u2014 "Conversions up 4x..."
1223
- Elena Voss, Brand Director Helix \u2014 "They didn't just design our site..."
1224
-
1225
- SECTION 9 \u2014 CTA FOOTER
1226
- Background HLS video:
1227
- src: https://stream.mux.com/8wrHPCX2dC3msyYU9ObwqNdm00u3ViXvOSHUMRYSEe5Q.m3u8
1228
- Top + bottom black fades (200px).
1229
-
1230
- Content (z-10, centered):
1231
- Heading: "Your next website starts here." \u2014 text-5xl md:text-6xl lg:text-7xl
1232
- Subtext: "Book a free strategy call. See what AI-powered design can do."
1233
- Two buttons: liquid-glass-strong "Book a Call" + solid bg-white text-black "View Pricing"
1234
- Footer: mt-32 pt-8 border-t border-white/10, copyright "\xA9 2026 Studio" + links (Privacy, Terms, Contact) in text-white/40 text-xs
1235
-
1236
- DEPENDENCIES
1237
- hls.js, motion (framer-motion), lucide-react, tailwindcss-animate
1238
-
1239
- KEY PATTERNS
1240
- All section badges use: liquid-glass rounded-full px-3.5 py-1 text-xs font-medium text-white font-body inline-block mb-4
1241
- All section headings use: text-4xl md:text-5xl lg:text-6xl font-heading italic text-white tracking-tight leading-[0.9]
1242
- All video sections use HLS via hls.js with Safari fallback (canPlayType)
1243
- All video fades: 200px height, linear-gradient(to bottom/top, black, transparent)
1244
- Outer page wrapper: bg-black overflow-visible`},{id:"mindloop-landing",title:"Inkwell",category:"Landing Page",prompt:`Build a dark monochrome landing page called Mindloop \u2014 a newsletter/content platform. Use React + Vite + TypeScript + Tailwind CSS + shadcn/ui + Framer Motion. Fonts: Inter (sans) and Instrument Serif (serif, used for italic accent words). The entire theme is pure black (#000) background with white foreground \u2014 no colors or gradients beyond monochrome. Install hls.js and framer-motion.
1245
-
1246
- Design System (index.css)
1247
- All CSS variables in HSL (no hsl() wrapper in the variable, just the values):
1248
-
1249
- --background: 0 0% 0%
1250
- --foreground: 0 0% 100%
1251
- --card: 0 0% 5%
1252
- --card-foreground: 0 0% 100%
1253
- --primary: 0 0% 100%
1254
- --primary-foreground: 0 0% 0%
1255
- --secondary: 0 0% 12%
1256
- --secondary-foreground: 0 0% 85%
1257
- --muted: 0 0% 15%
1258
- --muted-foreground: 0 0% 65%
1259
- --accent: 170 15% 45%
1260
- --accent-foreground: 0 0% 100%
1261
- --border: 0 0% 20%
1262
- --input: 0 0% 18%
1263
- --ring: 0 0% 40%
1264
- --hero-subtitle: 210 17% 95%
1265
- Liquid Glass Effect (global CSS class .liquid-glass)
1266
-
1267
- .liquid-glass {
1268
- background: rgba(255, 255, 255, 0.01);
1269
- background-blend-mode: luminosity;
1270
- backdrop-filter: blur(4px);
1271
- -webkit-backdrop-filter: blur(4px);
1272
- border: none;
1273
- box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);
1274
- position: relative;
1275
- overflow: hidden;
1276
- }
1277
- .liquid-glass::before {
1278
- content: '';
1279
- position: absolute;
1280
- inset: 0;
1281
- border-radius: inherit;
1282
- padding: 1.4px;
1283
- background: linear-gradient(180deg,
1284
- rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%,
1285
- rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%,
1286
- rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%);
1287
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1288
- -webkit-mask-composite: xor;
1289
- mask-composite: exclude;
1290
- pointer-events: none;
1291
- }
1292
- Animation Pattern
1293
- All sections use a reusable fadeUp helper with staggered delays:
1294
-
1295
- const fadeUp = (delay: number) => ({
1296
- initial: { opacity: 0, y: 20 },
1297
- whileInView: { opacity: 1, y: 0 },
1298
- viewport: { once: true, margin: "-100px" },
1299
- transition: { duration: 0.6, delay, ease: "easeOut" },
1300
- });
395
+ Pricing logic: Base price by service type + per-page rate + add-on costs + timeline multiplier. All prices formatted with .toLocaleString().
396
+ ${W}`},{id:"skyelite-hero",title:"Silver Lining",category:"Landing Page",prompt:`Create a premium, light-themed hero section.
1301
397
 
1302
- Page Structure (top to bottom)
1303
- 1. Navbar (fixed, transparent)
1304
- Left: Logo (concentric circles icon \u2014 outer w-7 h-7 with border-2 border-foreground/60, inner w-3 h-3 with border border-foreground/60) + "Mindloop" bold text.
1305
- Center-left: Nav links ["Home", "How It Works", "Philosophy", "Use Cases"] separated by \u2022 dots. Links are text-muted-foreground hover:text-foreground.
1306
- Right: 3 social icons (Instagram, Linkedin, Twitter from lucide-react) in liquid-glass circular buttons (w-10 h-10 rounded-full).
1307
- No background \u2014 fully transparent, fixed top-0 z-50, padding px-8 md:px-28 py-4.
1308
-
1309
- 2. Hero Section (full viewport height)
1310
- Background: autoplaying looping muted MP4 video covering the entire section.
1311
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260325_120549_0cd82c36-56b3-4dd9-b190-069cfc3a623f.mp4
1312
- Bottom gradient: h-64 bg-gradient-to-t from-background to-transparent for smooth fade to black.
1313
- Content (centered, z-10, pt-28 md:pt-32):
1314
- Avatar row: 3 overlapping circular avatars (-space-x-2, w-8 h-8 rounded-full border-2 border-background) + "7,000+ people already subscribed" in text-muted-foreground text-sm.
1315
- Heading: text-5xl md:text-7xl lg:text-8xl font-medium tracking-[-2px] \u2014 "Get Inspired with Us" where "Inspired" is font-serif italic font-normal.
1316
- Subtitle: text-lg in hsl(var(--hero-subtitle)) color \u2014 "Join our feed for meaningful updates, news around technology and a shared journey toward depth and direction."
1317
- Email form: liquid-glass rounded-full p-2 max-w-lg container with email input and a white bg-foreground text-background rounded-full px-8 py-3 "SUBSCRIBE" button with whileHover scale 1.03 and whileTap scale 0.98.
1318
-
1319
- 3. "Search has changed" Section
1320
- Top padding pt-52 md:pt-64, bottom padding pb-6 md:pb-9.
1321
- Heading: text-5xl md:text-7xl lg:text-8xl \u2014 "Search has changed. Have you?" with "changed." in serif italic.
1322
- Subtitle: text-muted-foreground text-lg max-w-2xl mx-auto mb-24.
1323
- 3 platform cards (grid md:grid-cols-3 gap-12 md:gap-8 mb-20): Each card has a 200x200 icon image centered, platform name (font-semibold text-base), and description (text-muted-foreground text-sm).
1324
- ChatGPT icon: local asset icon-chatgpt.png
1325
- Perplexity icon: local asset icon-perplexity.png
1326
- Google AI icon: local asset icon-google.png
1327
- Bottom tagline: "If you don't answer the questions, someone else will." in text-muted-foreground text-sm text-center.
1328
-
1329
- 4. Mission Section
1330
- Padding pt-0 pb-32 md:pb-44.
1331
- Video: Large 800x800 looping autoplaying muted video centered.
1332
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260325_132944_a0d124bb-eaa1-4082-aa30-2310efb42b4b.mp4
1333
- Scroll-driven word-by-word reveal using useScroll and useTransform from framer-motion:
1334
- Paragraph 1 (text-2xl md:text-4xl lg:text-5xl font-medium tracking-[-1px]): "We're building a space where curiosity meets clarity \u2014 where readers find depth, writers find reach, and every newsletter becomes a conversation worth having." Words "curiosity", "meets", "clarity" are highlighted in --foreground, rest in --hero-subtitle.
1335
- Paragraph 2 (text-xl md:text-2xl lg:text-3xl font-medium mt-10): "A platform where content, community, and insight flow together \u2014 with less noise, less friction, and more meaning for everyone involved."
1336
- Each word transitions opacity from 0.15 to 1 based on scroll progress.
1337
-
1338
- 5. Solution Section
1339
- Padding py-32 md:py-44, border-t border-border/30.
1340
- Label: "SOLUTION" in text-xs tracking-[3px] uppercase text-muted-foreground.
1341
- Heading: text-4xl md:text-6xl \u2014 "The platform for meaningful content" (serif italic on "meaningful").
1342
- Video: Rounded rounded-2xl, aspect-[3/1] object-cover.
1343
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260325_125119_8e5ae31c-0021-4396-bc08-f7aebeb877a2.mp4
1344
- 4-column feature grid (md:grid-cols-4 gap-8): Curated Feed, Writer Tools, Community, Distribution \u2014 each with title (font-semibold text-base) and description (text-muted-foreground text-sm).
1345
-
1346
- 6. CTA Section
1347
- Padding py-32 md:py-44, border-t border-border/30, overflow-hidden.
1348
- Background video (HLS via hls.js): absolute inset-0 object-cover z-0.
1349
- HLS URL: https://stream.mux.com/8wrHPCX2dC3msyYU9ObwqNdm00u3ViXvOSHUMRYSEe5Q.m3u8
1350
- Uses Hls.isSupported() check with fallback to native HLS for Safari.
1351
- Overlay: absolute inset-0 bg-background/45 z-[1].
1352
- Content (z-10, centered):
1353
- Concentric circles logo icon (w-10 h-10 outer, w-5 h-5 inner).
1354
- Heading: "Start Your Journey" (serif italic).
1355
- Subtitle in text-muted-foreground.
1356
- Two buttons: "Subscribe Now" (bg-foreground text-background rounded-lg px-8 py-3.5) and "Start Writing" (liquid-glass rounded-lg).
1357
-
1358
- 7. Footer
1359
- Simple py-12 px-8 md:px-28 footer.
1360
- Left: "\xA9 2026 Mindloop. All rights reserved." in text-muted-foreground text-sm.
1361
- Right: Privacy, Terms, Contact links in text-muted-foreground text-sm hover:text-foreground.
1362
-
1363
- Key Dependencies
1364
- framer-motion for all animations
1365
- hls.js for the CTA background video streaming
1366
- @fontsource/inter (400, 500, 600, 700)
1367
- @fontsource/instrument-serif (400, 400-italic)
1368
- lucide-react for icons
1369
- tailwindcss-animate plugin
1370
-
1371
- Assets Needed
1372
- 3 avatar images (avatar-1.png, avatar-2.png, avatar-3.png)
1373
- 3 platform icons (icon-chatgpt.png, icon-perplexity.png, icon-google.png)`},{id:"neuralyn-hero",title:"Prism Dashboard",category:"SaaS",prompt:`Create a dark landing page for "Neuralyn" \u2014 an analytics dashboard SaaS. Use React + Vite + Tailwind CSS + TypeScript + Framer Motion + shadcn/ui.
1374
-
1375
- Fonts
1376
- Inter (400, 500, 600, 700) for body/UI via @fontsource/inter
1377
- Instrument Serif (400, 400-italic) for the italic accent word via @fontsource/instrument-serif
1378
-
1379
- Color Theme (all HSL, dark mode by default in :root)
1380
- Background: 0 0% 0% (pure black)
1381
- Foreground: 0 0% 100% (pure white)
1382
- Muted foreground: 0 0% 65%
1383
- Card: 0 0% 5%
1384
- Border: 0 0% 20%
1385
- Hero subtitle: 210 17% 95%
1386
-
1387
- Page Structure
1388
- Section 1: Hero (full viewport height, overflow-hidden)
1389
-
1390
- Navbar \u2014 horizontal, padded px-8 md:px-28 py-4:
1391
-
1392
- Left: Logo image + "Neuralyn" text (text-xl font-bold tracking-tight) + nav links (Home, Services with ChevronDown icon, Reviews, Contact us) \u2014 links hidden on mobile, gap-1 between links, gap-12 md:gap-20 between logo and links
1393
- Right: "Sign In" button \u2014 solid white background (bg-foreground), black text (text-background), rounded-lg text-sm font-semibold, hover opacity transition
1394
-
1395
- Hero Content \u2014 centered column, mt-16 md:mt-20 px-4:
1396
-
1397
- Tag pill: A "liquid glass" styled pill (liquid-glass class) with inner "New" badge (white bg, black text, rounded-md text-sm font-medium px-2 py-0.5) + "Say Hello to Corewave v3.2" in text-sm font-medium text-muted-foreground. Pill has px-3 py-2 rounded-lg mb-6.
1398
- Title: text-5xl md:text-7xl, tracking-[-2px], font-medium, leading-tight md:leading-[1.15] mb-3. Text: "Your Insights." / "One Clear Overview." \u2014 the word "Overview" is in Instrument Serif italic (font-serif italic font-normal)
1399
- Subtitle: text-lg font-normal leading-6 opacity-90 mb-8, color uses CSS variable --hero-subtitle. Text: "Neuralyn helps teams track metrics, goals, and progress with precision." with a <br/> after "goals,"
1400
- CTA Button: "Get Started for Free" \u2014 solid white (bg-foreground text-background), rounded-full px-8 py-3.5 text-base font-medium, whileHover: scale 1.03, whileTap: scale 0.98
1401
-
1402
- Dashboard + Video Area \u2014 full viewport width using w-screen with marginLeft: calc(-50vw + 50%) trick, aspect-ratio: 16/9, positioned relative:
1403
-
1404
- Background video: <video>, absolutely positioned inset-0 w-full h-full object-cover. URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260307_083826_e938b29f-a43a-41ec-a153-3d4730578ab8.mp4
1405
- Dashboard image: Absolutely positioned, centered, max-w-5xl w-[90%] rounded-2xl, mixBlendMode: "luminosity". Has parallax scroll (y: 0\u2192-250).
1406
- Bottom gradient fade: Absolutely positioned at bottom of section, h-40, gradient from background to transparent, z-30, pointer-events-none.
1407
-
1408
- Parallax Scroll Effects (Framer Motion useScroll({ target: sectionRef, offset: ["start start", "end start"] }) + useTransform):
1409
-
1410
- Hero text content group: y: [0, -200] and opacity: [1, 0] (fades over first 50% of scroll)
1411
- Dashboard image: y: [0, -250]
1412
-
1413
- Entrance Animations: Staggered initial={{ opacity: 0, y }} / animate={{ opacity: 1, y: 0 }}:
1414
-
1415
- Tag pill: y: 10, duration 0.5s, delay 0
1416
- Title: y: 20, duration 0.6s, delay 0.1
1417
- Subtitle: y: 20, duration 0.6s, delay 0.2
1418
- CTA: y: 20, duration 0.6s, delay 0.3
1419
- Dashboard area: y: 40, duration 0.8s, delay 0.4
1420
-
1421
- Liquid Glass CSS
1422
-
1423
- .liquid-glass {
1424
- background: rgba(255, 255, 255, 0.01);
1425
- background-blend-mode: luminosity;
1426
- backdrop-filter: blur(4px);
1427
- -webkit-backdrop-filter: blur(4px);
1428
- border: none;
1429
- box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);
1430
- position: relative;
1431
- overflow: hidden;
1432
- }
1433
- .liquid-glass::before {
1434
- content: '';
1435
- position: absolute;
1436
- inset: 0;
1437
- border-radius: inherit;
1438
- padding: 1.4px;
1439
- background: linear-gradient(180deg,
1440
- rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%,
1441
- rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%,
1442
- rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%);
1443
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1444
- -webkit-mask-composite: xor;
1445
- mask-composite: exclude;
1446
- pointer-events: none;
1447
- }
398
+ Background: Subtle gradient using the primary color at 3% opacity over bg-background.
1448
399
 
1449
- Section 2: Testimonial (min-h-screen, centered, py-24 md:py-32 px-8 md:px-28)
1450
-
1451
- Quote symbol image (w-14 h-10 object-contain)
1452
- Testimonial text (text-4xl md:text-5xl font-medium leading-[1.2], wrapped in flex flex-wrap): "Neuralyn revolutionized how we handle financial insights using smart analytics. We are now driving better outcomes quicker than we ever imagined! Neuralyn revolutionized how we handle financial insights using smart analytics."
1453
- Scroll-driven word reveal: Each word is a <motion.span> with mr-[0.3em]. Uses useScroll({ target: containerRef, offset: ["start end", "end center"] }). Each word maps to a sequential range [i/total, (i+1)/total] \u2192 opacity: [0.2, 1] and color: ["hsl(0 0% 35%)", "hsl(0 0% 100%)"].
1454
- Closing " quotation mark in text-muted-foreground ml-2
1455
- Author row (flex items-center gap-4): Avatar image (w-14 h-14 rounded-full border-[3px] border-foreground object-cover) + name "Brooklyn Simmons" (text-base font-semibold leading-7 text-foreground) + role "Product Manager" (text-sm font-normal leading-5 text-muted-foreground)
1456
- Layout: max-w-3xl mx-auto, content left-aligned (items-start), gap-10 between elements
1457
-
1458
- Assets needed:
1459
- logo.png \u2014 small logo icon
1460
- hero-dashboard.png \u2014 dashboard screenshot
1461
- quote-symbol.png \u2014 decorative quote mark
1462
- testimonial-avatar.png \u2014 circular headshot`},{id:"nexora-hero",title:"Daylight SaaS",category:"SaaS",prompt:`Create a SaaS landing page hero section with the following exact specifications:
1463
-
1464
- Page Layout
1465
-
1466
- The entire page is h-screen flex flex-col bg-background overflow-hidden \u2014 the Navbar + Hero fill exactly 100vh with no scroll.
1467
- The page uses two Google Fonts imported via CSS: Instrument Serif (display/headings, including italic) and Inter (body text).
1468
- Fonts & Design Tokens (index.css)
1469
-
1470
- Import fonts:
1471
-
1472
- @import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@400;500;600&display=swap');
1473
- CSS variables (:root):
1474
-
1475
- --background: 0 0% 100% (white)
1476
- --foreground: 210 14% 17% (dark charcoal)
1477
- --primary: 210 14% 17% / --primary-foreground: 0 0% 100%
1478
- --secondary: 0 0% 96% / --secondary-foreground: 0 0% 9%
1479
- --muted: 0 0% 96% / --muted-foreground: 184 5% 55%
1480
- --accent: 239 84% 67% (indigo/blue) / --accent-foreground: 0 0% 100%
1481
- --border: 0 0% 90%
1482
- --ring: 239 84% 67%
1483
- --radius: 0.5rem
1484
- --font-display: 'Instrument Serif', serif
1485
- --font-body: 'Inter', sans-serif
1486
- --shadow-dashboard: 0 25px 80px -12px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.06)
1487
- Tailwind config extends fontFamily with display and body mapped to the CSS vars. All colors use hsl(var(--token)) pattern.
1488
-
1489
- Navbar
1490
-
1491
- flex items-center justify-between px-6 md:px-12 lg:px-20 py-5 font-body
1492
- Left: Logo text \u2726 Nexora \u2014 text-xl font-semibold tracking-tight text-foreground
1493
- Right (hidden on mobile): Nav links "Home", "Pricing", "About", "Contact" \u2014 text-sm text-muted-foreground hover:text-foreground with gap-8
1494
- CTA button: rounded-full px-5 text-sm font-medium using primary styling
1495
- Hero Section
1496
-
1497
-
1498
-
1499
-
1500
- Background Video: Fullscreen muted autoplay loop video, absolute inset-0 w-full h-full object-cover z-0
1501
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260319_015952_e1deeb12-8fb7-4071-a42a-60779fc64ab6.mp4
1502
- All content wrapped in relative z-10 flex flex-col items-center w-full
1503
- 1. Badge (top)
1504
-
1505
- Framer Motion: fade up from y:10, duration 0.5s
1506
- inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-4 py-1.5 text-sm text-muted-foreground font-body
1507
- Text: "Now with GPT-5 support \u2728"
1508
- mb-6
1509
- 2. Headline
1510
-
1511
- Framer Motion: fade up from y:16, duration 0.6s, delay 0.1s
1512
- text-center font-display text-5xl md:text-6xl lg:text-[5rem] leading-[0.95] tracking-tight text-foreground max-w-xl
1513
- Content: The Future of Smarter Automation \u2014 the word "Smarter" renders in Instrument Serif italic
1514
- 3. Subheadline
1515
-
1516
- Framer Motion: fade up from y:16, duration 0.6s, delay 0.2s
1517
- mt-4 text-center text-base md:text-lg text-muted-foreground max-w-[650px] leading-relaxed font-body
1518
- Text: "Automate your busywork with intelligent agents that learn, adapt, and execute\u2014so your team can focus on what matters most."
1519
- 4. CTA Buttons
1520
-
1521
- Framer Motion: fade up from y:16, duration 0.6s, delay 0.3s
1522
- mt-5 flex items-center gap-3
1523
- Primary button: rounded-full px-6 py-5 text-sm font-medium font-body \u2014 text "Book a demo"
1524
- Play button: ghost variant, h-11 w-11 rounded-full border-0 bg-background shadow-[0_2px_12px_rgba(0,0,0,0.08)] hover:bg-background/80 with a Play icon (lucide) h-4 w-4 fill-foreground
1525
- 5. Dashboard Preview (custom coded, NOT an image)
1526
-
1527
- Framer Motion: fade up from y:30, duration 0.8s, delay 0.5s
1528
- Container: mt-8 w-full max-w-5xl
1529
- Frosted glass wrapper: rounded-2xl overflow-hidden p-3 md:p-4 with inline styles:
1530
- background: rgba(255, 255, 255, 0.4)
1531
- border: 1px solid rgba(255, 255, 255, 0.5)
1532
- boxShadow: var(--shadow-dashboard)
1533
- Dashboard internals (all coded in React, text-[11px], select-none pointer-events-none):
1534
-
1535
- Top bar: Logo "N" in rounded box + "Nexora" + chevron | Search bar with \u2318K shortcut | "Move Money" + bell + avatar "JB"
1536
- Sidebar (w-40): Items \u2014 Home (active), Tasks (badge "10"), Transactions, Payments (chevron), Cards, Capital, Accounts (chevron). Section "Workflows": Trake rutes, Payments, Notifications, Settings
1537
- Main content (bg-secondary/30):
1538
- Greeting: "Welcome, Jane" \u2014 text-sm font-semibold
1539
- Action buttons row: Send (primary/accent), Request, Transfer, Deposit, Pay Bill, Create Invoice \u2014 rounded-full pill buttons text-[10px], + "Customize" text
1540
- Two equal-width cards (flex-1 basis-0) side by side:
1541
- Balance card: "Mercury Balance" with checkmark, amount $8,450,190.32 (cents in text-xs text-muted-foreground), stats (Last 30 Days, +$1.8M green, -$900K red), SVG area chart (h-20) with smooth cubic B\xE9zier curve, linear gradient fill from accent at 15% opacity to transparent, stroke in accent color strokeWidth="1.5"
1542
- Accounts card: Header "Accounts" with + and \u22EE icons. Three rows (py-3, no dividers, text-xs, justify-between): Credit $98,125.50, Treasury $6,750,200.00, Operations $1,592,864.82
1543
- Transactions table: "Recent Transactions" heading, table with columns Date/Description/Amount/Status. 4 rows: AWS -$5,200 Pending (amber), Client Payment +$125,000 Completed (green), Payroll -$85,450 Completed, Office Supplies -$1,200 Completed
1544
- Dependencies
1545
-
1546
- framer-motion for all animations
1547
- lucide-react for all icons
1548
- shadcn/ui Button component
1549
- Tailwind CSS with tailwindcss-animate plugin
1550
- Key Design Decisions
1551
-
1552
- The dashboard overflows toward the bottom of the viewport and is clipped by overflow-hidden on the parent
1553
- No dark mode \u2014 light only
1554
- All colors use semantic Tailwind tokens, never raw color values in components
1555
- The SVG chart uses a hand-crafted cubic B\xE9zier path, not a charting library`},{id:"portfolio-cosmic-hero",title:"Stellar Folio",category:"Portfolio",prompt:`Prompt to recreate this landing page:
1556
-
1557
- Build a single-page dark portfolio landing page using React + Vite + Tailwind CSS + TypeScript + GSAP + Framer Motion + hls.js.
400
+ Navigation: Brand name left (text-2xl, font-semibold). Desktop nav links (text-foreground, hover:text-muted-foreground). Mobile hamburger menu with bg-background/95 backdrop-blur dropdown.
1558
401
 
1559
- ---
402
+ Hero Content: Centered with negative top margin (-mt-80 to pull into the background area).
403
+ - Small uppercase label: text-sm, font-semibold, text-muted-foreground, tracking-wider.
404
+ - Large two-line heading with overlapping effect:
405
+ - Line 1: text-6xl to text-8xl, font-normal, text-muted-foreground, leading-none, tracking-tighter.
406
+ - Line 2: Same size but text-foreground, negative margin-top (-12px) for overlap.
407
+ - Subtitle: text-lg to text-xl, text-muted-foreground, max-w-2xl.
408
+ - Two pill CTAs: "Discover" (bg-muted text-foreground) + "Book Now" (bg-foreground text-background).
1560
409
 
1561
- ## Global Design System
410
+ Clean, modern, premium. min-h-screen.
411
+ ${W}`},{id:"taskly-hero",title:"Skyline",category:"Hero Section",prompt:`Create a light hero section with liquid glass navbar and gradient glow background.
1562
412
 
1563
- ### Fonts
1564
- Google Fonts import: Inter (300\u2013700) and Instrument Serif (italic, 400).
1565
- - --font-body: 'Inter', sans-serif \u2192 Tailwind font-body
1566
- - --font-display: 'Instrument Serif', serif \u2192 Tailwind font-display
413
+ Layout: max-w-[1600px], dual-column (stacked on mobile).
1567
414
 
1568
- ### CSS Custom Properties (HSL, no hsl() wrapper \u2014 Tailwind adds it)
1569
- --bg: 0 0% 4%;
1570
- --surface: 0 0% 8%;
1571
- --text: 0 0% 96%;
1572
- --muted: 0 0% 53%;
1573
- --stroke: 0 0% 12%;
1574
- --accent: 0 0% 96%;
415
+ Background: White/light base with layered gradient glow in top-left corner. Use 2 blurred ellipses (w-[600px], h-[600px]) with primary color at 15% and 10% opacity. Positioned absolute, pointer-events-none.
1575
416
 
1576
- ### Tailwind Custom Colors
1577
- bg: "hsl(var(--bg))",
1578
- surface: "hsl(var(--surface))",
1579
- "text-primary": "hsl(var(--text))",
1580
- muted: "hsl(var(--muted))",
1581
- stroke: "hsl(var(--stroke))",
417
+ Liquid Glass Navbar: Sticky at top-[30px], centered, w-fit. backdrop-blur-[50px], bg-background/30, rounded-[16px]. 1px border at foreground/10. Inner highlight shadow. Logo + nav links + glass "SignUp" button.
1582
418
 
1583
- ### Accent Gradient
1584
- linear-gradient(90deg, #89AACC 0%, #4E85BF 100%) \u2014 used on logo ring, hover borders, progress bars. CSS utility class .accent-gradient.
419
+ Hero Left:
420
+ - Social proof badge: Star icons + "Rated 4.9/5 by 2700+ customers".
421
+ - Headline: 75px, line-height 1.05, tracking -2px. Bold body font.
422
+ - Subheadline: 18px, tracking -1px.
423
+ - Primary CTA: bg-primary/80 with backdrop-blur-[2px]. rounded-[16px]. Inner highlight shadow. White circular arrow icon. Scale 1.02 on hover.
1585
424
 
1586
- ### Custom Animations (in index.css)
1587
- - @keyframes scroll-down \u2014 translateY(-100%) \u2192 translateY(200%), 1.5s ease-in-out infinite
1588
- - @keyframes role-fade-in \u2014 opacity 0 + translateY(8px) \u2192 opacity 1 + translateY(0), 0.4s ease-out
1589
- - @keyframes gradient-shift \u2014 background-position 0% 50% \u2192 100% 50% \u2192 0% 50%, 6s ease infinite (for animated gradient borders)
425
+ Hero Right: Decorative abstract element. Use a CSS-only gradient orb: large rounded div (400-500px) with radial-gradient using primary color, blur-[100px], mix-blend-screen to create a floating glow effect. Scale 1.25, slightly off-center.
1590
426
 
1591
- ### Forced dark theme \u2014 no light mode toggle. body gets bg-bg text-text-primary.
427
+ Footer Logos: 5 grayscale placeholder logos at gap-[100px].
428
+ ${W}`},{id:"velorah-hero",title:"Navy Serif",category:"Agency",prompt:`Create a cinematic hero section with serif typography and liquid glass buttons.
1592
429
 
1593
- ---
430
+ Background: Dark mesh gradient. Use radial-gradient blobs with primary color at 5% opacity over bg-background.
1594
431
 
1595
- ## Page Structure (Index.tsx)
432
+ Liquid Glass CSS: Define .liquid-glass class with backdrop-filter blur(4px), subtle box-shadow, gradient border via ::before pseudo-element.
1596
433
 
1597
- {isLoading && <LoadingScreen onComplete={() => setIsLoading(false)} />}
434
+ Navigation: z-10, flex row, justify-between, max-w-7xl. Logo with registered trademark symbol in serif style. Nav links: first active (text-foreground), rest text-muted-foreground. CTA: liquid-glass rounded-full, hover:scale-[1.03].
1598
435
 
1599
- ---
436
+ Hero Section: z-10, centered, text-center, px-6, generous vertical padding.
437
+ - H1: text-5xl to text-8xl. Serif font style. leading-[0.95], tracking-[-2.46px]. Certain words/phrases wrapped in text-muted-foreground for color contrast (e.g. "dreams" and "through the silence").
438
+ - Subtext: text-muted-foreground, text-base to text-lg, max-w-2xl, mt-8.
439
+ - CTA: liquid-glass rounded-full, px-14 py-5, hover:scale-[1.03].
1600
440
 
1601
- ## Section 1: Loading Screen
441
+ Animations (CSS keyframes):
442
+ - fade-rise: opacity 0 to 1, translateY(24px) to 0, 0.8s ease-out.
443
+ - Staggered: h1 (0s), subtext (0.2s delay), CTA (0.4s delay).
1602
444
 
1603
- Full-screen overlay (fixed inset-0 z-[9999] bg-bg). Uses requestAnimationFrame counter from 000\u2192100 over 2700ms.
1604
-
1605
- - Top-left: "Portfolio" label \u2014 text-xs text-muted uppercase tracking-[0.3em]. Animates y:-20\u21920, opacity 0\u21921.
1606
- - Center: Rotating words ["Design", "Create", "Inspire"] cycling every 900ms. AnimatePresence mode="wait" with y:20\u21920\u2192-20 transitions. text-4xl md:text-6xl lg:text-7xl font-display italic text-text-primary/80.
1607
- - Bottom-right: Counter display \u2014 text-6xl md:text-8xl lg:text-9xl font-display text-text-primary tabular-nums. Shows String(count).padStart(3, "0").
1608
- - Bottom progress bar: h-[3px] bg-stroke/50, inner div with .accent-gradient, scaleX(count/100) transform, box-shadow: 0 0 8px rgba(137, 170, 204, 0.35).
1609
- - On complete (count reaches 100): 400ms delay then calls onComplete.
1610
-
1611
- ---
1612
-
1613
- ## Section 2: Hero
1614
-
1615
- Full-viewport section with background HLS video and centered content.
1616
-
1617
- ### Background Video
1618
- - HLS source: https://stream.mux.com/Aa02T7oM1wH5Mk5EEVDYhbZ1ChcdhRsS2m1NYyx4Ua1g.m3u8
1619
- - Uses hls.js \u2014 if Hls.isSupported(), create HLS instance; else if native HLS support, set video.src directly.
1620
- - Video: autoPlay muted loop playsInline, absolutely positioned and centered with min-w-full min-h-full object-cover -translate-x-1/2 -translate-y-1/2.
1621
- - Dark overlay: bg-black/20
1622
- - Bottom fade: h-48 bg-gradient-to-t from-bg to-transparent
1623
-
1624
- ### Navbar (fixed, floats at top center)
1625
- fixed top-0 left-0 right-0 z-50 flex justify-center pt-4 md:pt-6 px-4.
1626
-
1627
- Inner pill: inline-flex items-center rounded-full backdrop-blur-md border border-white/10 bg-surface px-2 py-2. Gets shadow-md shadow-black/10 when scrollY > 100.
1628
-
1629
- Contents (left to right):
1630
- 1. Logo: 9\xD79 circle with accent gradient border (reverses direction on hover). Inner bg-bg circle with "JA" in font-display italic text-[13px]. Scales 110% on hover.
1631
- 2. Divider: w-px h-5 bg-stroke mx-1 (hidden on mobile)
1632
- 3. Nav links: ["Home", "Work", "Resume"] \u2014 text-xs sm:text-sm rounded-full px-3 sm:px-4 py-1.5 sm:py-2. Active: text-text-primary bg-stroke/50. Inactive: text-muted hover:text-text-primary hover:bg-stroke/50.
1633
- 4. Divider
1634
- 5. "Say hi" button: Same size as nav links. On hover, shows accent gradient border behind (using absolute span with inset: -2px). Inner content wrapped in bg-surface rounded-full backdrop-blur-md. Includes "\u2197" arrow.
1635
-
1636
- ### Hero Content (centered, z-10)
1637
- - Eyebrow: text-xs text-muted uppercase tracking-[0.3em] mb-8 \u2014 "COLLECTION '26". Class blur-in.
1638
- - Name: text-6xl md:text-8xl lg:text-9xl font-display italic leading-[0.9] tracking-tight text-text-primary mb-6 \u2014 "Michael Smith". Class name-reveal.
1639
- - Role line: "A {role} lives in Chicago." \u2014 roles cycle every 2s through ["Creative", "Fullstack", "Founder", "Scholar"]. Role word uses font-display italic text-text-primary animate-role-fade-in inline-block with key={roleIndex} for re-triggering animation.
1640
- - Description: text-sm md:text-base text-muted max-w-md mb-12 \u2014 "Designing seamless digital interactions by focusing on the unique nuances which bring systems to life."
1641
- - CTA Buttons (inline-flex gap-4):
1642
- - "See Works": Solid button. Default: bg-text-primary text-bg. Hover: bg-bg text-text-primary with accent gradient border ring.
1643
- - "Reach out...": Outlined button. Default: border-2 border-stroke bg-bg text-text-primary. Hover: border-transparent with accent gradient border ring.
1644
- - Both: rounded-full text-sm px-7 py-3.5 hover:scale-105.
1645
-
1646
- ### GSAP Entrance
1647
- Timeline with ease: "power3.out":
1648
- - .name-reveal: opacity 0\u21921, y 50\u21920, duration 1.2s, delay 0.1s
1649
- - .blur-in: opacity 0\u21921, filter blur(10px)\u2192blur(0px), y 20\u21920, duration 1s, stagger 0.1, delay 0.3s
1650
-
1651
- ### Scroll Indicator
1652
- Bottom-center, text-xs text-muted uppercase tracking-[0.2em] "SCROLL" label above a w-px h-10 bg-stroke line with animated highlight using .animate-scroll-down.
1653
-
1654
- ---
1655
-
1656
- ## Section 3: Selected Works
1657
-
1658
- bg-bg py-12 md:py-16. Inner: max-w-[1200px] mx-auto px-6 md:px-10 lg:px-16.
1659
-
1660
- ### Header
1661
- Framer Motion whileInView \u2014 opacity 0\u21921, y 30\u21920, duration 1s, ease [0.25,0.1,0.25,1], viewport once margin "-100px".
1662
- - Eyebrow: w-8 h-px bg-stroke + "Selected Work" text-xs text-muted uppercase tracking-[0.3em]
1663
- - Heading: "Featured *projects*" \u2014 italic word in font-display italic
1664
- - Subtext: "A selection of projects I've worked on, from concept to launch."
1665
- - "View all work" button (desktop only, hidden md:inline-flex) \u2014 rounded-full with gradient hover border ring + right arrow
1666
-
1667
- ### Bento Grid
1668
- grid grid-cols-1 md:grid-cols-12 gap-5 md:gap-6. Column spans alternate: 7/5/5/7.
1669
-
1670
- 4 project cards with titles: Automotive Motion, Urban Architecture, Human Perspective, Brand Identity.
1671
-
1672
- Each card: bg-surface border border-stroke rounded-3xl with aspect ratios. Contains:
1673
- - Background image with object-cover group-hover:scale-105
1674
- - Halftone overlay: radial-gradient(circle, #000 1px, transparent 1px) at 4\xD74px, opacity-20 mix-blend-multiply
1675
- - Hover: bg-bg/70 opacity-0\u21921 + backdrop-blur-lg
1676
- - Hover label: pill with animated gradient border, white bg, "View \u2014 *Title*" (title in font-display italic)
1677
-
1678
- ---
1679
-
1680
- ## Section 4: Journal
1681
-
1682
- bg-bg py-16 md:py-24. Same header pattern (eyebrow + "Recent *thoughts*" + subtext + "View all" button).
1683
-
1684
- 4 journal entries displayed as horizontal pills (rounded-[40px] sm:rounded-full) with titles, images, read times, and dates.
1685
-
1686
- Each entry: flex items-center gap-6 p-4 bg-surface/30 hover:bg-surface border border-stroke.
1687
-
1688
- ---
1689
-
1690
- ## Section 5: Explorations (Parallax Gallery)
1691
-
1692
- min-h-[300vh] section for scroll-driven parallax.
1693
-
1694
- ### Layer 1: Pinned Center (z-10)
1695
- h-screen div pinned with GSAP ScrollTrigger.create({ pin: contentRef, pinSpacing: false }).
1696
- - Eyebrow: "Explorations"
1697
- - Heading: "Visual *playground*"
1698
- - Subtext + Dribbble button
1699
-
1700
- ### Layer 2: Parallax Columns (z-20, absolute)
1701
- grid grid-cols-2 gap-12 md:gap-40 inside max-w-[1400px].
1702
-
1703
- 6 items split into 2 columns with GSAP scroll-driven parallax movement.
1704
- Cards: aspect-square max-w-[320px], with rotation and lightbox on click.
1705
-
1706
- ---
1707
-
1708
- ## Section 6: Stats
1709
-
1710
- bg-bg py-16 md:py-24. 3-column grid with stats: 20+ Years Experience, 95+ Projects Done, 200% Satisfied Clients.
1711
-
1712
- ---
1713
-
1714
- ## Section 7: Contact / Footer
1715
-
1716
- bg-bg pt-16 md:pt-20 pb-8 md:pb-12 overflow-hidden.
1717
-
1718
- ### Background Video
1719
- Same HLS source as hero, but flipped vertically (scale-y-[-1]). Heavier overlay: bg-black/60.
1720
-
1721
- ### GSAP Marquee
1722
- "BUILDING THE FUTURE \u2022 " repeated 10\xD7. GSAP xPercent: -50, duration 40, ease "none", repeat -1.
1723
-
1724
- ### CTA
1725
- Email button: mailto:hello@michaelsmith.com with gradient hover border ring.
1726
-
1727
- ### Footer Bar
1728
- Social links [Twitter, LinkedIn, Dribbble, GitHub] + Green pulsing dot + "Available for projects"
1729
-
1730
- ---
1731
-
1732
- ## Dependencies
1733
- gsap, framer-motion, hls.js, react-router-dom, tailwindcss-animate
1734
-
1735
- Add smooth scroll nav and page transitions.`},{id:"power-ai-hero",title:"Spectrum AI",category:"Hero Section",prompt:`Create a full-screen dark hero section with a looping background video, navbar, headline, subtitle, CTA button, and a logo marquee at the bottom. Here are the exact specifications:
1736
-
1737
- Theme & Colors (index.css CSS variables):
1738
- Background: 260 87% 3% (deep dark blue-purple)
1739
- Foreground: 40 6% 95% (off-white)
1740
- Hero sub text: 40 6% 82%
1741
- Body font: Geist Sans (via @fontsource/geist-sans)
1742
- Headline font: General Sans (loaded from Fontshare: https://api.fontshare.com/v2/css?f[]=general-sans@400,500,600,700&display=swap)
1743
-
1744
- Background Video (Index page wrapper):
1745
- Video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260328_065045_c44942da-53c6-4804-b734-f9e07fc22e08.mp4
1746
- Positioned absolute inset-0 w-full h-full object-cover behind all content
1747
- Starts with opacity: 0
1748
- Custom JS-controlled fade loop: 0.5s fade-in at start, 0.5s fade-out at end, using requestAnimationFrame. On ended, opacity resets to 0, waits 100ms, then replays from 0
1749
- No gradient overlays on the video
1750
- The wrapper div has overflow-hidden, the hero content sits in a relative z-10 div above
1751
-
1752
- Blurred overlay shape (centered behind content):
1753
- w-[984px] h-[527px] opacity-90 bg-gray-950 blur-[82px]
1754
- Absolutely positioned at top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2
1755
- pointer-events-none
1756
- The hero section has overflow-visible so the blur is not clipped
1757
-
1758
- Navbar:
1759
- Full width, py-5 px-8, flex row with justify-between
1760
- Left: logo image (src/assets/logo.png, height 32px)
1761
- Center: nav items \u2014 "Features" (with ChevronDown), "Solutions", "Plans", "Learning" (with ChevronDown). Each is a button with text-foreground/90 and hover transition
1762
- Right: "Sign Up" button using heroSecondary variant, rounded-full px-4 py-2
1763
- Below navbar: a 1px divider line with gradient from-transparent via-foreground/20 to-transparent, offset mt-[3px]
1764
-
1765
- Hero content (vertically centered in remaining space via flex-1):
1766
- Headline: "Power AI" at text-[220px], font-normal, leading-[1.02], tracking-[-0.024em], font-family General Sans
1767
- "Power " is plain text-foreground
1768
- "AI" uses bg-clip-text text-transparent with backgroundImage: linear-gradient(to left, #6366f1, #a855f7, #fcd34d) (indigo \u2192 purple \u2192 amber)
1769
- Subtitle: "The most powerful AI ever deployed / in talent acquisition" \u2014 text-hero-sub, text-lg, leading-8, max-w-md, mt-[9px], opacity-80
1770
- CTA: "Schedule a Consult" button, heroSecondary variant, px-[29px] py-[24px], mt-[25px]
1771
-
1772
- Logo marquee (pinned to bottom of hero, pb-10):
1773
- Container: max-w-5xl mx-auto
1774
- Left side: static text "Relied on by brands / across the globe" in text-foreground/50 text-sm
1775
- Right side: infinite scrolling marquee with logos: Vortex, Nimbus, Prysma, Cirrus, Kynder, Halcyn (duplicated for seamless loop)
1776
- Each logo: a liquid-glass 24x24 rounded-lg icon showing the first letter, plus the name in text-base font-semibold text-foreground
1777
- Marquee animation: translateX(0%) \u2192 translateX(-50%), 20s linear infinite
1778
- gap-16 between logos, gap-12 between text and marquee
1779
-
1780
- Liquid glass utility class (in index.css):
1781
- .liquid-glass { background: rgba(255, 255, 255, 0.01); background-blend-mode: luminosity; backdrop-filter: blur(4px); border: none; box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1); position: relative; overflow: hidden; }
1782
- .liquid-glass::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1.4px; background: linear-gradient(180deg, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%, rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%, rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; }
1783
-
1784
- Section structure: min-h-screen flex flex-col \u2014 navbar at top, content centered via flex-1 flex items-center justify-center, marquee at bottom.`},{id:"price-calculator",title:"Ember Pricing",category:"SaaS",prompt:`Recreate Project Estimation Calculator Section
1785
-
1786
- Create a full-width dark calculator section with id calculator-section. Background: bg-background, padding py-16 md:py-28 px-4 md:px-16, max-width max-w-7xl centered.
1787
-
1788
- Header: Centered. Small mono uppercase tracking-widest label "Try project estimation calculator" in text-muted-foreground. Below it, an h2: "Get premium website within your budget" \u2014 text-3xl md:text-4xl lg:text-5xl font-normal.
1789
-
1790
- Layout: 2-column grid (grid-cols-1 lg:grid-cols-2), rounded-2xl overflow-hidden, no gap.
1791
-
1792
- LEFT COLUMN (Calculator Form): Background #0D0D0D, padding p-8 lg:p-12, sections divided by divide-y divide-[#1E1E1E].
1793
-
1794
- 4 sections separated by horizontal dividers:
1795
-
1796
- Service Type (radio buttons): h3 "What kind of service do you need?" \u2014 3 options: "Only Design" (design), "Only Development" (development), "Design + Development" (both, default). Custom radio circles: w-5 h-5 rounded-full border-2, active = border-[#FF5656] with inner w-2 h-2 rounded-full bg-[#FF5656].
1797
-
1798
- Number of Pages (slider): h3 with current value in #FF5656. Shadcn <Slider> min=1, max=30, step=1, default=5. Labels "1" and "30" below.
1799
-
1800
- Add-ons (checkboxes): Two checkboxes with price labels on the right in #FF5656:
1801
-
1802
- "I will need help with content" \u2192 +$50/pages
1803
-
1804
- "I want to optimize my website for SEO" \u2192 +$50/pages Custom checkboxes: w-5 h-5 border-2 rounded, checked = border-[#FF5656] bg-[#FF5656] with white SVG checkmark.
1805
-
1806
- Timeline (radio buttons): h3 "How fast do you need this?" \u2014 3 options with prices:
1807
-
1808
- "Within 7 Days" \u2192 +$100/pages
1809
-
1810
- "Within 14 Days" \u2192 +$25/pages
1811
-
1812
- "Regular Speed (Based on discussion)" \u2192 no extra cost (default)
1813
-
1814
- RIGHT COLUMN (Cost Estimation): Padding p-8 lg:p-12, border border-white/10 rounded-r-2xl, min-height 717.98px.
1815
-
1816
- h3 "Estimated Cost" + description paragraph.
1817
-
1818
- 3 stacked cards (rounded-2xl p-6 space-y-3):
1819
-
1820
- Agency card: bg-muted/50. Title "Typical Agency charges minimum". Large price text-4xl font-bold. Subtitle: "+ Too much extra time & additional cost".
1821
-
1822
- Freelancer card: bg-muted/50. Title "Regular Freelancer charges minimum". Large price text-4xl font-bold. Subtitle: "+ Too much headache & back-and-forth".
1823
-
1824
- Your price card: bg-gradient-to-r from-pink-500 to-orange-500 text-white. Title "With Webfluin Studio". Price text-5xl font-bold. Subtitle: "Save your money, time & headache".
1825
-
1826
- PRICING LOGIC:
1827
-
1828
- calculatePrice():
1829
- Base prices by service:
1830
- design: base=399, perPage=100
1831
- development: base=199, perPage=100
1832
- both: base=499, perPage=200
1833
-
1834
- total = max(base, base + (pages - 1) * perPage)
1835
- if needContent: total += pages * 50
1836
- if needSEO: total += pages * 50
1837
- if rush: total += pages * 100
1838
- if fast: total += pages * 25
1839
-
1840
- calculateAgencyCost():
1841
- perPage = (both ? 1000 : 400)
1842
- return 8000 + (pages - 1) * perPage
1843
-
1844
- calculateFreelancerCost():
1845
- perPage = (both ? 500 : 200)
1846
- return 3000 + (pages - 1) * perPage
1847
-
1848
- All prices displayed with .toLocaleString() and $ prefix.
1849
-
1850
- State: serviceType (design|development|both, default both), pages (number, default 5), needContent (bool), needSEO (bool), timeline (regular|fast|rush, default regular).
1851
-
1852
- Dependencies: Shadcn Slider component, useToast hook.`},{id:"skyelite-hero",title:"Silver Lining",category:"Landing Page",prompt:`Create a premium private jet landing page hero section with the following specifications:
1853
-
1854
- Video Background:
1855
- Use this exact CloudFront video URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260328_091828_e240eb17-6edc-4129-ad9d-98678e3fd238.mp4
1856
- Video should autoplay, be muted, loop continuously, and include playsInline attribute
1857
- Video covers entire viewport (100vh) using object-cover
1858
-
1859
- Navigation Bar:
1860
- Brand name "SkyElite" on the left (text-2xl, font-semibold, text-gray-900)
1861
- Desktop menu items (hidden on mobile, visible md:flex): Start, Story, Rates, Benefits, FAQ
1862
- Navigation links in gray-900 with hover:text-gray-700 transition
1863
- Mobile hamburger menu button using Lucide React icons (Menu/X)
1864
- Mobile menu appears as dropdown with white/95 opacity background, backdrop blur, rounded corners, shadow
1865
- Max width 7xl, centered with px-8 py-6
1866
-
1867
- Hero Content (centered, -mt-80 to pull up):
1868
- Small uppercase label: "PRIVATE JETS" (text-sm, font-semibold, gray-600, tracking-wider, mb-4)
1869
- Large two-line heading with overlapping effect:
1870
- Line 1: "Premium." (text-6xl md:text-7xl lg:text-8xl, font-normal, text-gray-500, leading-none, tracking-tighter)
1871
- Line 2: "Accessible." (same size, color: #202A36, negative margin-top: -12px for overlap)
1872
- Subtitle: "Your dedication deserves recognition." (text-lg md:text-xl, gray-600, mb-6, max-w-2xl)
1873
- Two call-to-action buttons (gap-4, centered):
1874
- "Discover" button: px-4 py-2, rounded-full, bg-gray-300, text-gray-800, font-medium, hover:bg-gray-400
1875
- "Book Now" button: px-4 py-2, rounded-full, white text, bg-color #202A36, hover color #1a2229 with smooth transitions
1876
-
1877
- Typography:
1878
- Use Inter font (import from Google Fonts: 400, 500, 600, 700 weights)
1879
- Apply to entire body via CSS
1880
-
1881
- Technical Setup:
1882
- React with TypeScript
1883
- Tailwind CSS for styling
1884
- Lucide React for icons
1885
- useState hook for mobile menu toggle
1886
- Full screen height container (h-screen)
1887
- Responsive breakpoints: mobile-first, md, lg
1888
- All transitions use transition-colors class
1889
-
1890
- Layout Structure:
1891
- Outer container: min-h-screen, bg-gray-50
1892
- Hero section: relative, h-screen, overflow-hidden
1893
- Content wrapper: relative, h-full, flex flex-col
1894
- Main content area: flex-1, flex items-center justify-center
1895
-
1896
- Make it clean, modern, and premium-looking with smooth interactions.`},{id:"taskly-hero",title:"Skyline",category:"Hero Section",prompt:`System Prompt: High-Fidelity "Liquid Glass" Hero Section
1897
-
1898
- Core Layout: Create a 1600px max-width landing page hero section. The background should be pure white with a subtle, layered gradient glow in the top-left (using blurred ellipses in light blue #60B1FF and #319AFF). The design must be fully responsive, transitioning from a single-column mobile view to a dual-column desktop layout.
1899
-
1900
- Typography:
1901
-
1902
- Headlines & Brand: Use Fustat (Bold).
1903
- Body & UI: Use Inter (Normal/Medium).
1904
- Hero Headline: "Work smarter, achieve faster" (75px, 1.05 line-height, -2px tracking).
1905
-
1906
- The "Strong Liquid Glass" Navbar:
1907
-
1908
- Position: Sticky at top-[30px], centered, w-fit.
1909
- Visuals: backdrop-blur-[50px], background rgba(255,255,255,0.3), rounded-[16px].
1910
- Fidelity Details:
1911
- Outer Stroke: 1px solid rgba(0,0,0,0.1).
1912
- Inner Highlight Shadow: inset 0px 4px 4px 0px rgba(255,255,255,0.25).
1913
- Items: Logo "Taskly" (Fustat), Nav links (Home, Features, Company, Pricing), and a glassy "SignUp" button with an arrow icon.
1914
-
1915
- The Glassy Orb (Hero Right):
1916
-
1917
- Source URL: https://future.co/images/homepage/glassy-orb/orb-purple.webm
1918
- Blending Mode: Must use mix-blend-screen to filter the black background.
1919
- Scaling: scale-125 to make it massive and bleed slightly off-center.
1920
- Exact Color Grade (CSS Filter): hue-rotate(-55deg) saturate(250%) brightness(1.2) contrast(1.1). This transforms the purple asset into a vibrant, high-end "Electric Brand Blue" that matches the primary CTA.
1921
-
1922
- Hero Content (Hero Left):
1923
-
1924
- Social Proof: A "Rated 4.9/5 by 2700+ customers" badge with five orange #FF801E stars.
1925
- Subheadline: "Effortlessly manage your projects, collaborate with your team, and achieve your goals with our intuitive task management tool." (18px, Inter, -1px tracking).
1926
- Primary CTA: "Get Started Now" button.
1927
- Color: rgba(0,132,255,0.8) with backdrop-blur-[2px].
1928
- Details: rounded-[16px], white text, inner highlight shadow inset 0px 4px 4px 0px rgba(255,255,255,0.35), and a white circular arrow icon.
1929
- Animation: Scale 1.02 on hover with a smooth transition.
1930
-
1931
- Footer Logos: Include a "Trusted by Top-tier product companies" section at the bottom with 5 grayscale SVG logos (e.g., placeholder logos for tech companies) spaced at gap-[100px].
1932
-
1933
- Key Technical Specs for the Developer:
1934
-
1935
- Video Tag: autoPlay loop muted playsInline.
1936
- Container: Use a relative wrapper for the background glow and a z-10 main container for the content.
1937
- Smoothing: Apply -webkit-font-smoothing: antialiased for the sharpest typography.`},{id:"velorah-hero",title:"Navy Serif",category:"Agency",prompt:`Create a single-page hero section with a fullscreen looping background video, glassmorphic navigation, and cinematic typography. Use React + Vite + Tailwind CSS + TypeScript with shadcn/ui.
1938
-
1939
- Video Background:
1940
-
1941
- Fullscreen <video> element with autoPlay, loop, muted, playsInline
1942
- Source URL: https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260314_131748_f2ca2a28-fed7-44c8-b9a9-bd9acdd5ec31.mp4
1943
- Positioned absolute inset-0 w-full h-full object-cover z-0
1944
-
1945
- Fonts:
1946
-
1947
- Import from Google Fonts: Instrumental Serif (display) and Inter weights 400/500 (body)
1948
- CSS variables: --font-display: 'Instrument Serif', serif and --font-body: 'Inter', sans-serif
1949
- Body uses var(--font-body), headings use inline fontFamily: "'Instrument Serif', serif"
1950
-
1951
- Color Theme (dark, HSL values for CSS variables):
1952
-
1953
- --background: 201 100% 13% (deep navy blue)
1954
- --foreground: 0 0% 100% (white)
1955
- --muted-foreground: 240 4% 66% (muted gray)
1956
- --primary: 0 0% 100%, --primary-foreground: 0 0% 4%
1957
- --secondary: 0 0% 10%, --muted: 0 0% 10%, --accent: 0 0% 10%
1958
- --border: 0 0% 18%, --input: 0 0% 18%
1959
-
1960
- Navigation Bar:
1961
-
1962
- relative z-10, flex row, justify-between, px-8 py-6, max-w-7xl mx-auto
1963
- Logo: "Velorah\xAE" (\xAE as <sup className="text-xs">), text-3xl tracking-tight, Instrument Serif font, text-foreground
1964
- Nav links (hidden on mobile, md:flex): Home (active, text-foreground), Studio, About, Journal, Reach Us \u2014 all text-sm text-muted-foreground with hover:text-foreground transition-colors
1965
- CTA button: "Begin Journey", liquid-glass rounded-full px-6 py-2.5 text-sm text-foreground, hover:scale-[1.03]
1966
-
1967
- Hero Section:
1968
-
1969
- relative z-10, flex column, centered, text-center, px-6 pt-32 pb-40 py-[90px]
1970
- H1: "Where dreams rise through the silence." \u2014 text-5xl sm:text-7xl md:text-8xl, leading-[0.95], tracking-[-2.46px], max-w-7xl, font-normal, Instrument Serif. The words "dreams" and "through the silence." wrapped in <em className="not-italic text-muted-foreground"> for color contrast
1971
- Subtext: text-muted-foreground text-base sm:text-lg max-w-2xl mt-8 leading-relaxed \u2014 "We're designing tools for deep thinkers, bold creators, and quiet rebels. Amid the chaos, we build digital spaces for sharp focus and inspired work."
1972
- CTA button: "Begin Journey", liquid-glass rounded-full px-14 py-5 text-base text-foreground mt-12, hover:scale-[1.03] cursor-pointer
1973
-
1974
- Liquid Glass Effect (CSS class .liquid-glass):
1975
-
1976
- .liquid-glass {
1977
- background: rgba(255, 255, 255, 0.01);
1978
- background-blend-mode: luminosity;
1979
- backdrop-filter: blur(4px);
1980
- -webkit-backdrop-filter: blur(4px);
1981
- border: none;
1982
- box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);
1983
- position: relative;
1984
- overflow: hidden;
1985
- }
1986
- .liquid-glass::before {
1987
- content: '';
1988
- position: absolute;
1989
- inset: 0;
1990
- border-radius: inherit;
1991
- padding: 1.4px;
1992
- background: linear-gradient(180deg,
1993
- rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.15) 20%,
1994
- rgba(255,255,255,0) 40%, rgba(255,255,255,0) 60%,
1995
- rgba(255,255,255,0.15) 80%, rgba(255,255,255,0.45) 100%);
1996
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
1997
- -webkit-mask-composite: xor;
1998
- mask-composite: exclude;
1999
- pointer-events: none;
2000
- }
2001
-
2002
- Animations (CSS keyframes + classes):
2003
-
2004
- @keyframes fade-rise {
2005
- from { opacity: 0; transform: translateY(24px); }
2006
- to { opacity: 1; transform: translateY(0); }
2007
- }
2008
- .animate-fade-rise { animation: fade-rise 0.8s ease-out both; }
2009
- .animate-fade-rise-delay { animation: fade-rise 0.8s ease-out 0.2s both; }
2010
- .animate-fade-rise-delay-2 { animation: fade-rise 0.8s ease-out 0.4s both; }
2011
-
2012
- H1 gets animate-fade-rise
2013
- Subtext gets animate-fade-rise-delay
2014
- Hero CTA button gets animate-fade-rise-delay-2
2015
-
2016
- Layout: No decorative blobs, radial gradients, or overlays. Minimalist, cinematic, vertically centered hero. The video provides all visual depth.`}];function Ae(r){let e=ze.find(a=>a.id===r);if(e)return e;let t=r.toLowerCase().replace(/[^a-z0-9]/g,"");return ze.find(a=>{let n=a.title.toLowerCase().replace(/[^a-z0-9]/g,"");return n===t||n.includes(t)||t.includes(n)})}function ar(r){return jt[r]}function zt(r){return r?ze.filter(e=>e.category.toLowerCase()===r.toLowerCase()):ze}function rr(r){let e=r??ze,t={};for(let n of e){t[n.category]||(t[n.category]=[]);let o=jt[n.id],i=o?` \u2014 ${o.description}`:"";t[n.category].push(`${n.id} \u2014 "${n.title}"${i}`)}let a=[];for(let[n,o]of Object.entries(t))a.push(`**${n}**:
445
+ Minimalist: No decorative blobs, no overlays beyond the mesh gradient.
446
+ ${W}`}];function De(r){let e=ze.find(a=>a.id===r);if(e)return e;let t=r.toLowerCase().replace(/[^a-z0-9]/g,"");return ze.find(a=>{let n=a.title.toLowerCase().replace(/[^a-z0-9]/g,"");return n===t||n.includes(t)||t.includes(n)})}function nr(r){return Vt[r]}function qt(r){return r?ze.filter(e=>e.category.toLowerCase()===r.toLowerCase()):ze}function or(r){let e=r??ze,t={};for(let n of e){t[n.category]||(t[n.category]=[]);let o=Vt[n.id],i=o?` \u2014 ${o.description}`:"";t[n.category].push(`${n.id} \u2014 "${n.title}"${i}`)}let a=[];for(let[n,o]of Object.entries(t))a.push(`**${n}**:
2017
447
  ${o.map(i=>` \u2022 ${i}`).join(`
2018
448
  `)}`);return a.join(`
2019
449
 
2020
- `)}function $t(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function Vt(r){return(r?zt(r):ze).map(t=>{let a=jt[t.id];return{id:t.id,slug:$t(t.title),title:t.title,category:t.category,description:a?.description??"",tags:a?.tags??[],theme:a?.theme??"dark",colors:a?.colors??[],style:a?.style??""}})}function ir(r,e){let t=r.toLowerCase(),a=e?.maxResults??3,n=e?.themePreference,o=[[/saas|software|platform|dashboard|analytics/i,"saas",3],[/agency|studio|creative|design\s*agency/i,"agency",3],[/portfolio|personal|resume|cv/i,"portfolio",3],[/web3|crypto|blockchain|nft|defi/i,"web3",3],[/booking|reservation|hotel|schedule/i,"booking",3],[/ai|artificial|machine\s*learning|automation/i,"ai",2],[/education|course|learning|academy/i,"education",3],[/newsletter|blog|content|editorial/i,"newsletter",3],[/pricing|calculator|cost/i,"pricing",3],[/luxury|premium|jet|high.?end/i,"luxury",3],[/talent|hiring|recruit|hr/i,"talent",3],[/logistics|transport|shipping|delivery/i,"logistics",3],[/invoice|billing|payment/i,"invoicing",3],[/task|project\s*manag|todo/i,"task-management",3],[/fintech|finance|banking|money/i,"fintech",3],[/minimal|clean|simple/i,"minimal",2],[/dark|night|moody/i,"dark",1],[/light|bright|white/i,"light",1],[/glass|frosted|blur/i,"liquid-glass",2],[/animated|animation|motion/i,"animation",2],[/gradient|colorful/i,"gradient",1],[/cinematic|epic|dramatic/i,"cinematic",2],[/video|looping/i,"video",1]],i=Vt().map(d=>{let p=0;for(let[h,m,b]of o)h.test(t)&&d.tags.includes(m)&&(p+=b);let u=d.category.toLowerCase();return t.includes(u)&&(p+=2),n&&d.theme===n&&(p+=1),d.id==="18"&&!/loader|loading|animation/i.test(t)&&(p-=5),d.id==="price-calculator"&&!/pric|calculator|cost|estimat/i.test(t)&&(p-=5),{preset:d,score:p}});i.sort((d,p)=>p.score+Math.random()*.5-(d.score+Math.random()*.5));let l=i.filter(d=>d.score>0);return(l.length>=a?l.slice(0,a):i.slice(0,a)).map(d=>d.preset)}var or={landing:["visual theme","color","typography","component","layout","do","agent prompt"],design:["visual theme","color","typography","component","layout","depth","do","responsive","agent prompt"],dashboard:["color","typography","component","layout","depth","agent prompt"],crud:["component","layout","depth","agent prompt"],auth:["typography","component","agent prompt"],layout:["color","typography","layout","responsive","agent prompt"],admin:["color","typography","component","layout","depth","agent prompt"],general:["color","typography","component","layout","agent prompt"]},mt=[{id:"cohere",name:"Cohere",category:"AI & Machine Learning",sections:[{title:"1. Visual Theme & Atmosphere",content:`Cohere's interface is a polished enterprise command deck \u2014 confident, clean, and designed to make AI feel like serious infrastructure rather than a consumer toy. The experience lives on a bright white canvas where content is organized into generously rounded cards (22px radius) that create an organic, cloud-like containment language. This is a site that speaks to CTOs and enterprise architects: professional without being cold, sophisticated without being intimidating.
450
+ `)}function _i(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function Kt(r){return(r?qt(r):ze).map(t=>{let a=Vt[t.id];return{id:t.id,slug:_i(t.title),title:t.title,category:t.category,description:a?.description??"",tags:a?.tags??[],theme:a?.theme??"dark",colors:a?.colors??[],style:a?.style??""}})}function sr(r,e){let t=r.toLowerCase(),a=e?.maxResults??3,n=e?.themePreference,o=[[/saas|software|platform|dashboard|analytics/i,"saas",3],[/agency|studio|creative|design\s*agency/i,"agency",3],[/portfolio|personal|resume|cv/i,"portfolio",3],[/web3|crypto|blockchain|nft|defi/i,"web3",3],[/booking|reservation|hotel|schedule/i,"booking",3],[/ai|artificial|machine\s*learning|automation/i,"ai",2],[/education|course|learning|academy/i,"education",3],[/newsletter|blog|content|editorial/i,"newsletter",3],[/pricing|calculator|cost/i,"pricing",3],[/luxury|premium|jet|high.?end/i,"luxury",3],[/talent|hiring|recruit|hr/i,"talent",3],[/logistics|transport|shipping|delivery/i,"logistics",3],[/invoice|billing|payment/i,"invoicing",3],[/task|project\s*manag|todo/i,"task-management",3],[/fintech|finance|banking|money/i,"fintech",3],[/minimal|clean|simple/i,"minimal",2],[/dark|night|moody/i,"dark",1],[/light|bright|white/i,"light",1],[/glass|frosted|blur/i,"liquid-glass",2],[/animated|animation|motion/i,"animation",2],[/gradient|colorful/i,"gradient",1],[/cinematic|epic|dramatic/i,"cinematic",2]],i=Kt().map(d=>{let u=0;for(let[h,m,f]of o)h.test(t)&&d.tags.includes(m)&&(u+=f);let p=d.category.toLowerCase();return t.includes(p)&&(u+=2),n&&d.theme===n&&(u+=1),d.id==="18"&&!/loader|loading|animation/i.test(t)&&(u-=5),d.id==="price-calculator"&&!/pric|calculator|cost|estimat/i.test(t)&&(u-=5),{preset:d,score:u}});i.sort((d,u)=>u.score+Math.random()*.5-(d.score+Math.random()*.5));let s=i.filter(d=>d.score>0);return(s.length>=a?s.slice(0,a):i.slice(0,a)).map(d=>d.preset)}var dr={"SF Pro":"Inter","SF Pro Display":"Inter","SF Pro Text":"Inter","SF Pro Rounded":"Nunito Sans","SF Mono":"JetBrains Mono","system-ui":"Inter","ui-sans-serif":"Inter",Arial:"DM Sans","Inter Variable":"Inter",inter:"Inter","sohne-var":"Inter",sohne:"Inter",S\u00F6hne:"Inter",s\u00F6hne:"Inter",CohereText:"Source Serif 4","Unica77 Cohere Web":"Inter",Waldenburg:"Playfair Display",waldenburgNormal:"Playfair Display","rb-freigeist-neue":"Space Grotesk","basier-square":"Inter",Basier:"Inter","The Future":"Outfit",GeistMono:"JetBrains Mono",universalSans:"Inter",CursorGothic:"DM Serif Display",jjannon:"Crimson Text","Camera Plain Variable":"DM Sans",domaine:"DM Serif Display","Dammit Sans":"Rubik","Super Sans VF":"DM Sans","Matter Regular":"Inter","Degular Display":"DM Sans",abcDiatype:"DM Sans","ABC Diatype":"DM Sans","ABC Diatype Mono":"JetBrains Mono",__hashicorpSans_96f0ca:"Inter","MongoDB Value Serif":"Source Serif 4","Euclid Circular A":"DM Sans",Haas:"Inter","Cal Sans":"DM Sans",figmaSans:"Inter","GT Walsheim Framer Medium":"DM Sans","GT Walsheim":"DM Sans","GT Walsheim Pro":"DM Sans",Saans:"Inter",MediumLL:"Inter",NotionInter:"Inter",Roobert:"DM Sans","Roobert PRO Medium":"DM Sans","Pin Sans":"DM Sans",CoinbaseDisplay:"DM Sans",CoinbaseSans:"Inter","Kraken-Brand":"Space Grotesk","Kraken-Product":"Inter","Aeonik Pro":"DM Sans","Wise Sans":"DM Sans","BMWTypeNextLatin Light":"Inter",BMWTypeNextLatin:"Inter","IBM Plex Sans":"IBM Plex Sans","NVIDIA-EMEA":"Inter",SpotifyMixUI:"DM Sans","Uber Move":"DM Sans","Uber Move Text":"DM Sans",UberMoveText:"DM Sans","Airbnb Cereal VF":"Nunito Sans","Airbnb Cereal":"Nunito Sans",Cereal:"Nunito Sans","Noto Sans":"Noto Sans","D-DIN":"DM Sans","D-DIN-Bold":"DM Sans","Berkeley Mono":"JetBrains Mono","Circular Std":"DM Sans",Circular:"DM Sans",Graphik:"Inter","Neue Montreal":"Inter"},lr={landing:["visual theme","color","typography","component","layout","do","agent prompt"],design:["visual theme","color","typography","component","layout","depth","do","responsive","agent prompt"],dashboard:["color","typography","component","layout","depth","agent prompt"],crud:["component","layout","depth","agent prompt"],auth:["typography","component","agent prompt"],layout:["color","typography","layout","responsive","agent prompt"],admin:["color","typography","component","layout","depth","agent prompt"],general:["color","typography","component","layout","agent prompt"]},ft=[{id:"cohere",name:"Cohere",category:"AI & Machine Learning",sections:[{title:"1. Visual Theme & Atmosphere",content:`Cohere's interface is a polished enterprise command deck \u2014 confident, clean, and designed to make AI feel like serious infrastructure rather than a consumer toy. The experience lives on a bright white canvas where content is organized into generously rounded cards (22px radius) that create an organic, cloud-like containment language. This is a site that speaks to CTOs and enterprise architects: professional without being cold, sophisticated without being intimidating.
2021
451
 
2022
452
  The design language bridges two worlds with a dual-typeface system: CohereText, a custom display serif with tight tracking, gives headlines the gravitas of a technology manifesto, while Unica77 Cohere Web handles all body and UI text with geometric Swiss precision. This serif/sans pairing creates a "confident authority meets engineering clarity" personality that perfectly reflects an enterprise AI platform.
2023
453
 
@@ -10797,14 +9227,14 @@ What makes Uber's design truly distinctive is its use of full-bleed photography
10797
9227
  5. For shadows, use "whisper shadow (rgba(0,0,0,0.12) 0px 4px 16px)" -- never heavy drop shadows
10798
9228
  6. Keep layouts compact and information-dense -- Uber is efficient, not airy
10799
9229
  7. Illustrations should be warm and human -- describe "stylized people in warm tones" not abstract shapes
10800
- 8. Pair black CTAs with white secondaries for balanced dual-action layouts`}]}],qt={cohere:{description:"Cohere's interface is a polished enterprise command deck \u2014 confident, clean, and designed to make AI feel like serious infrastructure rather than a consumer toy. The experience lives on a bright wh...",category:"AI & Machine Learning",theme:"light",colors:["#000000","#212121","#17171c","#1863dc","#4c6ee6","#9b60aa"],fonts:{heading:"CohereText",body:"Unica77 Cohere Web"},tags:["light","ai-machine-learning","minimal","bold","enterprise","gradient"]},elevenlabs:{description:"ElevenLabs' website is a study in restrained elegance \u2014 a near-white canvas (`#ffffff`, `#f5f5f5`) where typography and subtle shadows do all the heavy lifting. The design feels like a premium audi...",category:"AI & Machine Learning",theme:"light",colors:["#ffffff","#f5f5f5","#f5f2ef","#000000","#4e4e4e","#777169"],fonts:{heading:"Waldenburg",body:"Inter"},tags:["light","ai-machine-learning","minimal","bold"]},minimax:{description:"MiniMax's website is a clean, product-showcase platform for a Chinese AI technology company that bridges consumer-friendly appeal with technical credibility. The design language is predominantly wh...",category:"AI & Machine Learning",theme:"light",colors:["#1456f0","#3daeff","#ea5ec1","#bfdbfe","#60a5fa","#3b82f6"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["light","ai-machine-learning","minimal","bold","playful","gradient"]},mistral:{description:"Mistral AI's interface is a sun-drenched landscape rendered in code \u2014 a warm, bold, unapologetically European design that trades the typical blue-screen AI aesthetic for golden amber, burnt orange,...",category:"AI & Machine Learning",theme:"dark",colors:["#fa520f","#fb6424","#ff8105","#ff8a00","#ffa110","#ffb83e"],fonts:{heading:"Arial",body:"Inter"},tags:["dark","ai-machine-learning","minimal","bold","elegant","gradient"]},ollama:{description:"Ollama's interface is radical minimalism taken to its logical conclusion \u2014 a pure-white void where content floats without decoration, shadow, or color. The design philosophy mirrors the product its...",category:"AI & Machine Learning",theme:"light",colors:["#000000","#262626","#090909","#ffffff","#fafafa","#e5e5e5"],fonts:{heading:"SF Pro Rounded",body:"ui-sans-serif"},tags:["light","ai-machine-learning","minimal","playful"]},opencode:{description:"OpenCode's website embodies a terminal-native, monospace-first aesthetic that reflects its identity as an open source AI coding agent. The entire visual system is built on a stark dark-on-light con...",category:"AI & Machine Learning",theme:"dark",colors:["#201d1d","#fdfcfc","#9a9898","#302c2c","#646262","#f1eeee"],fonts:{heading:"Inter",body:"16px (1.00rem)"},tags:["dark","ai-machine-learning","minimal","bold"]},replicate:{description:"Replicate's interface is a developer playground crackling with creative energy \u2014 a bold, high-contrast design that feels more like a music festival poster than a typical API platform. The hero sect...",category:"AI & Machine Learning",theme:"dark",colors:["#202020","#ea2804","#dd4425","#2b9a66","#24292e","#ffffff"],fonts:{heading:"rb-freigeist-neue",body:"basier-square"},tags:["dark","ai-machine-learning","minimal","bold","playful","gradient"]},runwayml:{description:"Runway's interface is a cinematic reel brought to life as a website \u2014 a dark, editorial, film-production-grade design where full-bleed photography and video ARE the primary UI elements. This is not...",category:"AI & Machine Learning",theme:"dark",colors:["#000000","#030303","#1a1a1a","#ffffff","#fefefe","#e9ecf2"],fonts:{heading:"Inter",body:"Inter"},tags:["dark","ai-machine-learning","minimal","bold"]},together:{description:"Together AI's interface is a pastel-gradient dreamscape built for enterprise AI infrastructure \u2014 a design that somehow makes GPU clusters and model inference feel light, airy, and optimistic. The h...",category:"AI & Machine Learning",theme:"dark",colors:["#ef2cc1","#fc4c02","#010120","#bdbbff","#ffffff","#000000"],fonts:{heading:"The Future",body:"Inter"},tags:["dark","ai-machine-learning","minimal","playful","enterprise","modern","elegant","data-dense","gradient"]},voltagent:{description:"VoltAgent's interface is a deep-space command terminal for the AI age \u2014 a developer-facing darkness built on near-pure-black surfaces (`#050507`) where the only interruption is the electric pulse o...",category:"AI & Machine Learning",theme:"light",colors:["#00d992","#2fd6a1","#10b981","#818cf8","#306cce","#2554a0"],fonts:{heading:"system-ui",body:"Inter"},tags:["light","ai-machine-learning","playful","data-dense"]},x:{description:"xAI's website is a masterclass in dark-first, monospace-driven brutalist minimalism -- a design system that feels like it was built by engineers who understand that restraint is the ultimate form o...",category:"AI & Machine Learning",theme:"dark",colors:["#ffffff","#1f2228","#000000"],fonts:{heading:"GeistMono",body:"universalSans"},tags:["dark","ai-machine-learning","minimal","elegant","data-dense","gradient"]},cursor:{description:"Cursor's website is a study in warm minimalism meets code-editor elegance. The entire experience is built on a warm off-white canvas (`#f2f1ed`) with dark warm-brown text (`#26251e`) -- not pure bl...",category:"Developer Tools",theme:"light",colors:["#26251e","#f2f1ed","#e6e5e0","#ffffff","#000000","#f54e00"],fonts:{heading:"CursorGothic",body:"jjannon"},tags:["light","developer-tools","minimal"]},expo:{description:"Expo's interface is a luminous, confidence-radiating developer platform built on the premise that tools for building apps should feel as polished as the apps themselves. The entire experience lives...",category:"Developer Tools",theme:"dark",colors:["#000000","#1c2024","#0d74ce","#476cff","#47c2ff","#8145b5"],fonts:{heading:"Inter",body:"Inter"},tags:["dark","developer-tools","playful"]},linear:{description:"Linear's website is a masterclass in dark-mode-first product design \u2014 a near-black canvas (`#08090a`) where content emerges from darkness like starlight. The overall impression is one of extreme pr...",category:"Developer Tools",theme:"dark",colors:["#010102","#08090a","#0f1011","#191a1b","#28282c","#f7f8f8"],fonts:{heading:"Inter Variable",body:"Inter Variable"},tags:["dark","developer-tools","minimal","bold"]},lovable:{description:"Lovable's website radiates warmth through restraint. The entire page sits on a creamy, parchment-toned background (`#f7f4ed`) that immediately separates it from the cold-white conventions of most d...",category:"Developer Tools",theme:"dark",colors:["#f7f4ed","#1c1c1c","#fcfbf8","#5f5f5d","#eceae4","#3b82f6"],fonts:{heading:"Camera Plain Variable",body:"Camera Plain Variable"},tags:["dark","developer-tools","minimal"]},mintlify:{description:"Mintlify's website is a study in documentation-as-product design \u2014 a white, airy, information-rich surface that treats clarity as its highest aesthetic value. The page opens with a luminous white (...",category:"Developer Tools",theme:"light",colors:["#0d0d0d","#ffffff","#18e299","#d4fae8","#0fa76e","#c37d0d"],fonts:{heading:"Inter",body:"Inter"},tags:["light","developer-tools","minimal","bold","gradient"]},posthog:{description:"PostHog's website feels like a startup's internal wiki that escaped into the wild \u2014 warm, irreverent, and deliberately anti-corporate. The background isn't the expected crisp white or dark void of ...",category:"Developer Tools",theme:"dark",colors:["#4d4f46","#23251d","#f54e00","#f7a501","#b17816","#3b82f6"],fonts:{heading:"IBM Plex Sans Variable",body:"IBM Plex Sans Variable"},tags:["dark","developer-tools","bold","playful","modern","gradient"]},raycast:{description:"Raycast's marketing site feels like the dark interior of a precision instrument \u2014 a Swiss watch case carved from obsidian. The background isn't just dark, it's an almost-black blue-tint (`#07080a`)...",category:"Developer Tools",theme:"dark",colors:["#07080a","#ffffff","#ff6363","#55b3ff","#5fc992","#ffbc33"],fonts:{heading:"Inter",body:"16px"},tags:["dark","developer-tools","minimal","data-dense","gradient"]},resend:{description:"Resend's website is a dark, cinematic canvas that treats email infrastructure like a luxury product. The entire page is draped in pure black (`#000000`) with text that glows in near-white (`#f0f0f0...",category:"Developer Tools",theme:"light",colors:["#000000","#f0f0f0","#ffffff","#ff5900","#ff801f","#ffa057"],fonts:{heading:"domaine",body:"inter"},tags:["light","developer-tools","minimal","elegant"]},sentry:{description:"Sentry's website is a dark-mode-first developer tool interface that speaks the language of code editors and terminal windows. The entire aesthetic is rooted in deep purple-black backgrounds (`#1f16...",category:"Developer Tools",theme:"dark",colors:["#1f1633","#150f23","#362d59","#6a5fc1","#79628c","#422082"],fonts:{heading:"Dammit Sans",body:"Rubik"},tags:["dark","developer-tools","bold"]},supabase:{description:"Supabase's website is a dark-mode-native developer platform that channels the aesthetic of a premium code editor \u2014 deep black backgrounds (`#0f0f0f`, `#171717`) with emerald green accents (`#3ecf8e...",category:"Developer Tools",theme:"dark",colors:["#3ecf8e","#00c573","#0f0f0f","#171717","#242424","#2e2e2e"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["dark","developer-tools","minimal","data-dense"]},superhuman:{description:"Superhuman's website feels like opening a luxury envelope \u2014 predominantly white, immaculately clean, with a single dramatic gesture of color that commands attention. The hero section is a cinematic...",category:"Developer Tools",theme:"dark",colors:["#1b1938","#cbb7fb","#292827","#714cb6","#ffffff","#e9e5dd"],fonts:{heading:"Super Sans VF",body:"Super Sans VF"},tags:["dark","developer-tools","minimal","bold","elegant","data-dense","gradient"]},vercel:{description:"Vercel's website is the visual thesis of developer infrastructure made invisible \u2014 a design system so restrained it borders on philosophical. The page is overwhelmingly white (`#ffffff`) with near-...",category:"Developer Tools",theme:"dark",colors:["#171717","#ffffff","#000000","#ff5b4f","#de1d8d","#0a72ef"],fonts:{heading:"Geist",body:"Geist"},tags:["dark","developer-tools","minimal"]},warp:{description:"Warp's website feels like sitting at a campfire in a deep forest \u2014 warm, dark, and alive with quiet confidence. Unlike the cold, blue-tinted blacks favored by most developer tools, Warp wraps every...",category:"Developer Tools",theme:"dark",colors:["#faf9f6","#353534","#868584","#afaeac","#666469","#454545"],fonts:{heading:"Matter Regular",body:"Matter Regular"},tags:["dark","developer-tools","minimal","bold"]},zapier:{description:"Zapier's website radiates warm, approachable professionalism. It rejects the cold monochrome minimalism of developer tools in favor of a cream-tinted canvas (`#fffefb`) that feels like unbleached p...",category:"Developer Tools",theme:"dark",colors:["#201515","#fffefb","#fffdf9","#ff4f00","#36342e","#939084"],fonts:{heading:"Degular Display",body:"Inter"},tags:["dark","developer-tools","minimal","bold","enterprise","modern","elegant"]},clickhouse:{description:`ClickHouse's interface is a high-performance cockpit rendered in acid yellow-green on obsidian black \u2014 a design that screams "speed" before you read a single word. The entire experience lives in da...`,category:"Infrastructure",theme:"dark",colors:["#faff69","#166534","#14572f","#f4f692","#4f5100","#161600"],fonts:{heading:"Inter",body:"Basier"},tags:["dark","infrastructure"]},composio:{description:"Composio's interface is a nocturnal command center \u2014 a dense, developer-focused darkness punctuated by electric cyan and deep cobalt signals. The entire experience is built on an almost-pure-black ...",category:"Infrastructure",theme:"dark",colors:["#0007cd","#00ffff","#0089ff","#0096ff","#0f0f0f","#000000"],fonts:{heading:"abcDiatype",body:"Inter"},tags:["dark","infrastructure","minimal","data-dense","gradient"]},hashicorp:{description:"HashiCorp's website is enterprise infrastructure made tangible \u2014 a design system that must communicate the complexity of cloud infrastructure management while remaining approachable. The visual lan...",category:"Infrastructure",theme:"dark",colors:["#000000","#15181e","#0d0e12","#f1f2f3","#d5d7db","#b2b6bd"],fonts:{heading:"__hashicorpSans_96f0ca",body:"system-ui"},tags:["dark","infrastructure","minimal","bold","enterprise","data-dense"]},mongodb:{description:"MongoDB's website is a deep-forest-meets-terminal experience \u2014 a design system rooted in the darkest teal-black (`#001e2b`) that evokes both the density of a database and the depth of a forest cano...",category:"Infrastructure",theme:"dark",colors:["#001e2b","#00ed64","#00684a","#006cfa","#3860be","#1eaedb"],fonts:{heading:"MongoDB Value Serif",body:"Euclid Circular A"},tags:["dark","infrastructure","bold","enterprise"]},sanity:{description:"Sanity's website is a developer-content platform rendered as a nocturnal command center -- dark, precise, and deeply structured. The entire experience sits on a near-black canvas (`#0b0b0b`) that r...",category:"Infrastructure",theme:"dark",colors:["#0b0b0b","#000000","#f36458","#0052ef","#55beff","#afe3ff"],fonts:{heading:"waldenburgNormal",body:"waldenburgNormal"},tags:["dark","infrastructure","playful"]},stripe:{description:"Stripe's website is the gold standard of fintech design -- a system that manages to feel simultaneously technical and luxurious, precise and warm. The page opens on a clean white canvas (`#ffffff`)...",category:"Infrastructure",theme:"light",colors:["#533afd","#061b31","#ffffff","#1c1e54","#0d253d","#ea2261"],fonts:{heading:"Inter",body:"Inter"},tags:["light","infrastructure","minimal","bold","enterprise","modern","data-dense","gradient"]},airtable:{description:'Airtable\'s website is a clean, enterprise-friendly platform that communicates "sophisticated simplicity" through a white canvas with deep navy text (`#181d26`) and Airtable Blue (`#1b61c9`) as the ...',category:"Design & Productivity",theme:"light",colors:["#181d26","#1b61c9","#ffffff","#006400","#333333","#254fad"],fonts:{heading:"Haas",body:"Haas"},tags:["light","design-productivity","minimal","playful","enterprise"]},cal:{description:"Cal.com's website is a masterclass in monochromatic restraint \u2014 a grayscale world where boldness comes not from color but from the sheer confidence of black text on white space. Inspired by Uber's ...",category:"Design & Productivity",theme:"dark",colors:["#242424","#111111","#ffffff","#0099ff","#3b82f6","#0000ee"],fonts:{heading:"Cal Sans",body:"Inter"},tags:["dark","design-productivity","minimal","bold","modern","data-dense"]},clay:{description:"Clay's website is a warm, playful celebration of color that treats B2B data enrichment like a craft rather than an enterprise chore. The design language is built on a foundation of warm cream backg...",category:"Design & Productivity",theme:"light",colors:["#000000","#ffffff","#faf9f7","#84e7a5","#078a52","#02492a"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["light","design-productivity","playful","enterprise"]},figma:{description:"Figma's interface is the design tool that designed itself \u2014 a masterclass in typographic sophistication where a custom variable font (figmaSans) modulates between razor-thin (weight 320) and bold (...",category:"Design & Productivity",theme:"dark",colors:["#000000","#ffffff"],fonts:{heading:"figmaSans",body:"Inter"},tags:["dark","design-productivity","bold","gradient"]},framer:{description:"Framer's website is a cinematic, tool-obsessed dark canvas that radiates the confidence of a design tool built by designers who worship craft. The entire experience is drenched in pure black \u2014 not ...",category:"Design & Productivity",theme:"dark",colors:["#000000","#ffffff","#0099ff","#a6a6a6","#090909","#0000ee"],fonts:{heading:"GT Walsheim Framer Medium",body:"Inter Variable"},tags:["dark","design-productivity"]},intercom:{description:'Intercom\'s website is a warm, confident customer service platform that communicates "AI-first helpdesk" through a clean, editorial design language. The page operates on a warm off-white canvas (`#f...',category:"Design & Productivity",theme:"light",colors:["#111111","#ffffff","#faf9f6","#ff5600","#fe4c02","#65b5ff"],fonts:{heading:"Saans",body:"MediumLL"},tags:["light","design-productivity","minimal"]},miro:{description:`Miro's website is a clean, collaborative-tool-forward platform that communicates "visual thinking" through generous whitespace, pastel accent colors, and a confident geometric font. The design uses...`,category:"Design & Productivity",theme:"light",colors:["#1c1c1e","#ffffff","#5b76fe","#2a41b6","#ffc6c6","#600000"],fonts:{heading:"Roobert PRO Medium",body:"Noto Sans"},tags:["light","design-productivity","minimal","modern"]},notion:{description:"Notion's website embodies the philosophy of the tool itself: a blank canvas that gets out of your way. The design system is built on warm neutrals rather than cold grays, creating a distinctly appr...",category:"Design & Productivity",theme:"dark",colors:["#ffffff","#0075de","#213183","#005bab","#f6f5f4","#31302e"],fonts:{heading:"NotionInter",body:"NotionInter"},tags:["dark","design-productivity","minimal","bold"]},pinterest:{description:"Pinterest's website is a warm, inspiration-driven canvas that treats visual discovery like a lifestyle magazine. The design operates on a soft, slightly warm white background with Pinterest Red (`#...",category:"Design & Productivity",theme:"dark",colors:["#e60023","#103c25","#0b2819","#211922","#000000","#62625b"],fonts:{heading:"Pin Sans",body:"Pin Sans"},tags:["dark","design-productivity","bold"]},webflow:{description:'Webflow\'s website is a visually rich, tool-forward platform that communicates "design without code" through clean white surfaces, the signature Webflow Blue (`#146ef5`), and a rich secondary color ...',category:"Design & Productivity",theme:"dark",colors:["#080808","#146ef5","#3b89ff","#006acc","#0055d4","#7a3dff"],fonts:{heading:"Inter",body:"20px"},tags:["dark","design-productivity","minimal"]},coinbase:{description:"Coinbase's website is a clean, trustworthy crypto platform that communicates financial reliability through a blue-and-white binary palette. The design uses Coinbase Blue (`#0052ff`) \u2014 a deep, satur...",category:"Fintech",theme:"light",colors:["#0052ff","#ffffff","#0a0b0d","#eef0f3","#578bfa","#0667d0"],fonts:{heading:"CoinbaseDisplay",body:"CoinbaseSans"},tags:["light","fintech","minimal","enterprise"]},kraken:{description:"Kraken's website is a clean, trustworthy crypto exchange that uses purple as its commanding brand color. The design operates on white backgrounds with Kraken Purple (`#7132f5`, `#5741d8`, `#5b1ecf`...",category:"Fintech",theme:"light",colors:["#7132f5","#5741d8","#5b1ecf","#101114","#686b82","#9497a9"],fonts:{heading:"Kraken-Brand",body:"Kraken-Product"},tags:["light","fintech","minimal","bold","enterprise"]},revolut:{description:`Revolut's website is fintech confidence distilled into pixels \u2014 a design system that communicates "your money is in capable hands" through massive typography, generous whitespace, and a disciplined...`,category:"Fintech",theme:"dark",colors:["#191c1f","#ffffff","#f4f4f4","#494fdf","#4f55f1","#376cd5"],fonts:{heading:"Aeonik Pro",body:"Inter"},tags:["dark","fintech","modern"]},wise:{description:`Wise's website is a bold, confident fintech platform that communicates "money without borders" through massive typography and a distinctive lime-green accent. The design operates on a warm off-whit...`,category:"Fintech",theme:"dark",colors:["#0e0f0c","#9fe870","#163300","#e2f6d5","#cdffad","#054d28"],fonts:{heading:"Wise Sans",body:"Inter"},tags:["dark","fintech","minimal","bold","data-dense"]},airbnb:{description:"Airbnb's website is a warm, photography-forward marketplace that feels like flipping through a travel magazine where every page invites you to book. The design operates on a foundation of pure whit...",category:"Enterprise & Consumer",theme:"light",colors:["#ff385c","#e00b41","#c13515","#b32505","#460479","#92174d"],fonts:{heading:"Nunito Sans",body:"Inter"},tags:["light","enterprise-consumer","minimal","bold"]},apple:{description:"Apple's website is a masterclass in controlled drama \u2014 vast expanses of pure black and near-white serve as cinematic backdrops for products that are photographed as if they were sculptures in a gal...",category:"Enterprise & Consumer",theme:"dark",colors:["#000000","#f5f5f7","#1d1d1f","#0071e3","#0066cc","#2997ff"],fonts:{heading:"Inter",body:"Inter"},tags:["dark","enterprise-consumer","minimal","gradient"]},bmw:{description:"BMW's website is automotive engineering made visual \u2014 a design system that communicates precision, performance, and German industrial confidence. The page alternates between deep dark hero sections...",category:"Enterprise & Consumer",theme:"light",colors:["#ffffff","#1c69d4","#0653b6","#262626","#757575","#bbbbbb"],fonts:{heading:"BMWTypeNextLatin Light",body:"BMWTypeNextLatin"},tags:["light","enterprise-consumer","minimal","elegant"]},ibm:{description:"IBM's website is the digital embodiment of enterprise authority built on the Carbon Design System \u2014 a design language so methodically structured it reads like an engineering specification rendered ...",category:"Enterprise & Consumer",theme:"dark",colors:["#0f62fe","#ffffff","#161616","#262626","#393939","#525252"],fonts:{heading:"IBM Plex Sans",body:"Inter"},tags:["dark","enterprise-consumer","minimal","playful","enterprise"]},nvidia:{description:"NVIDIA's website is a high-contrast, technology-forward experience that communicates raw computational power through design restraint. The page is built on a stark black (`#000000`) and white (`#ff...",category:"Enterprise & Consumer",theme:"dark",colors:["#76b900","#000000","#ffffff","#bff230","#df6500","#ef9100"],fonts:{heading:"NVIDIA-EMEA",body:"NVIDIA-EMEA"},tags:["dark","enterprise-consumer","minimal","bold","playful","data-dense"]},spacex:{description:"SpaceX's website is a full-screen cinematic experience that treats aerospace engineering like a film \u2014 every section is a scene, every photograph is a frame, and the interface disappears entirely b...",category:"Enterprise & Consumer",theme:"dark",colors:["#000000","#f0f0fa"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["dark","enterprise-consumer","minimal","bold"]},spotify:{description:"Spotify's web interface is a dark, immersive music player that wraps listeners in a near-black cocoon (`#121212`, `#181818`, `#1f1f1f`) where album art and content become the primary source of colo...",category:"Enterprise & Consumer",theme:"dark",colors:["#1ed760","#121212","#181818","#1f1f1f","#ffffff","#b3b3b3"],fonts:{heading:"Inter",body:"SpotifyMixUI"},tags:["dark","enterprise-consumer","bold"]},uber:{description:"Uber's design language is a masterclass in confident minimalism -- a black-and-white universe where every pixel serves a purpose and nothing decorates without earning its place. The entire experien...",category:"Enterprise & Consumer",theme:"dark",colors:["#000000","#ffffff","#e2e2e2","#f3f3f3","#efefef","#4b4b4b"],fonts:{heading:"Inter",body:"UberMoveText"},tags:["dark","enterprise-consumer","minimal","bold","playful","data-dense"]}};function ft(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function ke(r){let e=r.toLowerCase().replace(/[^a-z0-9]/g,"");return mt.find(t=>t.id===r||t.id.toLowerCase().replace(/[^a-z0-9]/g,"")===e||t.name.toLowerCase().replace(/[^a-z0-9]/g,"")===e)}function bt(r){return qt[r]}function Kt(r){return!r||r==="All"?mt:mt.filter(e=>e.category.toLowerCase()===r.toLowerCase())}function Jt(r){return Kt(r).map(t=>{let a=qt[t.id];return{id:t.id,slug:ft(t.name),name:t.name,category:t.category,description:a?.description??"",theme:a?.theme??"light",colors:a?.colors??[],fonts:a?.fonts??{heading:"Inter",body:"Inter"},tags:a?.tags??[]}})}function nr(r){let e=r??mt,t={};for(let n of e)(t[n.category]??=[]).push(n);let a=[];for(let[n,o]of Object.entries(t)){a.push(`**${n}**`);for(let i of o){let l=qt[i.id];a.push(` - ${i.name} (${i.id}) \u2014 ${l?.theme??"light"}, ${l?.description?.slice(0,60)??""}`)}}return a.join(`
10801
- `)}function sr(r,e){let t=ke(r);if(!t)return null;let a=or[e]??or.general;if(!a)return null;let n=t.sections.filter(o=>a.some(i=>o.title.toLowerCase().includes(i)));return n.length===0?null:n.map(o=>`## ${o.title}
9230
+ 8. Pair black CTAs with white secondaries for balanced dual-action layouts`}]}],Jt={cohere:{description:"Cohere's interface is a polished enterprise command deck \u2014 confident, clean, and designed to make AI feel like serious infrastructure rather than a consumer toy. The experience lives on a bright wh...",category:"AI & Machine Learning",theme:"light",colors:["#000000","#212121","#17171c","#1863dc","#4c6ee6","#9b60aa"],fonts:{heading:"CohereText",body:"Unica77 Cohere Web"},tags:["light","ai-machine-learning","minimal","bold","enterprise","gradient"]},elevenlabs:{description:"ElevenLabs' website is a study in restrained elegance \u2014 a near-white canvas (`#ffffff`, `#f5f5f5`) where typography and subtle shadows do all the heavy lifting. The design feels like a premium audi...",category:"AI & Machine Learning",theme:"light",colors:["#ffffff","#f5f5f5","#f5f2ef","#000000","#4e4e4e","#777169"],fonts:{heading:"Waldenburg",body:"Inter"},tags:["light","ai-machine-learning","minimal","bold"]},minimax:{description:"MiniMax's website is a clean, product-showcase platform for a Chinese AI technology company that bridges consumer-friendly appeal with technical credibility. The design language is predominantly wh...",category:"AI & Machine Learning",theme:"light",colors:["#1456f0","#3daeff","#ea5ec1","#bfdbfe","#60a5fa","#3b82f6"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["light","ai-machine-learning","minimal","bold","playful","gradient"]},mistral:{description:"Mistral AI's interface is a sun-drenched landscape rendered in code \u2014 a warm, bold, unapologetically European design that trades the typical blue-screen AI aesthetic for golden amber, burnt orange,...",category:"AI & Machine Learning",theme:"dark",colors:["#fa520f","#fb6424","#ff8105","#ff8a00","#ffa110","#ffb83e"],fonts:{heading:"Arial",body:"Inter"},tags:["dark","ai-machine-learning","minimal","bold","elegant","gradient"]},ollama:{description:"Ollama's interface is radical minimalism taken to its logical conclusion \u2014 a pure-white void where content floats without decoration, shadow, or color. The design philosophy mirrors the product its...",category:"AI & Machine Learning",theme:"light",colors:["#000000","#262626","#090909","#ffffff","#fafafa","#e5e5e5"],fonts:{heading:"SF Pro Rounded",body:"ui-sans-serif"},tags:["light","ai-machine-learning","minimal","playful"]},opencode:{description:"OpenCode's website embodies a terminal-native, monospace-first aesthetic that reflects its identity as an open source AI coding agent. The entire visual system is built on a stark dark-on-light con...",category:"AI & Machine Learning",theme:"dark",colors:["#201d1d","#fdfcfc","#9a9898","#302c2c","#646262","#f1eeee"],fonts:{heading:"Inter",body:"16px (1.00rem)"},tags:["dark","ai-machine-learning","minimal","bold"]},replicate:{description:"Replicate's interface is a developer playground crackling with creative energy \u2014 a bold, high-contrast design that feels more like a music festival poster than a typical API platform. The hero sect...",category:"AI & Machine Learning",theme:"dark",colors:["#202020","#ea2804","#dd4425","#2b9a66","#24292e","#ffffff"],fonts:{heading:"rb-freigeist-neue",body:"basier-square"},tags:["dark","ai-machine-learning","minimal","bold","playful","gradient"]},runwayml:{description:"Runway's interface is a cinematic reel brought to life as a website \u2014 a dark, editorial, film-production-grade design where full-bleed photography and video ARE the primary UI elements. This is not...",category:"AI & Machine Learning",theme:"dark",colors:["#000000","#030303","#1a1a1a","#ffffff","#fefefe","#e9ecf2"],fonts:{heading:"Inter",body:"Inter"},tags:["dark","ai-machine-learning","minimal","bold"]},together:{description:"Together AI's interface is a pastel-gradient dreamscape built for enterprise AI infrastructure \u2014 a design that somehow makes GPU clusters and model inference feel light, airy, and optimistic. The h...",category:"AI & Machine Learning",theme:"dark",colors:["#ef2cc1","#fc4c02","#010120","#bdbbff","#ffffff","#000000"],fonts:{heading:"The Future",body:"Inter"},tags:["dark","ai-machine-learning","minimal","playful","enterprise","modern","elegant","data-dense","gradient"]},voltagent:{description:"VoltAgent's interface is a deep-space command terminal for the AI age \u2014 a developer-facing darkness built on near-pure-black surfaces (`#050507`) where the only interruption is the electric pulse o...",category:"AI & Machine Learning",theme:"light",colors:["#00d992","#2fd6a1","#10b981","#818cf8","#306cce","#2554a0"],fonts:{heading:"system-ui",body:"Inter"},tags:["light","ai-machine-learning","playful","data-dense"]},x:{description:"xAI's website is a masterclass in dark-first, monospace-driven brutalist minimalism -- a design system that feels like it was built by engineers who understand that restraint is the ultimate form o...",category:"AI & Machine Learning",theme:"dark",colors:["#ffffff","#1f2228","#000000"],fonts:{heading:"GeistMono",body:"universalSans"},tags:["dark","ai-machine-learning","minimal","elegant","data-dense","gradient"]},cursor:{description:"Cursor's website is a study in warm minimalism meets code-editor elegance. The entire experience is built on a warm off-white canvas (`#f2f1ed`) with dark warm-brown text (`#26251e`) -- not pure bl...",category:"Developer Tools",theme:"light",colors:["#26251e","#f2f1ed","#e6e5e0","#ffffff","#000000","#f54e00"],fonts:{heading:"CursorGothic",body:"jjannon"},tags:["light","developer-tools","minimal"]},expo:{description:"Expo's interface is a luminous, confidence-radiating developer platform built on the premise that tools for building apps should feel as polished as the apps themselves. The entire experience lives...",category:"Developer Tools",theme:"dark",colors:["#000000","#1c2024","#0d74ce","#476cff","#47c2ff","#8145b5"],fonts:{heading:"Inter",body:"Inter"},tags:["dark","developer-tools","playful"]},linear:{description:"Linear's website is a masterclass in dark-mode-first product design \u2014 a near-black canvas (`#08090a`) where content emerges from darkness like starlight. The overall impression is one of extreme pr...",category:"Developer Tools",theme:"dark",colors:["#010102","#08090a","#0f1011","#191a1b","#28282c","#f7f8f8"],fonts:{heading:"Inter Variable",body:"Inter Variable"},tags:["dark","developer-tools","minimal","bold"]},lovable:{description:"Lovable's website radiates warmth through restraint. The entire page sits on a creamy, parchment-toned background (`#f7f4ed`) that immediately separates it from the cold-white conventions of most d...",category:"Developer Tools",theme:"dark",colors:["#f7f4ed","#1c1c1c","#fcfbf8","#5f5f5d","#eceae4","#3b82f6"],fonts:{heading:"Camera Plain Variable",body:"Camera Plain Variable"},tags:["dark","developer-tools","minimal"]},mintlify:{description:"Mintlify's website is a study in documentation-as-product design \u2014 a white, airy, information-rich surface that treats clarity as its highest aesthetic value. The page opens with a luminous white (...",category:"Developer Tools",theme:"light",colors:["#0d0d0d","#ffffff","#18e299","#d4fae8","#0fa76e","#c37d0d"],fonts:{heading:"Inter",body:"Inter"},tags:["light","developer-tools","minimal","bold","gradient"]},posthog:{description:"PostHog's website feels like a startup's internal wiki that escaped into the wild \u2014 warm, irreverent, and deliberately anti-corporate. The background isn't the expected crisp white or dark void of ...",category:"Developer Tools",theme:"dark",colors:["#4d4f46","#23251d","#f54e00","#f7a501","#b17816","#3b82f6"],fonts:{heading:"IBM Plex Sans Variable",body:"IBM Plex Sans Variable"},tags:["dark","developer-tools","bold","playful","modern","gradient"]},raycast:{description:"Raycast's marketing site feels like the dark interior of a precision instrument \u2014 a Swiss watch case carved from obsidian. The background isn't just dark, it's an almost-black blue-tint (`#07080a`)...",category:"Developer Tools",theme:"dark",colors:["#07080a","#ffffff","#ff6363","#55b3ff","#5fc992","#ffbc33"],fonts:{heading:"Inter",body:"16px"},tags:["dark","developer-tools","minimal","data-dense","gradient"]},resend:{description:"Resend's website is a dark, cinematic canvas that treats email infrastructure like a luxury product. The entire page is draped in pure black (`#000000`) with text that glows in near-white (`#f0f0f0...",category:"Developer Tools",theme:"light",colors:["#000000","#f0f0f0","#ffffff","#ff5900","#ff801f","#ffa057"],fonts:{heading:"domaine",body:"inter"},tags:["light","developer-tools","minimal","elegant"]},sentry:{description:"Sentry's website is a dark-mode-first developer tool interface that speaks the language of code editors and terminal windows. The entire aesthetic is rooted in deep purple-black backgrounds (`#1f16...",category:"Developer Tools",theme:"dark",colors:["#1f1633","#150f23","#362d59","#6a5fc1","#79628c","#422082"],fonts:{heading:"Dammit Sans",body:"Rubik"},tags:["dark","developer-tools","bold"]},supabase:{description:"Supabase's website is a dark-mode-native developer platform that channels the aesthetic of a premium code editor \u2014 deep black backgrounds (`#0f0f0f`, `#171717`) with emerald green accents (`#3ecf8e...",category:"Developer Tools",theme:"dark",colors:["#3ecf8e","#00c573","#0f0f0f","#171717","#242424","#2e2e2e"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["dark","developer-tools","minimal","data-dense"]},superhuman:{description:"Superhuman's website feels like opening a luxury envelope \u2014 predominantly white, immaculately clean, with a single dramatic gesture of color that commands attention. The hero section is a cinematic...",category:"Developer Tools",theme:"dark",colors:["#1b1938","#cbb7fb","#292827","#714cb6","#ffffff","#e9e5dd"],fonts:{heading:"Super Sans VF",body:"Super Sans VF"},tags:["dark","developer-tools","minimal","bold","elegant","data-dense","gradient"]},vercel:{description:"Vercel's website is the visual thesis of developer infrastructure made invisible \u2014 a design system so restrained it borders on philosophical. The page is overwhelmingly white (`#ffffff`) with near-...",category:"Developer Tools",theme:"dark",colors:["#171717","#ffffff","#000000","#ff5b4f","#de1d8d","#0a72ef"],fonts:{heading:"Geist",body:"Geist"},tags:["dark","developer-tools","minimal"]},warp:{description:"Warp's website feels like sitting at a campfire in a deep forest \u2014 warm, dark, and alive with quiet confidence. Unlike the cold, blue-tinted blacks favored by most developer tools, Warp wraps every...",category:"Developer Tools",theme:"dark",colors:["#faf9f6","#353534","#868584","#afaeac","#666469","#454545"],fonts:{heading:"Matter Regular",body:"Matter Regular"},tags:["dark","developer-tools","minimal","bold"]},zapier:{description:"Zapier's website radiates warm, approachable professionalism. It rejects the cold monochrome minimalism of developer tools in favor of a cream-tinted canvas (`#fffefb`) that feels like unbleached p...",category:"Developer Tools",theme:"dark",colors:["#201515","#fffefb","#fffdf9","#ff4f00","#36342e","#939084"],fonts:{heading:"Degular Display",body:"Inter"},tags:["dark","developer-tools","minimal","bold","enterprise","modern","elegant"]},clickhouse:{description:`ClickHouse's interface is a high-performance cockpit rendered in acid yellow-green on obsidian black \u2014 a design that screams "speed" before you read a single word. The entire experience lives in da...`,category:"Infrastructure",theme:"dark",colors:["#faff69","#166534","#14572f","#f4f692","#4f5100","#161600"],fonts:{heading:"Inter",body:"Basier"},tags:["dark","infrastructure"]},composio:{description:"Composio's interface is a nocturnal command center \u2014 a dense, developer-focused darkness punctuated by electric cyan and deep cobalt signals. The entire experience is built on an almost-pure-black ...",category:"Infrastructure",theme:"dark",colors:["#0007cd","#00ffff","#0089ff","#0096ff","#0f0f0f","#000000"],fonts:{heading:"abcDiatype",body:"Inter"},tags:["dark","infrastructure","minimal","data-dense","gradient"]},hashicorp:{description:"HashiCorp's website is enterprise infrastructure made tangible \u2014 a design system that must communicate the complexity of cloud infrastructure management while remaining approachable. The visual lan...",category:"Infrastructure",theme:"dark",colors:["#000000","#15181e","#0d0e12","#f1f2f3","#d5d7db","#b2b6bd"],fonts:{heading:"__hashicorpSans_96f0ca",body:"system-ui"},tags:["dark","infrastructure","minimal","bold","enterprise","data-dense"]},mongodb:{description:"MongoDB's website is a deep-forest-meets-terminal experience \u2014 a design system rooted in the darkest teal-black (`#001e2b`) that evokes both the density of a database and the depth of a forest cano...",category:"Infrastructure",theme:"dark",colors:["#001e2b","#00ed64","#00684a","#006cfa","#3860be","#1eaedb"],fonts:{heading:"MongoDB Value Serif",body:"Euclid Circular A"},tags:["dark","infrastructure","bold","enterprise"]},sanity:{description:"Sanity's website is a developer-content platform rendered as a nocturnal command center -- dark, precise, and deeply structured. The entire experience sits on a near-black canvas (`#0b0b0b`) that r...",category:"Infrastructure",theme:"dark",colors:["#0b0b0b","#000000","#f36458","#0052ef","#55beff","#afe3ff"],fonts:{heading:"waldenburgNormal",body:"waldenburgNormal"},tags:["dark","infrastructure","playful"]},stripe:{description:"Stripe's website is the gold standard of fintech design -- a system that manages to feel simultaneously technical and luxurious, precise and warm. The page opens on a clean white canvas (`#ffffff`)...",category:"Infrastructure",theme:"light",colors:["#533afd","#061b31","#ffffff","#1c1e54","#0d253d","#ea2261"],fonts:{heading:"Inter",body:"Inter"},tags:["light","infrastructure","minimal","bold","enterprise","modern","data-dense","gradient"]},airtable:{description:'Airtable\'s website is a clean, enterprise-friendly platform that communicates "sophisticated simplicity" through a white canvas with deep navy text (`#181d26`) and Airtable Blue (`#1b61c9`) as the ...',category:"Design & Productivity",theme:"light",colors:["#181d26","#1b61c9","#ffffff","#006400","#333333","#254fad"],fonts:{heading:"Haas",body:"Haas"},tags:["light","design-productivity","minimal","playful","enterprise"]},cal:{description:"Cal.com's website is a masterclass in monochromatic restraint \u2014 a grayscale world where boldness comes not from color but from the sheer confidence of black text on white space. Inspired by Uber's ...",category:"Design & Productivity",theme:"dark",colors:["#242424","#111111","#ffffff","#0099ff","#3b82f6","#0000ee"],fonts:{heading:"Cal Sans",body:"Inter"},tags:["dark","design-productivity","minimal","bold","modern","data-dense"]},clay:{description:"Clay's website is a warm, playful celebration of color that treats B2B data enrichment like a craft rather than an enterprise chore. The design language is built on a foundation of warm cream backg...",category:"Design & Productivity",theme:"light",colors:["#000000","#ffffff","#faf9f7","#84e7a5","#078a52","#02492a"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["light","design-productivity","playful","enterprise"]},figma:{description:"Figma's interface is the design tool that designed itself \u2014 a masterclass in typographic sophistication where a custom variable font (figmaSans) modulates between razor-thin (weight 320) and bold (...",category:"Design & Productivity",theme:"dark",colors:["#000000","#ffffff"],fonts:{heading:"figmaSans",body:"Inter"},tags:["dark","design-productivity","bold","gradient"]},framer:{description:"Framer's website is a cinematic, tool-obsessed dark canvas that radiates the confidence of a design tool built by designers who worship craft. The entire experience is drenched in pure black \u2014 not ...",category:"Design & Productivity",theme:"dark",colors:["#000000","#ffffff","#0099ff","#a6a6a6","#090909","#0000ee"],fonts:{heading:"GT Walsheim Framer Medium",body:"Inter Variable"},tags:["dark","design-productivity"]},intercom:{description:'Intercom\'s website is a warm, confident customer service platform that communicates "AI-first helpdesk" through a clean, editorial design language. The page operates on a warm off-white canvas (`#f...',category:"Design & Productivity",theme:"light",colors:["#111111","#ffffff","#faf9f6","#ff5600","#fe4c02","#65b5ff"],fonts:{heading:"Saans",body:"MediumLL"},tags:["light","design-productivity","minimal"]},miro:{description:`Miro's website is a clean, collaborative-tool-forward platform that communicates "visual thinking" through generous whitespace, pastel accent colors, and a confident geometric font. The design uses...`,category:"Design & Productivity",theme:"light",colors:["#1c1c1e","#ffffff","#5b76fe","#2a41b6","#ffc6c6","#600000"],fonts:{heading:"Roobert PRO Medium",body:"Noto Sans"},tags:["light","design-productivity","minimal","modern"]},notion:{description:"Notion's website embodies the philosophy of the tool itself: a blank canvas that gets out of your way. The design system is built on warm neutrals rather than cold grays, creating a distinctly appr...",category:"Design & Productivity",theme:"dark",colors:["#ffffff","#0075de","#213183","#005bab","#f6f5f4","#31302e"],fonts:{heading:"NotionInter",body:"NotionInter"},tags:["dark","design-productivity","minimal","bold"]},pinterest:{description:"Pinterest's website is a warm, inspiration-driven canvas that treats visual discovery like a lifestyle magazine. The design operates on a soft, slightly warm white background with Pinterest Red (`#...",category:"Design & Productivity",theme:"dark",colors:["#e60023","#103c25","#0b2819","#211922","#000000","#62625b"],fonts:{heading:"Pin Sans",body:"Pin Sans"},tags:["dark","design-productivity","bold"]},webflow:{description:'Webflow\'s website is a visually rich, tool-forward platform that communicates "design without code" through clean white surfaces, the signature Webflow Blue (`#146ef5`), and a rich secondary color ...',category:"Design & Productivity",theme:"dark",colors:["#080808","#146ef5","#3b89ff","#006acc","#0055d4","#7a3dff"],fonts:{heading:"Inter",body:"20px"},tags:["dark","design-productivity","minimal"]},coinbase:{description:"Coinbase's website is a clean, trustworthy crypto platform that communicates financial reliability through a blue-and-white binary palette. The design uses Coinbase Blue (`#0052ff`) \u2014 a deep, satur...",category:"Fintech",theme:"light",colors:["#0052ff","#ffffff","#0a0b0d","#eef0f3","#578bfa","#0667d0"],fonts:{heading:"CoinbaseDisplay",body:"CoinbaseSans"},tags:["light","fintech","minimal","enterprise"]},kraken:{description:"Kraken's website is a clean, trustworthy crypto exchange that uses purple as its commanding brand color. The design operates on white backgrounds with Kraken Purple (`#7132f5`, `#5741d8`, `#5b1ecf`...",category:"Fintech",theme:"light",colors:["#7132f5","#5741d8","#5b1ecf","#101114","#686b82","#9497a9"],fonts:{heading:"Kraken-Brand",body:"Kraken-Product"},tags:["light","fintech","minimal","bold","enterprise"]},revolut:{description:`Revolut's website is fintech confidence distilled into pixels \u2014 a design system that communicates "your money is in capable hands" through massive typography, generous whitespace, and a disciplined...`,category:"Fintech",theme:"dark",colors:["#191c1f","#ffffff","#f4f4f4","#494fdf","#4f55f1","#376cd5"],fonts:{heading:"Aeonik Pro",body:"Inter"},tags:["dark","fintech","modern"]},wise:{description:`Wise's website is a bold, confident fintech platform that communicates "money without borders" through massive typography and a distinctive lime-green accent. The design operates on a warm off-whit...`,category:"Fintech",theme:"dark",colors:["#0e0f0c","#9fe870","#163300","#e2f6d5","#cdffad","#054d28"],fonts:{heading:"Wise Sans",body:"Inter"},tags:["dark","fintech","minimal","bold","data-dense"]},airbnb:{description:"Airbnb's website is a warm, photography-forward marketplace that feels like flipping through a travel magazine where every page invites you to book. The design operates on a foundation of pure whit...",category:"Enterprise & Consumer",theme:"light",colors:["#ff385c","#e00b41","#c13515","#b32505","#460479","#92174d"],fonts:{heading:"Nunito Sans",body:"Inter"},tags:["light","enterprise-consumer","minimal","bold"]},apple:{description:"Apple's website is a masterclass in controlled drama \u2014 vast expanses of pure black and near-white serve as cinematic backdrops for products that are photographed as if they were sculptures in a gal...",category:"Enterprise & Consumer",theme:"dark",colors:["#000000","#f5f5f7","#1d1d1f","#0071e3","#0066cc","#2997ff"],fonts:{heading:"Inter",body:"Inter"},tags:["dark","enterprise-consumer","minimal","gradient"]},bmw:{description:"BMW's website is automotive engineering made visual \u2014 a design system that communicates precision, performance, and German industrial confidence. The page alternates between deep dark hero sections...",category:"Enterprise & Consumer",theme:"light",colors:["#ffffff","#1c69d4","#0653b6","#262626","#757575","#bbbbbb"],fonts:{heading:"BMWTypeNextLatin Light",body:"BMWTypeNextLatin"},tags:["light","enterprise-consumer","minimal","elegant"]},ibm:{description:"IBM's website is the digital embodiment of enterprise authority built on the Carbon Design System \u2014 a design language so methodically structured it reads like an engineering specification rendered ...",category:"Enterprise & Consumer",theme:"dark",colors:["#0f62fe","#ffffff","#161616","#262626","#393939","#525252"],fonts:{heading:"IBM Plex Sans",body:"Inter"},tags:["dark","enterprise-consumer","minimal","playful","enterprise"]},nvidia:{description:"NVIDIA's website is a high-contrast, technology-forward experience that communicates raw computational power through design restraint. The page is built on a stark black (`#000000`) and white (`#ff...",category:"Enterprise & Consumer",theme:"dark",colors:["#76b900","#000000","#ffffff","#bff230","#df6500","#ef9100"],fonts:{heading:"NVIDIA-EMEA",body:"NVIDIA-EMEA"},tags:["dark","enterprise-consumer","minimal","bold","playful","data-dense"]},spacex:{description:"SpaceX's website is a full-screen cinematic experience that treats aerospace engineering like a film \u2014 every section is a scene, every photograph is a frame, and the interface disappears entirely b...",category:"Enterprise & Consumer",theme:"dark",colors:["#000000","#f0f0fa"],fonts:{heading:"DM Sans",body:"DM Sans"},tags:["dark","enterprise-consumer","minimal","bold"]},spotify:{description:"Spotify's web interface is a dark, immersive music player that wraps listeners in a near-black cocoon (`#121212`, `#181818`, `#1f1f1f`) where album art and content become the primary source of colo...",category:"Enterprise & Consumer",theme:"dark",colors:["#1ed760","#121212","#181818","#1f1f1f","#ffffff","#b3b3b3"],fonts:{heading:"Inter",body:"SpotifyMixUI"},tags:["dark","enterprise-consumer","bold"]},uber:{description:"Uber's design language is a masterclass in confident minimalism -- a black-and-white universe where every pixel serves a purpose and nothing decorates without earning its place. The entire experien...",category:"Enterprise & Consumer",theme:"dark",colors:["#000000","#ffffff","#e2e2e2","#f3f3f3","#efefef","#4b4b4b"],fonts:{heading:"Inter",body:"UberMoveText"},tags:["dark","enterprise-consumer","minimal","bold","playful","data-dense"]}};function bt(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function me(r){let e=r.toLowerCase().replace(/[^a-z0-9]/g,"");return ft.find(t=>t.id===r||t.id.toLowerCase().replace(/[^a-z0-9]/g,"")===e||t.name.toLowerCase().replace(/[^a-z0-9]/g,"")===e)}function He(r){return Jt[r]}function Yt(r){return!r||r==="All"?ft:ft.filter(e=>e.category.toLowerCase()===r.toLowerCase())}function Qt(r){return Yt(r).map(t=>{let a=Jt[t.id];return{id:t.id,slug:bt(t.name),name:t.name,category:t.category,description:a?.description??"",theme:a?.theme??"light",colors:a?.colors??[],fonts:a?.fonts??{heading:"Inter",body:"Inter"},tags:a?.tags??[]}})}function cr(r){let e=r??ft,t={};for(let n of e)(t[n.category]??=[]).push(n);let a=[];for(let[n,o]of Object.entries(t)){a.push(`**${n}**`);for(let i of o){let s=Jt[i.id];a.push(` - ${i.name} (${i.id}) \u2014 ${s?.theme??"light"}, ${s?.description?.slice(0,60)??""}`)}}return a.join(`
9231
+ `)}function pr(r,e){let t=me(r);if(!t)return null;let a=lr[e]??lr.general;if(!a)return null;let n=t.sections.filter(o=>a.some(i=>o.title.toLowerCase().includes(i)));return n.length===0?null:n.map(o=>`## ${o.title}
10802
9232
 
10803
9233
  ${o.content}`).join(`
10804
9234
 
10805
9235
  ---
10806
9236
 
10807
- `)}function lr(r,e){let t=e?.maxResults??3,a=r.toLowerCase(),n=[[/\bcohere\b/i,"cohere"],[/\belevenlabs\b/i,"elevenlabs"],[/\bminimax\b/i,"minimax"],[/\bmistral ai\b/i,"mistral"],[/\bollama\b/i,"ollama"],[/\bopencode ai\b/i,"opencode"],[/\breplicate\b/i,"replicate"],[/\brunwayml\b/i,"runwayml"],[/\btogether ai\b/i,"together"],[/\bvoltagent\b/i,"voltagent"],[/\bxai\b/i,"x"],[/\bcursor\b/i,"cursor"],[/\bexpo\b/i,"expo"],[/\blinear\b/i,"linear"],[/\blovable\b/i,"lovable"],[/\bmintlify\b/i,"mintlify"],[/\bposthog\b/i,"posthog"],[/\braycast\b/i,"raycast"],[/\bresend\b/i,"resend"],[/\bsentry\b/i,"sentry"],[/\bsupabase\b/i,"supabase"],[/\bsuperhuman\b/i,"superhuman"],[/\bvercel\b/i,"vercel"],[/\bwarp\b/i,"warp"],[/\bzapier\b/i,"zapier"],[/\bclickhouse\b/i,"clickhouse"],[/\bcomposio\b/i,"composio"],[/\bhashicorp\b/i,"hashicorp"],[/\bmongodb\b/i,"mongodb"],[/\bsanity\b/i,"sanity"],[/\bstripe\b/i,"stripe"],[/\bairtable\b/i,"airtable"],[/\bcal\.com\b/i,"cal"],[/\bclay\b/i,"clay"],[/\bfigma\b/i,"figma"],[/\bframer\b/i,"framer"],[/\bintercom\b/i,"intercom"],[/\bmiro\b/i,"miro"],[/\bnotion\b/i,"notion"],[/\bpinterest\b/i,"pinterest"],[/\bwebflow\b/i,"webflow"],[/\bcoinbase\b/i,"coinbase"],[/\bkraken\b/i,"kraken"],[/\brevolut\b/i,"revolut"],[/\bwise\b/i,"wise"],[/\bairbnb\b/i,"airbnb"],[/\bapple\b/i,"apple"],[/\bbmw\b/i,"bmw"],[/\bibm\b/i,"ibm"],[/\bnvidia\b/i,"nvidia"],[/\bspacex\b/i,"spacex"],[/\bspotify\b/i,"spotify"],[/\buber\b/i,"uber"]],o=[[/\bdashboard|analytics|saas|admin\b/i,["linear","vercel","posthog","supabase","sentry"],3],[/\bai|machine.?learning|llm|chatbot\b/i,["mistral","opencode","cohere","replicate"],3],[/\bfintech|payment|banking|wallet\b/i,["stripe","revolut","wise","coinbase"],3],[/\bminimal|clean|simple\b/i,["notion","linear","cal","resend"],2],[/\bbold|cinematic|dramatic\b/i,["spacex","bmw","nvidia","apple"],2],[/\bcreative|design|portfolio\b/i,["figma","framer","webflow","pinterest"],2],[/\bproductivity|workspace|docs|notes\b/i,["notion","airtable","miro","superhuman"],2],[/\be-?commerce|marketplace|booking\b/i,["airbnb","spotify","uber","stripe"],2],[/\bdev.?tool|developer|api|cli\b/i,["vercel","linear","supabase","raycast","warp"],2],[/\bmusic|media|streaming\b/i,["spotify","elevenlabs","runwayml"],2],[/\bdark.?mode|dark.?theme\b/i,["linear","cursor","warp","raycast","spacex"],1],[/\blight|bright|white\b/i,["notion","airbnb","stripe","cal"],1]],i={};for(let[d,p]of n)d.test(a)&&(i[p]=(i[p]??0)+10);for(let[d,p,u]of o)if(d.test(a))for(let h of p)i[h]=(i[h]??0)+u;return Jt().map(d=>({...d,score:i[d.id]??0})).sort((d,p)=>p.score+Math.random()*.5-(d.score+Math.random()*.5)).slice(0,t)}var Yt={"resend-email":{description:"Transactional email with React Email templates and webhook handling.",tags:["email","transactional","welcome","notification","invite","alert"],envVars:[{key:"RESEND_API_KEY",description:"Resend API key for sending emails",setupUrl:"https://resend.com/api-keys"}],docsUrl:"https://resend.com/docs/send-with-nextjs",packages:["resend","@react-email/components"],difficulty:"easy"},"r2-storage":{description:"File uploads with drag-and-drop UI, stored in Cloudflare R2.",tags:["storage","upload","file","image","media","attachment","avatar"],envVars:[],docsUrl:"https://developers.cloudflare.com/r2/",packages:[],difficulty:"easy"},"openai-ai":{description:"AI-powered features with OpenAI SDK, streaming chat, and content generation.",tags:["ai","openai","chatbot","gpt","llm","assistant","generation"],envVars:[{key:"OPENAI_API_KEY",description:"OpenAI API key for AI features",setupUrl:"https://platform.openai.com/api-keys"}],docsUrl:"https://platform.openai.com/docs/guides/text-generation",packages:["openai","ai"],difficulty:"medium"},"anthropic-ai":{description:"AI features with the Anthropic SDK, streaming Claude chat, and content generation.",tags:["ai","anthropic","claude","llm","assistant","generation"],envVars:[{key:"ANTHROPIC_API_KEY",description:"Anthropic API key for Claude",setupUrl:"https://console.anthropic.com/settings/keys"}],docsUrl:"https://docs.anthropic.com/en/docs/initial-setup",packages:["@anthropic-ai/sdk","ai"],difficulty:"medium"},"openrouter-ai":{description:"AI model router with access to 200+ models (GPT, Claude, Llama, Mistral, etc.) through one API.",tags:["ai","openrouter","llm","multi-model","claude","gpt","llama","mistral"],envVars:[{key:"OPENROUTER_API_KEY",description:"OpenRouter API key",setupUrl:"https://openrouter.ai/keys"}],docsUrl:"https://openrouter.ai/docs/quickstart",packages:["@openrouter/sdk"],difficulty:"easy"},"stripe-payments":{description:"Payment processing with Stripe Checkout, webhooks, and billing portal.",tags:["payments","stripe","billing","subscription","checkout","invoice"],envVars:[{key:"STRIPE_SECRET_KEY",description:"Stripe secret key",setupUrl:"https://dashboard.stripe.com/apikeys"},{key:"STRIPE_PUBLISHABLE_KEY",description:"Stripe publishable key (client-side)",setupUrl:"https://dashboard.stripe.com/apikeys"},{key:"STRIPE_WEBHOOK_SECRET",description:"Stripe webhook signing secret",setupUrl:"https://dashboard.stripe.com/webhooks"}],docsUrl:"https://docs.stripe.com/checkout/quickstart",packages:["stripe","@stripe/stripe-js"],difficulty:"advanced"},"elevenlabs-voice":{description:"Text-to-speech and voice generation with ElevenLabs API.",tags:["voice","tts","speech","audio","elevenlabs","narration","podcast"],envVars:[{key:"ELEVENLABS_API_KEY",description:"ElevenLabs API key for voice generation",setupUrl:"https://elevenlabs.io/app/settings/api-keys"}],docsUrl:"https://elevenlabs.io/docs/api-reference/text-to-speech",packages:["elevenlabs"],difficulty:"medium"},"google-maps":{description:"Google Maps embed, Places autocomplete, and geolocation features.",tags:["maps","location","google","places","geocoding","directions","nearby"],envVars:[{key:"NEXT_PUBLIC_GOOGLE_MAPS_API_KEY",description:"Google Maps API key (client-side)",setupUrl:"https://console.cloud.google.com/apis/credentials"}],docsUrl:"https://developers.google.com/maps/documentation/javascript",packages:["@googlemaps/js-api-loader"],difficulty:"medium"},"twilio-sms":{description:"SMS notifications, OTP verification, and phone number validation.",tags:["sms","twilio","otp","phone","verification","text-message"],envVars:[{key:"TWILIO_ACCOUNT_SID",description:"Twilio account SID",setupUrl:"https://console.twilio.com/"},{key:"TWILIO_AUTH_TOKEN",description:"Twilio auth token",setupUrl:"https://console.twilio.com/"},{key:"TWILIO_PHONE_NUMBER",description:"Twilio phone number for sending SMS",setupUrl:"https://console.twilio.com/us1/develop/phone-numbers/manage/incoming"}],docsUrl:"https://www.twilio.com/docs/messaging/quickstart/node",packages:["twilio"],difficulty:"medium"},"posthog-analytics":{description:"Product analytics with event tracking, feature flags, and session replay.",tags:["analytics","posthog","tracking","funnel","event","feature-flag"],envVars:[{key:"NEXT_PUBLIC_POSTHOG_KEY",description:"PostHog project API key",setupUrl:"https://app.posthog.com/project/settings"},{key:"NEXT_PUBLIC_POSTHOG_HOST",description:"PostHog instance URL (default: https://us.i.posthog.com)",setupUrl:"https://app.posthog.com/project/settings"}],docsUrl:"https://posthog.com/docs/libraries/next-js",packages:["posthog-js","posthog-node"],difficulty:"easy"},"firecrawl-scraping":{description:"Web scraping and crawling with markdown output, structured extraction, and async crawls.",tags:["scraping","crawl","firecrawl","web","extract","rag","markdown"],envVars:[{key:"FIRECRAWL_API_KEY",description:"Firecrawl API key",setupUrl:"https://firecrawl.dev"}],docsUrl:"https://docs.firecrawl.dev/sdks/node",packages:["@mendable/firecrawl-js"],difficulty:"easy"},"replicate-media":{description:"Image and video generation with 200+ AI models (Flux, Wan Video, Runway, SDXL, etc.) through one API.",tags:["image","video","replicate","flux","sdxl","generation","media","avatar","thumbnail"],envVars:[{key:"REPLICATE_API_TOKEN",description:"Replicate API token",setupUrl:"https://replicate.com/account/api-tokens"}],docsUrl:"https://replicate.com/docs/get-started/nodejs",packages:["replicate"],difficulty:"medium"}},$e=[{id:"resend-email",name:"Resend Email",category:"communication",prompt:`## Resend Email Integration
9237
+ `)}function ur(r,e){let t=e?.maxResults??3,a=r.toLowerCase(),n=[[/\bcohere\b/i,"cohere"],[/\belevenlabs\b/i,"elevenlabs"],[/\bminimax\b/i,"minimax"],[/\bmistral ai\b/i,"mistral"],[/\bollama\b/i,"ollama"],[/\bopencode ai\b/i,"opencode"],[/\breplicate\b/i,"replicate"],[/\brunwayml\b/i,"runwayml"],[/\btogether ai\b/i,"together"],[/\bvoltagent\b/i,"voltagent"],[/\bxai\b/i,"x"],[/\bcursor\b/i,"cursor"],[/\bexpo\b/i,"expo"],[/\blinear\b/i,"linear"],[/\blovable\b/i,"lovable"],[/\bmintlify\b/i,"mintlify"],[/\bposthog\b/i,"posthog"],[/\braycast\b/i,"raycast"],[/\bresend\b/i,"resend"],[/\bsentry\b/i,"sentry"],[/\bsupabase\b/i,"supabase"],[/\bsuperhuman\b/i,"superhuman"],[/\bvercel\b/i,"vercel"],[/\bwarp\b/i,"warp"],[/\bzapier\b/i,"zapier"],[/\bclickhouse\b/i,"clickhouse"],[/\bcomposio\b/i,"composio"],[/\bhashicorp\b/i,"hashicorp"],[/\bmongodb\b/i,"mongodb"],[/\bsanity\b/i,"sanity"],[/\bstripe\b/i,"stripe"],[/\bairtable\b/i,"airtable"],[/\bcal\.com\b/i,"cal"],[/\bclay\b/i,"clay"],[/\bfigma\b/i,"figma"],[/\bframer\b/i,"framer"],[/\bintercom\b/i,"intercom"],[/\bmiro\b/i,"miro"],[/\bnotion\b/i,"notion"],[/\bpinterest\b/i,"pinterest"],[/\bwebflow\b/i,"webflow"],[/\bcoinbase\b/i,"coinbase"],[/\bkraken\b/i,"kraken"],[/\brevolut\b/i,"revolut"],[/\bwise\b/i,"wise"],[/\bairbnb\b/i,"airbnb"],[/\bapple\b/i,"apple"],[/\bbmw\b/i,"bmw"],[/\bibm\b/i,"ibm"],[/\bnvidia\b/i,"nvidia"],[/\bspacex\b/i,"spacex"],[/\bspotify\b/i,"spotify"],[/\buber\b/i,"uber"]],o=[[/\bdashboard|analytics|saas|admin\b/i,["linear","vercel","posthog","supabase","sentry"],3],[/\bai|machine.?learning|llm|chatbot\b/i,["mistral","opencode","cohere","replicate"],3],[/\bfintech|payment|banking|wallet\b/i,["stripe","revolut","wise","coinbase"],3],[/\bminimal|clean|simple\b/i,["notion","linear","cal","resend"],2],[/\bbold|cinematic|dramatic\b/i,["spacex","bmw","nvidia","apple"],2],[/\bcreative|design|portfolio\b/i,["figma","framer","webflow","pinterest"],2],[/\bproductivity|workspace|docs|notes\b/i,["notion","airtable","miro","superhuman"],2],[/\be-?commerce|marketplace|booking\b/i,["airbnb","spotify","uber","stripe"],2],[/\bdev.?tool|developer|api|cli\b/i,["vercel","linear","supabase","raycast","warp"],2],[/\bmusic|media|streaming\b/i,["spotify","elevenlabs","runwayml"],2],[/\bdark.?mode|dark.?theme\b/i,["linear","cursor","warp","raycast","spacex"],1],[/\blight|bright|white\b/i,["notion","airbnb","stripe","cal"],1]],i={};for(let[d,u]of n)d.test(a)&&(i[u]=(i[u]??0)+10);for(let[d,u,p]of o)if(d.test(a))for(let h of u)i[h]=(i[h]??0)+p;return Qt().map(d=>({...d,score:i[d.id]??0})).sort((d,u)=>u.score+Math.random()*.5-(d.score+Math.random()*.5)).slice(0,t)}var Xt={"resend-email":{description:"Transactional email with React Email templates and webhook handling.",tags:["email","transactional","welcome","notification","invite","alert"],envVars:[{key:"RESEND_API_KEY",description:"Resend API key for sending emails",setupUrl:"https://resend.com/api-keys"}],docsUrl:"https://resend.com/docs/send-with-nextjs",packages:["resend","@react-email/components"],difficulty:"easy"},"r2-storage":{description:"File uploads with drag-and-drop UI, stored in Cloudflare R2.",tags:["storage","upload","file","image","media","attachment","avatar"],envVars:[],docsUrl:"https://developers.cloudflare.com/r2/",packages:[],difficulty:"easy"},"openai-ai":{description:"AI-powered features with OpenAI SDK, streaming chat, and content generation.",tags:["ai","openai","chatbot","gpt","llm","assistant","generation"],envVars:[{key:"OPENAI_API_KEY",description:"OpenAI API key for AI features",setupUrl:"https://platform.openai.com/api-keys"}],docsUrl:"https://platform.openai.com/docs/guides/text-generation",packages:["openai","ai"],difficulty:"medium"},"anthropic-ai":{description:"AI features with the Anthropic SDK, streaming Claude chat, and content generation.",tags:["ai","anthropic","claude","llm","assistant","generation"],envVars:[{key:"ANTHROPIC_API_KEY",description:"Anthropic API key for Claude",setupUrl:"https://console.anthropic.com/settings/keys"}],docsUrl:"https://docs.anthropic.com/en/docs/initial-setup",packages:["@anthropic-ai/sdk","ai"],difficulty:"medium"},"openrouter-ai":{description:"AI model router with access to 200+ models (GPT, Claude, Llama, Mistral, etc.) through one API.",tags:["ai","openrouter","llm","multi-model","claude","gpt","llama","mistral"],envVars:[{key:"OPENROUTER_API_KEY",description:"OpenRouter API key",setupUrl:"https://openrouter.ai/keys"}],docsUrl:"https://openrouter.ai/docs/quickstart",packages:["@openrouter/sdk"],difficulty:"easy"},"stripe-payments":{description:"Payment processing with Stripe Checkout, webhooks, and billing portal.",tags:["payments","stripe","billing","subscription","checkout","invoice"],envVars:[{key:"STRIPE_SECRET_KEY",description:"Stripe secret key",setupUrl:"https://dashboard.stripe.com/apikeys"},{key:"STRIPE_PUBLISHABLE_KEY",description:"Stripe publishable key (client-side)",setupUrl:"https://dashboard.stripe.com/apikeys"},{key:"STRIPE_WEBHOOK_SECRET",description:"Stripe webhook signing secret",setupUrl:"https://dashboard.stripe.com/webhooks"}],docsUrl:"https://docs.stripe.com/checkout/quickstart",packages:["stripe","@stripe/stripe-js"],difficulty:"advanced"},"elevenlabs-voice":{description:"Text-to-speech and voice generation with ElevenLabs API.",tags:["voice","tts","speech","audio","elevenlabs","narration","podcast"],envVars:[{key:"ELEVENLABS_API_KEY",description:"ElevenLabs API key for voice generation",setupUrl:"https://elevenlabs.io/app/settings/api-keys"}],docsUrl:"https://elevenlabs.io/docs/api-reference/text-to-speech",packages:["elevenlabs"],difficulty:"medium"},"google-maps":{description:"Google Maps embed, Places autocomplete, and geolocation features.",tags:["maps","location","google","places","geocoding","directions","nearby"],envVars:[{key:"NEXT_PUBLIC_GOOGLE_MAPS_API_KEY",description:"Google Maps API key (client-side)",setupUrl:"https://console.cloud.google.com/apis/credentials"}],docsUrl:"https://developers.google.com/maps/documentation/javascript",packages:["@googlemaps/js-api-loader"],difficulty:"medium"},"twilio-sms":{description:"SMS notifications, OTP verification, and phone number validation.",tags:["sms","twilio","otp","phone","verification","text-message"],envVars:[{key:"TWILIO_ACCOUNT_SID",description:"Twilio account SID",setupUrl:"https://console.twilio.com/"},{key:"TWILIO_AUTH_TOKEN",description:"Twilio auth token",setupUrl:"https://console.twilio.com/"},{key:"TWILIO_PHONE_NUMBER",description:"Twilio phone number for sending SMS",setupUrl:"https://console.twilio.com/us1/develop/phone-numbers/manage/incoming"}],docsUrl:"https://www.twilio.com/docs/messaging/quickstart/node",packages:["twilio"],difficulty:"medium"},"posthog-analytics":{description:"Product analytics with event tracking, feature flags, and session replay.",tags:["analytics","posthog","tracking","funnel","event","feature-flag"],envVars:[{key:"NEXT_PUBLIC_POSTHOG_KEY",description:"PostHog project API key",setupUrl:"https://app.posthog.com/project/settings"},{key:"NEXT_PUBLIC_POSTHOG_HOST",description:"PostHog instance URL (default: https://us.i.posthog.com)",setupUrl:"https://app.posthog.com/project/settings"}],docsUrl:"https://posthog.com/docs/libraries/next-js",packages:["posthog-js","posthog-node"],difficulty:"easy"},"firecrawl-scraping":{description:"Web scraping and crawling with markdown output, structured extraction, and async crawls.",tags:["scraping","crawl","firecrawl","web","extract","rag","markdown"],envVars:[{key:"FIRECRAWL_API_KEY",description:"Firecrawl API key",setupUrl:"https://firecrawl.dev"}],docsUrl:"https://docs.firecrawl.dev/sdks/node",packages:["@mendable/firecrawl-js"],difficulty:"easy"},"replicate-media":{description:"Image and video generation with 200+ AI models (Flux, Wan Video, Runway, SDXL, etc.) through one API.",tags:["image","video","replicate","flux","sdxl","generation","media","avatar","thumbnail"],envVars:[{key:"REPLICATE_API_TOKEN",description:"Replicate API token",setupUrl:"https://replicate.com/account/api-tokens"}],docsUrl:"https://replicate.com/docs/get-started/nodejs",packages:["replicate"],difficulty:"medium"}},$e=[{id:"resend-email",name:"Resend Email",category:"communication",prompt:`## Resend Email Integration
10808
9238
 
10809
9239
  ### File Structure
10810
9240
  \`\`\`
@@ -12224,28 +10654,29 @@ export function ImageGenerator() {
12224
10654
  5. **Replicate charges per prediction.** Flux Schnell is ~$0.003/image. Flux Pro is ~$0.05/image. Video models are $0.05-$0.50/generation. Show generation cost to users.
12225
10655
  6. **Cache generated images.** Store output URLs in your database. Replicate URLs expire after a few hours. Download and re-host on R2 for permanent storage.
12226
10656
  7. **Network I/O does NOT count as CPU time on Workers.** Image generation wait time is all network I/O.
12227
- 8. **Never ask the user to paste REPLICATE_API_TOKEN in chat.** Direct them to set it in the Mistflow dashboard (Project Settings > Environment Variables).`}];function Hi(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function Ve(r){let e=$e.find(a=>a.id===r);if(e)return e;let t=r.toLowerCase().replace(/[^a-z0-9]/g,"");return $e.find(a=>{let n=a.name.toLowerCase().replace(/[^a-z0-9]/g,"");return n===t||n.includes(t)||t.includes(n)})}function qe(r){return Yt[r]}function Qt(r){return r?$e.filter(e=>e.category.toLowerCase()===r.toLowerCase()):$e}function dr(r){let e=r??$e,t={};for(let n of e){t[n.category]||(t[n.category]=[]);let o=Yt[n.id],i=o?` \u2014 ${o.description}`:"",l=o?.packages.length?` (${o.packages.join(", ")})`:"";t[n.category].push(`${n.id} \u2014 "${n.name}"${i}${l}`)}let a=[];for(let[n,o]of Object.entries(t))a.push(`**${n}**:
10657
+ 8. **Never ask the user to paste REPLICATE_API_TOKEN in chat.** Direct them to set it in the Mistflow dashboard (Project Settings > Environment Variables).`}];function ji(r){return r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function Ve(r){let e=$e.find(a=>a.id===r);if(e)return e;let t=r.toLowerCase().replace(/[^a-z0-9]/g,"");return $e.find(a=>{let n=a.name.toLowerCase().replace(/[^a-z0-9]/g,"");return n===t||n.includes(t)||t.includes(n)})}function qe(r){return Xt[r]}function Zt(r){return r?$e.filter(e=>e.category.toLowerCase()===r.toLowerCase()):$e}function hr(r){let e=r??$e,t={};for(let n of e){t[n.category]||(t[n.category]=[]);let o=Xt[n.id],i=o?` \u2014 ${o.description}`:"",s=o?.packages.length?` (${o.packages.join(", ")})`:"";t[n.category].push(`${n.id} \u2014 "${n.name}"${i}${s}`)}let a=[];for(let[n,o]of Object.entries(t))a.push(`**${n}**:
12228
10658
  ${o.map(i=>` - ${i}`).join(`
12229
10659
  `)}`);return a.join(`
12230
10660
 
12231
- `)}function cr(r){return(r?Qt(r):$e).map(t=>{let a=Yt[t.id];return{id:t.id,slug:Hi(t.name),name:t.name,category:t.category,description:a?.description??"",tags:a?.tags??[],envVars:a?.envVars??[],docsUrl:a?.docsUrl??"",packages:a?.packages??[],difficulty:a?.difficulty??"medium"}})}var Gi=[{name:"Dashboard",description:"Overview with key stats and today's activity",condition:r=>r.surfaceType==="internal-tool"||r.surfaceType==="customer-app",keywords:/\b(dashboard|overview|home.?page|stats)\b/i},{name:"Landing Page",description:"Public page explaining what this does",condition:r=>r.publicLanding===!0,keywords:/\b(landing|marketing|hero|homepage)\b/i},{name:"Scheduling / Booking",description:"Calendar, time slots, reservations",condition:r=>r.scheduling===!0,keywords:/\b(schedul|book|reserv|appointment|calendar|slot)\b/i},{name:"Payments / Billing",description:"Charge users, invoices, subscriptions (experimental \u2014 Stripe integration is early-stage)",condition:()=>!1,keywords:/\b(payment|billing|invoice|subscription|checkout|stripe)\b/i},{name:"Admin Panel",description:"Manage users, roles, and content",condition:r=>r.multiRole===!0||r.primaryActor==="both",keywords:/\b(admin|panel|manage.?user|moderat)\b/i},{name:"User Profiles",description:"Account pages, settings, preferences",condition:r=>r.primaryActor==="customers"||r.primaryActor==="both",keywords:/\b(profile|account|settings|preferences)\b/i},{name:"Search / Browse",description:"Find and filter content or listings",condition:r=>r.surfaceType==="marketplace",keywords:/\b(search|browse|filter|discover|explore)\b/i},{name:"Email Notifications",description:"Welcome emails, alerts, reminders",condition:r=>r.integrations?.includes("email")===!0,keywords:/\b(notification|alert|reminder|email.?notif|sms|welcome.?email)\b/i},{name:"Analytics / Reports",description:"Usage stats, trends, data exports",condition:()=>!1,keywords:/\b(analytics|report|chart|trend|insight|metric)\b/i},{name:"File Uploads",description:"Images, documents, attachments",condition:r=>r.integrations?.includes("file-uploads")===!0,keywords:/\b(upload|image|photo|attachment|document|gallery|file)\b/i},{name:"AI Features",description:"Chatbot, content generation, AI assistant",condition:r=>r.integrations?.includes("ai")===!0,keywords:/\b(ai|chatbot|gpt|llm|generat|assistant)\b/i},{name:"Maps / Location",description:"Google Maps, location search, geolocation",condition:r=>r.integrations?.includes("maps")===!0,keywords:/\b(map|location|address|geo|places)\b/i},{name:"Voice / TTS",description:"Text-to-speech, voice notes, audio generation",condition:()=>!1,keywords:/\b(voice|tts|text.?to.?speech|audio|speak|narrat|podcast|elevenlabs)\b/i},{name:"SMS / Text Messages",description:"Send SMS notifications, OTP verification",condition:r=>r.integrations?.includes("sms")===!0,keywords:/\b(sms|text.?message|twilio|otp|verification.?code|phone.?verif)\b/i},{name:"Web Scraping",description:"Scrape URLs, crawl websites, extract structured data",condition:()=>!1,keywords:/\b(scrape|crawl|web.?scrap|extract.?from.?url|read.?url|ingest.?web|firecrawl)\b/i},{name:"Chat / Messaging",description:"Real-time messaging between users",condition:()=>!1,keywords:/\b(chat|messag|inbox|conversation|dm)\b/i},{name:"Events / Tournaments",description:"Create and manage events, registrations",condition:()=>!1,keywords:/\b(event|tournament|competition|league|registration)\b/i},{name:"High Scores",description:"Track and display top scores with a leaderboard",condition:r=>r.surfaceType==="game",keywords:/\b(high.?score|leaderboard|top.?score|ranking|scoreboard)\b/i},{name:"Save Progress",description:"Save and resume game state between sessions",condition:r=>r.surfaceType==="game",keywords:/\b(save|progress|resume|checkpoint|continue)\b/i},{name:"Guest Play",description:"Play immediately without signing up, optionally link account later",condition:r=>r.surfaceType==="game",keywords:/\b(guest|anonymous|no.?login|play.?now|instant.?play)\b/i},{name:"Levels / Stages",description:"Progressive difficulty with unlockable stages",condition:()=>!1,keywords:/\b(level|stage|unlock|difficult|progress|world)\b/i},{name:"Achievements",description:"Badges, trophies, and milestones for player accomplishments",condition:()=>!1,keywords:/\b(achieve|badge|trophy|milestone|reward|unlock)\b/i},{name:"Daily Challenge",description:"New puzzle or challenge every day to keep players coming back",condition:()=>!1,keywords:/\b(daily|challenge|streak|word.?of.?the.?day|puzzle.?of)\b/i}];function pr(r,e,t){let a=t?.suggestedName||Wi(r),n=e.primaryActor==="both"?"Staff + Customers":e.primaryActor==="staff"?"Staff / Admin":e.primaryActor==="customers"?"End Users":"Users",o=e.audienceType??(e.surfaceType==="internal-tool"?"internal":(e.primaryActor==="customers"||e.primaryActor==="both","b2c")),i=e.surfaceType==="internal-tool"?"Internal tool":e.surfaceType==="marketplace"?"Marketplace":e.surfaceType==="content-site"?"Content site":e.surfaceType==="game"?"Game":"App",l;if(t?.suggestedFeatures&&t.suggestedFeatures.length>0)l=t.suggestedFeatures.map(s=>({name:s.name,description:s.description,checked:s.recommended,source:s.recommended?"explicit":"suggested"}));else{let s=`${r} ${e.primaryAction||""}`;l=[];for(let d of Gi){let p=d.keywords.test(s),u=d.condition(e);(p||u)&&l.push({name:d.name,description:d.description,checked:p,source:p?"explicit":"suggested"})}}return{name:a,audience:n,audienceType:o,surfaceType:i,primaryAction:e.primaryAction||"manage items",features:l,publicLanding:e.publicLanding??!1,authModel:e.authModel??"email",dbProvider:e.dbProvider??"neon",integrations:e.integrations??[],language:t?.language||"English"}}function ur(r){let e=r.features.filter(l=>l.checked),t=r.features.filter(l=>!l.checked),a={email:"Email sign-up",none:"No login (public)",social:"Social login","invite-only":"Invite-only"},n={neon:"Postgres",turso:"SQLite (legacy)"},o={b2c:"Your customers use this app (business-to-customer)",b2b:"Other businesses sign up for this (SaaS platform)",internal:"Internal team tool (staff only)"},i=[`**${r.name}** \u2014 ${r.surfaceType} for ${r.audience}`,`Audience: ${o[r.audienceType]??r.audienceType}`,`Primary action: ${r.primaryAction}`,`Access: ${a[r.authModel]??r.authModel} | Database: ${n[r.dbProvider]??r.dbProvider}${r.publicLanding?" | Landing page: Yes":""}${r.language&&r.language!=="English"?` | Language: ${r.language}`:""}`,""];if(e.length>0){i.push("**Included:**");for(let l of e)i.push(` \u2713 ${l.name} \u2014 ${l.description}`)}if(r.integrations.length>0&&(i.push(""),i.push(`**Integrations:** ${r.integrations.join(", ")}`)),t.length>0){i.push(""),i.push("**Available to add:**");for(let l of t)i.push(` \u25CB ${l.name} \u2014 ${l.description}`)}return i.join(`
12232
- `)}function Wi(r){let e=r.match(/\b(?:called|named)\s+["']?([A-Za-z][A-Za-z0-9 ]{1,30})["']?/i);if(e)return Xt(e[1]);let t=new Set(["build","create","make","a","an","the","for","me","my","app","application","website","web","tool","system","platform","using","with","and","that","this","want","need","please","can","you","i","mist","mistflow"]),n=r.toLowerCase().replace(/[^a-z0-9\s]/g,"").split(/\s+/).filter(o=>o.length>2&&!t.has(o)).slice(0,3);return n.length===0?"my-app":n.join("-")}function Xt(r){return r.toLowerCase().replace(/[^a-z0-9\s]/g,"").trim().replace(/\s+/g,"-")}var xt="__mistflow_url_choice__",Ki=600*1e3;function fr(){let r=me(He(),".mistflow","confirm-secret");if(tt(r))try{return Buffer.from(gr(r,"utf-8").trim(),"hex")}catch{}let e=Vi(32);return Zt(me(He(),".mistflow"),{recursive:!0}),ea(r,e.toString("hex"),{mode:384}),e}function br(r){return $i("sha256").update(r.trim().toLowerCase()).digest("hex").slice(0,16)}function Ji(r,e){let t={cwd:r,d:br(e),exp:Date.now()+Ki},a=Buffer.from(JSON.stringify(t)).toString("base64url"),n=mr("sha256",fr()).update(a).digest("base64url");return`${a}.${n}`}function Yi(r,e,t){let a=r.split(".");if(a.length!==2)return!1;let[n,o]=a,i=mr("sha256",fr()).update(n).digest("base64url"),l=Buffer.from(o),s=Buffer.from(i);if(l.length!==s.length||!qi(l,s))return!1;try{let d=JSON.parse(Buffer.from(n,"base64url").toString("utf-8"));return!(typeof d.exp!="number"||Date.now()>d.exp||d.cwd!==e||d.d!==br(t))}catch{return!1}}function Qi(r){let e=r,t=He(),a=!1;for(let n=0;n<64;n++){if(tt(me(e,"mistflow.json")))return"mistflow";if(!a&&tt(me(e,"package.json"))&&(a=!0),e===t)break;let o=zi(e);if(o===e)break;e=o}return a?"foreign":"none"}var Xi=te.object({description:te.string().min(1,"App description or modification request"),conversationId:te.string().optional().describe("Returned by a previous mist_plan call with status 'clarify'. Pass it back to continue the conversation."),answers:te.record(te.string()).optional().describe("User's answers to the clarifying questions from the previous round. Keys are the questions, values are the answers."),existingPlan:te.record(te.unknown()).optional().describe("If provided, modifies this existing plan instead of creating a new one. Pass the current plan object from mistflow.json."),existingPlanId:te.string().optional().describe("Alternative to existingPlan \u2014 pass the planId from a previous mist_plan call to modify that plan."),templateToken:te.string().optional().describe("Fork from a shared template. Pass the share token (from a mistflow.ai/t/... URL) to clone that project's plan into your workspace."),remixDescription:te.string().optional().describe("Optional remix request when forking a template. Describes how you want the template to be different. E.g. 'Make it for tracking books instead of habits, add a search feature.' Only used with templateToken."),autonomous:te.boolean().optional().describe("Skip clarifying questions and generate the plan immediately"),landingDesign:te.string().optional().describe("ID of a curated landing page design for the hero section. When set, the design's detailed blueprint (colors, fonts, layout, animations) is injected during the landing page implementation step. Use mist_project with action='landing-designs' to browse available landing designs."),appStyle:te.string().optional().describe("ID of a full-app style (e.g. 'stripe', 'linear', 'vercel', 'notion'). When set, the style's color palette, typography, component specs, shadows, and layout rules are injected during ALL implementation steps for consistent brand-quality design across every page. Use mist_project with action='app-styles' to browse available app styles."),language:te.string().optional().describe("UI language for the app. All user-facing text, labels, buttons, and content will be generated in this language. Use the language name in English (e.g. 'Spanish', 'French', 'Arabic', 'Japanese'). Defaults to English if not specified."),brandMentioned:te.boolean().optional().describe("Set to true ONLY when the user's original request explicitly invoked Mistflow by name (e.g. 'build me a CRM using mist', 'make a todo app with mistflow'). Skips the existing-project confirmation gate because the user clearly wants Mistflow. Do NOT set this for generic 'build me X' requests. Do NOT infer this \u2014 only set it when the user literally typed 'mist' or 'mistflow'."),confirmToken:te.string().optional().describe("The token returned in a previous mist_plan response with status 'confirm_new_project'. Only pass this AFTER asking the user via AskUserQuestion and they chose to scaffold a new Mistflow app in an existing-project directory. The token is bound to the cwd and description \u2014 you must pass the SAME description on the retry, and the tool must be invoked from the same directory.")});function Zi(r){let e=[[/payment/i,"Payments"],[/database/i,"Database"],[/auth|sign.?up|login|access/i,"Access"],[/landing.?page/i,"Landing page"],[/who.*using|user|role/i,"Users"],[/design|theme|style/i,"Design"],[/deploy/i,"Deploy"],[/domain/i,"Domain"],[/notification/i,"Notify"],[/email/i,"Email"],[/mobile|responsive/i,"Mobile"],[/integrat/i,"Integration"]];for(let[a,n]of e)if(a.test(r))return n;return r.replace(/[?.,!]/g,"").split(/\s+/).filter(a=>!["what","how","do","does","is","are","the","a","an","would","should","you","your","for","this","that","to","of","or","and","want","like","prefer"].includes(a.toLowerCase())).slice(0,2).join(" ").slice(0,12)||"Option"}function eo(r){let e=me(He(),".mistflow","plans",`${r}.json`);if(!tt(e))return null;try{return JSON.parse(gr(e,"utf-8")).plan??null}catch{return null}}async function to(r){let{description:e,conversationId:t,answers:a,existingPlan:n,existingPlanId:o,templateToken:i,remixDescription:l,autonomous:s,language:d,landingDesign:p,appStyle:u,brandMentioned:h,confirmToken:m}=r,b=n;if(!b&&o&&(b=eo(o)??void 0,!b))return c("Your previous plan is no longer available. Please describe your app again to generate a new plan.",!0);let f=t;if(!le())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let g;if(!f&&!b&&!i){let v=process.cwd(),S=Qi(v);if(S==="foreign"&&!h){if(!(m?Yi(m,v,e):!1)){let B=Ji(v,e);return c(JSON.stringify({status:"confirm_new_project",cwd:v,description:e,confirmToken:B,askUserQuestion:{question:"You're inside an existing project directory. Do you want to scaffold a new Mistflow app here, or edit the existing codebase directly?",header:"Scope",options:[{label:"Scaffold a new Mistflow app in a subdirectory",description:"Creates a fresh project in this folder without touching the existing code."},{label:"Edit this existing codebase directly",description:"Cancel Mistflow. Handle the request by editing the current project's files."}],multiSelect:!1},instruction:["The user is inside an existing project (package.json found up the directory tree, no mistflow.json) and did NOT explicitly invoke Mistflow by name.","MANDATORY: Use the AskUserQuestion tool with the provided askUserQuestion to confirm their intent before calling mist_plan again.","If they pick 'Scaffold a new Mistflow app in a subdirectory', call mist_plan again with the SAME description and confirmToken set to the token returned above.","If they pick 'Edit this existing codebase directly', DO NOT call mist_plan again. Fulfill their request by editing files directly in the current project.",m?"The previous confirmToken was invalid, expired, or did not match the current directory/description. Use the fresh token above.":""].filter(Boolean).join(`
12233
- `)}))}g="Note: You're inside an existing project. Mistflow will create the new app in a subdirectory. It won't modify this codebase."}else S==="foreign"&&h&&(g="Note: You're inside an existing project. Mistflow will create the new app in a subdirectory. It won't modify this codebase.")}if(i)try{if(!(await Ka(i)).plan)return c("This template has no plan to fork. Try a different template.",!0);let S=await Ja(i),w=S.plan,B="";if(l&&S.has_source)try{let x=await Wt(S.plan,l),W=x.plan??x,F=x.diff,ye=W?.steps??[],se=new Set([...(F?.added??[]).map(he=>he.number),...(F?.modified??[]).map(he=>he.number)]),ue=ye.map(he=>{let Ai=he.number;return se.has(Ai)?{...he,status:"pending"}:{...he,status:"completed",source:"forked"}});W.steps=ue,w=W;let Ht=ue.filter(he=>he.status==="pending").length;B=` Remixed: ${ue.filter(he=>he.status==="completed").length} steps unchanged, ${Ht} steps need re-implementation.`}catch(x){console.error("[plan] Remix failed, using original plan:",x),B=" (Remix failed \u2014 using original plan. You can modify it later.)"}let _=hr(),K=me(He(),".mistflow","plans");Zt(K,{recursive:!0}),ea(me(K,`${_}.json`),JSON.stringify({plan:w,projectId:S.id,sourceDeploymentId:S.source_deployment_id,forkToken:S.fork_token,requiredEnvVars:S.required_env_vars,dbProvider:S.db_provider}));let Q=w?.name??"forked-app",T=S.has_source,C=T?"Source code will be restored during init. Run init promptly \u2014 the download token expires in 1 hour.":"",L=S.deploy_url?` Instant deploy started \u2014 your app will be live at ${S.deploy_url} in under a minute.`:"";return c(JSON.stringify({planId:_,forkedFrom:S.forked_from,projectId:S.id,hasSource:T,deployUrl:S.deploy_url,message:`Forked "${S.forked_from}" into your workspace.${B}${L} ${C} NEXT: Call mist_build with action='init', name='${Q}', and planId='${_}' to create the project now.`}))}catch(v){let S=v instanceof Error?v.message:"Failed to fork template";return c(S,!0)}if(b){let v;try{v=await Wt(b,e)}catch(K){let Q=K instanceof Error?K.message:"Failed to modify plan";return c(Q,!0)}let S=v.plan,w=v.diff,B=[];if(w?.added?.length){let K=w.added.map(Q=>Q.title);B.push(`Added ${K.length} step(s): ${K.join(", ")}`)}if(w?.removed?.length){let K=w.removed.map(Q=>Q.title);B.push(`Removed ${K.length} step(s): ${K.join(", ")}`)}if(w?.modified?.length){let K=w.modified.map(Q=>Q.title);B.push(`Modified ${K.length} step(s): ${K.join(", ")}`)}let _=B.length>0?B.join(". "):"No changes detected.";return c(JSON.stringify({plan:S,diff:w,message:`Plan modified. ${_}. Update mistflow.json with the new plan, then continue with mist_build (action: 'implement').`}))}let y,N=a;if(a&&xt in a){y=a[xt];let{[xt]:v,...S}=a;N=Object.keys(S).length>0?S:void 0}let R;try{R=await La(e,{conversationId:f,answers:N,autonomous:s,language:d})}catch(v){let S=v instanceof Error?v.message:"Failed to generate plan";return c(S,!0)}if(R.status==="clarify"){let v=R.reflection||"",S=R.suggestedName||"",w=R.suggestedFeatures??[],B=R.questions??[],_=B.some(F=>Array.isArray(F.options)&&typeof F.options[0]=="object"&&F.options[0]?.label),K=B.map(F=>{let ye=F.decisionKey?String(F.decisionKey).slice(0,12):Zi(F.question),se;return _&&Array.isArray(F.options)?se=F.options.map(ue=>({label:ue.label,description:ue.description??""})):Array.isArray(F.options)?se=F.options.map((ue,Ht)=>({label:Ht===0?`${ue} (Recommended)`:String(ue),description:F.why??""})):se=[{label:"Yes (Recommended)",description:F.why??""},{label:"No",description:""}],{question:F.question,header:ye,options:se,multiSelect:!1}}),T=R.decisions?.audienceType??null,C=w.length>0?pr(e,{primaryActor:null,primaryAction:null,surfaceType:null,audienceType:T,multiRole:null,publicLanding:null,realMoney:null,scheduling:null,authModel:null,dbProvider:null,integrations:null},{suggestedName:S,suggestedFeatures:w,language:d}):null,L=C?ur(C):"",x=Xt(S||"my-app").slice(0,32);try{let F=await Ma(x);!F.available&&F.suggestion&&(x=F.suggestion)}catch{}L&&(L+=`
12234
-
12235
- **Your app URL:** https://${x}.mistflow.app`);let W={question:`Your app will be at ${x}.mistflow.app \u2014 want to customize the URL?`,header:"URL",options:[{label:`Keep ${x}.mistflow.app (Recommended)`,description:"This URL is available"},{label:"Choose a different URL",description:"Type your preferred subdomain"}],multiSelect:!1};return K.push(W),c(JSON.stringify({status:"clarify",conversation_id:R.conversation_id,questions:B,suggestedFeatures:w,suggestedName:S,suggestedSubdomain:x,reflection:v,briefText:L,askUserQuestions:K,instruction:[...g?[g,""]:[],v?`${v}
12236
- `:"",L?`Here's what I'd build:
12237
-
12238
- ${L}
12239
- `:"","MANDATORY: Use the AskUserQuestion tool to present these questions. Do NOT present them as text.","","IF you have access to the AskUserQuestion tool (Claude Code):"," Use it to present questions with selectable options. Pass the 'askUserQuestions' array directly.","","OTHERWISE (Cursor, Codex, or other hosts):"," Present each question conversationally with the options listed.","","Once you have all answers, call mist_plan again with:",` conversationId: "${R.conversation_id}"`,' answers: { "<question text>": "<user answer>", ... }'," description: (same description as before)","",`IMPORTANT: For the URL question, include the answer with the key "${xt}" in the answers dict.`,`If the user keeps the default, set the value to "${x}".`,"If they type a custom URL, set the value to the custom subdomain (just the subdomain part, not the full URL)."].join(`
12240
- `)}))}let k=R.plan,$=k.name??"Untitled App",U=R.methodology,E=k.steps;if(!Array.isArray(E)||E.length===0)return c("Plan generation incomplete \u2014 the plan is missing implementation steps. Please call mist_plan again with the same description to retry.",!0);let j=k.publicPages;if(!j||Array.isArray(j)&&j.length===0){let v=k.pages,S=E.some(B=>typeof B.name=="string"&&B.name.toLowerCase().includes("landing")||typeof B.title=="string"&&B.title.toLowerCase().includes("landing")),w=Array.isArray(v)&&v.some(B=>B.path==="/"||B.route==="/");S||w?j=["/","/pricing"]:j=["/"]}let J=k.primaryAction;if(!J){let v=k.features;if(Array.isArray(v)&&v.length>0){let w=v.find(_=>typeof _.priority=="string"&&_.priority.toLowerCase()==="must-have")??v[0];J={entity:w.name??w.title??"item",action:"create",fromPage:"/dashboard"}}}let G=k.nonNegotiables;(!G||Array.isArray(G)&&G.length===0)&&(G=["Landing page renders correctly at / with content (not a redirect)","Core user action works end-to-end (create entity, see it in list)"]);let V=hr(),ie=me(He(),".mistflow","plans");Zt(ie,{recursive:!0});try{let S=Date.now();for(let w of[ie,me(He(),".mistflow","mockup-state")])if(tt(w))for(let B of _i(w))try{let _=me(w,B),K=Oi(_).mtimeMs;S-K>6048e5&&ji(_)}catch{}}catch{}let A;if(p){let v=Ae(p);v?A=v.id:console.error(`Landing design '${p}' not found \u2014 ignoring. Use mist_project action='landing-designs' to browse available landing designs.`)}let q;if(u){let v=ke(u);v?q=v.id:console.error(`App style '${u}' not found \u2014 ignoring. Use mist_project action='app-styles' to browse available app styles.`)}let oe={name:k.name,summary:k.summary,dataModel:k.dataModel,pages:k.pages,features:k.features,steps:E.map(v=>({...v,name:v.name??v.title})),design:k.design,landingDesign:A,appStyle:q,dbProvider:k.dbProvider??"neon",authModel:k.authModel,audienceType:k.audienceType??"b2c",roles:k.roles,defaultRole:k.defaultRole,publicPages:j,navStyle:k.navStyle,multiTenant:k.multiTenant,primaryAction:J,nonNegotiables:G,requestedSubdomain:y,...d&&d.toLowerCase()!=="english"?{language:d}:{}};ea(me(ie,`${V}.json`),JSON.stringify({plan:oe,methodology:U}));let Ne=E.map(v=>`${v.number}. ${v.name??v.title}`),xe=E.some(v=>{let S=`${v.name??v.title} ${v.description??""}`.toLowerCase();return S.includes("landing")||S.includes("hero")||S.includes("marketing")||S.includes("homepage")}),ne="",Z=[],P;!A&&xe&&(Z=ir(e,{maxResults:3}).map(w=>{let B=$t(w.title);return{id:w.id,slug:B,title:w.title,style:w.style,description:w.description,url:`${ve()}/designs/landing-designs/${B}`}}),P={question:"Which landing page design style do you prefer?",header:"Design",options:[...Z.map((w,B)=>({label:B===0?`${w.title} (Recommended)`:w.title,description:`${w.style} \u2014 ${w.description} Preview: ${w.url}`})),{label:"See more designs",description:`Not sure? Browse all 27 landing designs at ${ve()}/designs?tab=landing-designs and pick one.`},{label:"Skip \u2014 use default design",description:"Proceed without a preset"}],multiSelect:!1},ne=` This plan has a landing page step. Ask the user which landing design they prefer using the AskUserQuestion tool with the 'landingDesignQuestion' object provided. Recommended: ${Z.map(w=>`[${w.title}](${w.url}) (${w.style})`).join(", ")}. In your message, say these are top picks based on their description and that if none feel right they can browse all 27 landing designs at ${ve()}/designs?tab=landing-designs (include this link verbatim). Once the user picks, pass landingDesign='<id>' to the mist_build init call. If user says "skip" or picks default, proceed without one.`);let I="",M=[],ee;q||(M=lr(e,{maxResults:3}).map(w=>({id:w.id,slug:ft(w.name),name:w.name,description:w.description,theme:w.theme,url:`${ve()}/designs/app-styles/${ft(w.name)}`})),ee={question:"What design style should your app have? Choose a design system for consistent, brand-quality UI across all pages.",header:"App Design",options:[...M.map((w,B)=>({label:B===0?`${w.name} (Recommended)`:w.name,description:`${w.theme} theme \u2014 ${w.description} Preview: ${w.url}`})),{label:"See more app styles",description:`Not sure? Browse all 53 app styles at ${ve()}/designs?tab=app-styles and pick one.`},{label:"Skip \u2014 use default styling",description:"Proceed without a design system"}],multiSelect:!1},I=` Ask the user which app style they want using the AskUserQuestion tool with the 'appStyleQuestion' object provided. Recommended: ${M.map(w=>`[${w.name}](${w.url})`).join(", ")}. In your message, say these are top picks based on their description and that if none feel right they can browse all 53 app styles at ${ve()}/designs?tab=app-styles (include this link verbatim). Once the user picks, pass appStyle='<id>' to the mist_build init call. If user says "skip", proceed without one.`);let D="",z=[];for(let v of E){let S=v.name??v.title,w=v.integrationId;if(w){let B=Ve(w);if(B){let _=qe(B.id);z.push({step:S,presetId:B.id,presetName:B.name,envVars:_?.envVars??[]})}}}if(z.length>0){let v=z.flatMap(B=>B.envVars),S=[...new Set(v.map(B=>B.key))];D=` This plan uses integrations (${z.map(B=>B.presetName).join(", ")}). Detailed blueprints will be auto-injected during each integration step.${S.length>0?` The user will need these API keys: ${S.join(", ")}.`:""}`}return c(JSON.stringify({planId:V,name:k.name,summary:k.summary,stepCount:E.length,steps:Ne,design:k.design,...A?{landingDesign:A}:{},...q?{appStyle:q}:{},...Z.length>0?{recommendedPresets:Z}:{},...P?{landingDesignQuestion:P}:{},...M.length>0?{recommendedAppStyles:M}:{},...ee?{appStyleQuestion:ee}:{},...z.length>0?{integrations:z.map(v=>({step:v.step,preset:v.presetId,name:v.presetName,envVars:v.envVars}))}:{},message:`Plan generated for "${$}" (${E.length} steps).${A?` Landing design "${A}" will be applied to the landing page.`:""}${q?` App style "${q}" will be applied across all pages.`:""}${D}${I}${ne}`,mockupPrompt:`Before building, ask the user: "Would you like to preview a mockup of your app before we start building? You can iterate on the design, or skip straight to building." If the user wants a mockup, call mist_build with action='mockup' and planId='${V}'. If the user says skip or "just build it", call mist_build with action='init', name='${$}', and planId='${V}' immediately.`,...g?{warning:g}:{}}))}var xr={name:"mist_plan",description:["ENTRY POINT for creating a NEW web app, website, internal tool, dashboard, landing page, marketplace, content site, or browser game. Mistflow scaffolds a complete Next.js project. It does NOT edit existing codebases.","","WHEN TO CALL THIS \u2014 route here automatically on natural 'build me X' intent. The user does NOT need to say 'mist' or 'mistflow'. Examples that MUST route here:","\u2022 'build me a habit tracker'","\u2022 'make a site for my bakery'","\u2022 'I want an app where users log workouts'","\u2022 'create a dashboard that shows sales'","\u2022 'build a Wordle clone'","\u2022 'build me a CRM using mist' / 'make a todo app with mistflow' (explicit brand invocation)","","PASSING THE DESCRIPTION: Pass the user's words EXACTLY. Do NOT expand, elaborate, add features, rewrite, or strip anything (including 'using mist' / 'with mistflow'). 'build me a habit tracker using mist' becomes description: 'build me a habit tracker using mist'. The description is preserved verbatim.","","BRAND MENTIONED FLAG: If the user's original request literally contained the word 'mist' or 'mistflow' as an explicit invocation (e.g. 'build me a CRM using mist', 'use mistflow to make a todo app'), set brandMentioned: true. If the user did NOT mention the brand by name, omit brandMentioned (do not set it). Only set brandMentioned when the user literally typed the brand name \u2014 never infer it. Do NOT set brandMentioned for the common English noun 'mist' used in other contexts (e.g. 'app about morning mist').","","SAFETY GATE \u2014 the handler walks up the directory tree to detect if you're inside an existing non-Mistflow codebase (package.json found anywhere up the tree, no mistflow.json). When that happens AND brandMentioned is not set, the handler returns status 'confirm_new_project' with a signed confirmToken and an askUserQuestion. On that response:","\u2022 MANDATORY: use the AskUserQuestion tool with the provided askUserQuestion to ask the user.","\u2022 If the user picks 'Scaffold a new Mistflow app in a subdirectory', call mist_plan again with the SAME description and confirmToken set to the token from the response.","\u2022 If the user picks 'Edit this existing codebase directly', DO NOT call mist_plan again. Fulfill their request by editing files directly.","\u2022 The confirmToken is bound to the cwd and description. If either changes, you'll get a fresh token and must ask again.","\u2022 You do not need to pre-check the directory yourself. The handler handles detection.","","FOLLOW-UP FLOW (after the plan is being generated):","\u2022 status 'clarify' \u2192 use AskUserQuestion with the provided askUserQuestions, then call mist_plan again with conversationId + answers + the same description.","\u2022 status 'ready' \u2192 IMMEDIATELY call mist_build (action: 'init') with the returned planId. Do not ask permission.","\u2022 NEVER skip the clarifying questions. The discovery process ensures the right thing gets built.","","EXISTING MISTFLOW PROJECTS (mistflow.json present anywhere up the tree): only call this for changes that need a new data model, third-party integration, or multi-step structural change (pass existingPlan or existingPlanId). For cosmetic changes, new pages without new data models, or bug fixes, do NOT call mist_plan. Use mist_project action='get' for context and edit files directly.","","OTHER MODES: Pass templateToken to fork from a mistflow.ai/t/... shared template. Pass landingDesign (27 curated hero designs) or appStyle (54 full-app styles like 'stripe', 'linear') to apply a design preset. Browse via mist_project action='landing-designs' or action='app-styles'."].join(`
12241
- `),inputSchema:Xi,handler:to};import{z as de}from"zod";import{existsSync as Pt,readFileSync as qo}from"fs";import{join as Bt,resolve as Ko}from"path";import{homedir as Jo}from"os";import{execFileSync as ha}from"child_process";import{z as yt}from"zod";import{existsSync as Se,mkdirSync as vt,writeFileSync as De,readFileSync as kt,readdirSync as ao,copyFileSync as ro}from"fs";import{join as X,resolve as aa,dirname as at}from"path";import{spawn as io}from"child_process";import{randomBytes as oo}from"crypto";import{simpleGit as Sr}from"simple-git";function no(r){let e=at(aa(r)),t=10,a=0;for(;a<t&&e!==at(e);){if(Se(X(e,"pnpm-workspace.yaml"))||Se(X(e,"lerna.json")))return e;let n=X(e,"package.json");if(Se(n))try{if(JSON.parse(kt(n,"utf-8")).workspaces)return e}catch{}e=at(e),a++}return null}function Me(r,e,t,a,n){return new Promise(o=>{let i=io(r,e,{cwd:t,stdio:["pipe","pipe","pipe"],timeout:a}),l="",s="";i.stdout?.on("data",d=>{let p=d.toString();if(s+=p,n)for(let u of p.split(`
12242
- `).filter(Boolean))n(u)}),i.stderr?.on("data",d=>{let p=d.toString();if(l+=p,n)for(let u of p.split(`
12243
- `).filter(Boolean))n(u)}),i.on("close",d=>{if(d===0)o({success:!0});else{let p=l.split(`
12244
- `).find(u=>u.startsWith("npm error"))??l.slice(0,300);o({success:!1,error:p})}}),i.on("error",d=>{o({success:!1,error:d.message})})})}var gl=yt.object({name:yt.string().min(1),plan:yt.any(),path:yt.string().optional()});function H(r,e,t){let a=X(r,e);vt(at(a),{recursive:!0}),De(a,t)}var yr={amber:{primary:"25 95% 53%",primaryForeground:"0 0% 100%"},emerald:{primary:"160 84% 39%",primaryForeground:"0 0% 100%"},indigo:{primary:"239 84% 67%",primaryForeground:"0 0% 100%"},rose:{primary:"347 77% 50%",primaryForeground:"0 0% 100%"},cyan:{primary:"189 94% 43%",primaryForeground:"0 0% 100%"},violet:{primary:"263 70% 50%",primaryForeground:"0 0% 100%"},orange:{primary:"21 90% 48%",primaryForeground:"0 0% 100%"},teal:{primary:"168 76% 42%",primaryForeground:"0 0% 100%"},sky:{primary:"199 89% 48%",primaryForeground:"0 0% 100%"}},wr={"clean-saas":{light:{background:"0 0% 100%",foreground:"240 10% 4%",card:"0 0% 100%",cardForeground:"240 10% 4%",muted:"240 5% 96%",mutedForeground:"240 4% 46%",border:"240 6% 90%",input:"240 6% 90%",ring:"240 5% 65%"},dark:{background:"240 10% 4%",foreground:"0 0% 98%",card:"240 10% 4%",cardForeground:"0 0% 98%",muted:"240 4% 16%",mutedForeground:"240 5% 65%",border:"240 4% 16%",input:"240 4% 16%",ring:"240 5% 84%"}},"warm-minimal":{light:{background:"40 20% 98%",foreground:"40 10% 10%",card:"40 15% 96%",cardForeground:"40 10% 10%",muted:"40 10% 93%",mutedForeground:"40 5% 45%",border:"40 10% 88%",input:"40 10% 88%",ring:"40 5% 55%"},dark:{background:"40 10% 7%",foreground:"40 10% 93%",card:"40 10% 7%",cardForeground:"40 10% 93%",muted:"40 5% 15%",mutedForeground:"40 5% 55%",border:"40 5% 15%",input:"40 5% 15%",ring:"40 5% 70%"}},"dense-professional":{light:{background:"220 14% 98%",foreground:"220 14% 10%",card:"0 0% 100%",cardForeground:"220 14% 10%",muted:"220 14% 95%",mutedForeground:"220 9% 46%",border:"220 13% 91%",input:"220 13% 91%",ring:"220 9% 46%"},dark:{background:"220 14% 7%",foreground:"220 14% 95%",card:"220 14% 7%",cardForeground:"220 14% 95%",muted:"220 9% 15%",mutedForeground:"220 9% 60%",border:"220 9% 15%",input:"220 9% 15%",ring:"220 9% 60%"}},"dark-first":{light:{background:"0 0% 100%",foreground:"0 0% 4%",card:"0 0% 100%",cardForeground:"0 0% 4%",muted:"0 0% 96%",mutedForeground:"0 0% 45%",border:"0 0% 90%",input:"0 0% 90%",ring:"0 0% 45%"},dark:{background:"0 0% 4%",foreground:"0 0% 95%",card:"0 0% 7%",cardForeground:"0 0% 95%",muted:"0 0% 12%",mutedForeground:"0 0% 55%",border:"0 0% 12%",input:"0 0% 12%",ring:"0 0% 55%"}},editorial:{light:{background:"30 20% 98%",foreground:"30 10% 8%",card:"30 15% 97%",cardForeground:"30 10% 8%",muted:"30 10% 94%",mutedForeground:"30 5% 40%",border:"30 10% 88%",input:"30 10% 88%",ring:"30 5% 50%"},dark:{background:"30 10% 6%",foreground:"30 10% 94%",card:"30 10% 6%",cardForeground:"30 10% 94%",muted:"30 5% 14%",mutedForeground:"30 5% 55%",border:"30 5% 14%",input:"30 5% 14%",ring:"30 5% 65%"}},brutalist:{light:{background:"0 0% 100%",foreground:"0 0% 0%",card:"0 0% 100%",cardForeground:"0 0% 0%",muted:"0 0% 95%",mutedForeground:"0 0% 30%",border:"0 0% 0%",input:"0 0% 85%",ring:"0 0% 0%"},dark:{background:"0 0% 0%",foreground:"0 0% 100%",card:"0 0% 5%",cardForeground:"0 0% 100%",muted:"0 0% 10%",mutedForeground:"0 0% 65%",border:"0 0% 100%",input:"0 0% 15%",ring:"0 0% 100%"}},playful:{light:{background:"45 100% 99%",foreground:"280 20% 15%",card:"45 50% 97%",cardForeground:"280 20% 15%",muted:"45 30% 94%",mutedForeground:"280 10% 45%",border:"45 20% 88%",input:"45 20% 90%",ring:"280 60% 60%"},dark:{background:"280 20% 7%",foreground:"45 30% 95%",card:"280 15% 10%",cardForeground:"45 30% 95%",muted:"280 10% 15%",mutedForeground:"280 10% 60%",border:"280 10% 18%",input:"280 10% 15%",ring:"280 60% 70%"}},luxury:{light:{background:"30 10% 98%",foreground:"30 15% 8%",card:"30 8% 97%",cardForeground:"30 15% 8%",muted:"30 5% 93%",mutedForeground:"30 5% 40%",border:"30 8% 85%",input:"30 8% 88%",ring:"30 10% 35%"},dark:{background:"30 10% 5%",foreground:"30 10% 92%",card:"30 8% 8%",cardForeground:"30 10% 92%",muted:"30 5% 13%",mutedForeground:"30 5% 55%",border:"30 5% 15%",input:"30 5% 13%",ring:"30 10% 70%"}}},so={sharp:"0.125rem",subtle:"0.375rem",rounded:"0.75rem",pill:"9999px"};function lo(r){let e=r?.tone??"clean-saas",t=r?.accentColor??"indigo",a=r?.borderRadius??"subtle",n=wr[e]??wr["clean-saas"],o=yr[t]??yr.indigo,i=so[a]??"0.375rem";return`@import "tailwindcss";
10661
+ `)}function gr(r){return(r?Zt(r):$e).map(t=>{let a=Xt[t.id];return{id:t.id,slug:ji(t.name),name:t.name,category:t.category,description:a?.description??"",tags:a?.tags??[],envVars:a?.envVars??[],docsUrl:a?.docsUrl??"",packages:a?.packages??[],difficulty:a?.difficulty??"medium"}})}var zi=[{name:"Dashboard",description:"Overview with key stats and today's activity",condition:r=>r.surfaceType==="internal-tool"||r.surfaceType==="customer-app",keywords:/\b(dashboard|overview|home.?page|stats)\b/i},{name:"Landing Page",description:"Public page explaining what this does",condition:r=>r.publicLanding===!0,keywords:/\b(landing|marketing|hero|homepage)\b/i},{name:"Scheduling / Booking",description:"Calendar, time slots, reservations",condition:r=>r.scheduling===!0,keywords:/\b(schedul|book|reserv|appointment|calendar|slot)\b/i},{name:"Payments / Billing",description:"Charge users, invoices, subscriptions (experimental \u2014 Stripe integration is early-stage)",condition:()=>!1,keywords:/\b(payment|billing|invoice|subscription|checkout|stripe)\b/i},{name:"Admin Panel",description:"Manage users, roles, and content",condition:r=>r.multiRole===!0||r.primaryActor==="both",keywords:/\b(admin|panel|manage.?user|moderat)\b/i},{name:"User Profiles",description:"Account pages, settings, preferences",condition:r=>r.primaryActor==="customers"||r.primaryActor==="both",keywords:/\b(profile|account|settings|preferences)\b/i},{name:"Search / Browse",description:"Find and filter content or listings",condition:r=>r.surfaceType==="marketplace",keywords:/\b(search|browse|filter|discover|explore)\b/i},{name:"Email Notifications",description:"Welcome emails, alerts, reminders",condition:r=>r.integrations?.includes("email")===!0,keywords:/\b(notification|alert|reminder|email.?notif|sms|welcome.?email)\b/i},{name:"Analytics / Reports",description:"Usage stats, trends, data exports",condition:()=>!1,keywords:/\b(analytics|report|chart|trend|insight|metric)\b/i},{name:"File Uploads",description:"Images, documents, attachments",condition:r=>r.integrations?.includes("file-uploads")===!0,keywords:/\b(upload|image|photo|attachment|document|gallery|file)\b/i},{name:"AI Features",description:"Chatbot, content generation, AI assistant",condition:r=>r.integrations?.includes("ai")===!0,keywords:/\b(ai|chatbot|gpt|llm|generat|assistant)\b/i},{name:"Maps / Location",description:"Google Maps, location search, geolocation",condition:r=>r.integrations?.includes("maps")===!0,keywords:/\b(map|location|address|geo|places)\b/i},{name:"Voice / TTS",description:"Text-to-speech, voice notes, audio generation",condition:()=>!1,keywords:/\b(voice|tts|text.?to.?speech|audio|speak|narrat|podcast|elevenlabs)\b/i},{name:"SMS / Text Messages",description:"Send SMS notifications, OTP verification",condition:r=>r.integrations?.includes("sms")===!0,keywords:/\b(sms|text.?message|twilio|otp|verification.?code|phone.?verif)\b/i},{name:"Web Scraping",description:"Scrape URLs, crawl websites, extract structured data",condition:()=>!1,keywords:/\b(scrape|crawl|web.?scrap|extract.?from.?url|read.?url|ingest.?web|firecrawl)\b/i},{name:"Chat / Messaging",description:"Real-time messaging between users",condition:()=>!1,keywords:/\b(chat|messag|inbox|conversation|dm)\b/i},{name:"Events / Tournaments",description:"Create and manage events, registrations",condition:()=>!1,keywords:/\b(event|tournament|competition|league|registration)\b/i},{name:"High Scores",description:"Track and display top scores with a leaderboard",condition:r=>r.surfaceType==="game",keywords:/\b(high.?score|leaderboard|top.?score|ranking|scoreboard)\b/i},{name:"Save Progress",description:"Save and resume game state between sessions",condition:r=>r.surfaceType==="game",keywords:/\b(save|progress|resume|checkpoint|continue)\b/i},{name:"Guest Play",description:"Play immediately without signing up, optionally link account later",condition:r=>r.surfaceType==="game",keywords:/\b(guest|anonymous|no.?login|play.?now|instant.?play)\b/i},{name:"Levels / Stages",description:"Progressive difficulty with unlockable stages",condition:()=>!1,keywords:/\b(level|stage|unlock|difficult|progress|world)\b/i},{name:"Achievements",description:"Badges, trophies, and milestones for player accomplishments",condition:()=>!1,keywords:/\b(achieve|badge|trophy|milestone|reward|unlock)\b/i},{name:"Daily Challenge",description:"New puzzle or challenge every day to keep players coming back",condition:()=>!1,keywords:/\b(daily|challenge|streak|word.?of.?the.?day|puzzle.?of)\b/i}];function mr(r,e,t){let a=t?.suggestedName||$i(r),n=e.primaryActor==="both"?"Staff + Customers":e.primaryActor==="staff"?"Staff / Admin":e.primaryActor==="customers"?"End Users":"Users",o=e.audienceType??(e.surfaceType==="internal-tool"?"internal":(e.primaryActor==="customers"||e.primaryActor==="both","b2c")),i=e.surfaceType==="internal-tool"?"Internal tool":e.surfaceType==="marketplace"?"Marketplace":e.surfaceType==="content-site"?"Content site":e.surfaceType==="game"?"Game":"App",s;if(t?.suggestedFeatures&&t.suggestedFeatures.length>0)s=t.suggestedFeatures.map(l=>({name:l.name,description:l.description,checked:l.recommended,source:l.recommended?"explicit":"suggested"}));else{let l=`${r} ${e.primaryAction||""}`;s=[];for(let d of zi){let u=d.keywords.test(l),p=d.condition(e);(u||p)&&s.push({name:d.name,description:d.description,checked:u,source:u?"explicit":"suggested"})}}return{name:a,audience:n,audienceType:o,surfaceType:i,primaryAction:e.primaryAction||"manage items",features:s,publicLanding:e.publicLanding??!1,authModel:e.authModel??"email",dbProvider:e.dbProvider??"neon",integrations:e.integrations??[],language:t?.language||"English"}}function fr(r){let e=r.features.filter(s=>s.checked),t=r.features.filter(s=>!s.checked),a={email:"Email sign-up",none:"No login (public)",social:"Social login","invite-only":"Invite-only"},n={neon:"Postgres",turso:"SQLite (legacy)"},o={b2c:"Your customers use this app (business-to-customer)",b2b:"Other businesses sign up for this (SaaS platform)",internal:"Internal team tool (staff only)"},i=[`**${r.name}** \u2014 ${r.surfaceType} for ${r.audience}`,`Audience: ${o[r.audienceType]??r.audienceType}`,`Primary action: ${r.primaryAction}`,`Access: ${a[r.authModel]??r.authModel} | Database: ${n[r.dbProvider]??r.dbProvider}${r.publicLanding?" | Landing page: Yes":""}${r.language&&r.language!=="English"?` | Language: ${r.language}`:""}`,""];if(e.length>0){i.push("**Included:**");for(let s of e)i.push(` \u2713 ${s.name} \u2014 ${s.description}`)}if(r.integrations.length>0&&(i.push(""),i.push(`**Integrations:** ${r.integrations.join(", ")}`)),t.length>0){i.push(""),i.push("**Available to add:**");for(let s of t)i.push(` \u25CB ${s.name} \u2014 ${s.description}`)}return i.join(`
10662
+ `)}function $i(r){let e=r.match(/\b(?:called|named)\s+["']?([A-Za-z][A-Za-z0-9 ]{1,30})["']?/i);if(e)return ea(e[1]);let t=new Set(["build","create","make","a","an","the","for","me","my","app","application","website","web","tool","system","platform","using","with","and","that","this","want","need","please","can","you","i","mist","mistflow"]),n=r.toLowerCase().replace(/[^a-z0-9\s]/g,"").split(/\s+/).filter(o=>o.length>2&&!t.has(o)).slice(0,3);return n.length===0?"my-app":n.join("-")}function ea(r){return r.toLowerCase().replace(/[^a-z0-9\s]/g,"").trim().replace(/\s+/g,"-")}var xt="__mistflow_url_choice__",Zi=600*1e3;function wr(){let r=fe(Ge(),".mistflow","confirm-secret");if(tt(r))try{return Buffer.from(xr(r,"utf-8").trim(),"hex")}catch{}let e=Qi(32);return ta(fe(Ge(),".mistflow"),{recursive:!0}),aa(r,e.toString("hex"),{mode:384}),e}function vr(r){return Yi("sha256").update(r.trim().toLowerCase()).digest("hex").slice(0,16)}function en(r,e){let t={cwd:r,d:vr(e),exp:Date.now()+Zi},a=Buffer.from(JSON.stringify(t)).toString("base64url"),n=yr("sha256",wr()).update(a).digest("base64url");return`${a}.${n}`}function tn(r,e,t){let a=r.split(".");if(a.length!==2)return!1;let[n,o]=a,i=yr("sha256",wr()).update(n).digest("base64url"),s=Buffer.from(o),l=Buffer.from(i);if(s.length!==l.length||!Xi(s,l))return!1;try{let d=JSON.parse(Buffer.from(n,"base64url").toString("utf-8"));return!(typeof d.exp!="number"||Date.now()>d.exp||d.cwd!==e||d.d!==vr(t))}catch{return!1}}function an(r){let e=r,t=Ge(),a=!1;for(let n=0;n<64;n++){if(tt(fe(e,"mistflow.json")))return"mistflow";if(!a&&tt(fe(e,"package.json"))&&(a=!0),e===t)break;let o=Ji(e);if(o===e)break;e=o}return a?"foreign":"none"}var rn=X.object({description:X.string().min(1,"App description or modification request"),conversationId:X.string().optional().describe("Returned by a previous mist_plan call with status 'clarify'. Pass it back to continue the conversation."),answers:X.record(X.string()).optional().describe("User's answers to the clarifying questions from the previous round. Keys are the questions, values are the answers."),existingPlan:X.record(X.unknown()).optional().describe("If provided, modifies this existing plan instead of creating a new one. Pass the current plan object from mistflow.json."),existingPlanId:X.string().optional().describe("Alternative to existingPlan \u2014 pass the planId from a previous mist_plan call to modify that plan."),templateToken:X.string().optional().describe("Fork from a shared template. Pass the share token (from a mistflow.ai/t/... URL) to clone that project's plan into your workspace."),remixDescription:X.string().optional().describe("Optional remix request when forking a template. Describes how you want the template to be different. E.g. 'Make it for tracking books instead of habits, add a search feature.' Only used with templateToken."),autonomous:X.boolean().optional().describe("Skip clarifying questions and generate the plan immediately"),landingDesign:X.string().optional().describe("ID of a curated landing page design for the hero section. When set, the design's detailed blueprint (colors, fonts, layout, animations) is injected during the landing page implementation step. Use mist_project with action='landing-designs' to browse available landing designs."),appStyle:X.string().optional().describe("ID of a full-app style (e.g. 'stripe', 'linear', 'vercel', 'notion'). When set, the style's color palette, typography, component specs, shadows, and layout rules are injected during ALL implementation steps for consistent brand-quality design across every page. Use mist_project with action='app-styles' to browse available app styles."),language:X.string().optional().describe("UI language for the app. All user-facing text, labels, buttons, and content will be generated in this language. Use the language name in English (e.g. 'Spanish', 'French', 'Arabic', 'Japanese'). Defaults to English if not specified."),brandMentioned:X.boolean().optional().describe("Set to true ONLY when the user's original request explicitly invoked Mistflow by name (e.g. 'build me a CRM using mist', 'make a todo app with mistflow'). Skips the existing-project confirmation gate because the user clearly wants Mistflow. Do NOT set this for generic 'build me X' requests. Do NOT infer this \u2014 only set it when the user literally typed 'mist' or 'mistflow'."),confirmToken:X.string().optional().describe("The token returned in a previous mist_plan response with status 'confirm_new_project'. Only pass this AFTER asking the user via AskUserQuestion and they chose to scaffold a new Mistflow app in an existing-project directory. The token is bound to the cwd and description \u2014 you must pass the SAME description on the retry, and the tool must be invoked from the same directory.")});function nn(r){let e=[[/payment/i,"Payments"],[/database/i,"Database"],[/auth|sign.?up|login|access/i,"Access"],[/landing.?page/i,"Landing page"],[/who.*using|user|role/i,"Users"],[/design|theme|style/i,"Design"],[/deploy/i,"Deploy"],[/domain/i,"Domain"],[/notification/i,"Notify"],[/email/i,"Email"],[/mobile|responsive/i,"Mobile"],[/integrat/i,"Integration"]];for(let[a,n]of e)if(a.test(r))return n;return r.replace(/[?.,!]/g,"").split(/\s+/).filter(a=>!["what","how","do","does","is","are","the","a","an","would","should","you","your","for","this","that","to","of","or","and","want","like","prefer"].includes(a.toLowerCase())).slice(0,2).join(" ").slice(0,12)||"Option"}function on(r){let e=fe(Ge(),".mistflow","plans",`${r}.json`);if(!tt(e))return null;try{return JSON.parse(xr(e,"utf-8")).plan??null}catch{return null}}async function sn(r){let{description:e,conversationId:t,answers:a,existingPlan:n,existingPlanId:o,templateToken:i,remixDescription:s,autonomous:l,language:d,landingDesign:u,appStyle:p,brandMentioned:h,confirmToken:m}=r,f=n;if(!f&&o&&(f=on(o)??void 0,!f))return c("Your previous plan is no longer available. Please describe your app again to generate a new plan.",!0);let b=t;if(!se())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let g;if(!b&&!f&&!i){let v=process.cwd(),x=an(v);if(x==="foreign"&&!h){if(!(m?tn(m,v,e):!1)){let I=en(v,e);return c(JSON.stringify({status:"confirm_new_project",cwd:v,description:e,confirmToken:I,askUserQuestion:{question:"You're inside an existing project directory. Do you want to scaffold a new Mistflow app here, or edit the existing codebase directly?",header:"Scope",options:[{label:"Scaffold a new Mistflow app in a subdirectory",description:"Creates a fresh project in this folder without touching the existing code."},{label:"Edit this existing codebase directly",description:"Cancel Mistflow. Handle the request by editing the current project's files."}],multiSelect:!1},instruction:["The user is inside an existing project (package.json found up the directory tree, no mistflow.json) and did NOT explicitly invoke Mistflow by name.","MANDATORY: Use the AskUserQuestion tool with the provided askUserQuestion to confirm their intent before calling mist_plan again.","If they pick 'Scaffold a new Mistflow app in a subdirectory', call mist_plan again with the SAME description and confirmToken set to the token returned above.","If they pick 'Edit this existing codebase directly', DO NOT call mist_plan again. Fulfill their request by editing files directly in the current project.",m?"The previous confirmToken was invalid, expired, or did not match the current directory/description. Use the fresh token above.":""].filter(Boolean).join(`
10663
+ `)}))}g="Note: You're inside an existing project. Mistflow will create the new app in a subdirectory. It won't modify this codebase."}else x==="foreign"&&h&&(g="Note: You're inside an existing project. Mistflow will create the new app in a subdirectory. It won't modify this codebase.")}if(i)try{if(!(await Ya(i)).plan)return c("This template has no plan to fork. Try a different template.",!0);let x=await Qa(i),C=x.plan,I="";if(s&&x.has_source)try{let V=await jt(x.plan,s),y=V.plan??V,k=V.diff,R=y?.steps??[],B=new Set([...(k?.added??[]).map(K=>K.number),...(k?.modified??[]).map(K=>K.number)]),L=R.map(K=>{let Ot=K.number;return B.has(Ot)?{...K,status:"pending"}:{...K,status:"completed",source:"forked"}});y.steps=L,C=y;let ue=L.filter(K=>K.status==="pending").length;I=` Remixed: ${L.filter(K=>K.status==="completed").length} steps unchanged, ${ue} steps need re-implementation.`}catch(V){console.error("[plan] Remix failed, using original plan:",V),I=" (Remix failed \u2014 using original plan. You can modify it later.)"}let j=br(),H=fe(Ge(),".mistflow","plans");ta(H,{recursive:!0}),aa(fe(H,`${j}.json`),JSON.stringify({plan:C,projectId:x.id,sourceDeploymentId:x.source_deployment_id,forkToken:x.fork_token,requiredEnvVars:x.required_env_vars,dbProvider:x.db_provider}));let $=C?.name??"forked-app",he=x.has_source,te=he?"Source code will be restored during init. Run init promptly \u2014 the download token expires in 1 hour.":"",ae=x.deploy_url?` Instant deploy started \u2014 your app will be live at ${x.deploy_url} in under a minute.`:"";return c(JSON.stringify({planId:j,forkedFrom:x.forked_from,projectId:x.id,hasSource:he,deployUrl:x.deploy_url,message:`Forked "${x.forked_from}" into your workspace.${I}${ae} ${te} NEXT: Call mist_build with action='init', name='${$}', and planId='${j}' to create the project now.`}))}catch(v){let x=v instanceof Error?v.message:"Failed to fork template";return c(x,!0)}if(f){let v;try{v=await jt(f,e)}catch(H){let $=H instanceof Error?H.message:"Failed to modify plan";return c($,!0)}let x=v.plan,C=v.diff,I=[];if(C?.added?.length){let H=C.added.map($=>$.title);I.push(`Added ${H.length} step(s): ${H.join(", ")}`)}if(C?.removed?.length){let H=C.removed.map($=>$.title);I.push(`Removed ${H.length} step(s): ${H.join(", ")}`)}if(C?.modified?.length){let H=C.modified.map($=>$.title);I.push(`Modified ${H.length} step(s): ${H.join(", ")}`)}let j=I.length>0?I.join(". "):"No changes detected.";return c(JSON.stringify({plan:x,diff:C,message:`Plan modified. ${j}. Update mistflow.json with the new plan, then continue with mist_build (action: 'implement').`}))}let w,P=a;if(a&&xt in a){w=a[xt];let{[xt]:v,...x}=a;P=Object.keys(x).length>0?x:void 0}let D;try{D=await La(e,{conversationId:b,answers:P,autonomous:l,language:d})}catch(v){let x=v instanceof Error?v.message:"Failed to generate plan";return c(x,!0)}if(D.status==="clarify"){let v=D.reflection||"",x=D.suggestedName||"",C=D.suggestedFeatures??[],I=D.questions??[],j=I.some(k=>Array.isArray(k.options)&&typeof k.options[0]=="object"&&k.options[0]?.label),H=I.map(k=>{let R=k.decisionKey?String(k.decisionKey).slice(0,12):nn(k.question),B;return j&&Array.isArray(k.options)?B=k.options.map(L=>({label:L.label,description:L.description??""})):Array.isArray(k.options)?B=k.options.map((L,ue)=>({label:ue===0?`${L} (Recommended)`:String(L),description:k.why??""})):B=[{label:"Yes (Recommended)",description:k.why??""},{label:"No",description:""}],{question:k.question,header:R,options:B,multiSelect:!1}}),he=D.decisions?.audienceType??null,te=C.length>0?mr(e,{primaryActor:null,primaryAction:null,surfaceType:null,audienceType:he,multiRole:null,publicLanding:null,realMoney:null,scheduling:null,authModel:null,dbProvider:null,integrations:null},{suggestedName:x,suggestedFeatures:C,language:d}):null,ae=te?fr(te):"",V=ea(x||"my-app").slice(0,32);try{let k=await Ma(V);!k.available&&k.suggestion&&(V=k.suggestion)}catch{}ae&&(ae+=`
10664
+
10665
+ **Your app URL:** https://${V}.mistflow.app`);let y={question:`Your app will be at ${V}.mistflow.app \u2014 want to customize the URL?`,header:"URL",options:[{label:`Keep ${V}.mistflow.app (Recommended)`,description:"This URL is available"},{label:"Choose a different URL",description:"Type your preferred subdomain"}],multiSelect:!1};return H.push(y),c(JSON.stringify({status:"clarify",conversation_id:D.conversation_id,questions:I,suggestedFeatures:C,suggestedName:x,suggestedSubdomain:V,reflection:v,briefText:ae,askUserQuestions:H,instruction:[...g?[g,""]:[],v?`${v}
10666
+ `:"",ae?`Here's what I'd build:
10667
+
10668
+ ${ae}
10669
+ `:"","MANDATORY: Use the AskUserQuestion tool to present these questions. Do NOT present them as text.","","IF you have access to the AskUserQuestion tool (Claude Code):"," Use it to present questions with selectable options. Pass the 'askUserQuestions' array directly.","","OTHERWISE (Cursor, Codex, or other hosts):"," Present each question conversationally with the options listed.","","Once you have all answers, call mist_plan again with:",` conversationId: "${D.conversation_id}"`,' answers: { "<question text>": "<user answer>", ... }'," description: (same description as before)","",`IMPORTANT: For the URL question, include the answer with the key "${xt}" in the answers dict.`,`If the user keeps the default, set the value to "${V}".`,"If they type a custom URL, set the value to the custom subdomain (just the subdomain part, not the full URL)."].join(`
10670
+ `)}))}let S=D.plan,U=S.name??"Untitled App",ne=D.methodology,G=S.steps;if(!Array.isArray(G)||G.length===0)return c("Plan generation incomplete \u2014 the plan is missing implementation steps. Please call mist_plan again with the same description to retry.",!0);let J=S.publicPages;if(!J||Array.isArray(J)&&J.length===0){let v=S.pages,x=G.some(I=>typeof I.name=="string"&&I.name.toLowerCase().includes("landing")||typeof I.title=="string"&&I.title.toLowerCase().includes("landing")),C=Array.isArray(v)&&v.some(I=>I.path==="/"||I.route==="/");x||C?J=["/","/pricing"]:J=["/"]}let ee=S.primaryAction;if(!ee){let v=S.features;if(Array.isArray(v)&&v.length>0){let C=v.find(j=>typeof j.priority=="string"&&j.priority.toLowerCase()==="must-have")??v[0];ee={entity:C.name??C.title??"item",action:"create",fromPage:"/dashboard"}}}let q=S.nonNegotiables;(!q||Array.isArray(q)&&q.length===0)&&(q=["Landing page renders correctly at / with content (not a redirect)","Core user action works end-to-end (create entity, see it in list)"]);let Y=br(),le=fe(Ge(),".mistflow","plans");ta(le,{recursive:!0});try{let x=Date.now();for(let C of[le,fe(Ge(),".mistflow","mockup-state")])if(tt(C))for(let I of Vi(C))try{let j=fe(C,I),H=qi(j).mtimeMs;x-H>6048e5&&Ki(j)}catch{}}catch{}let F;if(u){let v=De(u);v?F=v.id:console.error(`Landing design '${u}' not found \u2014 ignoring. Use mist_project action='landing-designs' to browse available landing designs.`)}let N;if(p){let v=me(p);v?N=v.id:console.error(`App style '${p}' not found \u2014 ignoring. Use mist_project action='app-styles' to browse available app styles.`)}let oe={name:S.name,summary:S.summary,dataModel:S.dataModel,pages:S.pages,features:S.features,steps:G.map(v=>({...v,name:v.name??v.title})),design:S.design,landingDesign:F,appStyle:N,dbProvider:S.dbProvider??"neon",authModel:S.authModel,audienceType:S.audienceType??"b2c",roles:S.roles,defaultRole:S.defaultRole,publicPages:J,navStyle:S.navStyle,multiTenant:S.multiTenant,primaryAction:ee,nonNegotiables:q,requestedSubdomain:w,...d&&d.toLowerCase()!=="english"?{language:d}:{}};aa(fe(le,`${Y}.json`),JSON.stringify({plan:oe,methodology:ne}));let ye=G.map(v=>`${v.number}. ${v.name??v.title}`),Ce=G.some(v=>{let x=`${v.name??v.title} ${v.description??""}`.toLowerCase();return x.includes("landing")||x.includes("hero")||x.includes("marketing")||x.includes("homepage")});if(!F&&Ce){let v=sr(e,{maxResults:1});v.length>0&&(F=v[0].id,console.error(`Auto-assigned landing layout preset: ${v[0].title} (${F})`))}let de="",Q=[],T;N||(Q=ur(e,{maxResults:3}).map(C=>({id:C.id,slug:bt(C.name),name:C.name,description:C.description,theme:C.theme,url:`${Ee()}/designs/app-styles/${bt(C.name)}`})),T={question:"What design style should your app have? Choose a design system for consistent, brand-quality UI across all pages.",header:"App Design",options:[...Q.map((C,I)=>({label:I===0?`${C.name} (Recommended)`:C.name,description:`${C.theme} theme \u2014 ${C.description} Preview: ${C.url}`})),{label:"See more app styles",description:`Not sure? Browse all 53 app styles at ${Ee()}/designs?tab=app-styles and pick one.`},{label:"Skip \u2014 use default styling",description:"Proceed without a design system"}],multiSelect:!1},de=` Ask the user which app style they want using the AskUserQuestion tool with the 'appStyleQuestion' object provided. Recommended: ${Q.map(C=>`[${C.name}](${C.url})`).join(", ")}. In your message, say these are top picks based on their description and that if none feel right they can browse all 53 app styles at ${Ee()}/designs?tab=app-styles (include this link verbatim). Once the user picks, pass appStyle='<id>' to the mist_build init call. If user says "skip", proceed without one.`);let A="",M=[];for(let v of G){let x=v.name??v.title,C=v.integrationId;if(C){let I=Ve(C);if(I){let j=qe(I.id);M.push({step:x,presetId:I.id,presetName:I.name,envVars:j?.envVars??[]})}}}if(M.length>0){let v=M.flatMap(I=>I.envVars),x=[...new Set(v.map(I=>I.key))];A=` This plan uses integrations (${M.map(I=>I.presetName).join(", ")}). Detailed blueprints will be auto-injected during each integration step.${x.length>0?` The user will need these API keys: ${x.join(", ")}.`:""}`}return c(JSON.stringify({planId:Y,name:S.name,summary:S.summary,stepCount:G.length,steps:ye,design:S.design,...F?{landingDesign:F}:{},...N?{appStyle:N}:{},...Q.length>0?{recommendedAppStyles:Q}:{},...T?{appStyleQuestion:T}:{},...M.length>0?{integrations:M.map(v=>({step:v.step,preset:v.presetId,name:v.presetName,envVars:v.envVars}))}:{},message:`Plan generated for "${U}" (${G.length} steps).${F?` Landing layout "${F}" auto-assigned.`:""}${N?` App style "${N}" will be applied across all pages.`:""}${A}${de}`,mockupPrompt:`Before building, ask the user: "Would you like to preview a mockup of your app before we start building? You can iterate on the design, or skip straight to building." If the user wants a mockup, call mist_build with action='mockup' and planId='${Y}'. If the user says skip or "just build it", call mist_build with action='init', name='${U}', and planId='${Y}' immediately.`,...g?{warning:g}:{}}))}var kr={name:"mist_plan",description:["ENTRY POINT for creating a NEW web app, website, internal tool, dashboard, landing page, marketplace, content site, or browser game. Mistflow scaffolds a complete Next.js project. It does NOT edit existing codebases.","","WHEN TO CALL THIS \u2014 route here automatically on natural 'build me X' intent. The user does NOT need to say 'mist' or 'mistflow'. Examples that MUST route here:","\u2022 'build me a habit tracker'","\u2022 'make a site for my bakery'","\u2022 'I want an app where users log workouts'","\u2022 'create a dashboard that shows sales'","\u2022 'build a Wordle clone'","\u2022 'build me a CRM using mist' / 'make a todo app with mistflow' (explicit brand invocation)","","PASSING THE DESCRIPTION: Pass the user's words EXACTLY. Do NOT expand, elaborate, add features, rewrite, or strip anything (including 'using mist' / 'with mistflow'). 'build me a habit tracker using mist' becomes description: 'build me a habit tracker using mist'. The description is preserved verbatim.","","BRAND MENTIONED FLAG: If the user's original request literally contained the word 'mist' or 'mistflow' as an explicit invocation (e.g. 'build me a CRM using mist', 'use mistflow to make a todo app'), set brandMentioned: true. If the user did NOT mention the brand by name, omit brandMentioned (do not set it). Only set brandMentioned when the user literally typed the brand name \u2014 never infer it. Do NOT set brandMentioned for the common English noun 'mist' used in other contexts (e.g. 'app about morning mist').","","SAFETY GATE \u2014 the handler walks up the directory tree to detect if you're inside an existing non-Mistflow codebase (package.json found anywhere up the tree, no mistflow.json). When that happens AND brandMentioned is not set, the handler returns status 'confirm_new_project' with a signed confirmToken and an askUserQuestion. On that response:","\u2022 MANDATORY: use the AskUserQuestion tool with the provided askUserQuestion to ask the user.","\u2022 If the user picks 'Scaffold a new Mistflow app in a subdirectory', call mist_plan again with the SAME description and confirmToken set to the token from the response.","\u2022 If the user picks 'Edit this existing codebase directly', DO NOT call mist_plan again. Fulfill their request by editing files directly.","\u2022 The confirmToken is bound to the cwd and description. If either changes, you'll get a fresh token and must ask again.","\u2022 You do not need to pre-check the directory yourself. The handler handles detection.","","FOLLOW-UP FLOW (after the plan is being generated):","\u2022 status 'clarify' \u2192 use AskUserQuestion with the provided askUserQuestions, then call mist_plan again with conversationId + answers + the same description.","\u2022 status 'ready' \u2192 IMMEDIATELY call mist_build (action: 'init') with the returned planId. Do not ask permission.","\u2022 NEVER skip the clarifying questions. The discovery process ensures the right thing gets built.","","EXISTING MISTFLOW PROJECTS (mistflow.json present anywhere up the tree): only call this for changes that need a new data model, third-party integration, or multi-step structural change (pass existingPlan or existingPlanId). For cosmetic changes, new pages without new data models, or bug fixes, do NOT call mist_plan. Use mist_project action='get' for context and edit files directly.","","OTHER MODES: Pass templateToken to fork from a mistflow.ai/t/... shared template. Pass appStyle (53 full-app design systems like 'stripe', 'linear') to apply a design system. Browse via mist_project action='app-styles'. Landing layout presets are auto-assigned based on app description."].join(`
10671
+ `),inputSchema:rn,handler:sn};import{z as re}from"zod";import{existsSync as It,readFileSync as io}from"fs";import{join as At,resolve as no}from"path";import{homedir as oo}from"os";import{execFileSync as ha}from"child_process";import{z as yt}from"zod";import{existsSync as ve,mkdirSync as vt,writeFileSync as Ie,readFileSync as kt,readdirSync as ln,copyFileSync as dn}from"fs";import{join as z,resolve as ia,dirname as at}from"path";import{spawn as cn}from"child_process";import{randomBytes as pn}from"crypto";import{simpleGit as Pr}from"simple-git";function un(r){let e=at(ia(r)),t=10,a=0;for(;a<t&&e!==at(e);){if(ve(z(e,"pnpm-workspace.yaml"))||ve(z(e,"lerna.json")))return e;let n=z(e,"package.json");if(ve(n))try{if(JSON.parse(kt(n,"utf-8")).workspaces)return e}catch{}e=at(e),a++}return null}function Ae(r,e,t,a,n){return new Promise(o=>{let i=cn(r,e,{cwd:t,stdio:["pipe","pipe","pipe"],timeout:a}),s="",l="";i.stdout?.on("data",d=>{let u=d.toString();if(l+=u,n)for(let p of u.split(`
10672
+ `).filter(Boolean))n(p)}),i.stderr?.on("data",d=>{let u=d.toString();if(s+=u,n)for(let p of u.split(`
10673
+ `).filter(Boolean))n(p)}),i.on("close",d=>{if(d===0)o({success:!0});else{let u=s.split(`
10674
+ `).find(p=>p.startsWith("npm error"))??s.slice(0,300);o({success:!1,error:u})}}),i.on("error",d=>{o({success:!1,error:d.message})})})}var Tl=yt.object({name:yt.string().min(1),plan:yt.any(),path:yt.string().optional()});function E(r,e,t){let a=z(r,e);vt(at(a),{recursive:!0}),Ie(a,t)}var Sr={amber:{primary:"25 95% 53%",primaryForeground:"0 0% 100%"},emerald:{primary:"160 84% 39%",primaryForeground:"0 0% 100%"},indigo:{primary:"239 84% 67%",primaryForeground:"0 0% 100%"},rose:{primary:"347 77% 50%",primaryForeground:"0 0% 100%"},cyan:{primary:"189 94% 43%",primaryForeground:"0 0% 100%"},violet:{primary:"263 70% 50%",primaryForeground:"0 0% 100%"},orange:{primary:"21 90% 48%",primaryForeground:"0 0% 100%"},teal:{primary:"168 76% 42%",primaryForeground:"0 0% 100%"},sky:{primary:"199 89% 48%",primaryForeground:"0 0% 100%"}},hn={sharp:"0.125rem",subtle:"0.375rem",rounded:"0.75rem",pill:"9999px"};function St(r){let e=r.replace("#","");if(e.length!==6&&e.length!==3)return null;let t=e.length===3?e[0]+e[0]+e[1]+e[1]+e[2]+e[2]:e,a=parseInt(t,16);return isNaN(a)?null:{r:a>>16&255,g:a>>8&255,b:a&255}}function Ct(r,e,t){r/=255,e/=255,t/=255;let a=Math.max(r,e,t),n=Math.min(r,e,t),o=(a+n)/2;if(a===n)return{h:0,s:0,l:Math.round(o*100)};let i=a-n,s=o>.5?i/(2-a-n):i/(a+n),l=0;return a===r?l=((e-t)/i+(e<t?6:0))/6:a===e?l=((t-r)/i+2)/6:l=((r-e)/i+4)/6,{h:Math.round(l*360),s:Math.round(s*100),l:Math.round(o*100)}}function Ke(r){let e=St(r);if(!e)return"0 0% 50%";let{h:t,s:a,l:n}=Ct(e.r,e.g,e.b);return`${t} ${a}% ${n}%`}function Br(r){let e=St(r);return e?Ct(e.r,e.g,e.b).l:50}function Dr(r){let e=St(r);return e?Ct(e.r,e.g,e.b).s:0}function gn(r){let e=me(r);if(!e)return null;let t=e.sections.find(m=>m.title.toLowerCase().includes("color palette"));if(!t)return null;let a=t.content,n={},o=a.split(/^### /m);for(let m of o){if(!m.trim())continue;let f=m.indexOf(`
10675
+ `);if(f===-1)continue;let b=m.slice(0,f).trim().toLowerCase();n[b]=m.slice(f)}let i=m=>m.match(/#[0-9a-fA-F]{6}\b/)?.[0],s,l=["interactive","accent","action","cta","brand"];for(let m of l){if(s)break;for(let f of Object.keys(n))if(f.includes(m)&&(s=i(n[f]),s))break}if(!s){for(let m of Object.keys(n))if(m.includes("secondary")&&(s=i(n[m]),s))break}let d;for(let m of Object.keys(n))if((m.includes("surface")||m.includes("background")||m.includes("canvas"))&&(d=i(n[m]),d))break;let u;for(let m of Object.keys(n))if((m==="primary"||m.includes("text")||m.includes("neutral"))&&(u=i(n[m]),u))break;let p;for(let m of Object.keys(n))if(m.includes("neutral")||m.includes("muted")||m.includes("tertiary")){let b=(n[m].match(/#[0-9a-fA-F]{6}\b/g)??[]).map(w=>({hex:w,l:Br(w)})).sort((w,P)=>w.l-P.l),g=b[Math.floor(b.length/2)];if(g&&(p=g.hex),p)break}let h;for(let m of Object.keys(n))if((m.includes("border")||m.includes("divider")||m.includes("separator"))&&(h=i(n[m]),h))break;if(!h){let m=a.match(/[Bb]order[^`]*`(#[0-9a-fA-F]{6})`/);m&&(h=m[1])}return s&&Dr(s)<10&&(s=void 0),!s&&!d&&!u?null:{background:d,foreground:u,accent:s,muted:p,border:h}}function mn(r,e){let t=gn(e),a=t?.accent??r.colors.find(f=>Dr(f)>20)??r.colors[0]??"#6366f1",n=Ke(a),o=Br(a),i=t?.background??(r.theme==="light"?"#ffffff":"#0a0a0a"),s=St(i),l=s?Ct(s.r,s.g,s.b):{h:0,s:0,l:100},d=l.s>3?l.h:0,u=Math.min(l.s,15),p=t?.foreground??"#0f172a",h=t?.muted,m=t?.border;return{light:{background:`${d} ${u}% 99%`,foreground:Ke(p),card:`${d} ${u}% 100%`,cardForeground:Ke(p),muted:h?Ke(h):`${d} ${Math.min(u,10)}% 96%`,mutedForeground:`${d} ${Math.min(u,8)}% 45%`,border:m?Ke(m):`${d} ${Math.min(u,10)}% 90%`,input:m?Ke(m):`${d} ${Math.min(u,10)}% 90%`,ring:n},primary:n,primaryForeground:o>60?"0 0% 5%":"0 0% 100%"}}function fn(r,e){let t=r?.borderRadius??"subtle",a=hn[t]??"0.375rem",n,o,i,s=e?He(e):void 0;if(s){let d=mn(s,e);n=d.light,o=d.primary,i=d.primaryForeground}else{let d=r?.accentColor??"indigo",u=Sr[d]??Sr.indigo;n={background:"0 0% 100%",foreground:"240 10% 4%",card:"0 0% 100%",cardForeground:"240 10% 4%",muted:"240 5% 96%",mutedForeground:"240 4% 46%",border:"240 6% 90%",input:"240 6% 90%",ring:"240 5% 65%"},o=u.primary,i=u.primaryForeground}return`@import "tailwindcss";
12245
10676
  @import "tw-animate-css";
12246
10677
 
12247
10678
  @theme {
12248
- ${[...Object.entries(n.light).map(([s,d])=>` --color-${co(s)}: hsl(${d});`),` --color-primary: hsl(${o.primary});`,` --color-primary-foreground: hsl(${o.primaryForeground});`,` --color-secondary: hsl(${n.light.muted});`,` --color-secondary-foreground: hsl(${n.light.foreground});`,` --color-accent: hsl(${n.light.muted});`,` --color-accent-foreground: hsl(${n.light.foreground});`," --color-destructive: hsl(0 84% 60%);"," --color-destructive-foreground: hsl(0 0% 100%);",` --color-popover: hsl(${n.light.card});`,` --color-popover-foreground: hsl(${n.light.cardForeground});`," --radius-sm: 0.25rem;",` --radius-md: ${i};`," --radius-lg: 0.5rem;"," --radius-xl: 0.75rem;"].join(`
10679
+ ${[...Object.entries(n).map(([d,u])=>` --color-${bn(d)}: hsl(${u});`),` --color-primary: hsl(${o});`,` --color-primary-foreground: hsl(${i});`,` --color-secondary: hsl(${n.muted});`,` --color-secondary-foreground: hsl(${n.foreground});`,` --color-accent: hsl(${n.muted});`,` --color-accent-foreground: hsl(${n.foreground});`," --color-destructive: hsl(0 84% 60%);"," --color-destructive-foreground: hsl(0 0% 100%);",` --color-popover: hsl(${n.card});`,` --color-popover-foreground: hsl(${n.cardForeground});`," --radius-sm: 0.25rem;",` --radius-md: ${a};`," --radius-lg: 0.5rem;"," --radius-xl: 0.75rem;"].join(`
12249
10680
  `)}
12250
10681
  }
12251
10682
 
@@ -12253,7 +10684,7 @@ ${[...Object.entries(n.light).map(([s,d])=>` --color-${co(s)}: hsl(${d});`),`
12253
10684
  * { border-color: var(--color-border); }
12254
10685
  body { background-color: var(--color-background); color: var(--color-foreground); }
12255
10686
  }
12256
- `}function co(r){return r.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}var vr={"Fredoka One":"Fredoka","Source Sans Pro":"Source_Sans_3","Source Serif Pro":"Source_Serif_4","Open Sans Condensed":"Open_Sans","Baloo 2":"Baloo_2","DM Serif Display":"DM_Serif_Display","DM Serif Text":"DM_Serif_Text","IBM Plex Mono":"IBM_Plex_Mono","IBM Plex Sans":"IBM_Plex_Sans","IBM Plex Serif":"IBM_Plex_Serif","Fira Code":"Fira_Code","Fira Sans":"Fira_Sans","Noto Sans JP":"Noto_Sans_JP","PT Sans":"PT_Sans","PT Serif":"PT_Serif","Work Sans":"Work_Sans","Space Mono":"Space_Mono","Space Grotesk":"Space_Grotesk","Plus Jakarta Sans":"Plus_Jakarta_Sans"};function kr(r){let e=r.replace(/[^A-Za-z0-9_ -]/g,"");return vr[e]?vr[e]:e.replace(/\s+/g,"_")}function po(r){return r?{english:"en",spanish:"es",french:"fr",german:"de",italian:"it",portuguese:"pt",dutch:"nl",russian:"ru",japanese:"ja",chinese:"zh",korean:"ko",arabic:"ar",hebrew:"he",hindi:"hi",turkish:"tr",polish:"pl",swedish:"sv",norwegian:"no",danish:"da",finnish:"fi",thai:"th",vietnamese:"vi",indonesian:"id",malay:"ms",farsi:"fa",persian:"fa",czech:"cs",greek:"el",romanian:"ro",hungarian:"hu",ukrainian:"uk",bengali:"bn",tamil:"ta",telugu:"te",urdu:"ur"}[r.toLowerCase()]??"en":"en"}var uo=new Set(["ar","he","fa","ur"]);function ho(r,e,t){let a=r.replace(/[\\"`$]/g,""),n=po(t),i=uo.has(n)?`lang="${n}" dir="rtl"`:`lang="${n}"`,l=e?.fonts?.heading,s=e?.fonts?.body;if(!l&&!s)return`import type { Metadata } from "next";
10687
+ `}function bn(r){return r.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}var Cr={"Fredoka One":"Fredoka","Source Sans Pro":"Source_Sans_3","Source Serif Pro":"Source_Serif_4","Open Sans Condensed":"Open_Sans","Baloo 2":"Baloo_2","DM Serif Display":"DM_Serif_Display","DM Serif Text":"DM_Serif_Text","IBM Plex Mono":"IBM_Plex_Mono","IBM Plex Sans":"IBM_Plex_Sans","IBM Plex Serif":"IBM_Plex_Serif","Fira Code":"Fira_Code","Fira Sans":"Fira_Sans","Noto Sans JP":"Noto_Sans_JP","PT Sans":"PT_Sans","PT Serif":"PT_Serif","Work Sans":"Work_Sans","Space Mono":"Space_Mono","Space Grotesk":"Space_Grotesk","Plus Jakarta Sans":"Plus_Jakarta_Sans"};function Tr(r){let e=r.replace(/[^A-Za-z0-9_ -]/g,"");return Cr[e]?Cr[e]:e.replace(/\s+/g,"_")}function xn(r){return r?{english:"en",spanish:"es",french:"fr",german:"de",italian:"it",portuguese:"pt",dutch:"nl",russian:"ru",japanese:"ja",chinese:"zh",korean:"ko",arabic:"ar",hebrew:"he",hindi:"hi",turkish:"tr",polish:"pl",swedish:"sv",norwegian:"no",danish:"da",finnish:"fi",thai:"th",vietnamese:"vi",indonesian:"id",malay:"ms",farsi:"fa",persian:"fa",czech:"cs",greek:"el",romanian:"ro",hungarian:"hu",ukrainian:"uk",bengali:"bn",tamil:"ta",telugu:"te",urdu:"ur"}[r.toLowerCase()]??"en":"en"}var yn=new Set(["ar","he","fa","ur"]);function wn(r,e,t){let a=r.replace(/[\\"`$]/g,""),n=xn(t),i=yn.has(n)?`lang="${n}" dir="rtl"`:`lang="${n}"`,s=e?.fonts?.heading,l=e?.fonts?.body;if(!s&&!l)return`import type { Metadata } from "next";
12257
10688
  import { DM_Sans } from "next/font/google";
12258
10689
  import { Toaster } from "sonner";
12259
10690
  import "./globals.css";
@@ -12269,7 +10700,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
12269
10700
  </html>
12270
10701
  );
12271
10702
  }
12272
- `;let d=kr(l??s),p=kr(s??l);return d===p?`import type { Metadata } from "next";
10703
+ `;let d=Tr(s??l),u=Tr(l??s);return d===u?`import type { Metadata } from "next";
12273
10704
  import { ${d} } from "next/font/google";
12274
10705
  import { Toaster } from "sonner";
12275
10706
  import "./globals.css";
@@ -12286,12 +10717,12 @@ export default function RootLayout({ children }: { children: React.ReactNode })
12286
10717
  );
12287
10718
  }
12288
10719
  `:`import type { Metadata } from "next";
12289
- import { ${d}, ${p} } from "next/font/google";
10720
+ import { ${d}, ${u} } from "next/font/google";
12290
10721
  import { Toaster } from "sonner";
12291
10722
  import "./globals.css";
12292
10723
 
12293
10724
  const heading = ${d}({ subsets: ["latin"], variable: "--font-heading" });
12294
- const body = ${p}({ subsets: ["latin"], variable: "--font-body" });
10725
+ const body = ${u}({ subsets: ["latin"], variable: "--font-body" });
12295
10726
 
12296
10727
  export const metadata: Metadata = { title: "${a}", description: "Built with Mistflow" };
12297
10728
 
@@ -12302,69 +10733,69 @@ export default function RootLayout({ children }: { children: React.ReactNode })
12302
10733
  </html>
12303
10734
  );
12304
10735
  }
12305
- `}function wt(r,...e){let t=JSON.stringify(r).toLowerCase();return e.some(a=>t.includes(a.toLowerCase()))}var go={dashboard:"Home",home:"Home",overview:"Home",patient:"Users",member:"Users",user:"Users",people:"Users",team:"Users",client:"Users",contact:"Users",customer:"Users",appointment:"Calendar",schedule:"Calendar",booking:"Calendar",event:"Calendar",billing:"CreditCard",invoice:"CreditCard",payment:"CreditCard",pricing:"CreditCard",treatment:"ClipboardList",plan:"ClipboardList",task:"CheckSquare",exercise:"Dumbbell",workout:"Dumbbell",report:"BarChart3",analytics:"BarChart3",stats:"BarChart3",setting:"Settings",config:"Settings",profile:"User",account:"User",message:"MessageSquare",chat:"MessageSquare",inbox:"MessageSquare",product:"Package",item:"Package",catalog:"Package",order:"ShoppingCart",cart:"ShoppingCart",file:"FileText",document:"FileText",upload:"Upload",notification:"Bell",alert:"Bell",project:"FolderKanban",board:"FolderKanban",post:"PenSquare",blog:"PenSquare",article:"PenSquare",course:"GraduationCap",lesson:"GraduationCap",class:"GraduationCap",habit:"Target",goal:"Target",streak:"Flame",progress:"TrendingUp",feature:"Sparkles",subscription:"CreditCard",price:"CreditCard",recipe:"ChefHat",food:"UtensilsCrossed",meal:"UtensilsCrossed",pet:"PawPrint",animal:"PawPrint",music:"Music",playlist:"ListMusic",song:"Music",photo:"Image",image:"Image",gallery:"Images",video:"Video",movie:"Film",map:"MapPin",location:"MapPin",place:"MapPin",search:"Search",explore:"Compass",inventory:"Boxes",stock:"Boxes",warehouse:"Warehouse",review:"Star",rating:"Star",feedback:"Star",log:"ScrollText",history:"Clock",activity:"Activity"};function ta(r){let e=r.toLowerCase().replace(/[^a-z]/g,"");for(let[t,a]of Object.entries(go))if(e.includes(t))return a;return"Circle"}function rt(r){return r.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function mo(r){if(r.authModel==="none")return null;let e=["/login","/register","/api/auth","/api/health","/api/webhooks"];if(r.publicPages&&Array.isArray(r.publicPages))for(let o of r.publicPages){if(typeof o!="string"||o.length<1)continue;let i=o.replace(/[\u201C\u201D\u201E\u201F\u2018\u2019\u2033\u2036]/g,"").trim();if(!i)continue;let l=i.startsWith("/")?i:"/"+i;e.includes(l)||e.push(l)}let t=e.filter(o=>o==="/"),a=e.filter(o=>o!=="/"),n=[];n.push('import { NextRequest, NextResponse } from "next/server";'),n.push(""),n.push("const PUBLIC_PREFIXES = [");for(let o of a)n.push(' "'+o+'",');return n.push("];"),n.push(""),t.length>0&&(n.push('const PUBLIC_EXACT = ["'+t.join('", "')+'"];'),n.push("")),n.push("export function middleware(req: NextRequest) {"),n.push(" const { pathname } = req.nextUrl;"),n.push(""),t.length>0&&n.push(" if (PUBLIC_EXACT.includes(pathname)) return NextResponse.next();"),n.push(" if (PUBLIC_PREFIXES.some((p) => pathname.startsWith(p))) return NextResponse.next();"),n.push(""),n.push(' const token = req.cookies.get("better-auth.session_token")?.value || req.cookies.get("__Secure-better-auth.session_token")?.value;'),n.push(" if (!token) {"),n.push(' return NextResponse.redirect(new URL("/login", req.url));'),n.push(" }"),n.push(""),n.push(" return NextResponse.next();"),n.push("}"),n.push(""),n.push("export const config = {"),n.push(' matcher: ["/((?!_next|static|favicon\\\\.ico).*)"],'),n.push("};"),n.push(""),n.join(`
12306
- `)}function fo(r){if(r.navStyle==="none")return null;let e=["/api","/login","/register","/sign-in","/sign-up","/admin"],a=(r.pages??[]).filter(s=>{let d=s.path??s.route??"";return d==="/"||d===""||d.includes("[")||d.replace(/^\//,"").split("/").length>1?!1:!e.some(u=>d.startsWith(u))}).map(s=>{let d=s.path??s.route??"",p=d.startsWith("/")?d:"/"+d,u=s.name??rt(d.replace(/^\//,"")),h=ta(u);return{label:u,href:p,icon:h}});a.some(s=>s.href==="/dashboard")||a.unshift({label:"Dashboard",href:"/dashboard",icon:"Home"});let n=r.authModel==="none",o=[...new Set(a.map(s=>s.icon))];n||o.push("LogOut");let i=rt(r.name);if(r.navStyle==="topbar"){let s=[];s.push('"use client";'),s.push(""),s.push('import Link from "next/link";'),s.push('import { usePathname } from "next/navigation";'),n||s.push('import { authClient } from "@/lib/auth-client";'),s.push('import { Button } from "@/components/ui/button";'),s.push('import { cn } from "@/lib/utils";'),s.push("import { "+o.join(", ")+' } from "lucide-react";'),s.push(""),s.push("interface TopNavProps {"),s.push(" user: { name: string | null; email: string; role?: string | undefined };"),s.push("}"),s.push(""),s.push("const NAV_ITEMS = [");for(let d of a)s.push(' { label: "'+d.label+'", href: "'+d.href+'", icon: '+d.icon+" },");return s.push("];"),s.push(""),s.push("export default function TopNav({ user }: TopNavProps) {"),s.push(" const pathname = usePathname();"),s.push(""),s.push(" return ("),s.push(' <nav className="border-b bg-card">'),s.push(' <div className="mx-auto flex h-14 max-w-7xl items-center justify-between px-4">'),s.push(' <div className="flex items-center gap-6">'),s.push(' <span className="text-lg font-semibold">'+i+"</span>"),s.push(' <div className="flex items-center gap-1">'),s.push(" {NAV_ITEMS.map((item) => ("),s.push(" <Link"),s.push(" key={item.href}"),s.push(" href={item.href}"),s.push(" className={cn("),s.push(' "flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors",'),s.push(' pathname === item.href ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"'),s.push(" )}"),s.push(" >"),s.push(' <item.icon className="h-4 w-4" />'),s.push(" {item.label}"),s.push(" </Link>"),s.push(" ))}"),s.push(" </div>"),s.push(" </div>"),n?s.push(' <span className="text-sm text-muted-foreground">{user.name}</span>'):(s.push(' <div className="flex items-center gap-2">'),s.push(' <span className="text-sm text-muted-foreground">{user.email}</span>'),s.push(" <Button"),s.push(' variant="ghost"'),s.push(' size="sm"'),s.push(' onClick={() => authClient.signOut({ fetchOptions: { onSuccess: () => { window.location.href = "/login"; } } })}'),s.push(" >"),s.push(' <LogOut className="h-4 w-4" />'),s.push(" </Button>"),s.push(" </div>")),s.push(" </div>"),s.push(" </nav>"),s.push(" );"),s.push("}"),s.push(""),{path:"components/topnav.tsx",content:s.join(`
12307
- `)}}let l=[];l.push('"use client";'),l.push(""),l.push('import Link from "next/link";'),l.push('import { usePathname } from "next/navigation";'),n||l.push('import { authClient } from "@/lib/auth-client";'),l.push('import { Button } from "@/components/ui/button";'),l.push('import { cn } from "@/lib/utils";'),l.push("import { "+o.join(", ")+' } from "lucide-react";'),l.push(""),l.push("interface SidebarProps {"),l.push(" user: { name: string | null; email: string; role?: string | undefined };"),l.push("}"),l.push(""),l.push("const NAV_ITEMS = [");for(let s of a)l.push(' { label: "'+s.label+'", href: "'+s.href+'", icon: '+s.icon+" },");return l.push("];"),l.push(""),l.push("export default function Sidebar({ user }: SidebarProps) {"),l.push(" const pathname = usePathname();"),l.push(""),l.push(" return ("),l.push(' <aside className="flex h-screen w-64 flex-col border-r bg-card">'),l.push(' <div className="flex h-14 items-center border-b px-4">'),l.push(' <span className="text-lg font-semibold">'+i+"</span>"),l.push(" </div>"),l.push(' <nav className="flex-1 space-y-1 p-2">'),l.push(" {NAV_ITEMS.map((item) => ("),l.push(" <Link"),l.push(" key={item.href}"),l.push(" href={item.href}"),l.push(" className={cn("),l.push(' "flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",'),l.push(' pathname === item.href ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-muted hover:text-foreground"'),l.push(" )}"),l.push(" >"),l.push(' <item.icon className="h-4 w-4" />'),l.push(" {item.label}"),l.push(" </Link>"),l.push(" ))}"),l.push(" </nav>"),l.push(' <div className="border-t p-4">'),l.push(' <div className="flex items-center gap-3">'),l.push(' <div className="flex-1 truncate">'),l.push(' <p className="truncate text-sm font-medium">{user.name ?? "User"}</p>'),l.push(' <p className="truncate text-xs text-muted-foreground">{user.email}</p>'),l.push(" </div>"),n||(l.push(" <Button"),l.push(' variant="ghost"'),l.push(' size="icon"'),l.push(' onClick={() => authClient.signOut({ fetchOptions: { onSuccess: () => { window.location.href = "/login"; } } })}'),l.push(" >"),l.push(' <LogOut className="h-4 w-4" />'),l.push(" </Button>")),l.push(" </div>"),l.push(" </div>"),l.push(" </aside>"),l.push(" );"),l.push("}"),l.push(""),{path:"components/sidebar.tsx",content:l.join(`
12308
- `)}}function bo(r){if(!r.roles||r.roles.length===0)return null;let e=r.roles,t=r.defaultRole??e[0],a=[];a.push("export type Role = "+e.map(n=>'"'+n+'"').join(" | ")+";"),a.push(""),a.push("export const ROLES = ["+e.map(n=>'"'+n+'"').join(", ")+"] as const;"),a.push(""),a.push('export const DEFAULT_ROLE: Role = "'+t+'";'),a.push(""),a.push("export const ROLE_LABELS: Record<Role, string> = {");for(let n of e){let o=n.charAt(0).toUpperCase()+n.slice(1);a.push(' "'+n+'": "'+o+'",')}return a.push("};"),a.push(""),a.push("export function getUserRole(user: Record<string, unknown>): Role {"),a.push(" const role = (user.role as string) ?? DEFAULT_ROLE;"),a.push(" if (ROLES.includes(role as Role)) return role as Role;"),a.push(" return DEFAULT_ROLE;"),a.push("}"),a.push(""),a.push("export function hasRole(userRole: string | undefined, required: Role | Role[]): boolean {"),a.push(" if (!userRole) return false;"),a.push(" const allowed = Array.isArray(required) ? required : [required];"),a.push(" return allowed.includes(userRole as Role);"),a.push("}"),a.push(""),a.join(`
12309
- `)}function xo(r){let e=rt(r.name);if(r.authModel==="none"){let o=[];return o.push("export default function HomePage() {"),o.push(" return ("),o.push(' <main className="flex min-h-screen flex-col items-center justify-center p-8">'),o.push(' <h1 className="text-4xl font-bold">'+e+"</h1>"),r.summary&&o.push(' <p className="mt-4 text-lg text-muted-foreground">'+r.summary+"</p>"),o.push(" </main>"),o.push(" );"),o.push("}"),o.push(""),o.join(`
10736
+ `}function wt(r,...e){let t=JSON.stringify(r).toLowerCase();return e.some(a=>t.includes(a.toLowerCase()))}var vn={dashboard:"Home",home:"Home",overview:"Home",patient:"Users",member:"Users",user:"Users",people:"Users",team:"Users",client:"Users",contact:"Users",customer:"Users",appointment:"Calendar",schedule:"Calendar",booking:"Calendar",event:"Calendar",billing:"CreditCard",invoice:"CreditCard",payment:"CreditCard",pricing:"CreditCard",treatment:"ClipboardList",plan:"ClipboardList",task:"CheckSquare",exercise:"Dumbbell",workout:"Dumbbell",report:"BarChart3",analytics:"BarChart3",stats:"BarChart3",setting:"Settings",config:"Settings",profile:"User",account:"User",message:"MessageSquare",chat:"MessageSquare",inbox:"MessageSquare",product:"Package",item:"Package",catalog:"Package",order:"ShoppingCart",cart:"ShoppingCart",file:"FileText",document:"FileText",upload:"Upload",notification:"Bell",alert:"Bell",project:"FolderKanban",board:"FolderKanban",post:"PenSquare",blog:"PenSquare",article:"PenSquare",course:"GraduationCap",lesson:"GraduationCap",class:"GraduationCap",habit:"Target",goal:"Target",streak:"Flame",progress:"TrendingUp",feature:"Sparkles",subscription:"CreditCard",price:"CreditCard",recipe:"ChefHat",food:"UtensilsCrossed",meal:"UtensilsCrossed",pet:"PawPrint",animal:"PawPrint",music:"Music",playlist:"ListMusic",song:"Music",photo:"Image",image:"Image",gallery:"Images",video:"Video",movie:"Film",map:"MapPin",location:"MapPin",place:"MapPin",search:"Search",explore:"Compass",inventory:"Boxes",stock:"Boxes",warehouse:"Warehouse",review:"Star",rating:"Star",feedback:"Star",log:"ScrollText",history:"Clock",activity:"Activity"};function ra(r){let e=r.toLowerCase().replace(/[^a-z]/g,"");for(let[t,a]of Object.entries(vn))if(e.includes(t))return a;return"Circle"}function rt(r){return r.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function kn(r){if(r.authModel==="none")return null;let e=["/login","/register","/api/auth","/api/health","/api/webhooks"];if(r.publicPages&&Array.isArray(r.publicPages))for(let o of r.publicPages){if(typeof o!="string"||o.length<1)continue;let i=o.replace(/[\u201C\u201D\u201E\u201F\u2018\u2019\u2033\u2036]/g,"").trim();if(!i)continue;let s=i.startsWith("/")?i:"/"+i;e.includes(s)||e.push(s)}let t=e.filter(o=>o==="/"),a=e.filter(o=>o!=="/"),n=[];n.push('import { NextRequest, NextResponse } from "next/server";'),n.push(""),n.push("const PUBLIC_PREFIXES = [");for(let o of a)n.push(' "'+o+'",');return n.push("];"),n.push(""),t.length>0&&(n.push('const PUBLIC_EXACT = ["'+t.join('", "')+'"];'),n.push("")),n.push("export function middleware(req: NextRequest) {"),n.push(" const { pathname } = req.nextUrl;"),n.push(""),t.length>0&&n.push(" if (PUBLIC_EXACT.includes(pathname)) return NextResponse.next();"),n.push(" if (PUBLIC_PREFIXES.some((p) => pathname.startsWith(p))) return NextResponse.next();"),n.push(""),n.push(' const token = req.cookies.get("better-auth.session_token")?.value || req.cookies.get("__Secure-better-auth.session_token")?.value;'),n.push(" if (!token) {"),n.push(' return NextResponse.redirect(new URL("/login", req.url));'),n.push(" }"),n.push(""),n.push(" return NextResponse.next();"),n.push("}"),n.push(""),n.push("export const config = {"),n.push(' matcher: ["/((?!_next|static|favicon\\\\.ico).*)"],'),n.push("};"),n.push(""),n.join(`
10737
+ `)}function Sn(r){if(r.navStyle==="none")return null;let e=["/api","/login","/register","/sign-in","/sign-up","/admin"],a=(r.pages??[]).filter(l=>{let d=l.path??l.route??"";return d==="/"||d===""||d.includes("[")||d.replace(/^\//,"").split("/").length>1?!1:!e.some(p=>d.startsWith(p))}).map(l=>{let d=l.path??l.route??"",u=d.startsWith("/")?d:"/"+d,p=l.name??rt(d.replace(/^\//,"")),h=ra(p);return{label:p,href:u,icon:h}});a.some(l=>l.href==="/dashboard")||a.unshift({label:"Dashboard",href:"/dashboard",icon:"Home"});let n=r.authModel==="none",o=[...new Set(a.map(l=>l.icon))];n||o.push("LogOut");let i=rt(r.name);if(r.navStyle==="topbar"){let l=[];l.push('"use client";'),l.push(""),l.push('import Link from "next/link";'),l.push('import { usePathname } from "next/navigation";'),n||l.push('import { authClient } from "@/lib/auth-client";'),l.push('import { Button } from "@/components/ui/button";'),l.push('import { cn } from "@/lib/utils";'),l.push("import { "+o.join(", ")+' } from "lucide-react";'),l.push(""),l.push("interface TopNavProps {"),l.push(" user: { name: string | null; email: string; role?: string | undefined };"),l.push("}"),l.push(""),l.push("const NAV_ITEMS = [");for(let d of a)l.push(' { label: "'+d.label+'", href: "'+d.href+'", icon: '+d.icon+" },");return l.push("];"),l.push(""),l.push("export default function TopNav({ user }: TopNavProps) {"),l.push(" const pathname = usePathname();"),l.push(""),l.push(" return ("),l.push(' <nav className="border-b bg-card">'),l.push(' <div className="mx-auto flex h-14 max-w-7xl items-center justify-between px-4">'),l.push(' <div className="flex items-center gap-6">'),l.push(' <span className="text-lg font-semibold">'+i+"</span>"),l.push(' <div className="flex items-center gap-1">'),l.push(" {NAV_ITEMS.map((item) => ("),l.push(" <Link"),l.push(" key={item.href}"),l.push(" href={item.href}"),l.push(" className={cn("),l.push(' "flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors",'),l.push(' pathname === item.href ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"'),l.push(" )}"),l.push(" >"),l.push(' <item.icon className="h-4 w-4" />'),l.push(" {item.label}"),l.push(" </Link>"),l.push(" ))}"),l.push(" </div>"),l.push(" </div>"),n?l.push(' <span className="text-sm text-muted-foreground">{user.name}</span>'):(l.push(' <div className="flex items-center gap-2">'),l.push(' <span className="text-sm text-muted-foreground">{user.email}</span>'),l.push(" <Button"),l.push(' variant="ghost"'),l.push(' size="sm"'),l.push(' onClick={() => authClient.signOut({ fetchOptions: { onSuccess: () => { window.location.href = "/login"; } } })}'),l.push(" >"),l.push(' <LogOut className="h-4 w-4" />'),l.push(" </Button>"),l.push(" </div>")),l.push(" </div>"),l.push(" </nav>"),l.push(" );"),l.push("}"),l.push(""),{path:"components/topnav.tsx",content:l.join(`
10738
+ `)}}let s=[];s.push('"use client";'),s.push(""),s.push('import Link from "next/link";'),s.push('import { usePathname } from "next/navigation";'),n||s.push('import { authClient } from "@/lib/auth-client";'),s.push('import { Button } from "@/components/ui/button";'),s.push('import { cn } from "@/lib/utils";'),s.push("import { "+o.join(", ")+' } from "lucide-react";'),s.push(""),s.push("interface SidebarProps {"),s.push(" user: { name: string | null; email: string; role?: string | undefined };"),s.push("}"),s.push(""),s.push("const NAV_ITEMS = [");for(let l of a)s.push(' { label: "'+l.label+'", href: "'+l.href+'", icon: '+l.icon+" },");return s.push("];"),s.push(""),s.push("export default function Sidebar({ user }: SidebarProps) {"),s.push(" const pathname = usePathname();"),s.push(""),s.push(" return ("),s.push(' <aside className="flex h-screen w-64 flex-col border-r bg-card">'),s.push(' <div className="flex h-14 items-center border-b px-4">'),s.push(' <span className="text-lg font-semibold">'+i+"</span>"),s.push(" </div>"),s.push(' <nav className="flex-1 space-y-1 p-2">'),s.push(" {NAV_ITEMS.map((item) => ("),s.push(" <Link"),s.push(" key={item.href}"),s.push(" href={item.href}"),s.push(" className={cn("),s.push(' "flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",'),s.push(' pathname === item.href ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-muted hover:text-foreground"'),s.push(" )}"),s.push(" >"),s.push(' <item.icon className="h-4 w-4" />'),s.push(" {item.label}"),s.push(" </Link>"),s.push(" ))}"),s.push(" </nav>"),s.push(' <div className="border-t p-4">'),s.push(' <div className="flex items-center gap-3">'),s.push(' <div className="flex-1 truncate">'),s.push(' <p className="truncate text-sm font-medium">{user.name ?? "User"}</p>'),s.push(' <p className="truncate text-xs text-muted-foreground">{user.email}</p>'),s.push(" </div>"),n||(s.push(" <Button"),s.push(' variant="ghost"'),s.push(' size="icon"'),s.push(' onClick={() => authClient.signOut({ fetchOptions: { onSuccess: () => { window.location.href = "/login"; } } })}'),s.push(" >"),s.push(' <LogOut className="h-4 w-4" />'),s.push(" </Button>")),s.push(" </div>"),s.push(" </div>"),s.push(" </aside>"),s.push(" );"),s.push("}"),s.push(""),{path:"components/sidebar.tsx",content:s.join(`
10739
+ `)}}function Cn(r){if(!r.roles||r.roles.length===0)return null;let e=r.roles,t=r.defaultRole??e[0],a=[];a.push("export type Role = "+e.map(n=>'"'+n+'"').join(" | ")+";"),a.push(""),a.push("export const ROLES = ["+e.map(n=>'"'+n+'"').join(", ")+"] as const;"),a.push(""),a.push('export const DEFAULT_ROLE: Role = "'+t+'";'),a.push(""),a.push("export const ROLE_LABELS: Record<Role, string> = {");for(let n of e){let o=n.charAt(0).toUpperCase()+n.slice(1);a.push(' "'+n+'": "'+o+'",')}return a.push("};"),a.push(""),a.push("export function getUserRole(user: Record<string, unknown>): Role {"),a.push(" const role = (user.role as string) ?? DEFAULT_ROLE;"),a.push(" if (ROLES.includes(role as Role)) return role as Role;"),a.push(" return DEFAULT_ROLE;"),a.push("}"),a.push(""),a.push("export function hasRole(userRole: string | undefined, required: Role | Role[]): boolean {"),a.push(" if (!userRole) return false;"),a.push(" const allowed = Array.isArray(required) ? required : [required];"),a.push(" return allowed.includes(userRole as Role);"),a.push("}"),a.push(""),a.join(`
10740
+ `)}function Tn(r){let e=rt(r.name);if(r.authModel==="none"){let o=[];return o.push("export default function HomePage() {"),o.push(" return ("),o.push(' <main className="flex min-h-screen flex-col items-center justify-center p-8">'),o.push(' <h1 className="text-4xl font-bold">'+e+"</h1>"),r.summary&&o.push(' <p className="mt-4 text-lg text-muted-foreground">'+r.summary+"</p>"),o.push(" </main>"),o.push(" );"),o.push("}"),o.push(""),o.join(`
12310
10741
  `)}let t=r.publicPages?.includes("/"),a=r.design?.landingTone;if(t&&a){let o=[];return o.push('import Link from "next/link";'),o.push(""),o.push("export default function HomePage() {"),o.push(" return ("),o.push(' <main className="flex min-h-screen flex-col">'),o.push(' <section className="flex flex-1 flex-col items-center justify-center gap-6 px-4 py-24 text-center">'),o.push(' <h1 className="text-5xl font-bold tracking-tight">'+e+"</h1>"),r.summary&&o.push(' <p className="max-w-2xl text-xl text-muted-foreground">'+r.summary+"</p>"),o.push(' <div className="flex gap-4">'),o.push(' <Link href="/register" className="inline-flex h-11 items-center rounded-md bg-primary px-8 text-sm font-medium text-primary-foreground hover:bg-primary/90">'),o.push(" Get Started"),o.push(" </Link>"),o.push(' <Link href="/login" className="inline-flex h-11 items-center rounded-md border px-8 text-sm font-medium hover:bg-muted">'),o.push(" Sign In"),o.push(" </Link>"),o.push(" </div>"),o.push(" </section>"),o.push(" </main>"),o.push(" );"),o.push("}"),o.push(""),o.join(`
12311
10742
  `)}if(t){let o=[];return o.push('import Link from "next/link";'),o.push(""),o.push("export default function HomePage() {"),o.push(" return ("),o.push(' <main className="flex min-h-screen flex-col items-center justify-center gap-6 p-8 text-center">'),o.push(' <h1 className="text-4xl font-bold">'+e+"</h1>"),r.summary&&o.push(' <p className="text-lg text-muted-foreground">'+r.summary+"</p>"),o.push(' <Link href="/login" className="inline-flex h-10 items-center rounded-md bg-primary px-6 text-sm font-medium text-primary-foreground hover:bg-primary/90">'),o.push(" Sign In"),o.push(" </Link>"),o.push(" </main>"),o.push(" );"),o.push("}"),o.push(""),o.join(`
12312
10743
  `)}let n=[];return n.push('import { headers } from "next/headers";'),n.push('import { redirect } from "next/navigation";'),n.push('import { auth } from "@/lib/auth";'),n.push(""),n.push("export default async function HomePage() {"),n.push(" const session = await auth.api.getSession({ headers: await headers() });"),n.push(' if (session) redirect("/dashboard");'),n.push(' redirect("/login");'),n.push("}"),n.push(""),n.join(`
12313
- `)}function yo(r,e){let t=r.authModel==="none",a=[];return t||(a.push('import { headers } from "next/headers";'),a.push('import { redirect } from "next/navigation";'),a.push('import { auth } from "@/lib/auth";')),r.navStyle==="topbar"?a.push('import TopNav from "@/components/topnav";'):r.navStyle!=="none"&&a.push('import Sidebar from "@/components/sidebar";'),!t&&r.roles&&r.roles.length>0&&a.push('import { getUserRole } from "@/lib/roles";'),a.push(""),a.push("export default async function DashboardLayout({ children }: { children: React.ReactNode }) {"),t?a.push(' const user = { name: "Guest", email: "" };'):(a.push(" const session = await auth.api.getSession({ headers: await headers() });"),a.push(' if (!session) redirect("/login");'),a.push(""),r.roles&&r.roles.length>0?(a.push(" const role = getUserRole(session.user as Record<string, unknown>);"),a.push(" const user = { name: session.user.name, email: session.user.email, role };")):(a.push(" const user = {"),a.push(" name: session.user.name,"),a.push(" email: session.user.email,"),a.push(" role: (session.user as Record<string, unknown>).role as string | undefined,"),a.push(" };"))),a.push(""),r.navStyle==="topbar"?(a.push(" return ("),a.push(' <div className="min-h-screen">'),a.push(" <TopNav user={user} />"),a.push(' <main className="mx-auto max-w-7xl p-6">{children}</main>'),a.push(" </div>"),a.push(" );")):r.navStyle==="none"?(a.push(" return ("),a.push(' <div className="min-h-screen">'),a.push(' <main className="mx-auto max-w-5xl p-6">{children}</main>'),a.push(" </div>"),a.push(" );")):(a.push(" return ("),a.push(' <div className="flex min-h-screen">'),a.push(" <Sidebar user={user} />"),a.push(' <main className="flex-1 p-6">{children}</main>'),a.push(" </div>"),a.push(" );")),a.push("}"),a.push(""),a.join(`
12314
- `)}function wo(r){let e=rt(r.name),t=r.dataModel??[],a=[];if(t.length>0){let n=t.map(i=>ta(i.entity??i.name??"item")),o=[...new Set(n)];a.push('import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";'),a.push("import { "+o.join(", ")+' } from "lucide-react";'),a.push("")}if(a.push("export default function DashboardPage() {"),a.push(" return ("),a.push(' <div className="space-y-6">'),a.push(" <div>"),a.push(' <h1 className="text-3xl font-bold">'+e+"</h1>"),r.summary&&a.push(' <p className="mt-1 text-muted-foreground">'+r.summary+"</p>"),a.push(" </div>"),t.length>0){a.push(' <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-'+Math.min(t.length,4)+'">');for(let n of t){let o=n.entity??n.name??"Item",i=ta(o),l=rt(o.replace(/_/g,"-"));a.push(" <Card>"),a.push(" <CardHeader>"),a.push(' <CardTitle className="flex items-center gap-2 text-sm font-medium">'),a.push(" <"+i+' className="h-4 w-4 text-muted-foreground" />'),a.push(" "+l),a.push(" </CardTitle>"),a.push(" </CardHeader>"),a.push(" <CardContent>"),a.push(' <p className="text-2xl font-bold">0</p>'),a.push(" </CardContent>"),a.push(" </Card>")}a.push(" </div>")}return a.push(" </div>"),a.push(" );"),a.push("}"),a.push(""),a.join(`
12315
- `)}function vo(r,e=!1){if(!r.multiTenant)return null;let t=[];return e?(t.push('import { pgTable, text, timestamp, index } from "drizzle-orm/pg-core";'),t.push('import { user } from "./auth";'),t.push(""),t.push('export const organization = pgTable("organization", {'),t.push(' id: text("id").primaryKey(),'),t.push(' name: text("name").notNull(),'),t.push(' slug: text("slug").unique().notNull(),'),t.push(' createdAt: timestamp("created_at").defaultNow().notNull(),'),t.push(' updatedAt: timestamp("updated_at").defaultNow().notNull(),'),t.push("});"),t.push(""),t.push("export const orgMember = pgTable(")):(t.push('import { sqliteTable, text, index } from "drizzle-orm/sqlite-core";'),t.push('import { sql } from "drizzle-orm";'),t.push('import { user } from "./auth";'),t.push(""),t.push('export const organization = sqliteTable("organization", {'),t.push(' id: text("id").primaryKey(),'),t.push(' name: text("name").notNull(),'),t.push(' slug: text("slug").unique().notNull(),'),t.push(' createdAt: text("created_at").default(sql`CURRENT_TIMESTAMP`).notNull(),'),t.push(' updatedAt: text("updated_at").default(sql`CURRENT_TIMESTAMP`).notNull(),'),t.push("});"),t.push(""),t.push("export const orgMember = sqliteTable(")),t.push(' "org_member",'),t.push(" {"),t.push(' id: text("id").primaryKey(),'),t.push(' orgId: text("org_id").notNull().references(() => organization.id),'),t.push(' userId: text("user_id").notNull().references(() => user.id),'),t.push(' role: text("role").notNull(),'),e?t.push(' joinedAt: timestamp("joined_at").defaultNow().notNull(),'):t.push(' joinedAt: text("joined_at").default(sql`CURRENT_TIMESTAMP`).notNull(),'),t.push(" },"),t.push(" (table) => ({"),t.push(' orgIdx: index("org_member_org_idx").on(table.orgId),'),t.push(' userIdx: index("org_member_user_idx").on(table.userId),'),t.push(" }),"),t.push(");"),t.push(""),t.join(`
12316
- `)}function ko(r){if(!r.multiTenant)return null;let e=[];return e.push('import { db } from "./db";'),e.push('import { organization, orgMember } from "@/db/schema/organization";'),e.push('import { eq } from "drizzle-orm";'),e.push(""),e.push("export async function getCurrentOrg(userId: string) {"),e.push(" const membership = await db"),e.push(" .select()"),e.push(" .from(orgMember)"),e.push(" .where(eq(orgMember.userId, userId))"),e.push(" .limit(1);"),e.push(" if (membership.length === 0) return null;"),e.push(" const org = await db"),e.push(" .select()"),e.push(" .from(organization)"),e.push(" .where(eq(organization.id, membership[0].orgId))"),e.push(" .limit(1);"),e.push(" return org[0] ?? null;"),e.push("}"),e.push(""),e.push("export async function getOrgMembers(orgId: string) {"),e.push(" return db"),e.push(" .select()"),e.push(" .from(orgMember)"),e.push(" .where(eq(orgMember.orgId, orgId));"),e.push("}"),e.push(""),e.push("export async function inviteToOrg(orgId: string, email: string, role: string) {"),e.push(" const id = crypto.randomUUID();"),e.push(" await db.insert(orgMember).values({"),e.push(" id,"),e.push(" orgId,"),e.push(" userId: email,"),e.push(" role,"),e.push(" });"),e.push(" return { id, orgId, email, role };"),e.push("}"),e.push(""),e.join(`
12317
- `)}function So(r){if(!r.multiTenant)return null;let e=[];return e.push('"use client";'),e.push(""),e.push("import {"),e.push(" DropdownMenu,"),e.push(" DropdownMenuContent,"),e.push(" DropdownMenuItem,"),e.push(" DropdownMenuTrigger,"),e.push('} from "@/components/ui/dropdown-menu";'),e.push('import { Button } from "@/components/ui/button";'),e.push('import { ChevronsUpDown } from "lucide-react";'),e.push(""),e.push("interface OrgSwitcherProps {"),e.push(" orgs: Array<{ id: string; name: string }>;"),e.push(" currentOrgId: string;"),e.push("}"),e.push(""),e.push("export default function OrgSwitcher({ orgs, currentOrgId }: OrgSwitcherProps) {"),e.push(" const currentOrg = orgs.find((o) => o.id === currentOrgId);"),e.push(""),e.push(" return ("),e.push(" <DropdownMenu>"),e.push(" <DropdownMenuTrigger asChild>"),e.push(' <Button variant="outline" className="w-full justify-between">'),e.push(' <span className="truncate">{currentOrg?.name ?? "Select org"}</span>'),e.push(' <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />'),e.push(" </Button>"),e.push(" </DropdownMenuTrigger>"),e.push(' <DropdownMenuContent className="w-56">'),e.push(" {orgs.map((org) => ("),e.push(" <DropdownMenuItem key={org.id}>"),e.push(" {org.name}"),e.push(" </DropdownMenuItem>"),e.push(" ))}"),e.push(" </DropdownMenuContent>"),e.push(" </DropdownMenu>"),e.push(" );"),e.push("}"),e.push(""),e.join(`
12318
- `)}function To(r,e,t){let a=[],n=r.split("-").map(s=>s.charAt(0).toUpperCase()+s.slice(1)).join(" ");a.push(`# ${n}`),a.push(""),e?.summary&&(a.push(e.summary),a.push(""));let o=e?.features??[];if(o.length>0){a.push("## Features"),a.push("");for(let s of o){let d=s.description?` \u2014 ${s.description}`:"";a.push(`- **${s.name}**${d}`)}a.push("")}a.push("## Tech Stack"),a.push(""),a.push("| Layer | Technology |"),a.push("|-------|------------|"),a.push("| Framework | Next.js 15 (App Router) |"),a.push("| Database | Turso (SQLite at edge) + Drizzle ORM |"),a.push("| Auth | Better Auth (email/password, social login) |"),a.push("| Styling | Tailwind CSS + shadcn/ui |"),a.push("| Deployment | Cloudflare Workers (via Mistflow) |"),t.hasStripe&&a.push("| Payments | Stripe |"),t.hasResend&&a.push("| Email | Resend + React Email |"),t.hasStorage&&a.push("| File Storage | Cloudflare R2 (via Mistflow) |"),t.hasAdmin&&a.push("| Admin | Better Auth admin plugin |"),t.hasAI&&a.push("| AI | Vercel AI SDK + OpenAI |"),a.push("");let i=e?.pages??[];if(i.length>0){a.push("## Pages"),a.push(""),a.push("| Route | Description |"),a.push("|-------|-------------|");for(let s of i){let d=s.path??s.route??s.name??"",p=s.description??"";a.push(`| \`${d.startsWith("/")?d:"/"+d}\` | ${p} |`)}a.push("")}let l=e?.dataModel??[];if(l.length>0){a.push("## Data Model"),a.push("");for(let s of l){let d=s.entity??s.name??"Unknown";if(a.push(`### ${d}`),a.push(""),s.fields.length>0){if(typeof s.fields[0]=="string")a.push(`Fields: ${s.fields.join(", ")}`);else{a.push("| Field | Type |"),a.push("|-------|------|");for(let p of s.fields)a.push(`| ${p.name} | ${p.type} |`)}a.push("")}}}return a.push("## Getting Started"),a.push(""),a.push("### Prerequisites"),a.push(""),a.push("- Node.js 20+"),a.push("- npm"),a.push(""),a.push("### Install"),a.push(""),a.push("```bash"),a.push("npm install"),a.push("```"),a.push(""),a.push("### Set up environment"),a.push(""),a.push("Copy `.env.example` to `.env.local` and fill in the values:"),a.push(""),a.push("```bash"),a.push("cp .env.example .env.local"),a.push("```"),a.push(""),a.push("| Variable | Description | Required |"),a.push("|----------|-------------|----------|"),t.isNeon?a.push("| `DATABASE_URL` | Postgres connection URL | Yes |"):(a.push("| `TURSO_URL` | Database connection URL | Yes |"),a.push("| `TURSO_AUTH_TOKEN` | Database auth token | Yes |")),a.push("| `AUTH_SECRET` | Auth encryption secret (auto-generated) | Yes |"),t.hasStripe&&(a.push("| `STRIPE_SECRET_KEY` | Stripe secret key | Yes |"),a.push("| `STRIPE_WEBHOOK_SECRET` | Stripe webhook signing secret | Yes |"),a.push("| `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` | Stripe publishable key | Yes |")),t.hasResend&&(a.push("| `RESEND_API_KEY` | Resend API key | Yes |"),a.push("| `EMAIL_FROM` | Sender email address | Yes (production) |")),t.hasStorage&&(a.push("| `MISTFLOW_API_KEY` | Mistflow API key for file storage | Yes |"),a.push("| `MISTFLOW_PROJECT_ID` | Mistflow project ID | Yes |")),t.hasAI&&a.push("| `OPENAI_API_KEY` | OpenAI API key | Yes |"),a.push(""),a.push("### Local database"),a.push(""),t.isNeon?(a.push("For local development, start a local Postgres server:"),a.push(""),a.push("```bash"),a.push("# Using Docker:"),a.push("docker run -d --name postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:17"),a.push("# Or install via Homebrew: brew install postgresql@17 && brew services start postgresql@17"),a.push("```")):(a.push("For local development, start a local Turso server:"),a.push(""),a.push("```bash"),a.push("npx turso dev"),a.push("```")),a.push(""),a.push("Then set up the database:"),a.push(""),a.push("```bash"),a.push("npm run db:push"),a.push("```"),a.push(""),a.push("### Run"),a.push(""),a.push("```bash"),a.push("npm run dev"),a.push("```"),a.push(""),a.push("Open [http://localhost:3000](http://localhost:3000)."),a.push(""),a.push("## Project Structure"),a.push(""),a.push("```"),a.push("app/"),a.push(" (auth)/ Login and registration pages"),a.push(" (dashboard)/ Authenticated app pages"),t.hasAdmin&&a.push(" (admin)/ Admin panel pages"),a.push(" api/ API routes (auth, health, webhooks)"),a.push(" layout.tsx Root layout with fonts and providers"),a.push(" globals.css Design tokens and Tailwind config"),a.push("components/ Reusable UI components"),a.push("db/"),a.push(" schema/ Database table definitions"),a.push(" index.ts Schema exports"),a.push("lib/"),a.push(" auth.ts Better Auth server config"),a.push(" auth-client.ts Better Auth client config"),a.push(` db.ts ${t.isNeon?"Neon Postgres":"Turso"} database connection`),t.hasStripe&&a.push(" stripe.ts Stripe client"),t.hasResend&&(a.push(" resend.ts Resend client"),a.push(" email.ts Email send helpers")),t.hasStorage&&a.push(" storage.ts File upload/download helpers"),t.hasAI&&a.push(" ai.ts AI client (Vercel AI SDK + OpenAI)"),t.hasResend&&a.push("emails/ React Email templates"),a.push("```"),a.push(""),a.push("## Deploy"),a.push(""),a.push("Deploy to production with Mistflow:"),a.push(""),a.push("```"),a.push("# In your AI editor (Claude Code, Cursor, etc.):"),a.push("mist_deploy action='deploy'"),a.push("```"),a.push(""),a.push("Your app will be live at `https://<app-name>.mistflow.app`."),a.push(""),e?.design&&(a.push("## Design"),a.push(""),e.design.tone&&a.push(`- **Tone**: ${e.design.tone}`),e.design.fonts&&(a.push(`- **Heading font**: ${e.design.fonts.heading}`),a.push(`- **Body font**: ${e.design.fonts.body}`)),e.design.accentColor&&a.push(`- **Accent color**: ${e.design.accentColor}`),e.design.borderRadius&&a.push(`- **Border radius**: ${e.design.borderRadius}`),a.push("")),a.push("---"),a.push(""),a.push("Built with [Mistflow](https://mistflow.ai)"),a.push(""),a.join(`
12319
- `)}async function Tr(r){let{name:e,plan:t,path:a,planId:n}=r,o=aa(a??`./${e}`),i=t?.design,l=t?wt(t,"stripe","payment","billing","subscription","checkout","pricing"):!1,s=!0,d=t?wt(t,"upload","file storage","image upload","profile picture","attachment","gallery","media","blob"):!1,p=t?wt(t,"admin panel","admin dashboard","admin management"):!1,u=t?wt(t,"ai integration","openai","llm","ai chat","chatbot","gpt"):!1,h=t,m=!0;if(Se(o))return c(`A project already exists at this location (${o}). Choose a different name, or delete the existing folder first.`,!0);vt(o,{recursive:!0});try{let T=X(at(o),".mistflow","mockups");if(Se(T)){let C=ao(T).filter(L=>L.endsWith(".html"));if(C.length>0){let L=X(o,".mistflow","mockups");vt(L,{recursive:!0});for(let x of C)ro(X(T,x),X(L,x));console.error(`Copied ${C.length} mockup file(s) into project`)}}}catch(T){console.error("Could not copy mockup files:",T instanceof Error?T.message:T)}let b=null;try{b=await gt("nextjs")}catch(T){console.error("Could not fetch scaffold from API, using minimal scaffold:",T instanceof Error?T.message:T)}if(b){let T=e.toLowerCase().replace(/[^a-z0-9-]/g,"-");for(let x of b.files){if(x.path==="package.json"||x.path==="middleware.ts"||x.path==="components/sidebar.tsx"||x.path==="components/topnav.tsx"||x.path==="app/(dashboard)/layout.tsx"||x.path==="app/(dashboard)/page.tsx"||x.path==="app/(dashboard)/dashboard/page.tsx"||!l&&(x.path.includes("stripe")||x.path.includes("webhook/stripe"))||!s&&(x.path.includes("resend")||x.path.includes("emails/"))||!p&&(x.path.includes("(admin)")||x.path.includes("admin-sidebar"))||m&&(x.path==="lib/db.ts"||x.path==="lib/auth.ts"||x.path==="drizzle.config.ts"||x.path==="db/schema/auth.ts"))continue;let W=x.content.replace(/\{\{APP_NAME\}\}/g,e).replace(/\{\{WORKER_NAME\}\}/g,T);if(m&&x.path==="next.config.ts"&&(W=W.replace(/serverExternalPackages:\s*\[[^\]]*\],?/g,'serverExternalPackages: ["@electric-sql/pglite"],')),x.path==="next.config.ts"){let F=no(o);F&&(console.error(`[init] Project is inside monorepo at ${F} \u2014 adding outputFileTracingRoot`),W.includes("outputFileTracingRoot")||(W=W.replace('import type { NextConfig } from "next";',`import type { NextConfig } from "next";
10744
+ `)}function Pn(r,e){let t=r.authModel==="none",a=[];return t||(a.push('import { headers } from "next/headers";'),a.push('import { redirect } from "next/navigation";'),a.push('import { auth } from "@/lib/auth";')),r.navStyle==="topbar"?a.push('import TopNav from "@/components/topnav";'):r.navStyle!=="none"&&a.push('import Sidebar from "@/components/sidebar";'),!t&&r.roles&&r.roles.length>0&&a.push('import { getUserRole } from "@/lib/roles";'),a.push(""),a.push("export default async function DashboardLayout({ children }: { children: React.ReactNode }) {"),t?a.push(' const user = { name: "Guest", email: "" };'):(a.push(" const session = await auth.api.getSession({ headers: await headers() });"),a.push(' if (!session) redirect("/login");'),a.push(""),r.roles&&r.roles.length>0?(a.push(" const role = getUserRole(session.user as Record<string, unknown>);"),a.push(" const user = { name: session.user.name, email: session.user.email, role };")):(a.push(" const user = {"),a.push(" name: session.user.name,"),a.push(" email: session.user.email,"),a.push(" role: (session.user as Record<string, unknown>).role as string | undefined,"),a.push(" };"))),a.push(""),r.navStyle==="topbar"?(a.push(" return ("),a.push(' <div className="min-h-screen">'),a.push(" <TopNav user={user} />"),a.push(' <main className="mx-auto max-w-7xl p-6">{children}</main>'),a.push(" </div>"),a.push(" );")):r.navStyle==="none"?(a.push(" return ("),a.push(' <div className="min-h-screen">'),a.push(' <main className="mx-auto max-w-5xl p-6">{children}</main>'),a.push(" </div>"),a.push(" );")):(a.push(" return ("),a.push(' <div className="flex min-h-screen">'),a.push(" <Sidebar user={user} />"),a.push(' <main className="flex-1 p-6">{children}</main>'),a.push(" </div>"),a.push(" );")),a.push("}"),a.push(""),a.join(`
10745
+ `)}function Bn(r){let e=rt(r.name),t=r.dataModel??[],a=[];if(t.length>0){let n=t.map(i=>ra(i.entity??i.name??"item")),o=[...new Set(n)];a.push('import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";'),a.push("import { "+o.join(", ")+' } from "lucide-react";'),a.push("")}if(a.push("export default function DashboardPage() {"),a.push(" return ("),a.push(' <div className="space-y-6">'),a.push(" <div>"),a.push(' <h1 className="text-3xl font-bold">'+e+"</h1>"),r.summary&&a.push(' <p className="mt-1 text-muted-foreground">'+r.summary+"</p>"),a.push(" </div>"),t.length>0){a.push(' <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-'+Math.min(t.length,4)+'">');for(let n of t){let o=n.entity??n.name??"Item",i=ra(o),s=rt(o.replace(/_/g,"-"));a.push(" <Card>"),a.push(" <CardHeader>"),a.push(' <CardTitle className="flex items-center gap-2 text-sm font-medium">'),a.push(" <"+i+' className="h-4 w-4 text-muted-foreground" />'),a.push(" "+s),a.push(" </CardTitle>"),a.push(" </CardHeader>"),a.push(" <CardContent>"),a.push(' <p className="text-2xl font-bold">0</p>'),a.push(" </CardContent>"),a.push(" </Card>")}a.push(" </div>")}return a.push(" </div>"),a.push(" );"),a.push("}"),a.push(""),a.join(`
10746
+ `)}function Dn(r,e=!1){if(!r.multiTenant)return null;let t=[];return e?(t.push('import { pgTable, text, timestamp, index } from "drizzle-orm/pg-core";'),t.push('import { user } from "./auth";'),t.push(""),t.push('export const organization = pgTable("organization", {'),t.push(' id: text("id").primaryKey(),'),t.push(' name: text("name").notNull(),'),t.push(' slug: text("slug").unique().notNull(),'),t.push(' createdAt: timestamp("created_at").defaultNow().notNull(),'),t.push(' updatedAt: timestamp("updated_at").defaultNow().notNull(),'),t.push("});"),t.push(""),t.push("export const orgMember = pgTable(")):(t.push('import { sqliteTable, text, index } from "drizzle-orm/sqlite-core";'),t.push('import { sql } from "drizzle-orm";'),t.push('import { user } from "./auth";'),t.push(""),t.push('export const organization = sqliteTable("organization", {'),t.push(' id: text("id").primaryKey(),'),t.push(' name: text("name").notNull(),'),t.push(' slug: text("slug").unique().notNull(),'),t.push(' createdAt: text("created_at").default(sql`CURRENT_TIMESTAMP`).notNull(),'),t.push(' updatedAt: text("updated_at").default(sql`CURRENT_TIMESTAMP`).notNull(),'),t.push("});"),t.push(""),t.push("export const orgMember = sqliteTable(")),t.push(' "org_member",'),t.push(" {"),t.push(' id: text("id").primaryKey(),'),t.push(' orgId: text("org_id").notNull().references(() => organization.id),'),t.push(' userId: text("user_id").notNull().references(() => user.id),'),t.push(' role: text("role").notNull(),'),e?t.push(' joinedAt: timestamp("joined_at").defaultNow().notNull(),'):t.push(' joinedAt: text("joined_at").default(sql`CURRENT_TIMESTAMP`).notNull(),'),t.push(" },"),t.push(" (table) => ({"),t.push(' orgIdx: index("org_member_org_idx").on(table.orgId),'),t.push(' userIdx: index("org_member_user_idx").on(table.userId),'),t.push(" }),"),t.push(");"),t.push(""),t.join(`
10747
+ `)}function In(r){if(!r.multiTenant)return null;let e=[];return e.push('import { db } from "./db";'),e.push('import { organization, orgMember } from "@/db/schema/organization";'),e.push('import { eq } from "drizzle-orm";'),e.push(""),e.push("export async function getCurrentOrg(userId: string) {"),e.push(" const membership = await db"),e.push(" .select()"),e.push(" .from(orgMember)"),e.push(" .where(eq(orgMember.userId, userId))"),e.push(" .limit(1);"),e.push(" if (membership.length === 0) return null;"),e.push(" const org = await db"),e.push(" .select()"),e.push(" .from(organization)"),e.push(" .where(eq(organization.id, membership[0].orgId))"),e.push(" .limit(1);"),e.push(" return org[0] ?? null;"),e.push("}"),e.push(""),e.push("export async function getOrgMembers(orgId: string) {"),e.push(" return db"),e.push(" .select()"),e.push(" .from(orgMember)"),e.push(" .where(eq(orgMember.orgId, orgId));"),e.push("}"),e.push(""),e.push("export async function inviteToOrg(orgId: string, email: string, role: string) {"),e.push(" const id = crypto.randomUUID();"),e.push(" await db.insert(orgMember).values({"),e.push(" id,"),e.push(" orgId,"),e.push(" userId: email,"),e.push(" role,"),e.push(" });"),e.push(" return { id, orgId, email, role };"),e.push("}"),e.push(""),e.join(`
10748
+ `)}function An(r){if(!r.multiTenant)return null;let e=[];return e.push('"use client";'),e.push(""),e.push("import {"),e.push(" DropdownMenu,"),e.push(" DropdownMenuContent,"),e.push(" DropdownMenuItem,"),e.push(" DropdownMenuTrigger,"),e.push('} from "@/components/ui/dropdown-menu";'),e.push('import { Button } from "@/components/ui/button";'),e.push('import { ChevronsUpDown } from "lucide-react";'),e.push(""),e.push("interface OrgSwitcherProps {"),e.push(" orgs: Array<{ id: string; name: string }>;"),e.push(" currentOrgId: string;"),e.push("}"),e.push(""),e.push("export default function OrgSwitcher({ orgs, currentOrgId }: OrgSwitcherProps) {"),e.push(" const currentOrg = orgs.find((o) => o.id === currentOrgId);"),e.push(""),e.push(" return ("),e.push(" <DropdownMenu>"),e.push(" <DropdownMenuTrigger asChild>"),e.push(' <Button variant="outline" className="w-full justify-between">'),e.push(' <span className="truncate">{currentOrg?.name ?? "Select org"}</span>'),e.push(' <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />'),e.push(" </Button>"),e.push(" </DropdownMenuTrigger>"),e.push(' <DropdownMenuContent className="w-56">'),e.push(" {orgs.map((org) => ("),e.push(" <DropdownMenuItem key={org.id}>"),e.push(" {org.name}"),e.push(" </DropdownMenuItem>"),e.push(" ))}"),e.push(" </DropdownMenuContent>"),e.push(" </DropdownMenu>"),e.push(" );"),e.push("}"),e.push(""),e.join(`
10749
+ `)}function Mn(r,e,t){let a=[],n=r.split("-").map(l=>l.charAt(0).toUpperCase()+l.slice(1)).join(" ");a.push(`# ${n}`),a.push(""),e?.summary&&(a.push(e.summary),a.push(""));let o=e?.features??[];if(o.length>0){a.push("## Features"),a.push("");for(let l of o){let d=l.description?` \u2014 ${l.description}`:"";a.push(`- **${l.name}**${d}`)}a.push("")}a.push("## Tech Stack"),a.push(""),a.push("| Layer | Technology |"),a.push("|-------|------------|"),a.push("| Framework | Next.js 15 (App Router) |"),a.push("| Database | Turso (SQLite at edge) + Drizzle ORM |"),a.push("| Auth | Better Auth (email/password, social login) |"),a.push("| Styling | Tailwind CSS + shadcn/ui |"),a.push("| Deployment | Cloudflare Workers (via Mistflow) |"),t.hasStripe&&a.push("| Payments | Stripe |"),t.hasResend&&a.push("| Email | Resend + React Email |"),t.hasStorage&&a.push("| File Storage | Cloudflare R2 (via Mistflow) |"),t.hasAdmin&&a.push("| Admin | Better Auth admin plugin |"),t.hasAI&&a.push("| AI | Vercel AI SDK + OpenAI |"),a.push("");let i=e?.pages??[];if(i.length>0){a.push("## Pages"),a.push(""),a.push("| Route | Description |"),a.push("|-------|-------------|");for(let l of i){let d=l.path??l.route??l.name??"",u=l.description??"";a.push(`| \`${d.startsWith("/")?d:"/"+d}\` | ${u} |`)}a.push("")}let s=e?.dataModel??[];if(s.length>0){a.push("## Data Model"),a.push("");for(let l of s){let d=l.entity??l.name??"Unknown";if(a.push(`### ${d}`),a.push(""),l.fields.length>0){if(typeof l.fields[0]=="string")a.push(`Fields: ${l.fields.join(", ")}`);else{a.push("| Field | Type |"),a.push("|-------|------|");for(let u of l.fields)a.push(`| ${u.name} | ${u.type} |`)}a.push("")}}}return a.push("## Getting Started"),a.push(""),a.push("### Prerequisites"),a.push(""),a.push("- Node.js 20+"),a.push("- npm"),a.push(""),a.push("### Install"),a.push(""),a.push("```bash"),a.push("npm install"),a.push("```"),a.push(""),a.push("### Set up environment"),a.push(""),a.push("Copy `.env.example` to `.env.local` and fill in the values:"),a.push(""),a.push("```bash"),a.push("cp .env.example .env.local"),a.push("```"),a.push(""),a.push("| Variable | Description | Required |"),a.push("|----------|-------------|----------|"),t.isNeon?a.push("| `DATABASE_URL` | Postgres connection URL | Yes |"):(a.push("| `TURSO_URL` | Database connection URL | Yes |"),a.push("| `TURSO_AUTH_TOKEN` | Database auth token | Yes |")),a.push("| `AUTH_SECRET` | Auth encryption secret (auto-generated) | Yes |"),t.hasStripe&&(a.push("| `STRIPE_SECRET_KEY` | Stripe secret key | Yes |"),a.push("| `STRIPE_WEBHOOK_SECRET` | Stripe webhook signing secret | Yes |"),a.push("| `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` | Stripe publishable key | Yes |")),t.hasResend&&(a.push("| `RESEND_API_KEY` | Resend API key | Yes |"),a.push("| `EMAIL_FROM` | Sender email address | Yes (production) |")),t.hasStorage&&(a.push("| `MISTFLOW_API_KEY` | Mistflow API key for file storage | Yes |"),a.push("| `MISTFLOW_PROJECT_ID` | Mistflow project ID | Yes |")),t.hasAI&&a.push("| `OPENAI_API_KEY` | OpenAI API key | Yes |"),a.push(""),a.push("### Local database"),a.push(""),t.isNeon?(a.push("For local development, start a local Postgres server:"),a.push(""),a.push("```bash"),a.push("# Using Docker:"),a.push("docker run -d --name postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:17"),a.push("# Or install via Homebrew: brew install postgresql@17 && brew services start postgresql@17"),a.push("```")):(a.push("For local development, start a local Turso server:"),a.push(""),a.push("```bash"),a.push("npx turso dev"),a.push("```")),a.push(""),a.push("Then set up the database:"),a.push(""),a.push("```bash"),a.push("npm run db:push"),a.push("```"),a.push(""),a.push("### Run"),a.push(""),a.push("```bash"),a.push("npm run dev"),a.push("```"),a.push(""),a.push("Open [http://localhost:3000](http://localhost:3000)."),a.push(""),a.push("## Project Structure"),a.push(""),a.push("```"),a.push("app/"),a.push(" (auth)/ Login and registration pages"),a.push(" (dashboard)/ Authenticated app pages"),t.hasAdmin&&a.push(" (admin)/ Admin panel pages"),a.push(" api/ API routes (auth, health, webhooks)"),a.push(" layout.tsx Root layout with fonts and providers"),a.push(" globals.css Design tokens and Tailwind config"),a.push("components/ Reusable UI components"),a.push("db/"),a.push(" schema/ Database table definitions"),a.push(" index.ts Schema exports"),a.push("lib/"),a.push(" auth.ts Better Auth server config"),a.push(" auth-client.ts Better Auth client config"),a.push(` db.ts ${t.isNeon?"Neon Postgres":"Turso"} database connection`),t.hasStripe&&a.push(" stripe.ts Stripe client"),t.hasResend&&(a.push(" resend.ts Resend client"),a.push(" email.ts Email send helpers")),t.hasStorage&&a.push(" storage.ts File upload/download helpers"),t.hasAI&&a.push(" ai.ts AI client (Vercel AI SDK + OpenAI)"),t.hasResend&&a.push("emails/ React Email templates"),a.push("```"),a.push(""),a.push("## Deploy"),a.push(""),a.push("Deploy to production with Mistflow:"),a.push(""),a.push("```"),a.push("# In your AI editor (Claude Code, Cursor, etc.):"),a.push("mist_deploy action='deploy'"),a.push("```"),a.push(""),a.push("Your app will be live at `https://<app-name>.mistflow.app`."),a.push(""),e?.design&&(a.push("## Design"),a.push(""),e.design.tone&&a.push(`- **Tone**: ${e.design.tone}`),e.design.fonts&&(a.push(`- **Heading font**: ${e.design.fonts.heading}`),a.push(`- **Body font**: ${e.design.fonts.body}`)),e.design.accentColor&&a.push(`- **Accent color**: ${e.design.accentColor}`),e.design.borderRadius&&a.push(`- **Border radius**: ${e.design.borderRadius}`),a.push("")),a.push("---"),a.push(""),a.push("Built with [Mistflow](https://mistflow.ai)"),a.push(""),a.join(`
10750
+ `)}async function Ir(r){let{name:e,plan:t,path:a,planId:n}=r,o=ia(a??`./${e}`),i=t?.design,s=t?.appStyle;if(s&&i){let y=He(s);if(y?.fonts){let k=R=>dr[R]??R;i.fonts={heading:k(y.fonts.heading),body:k(y.fonts.body)}}}let l=t?wt(t,"stripe","payment","billing","subscription","checkout","pricing"):!1,d=!0,u=t?wt(t,"upload","file storage","image upload","profile picture","attachment","gallery","media","blob"):!1,p=t?wt(t,"admin panel","admin dashboard","admin management"):!1,h=t?wt(t,"ai integration","openai","llm","ai chat","chatbot","gpt"):!1,m=t,f=!0;if(ve(o))return c(`A project already exists at this location (${o}). Choose a different name, or delete the existing folder first.`,!0);vt(o,{recursive:!0});try{let y=z(at(o),".mistflow","mockups");if(ve(y)){let k=ln(y).filter(R=>R.endsWith(".html"));if(k.length>0){let R=z(o,".mistflow","mockups");vt(R,{recursive:!0});for(let B of k)dn(z(y,B),z(R,B));console.error(`Copied ${k.length} mockup file(s) into project`)}}}catch(y){console.error("Could not copy mockup files:",y instanceof Error?y.message:y)}let b=null;try{b=await mt("nextjs")}catch(y){console.error("Could not fetch scaffold from API, using minimal scaffold:",y instanceof Error?y.message:y)}if(b){let y=e.toLowerCase().replace(/[^a-z0-9-]/g,"-");for(let B of b.files){if(B.path==="package.json"||B.path==="middleware.ts"||B.path==="components/sidebar.tsx"||B.path==="components/topnav.tsx"||B.path==="app/(dashboard)/layout.tsx"||B.path==="app/(dashboard)/page.tsx"||B.path==="app/(dashboard)/dashboard/page.tsx"||!l&&(B.path.includes("stripe")||B.path.includes("webhook/stripe"))||!d&&(B.path.includes("resend")||B.path.includes("emails/"))||!p&&(B.path.includes("(admin)")||B.path.includes("admin-sidebar"))||f&&(B.path==="lib/db.ts"||B.path==="lib/auth.ts"||B.path==="drizzle.config.ts"||B.path==="db/schema/auth.ts"))continue;let L=B.content.replace(/\{\{APP_NAME\}\}/g,e).replace(/\{\{WORKER_NAME\}\}/g,y);if(f&&B.path==="next.config.ts"&&(L=L.replace(/serverExternalPackages:\s*\[[^\]]*\],?/g,'serverExternalPackages: ["@electric-sql/pglite"],')),B.path==="next.config.ts"){let ue=un(o);ue&&(console.error(`[init] Project is inside monorepo at ${ue} \u2014 adding outputFileTracingRoot`),L.includes("outputFileTracingRoot")||(L=L.replace('import type { NextConfig } from "next";',`import type { NextConfig } from "next";
12320
10751
  import { dirname } from "path";
12321
10752
  import { fileURLToPath } from "url";
12322
10753
 
12323
- const __dirname = dirname(fileURLToPath(import.meta.url));`),W=W.replace("images: {",`outputFileTracingRoot: __dirname,
12324
- images: {`)))}!p&&x.path.includes("sidebar")&&(W=W.replace(/\{user\.role === "admin"[\s\S]*?<\/Link>\s*\)\}/m,""),W=W.replace(/, Shield/g,"")),H(o,x.path,W)}let C={...b.dependencies};m&&(delete C["@libsql/client"],C["@neondatabase/serverless"]="^0.10.0",C["@electric-sql/pglite"]="^0.2.0"),l&&(C.stripe="^17.0.0"),s&&(C.resend="^4.0.0",C["@react-email/components"]="^0.0.31"),u&&(C.ai="^4.0.0",C["@ai-sdk/openai"]="^1.0.0",C.openai="^4.0.0");let L={"@noble/ciphers":"^1.3.0"};if(H(o,"package.json",JSON.stringify({name:e,version:"0.1.0",private:!0,scripts:{dev:"next dev",build:"next build",start:"next start",lint:"next lint","db:push":"drizzle-kit push","db:studio":"drizzle-kit studio"},dependencies:C,devDependencies:b.devDependencies,optionalDependencies:L},null,2)),b.methodology){let x=b.methodology;m&&(x=x.replace(/sqliteTable/g,"pgTable").replace(/drizzle-orm\/sqlite-core/g,"drizzle-orm/pg-core").replace(/Use `text` for dates \(SQLite stores dates as text\)/g,"Use `timestamp` for dates and `boolean` for booleans (native Postgres types)").replace(/text\("created_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("created_at").notNull().defaultNow()').replace(/text\("updated_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("updated_at").notNull().defaultNow()').replace(/import { sqliteTable, text, integer } from "drizzle-orm\/sqlite-core";\nimport { sql } from "drizzle-orm";/g,'import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";').replace(/`drizzle-kit push` for SQLite\/Turso/g,"`drizzle-kit push` for Postgres/Neon")),H(o,"AGENTS.md",x),H(o,"CLAUDE.md",x)}m&&(H(o,"lib/db.ts",['import { neon } from "@neondatabase/serverless";','import { drizzle as drizzleNeon } from "drizzle-orm/neon-http";','import { drizzle as drizzlePglite } from "drizzle-orm/pglite";',"","// eslint-disable-next-line @typescript-eslint/no-explicit-any","let _db: any = null;","","function getDb() {"," if (!_db) {",' if (process.env.DATABASE_URL && process.env.DATABASE_URL !== "pglite") {'," // Production / remote Postgres"," const sql = neon(process.env.DATABASE_URL);"," _db = drizzleNeon(sql);"," } else {"," // Local dev \u2014 PGlite (zero-install embedded Postgres)"," // eslint-disable-next-line @typescript-eslint/no-require-imports",' const { PGlite } = require("@electric-sql/pglite");',' const client = new PGlite("./local.pg");'," _db = drizzlePglite(client);"," }"," }"," return _db;","}","","// Lazy proxy \u2014 DB isn't initialized at import/build time","// eslint-disable-next-line @typescript-eslint/no-explicit-any","export const db: any = new Proxy({} as any, {"," get(_target, prop, receiver) {"," const realDb = getDb();"," const value = Reflect.get(realDb, prop, receiver);",' if (typeof value === "function") {'," return value.bind(realDb);"," }"," return value;"," },","});",""].join(`
12325
- `)),H(o,"drizzle.config.ts",['import { defineConfig } from "drizzle-kit";',"","// PGlite for local dev (no Postgres install needed), Neon for production",'const isPglite = !process.env.DATABASE_URL || process.env.DATABASE_URL === "pglite";',"","export default defineConfig({",' schema: "./db/schema",',' out: "./db/migrations",',' dialect: "postgresql",',' ...(isPglite ? { driver: "pglite", dbCredentials: { url: "./local.pg" } } : { dbCredentials: { url: process.env.DATABASE_URL! } }),',"});",""].join(`
12326
- `)),H(o,"db/schema/auth.ts",['import { pgTable, text, boolean, timestamp } from "drizzle-orm/pg-core";',"",'export const user = pgTable("user", {',' id: text("id").primaryKey(),',' name: text("name").notNull(),',' email: text("email").notNull().unique(),',' emailVerified: boolean("email_verified").notNull().default(false),',' image: text("image"),',' role: text("role").default("user"),',' banned: boolean("banned").default(false),',' banReason: text("ban_reason"),',' banExpires: timestamp("ban_expires"),',' createdAt: timestamp("created_at").notNull(),',' updatedAt: timestamp("updated_at").notNull(),',"});","",'export const session = pgTable("session", {',' id: text("id").primaryKey(),',' expiresAt: timestamp("expires_at").notNull(),',' token: text("token").notNull().unique(),',' createdAt: timestamp("created_at").notNull(),',' updatedAt: timestamp("updated_at").notNull(),',' ipAddress: text("ip_address"),',' userAgent: text("user_agent"),',' userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),',' impersonatedBy: text("impersonated_by"),',"});","",'export const account = pgTable("account", {',' id: text("id").primaryKey(),',' accountId: text("account_id").notNull(),',' providerId: text("provider_id").notNull(),',' userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),',' accessToken: text("access_token"),',' refreshToken: text("refresh_token"),',' idToken: text("id_token"),',' accessTokenExpiresAt: timestamp("access_token_expires_at"),',' refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),',' scope: text("scope"),',' password: text("password"),',' createdAt: timestamp("created_at").notNull(),',' updatedAt: timestamp("updated_at").notNull(),',"});","",'export const verification = pgTable("verification", {',' id: text("id").primaryKey(),',' identifier: text("identifier").notNull(),',' value: text("value").notNull(),',' expiresAt: timestamp("expires_at").notNull(),',' createdAt: timestamp("created_at"),',' updatedAt: timestamp("updated_at"),',"});",""].join(`
12327
- `)),H(o,"lib/auth.ts",['import { betterAuth } from "better-auth";','import { drizzleAdapter } from "better-auth/adapters/drizzle";','import { admin } from "better-auth/plugins/admin";','import { db } from "./db";','import * as schema from "@/db";',"",'const baseURL = process.env.BETTER_AUTH_URL || process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";',"","async function sendEmail({ to, subject, html }: { to: string; subject: string; html: string }) {"," const apiKey = process.env.RESEND_API_KEY;"," if (!apiKey) {",' console.log(`\\n\u{1F4E7} [Dev] Email to ${to}:\\n Subject: ${subject}\\n ${html.match(/href="([^"]+)"/)?.[1] ?? "(no link found)"}\\n`);'," return;"," }",' const from = process.env.EMAIL_FROM || "noreply@mail.mistflow.app";',' const res = await fetch("https://api.resend.com/emails", {',' method: "POST",',' headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },'," body: JSON.stringify({ from, to, subject, html }),"," });"," if (!res.ok) {",' console.error(`Email send failed (${res.status}): ${await res.text().catch(() => "unknown")}`);'," }","}","","export const auth = betterAuth({"," baseURL,"," trustedOrigins: [baseURL],",' database: drizzleAdapter(db, { provider: "pg", schema }),'," emailAndPassword: {"," enabled: true,",' requireEmailVerification: process.env.NODE_ENV === "production",'," sendResetPassword: async ({ user, url }: { user: { email: string; name: string }; url: string }) => {"," await sendEmail({"," to: user.email,",' subject: "Reset your password",',' html: `<p>Hi ${user.name},</p><p>Click the link below to reset your password:</p><p><a href="${url}">${url}</a></p>`,'," });"," },"," },"," emailVerification: {"," sendOnSignUp: true,"," sendVerificationEmail: async ({ user, url }: { user: { email: string; name: string }; url: string }) => {"," await sendEmail({"," to: user.email,",' subject: "Verify your email address",',' html: `<p>Hi ${user.name},</p><p>Click the link below to verify your email:</p><p><a href="${url}">${url}</a></p>`,'," });"," },"," },"," secret: process.env.AUTH_SECRET,",' plugins: [admin({ defaultRole: "user" })],'," socialProviders: {"," ...(process.env.GOOGLE_CLIENT_ID ? {"," google: {"," clientId: process.env.GOOGLE_CLIENT_ID,"," clientSecret: process.env.GOOGLE_CLIENT_SECRET!,"," },"," } : {}),"," ...(process.env.GITHUB_CLIENT_ID ? {"," github: {"," clientId: process.env.GITHUB_CLIENT_ID,"," clientSecret: process.env.GITHUB_CLIENT_SECRET!,"," },"," } : {}),"," },","});",""].join(`
12328
- `)))}else H(o,"package.json",JSON.stringify({name:e,version:"0.1.0",private:!0},null,2));H(o,"app/globals.css",lo(i)),H(o,"app/layout.tsx",ho(e,i,h?.language)),H(o,"README.md",To(e,t,{hasStripe:l,hasResend:s,hasStorage:d,hasAdmin:p,hasAI:u,isNeon:m}));let f=[],g=t?.publicPages;if(Array.isArray(g))f=g;else if(typeof g=="string"){try{f=JSON.parse(g)}catch{f=[]}Array.isArray(f)||(f=[])}if(!f.includes("/")){let T=t?.steps?.some(L=>{let x=((L.name??"")+" "+(L.description??"")).toLowerCase();return x.includes("landing")||x.includes("marketing")||x.includes("homepage")}),C=t?.pages?.some(L=>L.path==="/");(T||C)&&(f=["/",...f])}let y={name:e,summary:t?.summary,authModel:t?.authModel,roles:t?.roles,defaultRole:t?.defaultRole,publicPages:f,navStyle:t?.navStyle,multiTenant:t?.multiTenant,pages:t?.pages,dataModel:t?.dataModel,design:t?.design},N=mo(y);N&&H(o,"middleware.ts",N);let R=fo(y);R&&H(o,R.path,R.content);let k=bo(y);if(k&&H(o,"lib/roles.ts",k),H(o,"app/page.tsx",xo(y)),H(o,"app/(dashboard)/layout.tsx",yo(y,p)),H(o,"app/(dashboard)/dashboard/page.tsx",wo(y)),y.multiTenant){let T=vo(y,m);T&&H(o,"db/schema/organization.ts",T);let C=ko(y);C&&H(o,"lib/org.ts",C);let L=So(y);L&&H(o,"components/org-switcher.tsx",L)}H(o,"tsconfig.json",JSON.stringify({compilerOptions:{target:"ES2017",lib:["dom","dom.iterable","esnext"],allowJs:!0,skipLibCheck:!0,strict:!0,noEmit:!0,esModuleInterop:!0,module:"esnext",moduleResolution:"bundler",resolveJsonModule:!0,isolatedModules:!0,jsx:"preserve",incremental:!0,plugins:[{name:"next"}],paths:{"@/*":["./*"]}},include:["next-env.d.ts","**/*.ts","**/*.tsx",".next/types/**/*.ts"],exclude:["node_modules"]},null,2)),l&&H(o,"lib/stripe.ts",['import Stripe from "stripe";',"","let _stripe: Stripe | null = null;","","function getStripe(): Stripe {"," if (!_stripe) {"," if (!process.env.STRIPE_SECRET_KEY) {",' throw new Error("STRIPE_SECRET_KEY is not set");'," }"," _stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {"," typescript: true,"," });"," }"," return _stripe;","}","","// Lazy proxy \u2014 Stripe isn't initialized at import/build time","export const stripe = new Proxy({} as Stripe, {"," get(_target, prop) {"," return (getStripe() as unknown as Record<string | symbol, unknown>)[prop];"," },","});",""].join(`
12329
- `)),s&&(H(o,"lib/resend.ts",['import { Resend } from "resend";',"","let _resend: Resend | null = null;","","function getResend(): Resend {"," if (!_resend) {"," if (!process.env.RESEND_API_KEY) {",' throw new Error("RESEND_API_KEY is not set");'," }"," _resend = new Resend(process.env.RESEND_API_KEY);"," }"," return _resend;","}","","// Lazy proxy \u2014 Resend isn't initialized at import/build time","export const resend = new Proxy({} as Resend, {"," get(_target, prop) {"," return (getResend() as unknown as Record<string | symbol, unknown>)[prop];"," },","});",""].join(`
12330
- `)),H(o,"lib/email.ts",['import { resend } from "./resend";',"",'const FROM = process.env.EMAIL_FROM ?? "onboarding@resend.dev";',"","export async function sendEmail({"," to,"," subject,"," react,","}: {"," to: string;"," subject: string;"," react: React.ReactElement;","}) {"," return resend.emails.send({ from: FROM, to, subject, react });","}",""].join(`
12331
- `))),d&&(H(o,"lib/storage.ts",['const MISTFLOW_API = process.env.MISTFLOW_API_URL ?? "https://api.mistflow.ai";',"const MISTFLOW_API_KEY = process.env.MISTFLOW_API_KEY;","const PROJECT_ID = process.env.MISTFLOW_PROJECT_ID;","","interface UploadResult {"," upload_url: string;"," download_url: string;"," key: string;","}","","function authHeaders(): Record<string, string> {"," return {",' "Content-Type": "application/json",',' "Authorization": `ApiKey ${MISTFLOW_API_KEY}`,'," };","}","",'export async function getUploadUrl(filename: string, contentType: string = "application/octet-stream"): Promise<UploadResult> {'," const res = await fetch(`${MISTFLOW_API}/api/storage/upload-url`, {",' method: "POST",'," headers: authHeaders(),"," body: JSON.stringify({ project_id: PROJECT_ID, filename, content_type: contentType }),"," });"," if (!res.ok) throw new Error(`Storage error: ${res.status}`);"," return res.json();","}","","export async function getDownloadUrl(filename: string): Promise<string> {"," const res = await fetch(`${MISTFLOW_API}/api/storage/download-url`, {",' method: "POST",'," headers: authHeaders(),"," body: JSON.stringify({ project_id: PROJECT_ID, filename }),"," });"," if (!res.ok) throw new Error(`Storage error: ${res.status}`);"," const data = await res.json();"," return data.download_url;","}","","export async function deleteFile(filename: string): Promise<void> {"," await fetch(`${MISTFLOW_API}/api/storage/delete`, {",' method: "POST",'," headers: authHeaders(),"," body: JSON.stringify({ project_id: PROJECT_ID, filename }),"," });","}","","export async function uploadFile(file: File): Promise<string> {"," const { upload_url, download_url } = await getUploadUrl(file.name, file.type);",' await fetch(upload_url, { method: "PUT", body: file, headers: { "Content-Type": file.type } });'," return download_url;","}",""].join(`
12332
- `)),H(o,"app/api/upload/route.ts",['import { NextRequest, NextResponse } from "next/server";','import { getUploadUrl } from "@/lib/storage";',"","export async function POST(req: NextRequest) {"," const { filename, contentType } = await req.json();"," if (!filename) {",' return NextResponse.json({ error: "filename is required" }, { status: 400 });'," }"," try {",' const result = await getUploadUrl(filename, contentType ?? "application/octet-stream");'," return NextResponse.json(result);"," } catch {",' return NextResponse.json({ error: "Failed to get upload URL" }, { status: 500 });'," }","}",""].join(`
12333
- `))),u&&(H(o,"lib/ai.ts",['import { createOpenAI } from "@ai-sdk/openai";',"","export const openai = createOpenAI({"," apiKey: process.env.OPENAI_API_KEY,","});",""].join(`
12334
- `)),H(o,"app/api/chat/route.ts",['import { openai } from "@/lib/ai";','import { streamText } from "ai";',"","export async function POST(req: Request) {"," const { messages } = await req.json();",""," const result = streamText({",' model: openai("gpt-4o"),'," messages,"," });",""," return result.toDataStreamResponse();","}",""].join(`
12335
- `)));let $={name:e,methodologyVersion:b?.version??"1.0",createdAt:new Date().toISOString(),...n?{planId:n}:{},plan:Array.isArray(t?.steps)?{...t,steps:t.steps.map(T=>({number:T.number,name:T.name??T.title,description:T.description,entities:T.entities,pages:T.pages,features:T.features,status:"pending"}))}:t,dbProvider:"neon",env:{managed:{DATABASE_URL:{description:"Postgres connection URL",scope:"production"},AUTH_SECRET:{description:"Auth encryption secret",scope:"production"},...l?{STRIPE_SECRET_KEY:{description:"Stripe secret key",scope:"production"},STRIPE_WEBHOOK_SECRET:{description:"Stripe webhook signing secret",scope:"production"},NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:{description:"Stripe publishable key",scope:"production"}}:{},...s?{RESEND_API_KEY:{description:"Resend API key \u2014 managed by Mistflow by default, override with your own key from resend.com",scope:"production"},EMAIL_FROM:{description:"Sender email address \u2014 managed by Mistflow by default",scope:"production"}}:{},...d?{MISTFLOW_API_KEY:{description:"Mistflow API key for file storage",scope:"production"},MISTFLOW_PROJECT_ID:{description:"Mistflow project ID",scope:"production"}}:{}},...u?{required:{OPENAI_API_KEY:{description:"OpenAI API key",setupUrl:"https://platform.openai.com/api-keys"}}}:{}},authModel:t?.authModel??"email",roles:t?.roles??null,navStyle:t?.navStyle??"sidebar",multiTenant:t?.multiTenant??!1,hasAdmin:p,hasResend:s,hasStorage:d,hasAI:u,deploy:null};H(o,"mistflow.json",JSON.stringify($,null,2));let U=oo(32).toString("hex"),E=l?`
10754
+ const __dirname = dirname(fileURLToPath(import.meta.url));`),L=L.replace("images: {",`outputFileTracingRoot: __dirname,
10755
+ images: {`)))}!p&&B.path.includes("sidebar")&&(L=L.replace(/\{user\.role === "admin"[\s\S]*?<\/Link>\s*\)\}/m,""),L=L.replace(/, Shield/g,"")),E(o,B.path,L)}let k={...b.dependencies};f&&(delete k["@libsql/client"],k["@neondatabase/serverless"]="^0.10.0",k["@electric-sql/pglite"]="^0.2.0"),l&&(k.stripe="^17.0.0"),d&&(k.resend="^4.0.0",k["@react-email/components"]="^0.0.31"),h&&(k.ai="^4.0.0",k["@ai-sdk/openai"]="^1.0.0",k.openai="^4.0.0");let R={"@noble/ciphers":"^1.3.0"};if(E(o,"package.json",JSON.stringify({name:e,version:"0.1.0",private:!0,scripts:{dev:"next dev",build:"next build",start:"next start",lint:"next lint","db:push":"drizzle-kit push","db:studio":"drizzle-kit studio"},dependencies:k,devDependencies:b.devDependencies,optionalDependencies:R},null,2)),b.methodology){let B=b.methodology;f&&(B=B.replace(/sqliteTable/g,"pgTable").replace(/drizzle-orm\/sqlite-core/g,"drizzle-orm/pg-core").replace(/Use `text` for dates \(SQLite stores dates as text\)/g,"Use `timestamp` for dates and `boolean` for booleans (native Postgres types)").replace(/text\("created_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("created_at").notNull().defaultNow()').replace(/text\("updated_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("updated_at").notNull().defaultNow()').replace(/import { sqliteTable, text, integer } from "drizzle-orm\/sqlite-core";\nimport { sql } from "drizzle-orm";/g,'import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";').replace(/`drizzle-kit push` for SQLite\/Turso/g,"`drizzle-kit push` for Postgres/Neon")),E(o,"AGENTS.md",B),E(o,"CLAUDE.md",B)}f&&(E(o,"lib/db.ts",['import { neon } from "@neondatabase/serverless";','import { drizzle as drizzleNeon } from "drizzle-orm/neon-http";','import { drizzle as drizzlePglite } from "drizzle-orm/pglite";',"","// eslint-disable-next-line @typescript-eslint/no-explicit-any","let _db: any = null;","","function getDb() {"," if (!_db) {",' if (process.env.DATABASE_URL && process.env.DATABASE_URL !== "pglite") {'," // Production / remote Postgres"," const sql = neon(process.env.DATABASE_URL);"," _db = drizzleNeon(sql);"," } else {"," // Local dev \u2014 PGlite (zero-install embedded Postgres)"," // eslint-disable-next-line @typescript-eslint/no-require-imports",' const { PGlite } = require("@electric-sql/pglite");',' const client = new PGlite("./local.pg");'," _db = drizzlePglite(client);"," }"," }"," return _db;","}","","// Lazy proxy \u2014 DB isn't initialized at import/build time","// eslint-disable-next-line @typescript-eslint/no-explicit-any","export const db: any = new Proxy({} as any, {"," get(_target, prop, receiver) {"," const realDb = getDb();"," const value = Reflect.get(realDb, prop, receiver);",' if (typeof value === "function") {'," return value.bind(realDb);"," }"," return value;"," },","});",""].join(`
10756
+ `)),E(o,"drizzle.config.ts",['import { defineConfig } from "drizzle-kit";',"","// PGlite for local dev (no Postgres install needed), Neon for production",'const isPglite = !process.env.DATABASE_URL || process.env.DATABASE_URL === "pglite";',"","export default defineConfig({",' schema: "./db/schema",',' out: "./db/migrations",',' dialect: "postgresql",',' ...(isPglite ? { driver: "pglite", dbCredentials: { url: "./local.pg" } } : { dbCredentials: { url: process.env.DATABASE_URL! } }),',"});",""].join(`
10757
+ `)),E(o,"db/schema/auth.ts",['import { pgTable, text, boolean, timestamp } from "drizzle-orm/pg-core";',"",'export const user = pgTable("user", {',' id: text("id").primaryKey(),',' name: text("name").notNull(),',' email: text("email").notNull().unique(),',' emailVerified: boolean("email_verified").notNull().default(false),',' image: text("image"),',' role: text("role").default("user"),',' banned: boolean("banned").default(false),',' banReason: text("ban_reason"),',' banExpires: timestamp("ban_expires"),',' createdAt: timestamp("created_at").notNull(),',' updatedAt: timestamp("updated_at").notNull(),',"});","",'export const session = pgTable("session", {',' id: text("id").primaryKey(),',' expiresAt: timestamp("expires_at").notNull(),',' token: text("token").notNull().unique(),',' createdAt: timestamp("created_at").notNull(),',' updatedAt: timestamp("updated_at").notNull(),',' ipAddress: text("ip_address"),',' userAgent: text("user_agent"),',' userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),',' impersonatedBy: text("impersonated_by"),',"});","",'export const account = pgTable("account", {',' id: text("id").primaryKey(),',' accountId: text("account_id").notNull(),',' providerId: text("provider_id").notNull(),',' userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),',' accessToken: text("access_token"),',' refreshToken: text("refresh_token"),',' idToken: text("id_token"),',' accessTokenExpiresAt: timestamp("access_token_expires_at"),',' refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),',' scope: text("scope"),',' password: text("password"),',' createdAt: timestamp("created_at").notNull(),',' updatedAt: timestamp("updated_at").notNull(),',"});","",'export const verification = pgTable("verification", {',' id: text("id").primaryKey(),',' identifier: text("identifier").notNull(),',' value: text("value").notNull(),',' expiresAt: timestamp("expires_at").notNull(),',' createdAt: timestamp("created_at"),',' updatedAt: timestamp("updated_at"),',"});",""].join(`
10758
+ `)),E(o,"lib/auth.ts",['import { betterAuth } from "better-auth";','import { drizzleAdapter } from "better-auth/adapters/drizzle";','import { admin } from "better-auth/plugins/admin";','import { db } from "./db";','import * as schema from "@/db";',"",'const baseURL = process.env.BETTER_AUTH_URL || process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";',"","async function sendEmail({ to, subject, html }: { to: string; subject: string; html: string }) {"," const apiKey = process.env.RESEND_API_KEY;"," if (!apiKey) {",' console.log(`\\n\u{1F4E7} [Dev] Email to ${to}:\\n Subject: ${subject}\\n ${html.match(/href="([^"]+)"/)?.[1] ?? "(no link found)"}\\n`);'," return;"," }",' const from = process.env.EMAIL_FROM || "noreply@mail.mistflow.app";',' const res = await fetch("https://api.resend.com/emails", {',' method: "POST",',' headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },'," body: JSON.stringify({ from, to, subject, html }),"," });"," if (!res.ok) {",' console.error(`Email send failed (${res.status}): ${await res.text().catch(() => "unknown")}`);'," }","}","","export const auth = betterAuth({"," baseURL,"," trustedOrigins: [baseURL],",' database: drizzleAdapter(db, { provider: "pg", schema }),'," emailAndPassword: {"," enabled: true,",' requireEmailVerification: process.env.NODE_ENV === "production",'," sendResetPassword: async ({ user, url }: { user: { email: string; name: string }; url: string }) => {"," await sendEmail({"," to: user.email,",' subject: "Reset your password",',' html: `<p>Hi ${user.name},</p><p>Click the link below to reset your password:</p><p><a href="${url}">${url}</a></p>`,'," });"," },"," },"," emailVerification: {"," sendOnSignUp: true,"," sendVerificationEmail: async ({ user, url }: { user: { email: string; name: string }; url: string }) => {"," await sendEmail({"," to: user.email,",' subject: "Verify your email address",',' html: `<p>Hi ${user.name},</p><p>Click the link below to verify your email:</p><p><a href="${url}">${url}</a></p>`,'," });"," },"," },"," secret: process.env.AUTH_SECRET,",' plugins: [admin({ defaultRole: "user" })],'," socialProviders: {"," ...(process.env.GOOGLE_CLIENT_ID ? {"," google: {"," clientId: process.env.GOOGLE_CLIENT_ID,"," clientSecret: process.env.GOOGLE_CLIENT_SECRET!,"," },"," } : {}),"," ...(process.env.GITHUB_CLIENT_ID ? {"," github: {"," clientId: process.env.GITHUB_CLIENT_ID,"," clientSecret: process.env.GITHUB_CLIENT_SECRET!,"," },"," } : {}),"," },","});",""].join(`
10759
+ `)))}else E(o,"package.json",JSON.stringify({name:e,version:"0.1.0",private:!0},null,2));E(o,"app/globals.css",fn(i,s)),E(o,"app/layout.tsx",wn(e,i,m?.language)),E(o,"README.md",Mn(e,t,{hasStripe:l,hasResend:d,hasStorage:u,hasAdmin:p,hasAI:h,isNeon:f}));let g=[],w=t?.publicPages;if(Array.isArray(w))g=w;else if(typeof w=="string"){try{g=JSON.parse(w)}catch{g=[]}Array.isArray(g)||(g=[])}if(!g.includes("/")){let y=t?.steps?.some(R=>{let B=((R.name??"")+" "+(R.description??"")).toLowerCase();return B.includes("landing")||B.includes("marketing")||B.includes("homepage")}),k=t?.pages?.some(R=>R.path==="/");(y||k)&&(g=["/",...g])}let P={name:e,summary:t?.summary,authModel:t?.authModel,roles:t?.roles,defaultRole:t?.defaultRole,publicPages:g,navStyle:t?.navStyle,multiTenant:t?.multiTenant,pages:t?.pages,dataModel:t?.dataModel,design:t?.design},D=kn(P);D&&E(o,"middleware.ts",D);let S=Sn(P);S&&E(o,S.path,S.content);let U=Cn(P);if(U&&E(o,"lib/roles.ts",U),E(o,"app/page.tsx",Tn(P)),E(o,"app/(dashboard)/layout.tsx",Pn(P,p)),E(o,"app/(dashboard)/dashboard/page.tsx",Bn(P)),P.multiTenant){let y=Dn(P,f);y&&E(o,"db/schema/organization.ts",y);let k=In(P);k&&E(o,"lib/org.ts",k);let R=An(P);R&&E(o,"components/org-switcher.tsx",R)}E(o,"tsconfig.json",JSON.stringify({compilerOptions:{target:"ES2017",lib:["dom","dom.iterable","esnext"],allowJs:!0,skipLibCheck:!0,strict:!0,noEmit:!0,esModuleInterop:!0,module:"esnext",moduleResolution:"bundler",resolveJsonModule:!0,isolatedModules:!0,jsx:"preserve",incremental:!0,plugins:[{name:"next"}],paths:{"@/*":["./*"]}},include:["next-env.d.ts","**/*.ts","**/*.tsx",".next/types/**/*.ts"],exclude:["node_modules"]},null,2)),l&&E(o,"lib/stripe.ts",['import Stripe from "stripe";',"","let _stripe: Stripe | null = null;","","function getStripe(): Stripe {"," if (!_stripe) {"," if (!process.env.STRIPE_SECRET_KEY) {",' throw new Error("STRIPE_SECRET_KEY is not set");'," }"," _stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {"," typescript: true,"," });"," }"," return _stripe;","}","","// Lazy proxy \u2014 Stripe isn't initialized at import/build time","export const stripe = new Proxy({} as Stripe, {"," get(_target, prop) {"," return (getStripe() as unknown as Record<string | symbol, unknown>)[prop];"," },","});",""].join(`
10760
+ `)),d&&(E(o,"lib/resend.ts",['import { Resend } from "resend";',"","let _resend: Resend | null = null;","","function getResend(): Resend {"," if (!_resend) {"," if (!process.env.RESEND_API_KEY) {",' throw new Error("RESEND_API_KEY is not set");'," }"," _resend = new Resend(process.env.RESEND_API_KEY);"," }"," return _resend;","}","","// Lazy proxy \u2014 Resend isn't initialized at import/build time","export const resend = new Proxy({} as Resend, {"," get(_target, prop) {"," return (getResend() as unknown as Record<string | symbol, unknown>)[prop];"," },","});",""].join(`
10761
+ `)),E(o,"lib/email.ts",['import { resend } from "./resend";',"",'const FROM = process.env.EMAIL_FROM ?? "onboarding@resend.dev";',"","export async function sendEmail({"," to,"," subject,"," react,","}: {"," to: string;"," subject: string;"," react: React.ReactElement;","}) {"," return resend.emails.send({ from: FROM, to, subject, react });","}",""].join(`
10762
+ `))),u&&(E(o,"lib/storage.ts",['const MISTFLOW_API = process.env.MISTFLOW_API_URL ?? "https://api.mistflow.ai";',"const MISTFLOW_API_KEY = process.env.MISTFLOW_API_KEY;","const PROJECT_ID = process.env.MISTFLOW_PROJECT_ID;","","interface UploadResult {"," upload_url: string;"," download_url: string;"," key: string;","}","","function authHeaders(): Record<string, string> {"," return {",' "Content-Type": "application/json",',' "Authorization": `ApiKey ${MISTFLOW_API_KEY}`,'," };","}","",'export async function getUploadUrl(filename: string, contentType: string = "application/octet-stream"): Promise<UploadResult> {'," const res = await fetch(`${MISTFLOW_API}/api/storage/upload-url`, {",' method: "POST",'," headers: authHeaders(),"," body: JSON.stringify({ project_id: PROJECT_ID, filename, content_type: contentType }),"," });"," if (!res.ok) throw new Error(`Storage error: ${res.status}`);"," return res.json();","}","","export async function getDownloadUrl(filename: string): Promise<string> {"," const res = await fetch(`${MISTFLOW_API}/api/storage/download-url`, {",' method: "POST",'," headers: authHeaders(),"," body: JSON.stringify({ project_id: PROJECT_ID, filename }),"," });"," if (!res.ok) throw new Error(`Storage error: ${res.status}`);"," const data = await res.json();"," return data.download_url;","}","","export async function deleteFile(filename: string): Promise<void> {"," await fetch(`${MISTFLOW_API}/api/storage/delete`, {",' method: "POST",'," headers: authHeaders(),"," body: JSON.stringify({ project_id: PROJECT_ID, filename }),"," });","}","","export async function uploadFile(file: File): Promise<string> {"," const { upload_url, download_url } = await getUploadUrl(file.name, file.type);",' await fetch(upload_url, { method: "PUT", body: file, headers: { "Content-Type": file.type } });'," return download_url;","}",""].join(`
10763
+ `)),E(o,"app/api/upload/route.ts",['import { NextRequest, NextResponse } from "next/server";','import { getUploadUrl } from "@/lib/storage";',"","export async function POST(req: NextRequest) {"," const { filename, contentType } = await req.json();"," if (!filename) {",' return NextResponse.json({ error: "filename is required" }, { status: 400 });'," }"," try {",' const result = await getUploadUrl(filename, contentType ?? "application/octet-stream");'," return NextResponse.json(result);"," } catch {",' return NextResponse.json({ error: "Failed to get upload URL" }, { status: 500 });'," }","}",""].join(`
10764
+ `))),h&&(E(o,"lib/ai.ts",['import { createOpenAI } from "@ai-sdk/openai";',"","export const openai = createOpenAI({"," apiKey: process.env.OPENAI_API_KEY,","});",""].join(`
10765
+ `)),E(o,"app/api/chat/route.ts",['import { openai } from "@/lib/ai";','import { streamText } from "ai";',"","export async function POST(req: Request) {"," const { messages } = await req.json();",""," const result = streamText({",' model: openai("gpt-4o"),'," messages,"," });",""," return result.toDataStreamResponse();","}",""].join(`
10766
+ `)));let ne={name:e,methodologyVersion:b?.version??"1.0",createdAt:new Date().toISOString(),...n?{planId:n}:{},plan:Array.isArray(t?.steps)?{...t,steps:t.steps.map(y=>({number:y.number,name:y.name??y.title,description:y.description,entities:y.entities,pages:y.pages,features:y.features,status:"pending"}))}:t,dbProvider:"neon",env:{managed:{DATABASE_URL:{description:"Postgres connection URL",scope:"production"},AUTH_SECRET:{description:"Auth encryption secret",scope:"production"},...l?{STRIPE_SECRET_KEY:{description:"Stripe secret key",scope:"production"},STRIPE_WEBHOOK_SECRET:{description:"Stripe webhook signing secret",scope:"production"},NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:{description:"Stripe publishable key",scope:"production"}}:{},...d?{RESEND_API_KEY:{description:"Resend API key \u2014 managed by Mistflow by default, override with your own key from resend.com",scope:"production"},EMAIL_FROM:{description:"Sender email address \u2014 managed by Mistflow by default",scope:"production"}}:{},...u?{MISTFLOW_API_KEY:{description:"Mistflow API key for file storage",scope:"production"},MISTFLOW_PROJECT_ID:{description:"Mistflow project ID",scope:"production"}}:{}},...h?{required:{OPENAI_API_KEY:{description:"OpenAI API key",setupUrl:"https://platform.openai.com/api-keys"}}}:{}},authModel:t?.authModel??"email",roles:t?.roles??null,navStyle:t?.navStyle??"sidebar",multiTenant:t?.multiTenant??!1,hasAdmin:p,hasResend:d,hasStorage:u,hasAI:h,deploy:null};E(o,"mistflow.json",JSON.stringify(ne,null,2));let G=pn(32).toString("hex"),J=l?`
12336
10767
  # Stripe
12337
10768
  STRIPE_SECRET_KEY=
12338
10769
  STRIPE_WEBHOOK_SECRET=
12339
10770
  NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
12340
10771
  NEXT_PUBLIC_APP_URL=http://localhost:3000
12341
- `:"",j=s?`
10772
+ `:"",ee=d?`
12342
10773
  # Email (Resend)
12343
10774
  RESEND_API_KEY=
12344
10775
  EMAIL_FROM=onboarding@resend.dev
12345
- `:"",J=d?`
10776
+ `:"",q=u?`
12346
10777
  # File Storage (Mistflow managed)
12347
10778
  MISTFLOW_API_KEY=
12348
10779
  MISTFLOW_PROJECT_ID=
12349
- `:"",G=u?`
10780
+ `:"",Y=h?`
12350
10781
  # AI (get your key at https://platform.openai.com/api-keys)
12351
10782
  OPENAI_API_KEY=
12352
- `:"",V=`# Local dev: PGlite is used automatically (zero-install embedded Postgres)
10783
+ `:"",le=`# Local dev: PGlite is used automatically (zero-install embedded Postgres)
12353
10784
  # Set DATABASE_URL only for production or to use a remote Postgres
12354
- # DATABASE_URL=postgresql://postgres:postgres@localhost:5432/devdb`,ie=`# Local dev: PGlite is used automatically (zero-install embedded Postgres)
10785
+ # DATABASE_URL=postgresql://postgres:postgres@localhost:5432/devdb`,F=`# Local dev: PGlite is used automatically (zero-install embedded Postgres)
12355
10786
  # Set DATABASE_URL only for production or to use a remote Postgres
12356
- # DATABASE_URL=postgresql://postgres:postgres@localhost:5432/devdb`;H(o,".env.local",`${V}
12357
- AUTH_SECRET=${U}
12358
- ${E}${j}${J}${G}`),H(o,".env.example",`${ie}
10787
+ # DATABASE_URL=postgresql://postgres:postgres@localhost:5432/devdb`;E(o,".env.local",`${le}
10788
+ AUTH_SECRET=${G}
10789
+ ${J}${ee}${q}${Y}`),E(o,".env.example",`${F}
12359
10790
  AUTH_SECRET=your-secret-here
12360
- ${E}${j}${J}${G}`);let A=[],q=(T,C)=>{A.push({phase:T,message:C})},oe=(T,C)=>{let L=A.find(x=>x.phase===T&&!x.durationMs);L&&(L.durationMs=C)};q("install","Installing packages...");let Ne=Date.now(),xe=0,ne=await Me("npm",["install"],o,12e4,T=>{let C=T.match(/added (\d+) packages/);C&&(xe=parseInt(C[1],10))});if(ne.success||(console.error("[init] npm install failed, retrying..."),ne=await Me("npm",["install"],o,12e4,T=>{let C=T.match(/added (\d+) packages/);C&&(xe=parseInt(C[1],10))})),!ne.success)return c(`Project files were created at ${o} but package installation failed after 2 attempts: ${ne.error}. Run "npm install" manually to retry.`,!0);oe("install",Date.now()-Ne),A[A.length-1].message=`Installed ${xe||"all"} packages`;let Z=b?.shadcnComponents??["button","card","input","label","form","dialog","table","dropdown-menu","badge","separator","skeleton","sheet","tabs","avatar","select","textarea","checkbox","switch","tooltip","popover","sonner"];q("ui",`Adding ${Z.length} UI components...`);let P=Date.now(),I=await Me("npx",["--yes","shadcn@latest","add","-y","-o",...Z],o,12e4);if(I.success||(console.error("[init] shadcn install failed, retrying..."),I=await Me("npx",["--yes","shadcn@latest","add","-y","-o",...Z],o,12e4)),I.success)A[A.length-1].message=`Added ${Z.length} UI components (Button, Card, Dialog, Table, ...)`;else return c(`Project created at ${o} but UI component installation failed after 2 attempts: ${I.error}. Run "npx shadcn@latest add -y -o ${Z.join(" ")}" manually to retry.`,!0);oe("ui",Date.now()-P),q("db","Setting up database...");let M=Date.now(),ee,D=await Me("npx",["drizzle-kit","push"],o,3e4);D.success?A[A.length-1].message="Database ready":(console.error("DB push failed:",D.error),ee="Database setup failed \u2014 login won't work yet. Try deploying again. If it keeps failing, contact support.",A[A.length-1].message=m?"Database setup skipped (configure DATABASE_URL to enable)":"Database setup skipped (configure TURSO_URL to enable)"),oe("db",Date.now()-M),q("git","Initializing git repository...");let z=Date.now();try{let T=Sr(o);await T.init(),await T.add("."),await T.commit("Initial Mistflow project setup"),A[A.length-1].message="Git repository initialized"}catch{console.error("Git initialization failed, continuing without git."),A[A.length-1].message="Git init skipped"}oe("git",Date.now()-z);let v=h?.requestedSubdomain||void 0,S,w;try{let T=await ht(e,void 0,"neon",v);S=T.id;let C=X(o,"mistflow.json"),L=JSON.parse(kt(C,"utf-8"));if(L.projectId=S,De(C,JSON.stringify(L,null,2)),T.managed_env&&Object.keys(T.managed_env).length>0){let x=X(o,".env.local"),W=Se(x)?kt(x,"utf-8"):"";for(let[F,ye]of Object.entries(T.managed_env)){let se=new RegExp(`^${F}=.*$`,"m");se.test(W)?W=W.replace(se,`${F}=${ye}`):W+=`
12361
- ${F}=${ye}`}De(x,W)}if(S)try{let{getBaseUrl:x,getAuthHeaders:W}=await import("./api-client-CE7LYEXJ.js"),F=W(),ye=t?.features,se={};Array.isArray(ye)&&ye.length>0&&(se.features=ye.map(ue=>ue.name)),t&&(se.plan=t),Object.keys(se).length>0&&await fetch(`${x()}/api/projects/${encodeURIComponent(S)}/state`,{method:"PUT",headers:{...F,"Content-Type":"application/json"},body:JSON.stringify(se)})}catch{}}catch(T){let C=T instanceof Error?T.message:String(T);console.error("Could not register project on backend:",C),w=`Project created locally but NOT registered on Mistflow servers (${C}). Deploy will auto-register it.`}let B=A.reduce((T,C)=>T+(C.durationMs??0),0),_={projectPath:o,projectId:S},K=A.map(T=>{let C=T.durationMs?` (${(T.durationMs/1e3).toFixed(1)}s)`:"";return`${T.message}${C}`});_.progress=K,_.totalSetupTime=`${(B/1e3).toFixed(1)}s`;let Q=[];return ee&&Q.push(ee),S||Q.push("Project was not registered with Mistflow (not signed in). Run mist_setup to sign in BEFORE deploying \u2014 deploy will fail without it."),w&&(_.registrationWarning=w),Q.length>0&&(_.warnings=Q),S?_.nextAction="NEXT: Call mist_build with action='implement' to start building the first plan step. Do this immediately \u2014 do NOT start a dev server or suggest localhost.":_.nextAction="NEXT: Call mist_build with action='implement' to start building the first plan step. IMPORTANT: You MUST run mist_setup to sign in before deploying \u2014 the project could not be registered because auth is missing.",c(JSON.stringify(_))}async function Cr(r){let{name:e,plan:t,projectId:a,sourceDeploymentId:n,forkToken:o,requiredEnvVars:i,dbProvider:l,planId:s}=r,d=aa(r.path??`./${e}`);if(Se(d))return c(`A project already exists at this location (${d}). Choose a different name, or delete the existing folder first.`,!0);let{mkdtempSync:p,renameSync:u,rmSync:h,cpSync:m}=await import("fs"),{tmpdir:b}=await import("os"),f=p(X(b(),"mistflow-fork-")),g=X(f,"project");vt(g,{recursive:!0});let y=[],N=(k,$)=>y.push({phase:k,message:$}),R=(k,$)=>{let U=y.find(E=>E.phase===k);U&&(U.durationMs=$)};try{N("download","Downloading source code from template...");let k=Date.now(),$=X(f,"source.tar.gz");try{await Ya(n,o,$)}catch(D){h(f,{recursive:!0,force:!0});let z=D instanceof Error?D.message:"Source download failed";return c(`Source code download failed: ${z}. You can still build from the plan \u2014 run mist_build init without the source (omit planId and pass the plan directly).`,!0)}R("download",Date.now()-k),y[y.length-1].message="Source code downloaded",N("extract","Extracting source code...");let U=Date.now(),E=await Me("tar",["-xzf",$,"-C",g,"--exclude","node_modules","--exclude",".git"],g,6e4);if(!E.success)return h(f,{recursive:!0,force:!0}),c(`Failed to extract source archive: ${E.error}`,!0);if(R("extract",Date.now()-U),!Se(X(g,"package.json")))return h(f,{recursive:!0,force:!0}),c("Source archive does not contain a package.json. The template may be corrupted.",!0);let j=[".mistflow",".env.local",".env.example","local.db","local.pg"];for(let D of j){let z=X(g,D);Se(z)&&h(z,{recursive:!0,force:!0})}let J={name:e,projectId:a,template:"nextjs",createdAt:new Date().toISOString(),planId:s??void 0,plan:t,dbProvider:l};De(X(g,"mistflow.json"),JSON.stringify(J,null,2));let G=i.map(D=>{let z=D.description?`# ${D.description}`:`# ${D.key}`,v=D.setup_url?` (${D.setup_url})`:"";return`${z}${v}
12362
- ${D.key}=`});De(X(g,".env.local"),G.join(`
10791
+ ${J}${ee}${q}${Y}`);let N=[],oe=(y,k)=>{N.push({phase:y,message:k})},ye=(y,k)=>{let R=N.find(B=>B.phase===y&&!B.durationMs);R&&(R.durationMs=k)};oe("install","Installing packages...");let Ce=Date.now(),de=0,Q=await Ae("npm",["install"],o,12e4,y=>{let k=y.match(/added (\d+) packages/);k&&(de=parseInt(k[1],10))});if(Q.success||(console.error("[init] npm install failed, retrying..."),Q=await Ae("npm",["install"],o,12e4,y=>{let k=y.match(/added (\d+) packages/);k&&(de=parseInt(k[1],10))})),!Q.success)return c(`Project files were created at ${o} but package installation failed after 2 attempts: ${Q.error}. Run "npm install" manually to retry.`,!0);ye("install",Date.now()-Ce),N[N.length-1].message=`Installed ${de||"all"} packages`;let T=b?.shadcnComponents??["button","card","input","label","form","dialog","table","dropdown-menu","badge","separator","skeleton","sheet","tabs","avatar","select","textarea","checkbox","switch","tooltip","popover","sonner"];oe("ui",`Adding ${T.length} UI components...`);let A=Date.now(),M=await Ae("npx",["--yes","shadcn@latest","add","-y","-o",...T],o,12e4);if(M.success||(console.error("[init] shadcn install failed, retrying..."),M=await Ae("npx",["--yes","shadcn@latest","add","-y","-o",...T],o,12e4)),M.success)N[N.length-1].message=`Added ${T.length} UI components (Button, Card, Dialog, Table, ...)`;else return c(`Project created at ${o} but UI component installation failed after 2 attempts: ${M.error}. Run "npx shadcn@latest add -y -o ${T.join(" ")}" manually to retry.`,!0);ye("ui",Date.now()-A),oe("db","Setting up database...");let v=Date.now(),x,C=await Ae("npx",["drizzle-kit","push"],o,3e4);C.success?N[N.length-1].message="Database ready":(console.error("DB push failed:",C.error),x="Database setup failed \u2014 login won't work yet. Try deploying again. If it keeps failing, contact support.",N[N.length-1].message=f?"Database setup skipped (configure DATABASE_URL to enable)":"Database setup skipped (configure TURSO_URL to enable)"),ye("db",Date.now()-v),oe("git","Initializing git repository...");let I=Date.now();try{let y=Pr(o);await y.init(),await y.add("."),await y.commit("Initial Mistflow project setup"),N[N.length-1].message="Git repository initialized"}catch{console.error("Git initialization failed, continuing without git."),N[N.length-1].message="Git init skipped"}ye("git",Date.now()-I);let j=m?.requestedSubdomain||void 0,H,$;try{let y=await gt(e,void 0,"neon",j);H=y.id;let k=z(o,"mistflow.json"),R=JSON.parse(kt(k,"utf-8"));if(R.projectId=H,Ie(k,JSON.stringify(R,null,2)),y.managed_env&&Object.keys(y.managed_env).length>0){let B=z(o,".env.local"),L=ve(B)?kt(B,"utf-8"):"";for(let[ue,Ne]of Object.entries(y.managed_env)){let K=new RegExp(`^${ue}=.*$`,"m");K.test(L)?L=L.replace(K,`${ue}=${Ne}`):L+=`
10792
+ ${ue}=${Ne}`}Ie(B,L)}if(H)try{let{getBaseUrl:B,getAuthHeaders:L}=await import("./api-client-WMD2JG5B.js"),ue=L(),Ne=t?.features,K={};Array.isArray(Ne)&&Ne.length>0&&(K.features=Ne.map(Ot=>Ot.name)),t&&(K.plan=t),Object.keys(K).length>0&&await fetch(`${B()}/api/projects/${encodeURIComponent(H)}/state`,{method:"PUT",headers:{...ue,"Content-Type":"application/json"},body:JSON.stringify(K)})}catch{}}catch(y){let k=y instanceof Error?y.message:String(y);console.error("Could not register project on backend:",k),$=`Project created locally but NOT registered on Mistflow servers (${k}). Deploy will auto-register it.`}let he=N.reduce((y,k)=>y+(k.durationMs??0),0),te={projectPath:o,projectId:H},ae=N.map(y=>{let k=y.durationMs?` (${(y.durationMs/1e3).toFixed(1)}s)`:"";return`${y.message}${k}`});te.progress=ae,te.totalSetupTime=`${(he/1e3).toFixed(1)}s`;let V=[];return x&&V.push(x),H||V.push("Project was not registered with Mistflow (not signed in). Run mist_setup to sign in BEFORE deploying \u2014 deploy will fail without it."),$&&(te.registrationWarning=$),V.length>0&&(te.warnings=V),H?te.nextAction="NEXT: Call mist_build with action='implement' to start building the first plan step. Do this immediately \u2014 do NOT start a dev server or suggest localhost.":te.nextAction="NEXT: Call mist_build with action='implement' to start building the first plan step. IMPORTANT: You MUST run mist_setup to sign in before deploying \u2014 the project could not be registered because auth is missing.",c(JSON.stringify(te))}async function Ar(r){let{name:e,plan:t,projectId:a,sourceDeploymentId:n,forkToken:o,requiredEnvVars:i,dbProvider:s,planId:l}=r,d=ia(r.path??`./${e}`);if(ve(d))return c(`A project already exists at this location (${d}). Choose a different name, or delete the existing folder first.`,!0);let{mkdtempSync:u,renameSync:p,rmSync:h,cpSync:m}=await import("fs"),{tmpdir:f}=await import("os"),b=u(z(f(),"mistflow-fork-")),g=z(b,"project");vt(g,{recursive:!0});let w=[],P=(S,U)=>w.push({phase:S,message:U}),D=(S,U)=>{let ne=w.find(G=>G.phase===S);ne&&(ne.durationMs=U)};try{P("download","Downloading source code from template...");let S=Date.now(),U=z(b,"source.tar.gz");try{await Xa(n,o,U)}catch(x){h(b,{recursive:!0,force:!0});let C=x instanceof Error?x.message:"Source download failed";return c(`Source code download failed: ${C}. You can still build from the plan \u2014 run mist_build init without the source (omit planId and pass the plan directly).`,!0)}D("download",Date.now()-S),w[w.length-1].message="Source code downloaded",P("extract","Extracting source code...");let ne=Date.now(),G=await Ae("tar",["-xzf",U,"-C",g,"--exclude","node_modules","--exclude",".git"],g,6e4);if(!G.success)return h(b,{recursive:!0,force:!0}),c(`Failed to extract source archive: ${G.error}`,!0);if(D("extract",Date.now()-ne),!ve(z(g,"package.json")))return h(b,{recursive:!0,force:!0}),c("Source archive does not contain a package.json. The template may be corrupted.",!0);let J=[".mistflow",".env.local",".env.example","local.db","local.pg"];for(let x of J){let C=z(g,x);ve(C)&&h(C,{recursive:!0,force:!0})}let ee={name:e,projectId:a,template:"nextjs",createdAt:new Date().toISOString(),planId:l??void 0,plan:t,dbProvider:s};Ie(z(g,"mistflow.json"),JSON.stringify(ee,null,2));let q=i.map(x=>{let C=x.description?`# ${x.description}`:`# ${x.key}`,I=x.setup_url?` (${x.setup_url})`:"";return`${C}${I}
10793
+ ${x.key}=`});Ie(z(g,".env.local"),q.join(`
12363
10794
 
12364
10795
  `)+`
12365
- `);let V=i.map(D=>`${D.key}=`);De(X(g,".env.example"),V.join(`
10796
+ `);let Y=i.map(x=>`${x.key}=`);Ie(z(g,".env.example"),Y.join(`
12366
10797
  `)+`
12367
- `),De(X(g,"README.md"),`# ${e}
10798
+ `),Ie(z(g,"README.md"),`# ${e}
12368
10799
 
12369
10800
  Forked from a Mistflow template. Built with Next.js, Drizzle ORM, and Better Auth.
12370
10801
 
@@ -12373,21 +10804,21 @@ Forked from a Mistflow template. Built with Next.js, Drizzle ORM, and Better Aut
12373
10804
  1. Copy \`.env.example\` to \`.env.local\` and fill in your values
12374
10805
  2. Run \`npm run dev\`
12375
10806
  3. Deploy with \`mist_deploy\`
12376
- `),N("setup","Setting up project directory...");let ie=Date.now();try{u(g,d)}catch(D){if(D.code==="EXDEV")m(g,d,{recursive:!0}),h(g,{recursive:!0,force:!0});else throw D}R("setup",Date.now()-ie),N("install","Installing packages...");let A=Date.now(),q=0,oe=await Me("npm",["install"],d,12e4,D=>{let z=D.match(/added (\d+) packages/);z&&(q=parseInt(z[1],10))});if(oe.success||(console.error("[initFromSource] npm install failed, retrying..."),oe=await Me("npm",["install"],d,12e4,D=>{let z=D.match(/added (\d+) packages/);z&&(q=parseInt(z[1],10))})),!oe.success)return c(`Source code was restored at ${d} but package installation failed: ${oe.error}. Run "npm install" manually.`,!0);R("install",Date.now()-A),y[y.length-1].message=`Installed ${q||"all"} packages`,N("git","Initializing git repository...");let Ne=Date.now();try{let D=Sr(d);await D.init(),await D.add("."),await D.commit("Forked from Mistflow template"),y[y.length-1].message="Git repository initialized"}catch{console.error("Git initialization failed, continuing without git."),y[y.length-1].message="Git init skipped"}R("git",Date.now()-Ne);try{let{markLocalSetupDone:D}=await import("./api-client-CE7LYEXJ.js");await D(a)}catch{console.error("[initFromSource] Could not mark local_setup_done on backend, continuing.")}let xe=JSON.parse(kt(X(d,"mistflow.json"),"utf-8"));xe.projectId=a,De(X(d,"mistflow.json"),JSON.stringify(xe,null,2));let ne=t.steps,Z=ne?.filter(D=>D.status==="completed").length??0,P=ne?.filter(D=>D.status==="pending").length??0,I=ne?.length??0,M=i.length>0?`
10807
+ `),P("setup","Setting up project directory...");let le=Date.now();try{p(g,d)}catch(x){if(x.code==="EXDEV")m(g,d,{recursive:!0}),h(g,{recursive:!0,force:!0});else throw x}D("setup",Date.now()-le),P("install","Installing packages...");let F=Date.now(),N=0,oe=await Ae("npm",["install"],d,12e4,x=>{let C=x.match(/added (\d+) packages/);C&&(N=parseInt(C[1],10))});if(oe.success||(console.error("[initFromSource] npm install failed, retrying..."),oe=await Ae("npm",["install"],d,12e4,x=>{let C=x.match(/added (\d+) packages/);C&&(N=parseInt(C[1],10))})),!oe.success)return c(`Source code was restored at ${d} but package installation failed: ${oe.error}. Run "npm install" manually.`,!0);D("install",Date.now()-F),w[w.length-1].message=`Installed ${N||"all"} packages`,P("git","Initializing git repository...");let ye=Date.now();try{let x=Pr(d);await x.init(),await x.add("."),await x.commit("Forked from Mistflow template"),w[w.length-1].message="Git repository initialized"}catch{console.error("Git initialization failed, continuing without git."),w[w.length-1].message="Git init skipped"}D("git",Date.now()-ye);try{let{markLocalSetupDone:x}=await import("./api-client-WMD2JG5B.js");await x(a)}catch{console.error("[initFromSource] Could not mark local_setup_done on backend, continuing.")}let Ce=JSON.parse(kt(z(d,"mistflow.json"),"utf-8"));Ce.projectId=a,Ie(z(d,"mistflow.json"),JSON.stringify(Ce,null,2));let de=t.steps,Q=de?.filter(x=>x.status==="completed").length??0,T=de?.filter(x=>x.status==="pending").length??0,A=de?.length??0,M=i.length>0?`
12377
10808
 
12378
10809
  Environment variables needed:
12379
- `+i.map(D=>` \u2022 ${D.key}${D.description?` \u2014 ${D.description}`:""}`).join(`
12380
- `):"",ee=P>0?`Source code restored with ${Z}/${I} steps complete. ${P} steps need implementation \u2014 call mist_build with action='implement' to apply your changes.`:`Source code fully restored (${I} steps complete). Configure your .env.local, then deploy with mist_deploy.`;return c(JSON.stringify({status:"success",projectPath:d,projectId:a,planStepsCompleted:Z,planStepsTotal:I,pendingSteps:P,progress:y,nextAction:ee+M}))}finally{try{h(f,{recursive:!0,force:!0})}catch{}}}import{z as na}from"zod";import{existsSync as sa,readFileSync as Fr,writeFileSync as la,mkdirSync as Mo}from"fs";import{join as Tt,resolve as Ro,dirname as Lo}from"path";import{createConnection as Fo}from"net";import{existsSync as St,mkdirSync as Br,readFileSync as Ir,readdirSync as Ar,writeFileSync as Co}from"fs";import{join as Je,resolve as Po}from"path";import{homedir as oa}from"os";function Ke(r){return r.entity??r.name??"Unknown"}function Ge(r){return typeof r=="string"?r:r.name}function ia(r){return typeof r=="string"?"text":r.type}function Pr(r){let e=r.fields||[],t=[];for(let a=0;a<3;a++){let n={};for(let o of e)n[Ge(o)]=Bo(Ge(o),ia(o),Ke(r),a);t.push(n)}return t}function Bo(r,e,t,a){let n=r.toLowerCase(),o=(e||"text").toLowerCase();return n==="name"||n==="title"?[`${t} Alpha`,`${t} Beta`,`${t} Gamma`][a]:n==="email"?["alice@example.com","bob@example.com","carol@example.com"][a]:n==="status"?["Active","Pending","Completed"][a]:n==="priority"?["High","Medium","Low"][a]:n.includes("date")||o==="date"?["Jan 15, 2024","Feb 20, 2024","Mar 10, 2024"][a]:n.includes("price")||n.includes("amount")||n.includes("cost")?["$29","$49","$99"][a]:n.includes("count")||n.includes("quantity")||o==="number"||o==="integer"?["12","34","56"][a]:o==="boolean"||o==="bool"?["Yes","No","Yes"][a]:n.includes("description")||o==="textarea"?["Brief description here","Another example entry","Third sample item"][a]:[`Sample ${a+1}`][0]}function Io(r){let e=r.dataModel??[],t=r.pages??[],a=r.design??{},n=t.map(u=>({label:u.name??u.path??"Page",route:u.path??u.route??"/"})),o=[],i=e.slice(0,3).map(u=>({name:Ke(u),fields:(u.fields||[]).map(h=>({name:Ge(h),type:ia(h)})),sampleData:Pr(u)})),l=[];r.primaryAction&&(l.push(`PRIMARY: ${r.primaryAction.action} \u2014 this is the first thing the user sees and does`),l.push(`SURFACE: ${r.primaryAction.dashboardSurface}`)),l.push(`METRICS: Key counts for ${e.map(u=>Ke(u)).join(", ")}`),l.push("RECENT: Latest activity or items"),o.push({name:"Dashboard",type:"dashboard",route:"/dashboard",purpose:r.primaryAction?`Action surface \u2014 user comes here to ${r.primaryAction.action.toLowerCase()}. Not a stats display.`:`Overview of ${e.map(u=>Ke(u)).join(", ")} with key metrics.`,informationHierarchy:l,interactionStates:["Empty state: new user, no data yet \u2014 show onboarding prompt","Loading state: skeleton placeholders for metrics and table","Populated state: real data with metrics, recent items, quick actions"],entities:i});let s=e[0];if(s){let u=Ke(s),h=u.toLowerCase().endsWith("s")?u:`${u}s`;o.push({name:`${u} List`,type:"detail",route:`/${h.toLowerCase()}`,purpose:`Browse, search, and manage ${h.toLowerCase()}. Create new ${u.toLowerCase()}s.`,informationHierarchy:[`HEADER: "${h}" title + "Add ${u}" button`,"SEARCH: Filter/search bar \u2014 users will have many items",`TABLE: ${(s.fields||[]).slice(0,5).map(m=>Ge(m)).join(", ")} columns`,"ROW ACTIONS: Edit, delete on each row"],interactionStates:[`Empty state: "No ${h.toLowerCase()} yet" with create CTA`,"Loading state: skeleton table rows",`Search with no results: "No ${h.toLowerCase()} matching..." with clear filter`],entities:[{name:u,fields:(s.fields||[]).map(m=>({name:Ge(m),type:ia(m)})),sampleData:Pr(s)}]})}r.steps.some(u=>{let h=`${u.name??u.title??""} ${u.description??""}`.toLowerCase();return h.includes("landing")||h.includes("hero")||h.includes("marketing")||h.includes("homepage")})&&o.push({name:"Landing Page",type:"landing",route:"/",purpose:`Convince visitors to sign up for ${r.name}. Answer: what is this, who is it for, why should I care.`,informationHierarchy:[`HERO: One sentence about what ${r.name} does \u2014 not "Transform your X", be specific`,"CTA: Sign up / Get started \u2014 one clear action","PROOF: What makes this valuable (features, not buzzwords)","SECONDARY CTA: Repeat the sign up prompt"],interactionStates:["Mobile: hero stacks vertically, nav collapses to hamburger","Desktop: hero side-by-side or centered, full nav"],entities:[]});let p=[];for(let u of e.slice(0,3)){let h=Ke(u);(u.fields||[]).find(b=>Ge(b).toLowerCase()==="name"||Ge(b).toLowerCase()==="title")&&p.push(`What if a ${h.toLowerCase()}'s name is 47 characters? Does the layout break?`),p.push(`What if there are 0 ${h.toLowerCase()}s? 1? 500?`)}return r.authModel&&r.authModel!=="none"&&p.push("What does a brand-new user see? (no data, no setup)"),p.push("What if the network is slow? What loads first?"),{appName:r.name,summary:r.summary??"",screens:o,navigation:{style:r.navStyle??"sidebar",items:n},primaryAction:r.primaryAction??null,designDirection:{tone:a.tone??"professional",accentColor:a.accentColor??"blue",navStyle:r.navStyle??"sidebar",fonts:a.fonts??{heading:"Inter",body:"Inter"}},edgeCases:p}}function Ao(r,e){let t=[];t.push(`# Wireframe sketch for ${r.appName}`),t.push(""),t.push(`**${r.appName}** \u2014 ${r.summary}`),t.push(""),e&&(t.push("## Feedback to apply"),t.push(e),t.push("")),t.push("## Design principles"),t.push(""),t.push("Apply these when deciding layout and hierarchy:"),t.push("1. **Information hierarchy** \u2014 What does the user see first, second, third? The primary action is first. Metrics are second. Everything else is supporting."),t.push("2. **Interaction states** \u2014 Every screen has at least: empty, loading, populated. Show the populated state but add HTML comments noting the others."),t.push("3. **Edge case paranoia** \u2014 What if there are 0 items? 500 items? A 47-character name? Think about these and comment where they matter."),t.push(`4. **Subtraction** \u2014 "As little design as possible" (Dieter Rams). Every element earns its pixels. If removing something doesn't hurt, remove it.`),t.push("5. **Design for trust** \u2014 Clear labels, predictable layout, obvious actions. No mystery meat navigation."),t.push(""),t.push("## Wireframe rules (strict)"),t.push(""),t.push("Write a **single self-contained HTML file** saved to `.mistflow/mockups/mockup-{planId}.html` (replace `{planId}` with the actual plan ID)."),t.push(""),t.push("The wireframe must:"),t.push("- Use **system fonts only** (`-apple-system, system-ui, sans-serif`) \u2014 no Google Fonts, no CDN"),t.push("- Use **inline CSS only** \u2014 no external stylesheets, no Tailwind CDN"),t.push("- Look **intentionally rough** \u2014 thin gray borders (#ddd), light backgrounds (#f8f8f8), no color, no shadows"),t.push("- Use **realistic placeholder content** that matches this specific app (sample data provided below) \u2014 NOT lorem ipsum"),t.push("- Include **HTML comments** explaining design decisions (e.g., `<!-- Primary action is prominent because users come here to check in members -->`)"),t.push("- Show **all screens in a single page** using tabs/sections that the user can click through"),t.push("- Be **responsive** \u2014 test that it looks reasonable at both 1200px and 375px widths"),t.push("- Include a small header bar showing: screen name tabs + the design direction summary"),t.push(""),t.push("The wireframe must NOT:"),t.push("- Use any color except grayscale (#333, #666, #999, #ddd, #f8f8f8, white)"),t.push("- Use any external dependencies \u2014 no CDN, no imports, no build step"),t.push("- Look polished \u2014 it should feel like a sketch on a whiteboard, not a finished product"),t.push("- Include decorative elements \u2014 no icons (use text labels), no illustrations, no gradients"),t.push(""),t.push("## Screens to wireframe"),t.push("");for(let a of r.screens){t.push(`### ${a.name} (\`${a.route}\`)`),t.push(`**Purpose**: ${a.purpose}`),t.push(""),t.push("**Information hierarchy** (render in this order, top to bottom):");for(let n of a.informationHierarchy)t.push(`- ${n}`);t.push(""),t.push("**Interaction states** (add HTML comments for non-visible states):");for(let n of a.interactionStates)t.push(`- ${n}`);if(t.push(""),a.entities.length>0){t.push("**Data model and sample content** (use this real data, not lorem ipsum):");for(let n of a.entities)t.push(`
10810
+ `+i.map(x=>` \u2022 ${x.key}${x.description?` \u2014 ${x.description}`:""}`).join(`
10811
+ `):"",v=T>0?`Source code restored with ${Q}/${A} steps complete. ${T} steps need implementation \u2014 call mist_build with action='implement' to apply your changes.`:`Source code fully restored (${A} steps complete). Configure your .env.local, then deploy with mist_deploy.`;return c(JSON.stringify({status:"success",projectPath:d,projectId:a,planStepsCompleted:Q,planStepsTotal:A,pendingSteps:T,progress:w,nextAction:v+M}))}finally{try{h(b,{recursive:!0,force:!0})}catch{}}}import{z as la}from"zod";import{existsSync as da,readFileSync as Gr,writeFileSync as ca,mkdirSync as Hn}from"fs";import{join as Pt,resolve as Gn,dirname as Wn}from"path";import{createConnection as On}from"net";import{existsSync as Tt,mkdirSync as Rr,readFileSync as Lr,readdirSync as Nr,writeFileSync as Rn}from"fs";import{join as Ye,resolve as Ln}from"path";import{homedir as sa}from"os";function Je(r){return r.entity??r.name??"Unknown"}function We(r){return typeof r=="string"?r:r.name}function oa(r){return typeof r=="string"?"text":r.type}function Mr(r){let e=r.fields||[],t=[];for(let a=0;a<3;a++){let n={};for(let o of e)n[We(o)]=Nn(We(o),oa(o),Je(r),a);t.push(n)}return t}function Nn(r,e,t,a){let n=r.toLowerCase(),o=(e||"text").toLowerCase();return n==="name"||n==="title"?[`${t} Alpha`,`${t} Beta`,`${t} Gamma`][a]:n==="email"?["alice@example.com","bob@example.com","carol@example.com"][a]:n==="status"?["Active","Pending","Completed"][a]:n==="priority"?["High","Medium","Low"][a]:n.includes("date")||o==="date"?["Jan 15, 2024","Feb 20, 2024","Mar 10, 2024"][a]:n.includes("price")||n.includes("amount")||n.includes("cost")?["$29","$49","$99"][a]:n.includes("count")||n.includes("quantity")||o==="number"||o==="integer"?["12","34","56"][a]:o==="boolean"||o==="bool"?["Yes","No","Yes"][a]:n.includes("description")||o==="textarea"?["Brief description here","Another example entry","Third sample item"][a]:[`Sample ${a+1}`][0]}function Fn(r){let e=r.dataModel??[],t=r.pages??[],a=r.design??{},n=t.map(p=>({label:p.name??p.path??"Page",route:p.path??p.route??"/"})),o=[],i=e.slice(0,3).map(p=>({name:Je(p),fields:(p.fields||[]).map(h=>({name:We(h),type:oa(h)})),sampleData:Mr(p)})),s=[];r.primaryAction&&(s.push(`PRIMARY: ${r.primaryAction.action} \u2014 this is the first thing the user sees and does`),s.push(`SURFACE: ${r.primaryAction.dashboardSurface}`)),s.push(`METRICS: Key counts for ${e.map(p=>Je(p)).join(", ")}`),s.push("RECENT: Latest activity or items"),o.push({name:"Dashboard",type:"dashboard",route:"/dashboard",purpose:r.primaryAction?`Action surface \u2014 user comes here to ${r.primaryAction.action.toLowerCase()}. Not a stats display.`:`Overview of ${e.map(p=>Je(p)).join(", ")} with key metrics.`,informationHierarchy:s,interactionStates:["Empty state: new user, no data yet \u2014 show onboarding prompt","Loading state: skeleton placeholders for metrics and table","Populated state: real data with metrics, recent items, quick actions"],entities:i});let l=e[0];if(l){let p=Je(l),h=p.toLowerCase().endsWith("s")?p:`${p}s`;o.push({name:`${p} List`,type:"detail",route:`/${h.toLowerCase()}`,purpose:`Browse, search, and manage ${h.toLowerCase()}. Create new ${p.toLowerCase()}s.`,informationHierarchy:[`HEADER: "${h}" title + "Add ${p}" button`,"SEARCH: Filter/search bar \u2014 users will have many items",`TABLE: ${(l.fields||[]).slice(0,5).map(m=>We(m)).join(", ")} columns`,"ROW ACTIONS: Edit, delete on each row"],interactionStates:[`Empty state: "No ${h.toLowerCase()} yet" with create CTA`,"Loading state: skeleton table rows",`Search with no results: "No ${h.toLowerCase()} matching..." with clear filter`],entities:[{name:p,fields:(l.fields||[]).map(m=>({name:We(m),type:oa(m)})),sampleData:Mr(l)}]})}r.steps.some(p=>{let h=`${p.name??p.title??""} ${p.description??""}`.toLowerCase();return h.includes("landing")||h.includes("hero")||h.includes("marketing")||h.includes("homepage")})&&o.push({name:"Landing Page",type:"landing",route:"/",purpose:`Convince visitors to sign up for ${r.name}. Answer: what is this, who is it for, why should I care.`,informationHierarchy:[`HERO: One sentence about what ${r.name} does \u2014 not "Transform your X", be specific`,"CTA: Sign up / Get started \u2014 one clear action","PROOF: What makes this valuable (features, not buzzwords)","SECONDARY CTA: Repeat the sign up prompt"],interactionStates:["Mobile: hero stacks vertically, nav collapses to hamburger","Desktop: hero side-by-side or centered, full nav"],entities:[]});let u=[];for(let p of e.slice(0,3)){let h=Je(p);(p.fields||[]).find(f=>We(f).toLowerCase()==="name"||We(f).toLowerCase()==="title")&&u.push(`What if a ${h.toLowerCase()}'s name is 47 characters? Does the layout break?`),u.push(`What if there are 0 ${h.toLowerCase()}s? 1? 500?`)}return r.authModel&&r.authModel!=="none"&&u.push("What does a brand-new user see? (no data, no setup)"),u.push("What if the network is slow? What loads first?"),{appName:r.name,summary:r.summary??"",screens:o,navigation:{style:r.navStyle??"sidebar",items:n},primaryAction:r.primaryAction??null,designDirection:{tone:a.tone??"professional",accentColor:a.accentColor??"blue",navStyle:r.navStyle??"sidebar",fonts:a.fonts??{heading:"Inter",body:"Inter"}},edgeCases:u}}function En(r,e){let t=[];t.push(`# Wireframe sketch for ${r.appName}`),t.push(""),t.push(`**${r.appName}** \u2014 ${r.summary}`),t.push(""),e&&(t.push("## Feedback to apply"),t.push(e),t.push("")),t.push("## Design principles"),t.push(""),t.push("Apply these when deciding layout and hierarchy:"),t.push("1. **Information hierarchy** \u2014 What does the user see first, second, third? The primary action is first. Metrics are second. Everything else is supporting."),t.push("2. **Interaction states** \u2014 Every screen has at least: empty, loading, populated. Show the populated state but add HTML comments noting the others."),t.push("3. **Edge case paranoia** \u2014 What if there are 0 items? 500 items? A 47-character name? Think about these and comment where they matter."),t.push(`4. **Subtraction** \u2014 "As little design as possible" (Dieter Rams). Every element earns its pixels. If removing something doesn't hurt, remove it.`),t.push("5. **Design for trust** \u2014 Clear labels, predictable layout, obvious actions. No mystery meat navigation."),t.push(""),t.push("## Wireframe rules (strict)"),t.push(""),t.push("Write a **single self-contained HTML file** saved to `.mistflow/mockups/mockup-{planId}.html` (replace `{planId}` with the actual plan ID)."),t.push(""),t.push("The wireframe must:"),t.push("- Use **system fonts only** (`-apple-system, system-ui, sans-serif`) \u2014 no Google Fonts, no CDN"),t.push("- Use **inline CSS only** \u2014 no external stylesheets, no Tailwind CDN"),t.push("- Look **intentionally rough** \u2014 thin gray borders (#ddd), light backgrounds (#f8f8f8), no color, no shadows"),t.push("- Use **realistic placeholder content** that matches this specific app (sample data provided below) \u2014 NOT lorem ipsum"),t.push("- Include **HTML comments** explaining design decisions (e.g., `<!-- Primary action is prominent because users come here to check in members -->`)"),t.push("- Show **all screens in a single page** using tabs/sections that the user can click through"),t.push("- Be **responsive** \u2014 test that it looks reasonable at both 1200px and 375px widths"),t.push("- Include a small header bar showing: screen name tabs + the design direction summary"),t.push(""),t.push("The wireframe must NOT:"),t.push("- Use any color except grayscale (#333, #666, #999, #ddd, #f8f8f8, white)"),t.push("- Use any external dependencies \u2014 no CDN, no imports, no build step"),t.push("- Look polished \u2014 it should feel like a sketch on a whiteboard, not a finished product"),t.push("- Include decorative elements \u2014 no icons (use text labels), no illustrations, no gradients"),t.push(""),t.push("## Screens to wireframe"),t.push("");for(let a of r.screens){t.push(`### ${a.name} (\`${a.route}\`)`),t.push(`**Purpose**: ${a.purpose}`),t.push(""),t.push("**Information hierarchy** (render in this order, top to bottom):");for(let n of a.informationHierarchy)t.push(`- ${n}`);t.push(""),t.push("**Interaction states** (add HTML comments for non-visible states):");for(let n of a.interactionStates)t.push(`- ${n}`);if(t.push(""),a.entities.length>0){t.push("**Data model and sample content** (use this real data, not lorem ipsum):");for(let n of a.entities)t.push(`
12381
10812
  **${n.name}** \u2014 fields: ${n.fields.map(o=>`${o.name} (${o.type})`).join(", ")}`),t.push("```json"),t.push(JSON.stringify(n.sampleData,null,2)),t.push("```");t.push("")}}t.push("## Navigation"),t.push(`**Style**: ${r.navigation.style} (use this layout)`),t.push("**Items**:");for(let a of r.navigation.items)t.push(`- ${a.label} \u2192 \`${a.route}\``);if(t.push(""),r.primaryAction&&(t.push("## Primary action (this drives the layout)"),t.push(`- **Action**: ${r.primaryAction.action}`),t.push(`- **Flow**: ${r.primaryAction.flow}`),t.push(`- **Dashboard must show**: ${r.primaryAction.dashboardSurface}`),t.push(""),t.push("The dashboard is an ACTION surface. The primary action should be the most prominent thing on the page \u2014 above the metrics, above the recent items. Users came here to DO something, not to look at numbers."),t.push("")),r.edgeCases.length>0){t.push("## Edge cases to consider"),t.push("Add HTML comments in the wireframe where these matter:");for(let a of r.edgeCases)t.push(`- ${a}`);t.push("")}return t.push("## Design direction (DO NOT apply to wireframe \u2014 this is for reference only)"),t.push(`The final app will use: ${r.designDirection.tone} tone, ${r.designDirection.accentColor} accent, ${r.designDirection.navStyle} nav, ${r.designDirection.fonts.heading} / ${r.designDirection.fonts.body} fonts.`),t.push("The wireframe is grayscale and rough. These tokens will be applied during the actual build."),t.push(""),t.push("## After writing the wireframe"),t.push(""),t.push("1. Write the file to `.mistflow/mockups/mockup-{planId}.html` (replace `{planId}` with the actual plan ID)"),t.push("2. Open it: `open .mistflow/mockups/mockup-{planId}.html`"),t.push(`3. Tell the user: "Here's a rough wireframe of your app. This shows the layout and information hierarchy \u2014 not the final visual design (colors, fonts, polish come during the build). Does the layout feel right? Want to move things around, or shall we start building?"`),t.join(`
12382
- `)}function Dr(r){return Je(oa(),".mistflow","mockup-state",`${r}.json`)}function Do(r){let e=Dr(r);if(!St(e))return null;try{return JSON.parse(Ir(e,"utf-8"))}catch{return null}}function ra(r,e){let t=Je(oa(),".mistflow","mockup-state");Br(t,{recursive:!0}),Co(Dr(r),JSON.stringify(e,null,2))}async function Mr(r){let{planId:e,feedback:t,approved:a}=r,n=Po(r.projectPath??process.cwd()),o=Je(oa(),".mistflow","plans",`${e}.json`);if(!St(o))return c(`Plan not found for planId '${e}'. Call mist_plan to generate a plan first.`,!0);let i;try{i=JSON.parse(Ir(o,"utf-8"))}catch{return c("Failed to read plan file. Call mist_plan again.",!0)}let l=i.plan;if(!l)return c("Plan data is empty. Call mist_plan again.",!0);let s=Do(e);s||(s={planId:e,iterationCount:0,approved:!1,screens:[],feedback:[]});let d=Je(n,".mistflow","mockups");if(Br(d,{recursive:!0}),a){s.approved=!0,ra(e,s);let m=St(d)?Ar(d).filter(b=>b.endsWith(".html")):[];return c(JSON.stringify({status:"approved",message:`Wireframe approved after ${s.iterationCount} iteration(s). Layout direction is locked in.`,mockupFiles:m.map(b=>`.mistflow/mockups/${b}`),nextAction:`NEXT: Call mist_build with action='init', name='${l.name}', and planId='${e}' to create the project. The wireframe in .mistflow/mockups/ will be used as layout reference during implementation.`}))}t?(s.iterationCount++,s.feedback.push(t)):s.iterationCount++,ra(e,s);let p=Io(l);s.screens=p.screens.map(m=>m.name),ra(e,s);let u=Ao(p,t??void 0),h;return s.iterationCount>=3&&(h="The wireframe is shaping up \u2014 want to keep refining the layout, or start building?"),c(JSON.stringify({status:"wireframe",iterationCount:s.iterationCount,screens:p.screens.map(m=>({name:m.name,type:m.type,route:m.route})),wireframePrompt:u,designDirection:p.designDirection,...h?{nudge:h}:{},mockupFile:`mockup-${e}.html`,nextAction:t?`Apply the user's feedback to the wireframe. Rewrite .mistflow/mockups/mockup-${e}.html with the changes. Open it in the browser for review. Ask if they want more changes or are ready to build.`:`Generate the wireframe HTML following the wireframePrompt instructions above. Write it to .mistflow/mockups/mockup-${e}.html, then open it in the browser. Ask the user if the layout feels right.`}))}function Rr(r){let e=Je(r,".mistflow","mockups");return St(e)?Ar(e).filter(t=>t.endsWith(".html")).map(t=>Je(e,t)):[]}function No(r){return new Promise(e=>{let t=Fo({port:r,host:"127.0.0.1"});t.on("connect",()=>{t.destroy(),e(!0)}),t.on("error",()=>{e(!1)})})}var Ll=na.object({projectPath:na.string().optional().describe("Path to the project directory (default: cwd)"),step:na.number().optional().describe("Specific step number to implement (default: next incomplete step)")});function Uo(r){let e=Tt(r,"mistflow.json");if(!sa(e))return null;try{return JSON.parse(Fr(e,"utf-8"))}catch{return null}}function Lr(r,e){let t=Tt(r,"mistflow.json");la(t,JSON.stringify(e,null,2)+`
12383
- `)}function Ct(r){return r.entity??r.name??"Unknown"}function Eo(r){return r.length===0?"":typeof r[0]=="string"?r.join(", "):r.map(e=>`${e.name} (${e.type})`).join(", ")}function Nr(r){return r.path??r.route??r.name??""}function Ho(r){let e=(r||"text").toLowerCase();return e==="string"||e==="varchar"||e==="char"?"text":e==="integer"||e==="int"||e==="number"||e==="float"||e==="decimal"||e==="double"?"number":e==="boolean"||e==="bool"?"boolean":e==="date"||e==="datetime"||e==="timestamp"?"date":e==="email"?"email":e==="url"||e==="uri"?"url":e==="enum"||e==="select"?"select":e==="text"||e==="longtext"||e==="textarea"?"textarea":"text"}function Ur(r,e){if(!r.entities||r.entities.length===0)return e;let t=r.entities.map(a=>a.toLowerCase());return e.filter(a=>{let n=Ct(a).toLowerCase();return t.some(o=>n.includes(o)||o.includes(n))})}function Go(r,e){if(!r.pages||r.pages.length===0)return[];let t=r.pages.map(a=>a.toLowerCase());return e.filter(a=>{let n=(a.name??"").toLowerCase(),o=Nr(a).toLowerCase();return t.some(i=>n.includes(i)||i.includes(n)||o.includes(i))})}function Wo(r){if(r.integrationId)return"integration";let e=`${r.name} ${r.description}`.toLowerCase();return e.includes("crud")||e.includes("list")&&e.includes("create")?"crud":e.includes("auth")||e.includes("login")||e.includes("register")?"auth":e.includes("admin")&&(e.includes("panel")||e.includes("dashboard")||e.includes("manage")||e.includes("users"))?"admin":e.includes("dashboard")||e.includes("overview")||e.includes("analytics")?"dashboard":e.includes("schema")||e.includes("database")||e.includes("model")?"schema":e.includes("layout")||e.includes("sidebar")||e.includes("navigation")?"layout":e.includes("deploy")||e.includes("cloudflare")?"deploy":e.includes("organization")||e.includes("team")||e.includes("workspace")||e.includes("multi-tenant")||e.includes("invite member")?"multi-tenant":e.includes("landing")||e.includes("hero")||e.includes("marketing")||e.includes("homepage")?"landing":e.includes("design")||e.includes("theme")||e.includes("styling")||e.includes("ui polish")||e.includes("visual")?"design":"general"}function _o(r,e){let t=[];if(t.push("### Design choices (decided at plan time \u2014 follow these exactly):"),r.tone&&t.push(`- **App tone**: ${r.tone}`),r.fonts&&(t.push(`- **Heading font**: ${r.fonts.heading} (load from Google Fonts)`),t.push(`- **Body font**: ${r.fonts.body} (load from Google Fonts)`)),r.accentColor&&t.push(`- **Accent color**: ${r.accentColor} (use for primary buttons, active states, highlights only)`),r.borderRadius){let a={sharp:"2px",subtle:"6px",rounded:"12px",pill:"9999px"};t.push(`- **Border radius**: ${r.borderRadius} (${a[r.borderRadius]??r.borderRadius}) \u2014 set as --radius in globals.css`)}if(r.shadowStyle){let a={flat:"No shadows \u2014 use borders for separation",subtle:"shadow-sm on cards, shadow on hover",elevated:"shadow-md on cards, shadow-lg on modals, layered depth",dramatic:"shadow-lg with colored tinting, bold depth"};t.push(`- **Shadow style**: ${r.shadowStyle} \u2014 ${a[r.shadowStyle]??r.shadowStyle}`)}if(r.cardStyle){let a={filled:"bg-card with subtle background fill, no visible border",bordered:"border border-border on white/transparent background",elevated:"bg-card shadow-md, no border, lifted appearance",glass:"bg-white/60 backdrop-blur-sm border border-white/20, translucent"};t.push(`- **Card style**: ${r.cardStyle} \u2014 ${a[r.cardStyle]??r.cardStyle}`)}if(r.landingTone&&t.push(`- **Landing page tone**: ${r.landingTone}`),r.visualStrategy){let a=r.visualStrategy,n=e?.hasDesignPreset===!0,o=a.type==="photo"?"hybrid":a.type;if(t.push(""),t.push("### Visual strategy:"),n&&t.push("**Design preset active** \u2014 the hero section visuals come from the design preset blueprint below. Do NOT use Unsplash photos in the hero. Use CSS gradients, animated backgrounds, or the preset's specified visual approach instead."),o==="hybrid"){if(a.heroImages?.length&&!n){t.push("**Hero image available** \u2014 use this Unsplash photo as the landing page hero BACKGROUND:");let i=a.heroImages[0];t.push(`- URL: ${i.url}`),t.push(`- Alt text for img tag: "${i.alt||"Hero image"} \u2014 Photo by ${i.photographer} on Unsplash"`),t.push("- Use as full-bleed background behind the entire hero section with a dark overlay (bg-black/60). The photo is atmosphere, NOT the main visual.")}if(a.sectionImages?.length){t.push("**Section images available** \u2014 use these for feature sections, about sections, or testimonial backgrounds (NOT the hero):");for(let i of a.sectionImages)t.push(`- ${i.url} \u2014 alt: "${i.alt||"section image"} \u2014 Photo by ${i.photographer} on Unsplash"`)}(a.heroImages?.length||a.sectionImages?.length)&&t.push("For image attribution: put photographer credit in the img alt text (already provided above) and add an HTML comment <!-- Images from Unsplash --> near the images. Do NOT add visible attribution text on the page.")}!n&&(o==="product-ui"||o==="hybrid")&&(t.push(""),t.push("**Hero layout \u2014 split hero with product UI mockup (follow this exactly):**"),t.push("The hero must use a split layout with text on the left and a product preview on the right. This is non-negotiable for SaaS/tool apps."),t.push(""),t.push("```"),t.push("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),t.push("\u2502 [Logo] [Sign In] [CTA \u2192] \u2502 \u2190 transparent nav, NOT sticky"),t.push("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),t.push("\u2502 \u2502"),t.push("\u2502 \u25CF Built for [audience] \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502"),t.push("\u2502 \u2502 Glassmorphic \u2502 \u2502"),t.push("\u2502 Big bold headline, \u2502 product mockup \u2502 \u2502"),t.push("\u2502 accent color on key word \u2502 card showing \u2502 \u2502"),t.push("\u2502 \u2502 real app data \u2502 \u2502"),t.push("\u2502 Description paragraph \u2502 (stats, table, \u2502 \u2502"),t.push("\u2502 \u2502 chart, etc.) \u2502 \u2502"),t.push("\u2502 [Primary CTA \u2192] [Secondary] \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502"),t.push("\u2502 \u2502"),t.push("\u2502 500+ 25K+ 99% \u2502"),t.push("\u2502 Label Label Label \u2502"),t.push("\u2502 \u2502"),t.push("\u2502 \u2190 full-bleed photo bg + dark overlay behind all \u2192 \u2502"),t.push("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),t.push("```"),t.push(""),t.push("**Left side (~55%)**: badge pill \u2192 bold headline (use accent color on ONE key word or phrase) \u2192 description \u2192 two CTA buttons (primary filled + secondary outline/ghost with white text) \u2192 stats row with 3 proof points"),t.push("**Right side (~45%)**: A glassmorphic floating card that previews what the app looks like inside:"),t.push("- Style: `bg-white/10 backdrop-blur-lg border border-white/20 rounded-2xl shadow-2xl p-6`"),t.push("- Content: Build realistic fake app data using styled divs \u2014 stat cards, mini table rows, schedule blocks, or charts that match what this specific app's dashboard shows"),t.push("- Must be DOMAIN-SPECIFIC: a library app shows book catalog rows, a gym app shows check-in stats, a CRM shows pipeline cards"),t.push("- Add subtle inner elements with `bg-white/5` or `bg-white/10` for depth"),t.push("**Stats row**: 3 proof-point numbers at the bottom of the left side (e.g., '500+ Gyms', '25K+ Members', '99% Uptime'). Use white text, large font for the number, small muted text for the label.")),!n&&o==="product-ui"&&(t.push("**No stock photos** \u2014 this is a product/SaaS app. Use SVG decorative elements instead:"),t.push("- Abstract dot grids, wave dividers between sections, gradient mesh backgrounds"),t.push("- Subtle background patterns using CSS (radial-gradient dots, grid lines)"))}return t.push(""),t.push("Apply these choices to every file you create. Customize the shadcn CSS variables in globals.css to match. Do NOT use default shadcn blue/zinc theme."),t.push(""),t.push("**CRITICAL: shadcn/ui components are already installed. NEVER write components/ui/*.tsx files from scratch.** If you need a shadcn component, run `npx shadcn@latest add <component>` to pull it. The project already includes: button, card, input, label, form, dialog, table, dropdown-menu, badge, separator, skeleton, sheet, tabs, avatar, select, textarea, checkbox, switch, tooltip, popover, sonner."),t.push(""),t.push("**shadcn MCP server is available.** You have the `shadcn` MCP server installed \u2014 use it to browse and search for components, blocks, and landing page sections from the shadcn registry. Before building a landing page section from scratch, check the registry for existing blocks (hero sections, feature grids, pricing tables, testimonials, footers) and customize them instead of reinventing."),t.push(""),t.push("**Project routes (use these exact paths):** Login is at `/login` (NOT /sign-in). Register is at `/register` (NOT /sign-up). All landing page and nav links MUST use `/login` and `/register`."),t.push(""),t.push("### Design quality rules (non-negotiable):"),t.push(""),t.push("**Typography**: Use the plan fonts everywhere. font-heading for headings (text-2xl+ bold), font-body for body text. Create clear hierarchy with 3-4 distinct text sizes \u2014 sizes too close together (14/15/16px) create muddy hierarchy. Use font-medium/font-semibold contrast, not just size. Never fall back to system fonts."),t.push(""),t.push("**Color**: Tint your neutrals toward the accent hue \u2014 even a subtle hint creates cohesion. Never use pure #000 or #fff. Never use gray text on colored backgrounds \u2014 use a shade of the background color instead. Use the 60/30/10 rule: dominant neutral 60%, secondary color 30%, accent for 10% highlights. Accent color goes on CTAs, active states, key metrics \u2014 not everywhere."),t.push(""),t.push("**Layout & space**: Create visual rhythm through VARIED spacing \u2014 tight groupings within related items, generous separation between sections. Don't center everything \u2014 left-aligned with asymmetric layouts feels more designed. Don't wrap everything in cards \u2014 not everything needs a container. Never nest cards inside cards."),t.push(""),t.push("**Cards & surfaces**: Match the plan's cardStyle. Stat cards need background fills with the accent color as a left border accent or subtle icon background \u2014 never just a border with a number inside. Use bg-muted/30 for section differentiation between page areas."),t.push(""),t.push("**Sidebar**: App name + icon at top. Nav items with hover:bg-muted rounded-md transition. Active item: bg-primary/10 text-primary font-medium. User email + sign out at bottom. The sidebar should feel like a distinct surface (bg-card or bg-muted/50)."),t.push(""),t.push("**Interaction**: Don't make every button primary \u2014 use ghost buttons, text links, secondary styles. Hierarchy matters. Use progressive disclosure \u2014 simple first, advanced behind expandable sections."),t.push(""),t.push("**Empty states**: Every empty list/table needs a rich empty state \u2014 not just 'Nothing here'. Include: a simple inline SVG illustration (draw a relevant icon like a checklist, calendar, or inbox as a 48x48 SVG), a specific message that teaches ('Create your first habit to start tracking your daily routine'), and a primary action button. Empty states are the first thing new users see \u2014 make them inviting."),t.push(""),t.push('**Loading states**: Use the shadcn `Skeleton` component for loading states on dashboard pages. When data is being fetched, show skeleton versions of cards, lists, and stats \u2014 not a blank page or a spinner. Example: `<Skeleton className="h-8 w-32" />` for a stat number, `<Skeleton className="h-20 w-full" />` for a card. Add a `loading.tsx` file in dashboard route groups.'),t.push(""),t.push('**Images**: For Unsplash images on landing pages, use `next/image` with `placeholder="blur"` and a blurDataURL (a tiny 10x6 base64 image \u2014 generate a solid color blur like `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAAP0lEQVQYV2N89+7dfwYGBgZGRkYGBgYmBjIBE7kaPHv27D8DA8N/BgYGRkZGRgYGJgYyARO5GkjWQHEoxRoAAPyTGAGBMpEAAAAASUVORK5CYII=`). This creates a smooth shimmer-in effect instead of images popping in.'),t.push(""),t.push("**Motion \u2014 SSR-safe patterns only** (`motion` package is installed): CRITICAL: This app deploys to Cloudflare Workers where IntersectionObserver may not fire reliably. NEVER use `initial={{ opacity: 0 }}` \u2014 content will stay invisible forever. Instead use CSS animations for entrance effects and motion only for enhancements:"),t.push("```tsx"),t.push("// SAFE: CSS @keyframes for section entrance (works without JS)"),t.push("// In globals.css:"),t.push("// @keyframes fade-up { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }"),t.push("// .animate-fade-up { animation: fade-up 0.5s ease-out both; }"),t.push("// Then use className='animate-fade-up' on sections"),t.push("//"),t.push("// SAFE: motion for hover/tap interactions only"),t.push("import { motion } from 'motion/react';"),t.push("<motion.div whileHover={{ scale: 1.02 }} transition={{ duration: 0.2 }}>"),t.push("//"),t.push("// NEVER DO THIS \u2014 breaks on Cloudflare:"),t.push("// <motion.div initial={{ opacity: 0 }} whileInView={{ opacity: 1 }}>"),t.push("```"),t.push("Use CSS `@keyframes` + `animation` for scroll-triggered entrance effects \u2014 they work on all runtimes with no JS dependency. Use `motion` only for hover, tap, and drag interactions. Add `hover:scale-[1.02] transition` on clickable cards via CSS. For dashboard pages, keep animations minimal \u2014 only CSS transitions."),t.push(""),t.push("**Landing page component patterns** (use these for professional, non-generic landing pages):"),t.push("Build these components inline (no external UI kit needed \u2014 shadcn + motion + Tailwind is enough):"),t.push("- **Animated number counters**: Use `@number-flow/react` (installed) for stat sections \u2014 `<NumberFlow value={count} />` with smooth digit transitions. Much better than static numbers."),t.push("- **Marquee / logo ticker**: For 'trusted by' sections, build a CSS-only infinite scroll marquee (`@keyframes marquee { from { transform: translateX(0) } to { transform: translateX(-50%) } }`) with duplicated content. Pause on hover."),t.push("- **Bento grid**: For features, use a CSS grid with varied `col-span` and `row-span` (e.g., 2x2 hero card, 1x1 detail cards). Each cell gets a unique visual: inline SVG demo, code snippet, mini chart, or animated icon. Never make all cells the same size."),t.push("- **Animated beam / connection lines**: For 'how it works' sections, use SVG paths with `motion` stroke-dashoffset animation to draw connection lines between steps."),t.push("- **Shimmer borders**: For hero CTAs, use a `background: conic-gradient(...)` wrapper with animation for an eye-catching shimmer border effect."),t.push("- **Comparison tables**: For pricing or vs-competitor sections, use a sticky-header table with check/x icons and row highlighting on the recommended plan."),t.push("- **Testimonial carousel**: Use CSS scroll-snap for horizontal testimonial cards with avatar, quote, name, role. Auto-scroll with `setInterval` paused on hover."),t.push("- **Gradient mesh backgrounds**: For hero sections, use multiple layered `radial-gradient` backgrounds with subtle `motion` parallax on scroll."),t.push("- **Floating elements**: Decorative shapes (circles, dots, rings) with `motion` float animations (`y: [0, -10, 0]` with `repeat: Infinity`) positioned absolutely behind content."),t.push("These patterns replace generic layouts. Pick 3-5 per landing page based on the app's content. The goal: every landing page should look like it was designed by a human, not generated by AI."),t.push(""),t.push("**Landing page navbar (non-negotiable):** The landing page navbar must be fully transparent (no background, no border, no backdrop-blur) and NOT sticky/fixed. It sits inside the hero section and scrolls with the page naturally. Use white text and logo on dark hero backgrounds. The primary CTA button in the nav should be the accent color (solid fill, rounded-md) so it pops against the dark hero. Do NOT use `sticky`, `fixed`, `top-0`, or `backdrop-blur` on landing page navbars. This is different from the dashboard sidebar/nav which IS fixed."),t.push(""),t.push("**Design for THIS app, not any app** (the #1 way to avoid generic AI output):"),t.push("- Every layout decision should be informed by what THIS app does. A gym check-in app needs a prominent search bar. A habit tracker needs a daily view. A CRM needs a pipeline. Don't default to the same dashboard-with-stats layout for everything."),t.push("- Write copy that is SPECIFIC to the app's domain. Not 'Manage your data efficiently' but 'Check in members in under 3 seconds'. Every headline, empty state, and CTA should reference what the user actually does in this app."),t.push("- Choose visual emphasis based on the primary action. If the user comes to log a workout, the workout form should be the biggest thing on the dashboard \u2014 not hidden behind a nav link."),t.push("- Use domain-appropriate metaphors. A fitness app might use progress rings. A project tracker might use kanban columns. A recipe app might use cards with photos. Don't use the same card grid for everything."),t.push(""),t.push("**NEVER do these (AI slop anti-patterns)**:"),t.push("- Hero text like 'Transform your X' / 'One Day at a Time' / 'Join thousands' \u2014 write SPECIFIC copy about what the app does"),t.push("- 3-column icon + title + paragraph feature grid \u2014 use asymmetric layouts, bento grids, or varied card sizes"),t.push("- The hero metric template (big number, small label, supporting stats, gradient accent) \u2014 design unique data displays"),t.push("- Cyan-on-dark, purple-to-blue gradients, neon accents on dark backgrounds \u2014 the AI color palette"),t.push("- Gradient text on headings or metrics \u2014 it's decorative noise, not meaningful"),t.push("- Glassmorphism / blur effects used decoratively \u2014 only use blur if it serves a real purpose (e.g. overlays)"),t.push("- Rounded rectangles with thick colored border on one side \u2014 a lazy accent that never looks intentional"),t.push("- Bounce/elastic easing on animations \u2014 feels dated; real objects decelerate smoothly"),t.push("- Repeating information users can already see \u2014 every word must earn its place"),t.push("- Modals for things that could be inline \u2014 modals are a last resort, not a default"),t.push("- Nav links to pages that don't exist \u2014 EVERY link in the sidebar/topnav MUST have a corresponding page. If you add a nav link, create the page. If a page isn't built yet, don't link to it."),t.push("- FAKE FORMS \u2014 NEVER use `setTimeout` or `await new Promise` to simulate API calls. Every form MUST have a real server action (actions.ts with 'use server') that writes to the database. If a form doesn't persist data, the feature is BROKEN. This is the #1 way features appear to work but are actually fake."),t.push(""),t.push("**Favicon**: A default SVG favicon exists at app/icon.svg. On the landing page step, update it to match the app \u2014 change the SVG shape and fill color to use the accent color. Keep it simple (a single icon/letter on a rounded square)."),t.join(`
12384
- `)}async function Oo(r){try{let e=await Va("nextjs",r);return{reminders:e.reminders,skill:e.skill}}catch{return{reminders:`### ${r} step
10813
+ `)}function Fr(r){return Ye(sa(),".mistflow","mockup-state",`${r}.json`)}function Un(r){let e=Fr(r);if(!Tt(e))return null;try{return JSON.parse(Lr(e,"utf-8"))}catch{return null}}function na(r,e){let t=Ye(sa(),".mistflow","mockup-state");Rr(t,{recursive:!0}),Rn(Fr(r),JSON.stringify(e,null,2))}async function Er(r){let{planId:e,feedback:t,approved:a}=r,n=Ln(r.projectPath??process.cwd()),o=Ye(sa(),".mistflow","plans",`${e}.json`);if(!Tt(o))return c(`Plan not found for planId '${e}'. Call mist_plan to generate a plan first.`,!0);let i;try{i=JSON.parse(Lr(o,"utf-8"))}catch{return c("Failed to read plan file. Call mist_plan again.",!0)}let s=i.plan;if(!s)return c("Plan data is empty. Call mist_plan again.",!0);let l=Un(e);l||(l={planId:e,iterationCount:0,approved:!1,screens:[],feedback:[]});let d=Ye(n,".mistflow","mockups");if(Rr(d,{recursive:!0}),a){l.approved=!0,na(e,l);let m=Tt(d)?Nr(d).filter(f=>f.endsWith(".html")):[];return c(JSON.stringify({status:"approved",message:`Wireframe approved after ${l.iterationCount} iteration(s). Layout direction is locked in.`,mockupFiles:m.map(f=>`.mistflow/mockups/${f}`),nextAction:`NEXT: Call mist_build with action='init', name='${s.name}', and planId='${e}' to create the project. The wireframe in .mistflow/mockups/ will be used as layout reference during implementation.`}))}t?(l.iterationCount++,l.feedback.push(t)):l.iterationCount++,na(e,l);let u=Fn(s);l.screens=u.screens.map(m=>m.name),na(e,l);let p=En(u,t??void 0),h;return l.iterationCount>=3&&(h="The wireframe is shaping up \u2014 want to keep refining the layout, or start building?"),c(JSON.stringify({status:"wireframe",iterationCount:l.iterationCount,screens:u.screens.map(m=>({name:m.name,type:m.type,route:m.route})),wireframePrompt:p,designDirection:u.designDirection,...h?{nudge:h}:{},mockupFile:`mockup-${e}.html`,nextAction:t?`Apply the user's feedback to the wireframe. Rewrite .mistflow/mockups/mockup-${e}.html with the changes. Open it in the browser for review. Ask if they want more changes or are ready to build.`:`Generate the wireframe HTML following the wireframePrompt instructions above. Write it to .mistflow/mockups/mockup-${e}.html, then open it in the browser. Ask the user if the layout feels right.`}))}function Ur(r){let e=Ye(r,".mistflow","mockups");return Tt(e)?Nr(e).filter(t=>t.endsWith(".html")).map(t=>Ye(e,t)):[]}function _n(r){return new Promise(e=>{let t=On({port:r,host:"127.0.0.1"});t.on("connect",()=>{t.destroy(),e(!0)}),t.on("error",()=>{e(!1)})})}var zl=la.object({projectPath:la.string().optional().describe("Path to the project directory (default: cwd)"),step:la.number().optional().describe("Specific step number to implement (default: next incomplete step)")});function jn(r){let e=Pt(r,"mistflow.json");if(!da(e))return null;try{return JSON.parse(Gr(e,"utf-8"))}catch{return null}}function Hr(r,e){let t=Pt(r,"mistflow.json");ca(t,JSON.stringify(e,null,2)+`
10814
+ `)}function Bt(r){return r.entity??r.name??"Unknown"}function zn(r){return r.length===0?"":typeof r[0]=="string"?r.join(", "):r.map(e=>`${e.name} (${e.type})`).join(", ")}function Wr(r){return r.path??r.route??r.name??""}function $n(r){let e=(r||"text").toLowerCase();return e==="string"||e==="varchar"||e==="char"?"text":e==="integer"||e==="int"||e==="number"||e==="float"||e==="decimal"||e==="double"?"number":e==="boolean"||e==="bool"?"boolean":e==="date"||e==="datetime"||e==="timestamp"?"date":e==="email"?"email":e==="url"||e==="uri"?"url":e==="enum"||e==="select"?"select":e==="text"||e==="longtext"||e==="textarea"?"textarea":"text"}function Or(r,e){if(!r.entities||r.entities.length===0)return e;let t=r.entities.map(a=>a.toLowerCase());return e.filter(a=>{let n=Bt(a).toLowerCase();return t.some(o=>n.includes(o)||o.includes(n))})}function Vn(r,e){if(!r.pages||r.pages.length===0)return[];let t=r.pages.map(a=>a.toLowerCase());return e.filter(a=>{let n=(a.name??"").toLowerCase(),o=Wr(a).toLowerCase();return t.some(i=>n.includes(i)||i.includes(n)||o.includes(i))})}function qn(r){if(r.integrationId)return"integration";let e=`${r.name} ${r.description}`.toLowerCase();return e.includes("crud")||e.includes("list")&&e.includes("create")?"crud":e.includes("auth")||e.includes("login")||e.includes("register")?"auth":e.includes("admin")&&(e.includes("panel")||e.includes("dashboard")||e.includes("manage")||e.includes("users"))?"admin":e.includes("dashboard")||e.includes("overview")||e.includes("analytics")?"dashboard":e.includes("schema")||e.includes("database")||e.includes("model")?"schema":e.includes("layout")||e.includes("sidebar")||e.includes("navigation")?"layout":e.includes("deploy")||e.includes("cloudflare")?"deploy":e.includes("organization")||e.includes("team")||e.includes("workspace")||e.includes("multi-tenant")||e.includes("invite member")?"multi-tenant":e.includes("landing")||e.includes("hero")||e.includes("marketing")||e.includes("homepage")?"landing":e.includes("design")||e.includes("theme")||e.includes("styling")||e.includes("ui polish")||e.includes("visual")?"design":"general"}function Kn(r,e){let t=[];if(t.push("### Design choices (decided at plan time \u2014 follow these exactly):"),r.tone&&t.push(`- **App tone**: ${r.tone}`),r.fonts&&(t.push(`- **Heading font**: ${r.fonts.heading} (load from Google Fonts)`),t.push(`- **Body font**: ${r.fonts.body} (load from Google Fonts)`)),r.accentColor&&t.push(`- **Accent color**: ${r.accentColor} (use for primary buttons, active states, highlights only)`),r.borderRadius){let a={sharp:"2px",subtle:"6px",rounded:"12px",pill:"9999px"};t.push(`- **Border radius**: ${r.borderRadius} (${a[r.borderRadius]??r.borderRadius}) \u2014 set as --radius in globals.css`)}if(r.shadowStyle){let a={flat:"No shadows \u2014 use borders for separation",subtle:"shadow-sm on cards, shadow on hover",elevated:"shadow-md on cards, shadow-lg on modals, layered depth",dramatic:"shadow-lg with colored tinting, bold depth"};t.push(`- **Shadow style**: ${r.shadowStyle} \u2014 ${a[r.shadowStyle]??r.shadowStyle}`)}if(r.cardStyle){let a={filled:"bg-card with subtle background fill, no visible border",bordered:"border border-border on white/transparent background",elevated:"bg-card shadow-md, no border, lifted appearance",glass:"bg-white/60 backdrop-blur-sm border border-white/20, translucent"};t.push(`- **Card style**: ${r.cardStyle} \u2014 ${a[r.cardStyle]??r.cardStyle}`)}if(r.landingTone&&t.push(`- **Landing page tone**: ${r.landingTone}`),r.visualStrategy){let a=r.visualStrategy,n=e?.hasDesignPreset===!0,o=a.type==="photo"?"hybrid":a.type;if(t.push(""),t.push("### Visual strategy:"),n&&t.push("**Design preset active** \u2014 the hero section visuals come from the design preset blueprint below. Do NOT use Unsplash photos in the hero. Use CSS gradients, animated backgrounds, or the preset's specified visual approach instead."),o==="hybrid"){if(a.heroImages?.length&&!n){t.push("**Hero image available** \u2014 use this Unsplash photo as the landing page hero BACKGROUND:");let i=a.heroImages[0];t.push(`- URL: ${i.url}`),t.push(`- Alt text for img tag: "${i.alt||"Hero image"} \u2014 Photo by ${i.photographer} on Unsplash"`),t.push("- Use as full-bleed background behind the entire hero section with a dark overlay (bg-black/60). The photo is atmosphere, NOT the main visual.")}if(a.sectionImages?.length){t.push("**Section images available** \u2014 use these for feature sections, about sections, or testimonial backgrounds (NOT the hero):");for(let i of a.sectionImages)t.push(`- ${i.url} \u2014 alt: "${i.alt||"section image"} \u2014 Photo by ${i.photographer} on Unsplash"`)}(a.heroImages?.length||a.sectionImages?.length)&&t.push("For image attribution: put photographer credit in the img alt text (already provided above) and add an HTML comment <!-- Images from Unsplash --> near the images. Do NOT add visible attribution text on the page.")}!n&&(o==="product-ui"||o==="hybrid")&&(t.push(""),t.push("**Hero layout \u2014 split hero with product UI mockup (follow this exactly):**"),t.push("The hero must use a split layout with text on the left and a product preview on the right. This is non-negotiable for SaaS/tool apps."),t.push(""),t.push("```"),t.push("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),t.push("\u2502 [Logo] [Sign In] [CTA \u2192] \u2502 \u2190 transparent nav, NOT sticky"),t.push("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),t.push("\u2502 \u2502"),t.push("\u2502 \u25CF Built for [audience] \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502"),t.push("\u2502 \u2502 Glassmorphic \u2502 \u2502"),t.push("\u2502 Big bold headline, \u2502 product mockup \u2502 \u2502"),t.push("\u2502 accent color on key word \u2502 card showing \u2502 \u2502"),t.push("\u2502 \u2502 real app data \u2502 \u2502"),t.push("\u2502 Description paragraph \u2502 (stats, table, \u2502 \u2502"),t.push("\u2502 \u2502 chart, etc.) \u2502 \u2502"),t.push("\u2502 [Primary CTA \u2192] [Secondary] \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502"),t.push("\u2502 \u2502"),t.push("\u2502 500+ 25K+ 99% \u2502"),t.push("\u2502 Label Label Label \u2502"),t.push("\u2502 \u2502"),t.push("\u2502 \u2190 full-bleed photo bg + dark overlay behind all \u2192 \u2502"),t.push("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),t.push("```"),t.push(""),t.push("**Left side (~55%)**: badge pill \u2192 bold headline (use accent color on ONE key word or phrase) \u2192 description \u2192 two CTA buttons (primary filled + secondary outline/ghost with white text) \u2192 stats row with 3 proof points"),t.push("**Right side (~45%)**: A glassmorphic floating card that previews what the app looks like inside:"),t.push("- Style: `bg-white/10 backdrop-blur-lg border border-white/20 rounded-2xl shadow-2xl p-6`"),t.push("- Content: Build realistic fake app data using styled divs \u2014 stat cards, mini table rows, schedule blocks, or charts that match what this specific app's dashboard shows"),t.push("- Must be DOMAIN-SPECIFIC: a library app shows book catalog rows, a gym app shows check-in stats, a CRM shows pipeline cards"),t.push("- Add subtle inner elements with `bg-white/5` or `bg-white/10` for depth"),t.push("**Stats row**: 3 proof-point numbers at the bottom of the left side (e.g., '500+ Gyms', '25K+ Members', '99% Uptime'). Use white text, large font for the number, small muted text for the label.")),!n&&o==="product-ui"&&(t.push("**No stock photos** \u2014 this is a product/SaaS app. Use SVG decorative elements instead:"),t.push("- Abstract dot grids, wave dividers between sections, gradient mesh backgrounds"),t.push("- Subtle background patterns using CSS (radial-gradient dots, grid lines)"))}return t.push(""),t.push("Apply these choices to every file you create. Customize the shadcn CSS variables in globals.css to match. Do NOT use default shadcn blue/zinc theme."),t.push(""),t.push("**CRITICAL: shadcn/ui components are already installed. NEVER write components/ui/*.tsx files from scratch.** If you need a shadcn component, run `npx shadcn@latest add <component>` to pull it. The project already includes: button, card, input, label, form, dialog, table, dropdown-menu, badge, separator, skeleton, sheet, tabs, avatar, select, textarea, checkbox, switch, tooltip, popover, sonner."),t.push(""),t.push("**shadcn MCP server is available.** You have the `shadcn` MCP server installed \u2014 use it to browse and search for components, blocks, and landing page sections from the shadcn registry. Before building a landing page section from scratch, check the registry for existing blocks (hero sections, feature grids, pricing tables, testimonials, footers) and customize them instead of reinventing."),t.push(""),t.push("**Project routes (use these exact paths):** Login is at `/login` (NOT /sign-in). Register is at `/register` (NOT /sign-up). All landing page and nav links MUST use `/login` and `/register`."),t.push(""),t.push("### Design quality rules (non-negotiable):"),t.push(""),t.push("**Typography**: Use the plan fonts everywhere. font-heading for headings (text-2xl+ bold), font-body for body text. Create clear hierarchy with 3-4 distinct text sizes \u2014 sizes too close together (14/15/16px) create muddy hierarchy. Use font-medium/font-semibold contrast, not just size. Never fall back to system fonts."),t.push(""),t.push("**Color**: Tint your neutrals toward the accent hue \u2014 even a subtle hint creates cohesion. Never use pure #000 or #fff. Never use gray text on colored backgrounds \u2014 use a shade of the background color instead. Use the 60/30/10 rule: dominant neutral 60%, secondary color 30%, accent for 10% highlights. Accent color goes on CTAs, active states, key metrics \u2014 not everywhere."),t.push(""),t.push("**Layout & space**: Create visual rhythm through VARIED spacing \u2014 tight groupings within related items, generous separation between sections. Don't center everything \u2014 left-aligned with asymmetric layouts feels more designed. Don't wrap everything in cards \u2014 not everything needs a container. Never nest cards inside cards."),t.push(""),t.push("**Cards & surfaces**: Match the plan's cardStyle. Stat cards need background fills with the accent color as a left border accent or subtle icon background \u2014 never just a border with a number inside. Use bg-muted/30 for section differentiation between page areas."),t.push(""),t.push("**Sidebar**: App name + icon at top. Nav items with hover:bg-muted rounded-md transition. Active item: bg-primary/10 text-primary font-medium. User email + sign out at bottom. The sidebar should feel like a distinct surface (bg-card or bg-muted/50)."),t.push(""),t.push("**Interaction**: Don't make every button primary \u2014 use ghost buttons, text links, secondary styles. Hierarchy matters. Use progressive disclosure \u2014 simple first, advanced behind expandable sections."),t.push(""),t.push("**Empty states**: Every empty list/table needs a rich empty state \u2014 not just 'Nothing here'. Include: a simple inline SVG illustration (draw a relevant icon like a checklist, calendar, or inbox as a 48x48 SVG), a specific message that teaches ('Create your first habit to start tracking your daily routine'), and a primary action button. Empty states are the first thing new users see \u2014 make them inviting."),t.push(""),t.push('**Loading states**: Use the shadcn `Skeleton` component for loading states on dashboard pages. When data is being fetched, show skeleton versions of cards, lists, and stats \u2014 not a blank page or a spinner. Example: `<Skeleton className="h-8 w-32" />` for a stat number, `<Skeleton className="h-20 w-full" />` for a card. Add a `loading.tsx` file in dashboard route groups.'),t.push(""),t.push('**Images**: For Unsplash images on landing pages, use `next/image` with `placeholder="blur"` and a blurDataURL (a tiny 10x6 base64 image \u2014 generate a solid color blur like `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAAP0lEQVQYV2N89+7dfwYGBgZGRkYGBgYmBjIBE7kaPHv27D8DA8N/BgYGRkZGRgYGJgYyARO5GkjWQHEoxRoAAPyTGAGBMpEAAAAASUVORK5CYII=`). This creates a smooth shimmer-in effect instead of images popping in.'),t.push(""),t.push("**Motion \u2014 SSR-safe patterns only** (`motion` package is installed): CRITICAL: This app deploys to Cloudflare Workers where IntersectionObserver may not fire reliably. NEVER use `initial={{ opacity: 0 }}` \u2014 content will stay invisible forever. Instead use CSS animations for entrance effects and motion only for enhancements:"),t.push("```tsx"),t.push("// SAFE: CSS @keyframes for section entrance (works without JS)"),t.push("// In globals.css:"),t.push("// @keyframes fade-up { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }"),t.push("// .animate-fade-up { animation: fade-up 0.5s ease-out both; }"),t.push("// Then use className='animate-fade-up' on sections"),t.push("//"),t.push("// SAFE: motion for hover/tap interactions only"),t.push("import { motion } from 'motion/react';"),t.push("<motion.div whileHover={{ scale: 1.02 }} transition={{ duration: 0.2 }}>"),t.push("//"),t.push("// NEVER DO THIS \u2014 breaks on Cloudflare:"),t.push("// <motion.div initial={{ opacity: 0 }} whileInView={{ opacity: 1 }}>"),t.push("```"),t.push("Use CSS `@keyframes` + `animation` for scroll-triggered entrance effects \u2014 they work on all runtimes with no JS dependency. Use `motion` only for hover, tap, and drag interactions. Add `hover:scale-[1.02] transition` on clickable cards via CSS. For dashboard pages, keep animations minimal \u2014 only CSS transitions."),t.push(""),t.push("**Landing page component patterns** (use these for professional, non-generic landing pages):"),t.push("Build these components inline (no external UI kit needed \u2014 shadcn + motion + Tailwind is enough):"),t.push("- **Animated number counters**: Use `@number-flow/react` (installed) for stat sections \u2014 `<NumberFlow value={count} />` with smooth digit transitions. Much better than static numbers."),t.push("- **Marquee / logo ticker**: For 'trusted by' sections, build a CSS-only infinite scroll marquee (`@keyframes marquee { from { transform: translateX(0) } to { transform: translateX(-50%) } }`) with duplicated content. Pause on hover."),t.push("- **Bento grid**: For features, use a CSS grid with varied `col-span` and `row-span` (e.g., 2x2 hero card, 1x1 detail cards). Each cell gets a unique visual: inline SVG demo, code snippet, mini chart, or animated icon. Never make all cells the same size."),t.push("- **Animated beam / connection lines**: For 'how it works' sections, use SVG paths with `motion` stroke-dashoffset animation to draw connection lines between steps."),t.push("- **Shimmer borders**: For hero CTAs, use a `background: conic-gradient(...)` wrapper with animation for an eye-catching shimmer border effect."),t.push("- **Comparison tables**: For pricing or vs-competitor sections, use a sticky-header table with check/x icons and row highlighting on the recommended plan."),t.push("- **Testimonial carousel**: Use CSS scroll-snap for horizontal testimonial cards with avatar, quote, name, role. Auto-scroll with `setInterval` paused on hover."),t.push("- **Gradient mesh backgrounds**: For hero sections, use multiple layered `radial-gradient` backgrounds with subtle `motion` parallax on scroll."),t.push("- **Floating elements**: Decorative shapes (circles, dots, rings) with `motion` float animations (`y: [0, -10, 0]` with `repeat: Infinity`) positioned absolutely behind content."),t.push("These patterns replace generic layouts. Pick 3-5 per landing page based on the app's content. The goal: every landing page should look like it was designed by a human, not generated by AI."),t.push(""),t.push("**Landing page navbar (non-negotiable):** The landing page navbar must be fully transparent (no background, no border, no backdrop-blur) and NOT sticky/fixed. It sits inside the hero section and scrolls with the page naturally. Use white text and logo on dark hero backgrounds. The primary CTA button in the nav should be the accent color (solid fill, rounded-md) so it pops against the dark hero. Do NOT use `sticky`, `fixed`, `top-0`, or `backdrop-blur` on landing page navbars. This is different from the dashboard sidebar/nav which IS fixed."),t.push(""),t.push("**Design for THIS app, not any app** (the #1 way to avoid generic AI output):"),t.push("- Every layout decision should be informed by what THIS app does. A gym check-in app needs a prominent search bar. A habit tracker needs a daily view. A CRM needs a pipeline. Don't default to the same dashboard-with-stats layout for everything."),t.push("- Write copy that is SPECIFIC to the app's domain. Not 'Manage your data efficiently' but 'Check in members in under 3 seconds'. Every headline, empty state, and CTA should reference what the user actually does in this app."),t.push("- Choose visual emphasis based on the primary action. If the user comes to log a workout, the workout form should be the biggest thing on the dashboard \u2014 not hidden behind a nav link."),t.push("- Use domain-appropriate metaphors. A fitness app might use progress rings. A project tracker might use kanban columns. A recipe app might use cards with photos. Don't use the same card grid for everything."),t.push(""),t.push("**NEVER do these (AI slop anti-patterns)**:"),t.push("- Hero text like 'Transform your X' / 'One Day at a Time' / 'Join thousands' \u2014 write SPECIFIC copy about what the app does"),t.push("- 3-column icon + title + paragraph feature grid \u2014 use asymmetric layouts, bento grids, or varied card sizes"),t.push("- The hero metric template (big number, small label, supporting stats, gradient accent) \u2014 design unique data displays"),t.push("- Cyan-on-dark, purple-to-blue gradients, neon accents on dark backgrounds \u2014 the AI color palette"),t.push("- Gradient text on headings or metrics \u2014 it's decorative noise, not meaningful"),t.push("- Glassmorphism / blur effects used decoratively \u2014 only use blur if it serves a real purpose (e.g. overlays)"),t.push("- Rounded rectangles with thick colored border on one side \u2014 a lazy accent that never looks intentional"),t.push("- Bounce/elastic easing on animations \u2014 feels dated; real objects decelerate smoothly"),t.push("- Repeating information users can already see \u2014 every word must earn its place"),t.push("- Modals for things that could be inline \u2014 modals are a last resort, not a default"),t.push("- Nav links to pages that don't exist \u2014 EVERY link in the sidebar/topnav MUST have a corresponding page. If you add a nav link, create the page. If a page isn't built yet, don't link to it."),t.push("- FAKE FORMS \u2014 NEVER use `setTimeout` or `await new Promise` to simulate API calls. Every form MUST have a real server action (actions.ts with 'use server') that writes to the database. If a form doesn't persist data, the feature is BROKEN. This is the #1 way features appear to work but are actually fake."),t.push(""),t.push("**Favicon**: A default SVG favicon exists at app/icon.svg. On the landing page step, update it to match the app \u2014 change the SVG shape and fill color to use the accent color. Keep it simple (a single icon/letter on a rounded square)."),t.join(`
10815
+ `)}async function Jn(r){try{let e=await Ka("nextjs",r);return{reminders:e.reminders,skill:e.skill}}catch{return{reminders:`### ${r} step
12385
10816
  - Follow existing patterns in the codebase
12386
- - Server Components by default, "use client" only when interactivity is needed`,skill:""}}}async function jo(r,e,t,a,n,o){let i=[];i.push(`## Step ${r.number}: ${r.name}`),i.push(""),i.push("### What to build:"),i.push(r.description),i.push(""),e.primaryAction&&(i.push("### Primary user action (non-negotiable):"),i.push(`- **Core action**: ${e.primaryAction.action}`),i.push(`- **User flow**: ${e.primaryAction.flow}`),i.push(`- **Dashboard must show**: ${e.primaryAction.dashboardSurface}`),i.push(""),i.push("The dashboard is an ACTION surface, not a stats display. Users must be able to complete the core action directly from the dashboard without navigating to a separate page. If this step builds the dashboard, make sure the primary action is front and center with inline forms/buttons \u2014 not behind a link to another page."),i.push(""));let s=["landing","design","dashboard","crud","layout","admin","general","auth"].includes(n);if(e.design&&s?(i.push(_o(e.design,{hasDesignPreset:!!e.landingDesign&&(n==="landing"||n==="design")})),i.push("")):e.design&&!s&&(i.push("### Design tokens (for reference only \u2014 this step is not UI-focused):"),e.design.accentColor&&i.push(`- Accent color: ${e.design.accentColor}`),e.design.fonts&&i.push(`- Fonts: ${e.design.fonts.heading} / ${e.design.fonts.body}`),i.push("")),o){let g=Rr(o);if(g.length>0){i.push("### Approved wireframe (MUST READ before writing any files):"),i.push("The user approved a wireframe sketch before building. **Read these files NOW before writing any code for this step:**");for(let y of g){let N=y.replace(o,"").replace(/^\//,"");i.push(`- \`${N}\``)}i.push(""),i.push("The wireframe defines the LAYOUT and INFORMATION HIERARCHY \u2014 what goes where, what's prominent, what's secondary. It includes HTML comments explaining WHY things are placed where they are."),i.push(""),i.push("The wireframe is intentionally rough (grayscale, system fonts). Your job is to:"),i.push("1. **Keep the same layout structure** \u2014 same information hierarchy, same element placement, same sections in the same order"),i.push("2. **Apply the design tokens** \u2014 colors, fonts, shadows, radius from the plan design choices above"),i.push("3. **Elevate the visual quality** \u2014 make it feel designed for THIS specific app, not generic"),i.push("4. **Respect the HTML comments** \u2014 they explain WHY things are placed where they are"),i.push("5. **If the wireframe shows a search bar at the top of the dashboard, your dashboard MUST have a search bar at the top** \u2014 do not rearrange the layout"),i.push("")}}e.roles&&Array.isArray(e.roles)&&e.roles.length>0&&(i.push("### Role system (from plan):"),i.push(`- Roles: ${e.roles.join(", ")}`),i.push(`- Default role for new signups: ${e.defaultRole??e.roles[0]}`),i.push("- Role helpers are in `lib/roles.ts` \u2014 use `getUserRole()` and `hasRole()` for access checks"),i.push("")),e.multiTenant&&(i.push("### Multi-tenant (from plan):"),i.push("- Organization tables are in `db/schema/organization.ts`"),i.push("- Org helpers are in `lib/org.ts` \u2014 use `getCurrentOrg()` to scope queries"),i.push("- All data queries MUST be scoped to the current org (filter by orgId)"),i.push("- Org switcher component is at `components/org-switcher.tsx`"),i.push("- CRITICAL: `getCurrentOrg()` returns null for new users who haven't created an org yet. The dashboard MUST handle this \u2014 if currentOrg is null, redirect to an onboarding page or show an inline 'Create your first team/workspace' form. NEVER call .id on a null org."),i.push("- WARNING: cookies().set() in server actions does NOT work on Cloudflare Workers. Do NOT use setCurrentOrgId() or any cookies().set() call inside server actions. Instead, pass the orgId as a form field or query param, or store the active org in the user's database record."),i.push("")),e.language&&(i.push(`### Language: ${e.language}`),i.push(`ALL user-facing text must be written in ${e.language}:`),i.push("- Page titles, headings, labels, button text, placeholder text"),i.push("- Navigation items, menu labels, footer text"),i.push("- Error messages, success messages, empty states"),i.push("- Landing page copy, marketing text, CTAs"),i.push("- Form labels and validation messages"),i.push("Code (variable names, comments, file names) stays in English."),i.push(`Set the HTML lang attribute to the appropriate locale code for ${e.language}.`),i.push(""));let d=["landing","design","auth","general","crud","dashboard"];e.audienceType&&d.includes(n)&&(e.audienceType==="b2c"?(i.push("### Audience: this app belongs to ONE business. The landing page talks TO their customers."),i.push("- Hero: what the customer gets ('Exceptional catering for your next event'), NOT what the tool does"),i.push("- CTAs: customer action ('Order Catering', 'Book Now'), NOT business action ('Get Started Free')"),i.push("- Testimonials: from customers ('They catered our wedding'), NOT from business owners"),i.push("- Features: customer benefits ('Specify your dietary needs'), NOT business benefits ('Track preferences')"),i.push("- Stats: social proof for customers ('2,400+ events served'), NOT internal metrics ('$48k revenue')"),i.push("- The business name IS the brand. Say it like a business homepage, not a SaaS onboarding."),i.push("")):e.audienceType==="b2b"?(i.push("### Audience: this is a SaaS platform. The landing page pitches TO business owners."),i.push("- Hero: the business pain + solution ('Catering orders managed in one place')"),i.push("- CTAs: business owner action ('Start Free Trial', 'Get Started')"),i.push("- Testimonials: from business owners who use the platform"),i.push("- Features: business benefits ('Track dietary preferences across all orders')"),i.push("- Stats: platform metrics ('500+ businesses', '50K+ orders processed')"),i.push("")):e.audienceType==="internal"&&(i.push("### Audience: internal staff tool. No marketing copy needed."),i.push("- No landing page. Auth page copy is functional: 'Sign in to continue'."),i.push("- Dashboard focuses on operational efficiency, not onboarding or sales."),i.push(""))),t.length>0&&(i.push("### Already completed:"),t.forEach(g=>i.push(`- ${g}`)),i.push(""));let p=e.dataModel?Ur(r,e.dataModel):[];p.length>0&&(i.push("### Data model (from plan):"),p.forEach(g=>{let y=Ct(g),N=Eo(g.fields);i.push(`- **${y}**: ${N}`),i.push(` Schema file: \`db/schema/${y.toLowerCase().replace(/\s+/g,"-")}.ts\``)}),i.push(""));let u=e.pages?Go(r,e.pages):[];if(u.length>0&&(i.push("### Pages to create/update:"),u.forEach(g=>{let y=g.description?` \u2014 ${g.description}`:"";i.push(`- \`${Nr(g)}\`${y}`)}),i.push("")),n==="crud"&&p.length>0&&p.forEach(g=>{let y=Ct(g),N=y.toLowerCase().replace(/\s+/g,"-"),R=N.endsWith("s")?N:`${N}s`;i.push(`### Files for ${y} CRUD:`),i.push(`- List page: \`app/(dashboard)/${R}/page.tsx\` (Server Component)`),i.push(`- Detail page: \`app/(dashboard)/${R}/[id]/page.tsx\``),i.push(`- Create page: \`app/(dashboard)/${R}/new/page.tsx\``),i.push(`- Server Actions: \`app/(dashboard)/${R}/actions.ts\``),i.push(`- DataTable columns: \`components/${N}-table-columns.tsx\``),i.push(`- Form: \`components/${N}-form.tsx\``),i.push("")}),(n==="landing"||n==="design")&&e.landingDesign){let g=Ae(e.landingDesign);g&&(i.push("### Design preset blueprint (follow this closely for the hero section):"),i.push(""),i.push(`Using preset: **${g.title}** (${g.category})`),i.push(""),i.push("The following is a detailed design specification for the hero section. Adapt it to this app's branding and content \u2014 use the layout structure, color system, typography choices, animations, and CSS patterns described below, but replace placeholder names, copy, and branding with this app's actual content."),i.push(""),i.push("---"),i.push(g.prompt),i.push("---"),i.push(""),i.push("**Adaptation rules**: Replace all brand names, headlines, and copy with content specific to this app. Keep the visual structure (layout, spacing, color relationships, animation patterns). Replace any external video/image URLs with CSS gradients, animated SVG patterns, or pure CSS backgrounds \u2014 do NOT use Unsplash stock photos in the hero. Use the fonts specified in the preset OR the plan's design.fonts \u2014 preset fonts take priority if specified."),i.push(""))}let h=e.appStyle;if(h&&s){let g=sr(h,n);if(g){let y=ke(h),N=bt(h);i.push(`### App style: ${y?.name??h}`),i.push(""),i.push(`Applying the **${y?.name}** app style across this app. Follow these design specifications for consistent, brand-quality UI. Where the plan's design tokens (accentColor, fonts, borderRadius) conflict with the app style, **plan tokens take priority** \u2014 they are the user's explicit choices.`),N?.fonts&&i.push(`
12387
- **Fonts**: Use \`${N.fonts.heading}\` for headings and \`${N.fonts.body}\` for body text (Google Fonts equivalents if the originals are proprietary).`),i.push(""),i.push(g),i.push("")}}let m=r.integrationId?Ve(r.integrationId):void 0;if(m){let g=qe(m.id);if(i.push("### Integration blueprint (follow this closely):"),i.push(""),i.push(`Using integration: **${m.name}** (${m.category})`),g?.docsUrl&&i.push(`Official docs: ${g.docsUrl}`),g?.envVars?.length){i.push(""),i.push("**Required environment variables:**");for(let y of g.envVars)i.push(`- \`${y.key}\`: ${y.description} \u2014 Get it at ${y.setupUrl}`);i.push(""),i.push("**IMPORTANT: Never ask the user to paste API keys in chat.** Direct them to set keys in the Mistflow dashboard (Project Settings > Environment Variables) or at app.mistflow.ai. Use mist_config resource='env' action='list' to check if keys are set (has_value: true/false). Only proceed with deploy once all required keys are set.")}g?.packages?.length&&(i.push(""),i.push(`**Packages to install:** \`npm install ${g.packages.join(" ")}\``)),i.push(""),i.push("---"),i.push(m.prompt),i.push("---"),i.push(""),i.push("**Adaptation rules**: Follow the file structure and code patterns above. Replace placeholder values (app names, URLs, copy) with this app's specific content. Use the app's existing data models and route structure. Never ask the user to paste API keys or secrets in the chat. Direct them to set keys in the Mistflow dashboard."),i.push("")}let{reminders:b,skill:f}=await Oo(n);return i.push(b),i.push(""),f&&(i.push(`### ${n} reference:`),i.push(f),i.push("")),i.join(`
12388
- `)}async function Er(r){let{projectPath:e,step:t}=r,a=Ro(e??process.cwd()),n=Uo(a);if(!n)return ge(a);let o=n.plan;if(!o||!o.steps||o.steps.length===0)return c("No project plan found. Start by describing your app idea first \u2014 the AI will create a plan for you.",!0);let i,l=o.steps.find(k=>k.status==="in_progress");if(l){let k=o.steps.findIndex($=>$.number===l.number);k!==-1&&(o.steps[k].status="completed",i=`Auto-completed step ${l.number} (${l.name})`,Lr(a,n))}let s;if(t!==void 0){if(s=o.steps.find(k=>k.number===t),!s)return c(`Step ${t} not found. The plan has ${o.steps.length} steps (numbered ${o.steps[0].number} to ${o.steps[o.steps.length-1].number}).`,!0)}else if(s=o.steps.find(k=>k.status!=="completed"),!s)return c(JSON.stringify({message:"All plan steps are completed!",completedSteps:o.steps.map(k=>k.name),nextAction:"NEXT: Deploy the app now. Call mist_deploy with action='deploy'. Do NOT suggest localhost or ask the user \u2014 just deploy."}));let d=o.steps.filter(k=>k.status==="completed").map(k=>`Step ${k.number}: ${k.name}`),{readLocalState:p}=await import("./state-manager-ZVLGPYXN.js"),u=p(a),h=Wo(s),m=[];if((h==="crud"||h==="schema")&&o.dataModel&&s.entities&&s.entities.length>0){let k=Ur(s,o.dataModel);for(let $ of k){let U=Ct($);try{let E=($.fields||[]).map(A=>typeof A=="string"?{name:A,type:"text"}:{name:A.name,type:Ho(A.type),required:A.required!==!1});if(E.length===0)continue;let j=n.dbProvider==="neon"?"nextjs-neon":"nextjs",J=await qa(j,U,E),G=0,V=0;for(let A of J.files){let q=Tt(a,A.path);if(sa(q)){V++;continue}Mo(Lo(q),{recursive:!0}),la(q,A.content),G++}let ie=Tt(a,"db","index.ts");if(sa(ie)){let A=Fr(ie,"utf-8");A.includes(J.dbExport)||la(ie,A.trimEnd()+`
12389
- `+J.dbExport+`
12390
- `)}G>0?m.push(`${J.entityPascal} CRUD (${G} new files${V>0?`, ${V} existing skipped`:""})`):V>0&&m.push(`${J.entityPascal} CRUD (all ${V} files already exist \u2014 skipped)`)}catch(E){console.error(`Module generation failed for ${U} (non-fatal):`,E instanceof Error?E.message:E)}}}let b=await jo(s,o,d,null,h,a),f=o.steps.findIndex(k=>k.number===s.number);if(f!==-1&&(n.plan.steps[f].status="in_progress",Lr(a,n)),u&&n.projectId){let{syncRemoteState:k}=await import("./state-manager-ZVLGPYXN.js");k(n.projectId,u).catch(()=>{})}let g=o.steps.every(k=>k.status==="completed"||k.number===s.number),y;if(g){let k=o.primaryAction?.action??"the core action",$=o.primaryAction?.flow??"sign up \u2192 reach dashboard \u2192 complete primary action";y=`THIS IS THE LAST STEP. Rules for speed:
10817
+ - Server Components by default, "use client" only when interactivity is needed`,skill:""}}}async function Yn(r,e,t,a,n,o){let i=[];i.push(`## Step ${r.number}: ${r.name}`),i.push(""),i.push("### What to build:"),i.push(r.description),i.push(""),e.primaryAction&&(i.push("### Primary user action (non-negotiable):"),i.push(`- **Core action**: ${e.primaryAction.action}`),i.push(`- **User flow**: ${e.primaryAction.flow}`),i.push(`- **Dashboard must show**: ${e.primaryAction.dashboardSurface}`),i.push(""),i.push("The dashboard is an ACTION surface, not a stats display. Users must be able to complete the core action directly from the dashboard without navigating to a separate page. If this step builds the dashboard, make sure the primary action is front and center with inline forms/buttons \u2014 not behind a link to another page."),i.push(""));let l=["landing","design","dashboard","crud","layout","admin","general","auth"].includes(n);if(e.design&&l?(i.push(Kn(e.design,{hasDesignPreset:!!e.landingDesign&&(n==="landing"||n==="design")})),i.push("")):e.design&&!l&&(i.push("### Design tokens (for reference only \u2014 this step is not UI-focused):"),e.design.accentColor&&i.push(`- Accent color: ${e.design.accentColor}`),e.design.fonts&&i.push(`- Fonts: ${e.design.fonts.heading} / ${e.design.fonts.body}`),i.push("")),o){let g=Ur(o);if(g.length>0){i.push("### Approved wireframe (MUST READ before writing any files):"),i.push("The user approved a wireframe sketch before building. **Read these files NOW before writing any code for this step:**");for(let w of g){let P=w.replace(o,"").replace(/^\//,"");i.push(`- \`${P}\``)}i.push(""),i.push("The wireframe defines the LAYOUT and INFORMATION HIERARCHY \u2014 what goes where, what's prominent, what's secondary. It includes HTML comments explaining WHY things are placed where they are."),i.push(""),i.push("The wireframe is intentionally rough (grayscale, system fonts). Your job is to:"),i.push("1. **Keep the same layout structure** \u2014 same information hierarchy, same element placement, same sections in the same order"),i.push("2. **Apply the design tokens** \u2014 colors, fonts, shadows, radius from the plan design choices above"),i.push("3. **Elevate the visual quality** \u2014 make it feel designed for THIS specific app, not generic"),i.push("4. **Respect the HTML comments** \u2014 they explain WHY things are placed where they are"),i.push("5. **If the wireframe shows a search bar at the top of the dashboard, your dashboard MUST have a search bar at the top** \u2014 do not rearrange the layout"),i.push("")}}e.roles&&Array.isArray(e.roles)&&e.roles.length>0&&(i.push("### Role system (from plan):"),i.push(`- Roles: ${e.roles.join(", ")}`),i.push(`- Default role for new signups: ${e.defaultRole??e.roles[0]}`),i.push("- Role helpers are in `lib/roles.ts` \u2014 use `getUserRole()` and `hasRole()` for access checks"),i.push("")),e.multiTenant&&(i.push("### Multi-tenant (from plan):"),i.push("- Organization tables are in `db/schema/organization.ts`"),i.push("- Org helpers are in `lib/org.ts` \u2014 use `getCurrentOrg()` to scope queries"),i.push("- All data queries MUST be scoped to the current org (filter by orgId)"),i.push("- Org switcher component is at `components/org-switcher.tsx`"),i.push("- CRITICAL: `getCurrentOrg()` returns null for new users who haven't created an org yet. The dashboard MUST handle this \u2014 if currentOrg is null, redirect to an onboarding page or show an inline 'Create your first team/workspace' form. NEVER call .id on a null org."),i.push("- WARNING: cookies().set() in server actions does NOT work on Cloudflare Workers. Do NOT use setCurrentOrgId() or any cookies().set() call inside server actions. Instead, pass the orgId as a form field or query param, or store the active org in the user's database record."),i.push("")),e.language&&(i.push(`### Language: ${e.language}`),i.push(`ALL user-facing text must be written in ${e.language}:`),i.push("- Page titles, headings, labels, button text, placeholder text"),i.push("- Navigation items, menu labels, footer text"),i.push("- Error messages, success messages, empty states"),i.push("- Landing page copy, marketing text, CTAs"),i.push("- Form labels and validation messages"),i.push("Code (variable names, comments, file names) stays in English."),i.push(`Set the HTML lang attribute to the appropriate locale code for ${e.language}.`),i.push(""));let d=["landing","design","auth","general","crud","dashboard"];e.audienceType&&d.includes(n)&&(e.audienceType==="b2c"?(i.push("### Audience: this app belongs to ONE business. The landing page talks TO their customers."),i.push("- Hero: what the customer gets ('Exceptional catering for your next event'), NOT what the tool does"),i.push("- CTAs: customer action ('Order Catering', 'Book Now'), NOT business action ('Get Started Free')"),i.push("- Testimonials: from customers ('They catered our wedding'), NOT from business owners"),i.push("- Features: customer benefits ('Specify your dietary needs'), NOT business benefits ('Track preferences')"),i.push("- Stats: social proof for customers ('2,400+ events served'), NOT internal metrics ('$48k revenue')"),i.push("- The business name IS the brand. Say it like a business homepage, not a SaaS onboarding."),i.push("")):e.audienceType==="b2b"?(i.push("### Audience: this is a SaaS platform. The landing page pitches TO business owners."),i.push("- Hero: the business pain + solution ('Catering orders managed in one place')"),i.push("- CTAs: business owner action ('Start Free Trial', 'Get Started')"),i.push("- Testimonials: from business owners who use the platform"),i.push("- Features: business benefits ('Track dietary preferences across all orders')"),i.push("- Stats: platform metrics ('500+ businesses', '50K+ orders processed')"),i.push("")):e.audienceType==="internal"&&(i.push("### Audience: internal staff tool. No marketing copy needed."),i.push("- No landing page. Auth page copy is functional: 'Sign in to continue'."),i.push("- Dashboard focuses on operational efficiency, not onboarding or sales."),i.push(""))),t.length>0&&(i.push("### Already completed:"),t.forEach(g=>i.push(`- ${g}`)),i.push(""));let u=e.dataModel?Or(r,e.dataModel):[];u.length>0&&(i.push("### Data model (from plan):"),u.forEach(g=>{let w=Bt(g),P=zn(g.fields);i.push(`- **${w}**: ${P}`),i.push(` Schema file: \`db/schema/${w.toLowerCase().replace(/\s+/g,"-")}.ts\``)}),i.push(""));let p=e.pages?Vn(r,e.pages):[];p.length>0&&(i.push("### Pages to create/update:"),p.forEach(g=>{let w=g.description?` \u2014 ${g.description}`:"";i.push(`- \`${Wr(g)}\`${w}`)}),i.push("")),n==="crud"&&u.length>0&&u.forEach(g=>{let w=Bt(g),P=w.toLowerCase().replace(/\s+/g,"-"),D=P.endsWith("s")?P:`${P}s`;i.push(`### Files for ${w} CRUD:`),i.push(`- List page: \`app/(dashboard)/${D}/page.tsx\` (Server Component)`),i.push(`- Detail page: \`app/(dashboard)/${D}/[id]/page.tsx\``),i.push(`- Create page: \`app/(dashboard)/${D}/new/page.tsx\``),i.push(`- Server Actions: \`app/(dashboard)/${D}/actions.ts\``),i.push(`- DataTable columns: \`components/${P}-table-columns.tsx\``),i.push(`- Form: \`components/${P}-form.tsx\``),i.push("")});let h=e.appStyle;if(h&&l){let g=pr(h,n);if(g){let w=me(h),P=He(h);i.push(`### App style: ${w?.name??h}`),i.push(""),i.push(`Applying the **${w?.name}** app style across this app. Follow these design specifications for consistent, brand-quality UI. The app style defines the visual identity (colors, fonts, spacing). All UI elements must use the project's CSS custom properties (--color-primary, --color-background, etc.) and the fonts configured in layout.tsx.`),P?.fonts&&i.push(`
10818
+ **Fonts**: Use \`${P.fonts.heading}\` for headings and \`${P.fonts.body}\` for body text (Google Fonts equivalents if the originals are proprietary).`),i.push(""),i.push(g),i.push("")}}if((n==="landing"||n==="design")&&e.landingDesign){let g=De(e.landingDesign);g&&(i.push("### Layout preset: "+g.title),i.push(""),i.push(`Using layout preset: **${g.title}** (${g.category})`),i.push(""),i.push("The following describes the STRUCTURAL layout, animation patterns, and section arrangement for the landing page. Use this as the skeleton. All colors, fonts, and visual styling come from the project's design system and CSS custom properties (defined in globals.css and layout.tsx). Do NOT hardcode any colors or font names."),i.push(""),i.push("---"),i.push(g.prompt),i.push("---"),i.push(""))}let m=r.integrationId?Ve(r.integrationId):void 0;if(m){let g=qe(m.id);if(i.push("### Integration blueprint (follow this closely):"),i.push(""),i.push(`Using integration: **${m.name}** (${m.category})`),g?.docsUrl&&i.push(`Official docs: ${g.docsUrl}`),g?.envVars?.length){i.push(""),i.push("**Required environment variables:**");for(let w of g.envVars)i.push(`- \`${w.key}\`: ${w.description} \u2014 Get it at ${w.setupUrl}`);i.push(""),i.push("**IMPORTANT: Never ask the user to paste API keys in chat.** Direct them to set keys in the Mistflow dashboard (Project Settings > Environment Variables) or at app.mistflow.ai. Use mist_config resource='env' action='list' to check if keys are set (has_value: true/false). Only proceed with deploy once all required keys are set.")}g?.packages?.length&&(i.push(""),i.push(`**Packages to install:** \`npm install ${g.packages.join(" ")}\``)),i.push(""),i.push("---"),i.push(m.prompt),i.push("---"),i.push(""),i.push("**Adaptation rules**: Follow the file structure and code patterns above. Replace placeholder values (app names, URLs, copy) with this app's specific content. Use the app's existing data models and route structure. Never ask the user to paste API keys or secrets in the chat. Direct them to set keys in the Mistflow dashboard."),i.push("")}let{reminders:f,skill:b}=await Jn(n);return i.push(f),i.push(""),b&&(i.push(`### ${n} reference:`),i.push(b),i.push("")),i.join(`
10819
+ `)}async function _r(r){let{projectPath:e,step:t}=r,a=Gn(e??process.cwd()),n=jn(a);if(!n)return ge(a);let o=n.plan;if(!o||!o.steps||o.steps.length===0)return c("No project plan found. Start by describing your app idea first \u2014 the AI will create a plan for you.",!0);let i,s=o.steps.find(S=>S.status==="in_progress");if(s){let S=o.steps.findIndex(U=>U.number===s.number);S!==-1&&(o.steps[S].status="completed",i=`Auto-completed step ${s.number} (${s.name})`,Hr(a,n))}let l;if(t!==void 0){if(l=o.steps.find(S=>S.number===t),!l)return c(`Step ${t} not found. The plan has ${o.steps.length} steps (numbered ${o.steps[0].number} to ${o.steps[o.steps.length-1].number}).`,!0)}else if(l=o.steps.find(S=>S.status!=="completed"),!l)return c(JSON.stringify({message:"All plan steps are completed!",completedSteps:o.steps.map(S=>S.name),nextAction:"NEXT: Deploy the app now. Call mist_deploy with action='deploy'. Do NOT suggest localhost or ask the user \u2014 just deploy."}));let d=o.steps.filter(S=>S.status==="completed").map(S=>`Step ${S.number}: ${S.name}`),{readLocalState:u}=await import("./state-manager-73ZUDKOP.js"),p=u(a),h=qn(l),m=[];if((h==="crud"||h==="schema")&&o.dataModel&&l.entities&&l.entities.length>0){let S=Or(l,o.dataModel);for(let U of S){let ne=Bt(U);try{let G=(U.fields||[]).map(F=>typeof F=="string"?{name:F,type:"text"}:{name:F.name,type:$n(F.type),required:F.required!==!1});if(G.length===0)continue;let J=n.dbProvider==="neon"?"nextjs-neon":"nextjs",ee=await Ja(J,ne,G),q=0,Y=0;for(let F of ee.files){let N=Pt(a,F.path);if(da(N)){Y++;continue}Hn(Wn(N),{recursive:!0}),ca(N,F.content),q++}let le=Pt(a,"db","index.ts");if(da(le)){let F=Gr(le,"utf-8");F.includes(ee.dbExport)||ca(le,F.trimEnd()+`
10820
+ `+ee.dbExport+`
10821
+ `)}q>0?m.push(`${ee.entityPascal} CRUD (${q} new files${Y>0?`, ${Y} existing skipped`:""})`):Y>0&&m.push(`${ee.entityPascal} CRUD (all ${Y} files already exist \u2014 skipped)`)}catch(G){console.error(`Module generation failed for ${ne} (non-fatal):`,G instanceof Error?G.message:G)}}}let f=await Yn(l,o,d,null,h,a),b=o.steps.findIndex(S=>S.number===l.number);if(b!==-1&&(n.plan.steps[b].status="in_progress",Hr(a,n)),p&&n.projectId){let{syncRemoteState:S}=await import("./state-manager-73ZUDKOP.js");S(n.projectId,p).catch(()=>{})}let g=o.steps.every(S=>S.status==="completed"||S.number===l.number),w;if(g){let S=o.primaryAction?.action??"the core action",U=o.primaryAction?.flow??"sign up \u2192 reach dashboard \u2192 complete primary action";w=`THIS IS THE LAST STEP. Rules for speed:
12391
10822
 
12392
10823
  1. Write ALL files using PARALLEL tool calls \u2014 batch multiple Write/Edit calls in a single message.
12393
10824
  2. Do NOT read files you already know (AGENTS.md, CLAUDE.md, mistflow.json, middleware.ts, lib/auth.ts, lib/db.ts).
@@ -12396,106 +10827,106 @@ Environment variables needed:
12396
10827
  - app/page.tsx must be a real landing page, NOT a redirect to /login
12397
10828
  - middleware.ts must have "/" in PUBLIC_EXACT or PUBLIC_PREFIXES
12398
10829
  - Forms must use server actions (actions.ts with 'use server'), NOT setTimeout/simulate
12399
- 5. Call mist_build with action='build' to verify a clean production build, then call mist_deploy with action='deploy' to ship it.`}else y=`IMPLEMENT THIS STEP NOW. Rules for speed:
10830
+ 5. Call mist_build with action='build' to verify a clean production build, then call mist_deploy with action='deploy' to ship it.`}else w=`IMPLEMENT THIS STEP NOW. Rules for speed:
12400
10831
 
12401
10832
  1. Write ALL files for this step using PARALLEL tool calls \u2014 batch multiple Write/Edit calls in a single message. Do NOT write one file at a time.
12402
10833
  2. Do NOT read files you already know: AGENTS.md, CLAUDE.md, mistflow.json, middleware.ts, lib/auth.ts, lib/db.ts, drizzle.config.ts \u2014 these haven't changed.
12403
10834
  3. Only read a file if you need to MODIFY it (e.g. sidebar.tsx to add a nav link, db/index.ts to add an export).
12404
- 4. After writing ALL files, call mist_build with action='implement' to move to the next step. The previous step is auto-marked complete \u2014 do NOT call implement twice.`;let N=JSON.stringify({instruction:b,step:{number:s.number,name:s.name,description:s.description,status:"in_progress"},...i?{autoCompleted:i}:{},...m.length>0?{generatedModules:m,generatedNote:"These CRUD modules were pre-generated. Review and customize them instead of writing from scratch. Focus on: business logic in actions.ts, UI polish, and wiring navigation."}:{},progress:`${d.length}/${o.steps.length} steps done`,nextAction:y});return await No(3e3)?Ie("http://localhost:3000",N):c(N)}import{z as da}from"zod";import{resolve as zo}from"path";import{execFileSync as $o}from"child_process";var Gl=da.object({projectPath:da.string().optional().describe("Path to the project directory (default: current working directory)"),buildOutput:da.string().optional().describe("Build output to parse (if not provided, runs npm run build)")});function ca(r){let e=[],t=/([^\s(]+)\((\d+),(\d+)\):\s*error\s+(TS\d+):\s*(.+)/g,a;for(;(a=t.exec(r))!==null;){let[,s,d,p,u,h]=a;e.push({file:s,line:parseInt(d,10),column:parseInt(p,10),message:`${u}: ${h}`,humanMessage:`There is a type error in ${s} on line ${d}: ${h}`,suggestion:`Check line ${d} in ${s}. ${u==="TS2345"?"The types of the arguments do not match.":`Fix the ${u} error.`}`})}let n=/(?:Error:\s*)?\.\/([^\s:]+):(\d+):(\d+)\s*\n\s*(.+)/g;for(;(a=n.exec(r))!==null;){let[,s,d,p,u]=a;e.some(h=>h.file===s&&h.line===parseInt(d,10))||e.push({file:s,line:parseInt(d,10),column:parseInt(p,10),message:u,humanMessage:`There is an error in ${s} on line ${d}: ${u.trim()}`,suggestion:`Check line ${d} in ${s} and fix the issue.`})}let o=/Module not found:\s*(?:Error:\s*)?Can't resolve ['"]([^'"]+)['"]\s*(?:in\s*['"]?([^'"]+)['"]?)?/g;for(;(a=o.exec(r))!==null;){let[,s,d]=a;e.push({file:d,message:`Module not found: ${s}`,humanMessage:`The file ${d??"your project"} is trying to import '${s}' which is not installed.`,suggestion:`Run npm install ${s}`})}let i=/Package subpath ['"]([^'"]+)['"] is not defined by "exports" in .*?node_modules\/([^/]+(?:\/[^/]+)?)\//g;for(;(a=i.exec(r))!==null;){let[,s,d]=a;e.push({message:`ERR_PACKAGE_PATH_NOT_EXPORTED: ${d}${s}`,humanMessage:`The package '${d}' does not export the subpath '${s}'. This is usually caused by a version conflict between packages that depend on different major versions of '${d}'.`,suggestion:`Add '${d}' at the version that exports '${s}' as an optionalDependency in package.json (this pins it at root level and lets the other version nest). Then delete node_modules and package-lock.json, and run npm install.`})}let l=/SyntaxError:\s*([^\s:]+):\s*(.+?)\s*\((\d+):(\d+)\)/g;for(;(a=l.exec(r))!==null;){let[,s,d,p,u]=a;e.some(h=>h.file===s&&h.line===parseInt(p,10))||e.push({file:s,line:parseInt(p,10),column:parseInt(u,10),message:`SyntaxError: ${d}`,humanMessage:`There is a syntax error in ${s} on line ${p}.`,suggestion:`Check line ${p} in ${s} for a missing closing bracket or unexpected token.`})}return e}async function Hr(r){let{projectPath:e,buildOutput:t}=r,a=zo(e??process.cwd()),n=t??"";if(!t)try{return $o("npm",["run","build"],{cwd:a,stdio:["pipe","pipe","pipe"],timeout:12e4}),c(JSON.stringify({errors:[],rawOutput:"",message:"Build succeeded with no errors."}))}catch(i){let l=i instanceof Error&&"stderr"in i?String(i.stderr):"",s=i instanceof Error&&"stdout"in i?String(i.stdout):"";n=l+`
12405
- `+s}let o=ca(n);return o.length===0?c(JSON.stringify({errors:[],rawOutput:n.slice(0,2e3),message:"Build failed but I could not extract specific errors. Here is the raw output."})):c(JSON.stringify({errors:o,rawOutput:n.slice(0,2e3),message:`Found ${o.length} error${o.length===1?"":"s"} in the build output.`}))}import{existsSync as pa,readFileSync as ua}from"fs";import{join as We}from"path";function Vo(r){let e=We(r,"mistflow.json");if(!pa(e))return null;try{return JSON.parse(ua(e,"utf-8"))}catch{return null}}async function Ye(r,e){try{let t=await fetch(r,{headers:e??{},redirect:"follow",signal:AbortSignal.timeout(15e3)}),a=await t.text();return{status:t.status,body:a,setCookie:t.headers.get("set-cookie")??void 0}}catch(t){return{status:0,body:String(t)}}}async function Gr(r,e,t){try{let a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",...t??{}},body:JSON.stringify(e),redirect:"follow",signal:AbortSignal.timeout(15e3)}),n=await a.text(),o;try{o=JSON.parse(n)}catch{}return{status:a.status,body:n,json:o,setCookie:a.headers.get("set-cookie")??void 0}}catch(a){return{status:0,body:String(a)}}}async function Wr(r){let e=r.projectPath??process.cwd(),t=Vo(e),a=r.url;if(a||(a=t?.deploy?.url),!a)return c("No deploy URL found. Deploy the app first with mist_deploy, then call mist_build action='qa'.",!0);let n=t?.plan,o=[],i=`qa-${Date.now()}@mistflow.dev`,l="TestPass123!",s=await Ye(`${a}/api/health`);s.status===200?o.push({check:"Health endpoint",status:"pass",detail:"Returns 200"}):o.push({check:"Health endpoint",status:"fail",detail:`Returns ${s.status}`,fix:"The worker is not running or crashed on startup. Check app/api/health/route.ts exists and the build succeeded."});let d=await Ye(a);d.status===200&&d.body.length>2e3?d.body.includes("Sign in")&&d.body.includes("password")&&!d.body.includes("hero")&&!d.body.includes("Get Started")&&!d.body.includes("features")?o.push({check:"Landing page",status:"fail",detail:"Root URL shows login form instead of landing page",fix:"Check middleware.ts \u2014 '/' must be in PUBLIC_EXACT. Check app/page.tsx \u2014 must be a landing page, not a redirect to /login."}):o.push({check:"Landing page",status:"pass",detail:`Loads (${d.body.length} bytes)`}):d.status===200?o.push({check:"Landing page",status:"fail",detail:`Page is very small (${d.body.length} bytes) \u2014 likely a redirect or placeholder`,fix:"Check app/page.tsx \u2014 should be a full landing page with hero, features, CTA."}):o.push({check:"Landing page",status:"fail",detail:`Returns ${d.status}`,fix:"Root page is broken. Check app/page.tsx and middleware.ts."});let p=await Ye(`${a}/api/auth/ok`);p.status===200?o.push({check:"Auth system",status:"pass",detail:"Better Auth running"}):o.push({check:"Auth system",status:"fail",detail:`Auth endpoint returns ${p.status}`,fix:"Better Auth is not working. Check lib/auth.ts, lib/db.ts, and that your database env vars are set (TURSO_URL/TURSO_AUTH_TOKEN for Turso, DATABASE_URL for Neon)."});let u={Origin:a,Referer:`${a}/register`},h=await Gr(`${a}/api/auth/sign-up/email`,{name:"QA Test",email:i,password:l},u);if(h.status===200&&(h.json?.user||h.json?.token))o.push({check:"Signup",status:"pass",detail:`User created (${i})`});else{let U=h.json?.message??h.json?.error??h.body.slice(0,100);o.push({check:"Signup",status:"fail",detail:`HTTP ${h.status}: ${U}`,fix:"Signup failed. Check: 1) Database tables exist (auth schema pushed?). 2) lib/auth.ts config. 3) db/schema/auth.ts has all Better Auth columns including admin plugin fields (role, banned, ban_reason, ban_expires). 4) lib/db.ts uses fetch: globalThis.fetch."})}let m=await Gr(`${a}/api/auth/sign-in/email`,{email:i,password:l},u);if(m.status===200&&(m.json?.user||m.json?.token))o.push({check:"Login",status:"pass",detail:"Session created"});else{let U=m.json?.message??m.json?.error??m.body.slice(0,100);String(U).toLowerCase().includes("not verified")?o.push({check:"Login",status:"pass",detail:"Email verification required (auth security working)"}):o.push({check:"Login",status:"fail",detail:`HTTP ${m.status}: ${U}`,fix:"Login failed after successful signup. Check auth configuration."})}let b=m.setCookie??h.setCookie??"",f=b?{Cookie:b}:{},g=await Ye(`${a}/dashboard`,f);g.status===200&&g.body.length>1e3?o.push({check:"Dashboard",status:"pass",detail:`Loads (${g.body.length} bytes)`}):o.push({check:"Dashboard",status:"fail",detail:`HTTP ${g.status}, ${g.body.length} bytes`,fix:"Dashboard page doesn't load. Check app/(dashboard)/dashboard/page.tsx exists and the dashboard layout doesn't crash (common: getCurrentOrg() returning null for new users)."});let y=[We(e,"components","sidebar.tsx"),We(e,"components","layout","sidebar.tsx"),We(e,"components","topnav.tsx")].find(U=>pa(U));if(y){let j=(ua(y,"utf-8").match(/href:\s*"([^"]+)"/g)??[]).map(V=>V.replace(/href:\s*"/,"").replace(/"$/,"")).filter(V=>!V.startsWith("/api")&&!V.includes("[")&&V!=="/dashboard"),J=0,G=[];for(let V of j.slice(0,6))(await Ye(`${a}${V}`,f)).status===500&&(J++,G.push(V));J>0?o.push({check:"Business pages",status:"fail",detail:`${J} page(s) return 500: ${G.join(", ")}`,fix:"These pages crash when loading data. Common causes: 1) Database tables missing \u2014 check that ALL schema files in db/schema/ match what's in the database. Run 'npm run db:push' or redeploy. 2) Wrong ORM dialect \u2014 if using Neon (Postgres), schema files must use pgTable from drizzle-orm/pg-core, NOT sqliteTable. 3) Server component crashes \u2014 check the page.tsx server component for unhandled null/undefined."}):j.length>0&&o.push({check:"Business pages",status:"pass",detail:`All ${j.length} dashboard pages load without errors`})}let N=[We(e,"components","sidebar.tsx"),We(e,"components","layout","sidebar.tsx"),We(e,"components","topnav.tsx")].find(U=>pa(U));if(N){let j=(ua(N,"utf-8").match(/href:\s*"([^"]+)"/g)??[]).map(G=>G.replace(/href:\s*"/,"").replace(/"$/,"")).filter(G=>!G.startsWith("/api")&&!G.includes("[")),J=0;for(let G of j.slice(0,8))(await Ye(`${a}${G}`,f)).status===404&&(J++,o.push({check:`Nav: ${G}`,status:"fail",detail:"HTTP 404",fix:`Page ${G} not found. Create the page or remove the nav link.`}));J===0&&j.length>0&&o.push({check:"Nav links",status:"pass",detail:`All ${j.length} links resolve`})}let R=o.filter(U=>U.status==="fail"),k=o.filter(U=>U.status==="pass");if(R.length===0)return c(JSON.stringify({status:"pass",message:`QA passed \u2014 all ${o.length} checks OK. The app is working correctly.`,url:a,checks:o}));let $=R.map((U,E)=>`${E+1}. **${U.check}**: ${U.detail}
12406
- Fix: ${U.fix}`).join(`
10835
+ 4. After writing ALL files, call mist_build with action='implement' to move to the next step. The previous step is auto-marked complete \u2014 do NOT call implement twice.`;let P=JSON.stringify({instruction:f,step:{number:l.number,name:l.name,description:l.description,status:"in_progress"},...i?{autoCompleted:i}:{},...m.length>0?{generatedModules:m,generatedNote:"These CRUD modules were pre-generated. Review and customize them instead of writing from scratch. Focus on: business logic in actions.ts, UI polish, and wiring navigation."}:{},progress:`${d.length}/${o.steps.length} steps done`,nextAction:w});return await _n(3e3)?Be("http://localhost:3000",P):c(P)}import{z as pa}from"zod";import{resolve as Qn}from"path";import{execFileSync as Xn}from"child_process";var Yl=pa.object({projectPath:pa.string().optional().describe("Path to the project directory (default: current working directory)"),buildOutput:pa.string().optional().describe("Build output to parse (if not provided, runs npm run build)")});function ua(r){let e=[],t=/([^\s(]+)\((\d+),(\d+)\):\s*error\s+(TS\d+):\s*(.+)/g,a;for(;(a=t.exec(r))!==null;){let[,l,d,u,p,h]=a;e.push({file:l,line:parseInt(d,10),column:parseInt(u,10),message:`${p}: ${h}`,humanMessage:`There is a type error in ${l} on line ${d}: ${h}`,suggestion:`Check line ${d} in ${l}. ${p==="TS2345"?"The types of the arguments do not match.":`Fix the ${p} error.`}`})}let n=/(?:Error:\s*)?\.\/([^\s:]+):(\d+):(\d+)\s*\n\s*(.+)/g;for(;(a=n.exec(r))!==null;){let[,l,d,u,p]=a;e.some(h=>h.file===l&&h.line===parseInt(d,10))||e.push({file:l,line:parseInt(d,10),column:parseInt(u,10),message:p,humanMessage:`There is an error in ${l} on line ${d}: ${p.trim()}`,suggestion:`Check line ${d} in ${l} and fix the issue.`})}let o=/Module not found:\s*(?:Error:\s*)?Can't resolve ['"]([^'"]+)['"]\s*(?:in\s*['"]?([^'"]+)['"]?)?/g;for(;(a=o.exec(r))!==null;){let[,l,d]=a;e.push({file:d,message:`Module not found: ${l}`,humanMessage:`The file ${d??"your project"} is trying to import '${l}' which is not installed.`,suggestion:`Run npm install ${l}`})}let i=/Package subpath ['"]([^'"]+)['"] is not defined by "exports" in .*?node_modules\/([^/]+(?:\/[^/]+)?)\//g;for(;(a=i.exec(r))!==null;){let[,l,d]=a;e.push({message:`ERR_PACKAGE_PATH_NOT_EXPORTED: ${d}${l}`,humanMessage:`The package '${d}' does not export the subpath '${l}'. This is usually caused by a version conflict between packages that depend on different major versions of '${d}'.`,suggestion:`Add '${d}' at the version that exports '${l}' as an optionalDependency in package.json (this pins it at root level and lets the other version nest). Then delete node_modules and package-lock.json, and run npm install.`})}let s=/SyntaxError:\s*([^\s:]+):\s*(.+?)\s*\((\d+):(\d+)\)/g;for(;(a=s.exec(r))!==null;){let[,l,d,u,p]=a;e.some(h=>h.file===l&&h.line===parseInt(u,10))||e.push({file:l,line:parseInt(u,10),column:parseInt(p,10),message:`SyntaxError: ${d}`,humanMessage:`There is a syntax error in ${l} on line ${u}.`,suggestion:`Check line ${u} in ${l} for a missing closing bracket or unexpected token.`})}return e}async function jr(r){let{projectPath:e,buildOutput:t}=r,a=Qn(e??process.cwd()),n=t??"";if(!t)try{return Xn("npm",["run","build"],{cwd:a,stdio:["pipe","pipe","pipe"],timeout:12e4}),c(JSON.stringify({errors:[],rawOutput:"",message:"Build succeeded with no errors."}))}catch(i){let s=i instanceof Error&&"stderr"in i?String(i.stderr):"",l=i instanceof Error&&"stdout"in i?String(i.stdout):"";n=s+`
10836
+ `+l}let o=ua(n);return o.length===0?c(JSON.stringify({errors:[],rawOutput:n.slice(0,2e3),message:"Build failed but I could not extract specific errors. Here is the raw output."})):c(JSON.stringify({errors:o,rawOutput:n.slice(0,2e3),message:`Found ${o.length} error${o.length===1?"":"s"} in the build output.`}))}import{existsSync as Zn,readFileSync as eo}from"fs";import{join as to}from"path";function ao(r){let e=to(r,"mistflow.json");if(!Zn(e))return null;try{return JSON.parse(eo(e,"utf-8"))}catch{return null}}async function zr(r){try{let e=await fetch(r,{redirect:"follow",signal:AbortSignal.timeout(15e3)}),t=await e.text();return{status:e.status,body:t}}catch(e){return{status:0,body:String(e)}}}async function ro(r,e,t){try{let a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",...t??{}},body:JSON.stringify(e),redirect:"follow",signal:AbortSignal.timeout(15e3)}),n=await a.text(),o;try{o=JSON.parse(n)}catch{}return{status:a.status,json:o}}catch{return{status:0}}}async function $r(r){try{let e=await r.screenshot({type:"png"});return Buffer.from(e).toString("base64")}catch{return}}async function Dt(r,e,t){let a=[],n=o=>{o.type()==="error"&&a.push(o.text())};r.on("console",n);try{let o=await t(),i=await $r(r);return{name:e,status:o.pass?"pass":"fail",detail:o.detail,fix:o.fix,screenshot:i,consoleErrors:a.length>0?a:void 0}}catch(o){let i=await $r(r);return{name:e,status:"fail",detail:`Unexpected error: ${o instanceof Error?o.message:String(o)}`,screenshot:i,consoleErrors:a.length>0?a:void 0}}finally{r.removeListener("console",n)}}async function Vr(r){let e=r.projectPath??process.cwd(),t=ao(e),a=r.url;if(a||(a=t?.deploy?.url),!a)return c("No deploy URL found. Deploy the app first with mist_deploy, then call mist_build action='qa'.",!0);a.startsWith("http")||(a=`https://${a}`);let n=t?.projectId,o=[],i=await zr(`${a}/api/health`);if(i.status!==200)return o.push({name:"Health endpoint",status:"fail",detail:`Returns ${i.status}`,fix:"The worker is not running or crashed on startup. Check app/api/health/route.ts exists and the build succeeded."}),it(a,o);o.push({name:"Health endpoint",status:"pass",detail:"Returns 200"});let s=await zr(`${a}/api/auth/ok`);if(s.status!==200)return o.push({name:"Auth system",status:"fail",detail:`Auth endpoint returns ${s.status}`,fix:"Better Auth is not working. Check lib/auth.ts, lib/db.ts, and that your database env vars are set."}),it(a,o);o.push({name:"Auth system",status:"pass",detail:"Better Auth running"});let l,d;if(n){let h=await Ua(n);h&&(l=h.email,d=h.password,console.error("[qa] Using admin credentials from backend"))}if(!l||!d){console.error("[qa] No stored credentials, creating throwaway user"),l=`qa-${Date.now()}@mistflow.dev`,d="TestPass123!";let h={Origin:a,Referer:`${a}/register`},m=await ro(`${a}/api/auth/sign-up/email`,{name:"QA Test",email:l,password:d},h);if(m.status!==200||!m.json?.user&&!m.json?.token){let f=m.json?.message??m.json?.error??"Unknown error";return o.push({name:"Signup",status:"fail",detail:`HTTP ${m.status}: ${f}`,fix:"Signup failed. Check: 1) Database tables exist (auth schema pushed?). 2) lib/auth.ts config. 3) db/schema/auth.ts has all Better Auth columns including admin plugin fields (role, banned, ban_reason, ban_expires)."}),it(a,o)}}let u,p;try{let{getIsolatedContext:h,takeScreenshot:m}=await import("./browser-manager-K5BT5YXO.js"),f=await h();u=f.context,p=f.page}catch{return o.push({name:"Browser",status:"fail",detail:"Playwright not installed. Browser-based QA skipped.",fix:"Run: npx playwright install chromium"}),it(a,o)}try{let h=await Dt(p,"Landing page",async()=>{await p.goto(a,{waitUntil:"domcontentloaded",timeout:3e4}),await p.waitForLoadState("networkidle").catch(()=>{});let f=await p.evaluate(()=>{let g=document.body;if(!g)return"";let w=document.createTreeWalker(g,NodeFilter.SHOW_TEXT),P="",D;for(;D=w.nextNode();){let S=D.parentElement;if(S){let U=window.getComputedStyle(S);U.display!=="none"&&U.visibility!=="hidden"&&parseFloat(U.opacity)>0&&(P+=D.textContent?.trim()+" ")}}return P.trim()});if(f.length<50)return{pass:!1,detail:`Landing page appears blank (${f.length} chars visible). Likely a CSS/JS rendering issue.`,fix:"Common cause: motion/react animations with opacity:0 and whileInView that never trigger on Cloudflare Workers (no Intersection Observer). Replace with CSS animations or set initial={{ opacity: 1 }}."};let b=p.url();return b.includes("/login")||b.includes("/sign-in")?{pass:!1,detail:"Root URL redirects to login instead of showing a landing page",fix:"Check middleware.ts: '/' must be in PUBLIC_EXACT. Check app/page.tsx: must be a landing page, not a redirect."}:{pass:!0,detail:`Renders visible content (${f.length} chars)`}});o.push(h);let m=await Dt(p,"Login",async()=>{await p.goto(`${a}/login`,{waitUntil:"domcontentloaded",timeout:15e3}),await p.waitForLoadState("networkidle").catch(()=>{});let f=p.locator('input[type="email"], input[name="email"], input[placeholder*="email" i]'),b=p.locator('input[type="password"], input[name="password"]');try{await f.first().waitFor({state:"visible",timeout:1e4})}catch{return{pass:!1,detail:"Login page has no visible email input field",fix:"Check app/(auth)/login/page.tsx renders a login form with email and password inputs."}}await f.first().fill(l),await b.first().fill(d),await p.locator('button[type="submit"], button:has-text("Sign in"), button:has-text("Log in"), button:has-text("Login")').first().click();try{await p.waitForURL(w=>!w.pathname.includes("/login"),{timeout:1e4})}catch{let w=await p.locator('[role="alert"], .text-red-500, .text-destructive, [data-error]').first().textContent().catch(()=>null);return{pass:!1,detail:w?`Login failed: ${w}`:"Login did not redirect. Page stayed on /login.",fix:"Check auth configuration. If email verification is required, the seeded admin account may not be verified. Check lib/auth.ts emailVerification settings."}}return{pass:!0,detail:`Logged in, redirected to ${p.url()}`}});if(o.push(m),m.status==="pass"){let f=await Dt(p,"Dashboard",async()=>{p.url().includes("/dashboard")||(await p.goto(`${a}/dashboard`,{waitUntil:"domcontentloaded",timeout:15e3}),await p.waitForLoadState("networkidle").catch(()=>{}));let w=await p.content();return w.length<1e3?{pass:!1,detail:`Dashboard page is very small (${w.length} bytes)`,fix:"Check app/(dashboard)/dashboard/page.tsx exists and the dashboard layout doesn't crash."}:await p.locator('text="Something went wrong"').isVisible().catch(()=>!1)?{pass:!1,detail:"Dashboard shows error boundary",fix:"A server component crashed. Check the page.tsx for unhandled null/undefined or missing database tables."}:{pass:!0,detail:`Loads (${w.length} bytes)`}});o.push(f);let b=await p.evaluate(()=>{let g=[];return document.querySelectorAll("nav a[href], aside a[href]").forEach(P=>{let D=P.getAttribute("href");D&&D.startsWith("/")&&!D.startsWith("/api")&&!D.includes("[")&&D!=="/dashboard"&&D!=="/"&&!D.includes("/login")&&!D.includes("/sign")&&g.push(D)}),[...new Set(g)]});if(b.length>0){let g=0,w=[];for(let P of b.slice(0,8)){let D=await Dt(p,`Page: ${P}`,async()=>{await p.goto(`${a}${P}`,{waitUntil:"domcontentloaded",timeout:15e3}),await p.waitForLoadState("networkidle").catch(()=>{});let S=await p.title(),U=await p.content();return S.toLowerCase().includes("500")||S.toLowerCase().includes("server error")?{pass:!1,detail:"Page returns 500 server error",fix:"Server component crashed. Common causes: 1) Database tables missing. 2) Wrong ORM dialect (pgTable vs sqliteTable). 3) Unhandled null/undefined in server component."}:S.toLowerCase().includes("404")||S.toLowerCase().includes("not found")?{pass:!1,detail:"Page returns 404",fix:`Page ${P} not found. Create the page or remove the nav link.`}:await p.locator('text="Something went wrong"').isVisible().catch(()=>!1)?{pass:!1,detail:"Page shows error boundary",fix:"A server component crashed. Check the page.tsx for unhandled errors."}:U.length<500?{pass:!1,detail:`Page is very small (${U.length} bytes)`,fix:"Page may not have rendered. Check the page component."}:{pass:!0,detail:"Loads without errors"}});D.status==="fail"&&(g++,w.push(P)),o.push(D)}}}}finally{u&&await u.close().catch(()=>{})}if(r.deploymentId){let h=o.filter(b=>b.status==="fail"),m=o.filter(b=>b.status==="pass"),f=Date.now();await Ha(r.deploymentId,{checks:o.map(({screenshot:b,...g})=>g),overall:h.length===0?"pass":"fail",passed:m.length,failed:h.length,duration_ms:Date.now()-f}).catch(()=>{})}return it(a,o)}function it(r,e){let t=e.filter(o=>o.status==="fail"),a=e.filter(o=>o.status==="pass"),n=[];if(t.length===0)n.push({type:"text",text:JSON.stringify({status:"pass",message:`QA passed. All ${e.length} checks OK. The app is working correctly.`,url:r,checks:e.map(({screenshot:o,...i})=>i)})});else{let o=t.map((i,s)=>`${s+1}. **${i.name}**: ${i.detail}
10837
+ Fix: ${i.fix}`).join(`
12407
10838
 
12408
- `);return c(JSON.stringify({status:"fail",message:`QA found ${R.length} issue(s) on the live app. Fix them and redeploy.`,url:a,passed:k.length,failed:R.length,checks:o,fixInstructions:`The deployed app at ${a} has ${R.length} issue(s):
10839
+ `);n.push({type:"text",text:JSON.stringify({status:"fail",message:`QA found ${t.length} issue(s) on the live app. Fix them and redeploy.`,url:r,passed:a.length,failed:t.length,checks:e.map(({screenshot:i,...s})=>s),fixInstructions:`The deployed app at ${r} has ${t.length} issue(s):
12409
10840
 
12410
- ${$}
10841
+ ${o}
12411
10842
 
12412
- Fix these issues in the source code, then call mist_deploy with action='deploy'${a.includes("-pv-")?" environment='preview'":""} to redeploy. After redeploying, call mist_build action='qa' again to verify the fixes.`}))}function Yo(r){let e=Bt(Jo(),".mistflow","plans",`${r}.json`);if(!Pt(e))return null;try{let t=JSON.parse(qo(e,"utf-8"));return t.plan?t:null}catch{return null}}var Qo=de.object({action:de.enum(["init","implement","debug","build","qa","mockup"]).describe("'mockup' generates visual mockup HTML files from a plan for user preview and approval. 'init' creates and sets up a new project from your plan. 'implement' executes the next (or specific) plan step. 'debug' analyzes build errors. 'build' runs the full production build locally (OpenNext for Cloudflare) without deploying. 'qa' tests the live deployed app \u2014 checks landing page, signup, login, dashboard, and nav links. Call after mist_deploy. If issues found, fix and redeploy, then call qa again."),name:de.string().optional().describe("(init) Project name"),planId:de.string().optional().describe("(init/mockup) Plan ID from mist_plan"),plan:de.any().optional().describe("(init) Full plan object \u2014 use planId instead when available"),path:de.string().optional().describe("(init) Target directory path"),landingDesign:de.string().optional().describe("(init) Landing design ID to apply to the landing page. Can be set here if not set during mist_plan. Use mist_project action='landing-designs' to browse."),appStyle:de.string().optional().describe("(init) App style ID to apply across all pages (e.g. 'stripe', 'linear'). Can be set here if not set during mist_plan. Use mist_project action='app-styles' to browse."),projectPath:de.string().optional().describe("Path to the project directory (default: cwd)"),step:de.number().optional().describe("(implement) Specific step number to implement"),buildOutput:de.string().optional().describe("(debug) Build output to parse instead of running a build"),feedback:de.string().optional().describe("(mockup) User feedback on the current mockup \u2014 describe what to change."),approved:de.boolean().optional().describe("(mockup) Set to true when the user approves the mockup. Locks in the design direction."),url:de.string().optional().describe("(qa) URL to test. Defaults to deploy URL from mistflow.json")}),_r={name:"mist_build",description:"STEP 2-3 of the Mistflow workflow. Build and develop a Mistflow project. Actions: 'mockup' generates visual HTML mockups from a plan for user preview \u2014 call with planId after plan approval if user wants to preview. Pass feedback to iterate, approved=true to lock in the design. 'init' creates and sets up a new project from a plan. Pass the planId returned by mist_plan \u2014 do NOT pass the full plan object. 'implement' executes the next plan step \u2014 call repeatedly until all steps are done. 'build' runs the full production build locally (OpenNext for Cloudflare) to verify before deploying. 'debug' analyzes build errors. 'qa' tests the LIVE deployed app \u2014 call AFTER mist_deploy to verify everything works. If qa finds issues, fix them and redeploy, then call qa again. The full workflow is: mist_plan \u2192 (optional) mist_build mockup \u2192 mist_build init \u2192 mist_build implement (repeat) \u2192 mist_deploy \u2192 mist_build qa (loop until pass).",inputSchema:Qo,handler:async r=>{let e=r;switch(e.action){case"init":{if(!e.name)return c("Project name is required for init.",!0);let t=e.plan,a=null;if(e.planId){if(a=Yo(e.planId),!a)return c(`Plan not found for planId '${e.planId}'. The plan may have expired. Call mist_plan again to generate a new plan.`,!0);t=a.plan}if(!t)return c("No plan provided. Pass the planId returned by mist_plan, or call mist_plan first to generate a plan.",!0);if(!Array.isArray(t?.steps)||t.steps.length===0)return c("The plan is missing a 'steps' array. This usually means the plan generation was incomplete. Call mist_plan again with the same description to get a complete plan with implementation steps.",!0);if(a?.sourceDeploymentId&&a?.forkToken&&a?.projectId)return Cr({name:e.name,plan:t,path:e.path,projectId:a.projectId,sourceDeploymentId:a.sourceDeploymentId,forkToken:a.forkToken,requiredEnvVars:a.requiredEnvVars??[],dbProvider:a.dbProvider??"neon",planId:e.planId});if(e.landingDesign){let n=Ae(e.landingDesign);n?t.landingDesign=n.id:console.error(`Landing design '${e.landingDesign}' not found \u2014 ignoring.`)}if(e.appStyle){let n=ke(e.appStyle);n?t.appStyle=n.id:console.error(`App style '${e.appStyle}' not found \u2014 ignoring.`)}return Tr({name:e.name,plan:t,path:e.path,planId:e.planId})}case"implement":return Er({projectPath:e.projectPath,step:e.step});case"debug":return Hr({projectPath:e.projectPath,buildOutput:e.buildOutput});case"build":{let t=Ko(e.projectPath??process.cwd());if(!Pt(Bt(t,"mistflow.json")))return c("Not a Mistflow project \u2014 mistflow.json not found. Run mist_build init first.",!0);if(!Pt(Bt(t,"node_modules")))try{ha("npm",["install"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:12e4})}catch{return c("npm install failed. Check package.json for issues.",!0)}let n=process.platform==="win32"?"npx.cmd":"npx",o=0,i=2;for(;;){o++;try{ha(n,["@opennextjs/cloudflare","build"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:18e4});let l=Pt(Bt(t,".open-next"));return c(JSON.stringify({success:!0,buildDir:".open-next",message:l?"Production build succeeded. Ready to deploy with mist_deploy.":"Build completed but .open-next/ directory not found. Check your OpenNext config."}))}catch(l){let s=l instanceof Error&&"stderr"in l?String(l.stderr):"",d=l instanceof Error&&"stdout"in l?String(l.stdout):"",p=s+`
12413
- `+d;if(o<i){let h=[],m=/Module not found:\s*(?:Error:\s*)?Can't resolve ['"]([^'"]+)['"]/g,b;for(;(b=m.exec(p))!==null;){let f=b[1];if(!f.startsWith(".")&&!f.startsWith("@/")&&!f.startsWith("~/")){let g=f.startsWith("@")?f.split("/").slice(0,2).join("/"):f.split("/")[0];h.includes(g)||h.push(g)}}if(h.length>0){console.error(`[build] Auto-installing missing packages: ${h.join(", ")}`);try{ha("npm",["install",...h],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:6e4});continue}catch{console.error("[build] Auto-install failed, reporting build errors")}}}let u=ca(p);return c(JSON.stringify({success:!1,errors:u,rawOutput:p.slice(0,3e3),message:u.length>0?`Build failed with ${u.length} error${u.length===1?"":"s"}:
10843
+ Fix these issues in the source code, then call mist_deploy with action='deploy'${r.includes("-pv-")?" environment='preview'":""} to redeploy. After redeploying, call mist_build action='qa' again to verify the fixes.`})})}for(let o of e)o.screenshot&&n.push({type:"image",data:o.screenshot,mimeType:"image/png"});return{content:n}}function so(r){let e=At(oo(),".mistflow","plans",`${r}.json`);if(!It(e))return null;try{let t=JSON.parse(io(e,"utf-8"));return t.plan?t:null}catch{return null}}var lo=re.object({action:re.enum(["init","implement","debug","build","qa","mockup"]).describe("'mockup' generates visual mockup HTML files from a plan for user preview and approval. 'init' creates and sets up a new project from your plan. 'implement' executes the next (or specific) plan step. 'debug' analyzes build errors. 'build' runs the full production build locally (OpenNext for Cloudflare) without deploying. 'qa' tests the live deployed app \u2014 checks landing page, signup, login, dashboard, and nav links. Call after mist_deploy. If issues found, fix and redeploy, then call qa again."),name:re.string().optional().describe("(init) Project name"),planId:re.string().optional().describe("(init/mockup) Plan ID from mist_plan"),plan:re.any().optional().describe("(init) Full plan object \u2014 use planId instead when available"),path:re.string().optional().describe("(init) Target directory path"),landingDesign:re.string().optional().describe("(init) Landing design ID to apply to the landing page. Can be set here if not set during mist_plan. Use mist_project action='landing-designs' to browse."),appStyle:re.string().optional().describe("(init) App style ID to apply across all pages (e.g. 'stripe', 'linear'). Can be set here if not set during mist_plan. Use mist_project action='app-styles' to browse."),projectPath:re.string().optional().describe("Path to the project directory (default: cwd)"),step:re.number().optional().describe("(implement) Specific step number to implement"),buildOutput:re.string().optional().describe("(debug) Build output to parse instead of running a build"),feedback:re.string().optional().describe("(mockup) User feedback on the current mockup \u2014 describe what to change."),approved:re.boolean().optional().describe("(mockup) Set to true when the user approves the mockup. Locks in the design direction."),url:re.string().optional().describe("(qa) URL to test. Defaults to deploy URL from mistflow.json"),deploymentId:re.string().optional().describe("(qa) Deployment ID to associate QA results with. Passed from mist_deploy output.")}),qr={name:"mist_build",description:"STEP 2-3 of the Mistflow workflow. Build and develop a Mistflow project. Actions: 'mockup' generates visual HTML mockups from a plan for user preview \u2014 call with planId after plan approval if user wants to preview. Pass feedback to iterate, approved=true to lock in the design. 'init' creates and sets up a new project from a plan. Pass the planId returned by mist_plan \u2014 do NOT pass the full plan object. 'implement' executes the next plan step \u2014 call repeatedly until all steps are done. 'build' runs the full production build locally (OpenNext for Cloudflare) to verify before deploying. 'debug' analyzes build errors. 'qa' tests the LIVE deployed app \u2014 call AFTER mist_deploy to verify everything works. If qa finds issues, fix them and redeploy, then call qa again. The full workflow is: mist_plan \u2192 (optional) mist_build mockup \u2192 mist_build init \u2192 mist_build implement (repeat) \u2192 mist_deploy \u2192 mist_build qa (loop until pass).",inputSchema:lo,handler:async r=>{let e=r;switch(e.action){case"init":{if(!e.name)return c("Project name is required for init.",!0);let t=e.plan,a=null;if(e.planId){if(a=so(e.planId),!a)return c(`Plan not found for planId '${e.planId}'. The plan may have expired. Call mist_plan again to generate a new plan.`,!0);t=a.plan}if(!t)return c("No plan provided. Pass the planId returned by mist_plan, or call mist_plan first to generate a plan.",!0);if(!Array.isArray(t?.steps)||t.steps.length===0)return c("The plan is missing a 'steps' array. This usually means the plan generation was incomplete. Call mist_plan again with the same description to get a complete plan with implementation steps.",!0);if(a?.sourceDeploymentId&&a?.forkToken&&a?.projectId)return Ar({name:e.name,plan:t,path:e.path,projectId:a.projectId,sourceDeploymentId:a.sourceDeploymentId,forkToken:a.forkToken,requiredEnvVars:a.requiredEnvVars??[],dbProvider:a.dbProvider??"neon",planId:e.planId});if(e.landingDesign){let n=De(e.landingDesign);n?t.landingDesign=n.id:console.error(`Landing design '${e.landingDesign}' not found \u2014 ignoring.`)}if(e.appStyle){let n=me(e.appStyle);n?t.appStyle=n.id:console.error(`App style '${e.appStyle}' not found \u2014 ignoring.`)}return Ir({name:e.name,plan:t,path:e.path,planId:e.planId})}case"implement":return _r({projectPath:e.projectPath,step:e.step});case"debug":return jr({projectPath:e.projectPath,buildOutput:e.buildOutput});case"build":{let t=no(e.projectPath??process.cwd());if(!It(At(t,"mistflow.json")))return c("Not a Mistflow project \u2014 mistflow.json not found. Run mist_build init first.",!0);if(!It(At(t,"node_modules")))try{ha("npm",["install"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:12e4})}catch{return c("npm install failed. Check package.json for issues.",!0)}let n=process.platform==="win32"?"npx.cmd":"npx",o=0,i=2;for(;;){o++;try{ha(n,["@opennextjs/cloudflare","build"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:18e4});let s=It(At(t,".open-next"));return c(JSON.stringify({success:!0,buildDir:".open-next",message:s?"Production build succeeded. Ready to deploy with mist_deploy.":"Build completed but .open-next/ directory not found. Check your OpenNext config."}))}catch(s){let l=s instanceof Error&&"stderr"in s?String(s.stderr):"",d=s instanceof Error&&"stdout"in s?String(s.stdout):"",u=l+`
10844
+ `+d;if(o<i){let h=[],m=/Module not found:\s*(?:Error:\s*)?Can't resolve ['"]([^'"]+)['"]/g,f;for(;(f=m.exec(u))!==null;){let b=f[1];if(!b.startsWith(".")&&!b.startsWith("@/")&&!b.startsWith("~/")){let g=b.startsWith("@")?b.split("/").slice(0,2).join("/"):b.split("/")[0];h.includes(g)||h.push(g)}}if(h.length>0){console.error(`[build] Auto-installing missing packages: ${h.join(", ")}`);try{ha("npm",["install",...h],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:6e4});continue}catch{console.error("[build] Auto-install failed, reporting build errors")}}}let p=ua(u);return c(JSON.stringify({success:!1,errors:p,rawOutput:u.slice(0,3e3),message:p.length>0?`Build failed with ${p.length} error${p.length===1?"":"s"}:
12414
10845
 
12415
- `+u.map((h,m)=>{let b=h.file?`${h.file}${h.line?`:${h.line}`:""}`:"unknown";return`${m+1}. [${b}] ${h.humanMessage}
10846
+ `+p.map((h,m)=>{let f=h.file?`${h.file}${h.line?`:${h.line}`:""}`:"unknown";return`${m+1}. [${f}] ${h.humanMessage}
12416
10847
  Fix: ${h.suggestion}`}).join(`
12417
10848
 
12418
10849
  `)+`
12419
10850
 
12420
- Fix these and run mist_build build again.`:"Build failed. Run mist_build with action='debug' for detailed analysis."}),!0)}}}case"qa":return Wr({projectPath:e.projectPath,url:e.url});case"mockup":return e.planId?Mr({planId:e.planId,projectPath:e.projectPath,feedback:e.feedback,approved:e.approved}):c("planId is required for mockup. Pass the planId from mist_plan.",!0);default:return c(`Unknown action: ${e.action}. Use mockup, init, implement, build, debug, or qa.`,!0)}}};import{z as Oe}from"zod";import{z as At}from"zod";import{resolve as Qr,join as Y,dirname as Dt,basename as gn}from"path";import{existsSync as ae,readFileSync as ya,writeFileSync as Xr,unlinkSync as $r,mkdirSync as mn,cpSync as fa,rmSync as ba,readdirSync as fn}from"fs";import{execFileSync as bn}from"child_process";import{spawn as xn}from"child_process";import{tmpdir as yn}from"os";function Or(r,e){if(r instanceof ce)switch(r.code){case"auth_missing":return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);case"auth_revoked":return c("Your Mistflow credentials were revoked. Run mist_setup to reconnect.",!0);case"auth_expired":case"auth_invalid":case"auth_org_not_found":return c("Your Mistflow session needs to be refreshed. Run mist_setup to reconnect.",!0);case"permission_denied":return c(r.message||"You don't have permission for that action.",!0);case"rate_limited":return c("You're hitting rate limits. Wait 30 seconds and try again.",!0);case"quota_exceeded":return c(`${r.message} Upgrade at https://app.mistflow.ai/pricing to lift limits.`,!0);case"validation_error":case"not_found":case"conflict":return c(r.message,!0);case"server_error":case"upstream_error":return c(`${e} failed: the Mistflow backend returned an error. Try again in 30 seconds.`,!0);case"network_error":return c(`${e} failed: cannot reach Mistflow servers. Check your network and try again.`,!0);default:return c(`${e} failed: ${r.message}`,!0)}let t=r instanceof Error?r.message:String(r);return c(`${e} failed: ${t}`,!0)}import{existsSync as it,readFileSync as ga}from"fs";import{join as ot}from"path";import{execFileSync as ud}from"child_process";function Xo(r){let e=ot(r,".env.local"),t=[];return it(e)?(ga(e,"utf-8").match(/^AUTH_SECRET=(.*)$/m)?.[1]?.trim()||t.push({check:"env",message:"AUTH_SECRET is missing from .env.local. Add a random secret for authentication.",file:".env.local"}),t):(t.push({check:"env",message:"Missing .env.local file. Create one with your local development environment variables (AUTH_SECRET, etc.).",file:".env.local"}),t)}function Zo(r){let e=ot(r,"app","api","auth","[...all]","route.ts");return it(e)?[]:[{check:"auth-routes",message:"Missing Better Auth catch-all route at app/api/auth/[...all]/route.ts. Create this file to handle authentication.",file:"app/api/auth/[...all]/route.ts"}]}function en(r){let e=ot(r,"app","api","health","route.ts");return it(e)?[]:[{check:"health-endpoint",message:"Missing health check endpoint at app/api/health/route.ts. Create this file so Mistflow can verify your deployment.",file:"app/api/health/route.ts"}]}function tn(r){let e=ot(r,"mistflow.json");if(!it(e))return[];let t;try{t=JSON.parse(ga(e,"utf-8"))}catch{return[]}let a=t.env;if(!a?.required||typeof a.required!="object")return[];let n=[],o=ot(r,".env"),i="";try{it(o)&&(i=ga(o,"utf-8"))}catch{}for(let[l,s]of Object.entries(a.required)){let d=!!process.env[l],p=i.includes(`${l}=`);if(d||p)continue;let u=s?.description?` for '${s.description}'`:"";n.push({check:"required-env",message:`${l} is required${u}. Run mist_config to set it if you haven't already.`})}return n}function jr(r){let e=[...Xo(r),...Zo(r),...en(r)],t=[...tn(r)];return{passed:e.length===0,errors:e,warnings:t}}import{existsSync as pe,readFileSync as _e,readdirSync as It,statSync as nt}from"fs";import{join as O}from"path";async function zr(r,e){let t=[];t.push(an(r)),t.push(rn(r)),t.push(on(r)),t.push(nn(r)),t.push(sn(r)),t.push(pn(r)),e?.plan&&t.push(...ln(r,e)),t.push(dn(r)),t.push(cn(r)),t.push(...hn(r)),t.push(un(r));let a=t.filter(d=>d.status==="fail"),n=t.filter(d=>d.status==="warn"),o=t.filter(d=>d.status==="pass"),i=a.length>0,l=!i,s;return l&&n.length===0?s=`All ${t.length} checks passed`:l?s=`${o.length}/${t.length} passed, ${n.length} warning(s)`:s=`${a.length} issue(s) found:
10851
+ Fix these and run mist_build build again.`:"Build failed. Run mist_build with action='debug' for detailed analysis."}),!0)}}}case"qa":return Vr({projectPath:e.projectPath,url:e.url,deploymentId:e.deploymentId});case"mockup":return e.planId?Er({planId:e.planId,projectPath:e.projectPath,feedback:e.feedback,approved:e.approved}):c("planId is required for mockup. Pass the planId from mist_plan.",!0);default:return c(`Unknown action: ${e.action}. Use mockup, init, implement, build, debug, or qa.`,!0)}}};import{z as _e}from"zod";import{z as Rt}from"zod";import{resolve as ri,join as _,dirname as Lt,basename as To}from"path";import{existsSync as Z,readFileSync as ya,writeFileSync as ii,unlinkSync as Qr,mkdirSync as Po,cpSync as fa,rmSync as ba,readdirSync as Bo}from"fs";import{execFileSync as Do}from"child_process";import{spawn as Io}from"child_process";import{tmpdir as Ao}from"os";function Kr(r,e){if(r instanceof ce)switch(r.code){case"auth_missing":return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);case"auth_revoked":return c("Your Mistflow credentials were revoked. Run mist_setup to reconnect.",!0);case"auth_expired":case"auth_invalid":case"auth_org_not_found":return c("Your Mistflow session needs to be refreshed. Run mist_setup to reconnect.",!0);case"permission_denied":return c(r.message||"You don't have permission for that action.",!0);case"rate_limited":return c("You're hitting rate limits. Wait 30 seconds and try again.",!0);case"quota_exceeded":return c(`${r.message} Upgrade at https://app.mistflow.ai/pricing to lift limits.`,!0);case"validation_error":case"not_found":case"conflict":return c(r.message,!0);case"server_error":case"upstream_error":return c(`${e} failed: the Mistflow backend returned an error. Try again in 30 seconds.`,!0);case"network_error":return c(`${e} failed: cannot reach Mistflow servers. Check your network and try again.`,!0);default:return c(`${e} failed: ${r.message}`,!0)}let t=r instanceof Error?r.message:String(r);return c(`${e} failed: ${t}`,!0)}import{existsSync as nt,readFileSync as ga}from"fs";import{join as ot}from"path";import{execFileSync as Cd}from"child_process";function co(r){let e=ot(r,".env.local"),t=[];return nt(e)?(ga(e,"utf-8").match(/^AUTH_SECRET=(.*)$/m)?.[1]?.trim()||t.push({check:"env",message:"AUTH_SECRET is missing from .env.local. Add a random secret for authentication.",file:".env.local"}),t):(t.push({check:"env",message:"Missing .env.local file. Create one with your local development environment variables (AUTH_SECRET, etc.).",file:".env.local"}),t)}function po(r){let e=ot(r,"app","api","auth","[...all]","route.ts");return nt(e)?[]:[{check:"auth-routes",message:"Missing Better Auth catch-all route at app/api/auth/[...all]/route.ts. Create this file to handle authentication.",file:"app/api/auth/[...all]/route.ts"}]}function uo(r){let e=ot(r,"app","api","health","route.ts");return nt(e)?[]:[{check:"health-endpoint",message:"Missing health check endpoint at app/api/health/route.ts. Create this file so Mistflow can verify your deployment.",file:"app/api/health/route.ts"}]}function ho(r){let e=ot(r,"mistflow.json");if(!nt(e))return[];let t;try{t=JSON.parse(ga(e,"utf-8"))}catch{return[]}let a=t.env;if(!a?.required||typeof a.required!="object")return[];let n=[],o=ot(r,".env"),i="";try{nt(o)&&(i=ga(o,"utf-8"))}catch{}for(let[s,l]of Object.entries(a.required)){let d=!!process.env[s],u=i.includes(`${s}=`);if(d||u)continue;let p=l?.description?` for '${l.description}'`:"";n.push({check:"required-env",message:`${s} is required${p}. Run mist_config to set it if you haven't already.`})}return n}function Jr(r){let e=[...co(r),...po(r),...uo(r)],t=[...ho(r)];return{passed:e.length===0,errors:e,warnings:t}}import{existsSync as pe,readFileSync as Oe,readdirSync as Mt,statSync as st}from"fs";import{join as O}from"path";async function Yr(r,e){let t=[];t.push(go(r)),t.push(mo(r)),t.push(fo(r)),t.push(bo(r)),t.push(xo(r)),t.push(ko(r)),e?.plan&&t.push(...yo(r,e)),t.push(wo(r)),t.push(vo(r)),t.push(...Co(r)),t.push(So(r));let a=t.filter(d=>d.status==="fail"),n=t.filter(d=>d.status==="warn"),o=t.filter(d=>d.status==="pass"),i=a.length>0,s=!i,l;return s&&n.length===0?l=`All ${t.length} checks passed`:s?l=`${o.length}/${t.length} passed, ${n.length} warning(s)`:l=`${a.length} issue(s) found:
12421
10852
  ${a.map(d=>` - ${d.message}`).join(`
12422
- `)}`,{passed:l,blocking:i,checksRun:t.length,checks:t,summary:s}}function an(r){let e=O(r,".open-next","worker.js");if(!pe(e))return{name:"worker-exists",status:"fail",message:"worker.js not found in build output. The build may have failed silently."};let t=_e(e,"utf-8");return t.length<1e3?{name:"worker-exists",status:"warn",message:`worker.js is unusually small (${t.length} bytes). The build output may be incomplete.`}:{name:"worker-exists",status:"pass",message:"Worker bundle exists"}}function rn(r){let e=O(r,".open-next","assets");if(!pe(e))return{name:"assets-exist",status:"warn",message:"No static assets directory in build output. CSS and images may not load."};let t=0;function a(n){try{for(let o of It(n)){let i=O(n,o);try{nt(i).isDirectory()?a(i):t++}catch{}}}catch{}}return a(e),t===0?{name:"assets-exist",status:"warn",message:"Assets directory is empty. Your app may not have styles or images."}:{name:"assets-exist",status:"pass",message:`${t} static assets ready`}}function on(r){let e=O(r,"app","api","health","route.ts");return pe(e)?{name:"health-route",status:"pass",message:"Health endpoint found"}:{name:"health-route",status:"warn",message:"No health endpoint found. Deployment verification may fail."}}function nn(r){let e=O(r,"app","api","auth","[...all]","route.ts");return pe(e)?{name:"auth-route",status:"pass",message:"Auth routes found"}:{name:"auth-route",status:"warn",message:"Auth catch-all route not found. Login/register may not work."}}function sn(r){let e=O(r,".open-next","worker.js");if(!pe(e))return{name:"worker-size",status:"pass",message:"Worker size check skipped"};let a=nt(e).size/(1024*1024);return a>60?{name:"worker-size",status:"fail",message:`Worker bundle is ${a.toFixed(1)}MB \u2014 exceeds Cloudflare's 64MB uncompressed limit.`}:a>30?{name:"worker-size",status:"warn",message:`Worker bundle is ${a.toFixed(1)}MB \u2014 large but within Cloudflare limits. May be slow to upload.`}:{name:"worker-size",status:"pass",message:`Worker bundle: ${a.toFixed(1)}MB`}}function ln(r,e){let t=[],a=new Set;if(e.plan?.pages)for(let i of e.plan.pages){let l=i.path??i.route??i.name;l&&a.add(l.replace(/^\//,""))}if(a.size===0)return[];let n=0,o=[];for(let i of a){if(i.startsWith("api/")||i==="login"||i==="register"||i==="sign-in"||i==="sign-up"){n++;continue}[O(r,"app","(dashboard)",i,"page.tsx"),O(r,"app","(dashboard)",i,"page.ts"),O(r,"app",i,"page.tsx"),O(r,"app",i,"page.ts"),O(r,"app","(admin)",i,"page.tsx")].some(s=>pe(s))?n++:o.push(`/${i}`)}return o.length===0?t.push({name:"plan-routes",status:"pass",message:`All ${a.size} planned pages found`}):o.length<=2?t.push({name:"plan-routes",status:"warn",message:`${n}/${a.size} planned pages found. Missing: ${o.join(", ")}`}):t.push({name:"plan-routes",status:"warn",message:`Only ${n}/${a.size} planned pages found. ${o.length} pages missing.`}),t}function dn(r){let e=O(r,"app");if(!pe(e))return{name:"empty-pages",status:"pass",message:"App directory check skipped"};let t=[];function a(n){try{for(let o of It(n)){let i=O(n,o);try{if(nt(i).isDirectory())a(i);else if(o==="page.tsx"||o==="page.ts"){let s=_e(i,"utf-8").trim();if(s.length<50||s.includes("export default function")&&s.includes("TODO")){let d=i.replace(r+"/","");t.push(d)}}}catch{}}}catch{}}return a(e),t.length>0?{name:"empty-pages",status:"warn",message:`${t.length} page(s) appear to be empty/placeholder: ${t.slice(0,3).join(", ")}`}:{name:"empty-pages",status:"pass",message:"No empty pages detected"}}function cn(r){let e=O(r,"app","page.tsx");if(!pe(e))return{name:"landing-page",status:"warn",message:"No root page.tsx found"};let t=_e(e,"utf-8");if(t.includes('redirect("/login")')||t.includes('redirect("/register")')){let a=O(r,"middleware.ts"),n=pe(a)?_e(a,"utf-8"):"";if(!(n.includes('"/"')||n.includes("'/'")))return{name:"landing-page",status:"fail",message:"Landing page (app/page.tsx) is just a redirect to /login, and middleware does not allow '/' as public. Users will never see a landing page."}}return t.length<200?{name:"landing-page",status:"warn",message:`Landing page is very small (${t.length} chars) \u2014 may be a placeholder.`}:{name:"landing-page",status:"pass",message:"Landing page has content"}}function pn(r){let e=O(r,"app");if(!pe(e))return{name:"cookies-in-actions",status:"pass",message:"No app directory"};let t=[];function a(n){try{for(let o of It(n)){if(o==="node_modules"||o===".next"||o===".open-next")continue;let i=O(n,o);try{if(nt(i).isDirectory())a(i);else if(o==="actions.ts"||o==="actions.tsx"){let s=_e(i,"utf-8");s.includes("use server")&&s.includes("cookies()")&&s.includes(".set(")&&t.push(i.replace(r+"/",""))}}catch{}}}catch{}}return a(e),t.length>0?{name:"cookies-in-actions",status:"fail",message:`${t.length} server action(s) use cookies().set() which crashes on Cloudflare Workers: ${t.join(", ")}. Use a database field or form parameter instead.`}:{name:"cookies-in-actions",status:"pass",message:"No cookies().set() in server actions"}}function un(r){let e=O(r,"app");if(!pe(e))return{name:"fake-forms",status:"pass",message:"No app directory"};let t=[];function a(n){try{for(let o of It(n)){if(o==="node_modules"||o===".next"||o===".open-next")continue;let i=O(n,o);try{if(nt(i).isDirectory())a(i);else if(o.endsWith(".tsx")||o.endsWith(".ts")){let s=_e(i,"utf-8");if((s.includes("setTimeout")||s.includes("new Promise"))&&s.includes("Simulate")||s.includes("simulate")||s.includes("// TODO")&&s.includes("API")){let d=i.replace(r+"/","");t.push(d)}}}catch{}}}catch{}}return a(e),t.length>0?{name:"fake-forms",status:"fail",message:`${t.length} file(s) have fake/simulated API calls instead of real server actions: ${t.slice(0,3).join(", ")}. Forms must use 'use server' actions that write to the database.`}:{name:"fake-forms",status:"pass",message:"No fake form handlers detected"}}function hn(r){let t=[O(r,"components","sidebar.tsx"),O(r,"components","topnav.tsx"),O(r,"components","nav.tsx")].find(l=>pe(l));if(!t)return[];let o=(_e(t,"utf-8").match(/href:\s*"([^"]+)"/g)??[]).map(l=>l.replace(/href:\s*"/,"").replace(/"$/,"")).filter(l=>!l.startsWith("/api")&&!l.includes("["));if(o.length===0)return[];let i=[];for(let l of o){let s=l.replace(/^\//,"");if(!s||s==="")continue;[O(r,"app","(dashboard)",s,"page.tsx"),O(r,"app","(dashboard)",s,"page.ts"),O(r,"app","(app)",s,"page.tsx"),O(r,"app",s,"page.tsx"),O(r,"app",s,"page.ts")].some(p=>pe(p))||i.push(l)}return i.length>0?[{name:"nav-links",status:"fail",message:`Sidebar/nav links to pages that don't exist: ${i.join(", ")}. These will 404.`}]:[{name:"nav-links",status:"pass",message:`All ${o.length} nav links have matching pages`}]}function Te(r,e){return bn("git",r,{cwd:e,encoding:"utf-8",timeout:3e4,stdio:["pipe","pipe","pipe"]}).trim()}function ma(r){try{return Te(["rev-parse","--is-inside-work-tree"],r),!0}catch{return!1}}function Vr(r){try{return Te(["status","--porcelain"],r).length>0}catch{return!1}}function qr(r,e){return Te(["add","-A"],r),Te(["commit","-m",e,"--allow-empty-message"],r),Te(["rev-parse","HEAD"],r)}function wn(r){return Te(["rev-parse","HEAD"],r)}function Kr(r){try{return Te(["remote","get-url","origin"],r),!0}catch{return!1}}function vn(r){try{let e=Te(["rev-parse","--abbrev-ref","HEAD"],r);return Te(["push","origin",e],r),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:"push failed"}}}function kn(r){let e=Dt(Qr(r)),t=Dt(e)===e?e:"/";for(;e!==t&&e!==Dt(e);){if(ae(Y(e,"pnpm-workspace.yaml"))||ae(Y(e,"lerna.json")))return e;let a=Y(e,"package.json");if(ae(a))try{if(JSON.parse(ya(a,"utf-8")).workspaces)return e}catch{}e=Dt(e)}return null}function Sn(r){let e=Y(yn(),"mistflow-build");mn(e,{recursive:!0});let t=Y(e,`${gn(r)}-${Date.now()}`);return fa(r,t,{recursive:!0,filter:a=>{let n=a.slice(r.length);return!(n.startsWith("/.git")||n.startsWith("\\.git")||n==="/node_modules"||n.startsWith("/node_modules/")||n==="/.open-next"||n.startsWith("/.open-next/")||n==="/.next"||n.startsWith("/.next/"))}}),t}function Tn(r,e){let t=Y(r,".open-next"),a=Y(r,".next");if(ae(t)){let n=Y(e,".open-next");ae(n)&&ba(n,{recursive:!0}),fa(t,n,{recursive:!0})}if(ae(a)){let n=Y(e,".next");ae(n)&&ba(n,{recursive:!0}),fa(a,n,{recursive:!0})}}function Cn(r){try{ba(r,{recursive:!0,force:!0})}catch{console.error(`[deploy] Failed to clean up isolated build dir: ${r}`)}}function Qe(r,e,t,a,n,o){return new Promise(i=>{let l=xn(r,e,{cwd:t,stdio:["pipe","pipe","pipe"],timeout:a,...o?{env:o}:{}}),s="",d="";l.stdout?.on("data",p=>{let u=p.toString();if(d+=u,n)for(let h of u.split(`
12423
- `).filter(Boolean))n(h)}),l.stderr?.on("data",p=>{let u=p.toString();if(s+=u,n)for(let h of u.split(`
12424
- `).filter(Boolean))n(h)}),l.on("close",(p,u)=>{i({success:p===0,stdout:d,stderr:s,signal:u})}),l.on("error",p=>{i({success:!1,stdout:d,stderr:s+p.message})})})}var Ad=At.object({projectPath:At.string().optional().describe("Path to the project directory (default: current working directory)"),message:At.string().optional().describe("Deploy message"),environment:At.enum(["production","preview"]).optional().default("production").describe("Target environment: 'production' (default) or 'preview' for a shareable URL")});function Pn(r){return new Promise(e=>setTimeout(e,r))}function Jr(r){switch(r){case"pending":return"Provisioning database...";case"building":return"Building your app...";case"deploying":return"Deploying to Cloudflare...";case"verifying":return"Verifying deployment...";default:return`Status: ${r}`}}function xa(r){let e=Y(r,"mistflow.json");if(ae(e))try{return JSON.parse(ya(e,"utf-8"))}catch{}return{}}function Bn(r,e){let t=Y(r,"mistflow.json"),a=xa(r),n=a.deploy?.count??a.deployCount??0;a.deploy={url:e,count:n+1,lastDeployedAt:new Date().toISOString()};let o=a.plan?.steps;if(Array.isArray(o))for(let i of o)i.status==="in_progress"&&(i.status="completed");delete a.deployUrl,delete a.deployCount,Xr(t,JSON.stringify(a,null,2)+`
12425
- `)}async function Zr(r,e){let a=process.platform==="win32"?"npx.cmd":"npx",n=0,o=Y(r,"node_modules",".bin","opennextjs-cloudflare"),i=ae(o),l={...process.env,NODE_ENV:"production"},s=await Qe(i?o:a,i?["build"]:["@opennextjs/cloudflare","build"],r,3e5,h=>{h.includes("Compiling")?e?.("Compiling your app..."):h.includes("Collecting page data")?e?.("Collecting page data..."):h.includes("Generating static pages")?e?.("Generating static pages..."):h.match(/^[○●◐λƒ]\s/)?n++:h.includes("Creating Cloudflare worker")?e?.("Creating Cloudflare worker..."):h.includes("Build completed")&&e?.("Build completed!")},l);if(s.success)return{success:!0,buildStats:n>0?`${n} routes compiled`:"build complete"};let d=s.stderr+`
12426
- `+s.stdout;if(s.signal==="SIGKILL"||d.includes("SIGKILL")||d.includes("exit code: 137"))return{success:!1,signal:"SIGKILL",error:"Your app ran out of memory while building. This sometimes happens with complex projects. Try deploying again \u2014 if it keeps failing, we'll help you figure it out."};let p=d.match(/Package subpath ['"]([^'"]+)['"] is not defined by "exports" in .*?node_modules\/([^/]+(?:\/[^/]+)?)\//);if(p){let[,h,m]=p;return{success:!1,error:`Version conflict: '${m}' does not export '${h}'. This happens when multiple dependencies need different major versions of '${m}'. Fix: add "${m}" at the version that exports '${h}' as an optionalDependency in package.json (this pins it at root level and lets the other version nest). Then delete node_modules and package-lock.json, and run npm install.`}}let u=d.split(`
12427
- `).filter(h=>h.includes("error")||h.includes("Error")).slice(0,10);return{success:!1,error:u.length>0?`OpenNext build failed:
12428
- ${u.join(`
10853
+ `)}`,{passed:s,blocking:i,checksRun:t.length,checks:t,summary:l}}function go(r){let e=O(r,".open-next","worker.js");if(!pe(e))return{name:"worker-exists",status:"fail",message:"worker.js not found in build output. The build may have failed silently."};let t=Oe(e,"utf-8");return t.length<1e3?{name:"worker-exists",status:"warn",message:`worker.js is unusually small (${t.length} bytes). The build output may be incomplete.`}:{name:"worker-exists",status:"pass",message:"Worker bundle exists"}}function mo(r){let e=O(r,".open-next","assets");if(!pe(e))return{name:"assets-exist",status:"warn",message:"No static assets directory in build output. CSS and images may not load."};let t=0;function a(n){try{for(let o of Mt(n)){let i=O(n,o);try{st(i).isDirectory()?a(i):t++}catch{}}}catch{}}return a(e),t===0?{name:"assets-exist",status:"warn",message:"Assets directory is empty. Your app may not have styles or images."}:{name:"assets-exist",status:"pass",message:`${t} static assets ready`}}function fo(r){let e=O(r,"app","api","health","route.ts");return pe(e)?{name:"health-route",status:"pass",message:"Health endpoint found"}:{name:"health-route",status:"warn",message:"No health endpoint found. Deployment verification may fail."}}function bo(r){let e=O(r,"app","api","auth","[...all]","route.ts");return pe(e)?{name:"auth-route",status:"pass",message:"Auth routes found"}:{name:"auth-route",status:"warn",message:"Auth catch-all route not found. Login/register may not work."}}function xo(r){let e=O(r,".open-next","worker.js");if(!pe(e))return{name:"worker-size",status:"pass",message:"Worker size check skipped"};let a=st(e).size/(1024*1024);return a>60?{name:"worker-size",status:"fail",message:`Worker bundle is ${a.toFixed(1)}MB \u2014 exceeds Cloudflare's 64MB uncompressed limit.`}:a>30?{name:"worker-size",status:"warn",message:`Worker bundle is ${a.toFixed(1)}MB \u2014 large but within Cloudflare limits. May be slow to upload.`}:{name:"worker-size",status:"pass",message:`Worker bundle: ${a.toFixed(1)}MB`}}function yo(r,e){let t=[],a=new Set;if(e.plan?.pages)for(let i of e.plan.pages){let s=i.path??i.route??i.name;s&&a.add(s.replace(/^\//,""))}if(a.size===0)return[];let n=0,o=[];for(let i of a){if(i.startsWith("api/")||i==="login"||i==="register"||i==="sign-in"||i==="sign-up"){n++;continue}[O(r,"app","(dashboard)",i,"page.tsx"),O(r,"app","(dashboard)",i,"page.ts"),O(r,"app",i,"page.tsx"),O(r,"app",i,"page.ts"),O(r,"app","(admin)",i,"page.tsx")].some(l=>pe(l))?n++:o.push(`/${i}`)}return o.length===0?t.push({name:"plan-routes",status:"pass",message:`All ${a.size} planned pages found`}):o.length<=2?t.push({name:"plan-routes",status:"warn",message:`${n}/${a.size} planned pages found. Missing: ${o.join(", ")}`}):t.push({name:"plan-routes",status:"warn",message:`Only ${n}/${a.size} planned pages found. ${o.length} pages missing.`}),t}function wo(r){let e=O(r,"app");if(!pe(e))return{name:"empty-pages",status:"pass",message:"App directory check skipped"};let t=[];function a(n){try{for(let o of Mt(n)){let i=O(n,o);try{if(st(i).isDirectory())a(i);else if(o==="page.tsx"||o==="page.ts"){let l=Oe(i,"utf-8").trim();if(l.length<50||l.includes("export default function")&&l.includes("TODO")){let d=i.replace(r+"/","");t.push(d)}}}catch{}}}catch{}}return a(e),t.length>0?{name:"empty-pages",status:"warn",message:`${t.length} page(s) appear to be empty/placeholder: ${t.slice(0,3).join(", ")}`}:{name:"empty-pages",status:"pass",message:"No empty pages detected"}}function vo(r){let e=O(r,"app","page.tsx");if(!pe(e))return{name:"landing-page",status:"warn",message:"No root page.tsx found"};let t=Oe(e,"utf-8");if(t.includes('redirect("/login")')||t.includes('redirect("/register")')){let a=O(r,"middleware.ts"),n=pe(a)?Oe(a,"utf-8"):"";if(!(n.includes('"/"')||n.includes("'/'")))return{name:"landing-page",status:"fail",message:"Landing page (app/page.tsx) is just a redirect to /login, and middleware does not allow '/' as public. Users will never see a landing page."}}return t.length<200?{name:"landing-page",status:"warn",message:`Landing page is very small (${t.length} chars) \u2014 may be a placeholder.`}:{name:"landing-page",status:"pass",message:"Landing page has content"}}function ko(r){let e=O(r,"app");if(!pe(e))return{name:"cookies-in-actions",status:"pass",message:"No app directory"};let t=[];function a(n){try{for(let o of Mt(n)){if(o==="node_modules"||o===".next"||o===".open-next")continue;let i=O(n,o);try{if(st(i).isDirectory())a(i);else if(o==="actions.ts"||o==="actions.tsx"){let l=Oe(i,"utf-8");l.includes("use server")&&l.includes("cookies()")&&l.includes(".set(")&&t.push(i.replace(r+"/",""))}}catch{}}}catch{}}return a(e),t.length>0?{name:"cookies-in-actions",status:"fail",message:`${t.length} server action(s) use cookies().set() which crashes on Cloudflare Workers: ${t.join(", ")}. Use a database field or form parameter instead.`}:{name:"cookies-in-actions",status:"pass",message:"No cookies().set() in server actions"}}function So(r){let e=O(r,"app");if(!pe(e))return{name:"fake-forms",status:"pass",message:"No app directory"};let t=[];function a(n){try{for(let o of Mt(n)){if(o==="node_modules"||o===".next"||o===".open-next")continue;let i=O(n,o);try{if(st(i).isDirectory())a(i);else if(o.endsWith(".tsx")||o.endsWith(".ts")){let l=Oe(i,"utf-8");if((l.includes("setTimeout")||l.includes("new Promise"))&&l.includes("Simulate")||l.includes("simulate")||l.includes("// TODO")&&l.includes("API")){let d=i.replace(r+"/","");t.push(d)}}}catch{}}}catch{}}return a(e),t.length>0?{name:"fake-forms",status:"fail",message:`${t.length} file(s) have fake/simulated API calls instead of real server actions: ${t.slice(0,3).join(", ")}. Forms must use 'use server' actions that write to the database.`}:{name:"fake-forms",status:"pass",message:"No fake form handlers detected"}}function Co(r){let t=[O(r,"components","sidebar.tsx"),O(r,"components","topnav.tsx"),O(r,"components","nav.tsx")].find(s=>pe(s));if(!t)return[];let o=(Oe(t,"utf-8").match(/href:\s*"([^"]+)"/g)??[]).map(s=>s.replace(/href:\s*"/,"").replace(/"$/,"")).filter(s=>!s.startsWith("/api")&&!s.includes("["));if(o.length===0)return[];let i=[];for(let s of o){let l=s.replace(/^\//,"");if(!l||l==="")continue;[O(r,"app","(dashboard)",l,"page.tsx"),O(r,"app","(dashboard)",l,"page.ts"),O(r,"app","(app)",l,"page.tsx"),O(r,"app",l,"page.tsx"),O(r,"app",l,"page.ts")].some(u=>pe(u))||i.push(s)}return i.length>0?[{name:"nav-links",status:"fail",message:`Sidebar/nav links to pages that don't exist: ${i.join(", ")}. These will 404.`}]:[{name:"nav-links",status:"pass",message:`All ${o.length} nav links have matching pages`}]}function ke(r,e){return Do("git",r,{cwd:e,encoding:"utf-8",timeout:3e4,stdio:["pipe","pipe","pipe"]}).trim()}function ma(r){try{return ke(["rev-parse","--is-inside-work-tree"],r),!0}catch{return!1}}function Xr(r){try{return ke(["status","--porcelain"],r).length>0}catch{return!1}}function Zr(r,e){return ke(["add","-A"],r),ke(["commit","-m",e,"--allow-empty-message"],r),ke(["rev-parse","HEAD"],r)}function Mo(r){return ke(["rev-parse","HEAD"],r)}function ei(r){try{return ke(["remote","get-url","origin"],r),!0}catch{return!1}}function Ro(r){try{let e=ke(["rev-parse","--abbrev-ref","HEAD"],r);return ke(["push","origin",e],r),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:"push failed"}}}function Lo(r){let e=Lt(ri(r)),t=Lt(e)===e?e:"/";for(;e!==t&&e!==Lt(e);){if(Z(_(e,"pnpm-workspace.yaml"))||Z(_(e,"lerna.json")))return e;let a=_(e,"package.json");if(Z(a))try{if(JSON.parse(ya(a,"utf-8")).workspaces)return e}catch{}e=Lt(e)}return null}function No(r){let e=_(Ao(),"mistflow-build");Po(e,{recursive:!0});let t=_(e,`${To(r)}-${Date.now()}`);return fa(r,t,{recursive:!0,filter:a=>{let n=a.slice(r.length);return!(n.startsWith("/.git")||n.startsWith("\\.git")||n==="/node_modules"||n.startsWith("/node_modules/")||n==="/.open-next"||n.startsWith("/.open-next/")||n==="/.next"||n.startsWith("/.next/"))}}),t}function Fo(r,e){let t=_(r,".open-next"),a=_(r,".next");if(Z(t)){let n=_(e,".open-next");Z(n)&&ba(n,{recursive:!0}),fa(t,n,{recursive:!0})}if(Z(a)){let n=_(e,".next");Z(n)&&ba(n,{recursive:!0}),fa(a,n,{recursive:!0})}}function Eo(r){try{ba(r,{recursive:!0,force:!0})}catch{console.error(`[deploy] Failed to clean up isolated build dir: ${r}`)}}function Qe(r,e,t,a,n,o){return new Promise(i=>{let s=Io(r,e,{cwd:t,stdio:["pipe","pipe","pipe"],timeout:a,...o?{env:o}:{}}),l="",d="";s.stdout?.on("data",u=>{let p=u.toString();if(d+=p,n)for(let h of p.split(`
10854
+ `).filter(Boolean))n(h)}),s.stderr?.on("data",u=>{let p=u.toString();if(l+=p,n)for(let h of p.split(`
10855
+ `).filter(Boolean))n(h)}),s.on("close",(u,p)=>{i({success:u===0,stdout:d,stderr:l,signal:p})}),s.on("error",u=>{i({success:!1,stdout:d,stderr:l+u.message})})})}var Od=Rt.object({projectPath:Rt.string().optional().describe("Path to the project directory (default: current working directory)"),message:Rt.string().optional().describe("Deploy message"),environment:Rt.enum(["production","preview"]).optional().default("production").describe("Target environment: 'production' (default) or 'preview' for a shareable URL")});function Uo(r){return new Promise(e=>setTimeout(e,r))}function ti(r){switch(r){case"pending":return"Provisioning database...";case"building":return"Building your app...";case"deploying":return"Deploying to Cloudflare...";case"verifying":return"Verifying deployment...";default:return`Status: ${r}`}}function xa(r){let e=_(r,"mistflow.json");if(Z(e))try{return JSON.parse(ya(e,"utf-8"))}catch{}return{}}function Ho(r,e){let t=_(r,"mistflow.json"),a=xa(r),n=a.deploy?.count??a.deployCount??0;a.deploy={url:e,count:n+1,lastDeployedAt:new Date().toISOString()};let o=a.plan?.steps;if(Array.isArray(o))for(let i of o)i.status==="in_progress"&&(i.status="completed");delete a.deployUrl,delete a.deployCount,ii(t,JSON.stringify(a,null,2)+`
10856
+ `)}async function ni(r,e){let a=process.platform==="win32"?"npx.cmd":"npx",n=0,o=_(r,"node_modules",".bin","opennextjs-cloudflare"),i=Z(o),s={...process.env,NODE_ENV:"production"},l=await Qe(i?o:a,i?["build"]:["@opennextjs/cloudflare","build"],r,3e5,h=>{h.includes("Compiling")?e?.("Compiling your app..."):h.includes("Collecting page data")?e?.("Collecting page data..."):h.includes("Generating static pages")?e?.("Generating static pages..."):h.match(/^[○●◐λƒ]\s/)?n++:h.includes("Creating Cloudflare worker")?e?.("Creating Cloudflare worker..."):h.includes("Build completed")&&e?.("Build completed!")},s);if(l.success)return{success:!0,buildStats:n>0?`${n} routes compiled`:"build complete"};let d=l.stderr+`
10857
+ `+l.stdout;if(l.signal==="SIGKILL"||d.includes("SIGKILL")||d.includes("exit code: 137"))return{success:!1,signal:"SIGKILL",error:"Your app ran out of memory while building. This sometimes happens with complex projects. Try deploying again \u2014 if it keeps failing, we'll help you figure it out."};let u=d.match(/Package subpath ['"]([^'"]+)['"] is not defined by "exports" in .*?node_modules\/([^/]+(?:\/[^/]+)?)\//);if(u){let[,h,m]=u;return{success:!1,error:`Version conflict: '${m}' does not export '${h}'. This happens when multiple dependencies need different major versions of '${m}'. Fix: add "${m}" at the version that exports '${h}' as an optionalDependency in package.json (this pins it at root level and lets the other version nest). Then delete node_modules and package-lock.json, and run npm install.`}}let p=d.split(`
10858
+ `).filter(h=>h.includes("error")||h.includes("Error")).slice(0,10);return{success:!1,error:p.length>0?`OpenNext build failed:
10859
+ ${p.join(`
12429
10860
  `)}`:`OpenNext build failed:
12430
- ${d.slice(-500)}`}}async function In(r,e){let t=kn(r);if(t)return console.error(`[deploy] Project is inside monorepo at ${t} \u2014 building in isolated temp directory`),e?.("Detected parent project folder \u2014 building in isolated directory..."),Yr(r,e);let a=await Zr(r,e);return!a.success&&a.signal==="SIGKILL"?(console.error("[deploy] Build was OOM-killed \u2014 retrying in isolated temp directory"),e?.("Build ran out of memory \u2014 retrying with a fresh setup..."),Yr(r,e)):a}async function Yr(r,e){let t;try{e?.("Copying project to isolated build directory..."),t=Sn(r),e?.("Installing dependencies...");let n=process.platform==="win32"?"npm.cmd":"npm",o=await Qe(n,["install","--prefer-offline"],t,12e4);if(!o.success)return{success:!1,error:`Failed to install dependencies in isolated build:
12431
- ${o.stderr.slice(-300)}`};await Qe(n,["dedupe"],t,6e4);let i=await Zr(t,e);return i.success&&(e?.("Copying build artifacts..."),Tn(t,r)),{...i,builtInIsolation:t}}finally{t&&Cn(t)}}async function An(r,e,t){if(!ae(Y(r,"db","schema")))return{success:!0,skipped:!0,skipReason:"No database structure found"};let a=Y(r,"db","schema");try{if(fn(a).filter(m=>m.endsWith(".ts")).length===0)return{success:!0,skipped:!0,skipReason:"No database files found in db/schema/"}}catch{return{success:!0,skipped:!0,skipReason:"Could not read db/schema/ directory"}}if(!ae(Y(r,"drizzle.config.ts")))return{success:!0,skipped:!0,skipReason:"No drizzle.config.ts found"};let n;try{n=await Ua(e)}catch{return console.error("[deploy] Could not fetch DB credentials \u2014 skipping local schema push"),{success:!0,skipped:!0,skipReason:"Could not fetch database credentials \u2014 backend will handle the database update"}}let{db_provider:o,credentials:i}=n;if(o==="neon"){if(!i.DATABASE_URL)return console.error("[deploy] No DATABASE_URL found \u2014 skipping local schema push"),{success:!0,skipped:!0,skipReason:"No DATABASE_URL configured \u2014 set it with mist_config"}}else if(!i.TURSO_URL||!i.TURSO_AUTH_TOKEN)return console.error("[deploy] No Turso credentials found \u2014 skipping local schema push"),{success:!0,skipped:!0,skipReason:"No Turso credentials configured"};let l={PATH:process.env.PATH??"",HOME:process.env.HOME??"",NODE_PATH:process.env.NODE_PATH??"",TMPDIR:process.env.TMPDIR??"",...i},d=process.platform==="win32"?"npx.cmd":"npx",u=await Qe(d,t?["drizzle-kit","push","--force"]:["drizzle-kit","push"],r,6e4,h=>{let m=h.replace(/(?:TURSO_AUTH_TOKEN|DATABASE_URL|AUTH_SECRET)=[^\s&]*/gi,b=>b.split("=")[0]+"=REDACTED").replace(/postgresql:\/\/[^@]*@/g,"postgresql://REDACTED@").replace(/libsql:\/\/[^\s]*/g,"libsql://REDACTED");console.error(`[drizzle-kit] ${m}`)},l);if(!u.success){let h=(u.stderr+`
12432
- `+u.stdout).trim(),m=h.toLowerCase();if(m.includes("data-loss")||m.includes("cannot be reverted"))return{success:!1,error:"Database update blocked: your database has existing data that would be deleted. The update includes changes that would remove existing data. If you're OK with losing the data, deploy again with forceSchema: true."};let b=h.split(`
10861
+ ${d.slice(-500)}`}}async function Go(r,e){let t=Lo(r);if(t)return console.error(`[deploy] Project is inside monorepo at ${t} \u2014 building in isolated temp directory`),e?.("Detected parent project folder \u2014 building in isolated directory..."),ai(r,e);let a=await ni(r,e);return!a.success&&a.signal==="SIGKILL"?(console.error("[deploy] Build was OOM-killed \u2014 retrying in isolated temp directory"),e?.("Build ran out of memory \u2014 retrying with a fresh setup..."),ai(r,e)):a}async function ai(r,e){let t;try{e?.("Copying project to isolated build directory..."),t=No(r),e?.("Installing dependencies...");let n=process.platform==="win32"?"npm.cmd":"npm",o=await Qe(n,["install","--prefer-offline"],t,12e4);if(!o.success)return{success:!1,error:`Failed to install dependencies in isolated build:
10862
+ ${o.stderr.slice(-300)}`};await Qe(n,["dedupe"],t,6e4);let i=await ni(t,e);return i.success&&(e?.("Copying build artifacts..."),Fo(t,r)),{...i,builtInIsolation:t}}finally{t&&Eo(t)}}async function Wo(r,e,t){if(!Z(_(r,"db","schema")))return{success:!0,skipped:!0,skipReason:"No database structure found"};let a=_(r,"db","schema");try{if(Bo(a).filter(m=>m.endsWith(".ts")).length===0)return{success:!0,skipped:!0,skipReason:"No database files found in db/schema/"}}catch{return{success:!0,skipped:!0,skipReason:"Could not read db/schema/ directory"}}if(!Z(_(r,"drizzle.config.ts")))return{success:!0,skipped:!0,skipReason:"No drizzle.config.ts found"};let n;try{n=await Ea(e)}catch{return console.error("[deploy] Could not fetch DB credentials \u2014 skipping local schema push"),{success:!0,skipped:!0,skipReason:"Could not fetch database credentials \u2014 backend will handle the database update"}}let{db_provider:o,credentials:i}=n;if(o==="neon"){if(!i.DATABASE_URL)return console.error("[deploy] No DATABASE_URL found \u2014 skipping local schema push"),{success:!0,skipped:!0,skipReason:"No DATABASE_URL configured \u2014 set it with mist_config"}}else if(!i.TURSO_URL||!i.TURSO_AUTH_TOKEN)return console.error("[deploy] No Turso credentials found \u2014 skipping local schema push"),{success:!0,skipped:!0,skipReason:"No Turso credentials configured"};let s={PATH:process.env.PATH??"",HOME:process.env.HOME??"",NODE_PATH:process.env.NODE_PATH??"",TMPDIR:process.env.TMPDIR??"",...i},d=process.platform==="win32"?"npx.cmd":"npx",p=await Qe(d,t?["drizzle-kit","push","--force"]:["drizzle-kit","push"],r,6e4,h=>{let m=h.replace(/(?:TURSO_AUTH_TOKEN|DATABASE_URL|AUTH_SECRET)=[^\s&]*/gi,f=>f.split("=")[0]+"=REDACTED").replace(/postgresql:\/\/[^@]*@/g,"postgresql://REDACTED@").replace(/libsql:\/\/[^\s]*/g,"libsql://REDACTED");console.error(`[drizzle-kit] ${m}`)},s);if(!p.success){let h=(p.stderr+`
10863
+ `+p.stdout).trim(),m=h.toLowerCase();if(m.includes("data-loss")||m.includes("cannot be reverted"))return{success:!1,error:"Database update blocked: your database has existing data that would be deleted. The update includes changes that would remove existing data. If you're OK with losing the data, deploy again with forceSchema: true."};let f=h.split(`
12433
10864
  `).filter(g=>g.includes("error")||g.includes("Error")||g.includes("ERR")).slice(0,5);return{success:!1,error:`Database update failed:
12434
- ${b.length>0?b.join(`
12435
- `):h.slice(-500)}`}}return{success:!0}}async function ei(r){let{projectPath:e,message:t,environment:a="production",forceSchema:n}=r,o=a,i=Qr(e??process.cwd());if(!le())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let l=jr(i);if(!l.passed){let P=l.errors.map(I=>{let M=`[${I.check}] ${I.message}`;return I.file&&(M+=` (${I.file}${I.line?`:${I.line}`:""})`),M}).join(`
10865
+ ${f.length>0?f.join(`
10866
+ `):h.slice(-500)}`}}return{success:!0}}async function oi(r){let{projectPath:e,message:t,environment:a="production",forceSchema:n}=r,o=a,i=ri(e??process.cwd());if(!se())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let s=Jr(i);if(!s.passed){let T=s.errors.map(A=>{let M=`[${A.check}] ${A.message}`;return A.file&&(M+=` (${A.file}${A.line?`:${A.line}`:""})`),M}).join(`
12436
10867
  `);return c(`Deploy blocked \u2014 fix these issues first:
12437
10868
 
12438
- ${P}`,!0)}let s=l.warnings.map(P=>`[${P.check}] ${P.message}`),d;if(ma(i))if(Vr(i))try{let P=xa(i).deploy?.count??0,I=t?`Deploy v${P+1}: ${t}`:`Deploy v${P+1}`;d=qr(i,I)}catch{console.error("[deploy] Pre-deploy git commit failed, continuing")}else try{d=wn(i)}catch{}let p=we(i),u=p?.projectId;if(!u){let P=Y(i,"mistflow.json");if(!ae(P))return c("No mistflow.json found. Run mist_build (action: 'init') first to set up your project.",!0);try{let I=JSON.parse(ya(P,"utf-8")),M=I.name;if(!M)return c("mistflow.json is missing a project name. Run mist_build (action: 'init') to set up your project.",!0);u=(await ht(M)).id,I.projectId=u,Xr(P,JSON.stringify(I,null,2)+`
12439
- `)}catch(I){let M=I instanceof ce?I.message:"Check your internet connection.";return c(`Could not register project with Mistflow: ${M}
10869
+ ${T}`,!0)}let l=s.warnings.map(T=>`[${T.check}] ${T.message}`),d;if(ma(i))if(Xr(i))try{let T=xa(i).deploy?.count??0,A=t?`Deploy v${T+1}: ${t}`:`Deploy v${T+1}`;d=Zr(i,A)}catch{console.error("[deploy] Pre-deploy git commit failed, continuing")}else try{d=Mo(i)}catch{}let u=we(i),p=u?.projectId;if(!p){let T=_(i,"mistflow.json");if(!Z(T))return c("No mistflow.json found. Run mist_build (action: 'init') first to set up your project.",!0);try{let A=JSON.parse(ya(T,"utf-8")),M=A.name;if(!M)return c("mistflow.json is missing a project name. Run mist_build (action: 'init') to set up your project.",!0);p=(await gt(M)).id,A.projectId=p,ii(T,JSON.stringify(A,null,2)+`
10870
+ `)}catch(A){let M=A instanceof ce?A.message:"Check your internet connection.";return c(`Could not register project with Mistflow: ${M}
12440
10871
 
12441
- Try deploying again in a moment.`,!0)}}if(u&&o==="production")try{let P=await Da(u),I=P,M=I.deploy_count??P.deployCount??0;(I.deploy_strategy??P.deploy_strategy)==="staging"&&M>0&&(o="preview",console.error("[deploy] Staging mode enabled \u2014 auto-redirecting to preview"))}catch{}let h=[],m=Date.now(),b=(P,I)=>{let M={phase:P,message:I};return h.push(M),M},f=(P,I)=>{P.durationMs=Date.now()-m,I&&(P.message=I)},g=!1;if(u&&o!=="preview"){let P=b("schema","Updating database structure..."),I=await An(i,u,n);if(I.skipped)f(P,I.skipReason??"Database update skipped");else if(I.success)g=!0,f(P,"Database updated successfully");else return f(P,"Database update failed"),c(`Deploy blocked \u2014 database update failed:
10872
+ Try deploying again in a moment.`,!0)}}if(p&&o==="production")try{let T=await Aa(p),A=T,M=A.deploy_count??T.deployCount??0;(A.deploy_strategy??T.deploy_strategy)==="staging"&&M>0&&(o="preview",console.error("[deploy] Staging mode enabled \u2014 auto-redirecting to preview"))}catch{}let h=[],m=Date.now(),f=(T,A)=>{let M={phase:T,message:A};return h.push(M),M},b=(T,A)=>{T.durationMs=Date.now()-m,A&&(T.message=A)},g=!1;if(p&&o!=="preview"){let T=f("schema","Updating database structure..."),A=await Wo(i,p,n);if(A.skipped)b(T,A.skipReason??"Database update skipped");else if(A.success)g=!0,b(T,"Database updated successfully");else return b(T,"Database update failed"),c(`Deploy blocked \u2014 database update failed:
12442
10873
 
12443
- ${I.error}
10874
+ ${A.error}
12444
10875
 
12445
- Try deploying again in a moment. If it keeps failing, check your database files in db/schema/.`,!0)}let y=b("build","Compiling your app for Cloudflare..."),N=Date.now(),R=await In(i,P=>{y.message=P});if(!R.success)return c(`Deploy blocked \u2014 OpenNext build failed:
10876
+ Try deploying again in a moment. If it keeps failing, check your database files in db/schema/.`,!0)}let w=f("build","Compiling your app for Cloudflare..."),P=Date.now(),D=await Go(i,T=>{w.message=T});if(!D.success)return c(`Deploy blocked \u2014 OpenNext build failed:
12446
10877
 
12447
- ${R.error}`,!0);f(y,`Build complete \u2014 ${R.buildStats??"ready"} (${((Date.now()-N)/1e3).toFixed(0)}s)`);let k=b("qa","Running smoke tests..."),$=await zr(i,p);if($.passed)f(k,`Smoke test passed \u2014 ${$.checksRun} checks OK`);else if(f(k,`Smoke test: ${$.summary}`),$.blocking)return c(`Deploy blocked \u2014 smoke test failed:
10878
+ ${D.error}`,!0);b(w,`Build complete \u2014 ${D.buildStats??"ready"} (${((Date.now()-P)/1e3).toFixed(0)}s)`);let S=f("qa","Running smoke tests..."),U=await Yr(i,u);if(U.passed)b(S,`Smoke test passed \u2014 ${U.checksRun} checks OK`);else if(b(S,`Smoke test: ${U.summary}`),U.blocking)return c(`Deploy blocked \u2014 smoke test failed:
12448
10879
 
12449
- ${$.summary}
10880
+ ${U.summary}
12450
10881
 
12451
- Fix these issues and try again.`,!0);let U=Y(i,".open-next");if(!ae(U))return c("Build succeeded but .open-next/ directory not found. Check your OpenNext configuration.",!0);b("package","Packaging build artifacts...");let E=Y(i,".open-next-build.tar.gz"),j=[".open-next"];if(ae(Y(i,"db"))&&j.push("db"),ae(Y(i,"drizzle.config.ts"))&&j.push("drizzle.config.ts"),ae(Y(i,"package.json"))&&j.push("package.json"),!(await Qe("tar",["-czf",E,"-C",i,...j],i,6e4)).success)return c("Failed to create build archive. Check disk space and permissions.",!0);let G;{let P=Y(i,".mistflow-source.tar.gz");(await Qe("tar",["-czf",P,"-C",i,"--exclude",".open-next","--exclude","node_modules","--exclude",".git","--exclude",".next","--exclude",".open-next-build.tar.gz","--exclude",".mistflow-source.tar.gz","."],i,6e4)).success?G=P:console.error("[deploy] Source archive creation failed, continuing without it")}b("upload","Uploading to Mistflow...");let ie=!!p.hasAdmin&&o==="production"?Ba()?.email:void 0,A,q;try{let P=await Ra(u,E,o,ie,g,G,d);if(A=P.deployment_id??P.id,!A)return c("Upload succeeded but no deployment ID was returned. Check the Mistflow dashboard.",!0);q=P.status}catch(P){return Or(P,"Deploy")}finally{try{$r(E)}catch{}if(G)try{$r(G)}catch{}}b("deploying","Deploying to the edge...");let oe=Date.now(),Ne=12e4,xe=3e3,ne=[Jr(q)],Z=q;for(;Date.now()-oe<Ne;){await Pn(xe);let P;try{P=await Be(A)}catch{continue}if(P.status!==Z&&(ne.push(Jr(P.status)),Z=P.status),P.status==="live"){let I=((Date.now()-oe)/1e3).toFixed(0),M=P.url??"";if(!M)return c("Deployment marked as live but no URL was returned. Check the Mistflow dashboard.",!0);let ee=o==="preview";if(!ee){Bn(i,M);try{let{readLocalState:x,syncRemoteState:W}=await import("./state-manager-ZVLGPYXN.js"),F=x(i);F&&u&&(F.deployCount=(F.deployCount??0)+1,W(u,F).catch(()=>{}))}catch{}if(ma(i)&&Kr(i))try{Vr(i)&&qr(i,"Update deploy metadata"),vn(i)}catch{}}let D=ee?"Preview":"App",z=xa(i),v=z.name,S=typeof v=="string"?v:"my app",w=z.features,B=Array.isArray(w)?w.length:0,_=z.plan,K=_&&typeof _=="object"&&"steps"in _?_.steps:void 0,Q=Array.isArray(K)?K.length:0,T=h.map(x=>x.message),C={url:M,time:`${I}s`,deploymentId:A,environment:o,statusLog:ne,deployTimeline:T,message:ee?`${D} is live at ${M} \u2014 preview deployed in ${I}s. This URL expires in 72 hours.`:`Your app is live at ${M} \u2014 deployed in ${I}s.`};if(ee)C.instruction=["STAGING FLOW: The preview is deployed with an isolated database. Verify it before going live.","","1. Call mist_build with action='qa' and url='"+M+"' to test the preview.","2. If QA passes \u2014 tell the user the preview looks good and ask: 'Ready to go live?'","3. If QA finds issues \u2014 fix them, then call mist_deploy action='deploy' environment='preview' to redeploy the preview.","4. When user confirms \u2014 call mist_deploy action='promote' to push to production (~10s).","","Show the preview URL to the user so they can check it themselves while QA runs."].join(`
12452
- `),C.nextAction=`MANDATORY: Call mist_build with action='qa' and url='${M}' to verify the preview. After QA passes, ask user to confirm, then call mist_deploy action='promote'.`,C.qaRequired=!0,C.qaUrl=M,C.previewDeploymentId=A,C.promoteAction=`mist_deploy action='promote' deploymentId='${A}'`;else{let x=encodeURIComponent(`Just built "${S}" with AI and deployed it live in ${I}s.
10882
+ Fix these issues and try again.`,!0);let ne=_(i,".open-next");if(!Z(ne))return c("Build succeeded but .open-next/ directory not found. Check your OpenNext configuration.",!0);f("package","Packaging build artifacts...");let G=_(i,".open-next-build.tar.gz"),J=[".open-next"];if(Z(_(i,"db"))&&J.push("db"),Z(_(i,"drizzle.config.ts"))&&J.push("drizzle.config.ts"),Z(_(i,"package.json"))&&J.push("package.json"),!(await Qe("tar",["-czf",G,"-C",i,...J],i,6e4)).success)return c("Failed to create build archive. Check disk space and permissions.",!0);let q;{let T=_(i,".mistflow-source.tar.gz");(await Qe("tar",["-czf",T,"-C",i,"--exclude",".open-next","--exclude","node_modules","--exclude",".git","--exclude",".next","--exclude",".open-next-build.tar.gz","--exclude",".mistflow-source.tar.gz","."],i,6e4)).success?q=T:console.error("[deploy] Source archive creation failed, continuing without it")}f("upload","Uploading to Mistflow...");let le=!!u.hasAdmin&&o==="production"?Ba()?.email:void 0,F,N;try{let T=await Ra(p,G,o,le,g,q,d);if(F=T.deployment_id??T.id,!F)return c("Upload succeeded but no deployment ID was returned. Check the Mistflow dashboard.",!0);N=T.status}catch(T){return Kr(T,"Deploy")}finally{try{Qr(G)}catch{}if(q)try{Qr(q)}catch{}}f("deploying","Deploying to the edge...");let oe=Date.now(),ye=12e4,Ce=3e3,de=[ti(N)],Q=N;for(;Date.now()-oe<ye;){await Uo(Ce);let T;try{T=await Pe(F)}catch{continue}if(T.status!==Q&&(de.push(ti(T.status)),Q=T.status),T.status==="live"){let A=((Date.now()-oe)/1e3).toFixed(0),M=T.url??"";if(!M)return c("Deployment marked as live but no URL was returned. Check the Mistflow dashboard.",!0);let v=o==="preview";if(!v){Ho(i,M);try{let{readLocalState:R,syncRemoteState:B}=await import("./state-manager-73ZUDKOP.js"),L=R(i);L&&p&&(L.deployCount=(L.deployCount??0)+1,B(p,L).catch(()=>{}))}catch{}if(ma(i)&&ei(i))try{Xr(i)&&Zr(i,"Update deploy metadata"),Ro(i)}catch{}}let x=v?"Preview":"App",C=xa(i),I=C.name,j=typeof I=="string"?I:"my app",H=C.features,$=Array.isArray(H)?H.length:0,he=C.plan,te=he&&typeof he=="object"&&"steps"in he?he.steps:void 0,ae=Array.isArray(te)?te.length:0,V=h.map(R=>R.message),y={url:M,time:`${A}s`,deploymentId:F,environment:o,statusLog:de,deployTimeline:V,message:v?`${x} is live at ${M} \u2014 preview deployed in ${A}s. This URL expires in 72 hours.`:`Your app is live at ${M} \u2014 deployed in ${A}s.`};if(v)y.instruction=["STAGING FLOW: The preview is deployed with an isolated database. Verify it before going live.","","1. Call mist_build with action='qa' and url='"+M+"' to test the preview.","2. If QA passes \u2014 tell the user the preview looks good and ask: 'Ready to go live?'","3. If QA finds issues \u2014 fix them, then call mist_deploy action='deploy' environment='preview' to redeploy the preview.","4. When user confirms \u2014 call mist_deploy action='promote' to push to production (~10s).","","Show the preview URL to the user so they can check it themselves while QA runs."].join(`
10883
+ `),y.nextAction=`MANDATORY: Call mist_build with action='qa' and url='${M}' to verify the preview. After QA passes, ask user to confirm, then call mist_deploy action='promote'.`,y.qaRequired=!0,y.qaUrl=M,y.previewDeploymentId=F,y.promoteAction=`mist_deploy action='promote' deploymentId='${F}'`;else{let R=encodeURIComponent(`Just built "${j}" with AI and deployed it live in ${A}s.
12453
10884
 
12454
- ${Q} steps, ${B} features, zero config.
10885
+ ${ae} steps, ${$} features, zero config.
12455
10886
 
12456
10887
  ${M}
12457
10888
 
12458
- Built with @mistflow`),W=encodeURIComponent(`I just described an app idea and got a live, working URL in ${I} seconds.
10889
+ Built with @mistflow`),B=encodeURIComponent(`I just described an app idea and got a live, working URL in ${A} seconds.
12459
10890
 
12460
- "${S}" \u2014 ${Q} build steps, ${B} features, fully deployed.
10891
+ "${j}" \u2014 ${ae} build steps, ${$} features, fully deployed.
12461
10892
 
12462
10893
  ${M}
12463
10894
 
12464
- Built with Mistflow (mistflow.ai)`);C.share={tweetUrl:`https://twitter.com/intent/tweet?text=${x}`,linkedInUrl:`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(M)}`,celebration:["","================================================",` ${S} is LIVE!`,"================================================","",` ${M}`,"",` Deployed in ${I}s`,` ${B>0?`${B} features`:""}${B>0&&Q>0?" \xB7 ":""}${Q>0?`${Q} build steps`:""}`,""," Share it:",` Twitter \u2192 https://twitter.com/intent/tweet?text=${x}`,` LinkedIn \u2192 https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(M)}`,"","================================================"].join(`
12465
- `)},C.instruction=["IMPORTANT: The app is deployed but NOT verified yet. Before celebrating:","","1. Call mist_build with action='qa' to test the live app.","2. If QA passes \u2014 present the URL prominently and show the celebration block above.","3. If QA finds issues \u2014 fix them, redeploy (mist_deploy action='deploy'), and run qa again.","4. Keep looping until QA passes. Only celebrate when all checks are green.","","Do NOT show the URL to the user until QA passes. A broken app is worse than no app."].join(`
12466
- `),C.nextAction=`MANDATORY: Call mist_build with action='qa' and url='${M}' to verify the app works. Do NOT tell the user the app is ready until QA passes.`,C.qaRequired=!0,C.qaUrl=M}P.admin_credentials&&(C.adminCredentials={message:`Admin account created. Save these credentials \u2014 they won't be shown again.
10895
+ Built with Mistflow (mistflow.ai)`);y.share={tweetUrl:`https://twitter.com/intent/tweet?text=${R}`,linkedInUrl:`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(M)}`,celebration:["","================================================",` ${j} is LIVE!`,"================================================","",` ${M}`,"",` Deployed in ${A}s`,` ${$>0?`${$} features`:""}${$>0&&ae>0?" \xB7 ":""}${ae>0?`${ae} build steps`:""}`,""," Share it:",` Twitter \u2192 https://twitter.com/intent/tweet?text=${R}`,` LinkedIn \u2192 https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(M)}`,"","================================================"].join(`
10896
+ `)},y.instruction=["IMPORTANT: The app is deployed but NOT verified yet. Before celebrating:","","1. Call mist_build with action='qa' to test the live app.","2. If QA passes \u2014 present the URL prominently and show the celebration block above.","3. If QA finds issues \u2014 fix them, redeploy (mist_deploy action='deploy'), and run qa again.","4. Keep looping until QA passes. Only celebrate when all checks are green.","","Do NOT show the URL to the user until QA passes. A broken app is worse than no app."].join(`
10897
+ `),y.nextAction=`MANDATORY: Call mist_build with action='qa' and url='${M}' to verify the app works. Do NOT tell the user the app is ready until QA passes.`,y.qaRequired=!0,y.qaUrl=M}T.admin_credentials&&(y.adminCredentials={message:`Admin account created. Save these credentials \u2014 they won't be shown again.
12467
10898
 
12468
- Email: ${P.admin_credentials.email}
12469
- Password: ${P.admin_credentials.password}
10899
+ Email: ${T.admin_credentials.email}
10900
+ Password: ${T.admin_credentials.password}
12470
10901
  Login: ${M}/login
12471
- Admin panel: ${M}/admin`}),s.length>0&&(C.warnings=s);let L=[];if(!ee){let x=JSON.stringify(z).toLowerCase();L.push({action:"Add a custom domain",command:"mist_config resource='domain' action='add' domain='yourdomain.com'",reason:"Give your app a professional URL instead of the default .mistflow.app domain.",priority:"medium"}),ma(i)&&!Kr(i)&&L.push({action:"Back up to GitHub",command:"Create a repo at github.com/new, then tell me the URL and I'll push your code there",reason:"Your source code is saved with every deploy, but GitHub gives you an extra backup and lets you collaborate.",priority:"medium"});let W=x.includes("user")||x.includes("account")||x.includes("member"),F=x.includes("stripe")||x.includes("payment")||x.includes("billing");W&&!F&&L.push({action:"Add payments",command:"Tell the AI: 'Add Stripe payments to my app'",reason:"Your app has user accounts \u2014 you could monetize with subscriptions or one-time payments.",priority:"low"}),L.push({action:"Share your app",command:"mist_project action='share'",reason:"Generate a shareable link so others can fork and customize your app.",priority:"low"}),L.push({action:"Make changes",command:"Describe what you want to change, then run mist_deploy action='deploy'",reason:"Edit your code and redeploy in seconds. Your app is yours to evolve.",priority:"low"}),L.push({action:"See analytics",command:`Visit ${Ia()} to see pageviews and visitors`,reason:"Track how people are using your app.",priority:"low"})}return L.length>0&&(C.nextSteps=L),Ie(M,JSON.stringify(C))}if(P.status==="failed")return c(P.error??"Deployment failed. Check the Mistflow dashboard for details.",!0)}return c(`Deploy is taking longer than expected. Your deploy ID is ${A} \u2014 check status later.`,!0)}import{z as Mt}from"zod";import{resolve as Dn,join as Mn}from"path";import{execFileSync as Rn}from"child_process";var Ed=Mt.object({projectPath:Mt.string().optional().describe("Path to the project directory (default: cwd)"),action:Mt.enum(["redeploy","rollback"]).describe("Action to perform: 'redeploy' re-deploys the latest build, 'rollback' reverts to a specific previous deployment"),deploymentId:Mt.string().optional().describe("Deployment ID to rollback to (required for 'rollback')")});function Re(r,e){return Rn("git",r,{cwd:e,encoding:"utf-8",timeout:3e4,stdio:["pipe","pipe","pipe"]}).trim()}function ti(r){try{return Re(["rev-parse","--is-inside-work-tree"],r),!0}catch{return!1}}async function Ln(r,e,t,a){if(e&&ti(r))try{Re(["cat-file","-t",e],r);let n=!1;try{Re(["status","--porcelain"],r).length>0&&(Re(["stash","push","-m","mistflow-rollback-auto-stash"],r),n=!0)}catch{}return Re(["reset","--hard",e],r),Re(["commit","--allow-empty","-m","Rollback to previous deploy"],r),{method:"git",success:!0,...n?{warning:"Your uncommitted changes were saved to git stash. Run `git stash pop` to restore them."}:{}}}catch{}if(t&&a)try{let{existsSync:n,mkdirSync:o,rmSync:i}=await import("fs"),l=Mn(r,".mistflow-rollback-source.tar.gz");await $a(a,l);let{spawn:s}=await import("child_process");await new Promise((d,p)=>{let u=s("tar",["-xzf",l,"-C",r,"--exclude","node_modules","--exclude",".git"],{cwd:r,stdio:"pipe"});u.on("close",h=>h===0?d():p(new Error(`tar exit ${h}`))),u.on("error",p)});try{i(l)}catch{}if(ti(r))try{Re(["add","-A"],r),Re(["commit","-m","Rollback to previous deploy (from source snapshot)"],r)}catch{}return{method:"r2",success:!0}}catch(n){return{method:"r2",success:!1,error:n instanceof Error?n.message:"Source download failed"}}return{method:"none",success:!1,error:"No source snapshot available for this deployment"}}function Fn(r){return new Promise(e=>setTimeout(e,r))}function Nn(r){switch(r){case"pending":return"Provisioning...";case"building":return"Building...";case"deploying":return"Deploying to Cloudflare...";case"verifying":return"Verifying deployment...";default:return`Status: ${r}`}}async function ai(r,e,t){let a=Date.now(),n=12e4,o=3e3,i=[],l="";for(;Date.now()-a<n;){await Fn(o);let s;try{s=await Be(r)}catch{continue}if(s.status!==l&&(i.push(Nn(s.status)),l=s.status),s.status==="live"){let d=((Date.now()-a)/1e3).toFixed(0),p=s.url??"";if(t)try{await t()}catch{}return c(JSON.stringify({url:p,time:`${d}s`,deploymentId:r,statusLog:i,message:p?`${e} complete \u2014 live at ${p} in ${d}s.`:`${e} complete in ${d}s.`}))}if(s.status==="failed")return c(s.error??`${e} failed. Check the Mistflow dashboard for details.`,!0)}return c(`${e} is taking longer than expected. Deployment ID: ${r} \u2014 check status later.`,!0)}async function wa(r){let{projectPath:e,action:t,deploymentId:a}=r,n=Dn(e??process.cwd());if(!le())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let i=we(n)?.projectId;if(!i)return c("No project ID found. Deploy your project first with mist_deploy, or initialize with mist_plan + mist_build.",!0);try{switch(t){case"redeploy":{let l=await Oa(i);return ai(l.deployment_id,"Redeploy")}case"rollback":{if(!a)return c("Deployment ID is required for rollback. Use mist_project (action: 'deployments') to see previous deployment IDs.",!0);let l=await za(a);return ai(l.deployment_id,"Rollback",async()=>{let s=await Ln(n,l.git_commit_sha,l.source_artifact_key,a);s.success||console.error(`[rollback] Local source restore failed: ${s.error}`),s.warning&&console.error(`[rollback] ${s.warning}`)})}default:return c(`Unknown action: ${t}. Use redeploy or rollback.`,!0)}}catch(l){if(l instanceof ce)return c(l.message,!0);let s=l instanceof Error?l.message:"An unexpected error occurred";return c(s,!0)}}import{resolve as Un}from"path";function En(r){return new Promise(e=>setTimeout(e,r))}async function ri(r){let e=Un(r.projectPath??process.cwd());if(!le())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let a=we(e)?.projectId;if(!a)return c("No project ID found. Deploy the project first.",!0);let n=r.deploymentId;if(!n)try{let d=(await et(a)).find(p=>p.environment==="preview"&&p.status==="live");if(!d)return c("No live preview found to promote. Deploy with staging mode first, then call promote after QA passes.",!0);n=d.id}catch{return c("Could not list deployments. Check your connection.",!0)}console.error(`[promote] Promoting preview ${n} to production...`);let o;try{o=(await ja(a,n)).deployment_id}catch(s){let d=s instanceof Error?s.message:"Promote failed";return c(`Promote failed: ${d}`,!0)}let i=Date.now(),l=12e4;for(;Date.now()-i<l;){await En(3e3);try{let s=await Be(o);if(s.status==="live"){let d=((Date.now()-i)/1e3).toFixed(0),p=s.url??"",u={url:p,time:`${d}s`,deploymentId:o,environment:"production",promoted:!0,message:`Promoted to production at ${p} in ${d}s. Same build that passed QA on preview.`};return u.instruction=["IMPORTANT: The app has been promoted to production. Run a quick QA check to verify.","","1. Call mist_build with action='qa' to test the live production app.","2. If QA passes \u2014 celebrate! Present the URL to the user.","3. If QA finds issues \u2014 these are likely environment differences (auth, DNS). Report them."].join(`
12472
- `),u.nextAction=`MANDATORY: Call mist_build with action='qa' and url='${p}' to verify production.`,u.qaRequired=!0,u.qaUrl=p,p?Ie(p,JSON.stringify(u)):c(JSON.stringify(u))}if(s.status==="failed")return c(`Promote failed: ${s.error??"Check the Mistflow dashboard for details."}`,!0)}catch{}}return c(`Promote is taking longer than expected. Deployment ID: ${o}`,!0)}import{z as ii}from"zod";import{spawn as Wn,execFileSync as oi}from"child_process";import{existsSync as Lt,readFileSync as ni,writeFileSync as _n,mkdirSync as On}from"fs";import{join as Xe,resolve as jn}from"path";import{homedir as si}from"os";import{createConnection as zn}from"net";import{existsSync as Hn,readFileSync as Gn}from"fs";function Rt(r){let e=new Set;if(!Hn(r))return e;let t=Gn(r,"utf-8");for(let a of t.split(`
12473
- `)){let n=a.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o>0){let i=n.slice(0,o).trim(),l=n.slice(o+1).trim();l&&l!=='""'&&l!=="''"&&e.add(i)}}return e}var $n=ii.object({projectPath:ii.string().optional().describe("Path to the project directory (default: current working directory)")});function li(){return Xe(si(),".mistflow","processes.json")}function di(){let r=li();if(!Lt(r))return[];try{return JSON.parse(ni(r,"utf-8"))}catch{return[]}}function ci(r){let e=Xe(si(),".mistflow");Lt(e)||On(e,{recursive:!0}),_n(li(),JSON.stringify(r,null,2))}function Vn(){let r=di(),e=[];for(let t of r)try{process.kill(t.pid,0),e.push(t)}catch{}ci(e)}function pi(r){return new Promise(e=>{let t=zn({port:r,host:"127.0.0.1"});t.on("connect",()=>{t.destroy(),e(!0)}),t.on("error",()=>{e(!1)})})}async function qn(r,e,t){let a=Date.now();for(;Date.now()-a<e;){if(await pi(r))return!0;await new Promise(n=>setTimeout(n,t))}return!1}function Kn(r){return Lt(Xe(r,"mistflow.json"))}function Jn(r){let e=Xe(r,"mistflow.json");if(!Lt(e))return[];let t;try{t=JSON.parse(ni(e,"utf-8"))}catch{return[]}let a=t.env?.required;if(!a||typeof a!="object")return[];let n=Object.keys(a);if(n.length===0)return[];let o=Rt(Xe(r,".env.local"));return n.filter(i=>!o.has(i))}var ui={name:"mist_preview",description:"Build the app and start a local production server on localhost:3000 for previewing. Use when the user says 'mist preview'.",inputSchema:$n,handler:async r=>{let t=jn(r.projectPath??process.cwd()),a=3e3;if(!Kn(t))return ge(t);let n=Jn(t);if(n.length>0)return c(`Missing required environment variables in .env.local: ${n.join(", ")}. Add them to ${Xe(t,".env.local")} before previewing.`,!0);Vn();let o=await pi(a),i=di(),l=i.some(u=>u.type==="dev-server"&&u.port===a);if(o&&!l)return c(`Port ${a} is in use. Stop the other process or I will use a different port.`,!0);let s=[...i];if(!o){try{oi("npx",["drizzle-kit","push"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:3e4})}catch{console.error("[preview] drizzle-kit push failed, continuing...")}try{oi("npm",["run","build"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:18e4})}catch(b){let f=b instanceof Error&&"stderr"in b?String(b.stderr).slice(-1500):"",g=b instanceof Error&&"stdout"in b?String(b.stdout).slice(-1500):"",y=(f+`
10902
+ Admin panel: ${M}/admin`}),l.length>0&&(y.warnings=l);let k=[];if(!v){let R=JSON.stringify(C).toLowerCase();k.push({action:"Add a custom domain",command:"mist_config resource='domain' action='add' domain='yourdomain.com'",reason:"Give your app a professional URL instead of the default .mistflow.app domain.",priority:"medium"}),ma(i)&&!ei(i)&&k.push({action:"Back up to GitHub",command:"Create a repo at github.com/new, then tell me the URL and I'll push your code there",reason:"Your source code is saved with every deploy, but GitHub gives you an extra backup and lets you collaborate.",priority:"medium"});let B=R.includes("user")||R.includes("account")||R.includes("member"),L=R.includes("stripe")||R.includes("payment")||R.includes("billing");B&&!L&&k.push({action:"Add payments",command:"Tell the AI: 'Add Stripe payments to my app'",reason:"Your app has user accounts \u2014 you could monetize with subscriptions or one-time payments.",priority:"low"}),k.push({action:"Share your app",command:"mist_project action='share'",reason:"Generate a shareable link so others can fork and customize your app.",priority:"low"}),k.push({action:"Make changes",command:"Describe what you want to change, then run mist_deploy action='deploy'",reason:"Edit your code and redeploy in seconds. Your app is yours to evolve.",priority:"low"}),k.push({action:"See analytics",command:`Visit ${Da()} to see pageviews and visitors`,reason:"Track how people are using your app.",priority:"low"})}return k.length>0&&(y.nextSteps=k),Be(M,JSON.stringify(y))}if(T.status==="failed")return c(T.error??"Deployment failed. Check the Mistflow dashboard for details.",!0)}return c(`Deploy is taking longer than expected. Your deploy ID is ${F} \u2014 check status later.`,!0)}import{z as Nt}from"zod";import{resolve as Oo,join as _o}from"path";import{execFileSync as jo}from"child_process";var Jd=Nt.object({projectPath:Nt.string().optional().describe("Path to the project directory (default: cwd)"),action:Nt.enum(["redeploy","rollback"]).describe("Action to perform: 'redeploy' re-deploys the latest build, 'rollback' reverts to a specific previous deployment"),deploymentId:Nt.string().optional().describe("Deployment ID to rollback to (required for 'rollback')")});function Me(r,e){return jo("git",r,{cwd:e,encoding:"utf-8",timeout:3e4,stdio:["pipe","pipe","pipe"]}).trim()}function si(r){try{return Me(["rev-parse","--is-inside-work-tree"],r),!0}catch{return!1}}async function zo(r,e,t,a){if(e&&si(r))try{Me(["cat-file","-t",e],r);let n=!1;try{Me(["status","--porcelain"],r).length>0&&(Me(["stash","push","-m","mistflow-rollback-auto-stash"],r),n=!0)}catch{}return Me(["reset","--hard",e],r),Me(["commit","--allow-empty","-m","Rollback to previous deploy"],r),{method:"git",success:!0,...n?{warning:"Your uncommitted changes were saved to git stash. Run `git stash pop` to restore them."}:{}}}catch{}if(t&&a)try{let{existsSync:n,mkdirSync:o,rmSync:i}=await import("fs"),s=_o(r,".mistflow-rollback-source.tar.gz");await qa(a,s);let{spawn:l}=await import("child_process");await new Promise((d,u)=>{let p=l("tar",["-xzf",s,"-C",r,"--exclude","node_modules","--exclude",".git"],{cwd:r,stdio:"pipe"});p.on("close",h=>h===0?d():u(new Error(`tar exit ${h}`))),p.on("error",u)});try{i(s)}catch{}if(si(r))try{Me(["add","-A"],r),Me(["commit","-m","Rollback to previous deploy (from source snapshot)"],r)}catch{}return{method:"r2",success:!0}}catch(n){return{method:"r2",success:!1,error:n instanceof Error?n.message:"Source download failed"}}return{method:"none",success:!1,error:"No source snapshot available for this deployment"}}function $o(r){return new Promise(e=>setTimeout(e,r))}function Vo(r){switch(r){case"pending":return"Provisioning...";case"building":return"Building...";case"deploying":return"Deploying to Cloudflare...";case"verifying":return"Verifying deployment...";default:return`Status: ${r}`}}async function li(r,e,t){let a=Date.now(),n=12e4,o=3e3,i=[],s="";for(;Date.now()-a<n;){await $o(o);let l;try{l=await Pe(r)}catch{continue}if(l.status!==s&&(i.push(Vo(l.status)),s=l.status),l.status==="live"){let d=((Date.now()-a)/1e3).toFixed(0),u=l.url??"";if(t)try{await t()}catch{}return c(JSON.stringify({url:u,time:`${d}s`,deploymentId:r,statusLog:i,message:u?`${e} complete \u2014 live at ${u} in ${d}s.`:`${e} complete in ${d}s.`}))}if(l.status==="failed")return c(l.error??`${e} failed. Check the Mistflow dashboard for details.`,!0)}return c(`${e} is taking longer than expected. Deployment ID: ${r} \u2014 check status later.`,!0)}async function wa(r){let{projectPath:e,action:t,deploymentId:a}=r,n=Oo(e??process.cwd());if(!se())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let i=we(n)?.projectId;if(!i)return c("No project ID found. Deploy your project first with mist_deploy, or initialize with mist_plan + mist_build.",!0);try{switch(t){case"redeploy":{let s=await za(i);return li(s.deployment_id,"Redeploy")}case"rollback":{if(!a)return c("Deployment ID is required for rollback. Use mist_project (action: 'deployments') to see previous deployment IDs.",!0);let s=await Va(a);return li(s.deployment_id,"Rollback",async()=>{let l=await zo(n,s.git_commit_sha,s.source_artifact_key,a);l.success||console.error(`[rollback] Local source restore failed: ${l.error}`),l.warning&&console.error(`[rollback] ${l.warning}`)})}default:return c(`Unknown action: ${t}. Use redeploy or rollback.`,!0)}}catch(s){if(s instanceof ce)return c(s.message,!0);let l=s instanceof Error?s.message:"An unexpected error occurred";return c(l,!0)}}import{resolve as qo}from"path";function Ko(r){return new Promise(e=>setTimeout(e,r))}async function di(r){let e=qo(r.projectPath??process.cwd());if(!se())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let a=we(e)?.projectId;if(!a)return c("No project ID found. Deploy the project first.",!0);let n=r.deploymentId;if(!n)try{let d=(await et(a)).find(u=>u.environment==="preview"&&u.status==="live");if(!d)return c("No live preview found to promote. Deploy with staging mode first, then call promote after QA passes.",!0);n=d.id}catch{return c("Could not list deployments. Check your connection.",!0)}console.error(`[promote] Promoting preview ${n} to production...`);let o;try{o=(await $a(a,n)).deployment_id}catch(l){let d=l instanceof Error?l.message:"Promote failed";return c(`Promote failed: ${d}`,!0)}let i=Date.now(),s=12e4;for(;Date.now()-i<s;){await Ko(3e3);try{let l=await Pe(o);if(l.status==="live"){let d=((Date.now()-i)/1e3).toFixed(0),u=l.url??"",p={url:u,time:`${d}s`,deploymentId:o,environment:"production",promoted:!0,message:`Promoted to production at ${u} in ${d}s. Same build that passed QA on preview.`};return p.instruction=["IMPORTANT: The app has been promoted to production. Run a quick QA check to verify.","","1. Call mist_build with action='qa' to test the live production app.","2. If QA passes \u2014 celebrate! Present the URL to the user.","3. If QA finds issues \u2014 these are likely environment differences (auth, DNS). Report them."].join(`
10903
+ `),p.nextAction=`MANDATORY: Call mist_build with action='qa' and url='${u}' to verify production.`,p.qaRequired=!0,p.qaUrl=u,u?Be(u,JSON.stringify(p)):c(JSON.stringify(p))}if(l.status==="failed")return c(`Promote failed: ${l.error??"Check the Mistflow dashboard for details."}`,!0)}catch{}}return c(`Promote is taking longer than expected. Deployment ID: ${o}`,!0)}import{z as ci}from"zod";import{spawn as Qo,execFileSync as pi}from"child_process";import{existsSync as Et,readFileSync as ui,writeFileSync as Xo,mkdirSync as Zo}from"fs";import{join as Xe,resolve as es}from"path";import{homedir as hi}from"os";import{createConnection as ts}from"net";import{existsSync as Jo,readFileSync as Yo}from"fs";function Ft(r){let e=new Set;if(!Jo(r))return e;let t=Yo(r,"utf-8");for(let a of t.split(`
10904
+ `)){let n=a.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o>0){let i=n.slice(0,o).trim(),s=n.slice(o+1).trim();s&&s!=='""'&&s!=="''"&&e.add(i)}}return e}var as=ci.object({projectPath:ci.string().optional().describe("Path to the project directory (default: current working directory)")});function gi(){return Xe(hi(),".mistflow","processes.json")}function mi(){let r=gi();if(!Et(r))return[];try{return JSON.parse(ui(r,"utf-8"))}catch{return[]}}function fi(r){let e=Xe(hi(),".mistflow");Et(e)||Zo(e,{recursive:!0}),Xo(gi(),JSON.stringify(r,null,2))}function rs(){let r=mi(),e=[];for(let t of r)try{process.kill(t.pid,0),e.push(t)}catch{}fi(e)}function bi(r){return new Promise(e=>{let t=ts({port:r,host:"127.0.0.1"});t.on("connect",()=>{t.destroy(),e(!0)}),t.on("error",()=>{e(!1)})})}async function is(r,e,t){let a=Date.now();for(;Date.now()-a<e;){if(await bi(r))return!0;await new Promise(n=>setTimeout(n,t))}return!1}function ns(r){return Et(Xe(r,"mistflow.json"))}function os(r){let e=Xe(r,"mistflow.json");if(!Et(e))return[];let t;try{t=JSON.parse(ui(e,"utf-8"))}catch{return[]}let a=t.env?.required;if(!a||typeof a!="object")return[];let n=Object.keys(a);if(n.length===0)return[];let o=Ft(Xe(r,".env.local"));return n.filter(i=>!o.has(i))}var xi={name:"mist_preview",description:"Build the app and start a local production server on localhost:3000 for previewing. Use when the user says 'mist preview'.",inputSchema:as,handler:async r=>{let t=es(r.projectPath??process.cwd()),a=3e3;if(!ns(t))return ge(t);let n=os(t);if(n.length>0)return c(`Missing required environment variables in .env.local: ${n.join(", ")}. Add them to ${Xe(t,".env.local")} before previewing.`,!0);rs();let o=await bi(a),i=mi(),s=i.some(p=>p.type==="dev-server"&&p.port===a);if(o&&!s)return c(`Port ${a} is in use. Stop the other process or I will use a different port.`,!0);let l=[...i];if(!o){try{pi("npx",["drizzle-kit","push"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:3e4})}catch{console.error("[preview] drizzle-kit push failed, continuing...")}try{pi("npm",["run","build"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:18e4})}catch(f){let b=f instanceof Error&&"stderr"in f?String(f.stderr).slice(-1500):"",g=f instanceof Error&&"stdout"in f?String(f.stdout).slice(-1500):"",w=(b+`
12474
10905
  `+g).trim();return c(`Build failed. Fix the errors before previewing:
12475
10906
 
12476
- ${y}`,!0)}let u=Wn("npx",["next","start","-p",String(a)],{cwd:t,detached:!0,stdio:["ignore","pipe","pipe"]}),h="";if(u.stderr?.on("data",b=>{h+=b.toString()}),u.pid&&(u.unref(),s.push({pid:u.pid,type:"dev-server",port:a,startedAt:new Date().toISOString()}),ci(s)),!await qn(a,15e3,500)){let b=h?`Server failed to start:
10907
+ ${w}`,!0)}let p=Qo("npx",["next","start","-p",String(a)],{cwd:t,detached:!0,stdio:["ignore","pipe","pipe"]}),h="";if(p.stderr?.on("data",f=>{h+=f.toString()}),p.pid&&(p.unref(),l.push({pid:p.pid,type:"dev-server",port:a,startedAt:new Date().toISOString()}),fi(l)),!await is(a,15e3,500)){let f=h?`Server failed to start:
12477
10908
 
12478
- ${h.slice(-1e3)}`:"Server failed to start within 15s. Check for runtime errors.";return c(b,!0)}}let d=`http://localhost:${a}`,p=JSON.stringify({localUrl:d,message:`Preview is live at ${d}. Run mist_deploy to get your permanent URL on mistflow.app.`});return Ie(d,p)}};import{resolve as Yn,join as Qn}from"path";import{existsSync as Xn,readFileSync as Zn}from"fs";var va="test@mistflow.dev",hi="MistflowTest123!",es="Test User";function gi(r){let e=Qn(r,"mistflow.json");if(!Xn(e))return null;try{return JSON.parse(Zn(e,"utf-8"))}catch{return null}}function ts(r){let e=JSON.stringify(r).toLowerCase();return["auth","login","sign-in","sign-up","signin","signup"].some(t=>e.includes(t))}function as(r){let e=r.plan;if(!e?.steps)return[];let t=new Set;for(let n of e.steps)if(n.pages)for(let o of n.pages)t.add(o);let a=new Set(["login","signup","sign-in","sign-up","signin","signout","sign-out","logout"]);return[...t].filter(n=>!a.has(n.toLowerCase())).slice(0,3)}function rs(r){let e=r.deploy;return e?.url?e.url:typeof r.deployUrl=="string"?r.deployUrl:null}async function mi(r){let e=Yn(r.projectPath??process.cwd()),t=r.verifyUrl,a=null;if(t)a=gi(e);else{if(a=gi(e),!a)return c("No mistflow.json found. Run mist_deploy first, or pass verifyUrl explicitly.",!0);if(t=rs(a)??void 0,!t)return c("No deploy URL found in mistflow.json. Deploy your app first with mist_deploy.",!0)}t.startsWith("http")||(t=`https://${t}`);let n=a?ts(a):!1,o=a?as(a):[],i;try{i=await pt()}catch{return c("Browser not available. Install Playwright to use verify: npx playwright install chromium",!0)}let l={verified:!0,url:t,authTested:!1,testUser:null,pages:[],message:""},s=[];try{await i.goto(t,{waitUntil:"domcontentloaded",timeout:3e4}),await i.waitForLoadState("networkidle").catch(()=>{})}catch{return l.verified=!1,l.message=`Could not load ${t}. The app may not be deployed yet or the URL may be incorrect.`,c(JSON.stringify(l),!0)}let d=await i.title(),p=d.toLowerCase().includes("error")||d.toLowerCase().includes("404")?"error":"ok";l.pages.push({path:"/",status:p,title:d});try{let f=await Pe(i,!1);s.push({data:f.toString("base64"),mimeType:"image/png"})}catch{}if(p==="error"&&(l.verified=!1),n)try{(await i.evaluate(async g=>{let y=await fetch("/api/auth/sign-up/email",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});return{status:y.status,ok:y.ok}},{email:va,password:hi,name:es})).ok||await i.evaluate(async g=>{let y=await fetch("/api/auth/sign-in/email",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});return{status:y.status,ok:y.ok}},{email:va,password:hi}),await i.reload({waitUntil:"domcontentloaded",timeout:15e3}),await i.waitForLoadState("networkidle").catch(()=>{}),l.authTested=!0,l.testUser={email:va};try{let g=await Pe(i,!1);s.push({data:g.toString("base64"),mimeType:"image/png"})}catch{}}catch{console.error("[verify] Auth test failed, continuing with public pages")}for(let f of o){let g=f.startsWith("/")?f:`/${f}`;try{await i.goto(`${t}${g}`,{waitUntil:"domcontentloaded",timeout:15e3}),await i.waitForLoadState("networkidle").catch(()=>{});let y=await i.title(),N=y.toLowerCase().includes("404")||y.toLowerCase().includes("not found")?"error":"ok";l.pages.push({path:g,status:N,title:y}),N==="error"&&(l.verified=!1);try{let R=await Pe(i,!1);s.push({data:R.toString("base64"),mimeType:"image/png"})}catch{}}catch{l.pages.push({path:g,status:"error",title:"Timeout"}),l.verified=!1}}let u=l.pages.filter(f=>f.status==="ok").length,h=l.pages.length,m=l.authTested?" Auth login successful.":"";l.message=l.verified?`Verified ${u}/${h} pages.${m} App looks good.`:`Verified ${u}/${h} pages \u2014 some issues found.${m} Check screenshots.`;let b=[{type:"text",text:JSON.stringify(l)}];for(let f of s)b.push({type:"image",data:f.data,mimeType:f.mimeType});return{content:b}}var is=Oe.object({action:Oe.enum(["deploy","promote","preview","redeploy","rollback","verify"]).describe("'deploy' builds and deploys to Cloudflare (auto-redirects to preview if staging mode is enabled). 'promote' promotes a verified preview to production (~10s, reuses the preview build). 'preview' builds the app and starts a local production server on localhost:3000. 'redeploy' re-deploys the latest build without rebuilding. 'rollback' reverts to a specific previous deployment. 'verify' navigates the deployed app, tests auth, and screenshots pages to confirm it works."),projectPath:Oe.string().optional().describe("Path to the project directory (default: cwd)"),environment:Oe.enum(["production","preview"]).optional().describe("(deploy) Target environment. Defaults to 'production'. Projects with staging mode auto-redirect to preview."),forceSchema:Oe.boolean().optional().describe("(deploy) Reset the database structure. Warning: this deletes existing data. Only use when the user confirms this is OK."),deploymentId:Oe.string().optional().describe("(rollback/promote) Deployment ID to rollback to, or preview deployment ID to promote"),verifyUrl:Oe.string().optional().describe("(verify) URL to verify. Defaults to deploy URL from mistflow.json")}),fi={name:"mist_deploy",description:"STEP 4 (final) of the Mistflow workflow. Deploy a Mistflow project. Call this AFTER all mist_build implement steps are done. If the project has staging mode enabled (configurable in dashboard), the tool automatically deploys to preview first with an isolated database. After QA passes, call action='promote' to go live (~10s, reuses the same build artifact). Actions: 'deploy' (default), 'promote' (promote preview to production), 'preview' (local dev server), 'redeploy', 'rollback', 'verify'. The workflow is: mist_plan \u2192 mist_build init \u2192 implement (repeat) \u2192 mist_build build \u2192 mist_deploy \u2192 mist_build qa.",inputSchema:is,handler:async r=>{let e=r;switch(e.action){case"deploy":return ei({projectPath:e.projectPath,environment:e.environment??"production",forceSchema:e.forceSchema});case"promote":return ri({projectPath:e.projectPath,deploymentId:e.deploymentId});case"preview":return ui.handler({projectPath:e.projectPath});case"redeploy":return wa({projectPath:e.projectPath,action:"redeploy"});case"rollback":return wa({projectPath:e.projectPath,action:"rollback",deploymentId:e.deploymentId});case"verify":return mi({projectPath:e.projectPath,verifyUrl:e.verifyUrl});default:return c(`Unknown action: ${e.action}. Use deploy, promote, preview, redeploy, rollback, or verify.`,!0)}}};import{z as re}from"zod";import{resolve as Ft}from"path";import{existsSync as Nt,readFileSync as Ut}from"fs";import{join as Et}from"path";import{z as Le}from"zod";import{resolve as os,join as bi}from"path";import{existsSync as ns,readFileSync as ss,writeFileSync as ls}from"fs";var ds=Le.object({action:Le.enum(["get","update"]).default("get").describe("'get' reads current project state. 'update' modifies it."),projectPath:Le.string().optional().describe("Path to the project directory (default: current working directory)"),completedStep:Le.number().optional().describe("(update only) Mark a plan step as completed by step number"),addEnvVar:Le.object({key:Le.string(),description:Le.string().optional(),setupUrl:Le.string().optional()}).optional().describe("(update only) Add a required env var to the project manifest")}),xi={name:"mist_state",description:"Read or update project state in mistflow.json. Use action='get' to load plan progress, env var status, and deploy info. Use action='update' to mark plan steps complete or add required env vars. Use when the user says 'mist status', 'mist state', or 'mist update state'.",inputSchema:ds,handler:async r=>{let e=r,t=os(e.projectPath??process.cwd()),a=bi(t,"mistflow.json");if(!ns(a))return ge(t);let n;try{n=JSON.parse(ss(a,"utf-8"))}catch{return c("Failed to parse mistflow.json.",!0)}if(e.action==="get"){let l=n.plan,s=l?.steps?.filter(g=>g.status==="completed").length??0,d=l?.steps?.length??0,p=Rt(bi(t,".env.local")),u=n.env?.required?Object.entries(n.env.required).map(([g,y])=>({name:g,description:y?.description,configured:p.has(g)})):[];n.projectId&&import("./state-manager-ZVLGPYXN.js").then(({fetchRemoteState:g})=>g(n.projectId)).catch(()=>{});let h=[`Project: ${n.name}`];if(l){h.push(`Plan: ${l.summary??l.name??"unnamed"} \u2014 ${s}/${d} steps complete`);for(let g of l.steps){let y=g.status==="completed"?"\u2713":g.status==="in_progress"?"\u2192":" ";h.push(` [${y}] ${g.number}. ${g.name}`)}}let m=u.filter(g=>!g.configured);m.length>0&&h.push(`Missing env vars: ${m.map(g=>g.name).join(", ")}`),n.deploy?.url?h.push(`Deployed: ${n.deploy.url} (${n.deploy.count??0} deploys)`):h.push("Not deployed yet");let b=[],f=l?.steps?.find(g=>g.status!=="completed");return f?b.push(`NEXT: Call mist_build with action='implement' to work on step ${f.number} (${f.name}).`):l&&s===d&&(n.deploy?.url||b.push("NEXT: All steps complete! Call mist_deploy with action='deploy' to deploy the app now.")),m.length>0&&b.push(`Missing env vars in .env.local: ${m.map(g=>g.name).join(", ")}`),c(JSON.stringify({name:n.name,projectId:n.projectId,planProgress:l?{name:l.name,summary:l.summary,totalSteps:d,completedSteps:s,steps:l.steps}:null,envStatus:u,deploy:n.deploy??null,contextMessage:h.join(`
12479
- `),nextSteps:b}))}let o=[];if(e.completedStep!==void 0){let l=n.plan;if(l?.steps){let s=l.steps.findIndex(d=>d.number===e.completedStep);if(s===-1)return c(`Step ${e.completedStep} not found in the plan.`,!0);l.steps[s].status="completed",o.push(`Step ${e.completedStep} marked as completed`)}}e.addEnvVar&&(n.env||(n.env={required:{}}),n.env.required||(n.env.required={}),n.env.required[e.addEnvVar.key]={description:e.addEnvVar.description,setupUrl:e.addEnvVar.setupUrl},o.push(`Added required env var: ${e.addEnvVar.key}`)),ls(a,JSON.stringify(n,null,2)+`
12480
- `),n.projectId&&import("./state-manager-ZVLGPYXN.js").then(async({readLocalState:l,syncRemoteState:s})=>{let d=l(t);d&&await s(n.projectId,d)}).catch(()=>{});let i=[];if(e.completedStep!==void 0){let s=n.plan?.steps?.find(d=>d.status!=="completed");s?i.push(`NEXT: Call mist_build with action='implement' to work on step ${s.number} (${s.name}). Do this now.`):i.push("NEXT: All steps complete! Call mist_deploy with action='deploy' to deploy the app now. Do NOT suggest localhost.")}return e.addEnvVar&&(i.push(`Add ${e.addEnvVar.key} to your .env.local file`),e.addEnvVar.setupUrl&&i.push(`Get the value from: ${e.addEnvVar.setupUrl}`)),c(JSON.stringify({updated:!0,changes:o,message:o.length>0?`Project state saved. ${o.join(". ")}.`:"No changes made.",nextSteps:i.length>0?i:void 0}))}};var cs=re.object({action:re.enum(["get","update","share","landing-designs","app-styles","integrations","errors","logs","deployments","version"]).default("get").describe("'get' reads current project state. 'update' marks steps complete or adds env vars. 'share' makes the project a shareable template. 'landing-designs' lists curated landing page hero designs. 'app-styles' lists 54 full-app styles (Stripe, Linear, Vercel, etc.) for consistent brand-quality UI across all pages. 'integrations' lists third-party service integration blueprints (Stripe, Resend, ElevenLabs, etc.) with setup guides. 'errors' fetches runtime errors from the deployed app. 'logs' fetches deploy logs for a specific deployment. 'deployments' lists deployment history. 'version' reports the installed @mistflow-ai/mcp version and whether an upgrade is available."),projectPath:re.string().optional().describe("Path to the project directory (default: cwd)"),completedStep:re.number().optional().describe("(update) Mark a plan step as completed by step number"),addEnvVar:re.object({key:re.string(),description:re.string().optional(),setupUrl:re.string().optional()}).optional().describe("(update) Add a required env var to the project manifest"),templateDescription:re.string().optional().describe("(share) Short description of what this template builds"),category:re.string().optional().describe("(landing-designs / app-styles) Filter by category"),presetId:re.string().optional().describe("(landing-designs) Get full details for a specific landing design by ID"),appStyleId:re.string().optional().describe("(app-styles) Get full details for a specific app style by ID (e.g. 'stripe', 'linear')"),integrationId:re.string().optional().describe("(integrations) Get full details for a specific integration preset by ID (e.g. 'stripe-payments', 'resend-email', 'elevenlabs-voice')"),period:re.string().optional().describe("(errors) Time period for errors: '1h', '24h', '7d' (default: '7d')"),deploymentId:re.string().optional().describe("(logs) Deployment ID to fetch logs for. If omitted, fetches logs for the latest deployment.")}),yi={name:"mist_project",description:"Read or update Mistflow project state. 'get' loads plan progress, env vars, and deploy info. 'update' marks plan steps complete or adds env vars (note: mist_build implement auto-marks the previous step, so manual updates are rarely needed). 'share' makes the project a forkable template with a shareable URL. 'landing-designs' lists curated landing page hero designs \u2014 pass an ID to mist_plan's landingDesign field to apply it. 'app-styles' lists 54 full-app styles from top companies (Stripe, Linear, Vercel, Notion, etc.) \u2014 pass an ID to mist_plan's appStyle field for consistent brand-quality design across ALL pages. 'integrations' lists third-party service integration blueprints (Stripe, Resend, ElevenLabs, OpenAI, Twilio, etc.) \u2014 these are auto-injected during implementation when the plan includes matching integration steps. 'errors' fetches runtime errors from the live deployed app (same data shown on the dashboard). 'logs' fetches deploy logs for a deployment (phase-by-phase progress with error details). 'deployments' lists deployment history with status and error messages.",inputSchema:cs,handler:async r=>{let e=r;if(["share","errors","logs","deployments"].includes(e.action)&&!le())return c("You need to sign in first. Run mist_setup to connect your account.",!0);switch(e.action){case"get":case"update":return xi.handler({action:e.action,projectPath:e.projectPath,completedStep:e.completedStep,addEnvVar:e.addEnvVar});case"share":{let a=Ft(e.projectPath??process.cwd()),n=Et(a,"mistflow.json");if(!Nt(n))return ge(a);let o;try{o=JSON.parse(Ut(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first to register it.",!0);try{let l=await Qa(i,{isTemplate:!0,description:e.templateDescription});return c(JSON.stringify({shareUrl:l.share_url,shareToken:l.share_token,message:`Your project is now a shareable template!
10909
+ ${h.slice(-1e3)}`:"Server failed to start within 15s. Check for runtime errors.";return c(f,!0)}}let d=`http://localhost:${a}`,u=JSON.stringify({localUrl:d,message:`Preview is live at ${d}. Run mist_deploy to get your permanent URL on mistflow.app.`});return Be(d,u)}};import{resolve as ss,join as ls}from"path";import{existsSync as ds,readFileSync as cs}from"fs";var va="test@mistflow.dev",yi="MistflowTest123!",ps="Test User";function wi(r){let e=ls(r,"mistflow.json");if(!ds(e))return null;try{return JSON.parse(cs(e,"utf-8"))}catch{return null}}function us(r){let e=JSON.stringify(r).toLowerCase();return["auth","login","sign-in","sign-up","signin","signup"].some(t=>e.includes(t))}function hs(r){let e=r.plan;if(!e?.steps)return[];let t=new Set;for(let n of e.steps)if(n.pages)for(let o of n.pages)t.add(o);let a=new Set(["login","signup","sign-in","sign-up","signin","signout","sign-out","logout"]);return[...t].filter(n=>!a.has(n.toLowerCase())).slice(0,3)}function gs(r){let e=r.deploy;return e?.url?e.url:typeof r.deployUrl=="string"?r.deployUrl:null}async function vi(r){let e=ss(r.projectPath??process.cwd()),t=r.verifyUrl,a=null;if(t)a=wi(e);else{if(a=wi(e),!a)return c("No mistflow.json found. Run mist_deploy first, or pass verifyUrl explicitly.",!0);if(t=gs(a)??void 0,!t)return c("No deploy URL found in mistflow.json. Deploy your app first with mist_deploy.",!0)}t.startsWith("http")||(t=`https://${t}`);let n=a?us(a):!1,o=a?hs(a):[],i;try{i=await ut()}catch{return c("Browser not available. Install Playwright to use verify: npx playwright install chromium",!0)}let s={verified:!0,url:t,authTested:!1,testUser:null,pages:[],message:""},l=[];try{await i.goto(t,{waitUntil:"domcontentloaded",timeout:3e4}),await i.waitForLoadState("networkidle").catch(()=>{})}catch{return s.verified=!1,s.message=`Could not load ${t}. The app may not be deployed yet or the URL may be incorrect.`,c(JSON.stringify(s),!0)}let d=await i.title(),u=d.toLowerCase().includes("error")||d.toLowerCase().includes("404")?"error":"ok";s.pages.push({path:"/",status:u,title:d});try{let b=await Te(i,!1);l.push({data:b.toString("base64"),mimeType:"image/png"})}catch{}if(u==="error"&&(s.verified=!1),n)try{(await i.evaluate(async g=>{let w=await fetch("/api/auth/sign-up/email",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});return{status:w.status,ok:w.ok}},{email:va,password:yi,name:ps})).ok||await i.evaluate(async g=>{let w=await fetch("/api/auth/sign-in/email",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(g)});return{status:w.status,ok:w.ok}},{email:va,password:yi}),await i.reload({waitUntil:"domcontentloaded",timeout:15e3}),await i.waitForLoadState("networkidle").catch(()=>{}),s.authTested=!0,s.testUser={email:va};try{let g=await Te(i,!1);l.push({data:g.toString("base64"),mimeType:"image/png"})}catch{}}catch{console.error("[verify] Auth test failed, continuing with public pages")}for(let b of o){let g=b.startsWith("/")?b:`/${b}`;try{await i.goto(`${t}${g}`,{waitUntil:"domcontentloaded",timeout:15e3}),await i.waitForLoadState("networkidle").catch(()=>{});let w=await i.title(),P=w.toLowerCase().includes("404")||w.toLowerCase().includes("not found")?"error":"ok";s.pages.push({path:g,status:P,title:w}),P==="error"&&(s.verified=!1);try{let D=await Te(i,!1);l.push({data:D.toString("base64"),mimeType:"image/png"})}catch{}}catch{s.pages.push({path:g,status:"error",title:"Timeout"}),s.verified=!1}}let p=s.pages.filter(b=>b.status==="ok").length,h=s.pages.length,m=s.authTested?" Auth login successful.":"";s.message=s.verified?`Verified ${p}/${h} pages.${m} App looks good.`:`Verified ${p}/${h} pages \u2014 some issues found.${m} Check screenshots.`;let f=[{type:"text",text:JSON.stringify(s)}];for(let b of l)f.push({type:"image",data:b.data,mimeType:b.mimeType});return{content:f}}var ms=_e.object({action:_e.enum(["deploy","promote","preview","redeploy","rollback","verify"]).describe("'deploy' builds and deploys to Cloudflare (auto-redirects to preview if staging mode is enabled). 'promote' promotes a verified preview to production (~10s, reuses the preview build). 'preview' builds the app and starts a local production server on localhost:3000. 'redeploy' re-deploys the latest build without rebuilding. 'rollback' reverts to a specific previous deployment. 'verify' navigates the deployed app, tests auth, and screenshots pages to confirm it works."),projectPath:_e.string().optional().describe("Path to the project directory (default: cwd)"),environment:_e.enum(["production","preview"]).optional().describe("(deploy) Target environment. Defaults to 'production'. Projects with staging mode auto-redirect to preview."),forceSchema:_e.boolean().optional().describe("(deploy) Reset the database structure. Warning: this deletes existing data. Only use when the user confirms this is OK."),deploymentId:_e.string().optional().describe("(rollback/promote) Deployment ID to rollback to, or preview deployment ID to promote"),verifyUrl:_e.string().optional().describe("(verify) URL to verify. Defaults to deploy URL from mistflow.json")}),ki={name:"mist_deploy",description:"STEP 4 (final) of the Mistflow workflow. Deploy a Mistflow project. Call this AFTER all mist_build implement steps are done. If the project has staging mode enabled (configurable in dashboard), the tool automatically deploys to preview first with an isolated database. After QA passes, call action='promote' to go live (~10s, reuses the same build artifact). Actions: 'deploy' (default), 'promote' (promote preview to production), 'preview' (local dev server), 'redeploy', 'rollback', 'verify'. The workflow is: mist_plan \u2192 mist_build init \u2192 implement (repeat) \u2192 mist_build build \u2192 mist_deploy \u2192 mist_build qa.",inputSchema:ms,handler:async r=>{let e=r;switch(e.action){case"deploy":return oi({projectPath:e.projectPath,environment:e.environment??"production",forceSchema:e.forceSchema});case"promote":return di({projectPath:e.projectPath,deploymentId:e.deploymentId});case"preview":return xi.handler({projectPath:e.projectPath});case"redeploy":return wa({projectPath:e.projectPath,action:"redeploy"});case"rollback":return wa({projectPath:e.projectPath,action:"rollback",deploymentId:e.deploymentId});case"verify":return vi({projectPath:e.projectPath,verifyUrl:e.verifyUrl});default:return c(`Unknown action: ${e.action}. Use deploy, promote, preview, redeploy, rollback, or verify.`,!0)}}};import{z as ie}from"zod";import{resolve as Ut}from"path";import{existsSync as Ht,readFileSync as Gt}from"fs";import{join as Wt}from"path";import{z as Re}from"zod";import{resolve as fs,join as Si}from"path";import{existsSync as bs,readFileSync as xs,writeFileSync as ys}from"fs";var ws=Re.object({action:Re.enum(["get","update"]).default("get").describe("'get' reads current project state. 'update' modifies it."),projectPath:Re.string().optional().describe("Path to the project directory (default: current working directory)"),completedStep:Re.number().optional().describe("(update only) Mark a plan step as completed by step number"),addEnvVar:Re.object({key:Re.string(),description:Re.string().optional(),setupUrl:Re.string().optional()}).optional().describe("(update only) Add a required env var to the project manifest")}),Ci={name:"mist_state",description:"Read or update project state in mistflow.json. Use action='get' to load plan progress, env var status, and deploy info. Use action='update' to mark plan steps complete or add required env vars. Use when the user says 'mist status', 'mist state', or 'mist update state'.",inputSchema:ws,handler:async r=>{let e=r,t=fs(e.projectPath??process.cwd()),a=Si(t,"mistflow.json");if(!bs(a))return ge(t);let n;try{n=JSON.parse(xs(a,"utf-8"))}catch{return c("Failed to parse mistflow.json.",!0)}if(e.action==="get"){let s=n.plan,l=s?.steps?.filter(g=>g.status==="completed").length??0,d=s?.steps?.length??0,u=Ft(Si(t,".env.local")),p=n.env?.required?Object.entries(n.env.required).map(([g,w])=>({name:g,description:w?.description,configured:u.has(g)})):[];n.projectId&&import("./state-manager-73ZUDKOP.js").then(({fetchRemoteState:g})=>g(n.projectId)).catch(()=>{});let h=[`Project: ${n.name}`];if(s){h.push(`Plan: ${s.summary??s.name??"unnamed"} \u2014 ${l}/${d} steps complete`);for(let g of s.steps){let w=g.status==="completed"?"\u2713":g.status==="in_progress"?"\u2192":" ";h.push(` [${w}] ${g.number}. ${g.name}`)}}let m=p.filter(g=>!g.configured);m.length>0&&h.push(`Missing env vars: ${m.map(g=>g.name).join(", ")}`),n.deploy?.url?h.push(`Deployed: ${n.deploy.url} (${n.deploy.count??0} deploys)`):h.push("Not deployed yet");let f=[],b=s?.steps?.find(g=>g.status!=="completed");return b?f.push(`NEXT: Call mist_build with action='implement' to work on step ${b.number} (${b.name}).`):s&&l===d&&(n.deploy?.url||f.push("NEXT: All steps complete! Call mist_deploy with action='deploy' to deploy the app now.")),m.length>0&&f.push(`Missing env vars in .env.local: ${m.map(g=>g.name).join(", ")}`),c(JSON.stringify({name:n.name,projectId:n.projectId,planProgress:s?{name:s.name,summary:s.summary,totalSteps:d,completedSteps:l,steps:s.steps}:null,envStatus:p,deploy:n.deploy??null,contextMessage:h.join(`
10910
+ `),nextSteps:f}))}let o=[];if(e.completedStep!==void 0){let s=n.plan;if(s?.steps){let l=s.steps.findIndex(d=>d.number===e.completedStep);if(l===-1)return c(`Step ${e.completedStep} not found in the plan.`,!0);s.steps[l].status="completed",o.push(`Step ${e.completedStep} marked as completed`)}}e.addEnvVar&&(n.env||(n.env={required:{}}),n.env.required||(n.env.required={}),n.env.required[e.addEnvVar.key]={description:e.addEnvVar.description,setupUrl:e.addEnvVar.setupUrl},o.push(`Added required env var: ${e.addEnvVar.key}`)),ys(a,JSON.stringify(n,null,2)+`
10911
+ `),n.projectId&&import("./state-manager-73ZUDKOP.js").then(async({readLocalState:s,syncRemoteState:l})=>{let d=s(t);d&&await l(n.projectId,d)}).catch(()=>{});let i=[];if(e.completedStep!==void 0){let l=n.plan?.steps?.find(d=>d.status!=="completed");l?i.push(`NEXT: Call mist_build with action='implement' to work on step ${l.number} (${l.name}). Do this now.`):i.push("NEXT: All steps complete! Call mist_deploy with action='deploy' to deploy the app now. Do NOT suggest localhost.")}return e.addEnvVar&&(i.push(`Add ${e.addEnvVar.key} to your .env.local file`),e.addEnvVar.setupUrl&&i.push(`Get the value from: ${e.addEnvVar.setupUrl}`)),c(JSON.stringify({updated:!0,changes:o,message:o.length>0?`Project state saved. ${o.join(". ")}.`:"No changes made.",nextSteps:i.length>0?i:void 0}))}};var vs=ie.object({action:ie.enum(["get","update","share","landing-designs","app-styles","integrations","errors","logs","deployments","version"]).default("get").describe("'get' reads current project state. 'update' marks steps complete or adds env vars. 'share' makes the project a shareable template. 'landing-designs' lists curated landing page hero designs. 'app-styles' lists 54 full-app styles (Stripe, Linear, Vercel, etc.) for consistent brand-quality UI across all pages. 'integrations' lists third-party service integration blueprints (Stripe, Resend, ElevenLabs, etc.) with setup guides. 'errors' fetches runtime errors from the deployed app. 'logs' fetches deploy logs for a specific deployment. 'deployments' lists deployment history. 'version' reports the installed @mistflow-ai/mcp version and whether an upgrade is available."),projectPath:ie.string().optional().describe("Path to the project directory (default: cwd)"),completedStep:ie.number().optional().describe("(update) Mark a plan step as completed by step number"),addEnvVar:ie.object({key:ie.string(),description:ie.string().optional(),setupUrl:ie.string().optional()}).optional().describe("(update) Add a required env var to the project manifest"),templateDescription:ie.string().optional().describe("(share) Short description of what this template builds"),category:ie.string().optional().describe("(landing-designs / app-styles) Filter by category"),presetId:ie.string().optional().describe("(landing-designs) Get full details for a specific landing design by ID"),appStyleId:ie.string().optional().describe("(app-styles) Get full details for a specific app style by ID (e.g. 'stripe', 'linear')"),integrationId:ie.string().optional().describe("(integrations) Get full details for a specific integration preset by ID (e.g. 'stripe-payments', 'resend-email', 'elevenlabs-voice')"),period:ie.string().optional().describe("(errors) Time period for errors: '1h', '24h', '7d' (default: '7d')"),deploymentId:ie.string().optional().describe("(logs) Deployment ID to fetch logs for. If omitted, fetches logs for the latest deployment.")}),Ti={name:"mist_project",description:"Read or update Mistflow project state. 'get' loads plan progress, env vars, and deploy info. 'update' marks plan steps complete or adds env vars (note: mist_build implement auto-marks the previous step, so manual updates are rarely needed). 'share' makes the project a forkable template with a shareable URL. 'landing-designs' lists curated landing page hero designs \u2014 pass an ID to mist_plan's landingDesign field to apply it. 'app-styles' lists 54 full-app styles from top companies (Stripe, Linear, Vercel, Notion, etc.) \u2014 pass an ID to mist_plan's appStyle field for consistent brand-quality design across ALL pages. 'integrations' lists third-party service integration blueprints (Stripe, Resend, ElevenLabs, OpenAI, Twilio, etc.) \u2014 these are auto-injected during implementation when the plan includes matching integration steps. 'errors' fetches runtime errors from the live deployed app (same data shown on the dashboard). 'logs' fetches deploy logs for a deployment (phase-by-phase progress with error details). 'deployments' lists deployment history with status and error messages.",inputSchema:vs,handler:async r=>{let e=r;if(["share","errors","logs","deployments"].includes(e.action)&&!se())return c("You need to sign in first. Run mist_setup to connect your account.",!0);switch(e.action){case"get":case"update":return Ci.handler({action:e.action,projectPath:e.projectPath,completedStep:e.completedStep,addEnvVar:e.addEnvVar});case"share":{let a=Ut(e.projectPath??process.cwd()),n=Wt(a,"mistflow.json");if(!Ht(n))return ge(a);let o;try{o=JSON.parse(Gt(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first to register it.",!0);try{let s=await Za(i,{isTemplate:!0,description:e.templateDescription});return c(JSON.stringify({shareUrl:s.share_url,shareToken:s.share_token,message:`Your project is now a shareable template!
12481
10912
 
12482
- Anyone can fork it: ${l.share_url}
10913
+ Anyone can fork it: ${s.share_url}
12483
10914
 
12484
10915
  Others can use it in their AI editor:
12485
- "build me something like ${l.share_url}"`}))}catch(l){let s=l instanceof Error?l.message:"Failed to share project";return c(s,!0)}}case"landing-designs":{if(e.presetId){let i=Ae(e.presetId);if(!i)return c(`Preset '${e.presetId}' not found. Use mist_project action='presets' without presetId to list all available presets.`,!0);let l=ar(e.presetId);return c(JSON.stringify({preset:{id:i.id,title:i.title,category:i.category,description:l?.description??"",style:l?.style??"",theme:l?.theme??"dark",colors:l?.colors??[],tags:l?.tags??[],promptLength:i.prompt.length},message:`Landing design "${i.title}" (${i.category}) \u2014 ${l?.description??""}. To use it, pass landingDesign="${i.id}" when calling mist_plan.`}))}let a=Vt(e.category??void 0),n=zt(e.category),o=rr(n);return c(JSON.stringify({count:a.length,presets:a.map(i=>({id:i.id,title:i.title,category:i.category,description:i.description,style:i.style,theme:i.theme,colors:i.colors})),formatted:o,message:`${a.length} landing designs available.${e.category?` Filtered by: ${e.category}.`:""} To use one, pass landingDesign="<id>" when calling mist_plan. The design blueprint will be injected during the landing page implementation step. Browse them at ${ve()}/designs?tab=landing-designs.`}))}case"app-styles":{if(e.appStyleId){let i=ke(e.appStyleId);if(!i)return c(`App style '${e.appStyleId}' not found. Use mist_project action='app-styles' without appStyleId to list all available app styles.`,!0);let l=bt(i.id);return c(JSON.stringify({appStyle:{id:i.id,name:i.name,category:l?.category??i.category,description:l?.description??"",theme:l?.theme??"light",colors:l?.colors??[],fonts:l?.fonts??{heading:"Inter",body:"Inter"},tags:l?.tags??[],sectionCount:i.sections.length,sections:i.sections.map(s=>s.title)},message:`App style "${i.name}" (${i.category}) \u2014 ${l?.description??""}. To use it, pass appStyle="${i.id}" when calling mist_plan. The style's component specs, typography, color palette, and layout rules will be injected during ALL implementation steps for consistent brand-quality design.`}))}let a=Jt(e.category??void 0),n=Kt(e.category??void 0),o=nr(n);return c(JSON.stringify({count:a.length,appStyles:a.map(i=>({id:i.id,name:i.name,category:i.category,description:i.description,theme:i.theme,colors:i.colors,fonts:i.fonts})),formatted:o,message:`${a.length} app styles available.${e.category?` Filtered by: ${e.category}.`:""} To use one, pass appStyle="<id>" when calling mist_plan. The style will be applied across ALL pages for consistent design. Browse them at ${ve()}/designs?tab=app-styles.`}))}case"integrations":{if(e.integrationId){let i=Ve(e.integrationId);if(!i)return c(`Integration '${e.integrationId}' not found. Use mist_project action='integrations' without integrationId to list all available integrations.`,!0);let l=qe(i.id);return c(JSON.stringify({integration:{id:i.id,name:i.name,category:i.category,description:l?.description??"",packages:l?.packages??[],envVars:l?.envVars??[],docsUrl:l?.docsUrl??"",difficulty:l?.difficulty??"medium"},message:`Integration "${i.name}" (${i.category}) \u2014 ${l?.description??""}. This blueprint is auto-injected during implementation when your plan has a matching integration step. Required env vars: ${l?.envVars?.map(s=>s.key).join(", ")||"none"}. Docs: ${l?.docsUrl??"n/a"}.`}))}let a=cr(e.category??void 0),n=Qt(e.category??void 0),o=dr(n);return c(JSON.stringify({count:a.length,integrations:a.map(i=>({id:i.id,name:i.name,category:i.category,description:i.description,packages:i.packages,difficulty:i.difficulty,envVars:i.envVars.map(l=>l.key)})),formatted:o,message:`${a.length} integration blueprints available.${e.category?` Filtered by: ${e.category}.`:""} Integration blueprints are auto-injected during implementation when your plan includes a matching integration step. Use integrationId to see full details including env vars and setup URLs.`}))}case"errors":{let a=Ft(e.projectPath??process.cwd()),n=Et(a,"mistflow.json");if(!Nt(n))return ge(a);let o;try{o=JSON.parse(Ut(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first.",!0);try{let l=await _a(i,e.period??"7d");return l.total===0?c(JSON.stringify({total:0,period:l.period,message:`No runtime errors in the last ${l.period}. The app is running clean.`})):c(JSON.stringify({total:l.total,period:l.period,errors:l.errors,message:`${l.total} runtime error(s) in the last ${l.period}. Review the errors above and use mist_build debug to investigate.`}))}catch(l){let s=l instanceof Error?l.message:"Failed to fetch errors";return c(s,!0)}}case"logs":{let a=Ft(e.projectPath??process.cwd()),n=Et(a,"mistflow.json");if(!Nt(n))return ge(a);let o;try{o=JSON.parse(Ut(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first.",!0);let l=e.deploymentId;if(!l)try{let s=await et(i);if(s.length===0)return c("No deployments found for this project.",!0);l=s[0].id}catch(s){let d=s instanceof Error?s.message:"Failed to fetch deployments";return c(d,!0)}try{let[s,d]=await Promise.all([Wa(l),Be(l)]),p=s.filter(h=>h.level==="error"),u=s.filter(h=>h.level==="warn");return c(JSON.stringify({deploymentId:l,status:d.status,errorMessage:d.error??null,totalLogs:s.length,errorCount:p.length,warnCount:u.length,logs:s.map(h=>({time:h.timestamp,level:h.level,phase:h.phase,message:h.message})),message:d.status==="failed"?`Deployment failed. ${p.length} error(s) found in logs. Review the logs above to diagnose the issue.`:`Deployment status: ${d.status}. ${s.length} log entries (${p.length} errors, ${u.length} warnings).`}))}catch(s){let d=s instanceof Error?s.message:"Failed to fetch deploy logs";return c(d,!0)}}case"deployments":{let a=Ft(e.projectPath??process.cwd()),n=Et(a,"mistflow.json");if(!Nt(n))return ge(a);let o;try{o=JSON.parse(Ut(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first.",!0);try{let l=await et(i);return c(JSON.stringify({total:l.length,deployments:l.map(s=>({id:s.id,status:s.status,errorMessage:s.error_message,durationSeconds:s.duration_seconds,isRollback:!!s.rollback_from_id,createdAt:s.created_at})),message:`${l.length} deployment(s) found. Use mist_project action='logs' deploymentId='<id>' to see detailed logs for any deployment.`}))}catch(l){let s=l instanceof Error?l.message:"Failed to fetch deployments";return c(s,!0)}}case"version":{let a=ct(),n=a.severity==="none",o={none:"up to date",patch:"patch update available",minor:"minor update available",major:"major update available",unsupported:"UNSUPPORTED \u2014 upgrade required"};return c(JSON.stringify({current:a.current,latest:a.latest||"unknown",minSupported:a.minSupported||"unknown",severity:a.severity,upToDate:n,upgradeCmd:a.upgradeCmd,changelogUrl:a.changelogUrl,backendSignalReceived:a.backendSignalReceived,message:a.backendSignalReceived?`Mistflow MCP ${a.current} (${o[a.severity]??a.severity}). Latest: ${a.latest}.${n?"":` Run \`${a.upgradeCmd}\` and restart your editor to upgrade.`}`:`Mistflow MCP ${a.current}. The backend hasn't replied yet \u2014 make one other API call (e.g. mist_project action='get') then retry to see the latest version.`}))}default:return c(`Unknown action: ${e.action}. Use get, update, share, landing-designs, app-styles, integrations, errors, logs, deployments, or version.`,!0)}}};import{z as fe}from"zod";import{z as Fe}from"zod";import{resolve as ps}from"path";var Hc=Fe.object({projectPath:Fe.string().optional().describe("Path to the project directory (default: cwd)"),action:Fe.enum(["set","list","delete"]).describe("Action to perform"),key:Fe.string().optional().describe("Environment variable name (required for 'set' and 'delete')"),value:Fe.string().optional().describe("Environment variable value (required for 'set')"),category:Fe.string().optional().describe("Category for the env var (default: 'custom')"),description:Fe.string().optional().describe("Description of what this env var is for"),setupUrl:Fe.string().optional().describe("URL where the user can obtain this value (e.g. Stripe dashboard)")});async function wi(r){let{projectPath:e,action:t,key:a,value:n,category:o,description:i,setupUrl:l}=r,s=ps(e??process.cwd());if(!le())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let p=we(s)?.projectId;if(!p)return c("No project ID found. Deploy your project first with mist_deploy, or initialize with mist_plan + mist_build.",!0);try{switch(t){case"set":return a?n?(await Ha(p,a,n,{category:o,description:i,setupUrl:l}),c(JSON.stringify({set:!0,key:a,message:`Environment variable '${a}' has been set. It will be available on your next deployment.`}))):c("Value is required. Provide the env var value.",!0):c("Key is required. Provide the env var name like 'STRIPE_SECRET_KEY'.",!0);case"list":{let u=await Ea(p);return u.length===0?c(JSON.stringify({envVars:[],message:"No environment variables configured. Use action 'set' to add one."})):c(JSON.stringify({envVars:u.map(h=>({key:h.key,category:h.category,description:h.description,hasValue:h.has_value})),message:`${u.length} environment variable(s) configured.`}))}case"delete":return a?(await Ga(p,a),c(JSON.stringify({deleted:!0,key:a,message:`Environment variable '${a}' has been removed.`}))):c("Key is required. Provide the env var name to delete.",!0);default:return c(`Unknown action: ${t}. Use set, list, or delete.`,!0)}}catch(u){if(u instanceof ce)return c(u.message,!0);let h=u instanceof Error?u.message:"An unexpected error occurred";return c(h,!0)}}import{z as st}from"zod";import{resolve as us,join as hs}from"path";import{existsSync as gs,readFileSync as ms,writeFileSync as fs}from"fs";var Vc=st.object({projectPath:st.string().optional().describe("Path to the project directory (default: cwd)"),action:st.enum(["add","list","verify","remove"]).describe("Action to perform"),domain:st.string().optional().describe("Domain name (required for 'add' and 'remove')"),domainId:st.string().optional().describe("Domain ID (required for 'verify' and 'remove')")});function ka(r,e){let t=hs(r,"mistflow.json");if(!gs(t))return;let a;try{a=JSON.parse(ms(t,"utf-8"))}catch{return}a.domains=e,fs(t,JSON.stringify(a,null,2)+`
12486
- `)}async function vi(r){let{projectPath:e,action:t,domain:a,domainId:n}=r,o=us(e??process.cwd());if(!le())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let l=we(o)?.projectId;if(!l)return c("No project ID found. Deploy your project first with mist_deploy, or initialize with mist_plan + mist_build.",!0);try{switch(t){case"add":{if(!a)return c("Domain name is required. Provide the domain like 'myapp.com' or 'app.mycompany.com'.",!0);let s=await Fa(l,a),d=await Ee(l);return ka(o,d.map(p=>({domain:p.domain,status:p.status}))),c(JSON.stringify({added:!0,domain:s.domain,status:s.status,instructions:s.instructions,message:`Domain '${s.domain}' added. Set up DNS records as described, then use action 'verify' to check status.`}))}case"list":{let s=await Ee(l);return s.length===0?c(JSON.stringify({domains:[],message:"No custom domains configured. Use action 'add' to add one."})):c(JSON.stringify({domains:s.map(d=>({id:d.id,domain:d.domain,status:d.status,ssl:d.ssl_status,error:d.error_message}))}))}case"verify":{if(!n){if(a){let u=(await Ee(l)).find(h=>h.domain===a);if(u){let h=await _t(l,u.id);return c(JSON.stringify({domain:h.domain,status:h.status,ssl:h.ssl_status,error:h.error_message,message:h.status==="active"?`Domain '${h.domain}' is active and serving traffic.`:`Domain '${h.domain}' is ${h.status}. Make sure DNS records are configured correctly.`}))}return c(`Domain '${a}' not found. Use action 'list' to see configured domains.`,!0)}return c("Provide either domainId or domain name to verify.",!0)}let s=await _t(l,n),d=await Ee(l);return ka(o,d.map(p=>({domain:p.domain,status:p.status}))),c(JSON.stringify({domain:s.domain,status:s.status,ssl:s.ssl_status,error:s.error_message,message:s.status==="active"?`Domain '${s.domain}' is active and serving traffic.`:`Domain '${s.domain}' is ${s.status}. Make sure DNS records are configured correctly.`}))}case"remove":{if(!n&&!a)return c("Provide either domainId or domain name to remove.",!0);let s=n;if(!s&&a){let u=(await Ee(l)).find(h=>h.domain===a);if(!u)return c(`Domain '${a}' not found.`,!0);s=u.id}await Na(l,s);let d=await Ee(l);return ka(o,d.map(p=>({domain:p.domain,status:p.status}))),c(JSON.stringify({removed:!0,message:"Domain removed. It may take a few minutes for DNS changes to propagate."}))}default:return c(`Unknown action: ${t}. Use add, list, verify, or remove.`,!0)}}catch(s){if(s instanceof ce)return c(s.message,!0);let d=s instanceof Error?s.message:"An unexpected error occurred";return c(d,!0)}}var bs=fe.object({resource:fe.enum(["env","domain"]).describe("'env' manages app secrets and configuration values. 'domain' manages custom domains."),action:fe.string().describe("Action to perform. env: 'set', 'list', 'delete'. domain: 'add', 'list', 'verify', 'remove'."),projectPath:fe.string().optional().describe("Path to the project directory (default: cwd)"),key:fe.string().optional().describe("(env) Variable name"),value:fe.string().optional().describe("(env set) Variable value"),category:fe.string().optional().describe("(env set) Category"),description:fe.string().optional().describe("(env set) Description"),setupUrl:fe.string().optional().describe("(env set) URL to obtain the value"),domain:fe.string().optional().describe("(domain) Domain name"),domainId:fe.string().optional().describe("(domain) Domain ID")}),ki={name:"mist_config",description:"Manage project configuration: app secrets and custom domains. Set resource='env' to manage encrypted app secrets (set, list, delete). Set resource='domain' to manage custom domains (add, list, verify, remove). Use when the user says 'mist env' or 'mist domain'.",inputSchema:bs,handler:async r=>{let e=r;switch(e.resource){case"env":return wi({projectPath:e.projectPath,action:e.action,key:e.key,value:e.value,category:e.category,description:e.description,setupUrl:e.setupUrl});case"domain":return vi({projectPath:e.projectPath,action:e.action,domain:e.domain,domainId:e.domainId});default:return c(`Unknown resource: ${e.resource}. Use env or domain.`,!0)}}};import{z as je}from"zod";var xs=je.object({action:je.enum(["navigate","go_back","go_forward","click","type","fill","select_option","press_key","hover","screenshot","snapshot"]).describe("Action to perform. Navigation: navigate|go_back|go_forward. Interaction: click|type|fill|select_option|press_key|hover. Visual: screenshot (returns image) | snapshot (returns accessibility tree)."),url:je.string().optional().describe("URL to navigate to. Required for 'navigate'; optional for 'screenshot' (navigates before capturing)."),selector:je.string().optional().describe("CSS selector of the target element. Required for: click, type, fill, select_option, hover. Optional for screenshot (captures just that element)."),value:je.string().optional().describe("Text to type/fill, option to select, or key to press (e.g. 'Enter', 'Tab'). Required for: type, fill, select_option, press_key."),fullPage:je.boolean().default(!1).describe("For 'screenshot': capture the full scrollable page instead of just the viewport."),includeScreenshot:je.boolean().default(!1).describe("For navigate/interact actions: also return a screenshot alongside the accessibility snapshot.")}),Si={name:"mist_browser",description:"Unified browser tool for navigating, interacting with, and capturing the app. Use 'navigate' to open a URL, interaction actions (click/type/fill/etc.) to test flows, 'snapshot' to inspect the accessibility tree, and 'screenshot' for a visual capture. Use after mist_preview to verify UI, test flows, and iterate on design.",inputSchema:xs,handler:async r=>{let e=r,t=await pt();if(e.action==="navigate"){if(!e.url)return c("URL is required for 'navigate'.",!0);let o=[],i=d=>{d.type()==="error"&&o.push(d.text())};t.on("console",i),await t.goto(e.url,{waitUntil:"domcontentloaded",timeout:3e4}),await t.waitForLoadState("networkidle").catch(()=>{});let l=[],s=d=>l.push(d.message);if(t.on("pageerror",s),await t.waitForTimeout(500),t.removeListener("console",i),t.removeListener("pageerror",s),o.length>0||l.length>0){let d=await ut(t),p=[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),snapshot:d,consoleErrors:o,pageErrors:l,hasErrors:!0})}];if(e.includeScreenshot){let u=await Pe(t);p.push({type:"image",data:u.toString("base64"),mimeType:"image/png"})}return{content:p}}}else if(e.action==="go_back")await t.goBack({waitUntil:"domcontentloaded",timeout:1e4});else if(e.action==="go_forward")await t.goForward({waitUntil:"domcontentloaded",timeout:1e4});else if(e.action==="click"){if(!e.selector)return c("Selector is required for 'click'.",!0);await t.click(e.selector,{timeout:1e4}),await t.waitForLoadState("domcontentloaded").catch(()=>{}),await t.waitForTimeout(500)}else if(e.action==="type"){if(!e.selector)return c("Selector is required for 'type'.",!0);if(!e.value)return c("Value is required for 'type'.",!0);await t.type(e.selector,e.value,{delay:50})}else if(e.action==="fill"){if(!e.selector)return c("Selector is required for 'fill'.",!0);if(!e.value)return c("Value is required for 'fill'.",!0);await t.fill(e.selector,e.value)}else if(e.action==="select_option"){if(!e.selector)return c("Selector is required for 'select_option'.",!0);if(!e.value)return c("Value is required for 'select_option'.",!0);await t.selectOption(e.selector,e.value)}else if(e.action==="hover"){if(!e.selector)return c("Selector is required for 'hover'.",!0);await t.hover(e.selector,{timeout:1e4})}else if(e.action==="press_key"){if(!e.value)return c("Value is required for 'press_key' (e.g. 'Enter').",!0);await t.keyboard.press(e.value),await t.waitForLoadState("domcontentloaded").catch(()=>{}),await t.waitForTimeout(500)}else if(e.action==="screenshot"){e.url&&(await t.goto(e.url,{waitUntil:"domcontentloaded",timeout:3e4}),await t.waitForLoadState("networkidle").catch(()=>{}));let o;if(e.selector){let i=await t.$(e.selector);if(!i)return c(`Element not found: ${e.selector}`,!0);o=await i.screenshot({type:"png"})}else o=await Pe(t,e.fullPage);return{content:[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),message:`Screenshot captured (${e.fullPage?"full page":"viewport"})`})},{type:"image",data:o.toString("base64"),mimeType:"image/png"}]}}else if(e.action==="snapshot"){let o=await ut(t);return{content:[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),snapshot:o})}]}}let a=await ut(t),n=[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),snapshot:a})}];if(e.includeScreenshot){let o=await Pe(t);n.push({type:"image",data:o.toString("base64"),mimeType:"image/png"})}return{content:n}}};import{existsSync as Ce,readFileSync as dt,writeFileSync as Ze}from"fs";import{join as be}from"path";import{z as lt}from"zod";function Ti(r){let e=be(r,"mistflow.json");if(!Ce(e))return{result:{name:"Project",status:"fail",message:"No mistflow.json found. This is not a Mistflow project.",fix:"Run mist_plan to design your app, then mist_build init to scaffold it."},config:null};let t;try{t=JSON.parse(dt(e,"utf-8"))}catch{return{result:{name:"Project",status:"fail",message:"mistflow.json exists but contains invalid JSON.",fix:"Check mistflow.json for syntax errors. If corrupted beyond repair, delete it and re-run mist_build init."},config:null}}if(!t.name||typeof t.name!="string")return{result:{name:"Project",status:"warn",message:"mistflow.json is missing the 'name' field."},config:t};let a=t.projectId,n=a?`, id: ${a}`:", no projectId (ephemeral)";return{result:{name:"Project",status:"pass",message:`${t.name}${n}`},config:t}}async function ys(){let r=Pa();if(!r.ok)return{result:{name:"Auth",status:"fail",message:r.reason==="missing"?"No credentials found.":"Credentials file is malformed.",fix:"Run mist_setup to log in."},creds:null,authValid:!1};try{let e=Aa(),t=await fetch(`${Ue()}/api/org`,{headers:e,signal:AbortSignal.timeout(1e4)});try{Ta(t.headers)}catch{}if(!t.ok)return t.status===401?{result:{name:"Auth",status:"fail",message:"API key is invalid or revoked.",fix:"Run mist_setup to re-authenticate."},creds:r.creds,authValid:!1}:{result:{name:"Auth",status:"warn",message:`Server returned ${t.status}. Credentials may still be valid.`},creds:r.creds,authValid:!1};let a=await t.json(),n=a.slug??r.creds.orgSlug??"unknown",o=a.plan?`, plan: ${a.plan}`:"";return{result:{name:"Auth",status:"pass",message:`org: ${n}${o}`},creds:r.creds,authValid:!0}}catch(e){return e instanceof ce?{result:{name:"Auth",status:"fail",message:`Auth check failed: ${e.message}`,fix:"Run mist_setup to re-authenticate."},creds:r.creds,authValid:!1}:{result:{name:"Auth",status:"warn",message:"Could not reach API to validate credentials. Network issue?"},creds:r.creds,authValid:!1}}}async function ws(){let r=Date.now();try{let e=await gt("nextjs"),t=Date.now()-r;return{result:{name:"API",status:"pass",message:`${Ue()} reachable (${t}ms)`},scaffold:e}}catch(e){let t=Date.now()-r;return{result:{name:"API",status:"fail",message:e instanceof ce?e.message:`Timeout or network error after ${t}ms`,fix:"Check your network connection. If using --api-url, verify the backend is running."},scaffold:null}}}function vs(){let r=ct();if(!r.backendSignalReceived)return{name:"MCP version",status:"warn",message:`v${r.current} installed, but no backend signal received to compare against.`};let e={none:"up to date",patch:"patch update available",minor:"minor update available",major:"major update available",unsupported:"no longer supported"};return r.severity==="none"?{name:"MCP version",status:"pass",message:`v${r.current} (latest)`}:r.severity==="unsupported"?{name:"MCP version",status:"fail",message:`v${r.current} is ${e[r.severity]}. Minimum: v${r.minSupported}.`,fix:`Run \`${r.upgradeCmd}\` then restart your editor.`}:{name:"MCP version",status:"warn",message:`v${r.current} installed, v${r.latest} available (${e[r.severity]}).`,fix:`Run \`${r.upgradeCmd}\` then restart your editor.`}}function ks(r,e,t,a){let n=be(r,"AGENTS.md"),o=be(r,"CLAUDE.md"),i=Ce(n),l=e.methodologyVersion??"",s=t?.version??"";if(!i){if(!a||!t?.methodology)return{name:"AGENTS.md",status:"fail",message:"Missing. The host AI has no methodology context for this project.",fix:t?"Run mist_doctor without reportOnly to auto-restore it.":"Cannot restore: API unreachable. Fix connectivity first."};let d=Ci(t.methodology,e);return Ze(n,d),Ze(o,d),{name:"AGENTS.md",status:"fix",message:`Restored from methodology v${s}.`}}if(a&&!Ce(o)){let d=dt(n,"utf-8");Ze(o,d)}if(s&&l&&s!==l){if(!a||!t?.methodology)return{name:"AGENTS.md",status:"warn",message:`Methodology v${l} installed, v${s} available.`,fix:"Run mist_doctor to update it."};let d=Ci(t.methodology,e);Ze(n,d),Ze(o,d);try{let p=be(r,"mistflow.json"),u=JSON.parse(dt(p,"utf-8"));u.methodologyVersion=s,Ze(p,JSON.stringify(u,null,2)+`
12487
- `)}catch{}return{name:"AGENTS.md",status:"fix",message:`Updated methodology v${l} -> v${s}.`}}return{name:"AGENTS.md",status:"pass",message:l?`v${l}`:"present"}}async function Ss(r,e,t,a){let n=e.projectId;if(!n)return{name:"State sync",status:"skip",message:"No projectId. State sync not applicable for ephemeral projects."};if(!t)return{name:"State sync",status:"skip",message:"Skipped (not authenticated)."};let o=Xa(r),i=await Za(n);if(!o&&!i)return{name:"State sync",status:"warn",message:"No local or remote state found."};if(!o&&i){if(a){let{writeLocalState:l}=await import("./state-manager-ZVLGPYXN.js");return l(r,i),{name:"State sync",status:"fix",message:"Local state was missing. Restored from remote."}}return{name:"State sync",status:"warn",message:"Local .mistflow/state.json is missing but remote state exists.",fix:"Run mist_doctor to restore it from the server."}}return o&&!i?{name:"State sync",status:"warn",message:"Local state exists but no remote state found. Remote sync may have failed."}:o&&o.projectId!==n?{name:"State sync",status:"warn",message:`state.json projectId (${o.projectId}) doesn't match mistflow.json projectId (${n}).`}:{name:"State sync",status:"pass",message:`deployCount: ${o.deployCount}, features: ${o.features.length}`}}function Ts(r){let e=[],t=[];if(Ce(be(r,"package.json"))?Ce(be(r,"node_modules"))||e.push("node_modules not installed (run npm install)"):e.push("missing package.json"),!Ce(be(r,".env.local")))e.push("missing .env.local");else try{dt(be(r,".env.local"),"utf-8").match(/^AUTH_SECRET=(.+)$/m)||e.push("AUTH_SECRET not set in .env.local")}catch{e.push(".env.local exists but is not readable")}let a=be(r,"app","api","auth","[...all]","route.ts");Ce(a)||t.push("missing app/api/auth/[...all]/route.ts");let n=be(r,"app","api","health","route.ts");return Ce(n)||t.push("missing app/api/health/route.ts (needed for deploy verification)"),e.length>0?{name:"Structure",status:"fail",message:e.join("; "),fix:e.map(o=>o.includes("node_modules")?"Run `npm install` in the project directory.":o.includes(".env.local")?"Create .env.local with AUTH_SECRET=<random-secret>.":o.includes("AUTH_SECRET")?"Add AUTH_SECRET=<random-secret> to .env.local.":o.includes("package.json")?"This project is missing package.json. Was it scaffolded correctly?":"").filter(Boolean).join(" ")}:t.length>0?{name:"Structure",status:"warn",message:t.join("; ")}:{name:"Structure",status:"pass",message:"all required files present"}}function Cs(r,e){let t=e.env;if(!t?.required||typeof t.required!="object"||Object.keys(t.required).length===0)return{name:"Env vars",status:"pass",message:"no required env vars declared"};let a=[],n="";for(let o of[".env.local",".env"]){let i=be(r,o);try{Ce(i)&&(n+=`
12488
- `+dt(i,"utf-8"))}catch{}}for(let[o,i]of Object.entries(t.required)){let l=n.includes(`${o}=`),s=!!process.env[o];if(!l&&!s){let d=i?.description?` (${i.description})`:"";a.push(`${o}${d}`)}}return a.length>0?{name:"Env vars",status:"warn",message:`${a.length} required but not set: ${a.join(", ")}`,fix:"Set them via mist_config or add to .env.local."}:{name:"Env vars",status:"pass",message:`${Object.keys(t.required).length} required, all set`}}function Ps(r){let e=r.plan;if(!e?.steps||e.steps.length===0)return{name:"Plan",status:"skip",message:"No plan found in mistflow.json."};let t=e.steps.length,a=e.steps.filter(i=>i.status==="completed").length,n=e.steps.filter(i=>i.status==="in_progress").length,o=t-a-n;if(a===t)return{name:"Plan",status:"pass",message:`${a}/${t} steps completed`};if(n>0){let i=e.steps.find(l=>l.status==="in_progress");return{name:"Plan",status:"warn",message:`${a}/${t} completed, step ${i?.number} "${i?.name}" in progress`,fix:"Run mist_build implement to continue."}}return a===0?{name:"Plan",status:"warn",message:`${t} steps planned, none started.`,fix:"Run mist_build implement to start building."}:{name:"Plan",status:"warn",message:`${a}/${t} completed, ${o} remaining.`,fix:"Run mist_build implement to continue."}}function Ci(r,e){let t=e.dbProvider;return t==="neon"||!t?r.replace(/sqliteTable/g,"pgTable").replace(/drizzle-orm\/sqlite-core/g,"drizzle-orm/pg-core").replace(/Use `text` for dates \(SQLite stores dates as text\)/g,"Use `timestamp` for dates and `boolean` for booleans (native Postgres types)").replace(/text\("created_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("created_at").notNull().defaultNow()').replace(/text\("updated_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("updated_at").notNull().defaultNow()').replace(/import { sqliteTable, text, integer } from "drizzle-orm\/sqlite-core";\nimport { sql } from "drizzle-orm";/g,'import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";').replace(/`drizzle-kit push` for SQLite\/Turso/g,"`drizzle-kit push` for Postgres/Neon"):r}function Bs(r){let e={pass:"PASS",warn:"WARN",fail:"FAIL",fix:"FIXED",skip:"SKIP"},t=Math.max(...r.map(p=>p.name.length)),a=r.map(p=>{let u=".".repeat(t-p.name.length+4),h=e[p.status].padEnd(5);return` ${p.name} ${u} ${h} ${p.message}`}),n=r.filter(p=>p.status==="fix").length,o=r.filter(p=>p.status==="fail").length,i=r.filter(p=>p.status==="warn").length,l=[];n>0&&l.push(`${n} fixed`),o>0&&l.push(`${o} failure${o>1?"s":""}`),i>0&&l.push(`${i} warning${i>1?"s":""}`);let s=`mist_doctor results:
10916
+ "build me something like ${s.share_url}"`}))}catch(s){let l=s instanceof Error?s.message:"Failed to share project";return c(l,!0)}}case"landing-designs":{if(e.presetId){let i=De(e.presetId);if(!i)return c(`Preset '${e.presetId}' not found. Use mist_project action='presets' without presetId to list all available presets.`,!0);let s=nr(e.presetId);return c(JSON.stringify({preset:{id:i.id,title:i.title,category:i.category,description:s?.description??"",style:s?.style??"",theme:s?.theme??"dark",colors:s?.colors??[],tags:s?.tags??[],promptLength:i.prompt.length},message:`Landing design "${i.title}" (${i.category}) \u2014 ${s?.description??""}. To use it, pass landingDesign="${i.id}" when calling mist_plan.`}))}let a=Kt(e.category??void 0),n=qt(e.category),o=or(n);return c(JSON.stringify({count:a.length,presets:a.map(i=>({id:i.id,title:i.title,category:i.category,description:i.description,style:i.style,theme:i.theme,colors:i.colors})),formatted:o,message:`${a.length} landing designs available.${e.category?` Filtered by: ${e.category}.`:""} To use one, pass landingDesign="<id>" when calling mist_plan. The design blueprint will be injected during the landing page implementation step. Browse them at ${Ee()}/designs?tab=landing-designs.`}))}case"app-styles":{if(e.appStyleId){let i=me(e.appStyleId);if(!i)return c(`App style '${e.appStyleId}' not found. Use mist_project action='app-styles' without appStyleId to list all available app styles.`,!0);let s=He(i.id);return c(JSON.stringify({appStyle:{id:i.id,name:i.name,category:s?.category??i.category,description:s?.description??"",theme:s?.theme??"light",colors:s?.colors??[],fonts:s?.fonts??{heading:"Inter",body:"Inter"},tags:s?.tags??[],sectionCount:i.sections.length,sections:i.sections.map(l=>l.title)},message:`App style "${i.name}" (${i.category}) \u2014 ${s?.description??""}. To use it, pass appStyle="${i.id}" when calling mist_plan. The style's component specs, typography, color palette, and layout rules will be injected during ALL implementation steps for consistent brand-quality design.`}))}let a=Qt(e.category??void 0),n=Yt(e.category??void 0),o=cr(n);return c(JSON.stringify({count:a.length,appStyles:a.map(i=>({id:i.id,name:i.name,category:i.category,description:i.description,theme:i.theme,colors:i.colors,fonts:i.fonts})),formatted:o,message:`${a.length} app styles available.${e.category?` Filtered by: ${e.category}.`:""} To use one, pass appStyle="<id>" when calling mist_plan. The style will be applied across ALL pages for consistent design. Browse them at ${Ee()}/designs?tab=app-styles.`}))}case"integrations":{if(e.integrationId){let i=Ve(e.integrationId);if(!i)return c(`Integration '${e.integrationId}' not found. Use mist_project action='integrations' without integrationId to list all available integrations.`,!0);let s=qe(i.id);return c(JSON.stringify({integration:{id:i.id,name:i.name,category:i.category,description:s?.description??"",packages:s?.packages??[],envVars:s?.envVars??[],docsUrl:s?.docsUrl??"",difficulty:s?.difficulty??"medium"},message:`Integration "${i.name}" (${i.category}) \u2014 ${s?.description??""}. This blueprint is auto-injected during implementation when your plan has a matching integration step. Required env vars: ${s?.envVars?.map(l=>l.key).join(", ")||"none"}. Docs: ${s?.docsUrl??"n/a"}.`}))}let a=gr(e.category??void 0),n=Zt(e.category??void 0),o=hr(n);return c(JSON.stringify({count:a.length,integrations:a.map(i=>({id:i.id,name:i.name,category:i.category,description:i.description,packages:i.packages,difficulty:i.difficulty,envVars:i.envVars.map(s=>s.key)})),formatted:o,message:`${a.length} integration blueprints available.${e.category?` Filtered by: ${e.category}.`:""} Integration blueprints are auto-injected during implementation when your plan includes a matching integration step. Use integrationId to see full details including env vars and setup URLs.`}))}case"errors":{let a=Ut(e.projectPath??process.cwd()),n=Wt(a,"mistflow.json");if(!Ht(n))return ge(a);let o;try{o=JSON.parse(Gt(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first.",!0);try{let s=await ja(i,e.period??"7d");return s.total===0?c(JSON.stringify({total:0,period:s.period,message:`No runtime errors in the last ${s.period}. The app is running clean.`})):c(JSON.stringify({total:s.total,period:s.period,errors:s.errors,message:`${s.total} runtime error(s) in the last ${s.period}. Review the errors above and use mist_build debug to investigate.`}))}catch(s){let l=s instanceof Error?s.message:"Failed to fetch errors";return c(l,!0)}}case"logs":{let a=Ut(e.projectPath??process.cwd()),n=Wt(a,"mistflow.json");if(!Ht(n))return ge(a);let o;try{o=JSON.parse(Gt(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first.",!0);let s=e.deploymentId;if(!s)try{let l=await et(i);if(l.length===0)return c("No deployments found for this project.",!0);s=l[0].id}catch(l){let d=l instanceof Error?l.message:"Failed to fetch deployments";return c(d,!0)}try{let[l,d]=await Promise.all([_a(s),Pe(s)]),u=l.filter(h=>h.level==="error"),p=l.filter(h=>h.level==="warn");return c(JSON.stringify({deploymentId:s,status:d.status,errorMessage:d.error??null,totalLogs:l.length,errorCount:u.length,warnCount:p.length,logs:l.map(h=>({time:h.timestamp,level:h.level,phase:h.phase,message:h.message})),message:d.status==="failed"?`Deployment failed. ${u.length} error(s) found in logs. Review the logs above to diagnose the issue.`:`Deployment status: ${d.status}. ${l.length} log entries (${u.length} errors, ${p.length} warnings).`}))}catch(l){let d=l instanceof Error?l.message:"Failed to fetch deploy logs";return c(d,!0)}}case"deployments":{let a=Ut(e.projectPath??process.cwd()),n=Wt(a,"mistflow.json");if(!Ht(n))return ge(a);let o;try{o=JSON.parse(Gt(n,"utf-8"))}catch{return c("Could not read mistflow.json.",!0)}let i=o.projectId;if(!i)return c("No project ID found. Deploy the project first.",!0);try{let s=await et(i);return c(JSON.stringify({total:s.length,deployments:s.map(l=>({id:l.id,status:l.status,errorMessage:l.error_message,durationSeconds:l.duration_seconds,isRollback:!!l.rollback_from_id,createdAt:l.created_at})),message:`${s.length} deployment(s) found. Use mist_project action='logs' deploymentId='<id>' to see detailed logs for any deployment.`}))}catch(s){let l=s instanceof Error?s.message:"Failed to fetch deployments";return c(l,!0)}}case"version":{let a=pt(),n=a.severity==="none",o={none:"up to date",patch:"patch update available",minor:"minor update available",major:"major update available",unsupported:"UNSUPPORTED \u2014 upgrade required"};return c(JSON.stringify({current:a.current,latest:a.latest||"unknown",minSupported:a.minSupported||"unknown",severity:a.severity,upToDate:n,upgradeCmd:a.upgradeCmd,changelogUrl:a.changelogUrl,backendSignalReceived:a.backendSignalReceived,message:a.backendSignalReceived?`Mistflow MCP ${a.current} (${o[a.severity]??a.severity}). Latest: ${a.latest}.${n?"":` Run \`${a.upgradeCmd}\` and restart your editor to upgrade.`}`:`Mistflow MCP ${a.current}. The backend hasn't replied yet \u2014 make one other API call (e.g. mist_project action='get') then retry to see the latest version.`}))}default:return c(`Unknown action: ${e.action}. Use get, update, share, landing-designs, app-styles, integrations, errors, logs, deployments, or version.`,!0)}}};import{z as be}from"zod";import{z as Le}from"zod";import{resolve as ks}from"path";var Yc=Le.object({projectPath:Le.string().optional().describe("Path to the project directory (default: cwd)"),action:Le.enum(["set","list","delete"]).describe("Action to perform"),key:Le.string().optional().describe("Environment variable name (required for 'set' and 'delete')"),value:Le.string().optional().describe("Environment variable value (required for 'set')"),category:Le.string().optional().describe("Category for the env var (default: 'custom')"),description:Le.string().optional().describe("Description of what this env var is for"),setupUrl:Le.string().optional().describe("URL where the user can obtain this value (e.g. Stripe dashboard)")});async function Pi(r){let{projectPath:e,action:t,key:a,value:n,category:o,description:i,setupUrl:s}=r,l=ks(e??process.cwd());if(!se())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let u=we(l)?.projectId;if(!u)return c("No project ID found. Deploy your project first with mist_deploy, or initialize with mist_plan + mist_build.",!0);try{switch(t){case"set":return a?n?(await Wa(u,a,n,{category:o,description:i,setupUrl:s}),c(JSON.stringify({set:!0,key:a,message:`Environment variable '${a}' has been set. It will be available on your next deployment.`}))):c("Value is required. Provide the env var value.",!0):c("Key is required. Provide the env var name like 'STRIPE_SECRET_KEY'.",!0);case"list":{let p=await Ga(u);return p.length===0?c(JSON.stringify({envVars:[],message:"No environment variables configured. Use action 'set' to add one."})):c(JSON.stringify({envVars:p.map(h=>({key:h.key,category:h.category,description:h.description,hasValue:h.has_value})),message:`${p.length} environment variable(s) configured.`}))}case"delete":return a?(await Oa(u,a),c(JSON.stringify({deleted:!0,key:a,message:`Environment variable '${a}' has been removed.`}))):c("Key is required. Provide the env var name to delete.",!0);default:return c(`Unknown action: ${t}. Use set, list, or delete.`,!0)}}catch(p){if(p instanceof ce)return c(p.message,!0);let h=p instanceof Error?p.message:"An unexpected error occurred";return c(h,!0)}}import{z as lt}from"zod";import{resolve as Ss,join as Cs}from"path";import{existsSync as Ts,readFileSync as Ps,writeFileSync as Bs}from"fs";var ip=lt.object({projectPath:lt.string().optional().describe("Path to the project directory (default: cwd)"),action:lt.enum(["add","list","verify","remove"]).describe("Action to perform"),domain:lt.string().optional().describe("Domain name (required for 'add' and 'remove')"),domainId:lt.string().optional().describe("Domain ID (required for 'verify' and 'remove')")});function ka(r,e){let t=Cs(r,"mistflow.json");if(!Ts(t))return;let a;try{a=JSON.parse(Ps(t,"utf-8"))}catch{return}a.domains=e,Bs(t,JSON.stringify(a,null,2)+`
10917
+ `)}async function Bi(r){let{projectPath:e,action:t,domain:a,domainId:n}=r,o=Ss(e??process.cwd());if(!se())return c("No Mistflow credentials found. Run mist_setup to connect your account.",!0);let s=we(o)?.projectId;if(!s)return c("No project ID found. Deploy your project first with mist_deploy, or initialize with mist_plan + mist_build.",!0);try{switch(t){case"add":{if(!a)return c("Domain name is required. Provide the domain like 'myapp.com' or 'app.mycompany.com'.",!0);let l=await Na(s,a),d=await Ue(s);return ka(o,d.map(u=>({domain:u.domain,status:u.status}))),c(JSON.stringify({added:!0,domain:l.domain,status:l.status,instructions:l.instructions,message:`Domain '${l.domain}' added. Set up DNS records as described, then use action 'verify' to check status.`}))}case"list":{let l=await Ue(s);return l.length===0?c(JSON.stringify({domains:[],message:"No custom domains configured. Use action 'add' to add one."})):c(JSON.stringify({domains:l.map(d=>({id:d.id,domain:d.domain,status:d.status,ssl:d.ssl_status,error:d.error_message}))}))}case"verify":{if(!n){if(a){let p=(await Ue(s)).find(h=>h.domain===a);if(p){let h=await zt(s,p.id);return c(JSON.stringify({domain:h.domain,status:h.status,ssl:h.ssl_status,error:h.error_message,message:h.status==="active"?`Domain '${h.domain}' is active and serving traffic.`:`Domain '${h.domain}' is ${h.status}. Make sure DNS records are configured correctly.`}))}return c(`Domain '${a}' not found. Use action 'list' to see configured domains.`,!0)}return c("Provide either domainId or domain name to verify.",!0)}let l=await zt(s,n),d=await Ue(s);return ka(o,d.map(u=>({domain:u.domain,status:u.status}))),c(JSON.stringify({domain:l.domain,status:l.status,ssl:l.ssl_status,error:l.error_message,message:l.status==="active"?`Domain '${l.domain}' is active and serving traffic.`:`Domain '${l.domain}' is ${l.status}. Make sure DNS records are configured correctly.`}))}case"remove":{if(!n&&!a)return c("Provide either domainId or domain name to remove.",!0);let l=n;if(!l&&a){let p=(await Ue(s)).find(h=>h.domain===a);if(!p)return c(`Domain '${a}' not found.`,!0);l=p.id}await Fa(s,l);let d=await Ue(s);return ka(o,d.map(u=>({domain:u.domain,status:u.status}))),c(JSON.stringify({removed:!0,message:"Domain removed. It may take a few minutes for DNS changes to propagate."}))}default:return c(`Unknown action: ${t}. Use add, list, verify, or remove.`,!0)}}catch(l){if(l instanceof ce)return c(l.message,!0);let d=l instanceof Error?l.message:"An unexpected error occurred";return c(d,!0)}}var Ds=be.object({resource:be.enum(["env","domain"]).describe("'env' manages app secrets and configuration values. 'domain' manages custom domains."),action:be.string().describe("Action to perform. env: 'set', 'list', 'delete'. domain: 'add', 'list', 'verify', 'remove'."),projectPath:be.string().optional().describe("Path to the project directory (default: cwd)"),key:be.string().optional().describe("(env) Variable name"),value:be.string().optional().describe("(env set) Variable value"),category:be.string().optional().describe("(env set) Category"),description:be.string().optional().describe("(env set) Description"),setupUrl:be.string().optional().describe("(env set) URL to obtain the value"),domain:be.string().optional().describe("(domain) Domain name"),domainId:be.string().optional().describe("(domain) Domain ID")}),Di={name:"mist_config",description:"Manage project configuration: app secrets and custom domains. Set resource='env' to manage encrypted app secrets (set, list, delete). Set resource='domain' to manage custom domains (add, list, verify, remove). Use when the user says 'mist env' or 'mist domain'.",inputSchema:Ds,handler:async r=>{let e=r;switch(e.resource){case"env":return Pi({projectPath:e.projectPath,action:e.action,key:e.key,value:e.value,category:e.category,description:e.description,setupUrl:e.setupUrl});case"domain":return Bi({projectPath:e.projectPath,action:e.action,domain:e.domain,domainId:e.domainId});default:return c(`Unknown resource: ${e.resource}. Use env or domain.`,!0)}}};import{z as je}from"zod";var Is=je.object({action:je.enum(["navigate","go_back","go_forward","click","type","fill","select_option","press_key","hover","screenshot","snapshot"]).describe("Action to perform. Navigation: navigate|go_back|go_forward. Interaction: click|type|fill|select_option|press_key|hover. Visual: screenshot (returns image) | snapshot (returns accessibility tree)."),url:je.string().optional().describe("URL to navigate to. Required for 'navigate'; optional for 'screenshot' (navigates before capturing)."),selector:je.string().optional().describe("CSS selector of the target element. Required for: click, type, fill, select_option, hover. Optional for screenshot (captures just that element)."),value:je.string().optional().describe("Text to type/fill, option to select, or key to press (e.g. 'Enter', 'Tab'). Required for: type, fill, select_option, press_key."),fullPage:je.boolean().default(!1).describe("For 'screenshot': capture the full scrollable page instead of just the viewport."),includeScreenshot:je.boolean().default(!1).describe("For navigate/interact actions: also return a screenshot alongside the accessibility snapshot.")}),Ii={name:"mist_browser",description:"Unified browser tool for navigating, interacting with, and capturing the app. Use 'navigate' to open a URL, interaction actions (click/type/fill/etc.) to test flows, 'snapshot' to inspect the accessibility tree, and 'screenshot' for a visual capture. Use after mist_preview to verify UI, test flows, and iterate on design.",inputSchema:Is,handler:async r=>{let e=r,t=await ut();if(e.action==="navigate"){if(!e.url)return c("URL is required for 'navigate'.",!0);let o=[],i=d=>{d.type()==="error"&&o.push(d.text())};t.on("console",i),await t.goto(e.url,{waitUntil:"domcontentloaded",timeout:3e4}),await t.waitForLoadState("networkidle").catch(()=>{});let s=[],l=d=>s.push(d.message);if(t.on("pageerror",l),await t.waitForTimeout(500),t.removeListener("console",i),t.removeListener("pageerror",l),o.length>0||s.length>0){let d=await ht(t),u=[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),snapshot:d,consoleErrors:o,pageErrors:s,hasErrors:!0})}];if(e.includeScreenshot){let p=await Te(t);u.push({type:"image",data:p.toString("base64"),mimeType:"image/png"})}return{content:u}}}else if(e.action==="go_back")await t.goBack({waitUntil:"domcontentloaded",timeout:1e4});else if(e.action==="go_forward")await t.goForward({waitUntil:"domcontentloaded",timeout:1e4});else if(e.action==="click"){if(!e.selector)return c("Selector is required for 'click'.",!0);await t.click(e.selector,{timeout:1e4}),await t.waitForLoadState("domcontentloaded").catch(()=>{}),await t.waitForTimeout(500)}else if(e.action==="type"){if(!e.selector)return c("Selector is required for 'type'.",!0);if(!e.value)return c("Value is required for 'type'.",!0);await t.type(e.selector,e.value,{delay:50})}else if(e.action==="fill"){if(!e.selector)return c("Selector is required for 'fill'.",!0);if(!e.value)return c("Value is required for 'fill'.",!0);await t.fill(e.selector,e.value)}else if(e.action==="select_option"){if(!e.selector)return c("Selector is required for 'select_option'.",!0);if(!e.value)return c("Value is required for 'select_option'.",!0);await t.selectOption(e.selector,e.value)}else if(e.action==="hover"){if(!e.selector)return c("Selector is required for 'hover'.",!0);await t.hover(e.selector,{timeout:1e4})}else if(e.action==="press_key"){if(!e.value)return c("Value is required for 'press_key' (e.g. 'Enter').",!0);await t.keyboard.press(e.value),await t.waitForLoadState("domcontentloaded").catch(()=>{}),await t.waitForTimeout(500)}else if(e.action==="screenshot"){e.url&&(await t.goto(e.url,{waitUntil:"domcontentloaded",timeout:3e4}),await t.waitForLoadState("networkidle").catch(()=>{}));let o;if(e.selector){let i=await t.$(e.selector);if(!i)return c(`Element not found: ${e.selector}`,!0);o=await i.screenshot({type:"png"})}else o=await Te(t,e.fullPage);return{content:[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),message:`Screenshot captured (${e.fullPage?"full page":"viewport"})`})},{type:"image",data:o.toString("base64"),mimeType:"image/png"}]}}else if(e.action==="snapshot"){let o=await ht(t);return{content:[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),snapshot:o})}]}}let a=await ht(t),n=[{type:"text",text:JSON.stringify({url:t.url(),title:await t.title(),snapshot:a})}];if(e.includeScreenshot){let o=await Te(t);n.push({type:"image",data:o.toString("base64"),mimeType:"image/png"})}return{content:n}}};import{existsSync as Se,readFileSync as ct,writeFileSync as Ze}from"fs";import{join as xe}from"path";import{z as dt}from"zod";function Ai(r){let e=xe(r,"mistflow.json");if(!Se(e))return{result:{name:"Project",status:"fail",message:"No mistflow.json found. This is not a Mistflow project.",fix:"Run mist_plan to design your app, then mist_build init to scaffold it."},config:null};let t;try{t=JSON.parse(ct(e,"utf-8"))}catch{return{result:{name:"Project",status:"fail",message:"mistflow.json exists but contains invalid JSON.",fix:"Check mistflow.json for syntax errors. If corrupted beyond repair, delete it and re-run mist_build init."},config:null}}if(!t.name||typeof t.name!="string")return{result:{name:"Project",status:"warn",message:"mistflow.json is missing the 'name' field."},config:t};let a=t.projectId,n=a?`, id: ${a}`:", no projectId (ephemeral)";return{result:{name:"Project",status:"pass",message:`${t.name}${n}`},config:t}}async function As(){let r=Pa();if(!r.ok)return{result:{name:"Auth",status:"fail",message:r.reason==="missing"?"No credentials found.":"Credentials file is malformed.",fix:"Run mist_setup to log in."},creds:null,authValid:!1};try{let e=Ia(),t=await fetch(`${Fe()}/api/org`,{headers:e,signal:AbortSignal.timeout(1e4)});try{Ca(t.headers)}catch{}if(!t.ok)return t.status===401?{result:{name:"Auth",status:"fail",message:"API key is invalid or revoked.",fix:"Run mist_setup to re-authenticate."},creds:r.creds,authValid:!1}:{result:{name:"Auth",status:"warn",message:`Server returned ${t.status}. Credentials may still be valid.`},creds:r.creds,authValid:!1};let a=await t.json(),n=a.slug??r.creds.orgSlug??"unknown",o=a.plan?`, plan: ${a.plan}`:"";return{result:{name:"Auth",status:"pass",message:`org: ${n}${o}`},creds:r.creds,authValid:!0}}catch(e){return e instanceof ce?{result:{name:"Auth",status:"fail",message:`Auth check failed: ${e.message}`,fix:"Run mist_setup to re-authenticate."},creds:r.creds,authValid:!1}:{result:{name:"Auth",status:"warn",message:"Could not reach API to validate credentials. Network issue?"},creds:r.creds,authValid:!1}}}async function Ms(){let r=Date.now();try{let e=await mt("nextjs"),t=Date.now()-r;return{result:{name:"API",status:"pass",message:`${Fe()} reachable (${t}ms)`},scaffold:e}}catch(e){let t=Date.now()-r;return{result:{name:"API",status:"fail",message:e instanceof ce?e.message:`Timeout or network error after ${t}ms`,fix:"Check your network connection. If using --api-url, verify the backend is running."},scaffold:null}}}function Rs(){let r=pt();if(!r.backendSignalReceived)return{name:"MCP version",status:"warn",message:`v${r.current} installed, but no backend signal received to compare against.`};let e={none:"up to date",patch:"patch update available",minor:"minor update available",major:"major update available",unsupported:"no longer supported"};return r.severity==="none"?{name:"MCP version",status:"pass",message:`v${r.current} (latest)`}:r.severity==="unsupported"?{name:"MCP version",status:"fail",message:`v${r.current} is ${e[r.severity]}. Minimum: v${r.minSupported}.`,fix:`Run \`${r.upgradeCmd}\` then restart your editor.`}:{name:"MCP version",status:"warn",message:`v${r.current} installed, v${r.latest} available (${e[r.severity]}).`,fix:`Run \`${r.upgradeCmd}\` then restart your editor.`}}function Ls(r,e,t,a){let n=xe(r,"AGENTS.md"),o=xe(r,"CLAUDE.md"),i=Se(n),s=e.methodologyVersion??"",l=t?.version??"";if(!i){if(!a||!t?.methodology)return{name:"AGENTS.md",status:"fail",message:"Missing. The host AI has no methodology context for this project.",fix:t?"Run mist_doctor without reportOnly to auto-restore it.":"Cannot restore: API unreachable. Fix connectivity first."};let d=Mi(t.methodology,e);return Ze(n,d),Ze(o,d),{name:"AGENTS.md",status:"fix",message:`Restored from methodology v${l}.`}}if(a&&!Se(o)){let d=ct(n,"utf-8");Ze(o,d)}if(l&&s&&l!==s){if(!a||!t?.methodology)return{name:"AGENTS.md",status:"warn",message:`Methodology v${s} installed, v${l} available.`,fix:"Run mist_doctor to update it."};let d=Mi(t.methodology,e);Ze(n,d),Ze(o,d);try{let u=xe(r,"mistflow.json"),p=JSON.parse(ct(u,"utf-8"));p.methodologyVersion=l,Ze(u,JSON.stringify(p,null,2)+`
10918
+ `)}catch{}return{name:"AGENTS.md",status:"fix",message:`Updated methodology v${s} -> v${l}.`}}return{name:"AGENTS.md",status:"pass",message:s?`v${s}`:"present"}}async function Ns(r,e,t,a){let n=e.projectId;if(!n)return{name:"State sync",status:"skip",message:"No projectId. State sync not applicable for ephemeral projects."};if(!t)return{name:"State sync",status:"skip",message:"Skipped (not authenticated)."};let o=er(r),i=await tr(n);if(!o&&!i)return{name:"State sync",status:"warn",message:"No local or remote state found."};if(!o&&i){if(a){let{writeLocalState:s}=await import("./state-manager-73ZUDKOP.js");return s(r,i),{name:"State sync",status:"fix",message:"Local state was missing. Restored from remote."}}return{name:"State sync",status:"warn",message:"Local .mistflow/state.json is missing but remote state exists.",fix:"Run mist_doctor to restore it from the server."}}return o&&!i?{name:"State sync",status:"warn",message:"Local state exists but no remote state found. Remote sync may have failed."}:o&&o.projectId!==n?{name:"State sync",status:"warn",message:`state.json projectId (${o.projectId}) doesn't match mistflow.json projectId (${n}).`}:{name:"State sync",status:"pass",message:`deployCount: ${o.deployCount}, features: ${o.features.length}`}}function Fs(r){let e=[],t=[];if(Se(xe(r,"package.json"))?Se(xe(r,"node_modules"))||e.push("node_modules not installed (run npm install)"):e.push("missing package.json"),!Se(xe(r,".env.local")))e.push("missing .env.local");else try{ct(xe(r,".env.local"),"utf-8").match(/^AUTH_SECRET=(.+)$/m)||e.push("AUTH_SECRET not set in .env.local")}catch{e.push(".env.local exists but is not readable")}let a=xe(r,"app","api","auth","[...all]","route.ts");Se(a)||t.push("missing app/api/auth/[...all]/route.ts");let n=xe(r,"app","api","health","route.ts");return Se(n)||t.push("missing app/api/health/route.ts (needed for deploy verification)"),e.length>0?{name:"Structure",status:"fail",message:e.join("; "),fix:e.map(o=>o.includes("node_modules")?"Run `npm install` in the project directory.":o.includes(".env.local")?"Create .env.local with AUTH_SECRET=<random-secret>.":o.includes("AUTH_SECRET")?"Add AUTH_SECRET=<random-secret> to .env.local.":o.includes("package.json")?"This project is missing package.json. Was it scaffolded correctly?":"").filter(Boolean).join(" ")}:t.length>0?{name:"Structure",status:"warn",message:t.join("; ")}:{name:"Structure",status:"pass",message:"all required files present"}}function Es(r,e){let t=e.env;if(!t?.required||typeof t.required!="object"||Object.keys(t.required).length===0)return{name:"Env vars",status:"pass",message:"no required env vars declared"};let a=[],n="";for(let o of[".env.local",".env"]){let i=xe(r,o);try{Se(i)&&(n+=`
10919
+ `+ct(i,"utf-8"))}catch{}}for(let[o,i]of Object.entries(t.required)){let s=n.includes(`${o}=`),l=!!process.env[o];if(!s&&!l){let d=i?.description?` (${i.description})`:"";a.push(`${o}${d}`)}}return a.length>0?{name:"Env vars",status:"warn",message:`${a.length} required but not set: ${a.join(", ")}`,fix:"Set them via mist_config or add to .env.local."}:{name:"Env vars",status:"pass",message:`${Object.keys(t.required).length} required, all set`}}function Us(r){let e=r.plan;if(!e?.steps||e.steps.length===0)return{name:"Plan",status:"skip",message:"No plan found in mistflow.json."};let t=e.steps.length,a=e.steps.filter(i=>i.status==="completed").length,n=e.steps.filter(i=>i.status==="in_progress").length,o=t-a-n;if(a===t)return{name:"Plan",status:"pass",message:`${a}/${t} steps completed`};if(n>0){let i=e.steps.find(s=>s.status==="in_progress");return{name:"Plan",status:"warn",message:`${a}/${t} completed, step ${i?.number} "${i?.name}" in progress`,fix:"Run mist_build implement to continue."}}return a===0?{name:"Plan",status:"warn",message:`${t} steps planned, none started.`,fix:"Run mist_build implement to start building."}:{name:"Plan",status:"warn",message:`${a}/${t} completed, ${o} remaining.`,fix:"Run mist_build implement to continue."}}function Mi(r,e){let t=e.dbProvider;return t==="neon"||!t?r.replace(/sqliteTable/g,"pgTable").replace(/drizzle-orm\/sqlite-core/g,"drizzle-orm/pg-core").replace(/Use `text` for dates \(SQLite stores dates as text\)/g,"Use `timestamp` for dates and `boolean` for booleans (native Postgres types)").replace(/text\("created_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("created_at").notNull().defaultNow()').replace(/text\("updated_at"\)\.notNull\(\)\.default\(sql`\(CURRENT_TIMESTAMP\)`\)/g,'timestamp("updated_at").notNull().defaultNow()').replace(/import { sqliteTable, text, integer } from "drizzle-orm\/sqlite-core";\nimport { sql } from "drizzle-orm";/g,'import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";').replace(/`drizzle-kit push` for SQLite\/Turso/g,"`drizzle-kit push` for Postgres/Neon"):r}function Hs(r){let e={pass:"PASS",warn:"WARN",fail:"FAIL",fix:"FIXED",skip:"SKIP"},t=Math.max(...r.map(u=>u.name.length)),a=r.map(u=>{let p=".".repeat(t-u.name.length+4),h=e[u.status].padEnd(5);return` ${u.name} ${p} ${h} ${u.message}`}),n=r.filter(u=>u.status==="fix").length,o=r.filter(u=>u.status==="fail").length,i=r.filter(u=>u.status==="warn").length,s=[];n>0&&s.push(`${n} fixed`),o>0&&s.push(`${o} failure${o>1?"s":""}`),i>0&&s.push(`${i} warning${i>1?"s":""}`);let l=`mist_doctor results:
12489
10920
 
12490
10921
  `+a.join(`
12491
- `);l.length>0?s+=`
10922
+ `);s.length>0?l+=`
12492
10923
 
12493
- ${l.join(", ")}`:s+=`
10924
+ ${s.join(", ")}`:l+=`
12494
10925
 
12495
- All checks passed.`;let d=r.filter(p=>(p.status==="fail"||p.status==="warn")&&p.fix);if(d.length>0){s+=`
10926
+ All checks passed.`;let d=r.filter(u=>(u.status==="fail"||u.status==="warn")&&u.fix);if(d.length>0){l+=`
12496
10927
 
12497
- To fix:`;for(let p of d)s+=`
12498
- - ${p.fix}`}return s}var Pi=lt.object({projectPath:lt.string().optional().describe("Path to the project directory. Defaults to the current working directory."),checks:lt.array(lt.enum(["project","auth","api","version","methodology","state","structure","env","plan"])).optional().describe("Run only specific checks. Omit to run all."),reportOnly:lt.boolean().optional().describe("If true, report issues without auto-fixing them.")}),Bi={name:"mist_doctor",description:"Diagnose project health: checks auth, API connectivity, AGENTS.md methodology, project state, version alignment, and structure. Auto-fixes safe issues (missing AGENTS.md, stale state). Run when something feels off.",inputSchema:Pi,handler:async r=>{let e=Pi.parse(r),t=e.projectPath||process.cwd(),a=!e.reportOnly,n=!e.checks,o=e.checks??[],i=f=>n||o.includes(f),l=[],s=null;if(i("project")){let f=Ti(t);l.push(f.result),s=f.config}else s=Ti(t).config;let d=!1;if(i("auth")||i("state")){let f=await ys();i("auth")&&l.push(f.result),d=f.authValid}let u=null;if(i("api")||i("methodology")){let f=await ws();i("api")&&l.push(f.result),u=f.scaffold}i("version")&&l.push(vs()),s?(i("methodology")&&l.push(ks(t,s,u,a)),i("state")&&l.push(await Ss(t,s,d,a)),i("structure")&&l.push(Ts(t)),i("env")&&l.push(Cs(t,s)),i("plan")&&l.push(Ps(s))):n&&(l.push({name:"AGENTS.md",status:"skip",message:"Skipped (not a Mistflow project)."}),l.push({name:"State sync",status:"skip",message:"Skipped (not a Mistflow project)."}),l.push({name:"Structure",status:"skip",message:"Skipped (not a Mistflow project)."}),l.push({name:"Env vars",status:"skip",message:"Skipped (not a Mistflow project)."}),l.push({name:"Plan",status:"skip",message:"Skipped (not a Mistflow project)."}));let m=Bs(l),b=l.some(f=>f.status==="fail");return c(m,b)}};var Sa=new Is({name:"mistflow",version:"0.2.0"},{capabilities:{tools:{}},instructions:`Mistflow is a full-stack app builder that creates and deploys web apps from natural language descriptions. When a user asks to build, create, or make a web app, website, landing page, dashboard, internal tool, marketplace, content site, or browser game, use Mistflow tools. Mistflow creates NEW apps from scratch. It does NOT modify existing non-Mistflow codebases.
10928
+ To fix:`;for(let u of d)l+=`
10929
+ - ${u.fix}`}return l}var Ri=dt.object({projectPath:dt.string().optional().describe("Path to the project directory. Defaults to the current working directory."),checks:dt.array(dt.enum(["project","auth","api","version","methodology","state","structure","env","plan"])).optional().describe("Run only specific checks. Omit to run all."),reportOnly:dt.boolean().optional().describe("If true, report issues without auto-fixing them.")}),Li={name:"mist_doctor",description:"Diagnose project health: checks auth, API connectivity, AGENTS.md methodology, project state, version alignment, and structure. Auto-fixes safe issues (missing AGENTS.md, stale state). Run when something feels off.",inputSchema:Ri,handler:async r=>{let e=Ri.parse(r),t=e.projectPath||process.cwd(),a=!e.reportOnly,n=!e.checks,o=e.checks??[],i=b=>n||o.includes(b),s=[],l=null;if(i("project")){let b=Ai(t);s.push(b.result),l=b.config}else l=Ai(t).config;let d=!1;if(i("auth")||i("state")){let b=await As();i("auth")&&s.push(b.result),d=b.authValid}let p=null;if(i("api")||i("methodology")){let b=await Ms();i("api")&&s.push(b.result),p=b.scaffold}i("version")&&s.push(Rs()),l?(i("methodology")&&s.push(Ls(t,l,p,a)),i("state")&&s.push(await Ns(t,l,d,a)),i("structure")&&s.push(Fs(t)),i("env")&&s.push(Es(t,l)),i("plan")&&s.push(Us(l))):n&&(s.push({name:"AGENTS.md",status:"skip",message:"Skipped (not a Mistflow project)."}),s.push({name:"State sync",status:"skip",message:"Skipped (not a Mistflow project)."}),s.push({name:"Structure",status:"skip",message:"Skipped (not a Mistflow project)."}),s.push({name:"Env vars",status:"skip",message:"Skipped (not a Mistflow project)."}),s.push({name:"Plan",status:"skip",message:"Skipped (not a Mistflow project)."}));let m=Hs(s),f=s.some(b=>b.status==="fail");return c(m,f)}};var Sa=new Gs({name:"mistflow",version:"0.2.0"},{capabilities:{tools:{}},instructions:`Mistflow is a full-stack app builder that creates and deploys web apps from natural language descriptions. When a user asks to build, create, or make a web app, website, landing page, dashboard, internal tool, marketplace, content site, or browser game, use Mistflow tools. Mistflow creates NEW apps from scratch. It does NOT modify existing non-Mistflow codebases.
12499
10930
 
12500
10931
  New app workflow:
12501
10932
  1. mist_plan - pass the user's description EXACTLY as written. Do NOT expand, rephrase, or add features. If the tool returns status "confirm_new_project" (safety gate when inside an existing codebase), you MUST ask the user whether to scaffold a new Mistflow app or edit the existing code. If it returns status "clarify", present the discovery questions to the user, collect answers, and call mist_plan again with the conversationId and answers.
@@ -12526,4 +10957,4 @@ Other tools:
12526
10957
  - mist_project: read/update project state, browse landing designs and app styles, view runtime errors, deploy logs, deployment history, and check MCP version.
12527
10958
  - mist_config: manage encrypted app secrets (env vars) and custom domains.
12528
10959
  - mist_browser: navigate, interact with, and screenshot the app during preview or after deploy.
12529
- - mist_doctor: diagnose project health. Checks auth, API connectivity, AGENTS.md methodology, MCP version, project state, structure, and env vars. Auto-fixes safe issues (missing/outdated AGENTS.md, missing local state). Run when something feels off or tools behave unexpectedly.`}),Ii=[tr,xr,_r,fi,yi,ki,Si,Bi];Sa.setRequestHandler(Ms,async()=>({tools:Ii.map(r=>({name:r.name,description:r.description,inputSchema:Rs(r.inputSchema)}))}));Sa.setRequestHandler(Ds,async r=>{let e=Ii.find(t=>t.name===r.params.name);if(!e)return c(`Unknown tool: ${r.params.name}`,!0);try{let t=e.inputSchema.safeParse(r.params.arguments);if(!t.success){let a=t.error.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ");return c(`Invalid input: ${a}`,!0)}return await e.handler(t.data)}catch(t){let a=t instanceof Error?t.message:"An unexpected error occurred";return console.error("Tool error:",t),c(a,!0)}});async function Ls(){let r=process.argv.indexOf("--api-url");r!==-1&&process.argv[r+1]&&(process.env.MISTFLOW_API_URL=process.argv[r+1]),process.argv.includes("--local")&&!process.env.MISTFLOW_API_URL&&(process.env.MISTFLOW_API_URL="http://localhost:9100");let e=new As;await Sa.connect(e),console.error(`Mistflow MCP server running on stdio (API: ${process.env.MISTFLOW_API_URL||"https://api.mistflow.ai"})`)}Ls().catch(r=>{console.error("Fatal error:",r),process.exit(1)});
10960
+ - mist_doctor: diagnose project health. Checks auth, API connectivity, AGENTS.md methodology, MCP version, project state, structure, and env vars. Auto-fixes safe issues (missing/outdated AGENTS.md, missing local state). Run when something feels off or tools behave unexpectedly.`}),Ni=[ir,kr,qr,ki,Ti,Di,Ii,Li];Sa.setRequestHandler(_s,async()=>({tools:Ni.map(r=>({name:r.name,description:r.description,inputSchema:js(r.inputSchema)}))}));Sa.setRequestHandler(Os,async r=>{let e=Ni.find(t=>t.name===r.params.name);if(!e)return c(`Unknown tool: ${r.params.name}`,!0);try{let t=e.inputSchema.safeParse(r.params.arguments);if(!t.success){let a=t.error.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ");return c(`Invalid input: ${a}`,!0)}return await e.handler(t.data)}catch(t){let a=t instanceof Error?t.message:"An unexpected error occurred";return console.error("Tool error:",t),c(a,!0)}});async function zs(){let r=process.argv.indexOf("--api-url");r!==-1&&process.argv[r+1]&&(process.env.MISTFLOW_API_URL=process.argv[r+1]),process.argv.includes("--local")&&!process.env.MISTFLOW_API_URL&&(process.env.MISTFLOW_API_URL="http://localhost:9100");let e=new Ws;await Sa.connect(e),console.error(`Mistflow MCP server running on stdio (API: ${process.env.MISTFLOW_API_URL||"https://api.mistflow.ai"})`)}zs().catch(r=>{console.error("Fatal error:",r),process.exit(1)});