@mistflow-ai/mcp 0.4.2 → 0.4.3

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.
Files changed (2) hide show
  1. package/dist/index.js +2 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2112,7 +2112,7 @@ AUTH_SECRET=${W}
2112
2112
  ${H}${z}${_}${ee}`),F(r,".env.example",`${B}
2113
2113
  AUTH_SECRET=your-secret-here
2114
2114
  ${H}${z}${_}${ee}`);let E=[],le=(S,D)=>{E.push({phase:S,message:D})},ce=(S,D)=>{let G=E.find(J=>J.phase===S&&!J.durationMs);G&&(G.durationMs=D)};if(o){let S=Ke(o.server,o.progressToken,()=>E[E.length-1]?.message??"Setting up project...");o.cleanup=()=>S.stop()}let me=b?.requestedSubdomain||void 0,re,k;le("register","Registering project on Mistflow...");let M=Date.now();try{let S=await Vo(e,void 0,"neon",me);re=S.id;let D=Z(r,"mistflow.json"),G=JSON.parse(Ft(D,"utf-8"));if(G.projectId=re,Be(D,JSON.stringify(G,null,2)),co(r,po(re,e)),S.managed_env&&Object.keys(S.managed_env).length>0){let J=Z(r,".env.local"),oe=Ee(J)?Ft(J,"utf-8"):"";for(let[xe,C]of Object.entries(S.managed_env)){let K=new RegExp(`^${xe}=.*$`,"m");K.test(oe)?oe=oe.replace(K,`${xe}=${C}`):oe+=`
