@mistflow-ai/mcp 1.0.11 → 1.0.12

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
@@ -1783,8 +1783,8 @@ is cheaper than building the wrong thing and iterating.
1783
1783
  `).trim())}};import{existsSync as eo,mkdirSync as Tn,readFileSync as Pn,readdirSync as In,writeFileSync as pa}from"fs";import{join as $e,resolve as ua}from"path";import{homedir as ir}from"os";import{z as Ct}from"zod";function ct(t){return t.entity??t.name??"Unknown"}function dt(t){return typeof t=="string"?t:t.name}function sr(t){return typeof t=="string"?"text":t.type}function xn(t){let e=t.sampleRows;if(Array.isArray(e)&&e.length>0)return e.slice(0,3).map(s=>{let i={};for(let[n,a]of Object.entries(s))i[n]=a==null?"":String(a);return i});let r=t.fields||[],o=[];for(let s=0;s<3;s++){let i={};for(let n of r)i[dt(n)]=ma(dt(n),sr(n),ct(t),s);o.push(i)}return o}function ma(t,e,r,o){let s=t.toLowerCase(),i=(e||"text").toLowerCase();return s==="name"||s==="title"?[`${r} Alpha`,`${r} Beta`,`${r} Gamma`][o]:s==="email"?["alice@example.com","bob@example.com","carol@example.com"][o]:s==="status"?["Active","Pending","Completed"][o]:s==="priority"?["High","Medium","Low"][o]:s.includes("date")||i==="date"?["Jan 15, 2024","Feb 20, 2024","Mar 10, 2024"][o]:s.includes("price")||s.includes("amount")||s.includes("cost")?["$29","$49","$99"][o]:s.includes("count")||s.includes("quantity")||i==="number"||i==="integer"?["12","34","56"][o]:i==="boolean"||i==="bool"?["Yes","No","Yes"][o]:s.includes("description")||i==="textarea"?["Brief description here","Another example entry","Third sample item"][o]:`Sample ${o+1}`}function ha(t){let e=t.dataModel??[],r=t.pages??[],o=t.design??{},s=r.map(m=>({label:m.name??m.path??"Page",route:m.path??m.route??"/"})),i=[],n=e.slice(0,3).map(m=>({name:ct(m),fields:(m.fields||[]).map(p=>({name:dt(p),type:sr(p)})),sampleData:xn(m)})),a=[];t.primaryAction&&(a.push(`PRIMARY: ${t.primaryAction.action} \u2014 this is the first thing the user sees and does`),a.push(`SURFACE: ${t.primaryAction.dashboardSurface}`)),a.push(`METRICS: Key counts for ${e.map(m=>ct(m)).join(", ")}`),a.push("RECENT: Latest activity or items"),i.push({name:"Dashboard",type:"dashboard",route:"/dashboard",purpose:t.primaryAction?`Action surface \u2014 user comes here to ${t.primaryAction.action.toLowerCase()}. Not a stats display.`:`Overview of ${e.map(m=>ct(m)).join(", ")} with key metrics.`,informationHierarchy:a,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:n});let l=e[0];if(l){let m=ct(l),p=m.toLowerCase().endsWith("s")?m:`${m}s`;i.push({name:`${m} List`,type:"detail",route:`/${p.toLowerCase()}`,purpose:`Browse, search, and manage ${p.toLowerCase()}. Create new ${m.toLowerCase()}s.`,informationHierarchy:[`HEADER: "${p}" title + "Add ${m}" button`,"SEARCH: Filter/search bar \u2014 users will have many items",`TABLE: ${(l.fields||[]).slice(0,5).map(y=>dt(y)).join(", ")} columns`,"ROW ACTIONS: Edit, delete on each row"],interactionStates:[`Empty state: "No ${p.toLowerCase()} yet" with create CTA`,"Loading state: skeleton table rows",`Search with no results: "No ${p.toLowerCase()} matching..." with clear filter`],entities:[{name:m,fields:(l.fields||[]).map(y=>({name:dt(y),type:sr(y)})),sampleData:xn(l)}]})}t.steps.some(m=>{let p=`${m.name??m.title??""} ${m.description??""}`.toLowerCase();return p.includes("landing")||p.includes("hero")||p.includes("marketing")||p.includes("homepage")})&&i.push({name:"Landing Page",type:"landing",route:"/",purpose:`Convince visitors to sign up for ${t.name}. Answer: what is this, who is it for, why should I care.`,informationHierarchy:[`HERO: One sentence about what ${t.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 h=[];for(let m of e.slice(0,3)){let p=ct(m);(m.fields||[]).find(x=>{let b=dt(x).toLowerCase();return b==="name"||b==="title"})&&h.push(`What if a ${p.toLowerCase()}'s name is 47 characters? Does the layout break?`),h.push(`What if there are 0 ${p.toLowerCase()}s? 1? 500?`)}return t.authModel&&t.authModel!=="none"&&h.push("What does a brand-new user see? (no data, no setup)"),h.push("What if the network is slow? What loads first?"),{appName:t.name,summary:t.summary??"",screens:i,navigation:{style:t.navStyle??"sidebar",items:s},primaryAction:t.primaryAction??null,designDirection:{tone:o.tone??"professional",accentColor:o.accentColor??"blue",navStyle:t.navStyle??"sidebar",fonts:o.fonts??{heading:"Inter",body:"Inter"}},edgeCases:h}}function ga(t,e,r){let o=[];o.push(`# Wireframe sketch for ${t.appName}`),o.push(""),o.push(`**${t.appName}** \u2014 ${t.summary}`),o.push(""),e&&(o.push("## Feedback to apply"),o.push(e),o.push("")),o.push("## Design principles"),o.push(""),o.push("Apply these when deciding layout and hierarchy:"),o.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."),o.push("2. **Interaction states** \u2014 Every screen has at least: empty, loading, populated. Show the populated state but add HTML comments noting the others."),o.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."),o.push(`4. **Subtraction** \u2014 "As little design as possible" (Dieter Rams). Every element earns its pixels. If removing something doesn't hurt, remove it.`),o.push("5. **Design for trust** \u2014 Clear labels, predictable layout, obvious actions. No mystery meat navigation."),o.push(""),o.push("## Wireframe rules (strict)"),o.push(""),o.push(`Write a **single self-contained HTML file** saved to \`${r}\`.`),o.push(""),o.push("The wireframe must:"),o.push("- Use **system fonts only** (`-apple-system, system-ui, sans-serif`) \u2014 no Google Fonts, no CDN"),o.push("- Use **inline CSS only** \u2014 no external stylesheets, no Tailwind CDN"),o.push("- Look **intentionally rough** \u2014 thin gray borders (#ddd), light backgrounds (#f8f8f8), no color, no shadows"),o.push("- Use **realistic placeholder content** that matches this specific app (sample data provided below) \u2014 NOT lorem ipsum"),o.push("- Include **HTML comments** explaining design decisions"),o.push("- Show **all screens in a single page** using tabs/sections that the user can click through"),o.push("- Be **responsive** \u2014 test that it looks reasonable at both 1200px and 375px widths"),o.push("- Include a small header bar showing: screen name tabs + the design direction summary"),o.push(""),o.push("The wireframe must NOT:"),o.push("- Use any color except grayscale (#333, #666, #999, #ddd, #f8f8f8, white)"),o.push("- Use any external dependencies \u2014 no CDN, no imports, no build step"),o.push("- Look polished \u2014 it should feel like a sketch on a whiteboard, not a finished product"),o.push("- Include decorative elements \u2014 no icons (use text labels), no illustrations, no gradients"),o.push(""),o.push("## Screens to wireframe"),o.push("");for(let s of t.screens){o.push(`### ${s.name} (\`${s.route}\`)`),o.push(`**Purpose**: ${s.purpose}`),o.push(""),o.push("**Information hierarchy** (render in this order, top to bottom):");for(let i of s.informationHierarchy)o.push(`- ${i}`);o.push(""),o.push("**Interaction states** (add HTML comments for non-visible states):");for(let i of s.interactionStates)o.push(`- ${i}`);if(o.push(""),s.entities.length>0){o.push("**Data model and sample content** (use this real data, not lorem ipsum):");for(let i of s.entities)o.push(`
1784
1784
  **${i.name}** \u2014 fields: ${i.fields.map(n=>`${n.name} (${n.type})`).join(", ")}`),o.push("```json"),o.push(JSON.stringify(i.sampleData,null,2)),o.push("```");o.push("")}}o.push("## Navigation"),o.push(`**Style**: ${t.navigation.style} (use this layout)`),o.push("**Items**:");for(let s of t.navigation.items)o.push(`- ${s.label} \u2192 \`${s.route}\``);if(o.push(""),t.primaryAction&&(o.push("## Primary action (this drives the layout)"),o.push(`- **Action**: ${t.primaryAction.action}`),o.push(`- **Flow**: ${t.primaryAction.flow}`),o.push(`- **Dashboard must show**: ${t.primaryAction.dashboardSurface}`),o.push(""),o.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."),o.push("")),t.edgeCases.length>0){o.push("## Edge cases to consider"),o.push("Add HTML comments in the wireframe where these matter:");for(let s of t.edgeCases)o.push(`- ${s}`);o.push("")}return o.push("## Design direction (DO NOT apply to wireframe \u2014 this is for reference only)"),o.push(`The final app will use: ${t.designDirection.tone} tone, ${t.designDirection.accentColor} accent, ${t.designDirection.navStyle} nav, ${t.designDirection.fonts.heading} / ${t.designDirection.fonts.body} fonts.`),o.push("The wireframe is grayscale and rough. These tokens will be applied during the actual build."),o.push(""),o.push("## After writing the wireframe"),o.push(`1. Write the file to \`${r}\``),o.push(`2. Open it for the user: \`open "${r}"\``),o.push(`3. Tell the user: "Here's a rough wireframe of your app. Does the layout feel right? Let me know what to change, or I can start building if it's close."`),o.push("4. WAIT for the user's response. Do NOT call mist_init until they approve the layout."),o.join(`
1785
1785
  `)}function Cn(t){return $e(ir(),".mistflow","mockup-state",`${t}.json`)}function fa(t){let e=Cn(t);if(!eo(e))return null;try{return JSON.parse(Pn(e,"utf-8"))}catch{return null}}function Sn(t,e){let r=$e(ir(),".mistflow","mockup-state");Tn(r,{recursive:!0}),pa(Cn(t),JSON.stringify(e,null,2))}var ya=Ct.object({planId:Ct.string().min(1).describe("Plan ID from mist_plan. Required."),projectPath:Ct.string().optional().describe("Project directory (default: cwd). The mockup is written to <projectPath>/.mistflow/mockups/."),feedback:Ct.string().optional().describe("User feedback to apply to the next iteration."),approved:Ct.boolean().optional().describe("Mark the wireframe as approved (terminal \u2014 unlocks scaffolding).")}).refine(t=>!(t.feedback&&t.approved),{message:"Pass either 'feedback' or 'approved' \u2014 not both. Feedback iterates the design; approved locks it in."}),An={name:"mist_mockup",description:Nr,inputSchema:ya,handler:async t=>{let e=t,{planId:r,feedback:o,approved:s}=e,i=ua(e.projectPath??process.cwd()),n=$e(ir(),".mistflow","plans",`${r}.json`);if(!eo(n))return c(`Plan not found for planId '${r}'. Call mist_plan to generate a plan first.`,!0);let a;try{a=JSON.parse(Pn(n,"utf-8"))}catch{return c("Failed to read plan file. Call mist_plan again.",!0)}let l=a.plan;if(!l)return c("Plan data is empty. Call mist_plan again.",!0);let d=fa(r);d||(d={planId:r,iterationCount:0,approved:!1,screens:[],feedback:[]});let h=$e(i,".mistflow","mockups");Tn(h,{recursive:!0});let m=`mockup-${r}.html`,p=$e(h,m);if(s){d.approved=!0,Sn(r,d);let T=eo(h)?In(h).filter(A=>A.endsWith(".html")).map(A=>$e(".mistflow","mockups",A)):[];return c(JSON.stringify({status:"approved",message:`Wireframe approved after ${d.iterationCount} iteration(s). Layout direction is locked in.`,mockupFiles:T,nextAction:`Call mist_init with planId='${r}' and path='<absolute project path>' to scaffold the project. Mockups in .mistflow/mockups/ will be used as layout reference during implementation.`}))}d.iterationCount++,o&&d.feedback.push(o);let y=ha(l);d.screens=y.screens.map(T=>T.name),Sn(r,d);let x=ga(y,o??void 0,p),b=d.iterationCount>=3?"The wireframe is shaping up \u2014 want to keep refining the layout, or start building?":void 0,f=o?`Apply the user's feedback to ${p}. Rewrite the file, open it for review, then ask if they want more changes or are ready to build.`:`Generate the wireframe HTML following the wireframePrompt, write it to ${p}, then open it in the browser. Ask the user if the layout feels right.`;return c(JSON.stringify({status:"wireframe",iterationCount:d.iterationCount,screens:y.screens.map(T=>({name:T.name,type:T.type,route:T.route})),wireframePrompt:x,designDirection:y.designDirection,...b?{nudge:b}:{},mockupFile:m,mockupPath:p,nextAction:f}))}};function _n(t){let e=$e(t,".mistflow","mockups");return eo(e)?In(e).filter(r=>r.endsWith(".html")).map(r=>$e(e,r)):[]}import{z as ar}from"zod";import{resolve as ba}from"path";import{spawn as wa}from"child_process";function to(t){let e=[],r=/([^\s(]+)\((\d+),(\d+)\):\s*error\s+(TS\d+):\s*(.+)/g;for(let a of t.matchAll(r)){let[,l,d,h,m,p]=a;e.push({file:l,line:parseInt(d,10),column:parseInt(h,10),message:`${m}: ${p}`,humanMessage:`There is a type error in ${l} on line ${d}: ${p}`,suggestion:`Check line ${d} in ${l}. ${m==="TS2345"?"The types of the arguments do not match.":`Fix the ${m} error.`}`})}let o=/(?:Error:\s*)?\.\/([^\s:]+):(\d+):(\d+)\s*\n\s*(.+)/g;for(let a of t.matchAll(o)){let[,l,d,h,m]=a;e.some(p=>p.file===l&&p.line===parseInt(d,10))||e.push({file:l,line:parseInt(d,10),column:parseInt(h,10),message:m,humanMessage:`There is an error in ${l} on line ${d}: ${m.trim()}`,suggestion:`Check line ${d} in ${l} and fix the issue.`})}let s=/Module not found:\s*(?:Error:\s*)?Can't resolve ['"]([^'"]+)['"]\s*(?:in\s*['"]?([^'"]+)['"]?)?/g;for(let a of t.matchAll(s)){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(let a of t.matchAll(i)){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 n=/SyntaxError:\s*([^\s:]+):\s*(.+?)\s*\((\d+):(\d+)\)/g;for(let a of t.matchAll(n)){let[,l,d,h,m]=a;e.some(p=>p.file===l&&p.line===parseInt(h,10))||e.push({file:l,line:parseInt(h,10),column:parseInt(m,10),message:`SyntaxError: ${d}`,humanMessage:`There is a syntax error in ${l} on line ${h}.`,suggestion:`Check line ${h} in ${l} for a missing closing bracket or unexpected token.`})}return e}var va=ar.object({projectPath:ar.string().optional().describe("Absolute path to the project directory. Defaults to cwd."),buildOutput:ar.string().optional().describe("Build output to parse. If omitted, the tool runs `npm run build` in projectPath.")});function ka(t){return new Promise(e=>{let r=wa("npm",["run","build"],{cwd:t,stdio:["ignore","pipe","pipe"]}),o="";r.stdout?.on("data",s=>{o+=s.toString()}),r.stderr?.on("data",s=>{o+=s.toString()}),r.on("error",s=>{e({exitCode:127,combined:`${o}
1786
- ${s.message}`})}),r.on("close",s=>{e({exitCode:s??1,combined:o})})})}var Rn={name:"mist_debug",description:Er,inputSchema:va,handler:async t=>{let e=t,r=ba(e.projectPath??process.cwd()),o=e.buildOutput??"";if(!e.buildOutput){let n=await ka(r);if(n.exitCode===0)return c(JSON.stringify({errors:[],rawOutput:"",message:"Build succeeded with no errors."}));o=n.combined}let s=to(o),i=o.slice(0,2e3);return s.length===0?c(JSON.stringify({errors:s,rawOutput:i,message:"Build output could not be parsed into structured errors. See rawOutput for the first 2KB."})):c(JSON.stringify({errors:s,rawOutput:i,message:`Found ${s.length} error${s.length===1?"":"s"} in the build output.`}))}};import{z as C}from"zod";import{existsSync as At,mkdirSync as no,readFileSync as Mn,readdirSync as Ma,statSync as La,unlinkSync as Ua,writeFileSync as so}from"fs";import{dirname as $a,isAbsolute as Fa,join as de}from"path";import{homedir as Fe}from"os";import{createHash as qa,createHmac as Ln,randomBytes as Ba,randomUUID as On,timingSafeEqual as za}from"crypto";me();function oo(t,e,r,o=3e3){if(e===void 0)return{stop:()=>{}};let s=0,i=!1,a=setInterval(()=>{i||(s++,t.notification({method:"notifications/progress",params:{progressToken:e,progress:s,message:r()}}).catch(()=>{}))},o);return{stop:()=>{i||(i=!0,clearInterval(a))}}}function xa(t){try{return!!t.getClientCapabilities()?.elicitation}catch{return!1}}function Sa(){let t=(process.env.MISTFLOW_ELICITATION??"").toLowerCase().trim();return t==="off"||t==="false"||t==="0"||t==="disabled"}function Ta(t){let e=t.replace(/[^a-zA-Z0-9_]/g,"_");return/^[a-zA-Z_]/.test(e)?e:`_${e}`}function Pa(t){let e={},r=[],o=[],s=new Set;for(let i=0;i<t.length;i++){let n=t[i],a=n.decisionKey?Ta(n.decisionKey):`q_${i+1}`,l=a,d=2;for(;s.has(l);)l=`${a}_${d}`,d++;s.add(l);let h=`${l}_other`;s.add(h),o.push({primary:l,other:h,question:n});let m=(n.options??[]).map(y=>typeof y=="string"?y:y.label),p=[...m,"Other (specify in the 'Other' field below)"];e[l]={type:"string",title:n.question,description:n.why?`${n.why}${n.recommended?`
1787
- Recommended: ${n.recommended}`:""}`:n.recommended?`Recommended: ${n.recommended}`:void 0,enum:p,enumNames:p,...n.recommended&&m.includes(n.recommended)?{default:n.recommended}:{}},r.push(l),e[h]={type:"string",title:"If 'Other' selected above: type your answer",description:"Leave blank if you picked an option from the list."}}return{schema:{type:"object",properties:e,required:r},fieldKeys:o}}function Ia(t,e){let r=[],o;for(let{primary:s,other:i,question:n}of e){let a=String(t[s]??"").trim(),l=String(t[i]??"").trim(),d=a.toLowerCase().startsWith("other"),h;l?h=l:d?h=n.recommended??(n.options?.[0]&&typeof n.options[0]=="object"?n.options[0].label:"")??a:h=a;let m=n.decisionKey??"";if(m==="urlChoice"){o=h;continue}r.push({question:n.question,decisionKey:m,answer:h})}return{answers:r,urlChoice:o}}async function lr(t,e,r){if(Sa())return{outcome:"unsupported"};if(!xa(t))return{outcome:"unsupported"};if(e.length===0)return{outcome:"submitted",answers:[]};let{schema:o,fieldKeys:s}=Pa(e),i;try{i=await t.elicitInput({message:r,requestedSchema:o,mode:"form"},{timeout:300*1e3})}catch(l){let d=l instanceof Error?l.message:String(l);return d.toLowerCase().includes("not support")?{outcome:"unsupported"}:{outcome:"error",errorMessage:d}}if(i.action==="decline")return{outcome:"declined"};if(i.action==="cancel")return{outcome:"cancelled"};if(i.action!=="accept"||!i.content)return{outcome:"error",errorMessage:`Unexpected elicitation result: ${i.action}`};let{answers:n,urlChoice:a}=Ia(i.content,s);return{outcome:"submitted",answers:n,urlChoice:a}}var Ca=[{name:"Dashboard",description:"Overview with key stats and today's activity",condition:t=>t.surfaceType==="internal-tool"||t.surfaceType==="customer-app",keywords:/\b(dashboard|overview|home.?page|stats)\b/i},{name:"Landing Page",description:"Public page explaining what this does",condition:t=>t.publicLanding===!0,keywords:/\b(landing|marketing|hero|homepage)\b/i},{name:"Scheduling / Booking",description:"Calendar, time slots, reservations",condition:t=>t.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:t=>t.multiRole===!0||t.primaryActor==="both",keywords:/\b(admin|panel|manage.?user|moderat)\b/i},{name:"User Profiles",description:"Account pages, settings, preferences",condition:t=>t.primaryActor==="customers"||t.primaryActor==="both",keywords:/\b(profile|account|settings|preferences)\b/i},{name:"Search / Browse",description:"Find and filter content or listings",condition:t=>t.surfaceType==="marketplace",keywords:/\b(search|browse|filter|discover|explore)\b/i},{name:"Email Notifications",description:"Welcome emails, alerts, reminders",condition:t=>t.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:t=>t.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:t=>t.integrations?.includes("ai")===!0,keywords:/\b(ai|chatbot|gpt|llm|generat|assistant)\b/i},{name:"Maps / Location",description:"Google Maps, location search, geolocation",condition:t=>t.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:t=>t.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:t=>t.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:t=>t.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:t=>t.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 En(t,e,r){let o=r?.suggestedName||Aa(t),s=e.primaryActor==="both"?"Staff + Customers":e.primaryActor==="staff"?"Staff / Admin":e.primaryActor==="customers"?"End Users":"Users",i=e.audienceType??(e.surfaceType==="internal-tool"?"internal":(e.primaryActor==="customers"||e.primaryActor==="both","b2c")),n=e.surfaceType==="internal-tool"?"Internal tool":e.surfaceType==="marketplace"?"Marketplace":e.surfaceType==="content-site"?"Content site":e.surfaceType==="game"?"Game":"App",a;if(r?.suggestedFeatures&&r.suggestedFeatures.length>0)a=r.suggestedFeatures.map(l=>({name:l.name,description:l.description,checked:l.recommended,source:l.recommended?"explicit":"suggested"}));else{let l=`${t} ${e.primaryAction||""}`;a=[];for(let d of Ca){let h=d.keywords.test(l),m=d.condition(e);(h||m)&&a.push({name:d.name,description:d.description,checked:h,source:h?"explicit":"suggested"})}}return{name:o,audience:s,audienceType:i,surfaceType:n,primaryAction:e.primaryAction||"manage items",features:a,publicLanding:e.publicLanding??!0,authModel:e.authModel??"email",dbProvider:e.dbProvider??"neon",integrations:e.integrations??[],language:r?.language||"English"}}function Nn(t){let e=t.features.filter(a=>a.checked),r=t.features.filter(a=>!a.checked),o={email:"Email sign-up",none:"No login (public)",social:"Social login","invite-only":"Invite-only"},s={neon:"Postgres",turso:"SQLite (legacy)"},i={b2c:"Your customers use this app (business-to-customer)",b2b:"Other businesses sign up for this (SaaS platform)",internal:"Internal team tool (staff only)"},n=[`**${t.name}** \u2014 ${t.surfaceType} for ${t.audience}`,`Audience: ${i[t.audienceType]??t.audienceType}`,`Primary action: ${t.primaryAction}`,`Access: ${o[t.authModel]??t.authModel} | Database: ${s[t.dbProvider]??t.dbProvider}${t.publicLanding?" | Landing page: Yes":""}${t.language&&t.language!=="English"?` | Language: ${t.language}`:""}`,""];if(e.length>0){n.push("**Included:**");for(let a of e)n.push(` \u2713 ${a.name} \u2014 ${a.description}`)}if(t.integrations.length>0&&(n.push(""),n.push(`**Integrations:** ${t.integrations.join(", ")}`)),r.length>0){n.push(""),n.push("**Available to add:**");for(let a of r)n.push(` \u25CB ${a.name} \u2014 ${a.description}`)}return n.join(`
1786
+ ${s.message}`})}),r.on("close",s=>{e({exitCode:s??1,combined:o})})})}var Rn={name:"mist_debug",description:Er,inputSchema:va,handler:async t=>{let e=t,r=ba(e.projectPath??process.cwd()),o=e.buildOutput??"";if(!e.buildOutput){let n=await ka(r);if(n.exitCode===0)return c(JSON.stringify({errors:[],rawOutput:"",message:"Build succeeded with no errors."}));o=n.combined}let s=to(o),i=o.slice(0,2e3);return s.length===0?c(JSON.stringify({errors:s,rawOutput:i,message:"Build output could not be parsed into structured errors. See rawOutput for the first 2KB."})):c(JSON.stringify({errors:s,rawOutput:i,message:`Found ${s.length} error${s.length===1?"":"s"} in the build output.`}))}};import{z as C}from"zod";import{existsSync as At,mkdirSync as no,readFileSync as Mn,readdirSync as Ma,statSync as La,unlinkSync as Ua,writeFileSync as so}from"fs";import{dirname as $a,isAbsolute as Fa,join as de}from"path";import{homedir as Fe}from"os";import{createHash as qa,createHmac as Ln,randomBytes as Ba,randomUUID as On,timingSafeEqual as za}from"crypto";me();function oo(t,e,r,o=3e3){if(e===void 0)return{stop:()=>{}};let s=0,i=!1,a=setInterval(()=>{i||(s++,t.notification({method:"notifications/progress",params:{progressToken:e,progress:s,message:r()}}).catch(()=>{}))},o);return{stop:()=>{i||(i=!0,clearInterval(a))}}}function xa(t){try{return!!t.getClientCapabilities()?.elicitation}catch{return!1}}function Sa(){let t=(process.env.MISTFLOW_ELICITATION??"").toLowerCase().trim();return t==="off"||t==="false"||t==="0"||t==="disabled"}function Ta(t){let e=t.replace(/[^a-zA-Z0-9_]/g,"_");return/^[a-zA-Z_]/.test(e)?e:`_${e}`}function Pa(t){let e={},r=[],o=[],s=new Set;for(let i=0;i<t.length;i++){let n=t[i],a=n.decisionKey?Ta(n.decisionKey):`q_${i+1}`,l=a,d=2;for(;s.has(l);)l=`${a}_${d}`,d++;s.add(l);let h=n.freetext?"":`${l}_other`;if(h&&s.add(h),o.push({primary:l,other:h,question:n}),n.freetext){e[l]={type:"string",title:n.question,description:n.why,...n.recommended?{default:n.recommended}:{}},r.push(l);continue}let m=(n.options??[]).map(y=>typeof y=="string"?y:y.label),p=[...m,"Other (specify in the 'Other' field below)"];e[l]={type:"string",title:n.question,description:n.why?`${n.why}${n.recommended?`
1787
+ Recommended: ${n.recommended}`:""}`:n.recommended?`Recommended: ${n.recommended}`:void 0,enum:p,enumNames:p,...n.recommended&&m.includes(n.recommended)?{default:n.recommended}:{}},r.push(l),e[h]={type:"string",title:"If 'Other' selected above: type your answer",description:"Leave blank if you picked an option from the list."}}return{schema:{type:"object",properties:e,required:r},fieldKeys:o}}function Ia(t,e){let r=[],o;for(let{primary:s,other:i,question:n}of e){let a=String(t[s]??"").trim(),l;if(n.freetext)l=a||n.recommended||"";else{let h=i?String(t[i]??"").trim():"",m=a.toLowerCase().startsWith("other");h?l=h:m?l=n.recommended??(n.options?.[0]&&typeof n.options[0]=="object"?n.options[0].label:"")??a:l=a}let d=n.decisionKey??"";if(d==="urlChoice"){o=l;continue}r.push({question:n.question,decisionKey:d,answer:l})}return{answers:r,urlChoice:o}}async function lr(t,e,r){if(Sa())return{outcome:"unsupported"};if(!xa(t))return{outcome:"unsupported"};if(e.length===0)return{outcome:"submitted",answers:[]};let{schema:o,fieldKeys:s}=Pa(e),i;try{i=await t.elicitInput({message:r,requestedSchema:o,mode:"form"},{timeout:300*1e3})}catch(l){let d=l instanceof Error?l.message:String(l);return d.toLowerCase().includes("not support")?{outcome:"unsupported"}:{outcome:"error",errorMessage:d}}if(i.action==="decline")return{outcome:"declined"};if(i.action==="cancel")return{outcome:"cancelled"};if(i.action!=="accept"||!i.content)return{outcome:"error",errorMessage:`Unexpected elicitation result: ${i.action}`};let{answers:n,urlChoice:a}=Ia(i.content,s);return{outcome:"submitted",answers:n,urlChoice:a}}var Ca=[{name:"Dashboard",description:"Overview with key stats and today's activity",condition:t=>t.surfaceType==="internal-tool"||t.surfaceType==="customer-app",keywords:/\b(dashboard|overview|home.?page|stats)\b/i},{name:"Landing Page",description:"Public page explaining what this does",condition:t=>t.publicLanding===!0,keywords:/\b(landing|marketing|hero|homepage)\b/i},{name:"Scheduling / Booking",description:"Calendar, time slots, reservations",condition:t=>t.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:t=>t.multiRole===!0||t.primaryActor==="both",keywords:/\b(admin|panel|manage.?user|moderat)\b/i},{name:"User Profiles",description:"Account pages, settings, preferences",condition:t=>t.primaryActor==="customers"||t.primaryActor==="both",keywords:/\b(profile|account|settings|preferences)\b/i},{name:"Search / Browse",description:"Find and filter content or listings",condition:t=>t.surfaceType==="marketplace",keywords:/\b(search|browse|filter|discover|explore)\b/i},{name:"Email Notifications",description:"Welcome emails, alerts, reminders",condition:t=>t.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:t=>t.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:t=>t.integrations?.includes("ai")===!0,keywords:/\b(ai|chatbot|gpt|llm|generat|assistant)\b/i},{name:"Maps / Location",description:"Google Maps, location search, geolocation",condition:t=>t.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:t=>t.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:t=>t.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:t=>t.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:t=>t.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 En(t,e,r){let o=r?.suggestedName||Aa(t),s=e.primaryActor==="both"?"Staff + Customers":e.primaryActor==="staff"?"Staff / Admin":e.primaryActor==="customers"?"End Users":"Users",i=e.audienceType??(e.surfaceType==="internal-tool"?"internal":(e.primaryActor==="customers"||e.primaryActor==="both","b2c")),n=e.surfaceType==="internal-tool"?"Internal tool":e.surfaceType==="marketplace"?"Marketplace":e.surfaceType==="content-site"?"Content site":e.surfaceType==="game"?"Game":"App",a;if(r?.suggestedFeatures&&r.suggestedFeatures.length>0)a=r.suggestedFeatures.map(l=>({name:l.name,description:l.description,checked:l.recommended,source:l.recommended?"explicit":"suggested"}));else{let l=`${t} ${e.primaryAction||""}`;a=[];for(let d of Ca){let h=d.keywords.test(l),m=d.condition(e);(h||m)&&a.push({name:d.name,description:d.description,checked:h,source:h?"explicit":"suggested"})}}return{name:o,audience:s,audienceType:i,surfaceType:n,primaryAction:e.primaryAction||"manage items",features:a,publicLanding:e.publicLanding??!0,authModel:e.authModel??"email",dbProvider:e.dbProvider??"neon",integrations:e.integrations??[],language:r?.language||"English"}}function Nn(t){let e=t.features.filter(a=>a.checked),r=t.features.filter(a=>!a.checked),o={email:"Email sign-up",none:"No login (public)",social:"Social login","invite-only":"Invite-only"},s={neon:"Postgres",turso:"SQLite (legacy)"},i={b2c:"Your customers use this app (business-to-customer)",b2b:"Other businesses sign up for this (SaaS platform)",internal:"Internal team tool (staff only)"},n=[`**${t.name}** \u2014 ${t.surfaceType} for ${t.audience}`,`Audience: ${i[t.audienceType]??t.audienceType}`,`Primary action: ${t.primaryAction}`,`Access: ${o[t.authModel]??t.authModel} | Database: ${s[t.dbProvider]??t.dbProvider}${t.publicLanding?" | Landing page: Yes":""}${t.language&&t.language!=="English"?` | Language: ${t.language}`:""}`,""];if(e.length>0){n.push("**Included:**");for(let a of e)n.push(` \u2713 ${a.name} \u2014 ${a.description}`)}if(t.integrations.length>0&&(n.push(""),n.push(`**Integrations:** ${t.integrations.join(", ")}`)),r.length>0){n.push(""),n.push("**Available to add:**");for(let a of r)n.push(` \u25CB ${a.name} \u2014 ${a.description}`)}return n.join(`
1788
1788
  `)}function Aa(t){let e=t.match(/\b(?:called|named)\s+["']?([A-Za-z][A-Za-z0-9 ]{1,30})["']?/i);if(e)return cr(e[1]);let r=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"]),s=t.toLowerCase().replace(/[^a-z0-9\s]/g,"").split(/\s+/).filter(i=>i.length>2&&!r.has(i)).slice(0,3);return s.length===0?"my-app":s.join("-")}function cr(t){return t.toLowerCase().replace(/[^a-z0-9\s]/g,"").trim().replace(/\s+/g,"-")}var _a=["typographic","split-panel","terminal","full-bleed-photo","magazine-hero"],Ra=["sharp","soft","pill","organic"],Ea=["flat","paper-grain","film-grain","scanlines","gradient-mesh","noise","glassmorphic"];function dr(t,e,r){return e.includes(t)?t:r}function ce(t){return String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function pt(t,e){return typeof t!="string"?e:/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/.test(t.trim())?t.trim():e}function Na(t){let e=new Set;for(let o of t)o.fonts?.display&&e.add(o.fonts.display),o.fonts?.body&&e.add(o.fonts.body);return e.size===0?"":`https://fonts.googleapis.com/css2?${[...e].map(o=>`family=${o.trim().replace(/\s+/g,"+").replace(/[^A-Za-z0-9+]/g,"")}:wght@400;700`).join("&")}&display=swap`}function Dn(t){let e=(t||"").trim(),r=e.toLowerCase(),o=/mono|courier|code/.test(r)?"ui-monospace, monospace":/serif|garamond|bodoni|fraunces|playfair|lora|sentient|migra|sectra|cormorant|abril|crimson/.test(r)?"Georgia, serif":"system-ui, sans-serif";return e?`"${e.replace(/"/g,"")}", ${o}`:o}function Da(t){switch(t){case"sharp":return{card:"0px",button:"0px",chip:"0px"};case"pill":return{card:"20px",button:"999px",chip:"999px"};case"organic":return{card:"4px 24px 4px 24px",button:"24px 4px 24px 4px",chip:"12px 2px 12px 2px"};default:return{card:"10px",button:"8px",chip:"6px"}}}function ja(){let t=`url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.3 0 0 0 0 0.3 0 0 0 0 0.3 0 0 0 0.55 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>")`;return`
1789
1789
  .card-hero { position: relative; overflow: hidden; isolation: isolate; }
1790
1790
  .card-hero::before {
@@ -2232,7 +2232,7 @@ ${o}
2232
2232
  `)}))}else return c(JSON.stringify({status:"confirm_new_project",projectPath:o,description:R,confirmToken:k,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.",b?"The previous confirmToken was invalid, expired, or did not match the current directory/description. Use the fresh token above.":""].filter(Boolean).join(`
2233
2233
  `)}))}L="Note: You're inside an existing project. Mistflow will create the new app in a subdirectory. It won't modify this codebase."}else u==="foreign"&&x&&(L="Note: You're inside an existing project. Mistflow will create the new app in a subdirectory. It won't modify this codebase.")}if(l)try{if(!(await Ko(l)).plan)return c("This template has no plan to fork. Try a different template.",!0);let g=await Jo(l),k=g.plan,S="";if(d&&g.has_source)try{let ne=await Wt(g.plan,d),B=ne.plan??ne,Ot=ne.diff,wo=B?.steps??[],V=new Set([...(Ot?.added??[]).map(z=>z.number),...(Ot?.modified??[]).map(z=>z.number)]),ue=wo.map(z=>{let Xe=z.number;return V.has(Xe)?{...z,status:"pending"}:{...z,status:"completed",source:"forked"}});B.steps=ue,k=B;let Pe=ue.filter(z=>z.status==="pending").length;S=` Remixed: ${ue.filter(z=>z.status==="completed").length} steps unchanged, ${Pe} steps need re-implementation.`}catch(ne){console.error("[plan] Remix failed, using original plan:",ne),S=" (Remix failed \u2014 using original plan. You can modify it later.)"}let Q=On(),J=de(Fe(),".mistflow","plans");no(J,{recursive:!0}),so(de(J,`${Q}.json`),JSON.stringify({plan:k,projectId:g.id,sourceDeploymentId:g.source_deployment_id,forkToken:g.fork_token,requiredEnvVars:g.required_env_vars,dbProvider:g.db_provider}));let re=k?.name??"forked-app",ie=g.has_source,ft=ie?"Source code will be restored during init. Run init promptly \u2014 the download token expires in 1 hour.":"",Ge=g.deploy_url?` Instant deploy started \u2014 your app will be live at ${g.deploy_url} in under a minute.`:"";return c(JSON.stringify({planId:Q,forkedFrom:g.forked_from,projectId:g.id,hasSource:ie,deployUrl:g.deploy_url,message:`Forked "${g.forked_from}" into your workspace.${S}${Ge} ${ft} NEXT: Call mist_init, name='${re}', and planId='${Q}' to create the project now.`}))}catch(u){let g=u instanceof Error?u.message:"Failed to fork template";return c(g,!0)}if(P){let u;try{u=await Wt(P,R)}catch(J){let re=J instanceof Error?J.message:"Failed to modify plan";return c(re,!0)}let g=u.plan,k=u.diff,S=[];if(k?.added?.length){let J=k.added.map(re=>re.title);S.push(`Added ${J.length} step(s): ${J.join(", ")}`)}if(k?.removed?.length){let J=k.removed.map(re=>re.title);S.push(`Removed ${J.length} step(s): ${J.join(", ")}`)}if(k?.modified?.length){let J=k.modified.map(re=>re.title);S.push(`Modified ${J.length} step(s): ${J.join(", ")}`)}let Q=S.length>0?S.join(". "):"No changes detected.";return c(JSON.stringify({plan:g,diff:k,message:`Plan modified. ${Q}. Update mistflow.json with the new plan, then continue with mist_implement.`}))}let v=f?.trim()||void 0,M=i;if(Array.isArray(i)){let u=i.findIndex(g=>g&&typeof g=="object"&&g.decisionKey==="urlChoice");if(u>=0){let g=i[u];!v&&g.answer&&(v=g.answer);let k=i.slice(0,u).concat(i.slice(u+1));M=k.length>0?k:void 0}}else if(i!=null){let u=i;if(!v&&ro in u&&(v=u[ro]),!v&&"urlChoice"in u&&(v=u.urlChoice),ro in u||"urlChoice"in u){let{[ro]:g,urlChoice:k,...S}=u;M=Object.keys(S).length>0?S:void 0}}if(v&&(v=v.replace(/^Keep\s+/i,"").replace(/\s*\(Recommended\)\s*$/i,"").replace(/\.mistflow\.app.*$/i,"").trim()||void 0),v){let u=v.toLowerCase().replace(/\s+/g,"-");/^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/.test(u)?v=u:(console.error(`[mist_plan] Discarding urlChoice '${v}' \u2014 does not look like a subdomain. Backend will auto-generate.`),v=void 0)}let W;if(A){W={...A};let u={fontsHint:"fonts_hint",colorMood:"color_mood",heroHeadline:"hero_headline",ctaText:"cta_text",bodySample:"body_sample",heroTreatment:"hero_treatment",shapeLang:"shape_lang",decorationHint:"decoration_hint"};for(let[g,k]of Object.entries(u))A[g]!==void 0&&W[k]===void 0&&(W[k]=A[g])}let G=i?"Generating plan with your answers (LLM call)":T?"Finalizing design direction":"Thinking through discovery questions",X=e?oo(e.server,e.progressToken,()=>G):{stop:()=>{}};e&&(e.cleanup=()=>X.stop());let _;try{j&&!M&&!T&&!P&&!a?_=await zt(j):_=await Ht(R,{conversationId:j,answers:M,autonomous:h,language:m,designConversationId:T,designDirection:W})}catch(u){X.stop();let g=u instanceof Error?u.message:"Failed to generate plan";return c(g,!0)}if(_.status==="clarify_pending"){X.stop();let u=_;return c(JSON.stringify({status:"running",conversationId:u.conversation_id,phase:"generating_questions",nextAction:`Discovery questions are generating. Call mist_plan with { projectPath, conversationId: "${u.conversation_id}" } IMMEDIATELY \u2014 do NOT run bash sleep between polls. The server holds each poll open up to ~10s and returns as soon as questions land. Do NOT re-send description or answers.`}))}if(_.status==="plan_pending"){X.stop();let u=_;return c(JSON.stringify({status:"running",conversationId:u.conversation_id,phase:"generating_plan",nextAction:`Plan is being generated (build_plan + image enrichment, 30-60s typical). Call mist_plan with { projectPath, conversationId: "${u.conversation_id}" } IMMEDIATELY \u2014 do NOT run bash sleep between polls. The server holds each poll open up to ~10s and returns as soon as the plan lands. Do NOT re-send answers.`}))}if(_.status==="design_clarify_pending"&&(G="Generating creative design directions",_=await Xa(_)),X.stop(),_.status==="clarify"){let u=_.reflection||"",g=_.suggestedName||"",k=_.suggestedFeatures??[],S=_.questions??[],Q=S.some(V=>Array.isArray(V.options)&&typeof V.options[0]=="object"&&V.options[0]?.label),J={primaryActor:"Users",primaryAction:"Core action",surfaceType:"App type",audienceType:"Audience",multiRole:"Roles",publicLanding:"Landing page",realMoney:"Payments",scheduling:"Scheduling",authModel:"Access",dbProvider:"Database",integrations:"Integration",entityShape:"Item shape",coreView:"View",scope:"Scope",sharing:"Sharing",workflow:"Workflow",constraints:"Constraints",domain:"Product"},re=S.map(V=>{let ue=V.decisionKey&&J[V.decisionKey]||Ya(V.question),Pe;return Q&&Array.isArray(V.options)?Pe=V.options.map(ae=>({label:ae.label,description:ae.description??""})):Array.isArray(V.options)?Pe=V.options.map((ae,z)=>({label:z===0?`${ae} (Recommended)`:String(ae),description:V.why??""})):Pe=[{label:"Yes (Recommended)",description:V.why??""},{label:"No",description:""}],{question:V.question,header:ue,options:Pe,multiSelect:!1}}),ft=_.decisions?.audienceType??null,Ge=k.length>0?En(R,{primaryActor:null,primaryAction:null,surfaceType:null,audienceType:ft,multiRole:null,publicLanding:null,realMoney:null,scheduling:null,authModel:null,dbProvider:null,integrations:null},{suggestedName:g,suggestedFeatures:k,language:m}):null,ne=Ge?Nn(Ge):"",B=cr(g||"my-app").slice(0,32);try{let V=await Eo(B);!V.available&&V.suggestion&&(B=V.suggestion)}catch{}ne&&(ne+=`
2234
2234
 
2235
- **Your app URL:** https://${B}.mistflow.app`);let Ot={question:`Your app will be at ${B}.mistflow.app \u2014 want to customize the URL?`,decisionKey:"urlChoice",recommended:`Keep ${B}.mistflow.app`,why:"This URL matches your app name and is available. You can customize it now \u2014 subdomains are locked in at scaffold time.",options:[{label:`Keep ${B}.mistflow.app`,description:"This URL is available"},{label:"Choose a different URL",description:"Type your preferred subdomain"}]};S.push(Ot);let wo={question:`Your app will be at ${B}.mistflow.app \u2014 want to customize the URL?`,header:"URL",options:[{label:`Keep ${B}.mistflow.app (Recommended)`,description:"This URL is available"},{label:"Choose a different URL",description:"Type your preferred subdomain"}],multiSelect:!1};if(re.push(wo),e?.server){let V=[g?`## ${g}`:"## Pick a few details","",`${S.length} quick question${S.length===1?"":"s"} to pin down the build.`,"Pick from each dropdown \u2014 or pick `Other` and type your own answer below it."].join(`
2235
+ **Your app URL:** https://${B}.mistflow.app`);let Ot={question:"Your app URL \u2014 keep the suggested subdomain or type your own",decisionKey:"urlChoice",freetext:!0,recommended:B,why:`Your app will be at <subdomain>.mistflow.app. Subdomains are locked at scaffold time. Keep '${B}' or type your preferred subdomain (lowercase, alphanumeric + hyphens, 3-32 chars).`,options:[{label:`Keep ${B}.mistflow.app`,description:"This URL is available"},{label:"Choose a different URL",description:"Type your preferred subdomain"}]};S.push(Ot);let wo={question:`Your app will be at ${B}.mistflow.app \u2014 want to customize the URL?`,header:"URL",options:[{label:`Keep ${B}.mistflow.app (Recommended)`,description:"This URL is available"},{label:"Choose a different URL",description:"Type your preferred subdomain"}],multiSelect:!1};if(re.push(wo),e?.server){let V=[g?`## ${g}`:"## Pick a few details","",`${S.length} quick question${S.length===1?"":"s"} to pin down the build.`,"Pick from each dropdown \u2014 or pick `Other` and type your own answer below it."].join(`
2236
2236
  `),ue=await lr(e.server,S,V);if(ue.outcome==="submitted"){X.stop();let Pe={};for(let z of ue.answers??[])z.decisionKey?Pe[z.decisionKey]=z.answer:Pe[z.question]=z.answer;let ae=ue.urlChoice?.trim();ae&&(ae=ae.replace(/^Keep\s+/i,"").replace(/\s*\(Recommended\)\s*$/i,"").replace(/\.mistflow\.app.*$/i,"").trim()||void 0);try{let z=await Ht(R,{conversationId:_.conversation_id,answers:Pe,autonomous:h,language:m});if(z.status==="plan_pending"){let Xe=z;return c(JSON.stringify({status:"running",conversationId:Xe.conversation_id,phase:"generating_plan",...ae?{urlChoice:ae}:{},nextAction:`User answered via the native form. Plan is generating now (30-60s typical). Call mist_plan with { projectPath, conversationId: "${Xe.conversation_id}"${ae?`, urlChoice: "${ae}"`:""} } IMMEDIATELY \u2014 do NOT run bash sleep between polls. The server holds each poll up to ~10s and returns when the plan lands. Pass urlChoice on every poll so it threads through to the saved plan.`}))}_=z}catch(z){let Xe=z instanceof Error?z.message:String(z);return c(`Submitting your answers failed: ${Xe}. Please retry by calling mist_plan with the same conversationId and answers.`,!0)}}else{if(ue.outcome==="declined")return X.stop(),c("User declined the planning flow via the form. They likely want a different approach \u2014 ask them what they'd prefer instead of re-running mist_plan.",!0);if(ue.outcome==="cancelled")return X.stop(),c("User cancelled the planning form without picking. The conversation is still alive \u2014 re-run mist_plan with the same conversationId if they want to retry, or start a fresh plan if they want to change the description.",!0);ue.outcome==="error"&&console.error(`[mist_plan] Elicitation failed (${ue.errorMessage}) \u2014 falling back to prose flow.`)}}return c(JSON.stringify({status:"clarify",nextAction:"STOP \u2014 DO NOT submit answers yourself. Render every entry in `askUserQuestions` via your host's native question tool (AskUserQuestion in Claude Code, request_user_input in OpenAI Codex Plan mode, quick pick in Cursor) and WAIT for the user to actually answer. If your host has no native question tool, stop your turn, print the questions verbatim as a numbered list with all options visible, and wait for the user's next message. Calling mist_plan with answers in the same turn you received the questions is ALWAYS wrong, regardless of how obvious `recommended` looks.",conversation_id:_.conversation_id,questions:S,questionCount:S.length,suggestedFeatures:k,suggestedName:g,suggestedSubdomain:B,reflection:u,briefText:ne,askUserQuestions:re,planTimingHint:"After the user answers all questions, generating the actual plan takes about 60-90 seconds (backend LLM). Narrate this explicitly before the next mist_plan call.",instruction:["\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550","STOP. DO NOT CONTINUE UNTIL THE USER ACTUALLY ANSWERS THESE QUESTIONS.","\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550","","You MUST ask the user via your host's native structured-question","tool (not a text prompt, not a bash echo, not a chat message).","The user has to actually choose. You do NOT get to pick the","'recommended' answer on their behalf \u2014 even if it seems obvious,","even if they said 'just build it', even if you are inside /loop","or any autonomous mode. The recommended label is a hint for the","user, not a permission slip for you to decide. Every question is","a real product decision the user is paying to make.","","Per host (use whichever applies):"," \u2022 Claude Code \u2192 AskUserQuestion tool"," \u2022 Cursor \u2192 quick-pick UI"," \u2022 OpenAI Codex (Plan mode) \u2192 request_user_input tool"," \u2022 OpenAI Codex (Default mode) \u2192 request_user_input returns"," 'unavailable in <mode> mode'. When you see that error, STOP"," your turn, print the questions as a numbered chat message"," with all options visible, and wait for the user's next"," message. Do NOT resume by picking answers yourself."," \u2022 Any host without a native question tool \u2192 same as above:"," stop your turn, print the questions, wait.","","What NOT to do (these have all happened in production transcripts","and are unacceptable):"," \u2717 'I'll go with the recommended defaults \u2014 say the word if you"," want to change any before I continue.' (auto-accepting)"," \u2717 'Locking in the defaults with X as the only override.'"," (inferring answers from the original spec)"," \u2717 Printing the questions + options as markdown and inferring"," answers from silence."," \u2717 Calling mist_plan with answers you picked yourself."," \u2717 Skipping the question UI because /loop is active \u2014 in loop,"," stop the loop and wait for the user. The loop will resume.","","How to call the tool (when available): pass each object in the","`askUserQuestions` array below. Each has `question`, `header`,","`options[]` (each option has `label` + `description`), and","`multiSelect`. The tool returns the user's selected labels.","","Before calling mist_plan again with the answers, tell the user:"," 'Generating your plan now. This takes 30\u201360 seconds \u2014 I'm"," writing the data model, page layout, and build steps.'","Then call mist_plan with:",` conversationId: "${_.conversation_id}"`,` answers: { "<question text>": "<the user's selected label>", ... }`,' urlChoice: "<the URL subdomain the user picked>" \u2190 top-level param, NOT inside answers'," (description is no longer needed \u2014 the server has it from the first call)","","Follow-up clarify rounds are normal \u2014 if the user's answers reveal new","ambiguity, you'll get another `clarify` response. Relay those too,","same way, never inferring. Keep going until the response status is","'ready' or 'design_clarify_pending'.","","IMPORTANT: For the URL question, pass the answer as the top-level 'urlChoice' parameter (not inside answers).",`If the user keeps the default, set urlChoice: "${B}".`,'If they type a custom URL, set urlChoice to just the subdomain part (e.g. "myapp" for "myapp.mistflow.app"). Do not include ".mistflow.app" or any "Keep X" label text \u2014 the tool strips those but passing just the subdomain is cleanest.',...u||ne?["","\u2500\u2500\u2500 BACKGROUND (not for you to summarize and proceed \u2014 it's what the user will see when you show them the questions) \u2500\u2500\u2500",...u?[u]:[],...ne?["",ne]:[]]:[],...L?["",L]:[]].join(`
2237
2237
  `)}))}if(_.status==="design_clarify"){let u=_.directions??[],g=_.plan.name??"your app",k;try{let ie=u.map(B=>({id:B.id,name:B.name,summary:B.summary,hero_headline:B.hero_headline,cta_text:B.cta_text,body_sample:B.body_sample,fonts:B.fonts,colors:B.colors,hero_treatment:B.hero_treatment,shape_lang:B.shape_lang,texture:B.texture,decoration_hint:B.decoration_hint})),ft=jn(g,ie),Ge=de(o,".mistflow");no(Ge,{recursive:!0});let ne=de(Ge,"design-directions.html");so(ne,ft,"utf-8"),k=ne}catch(ie){console.error(`[mist_plan] design-directions preview render failed: ${ie instanceof Error?ie.message:String(ie)}`)}let S=u.map(ie=>({label:ie.name,description:`${ie.summary} \u2014 ${ie.fonts?.display??""} + ${ie.fonts?.body??""}`}));S.push({label:"Describe your own direction",description:"Skip the proposed options and give me a short description of how the app should feel."});let Q={question:`${g} is planned. Now pick the creative direction \u2014 this shapes fonts, colors, and overall feel.`,header:"Design",options:S,multiSelect:!1},J=k?[`A visual preview of all ${u.length} directions has been written to:`,` ${k}`,"Each card is rendered in its direction's own fonts + palette so the user can see what they're picking \u2014 the picker is meaningless without it.","","OPEN THE PREVIEW NOW. Pick whichever works in your host:",` \u2022 macOS: run open "${k}"`,` \u2022 Linux: run xdg-open "${k}"`,` \u2022 Windows: run start "" "${k}"`," \u2022 No shell access: tell the user the exact path and ask them to open it in their browser before they answer.",'Do NOT skip the preview. "I described the options in text" is NOT a replacement \u2014 the user needs to SEE the directions.'].join(`
2238
2238
  `):"No visual preview rendered (see server logs). The question options below carry fonts + mood so the user can still pick, but warn them the HTML preview didn't land.",re=k?`open "${k}"`:"";return c(JSON.stringify({status:"design_clarify",designConversationId:_.design_conversation_id,directions:u,previewPath:k,askUserQuestion:Q,instruction:[`The plan for "${g}" is ready. I've proposed ${u.length} creative directions \u2014 each commits to a specific aesthetic (fonts, colors, voice).`,"","\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550","STOP. DO NOT PICK A DIRECTION YOURSELF. THE USER PICKS.","\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550","",J,re?`Run this command to open the preview for the user: ${re}`:"","","Then ASK THE USER which direction they want. Use whichever your host supports:"," \u2022 Claude Code \u2192 AskUserQuestion tool with the directionQuestion payload above"," \u2022 Cursor \u2192 quick-pick UI"," \u2022 OpenAI Codex (Plan mode) \u2192 request_user_input tool"," \u2022 OpenAI Codex (Default mode) OR any host without a native question tool:"," STOP your turn. Print the direction names + one-line summaries as a"," numbered chat message and wait for the user's reply. Do NOT resume.","","What NOT to do (these have all happened in production transcripts and are unacceptable):"," \u2717 'I'll go with a custom ops-focused brief that fits better than the default.'"," (auto-picking a direction the user never chose)"," \u2717 'Submitting a custom design brief now so we can keep moving.'"," \u2717 Calling mist_plan with designDirection: { custom: '<your own description>' }"," because the user didn't respond fast enough."," \u2717 Skipping this picker because you already decided on the design yourself."," \u2717 Opening the HTML preview but not actually asking the user anything.","","Once the user picks a direction, call mist_plan with:",` designConversationId: "${_.design_conversation_id}"`," designDirection: <the full direction object from the 'directions' array that the user picked>","(No description needed \u2014 server has it from the first call.)","","IF the user picks 'Describe your own direction':"," Ask them a short open question ('How should the app feel? Any fonts or colors in mind?'),"," wait for a real answer, then call mist_plan with"," designDirection: { custom: '<their exact words>' } + the same designConversationId.","","The next mist_plan call takes ~10-20s \u2014 that's the LLM generating the final DESIGN.md with the picked direction. Tell the user 'Locking in the direction now \u2014 this takes about 15 seconds.' before calling."].filter(Boolean).join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mistflow-ai/mcp",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Mistflow MCP server for AI coding editors. Installed into Claude Code, Cursor, Codex CLI, and VS Code Copilot by the mistflow-ai installer.",
5
5
  "license": "Elastic-2.0",
6
6
  "type": "module",