2115
- ${xe}=${C}`}Be(J,oe)}try{let{getBaseUrl:J,getAuthHeaders:oe}=await import("./api-client-RCNDMCPS.js"),xe=oe(),C=t?.features,K=t?.steps,ne={};Array.isArray(C)&&C.length>0&&(ne.features=C.map(X=>X.name)),t&&(ne.plan=t),Array.isArray(K)&&K.length>0&&(ne.provenance=K.map(X=>({feature:X.name??X.title??`Step ${X.number??"?"}`,user_intent:(X.description??"").slice(0,500),decisions:"Seeded from plan at init",tradeoffs:"",files_affected:[]}))),Object.keys(ne).length>0&&await fetch(`${J()}/api/projects/${encodeURIComponent(re)}/state`,{method:"PUT",headers:{...xe,"Content-Type":"application/json"},body:JSON.stringify(ne)})}catch{}E[E.length-1].message=`Registered as ${re.slice(0,8)}`}catch(S){let D=S instanceof Error?S.message:String(S);console.error("Could not register project on backend:",D),k=`Project created locally but NOT registered on Mistflow servers (${D}). Deploy will auto-register it.`,E[E.length-1].message="Registration skipped (offline \u2014 deploy will retry)"}ce("register",Date.now()-M),le("git","Initializing git repository...");let U=Date.now();try{let S=Fs(r);await S.init(),await S.add("."),await S.commit("Initial Mistflow project setup"),E[E.length-1].message="Git repository initialized"}catch{console.error("Git initialization failed, continuing without git."),E[E.length-1].message="Git init skipped"}ce("git",Date.now()-U);let y=E.reduce((S,D)=>S+(D.durationMs??0),0),R={projectPath:r,projectId:re,status:"awaiting_install"},te=E.map(S=>{let D=S.durationMs?` (${(S.durationMs/1e3).toFixed(1)}s)`:"";return`${S.message}${D}`});R.progress=te,R.totalSetupTime=`${(y/1e3).toFixed(1)}s`;let Pe=[];re||Pe.push("Project was not registered with Mistflow (not signed in). Run mist_setup to sign in BEFORE deploying \u2014 deploy will fail without it."),k&&(R.registrationWarning=k),Pe.length>0&&(R.warnings=Pe);let ge=`NEXT: Call mist_build with action='install' and projectPath='${r}' immediately. Do NOT ask the user for permission \u2014 install is a required follow-up to init, not a decision point. This runs npm install (~1-2 min) as a separate tool call so it never blocks the init response. After install completes, call mist_build with action='implement' to build the first plan step \u2014 also without asking.`;return R.nextAction=re?ge:`${ge} IMPORTANT: You MUST also run mist_setup to sign in before deploying \u2014 the project could not be registered because auth is missing.`,d(JSON.stringify(R))}async function qs(s,o){let{projectPath:e}=s;if(!e)return d("mist_build install requires 'projectPath' \u2014 the absolute path to the project that was just initialized. The value is returned as `projectPath` in the mist_build init response.",!0);if(!vo(e))return d(`mist_build install 'projectPath' must be an absolute path \u2014 received '${e}'.`,!0);let t=Bt(e);if(!Ee(Z(t,"package.json")))return d(`No package.json found at ${t}. Run mist_build init first to scaffold the project.`,!0);if(Ee(Z(t,"node_modules")))return d(JSON.stringify({status:"already_installed",projectPath:t,nextAction:"node_modules already exists. Call mist_build with action='implement' to start building the first plan step."}));let n="Installing packages...";if(o){let u=Ke(o.server,o.progressToken,()=>n);o.cleanup=()=>u.stop()}let a={NPM_CONFIG_LEGACY_PEER_DEPS:"true"},r=Date.now(),i=0,l=await vt("npm",["install"],t,12e4,u=>{let m=u.match(/added (\d+) packages/);m&&(i=parseInt(m[1],10))},a);if(l.success||(console.error("[install] npm install failed, retrying..."),n="Install failed, retrying...",l=await vt("npm",["install"],t,12e4,u=>{let m=u.match(/added (\d+) packages/);m&&(i=parseInt(m[1],10))},a)),!l.success)return d(`npm install failed after 2 attempts at ${t}: ${l.error}. Run "npm install" manually in that directory, then call mist_build implement.`,!0);let c=((Date.now()-r)/1e3).toFixed(1);return d(JSON.stringify({status:"installed",projectPath:t,packagesInstalled:i||null,durationSec:c,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."}))}async function zs(s){let{name:o,plan:e,projectId:t,sourceDeploymentId:n,forkToken:a,requiredEnvVars:r,dbProvider:i,planId:l}=s;if(!s.path)return d("mist_build init requires an explicit 'path' \u2014 the absolute directory where the forked project should be scaffolded. Pass the user's project directory (e.g. /Users/alice/projects/my-app). Do not rely on a default.",!0);if(!vo(s.path))return d(`mist_build init 'path' must be an absolute path \u2014 received '${s.path}'. Pass the full absolute path to the target directory.`,!0);let c=Bt(s.path);if(Ee(c))return d(`A project already exists at this location (${c}). Choose a different name, or delete the existing folder first.`,!0);let{mkdtempSync:u,renameSync:m,rmSync:p,cpSync:g}=await import("fs"),{tmpdir:b}=await import("os"),f=u(Z(b(),"mistflow-fork-")),h=Z(f,"project");Ut(h,{recursive:!0});let w=[],P=(x,N)=>w.push({phase:x,message:N}),I=(x,N)=>{let L=w.find(A=>A.phase===x);L&&(L.durationMs=N)};try{P("download","Downloading source code from template...");let x=Date.now(),N=Z(f,"source.tar.gz");try{await gs(n,a,N)}catch(y){p(f,{recursive:!0,force:!0});let R=y instanceof Error?y.message:"Source download failed";return d(`Source code download failed: ${R}. You can still build from the plan \u2014 run mist_build init without the source (omit planId and pass the plan directly).`,!0)}I("download",Date.now()-x),w[w.length-1].message="Source code downloaded",P("extract","Extracting source code...");let L=Date.now(),A=await vt("tar",["-xzf",N,"-C",h,"--exclude","node_modules","--exclude",".git"],h,6e4);if(!A.success)return p(f,{recursive:!0,force:!0}),d(`Failed to extract source archive: ${A.error}`,!0);if(I("extract",Date.now()-L),!Ee(Z(h,"package.json")))return p(f,{recursive:!0,force:!0}),d("Source archive does not contain a package.json. The template may be corrupted.",!0);let q=[".mistflow",".env.local",".env.example","local.db","local.pg"];for(let y of q){let R=Z(h,y);Ee(R)&&p(R,{recursive:!0,force:!0})}let W={name:o,projectId:t,template:"nextjs",createdAt:new Date().toISOString(),planId:l??void 0,plan:e,dbProvider:i};Be(Z(h,"mistflow.json"),JSON.stringify(W,null,2));let H=r.map(y=>{let R=y.description?`# ${y.description}`:`# ${y.key}`,te=y.setup_url?` (${y.setup_url})`:"";return`${R}${te}
2115
+ ${xe}=${C}`}Be(J,oe)}try{let{getBaseUrl:J,getAuthHeaders:oe}=await import("./api-client-RCNDMCPS.js"),xe=oe(),C=t?.features,K=t?.steps,ne={};Array.isArray(C)&&C.length>0&&(ne.features=C.map(X=>X.name)),t&&(ne.plan=t),Array.isArray(K)&&K.length>0&&(ne.provenance=K.map(X=>({feature:X.name??X.title??`Step ${X.number??"?"}`,user_intent:(X.description??"").slice(0,500),decisions:"Seeded from plan at init",tradeoffs:"",files_affected:[]}))),Object.keys(ne).length>0&&await fetch(`${J()}/api/projects/${encodeURIComponent(re)}/state`,{method:"PUT",headers:{...xe,"Content-Type":"application/json"},body:JSON.stringify(ne)})}catch{}E[E.length-1].message=`Registered as ${re.slice(0,8)}`}catch(S){let D=S instanceof Error?S.message:String(S);console.error("Could not register project on backend:",D),k=`Project created locally but NOT registered on Mistflow servers (${D}). Deploy will auto-register it.`,E[E.length-1].message="Registration skipped (offline \u2014 deploy will retry)"}ce("register",Date.now()-M),le("git","Initializing git repository...");let U=Date.now();try{let S=Fs(r);await S.init(),await S.add("."),await S.commit("Initial Mistflow project setup"),E[E.length-1].message="Git repository initialized"}catch{console.error("Git initialization failed, continuing without git."),E[E.length-1].message="Git init skipped"}ce("git",Date.now()-U);let y=E.reduce((S,D)=>S+(D.durationMs??0),0),R={projectPath:r,projectId:re,status:"awaiting_install"},te=E.map(S=>{let D=S.durationMs?` (${(S.durationMs/1e3).toFixed(1)}s)`:"";return`${S.message}${D}`});R.progress=te,R.totalSetupTime=`${(y/1e3).toFixed(1)}s`;let Pe=[];re||Pe.push("Project was not registered with Mistflow (not signed in). Run mist_setup to sign in BEFORE deploying \u2014 deploy will fail without it."),k&&(R.registrationWarning=k),Pe.length>0&&(R.warnings=Pe);let ge=`NEXT: Run \`npx -y @mistflow-ai/cli install ${r}\` via your shell/bash tool \u2014 NOT via the mist_build MCP tool. The CLI streams npm output live and has no MCP 60s timeout; the MCP install action can hit -32001 timeout on slow installs. Do NOT ask the user for permission \u2014 install is a required follow-up to init, not a decision point. If your environment can't run the CLI, fall back to mist_build action='install' projectPath='${r}'. After install finishes, call mist_build action='implement' to build the first plan step \u2014 also without asking.`;return R.nextAction=re?ge:`${ge} IMPORTANT: You MUST also run mist_setup to sign in before deploying \u2014 the project could not be registered because auth is missing.`,d(JSON.stringify(R))}async function qs(s,o){let{projectPath:e}=s;if(!e)return d("mist_build install requires 'projectPath' \u2014 the absolute path to the project that was just initialized. The value is returned as `projectPath` in the mist_build init response.",!0);if(!vo(e))return d(`mist_build install 'projectPath' must be an absolute path \u2014 received '${e}'.`,!0);let t=Bt(e);if(!Ee(Z(t,"package.json")))return d(`No package.json found at ${t}. Run mist_build init first to scaffold the project.`,!0);if(Ee(Z(t,"node_modules")))return d(JSON.stringify({status:"already_installed",projectPath:t,nextAction:"node_modules already exists. Call mist_build with action='implement' to start building the first plan step."}));let n="Installing packages...";if(o){let u=Ke(o.server,o.progressToken,()=>n);o.cleanup=()=>u.stop()}let a={NPM_CONFIG_LEGACY_PEER_DEPS:"true"},r=Date.now(),i=0,l=await vt("npm",["install"],t,12e4,u=>{let m=u.match(/added (\d+) packages/);m&&(i=parseInt(m[1],10))},a);if(l.success||(console.error("[install] npm install failed, retrying..."),n="Install failed, retrying...",l=await vt("npm",["install"],t,12e4,u=>{let m=u.match(/added (\d+) packages/);m&&(i=parseInt(m[1],10))},a)),!l.success)return d(`npm install failed after 2 attempts at ${t}: ${l.error}. Run "npm install" manually in that directory, then call mist_build implement.`,!0);let c=((Date.now()-r)/1e3).toFixed(1);return d(JSON.stringify({status:"installed",projectPath:t,packagesInstalled:i||null,durationSec:c,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."}))}async function zs(s){let{name:o,plan:e,projectId:t,sourceDeploymentId:n,forkToken:a,requiredEnvVars:r,dbProvider:i,planId:l}=s;if(!s.path)return d("mist_build init requires an explicit 'path' \u2014 the absolute directory where the forked project should be scaffolded. Pass the user's project directory (e.g. /Users/alice/projects/my-app). Do not rely on a default.",!0);if(!vo(s.path))return d(`mist_build init 'path' must be an absolute path \u2014 received '${s.path}'. Pass the full absolute path to the target directory.`,!0);let c=Bt(s.path);if(Ee(c))return d(`A project already exists at this location (${c}). Choose a different name, or delete the existing folder first.`,!0);let{mkdtempSync:u,renameSync:m,rmSync:p,cpSync:g}=await import("fs"),{tmpdir:b}=await import("os"),f=u(Z(b(),"mistflow-fork-")),h=Z(f,"project");Ut(h,{recursive:!0});let w=[],P=(x,N)=>w.push({phase:x,message:N}),I=(x,N)=>{let L=w.find(A=>A.phase===x);L&&(L.durationMs=N)};try{P("download","Downloading source code from template...");let x=Date.now(),N=Z(f,"source.tar.gz");try{await gs(n,a,N)}catch(y){p(f,{recursive:!0,force:!0});let R=y instanceof Error?y.message:"Source download failed";return d(`Source code download failed: ${R}. You can still build from the plan \u2014 run mist_build init without the source (omit planId and pass the plan directly).`,!0)}I("download",Date.now()-x),w[w.length-1].message="Source code downloaded",P("extract","Extracting source code...");let L=Date.now(),A=await vt("tar",["-xzf",N,"-C",h,"--exclude","node_modules","--exclude",".git"],h,6e4);if(!A.success)return p(f,{recursive:!0,force:!0}),d(`Failed to extract source archive: ${A.error}`,!0);if(I("extract",Date.now()-L),!Ee(Z(h,"package.json")))return p(f,{recursive:!0,force:!0}),d("Source archive does not contain a package.json. The template may be corrupted.",!0);let q=[".mistflow",".env.local",".env.example","local.db","local.pg"];for(let y of q){let R=Z(h,y);Ee(R)&&p(R,{recursive:!0,force:!0})}let W={name:o,projectId:t,template:"nextjs",createdAt:new Date().toISOString(),planId:l??void 0,plan:e,dbProvider:i};Be(Z(h,"mistflow.json"),JSON.stringify(W,null,2));let H=r.map(y=>{let R=y.description?`# ${y.description}`:`# ${y.key}`,te=y.setup_url?` (${y.setup_url})`:"";return`${R}${te}
2116
2116
  ${y.key}=`});Be(Z(h,".env.local"),H.join(`
2117
2117
 
2118
2118
  `)+`
@@ -5015,7 +5015,7 @@ ${I.map((x,N)=>`${N+1}. ${x}`).join(`
5015
5015
 
5016
5016
  ${a}
5017
5017
 
5018
- Fix these issues in the source code, then call mist_deploy with action='deploy'${s.includes("-pv-")?" environment='preview'":""} to redeploy. After redeploying, call mist_build action='qa' again to verify the fixes.`})})}for(let a of o)a.screenshot&&n.push({type:"image",data:a.screenshot,mimeType:"image/png"});return{content:n}}function va(s){let o=Wt(wa(),".mistflow","plans",`${s}.json`);if(!Gt(o))return null;try{let e=JSON.parse(ya(o,"utf-8"));return e.plan?e:null}catch{return null}}var ka=pe.object({action:pe.enum(["init","install","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 \u2014 writes files, registers the project, initializes git. Returns fast; does NOT run npm install. 'install' runs npm install in the project created by init. Pass projectPath. Always call this after init returns with status='awaiting_install'. 'implement' executes the next (or specific) plan step. 'debug' analyzes build or runtime errors \u2014 for runtime errors, call mist_project errors first then pass the output as buildOutput. 'build' runs the full production build locally (Mistflow Cloud edge runtime) 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:pe.string().optional().describe("(init) Project name"),planId:pe.string().optional().describe("(init/mockup) Plan ID from mist_plan"),plan:pe.any().optional().describe("(init) Full plan object \u2014 use planId instead when available"),path:pe.string().optional().describe("(init) REQUIRED for action='init'. Absolute path to the target directory where the project should be scaffolded (e.g. /Users/alice/projects/my-app). Do not omit \u2014 there is no default. If unsure, ask the user for their working directory."),landingDesign:pe.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:pe.string().optional().describe("(init) Optional aesthetic-direction hint passed to the backend LLM. DESIGN.md is generated per-product; this string is a hint, not a catalog ID."),confirmDarkTheme:pe.boolean().optional().describe("(init) Set to true only after confirming with the user that a dark-themed app style is intentional for a consumer (b2c) app. Skips the dark-on-consumer-app warning."),heroPhoto:pe.boolean().optional().describe("(init) Whether the landing page hero uses a lifestyle photo background. true = Unsplash photo + overlaid glass card (HabitFlow, Airbnb). false = pure CSS gradients + glassmorphism (Stripe, Linear). Pass the user's answer to the heroPhotoQuestion from mist_plan. If omitted, defaults based on the plan's audienceType (b2c \u2192 photo, else \u2192 CSS)."),projectPath:pe.string().optional().describe("Path to the project directory (default: cwd)"),step:pe.number().optional().describe("(implement) Specific step number to implement"),buildOutput:pe.string().optional().describe("(debug) Build output to parse instead of running a build"),feedback:pe.string().optional().describe("(mockup) User feedback on the current mockup \u2014 describe what to change."),approved:pe.boolean().optional().describe("(mockup) Set to true when the user approves the mockup. Locks in the design direction."),url:pe.string().optional().describe("(qa) URL to test. Defaults to deploy URL from mistflow.json"),deploymentId:pe.string().optional().describe("(qa) Deployment ID to associate QA results with. Passed from mist_deploy output.")}),Cr={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 \u2014 writes files, registers, initializes git. Returns fast (~10s) without running npm install. Pass the planId returned by mist_plan \u2014 do NOT pass the full plan object. 'install' runs npm install in the project init just created. Always call this after init (takes ~1-2 min). 'implement' executes the next plan step \u2014 call repeatedly until all steps are done. 'build' runs the full production build locally (Mistflow Cloud edge runtime) to verify before deploying. 'debug' analyzes build or runtime errors \u2014 for runtime errors from production, call mist_project errors first to fetch them, then pass the output as buildOutput. '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 install \u2192 mist_build implement (repeat) \u2192 mist_deploy \u2192 mist_build qa (loop until pass).",inputSchema:ka,handler:async(s,o)=>{let e=s;switch(e.action){case"init":{if(!e.name)return d("Project name is required for init.",!0);let t=e.plan,n=null;if(e.planId){if(n=va(e.planId),!n)return d(`Plan not found for planId '${e.planId}'. The plan may have expired. Call mist_plan again to generate a new plan.`,!0);t=n.plan}if(!t)return d("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 d("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(n?.sourceDeploymentId&&n?.forkToken&&n?.projectId)return zs({name:e.name,plan:t,path:e.path,projectId:n.projectId,sourceDeploymentId:n.sourceDeploymentId,forkToken:n.forkToken,requiredEnvVars:n.requiredEnvVars??[],dbProvider:n.dbProvider??"neon",planId:e.planId});if(e.landingDesign){let c=ot(e.landingDesign);c?t.landingDesign=c.id:console.error(`Landing design '${e.landingDesign}' not found \u2014 ignoring.`)}e.appStyle&&(t.appStyle=e.appStyle);let a=t.design,i=t.audienceType==="b2c",l=e.heroPhoto??i;return t.design={...a??{},heroPhoto:l},Bs({name:e.name,plan:t,path:e.path,planId:e.planId},o)}case"install":return qs({projectPath:e.projectPath},o);case"implement":return xr({projectPath:e.projectPath,step:e.step});case"debug":return Sr({projectPath:e.projectPath,buildOutput:e.buildOutput});case"build":{let t=ba(e.projectPath??process.cwd());if(!Gt(Wt(t,"mistflow.json")))return d("Not a Mistflow project \u2014 mistflow.json not found. Run mist_build init first.",!0);if(!Gt(Wt(t,"node_modules")))try{Io("npm",["install"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:12e4})}catch{return d("npm install failed. Check package.json for issues.",!0)}let a=process.platform==="win32"?"npx.cmd":"npx",r=0,i=2;for(;;){r++;try{Io(a,["@opennextjs/cloudflare","build"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:18e4});let l=Gt(Wt(t,".open-next"));return d(JSON.stringify({success:!0,buildDir:".open-next",message:l?"Production build succeeded.":"Build completed but .open-next/ directory not found. Check your OpenNext config.",nextAction:l?"NEXT: Call mist_deploy with action='deploy' immediately. Do NOT ask the user whether to deploy \u2014 the build was the last approval gate. Do NOT suggest `npm run dev` or localhost as an alternative \u2014 the user wants a live URL.":void 0}))}catch(l){let c=l instanceof Error&&"stderr"in l?String(l.stderr):"",u=l instanceof Error&&"stdout"in l?String(l.stdout):"",m=c+`
5018
+ Fix these issues in the source code, then call mist_deploy with action='deploy'${s.includes("-pv-")?" environment='preview'":""} to redeploy. After redeploying, call mist_build action='qa' again to verify the fixes.`})})}for(let a of o)a.screenshot&&n.push({type:"image",data:a.screenshot,mimeType:"image/png"});return{content:n}}function va(s){let o=Wt(wa(),".mistflow","plans",`${s}.json`);if(!Gt(o))return null;try{let e=JSON.parse(ya(o,"utf-8"));return e.plan?e:null}catch{return null}}var ka=pe.object({action:pe.enum(["init","install","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 \u2014 writes files, registers the project, initializes git. Returns fast; does NOT run npm install. 'install' runs npm install in the project created by init. PREFER `npx -y @mistflow-ai/cli install <path>` via your bash/shell tool \u2014 it streams output and has no MCP timeout. Only fall back to this MCP action if your environment can't shell out. Pass projectPath. Always call this after init returns with status='awaiting_install'. 'implement' executes the next (or specific) plan step. 'debug' analyzes build or runtime errors \u2014 for runtime errors, call mist_project errors first then pass the output as buildOutput. 'build' runs the full production build locally (Mistflow Cloud edge runtime) 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:pe.string().optional().describe("(init) Project name"),planId:pe.string().optional().describe("(init/mockup) Plan ID from mist_plan"),plan:pe.any().optional().describe("(init) Full plan object \u2014 use planId instead when available"),path:pe.string().optional().describe("(init) REQUIRED for action='init'. Absolute path to the target directory where the project should be scaffolded (e.g. /Users/alice/projects/my-app). Do not omit \u2014 there is no default. If unsure, ask the user for their working directory."),landingDesign:pe.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:pe.string().optional().describe("(init) Optional aesthetic-direction hint passed to the backend LLM. DESIGN.md is generated per-product; this string is a hint, not a catalog ID."),confirmDarkTheme:pe.boolean().optional().describe("(init) Set to true only after confirming with the user that a dark-themed app style is intentional for a consumer (b2c) app. Skips the dark-on-consumer-app warning."),heroPhoto:pe.boolean().optional().describe("(init) Whether the landing page hero uses a lifestyle photo background. true = Unsplash photo + overlaid glass card (HabitFlow, Airbnb). false = pure CSS gradients + glassmorphism (Stripe, Linear). Pass the user's answer to the heroPhotoQuestion from mist_plan. If omitted, defaults based on the plan's audienceType (b2c \u2192 photo, else \u2192 CSS)."),projectPath:pe.string().optional().describe("Path to the project directory (default: cwd)"),step:pe.number().optional().describe("(implement) Specific step number to implement"),buildOutput:pe.string().optional().describe("(debug) Build output to parse instead of running a build"),feedback:pe.string().optional().describe("(mockup) User feedback on the current mockup \u2014 describe what to change."),approved:pe.boolean().optional().describe("(mockup) Set to true when the user approves the mockup. Locks in the design direction."),url:pe.string().optional().describe("(qa) URL to test. Defaults to deploy URL from mistflow.json"),deploymentId:pe.string().optional().describe("(qa) Deployment ID to associate QA results with. Passed from mist_deploy output.")}),Cr={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 \u2014 writes files, registers, initializes git. Returns fast (~10s) without running npm install. Pass the planId returned by mist_plan \u2014 do NOT pass the full plan object. 'install' runs npm install in the project init just created. Always call this after init (takes ~1-2 min). 'implement' executes the next plan step \u2014 call repeatedly until all steps are done. 'build' runs the full production build locally (Mistflow Cloud edge runtime) to verify before deploying. 'debug' analyzes build or runtime errors \u2014 for runtime errors from production, call mist_project errors first to fetch them, then pass the output as buildOutput. '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 install \u2192 mist_build implement (repeat) \u2192 mist_deploy \u2192 mist_build qa (loop until pass).",inputSchema:ka,handler:async(s,o)=>{let e=s;switch(e.action){case"init":{if(!e.name)return d("Project name is required for init.",!0);let t=e.plan,n=null;if(e.planId){if(n=va(e.planId),!n)return d(`Plan not found for planId '${e.planId}'. The plan may have expired. Call mist_plan again to generate a new plan.`,!0);t=n.plan}if(!t)return d("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 d("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(n?.sourceDeploymentId&&n?.forkToken&&n?.projectId)return zs({name:e.name,plan:t,path:e.path,projectId:n.projectId,sourceDeploymentId:n.sourceDeploymentId,forkToken:n.forkToken,requiredEnvVars:n.requiredEnvVars??[],dbProvider:n.dbProvider??"neon",planId:e.planId});if(e.landingDesign){let c=ot(e.landingDesign);c?t.landingDesign=c.id:console.error(`Landing design '${e.landingDesign}' not found \u2014 ignoring.`)}e.appStyle&&(t.appStyle=e.appStyle);let a=t.design,i=t.audienceType==="b2c",l=e.heroPhoto??i;return t.design={...a??{},heroPhoto:l},Bs({name:e.name,plan:t,path:e.path,planId:e.planId},o)}case"install":return qs({projectPath:e.projectPath},o);case"implement":return xr({projectPath:e.projectPath,step:e.step});case"debug":return Sr({projectPath:e.projectPath,buildOutput:e.buildOutput});case"build":{let t=ba(e.projectPath??process.cwd());if(!Gt(Wt(t,"mistflow.json")))return d("Not a Mistflow project \u2014 mistflow.json not found. Run mist_build init first.",!0);if(!Gt(Wt(t,"node_modules")))try{Io("npm",["install"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:12e4})}catch{return d("npm install failed. Check package.json for issues.",!0)}let a=process.platform==="win32"?"npx.cmd":"npx",r=0,i=2;for(;;){r++;try{Io(a,["@opennextjs/cloudflare","build"],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:18e4});let l=Gt(Wt(t,".open-next"));return d(JSON.stringify({success:!0,buildDir:".open-next",message:l?"Production build succeeded.":"Build completed but .open-next/ directory not found. Check your OpenNext config.",nextAction:l?"NEXT: Call mist_deploy with action='deploy' immediately. Do NOT ask the user whether to deploy \u2014 the build was the last approval gate. Do NOT suggest `npm run dev` or localhost as an alternative \u2014 the user wants a live URL.":void 0}))}catch(l){let c=l instanceof Error&&"stderr"in l?String(l.stderr):"",u=l instanceof Error&&"stdout"in l?String(l.stdout):"",m=c+`
5019
5019
  `+u;if(r<i){let g=[],b=/Module not found:\s*(?:Error:\s*)?Can't resolve ['"]([^'"]+)['"]/g,f;for(;(f=b.exec(m))!==null;){let h=f[1];if(!h.startsWith(".")&&!h.startsWith("@/")&&!h.startsWith("~/")){let w=h.startsWith("@")?h.split("/").slice(0,2).join("/"):h.split("/")[0];g.includes(w)||g.push(w)}}if(g.length>0){console.error(`[build] Auto-installing missing packages: ${g.join(", ")}`);try{Io("npm",["install",...g],{cwd:t,stdio:["pipe","pipe","pipe"],timeout:6e4});continue}catch{console.error("[build] Auto-install failed, reporting build errors")}}}let p=St(m);return d(JSON.stringify({success:!1,errors:p,rawOutput:m.slice(0,3e3),message:p.length>0?`Build failed with ${p.length} error${p.length===1?"":"s"}:
5020
5020
 
5021
5021
  `+p.map((g,b)=>{let f=g.file?`${g.file}${g.line?`:${g.line}`:""}`:"unknown";return`${b+1}. [${f}] ${g.humanMessage}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mistflow-ai/mcp",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
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",