@mastergo/magic-mcp 0.2.3 → 0.2.4
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 +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1252,7 +1252,7 @@ ${o}
|
|
|
1252
1252
|
`;s=r+c}return gt.default.writeFileSync(n,s),"added"}function u4(t){let e=[],n=[];if(!t||typeof t!="string")return{urls:e,lostFragments:n};let r=/url\(\s*(?:"([^"]*)"|'([^']*)'|([^)]*))\s*\)/gi,o;for(;(o=r.exec(t))!==null;){let i=(o[1]??o[2]??o[3]??"").trim();if(i){if(i==="[object Object]"||i.includes("[object Object]")){n.push(o[0]);continue}e.push(i)}}return{urls:e,lostFragments:n}}function fy(t,e,n,r){if(!t||typeof t!="object")return;if(Array.isArray(t)){t.forEach((i,s)=>fy(i,`${e}[${s}]`,n,r));return}let o=typeof t.id=="string"?t.id:"";for(let[i,s]of Object.entries(t)){let a=e?`${e}.${i}`:i;if(typeof s=="string"){if(i==="cssCode"){let{urls:c,lostFragments:l}=u4(s);for(let p of c){let d=p.startsWith("data:image/")?"data":"remote",f=p.startsWith("//")?`https:${p}`:p;(d==="data"||dy(f))&&(n.has(f)||n.set(f,{token:a,url:f,kind:d}))}for(let p of l)r.push({nodeId:o,token:a,rawCssFragment:p})}else if(s.startsWith("data:image/"))n.has(s)||n.set(s,{token:a,url:s,kind:"data"});else if(s.startsWith("http")||s.startsWith("//")){let c=s.startsWith("//")?`https:${s}`:s;dy(c)&&!n.has(c)&&n.set(c,{token:a,url:c,kind:"remote"})}}else s&&typeof s=="object"&&fy(s,a,n,r)}}function R$(t){let e=t.match(/paint_(\d+):(\d+)/);return e?Number(e[2]):Number.MAX_SAFE_INTEGER}async function p4(t,e,n,r){var o;try{let i=await ot.getDsl(t,e,n?{sourceLayerId:n}:void 0),s=(i==null?void 0:i.dsl)??{},a=(s==null?void 0:s.styles)??{},c=Object.keys(a).filter(p=>p.startsWith("paint_")).sort((p,d)=>R$(p)-R$(d)||p.localeCompare(d)),l=[];for(let p of c){let d=(o=a[p])==null?void 0:o.value;Array.isArray(d)&&d.forEach((f,h)=>{let y=typeof(f==null?void 0:f.url)=="string"?f.url:"";!y||!dy(y)||l.push({token:`dsl.styles.${p}.value[${h}].url`,url:y,kind:"remote"})})}return l}catch(i){return r.push(`DSL fallback fetch failed: ${(i==null?void 0:i.message)??String(i)}`),[]}}function d4(t,e){if(!e.length)return 0;let n=0,r=0,o=i=>{if(!(!i||typeof i!="object")){if(Array.isArray(i)){i.forEach(o);return}for(let[s,a]of Object.entries(i))typeof a=="string"&&s==="cssCode"&&a.includes("[object Object]")?i[s]=a.replace(/url\(\s*\[object Object\]\s*\)/gi,c=>{if(n>=e.length)return c;let l=e[n++];return r++,`url(${l})`}):a&&typeof a=="object"&&o(a)}};return o(t),r}function f4(t,e,n,r){if(!Array.isArray(t==null?void 0:t.path)||t.path.length===0)return null;let o=Ji(String(t.id??"icon")),i=t.width??16,s=t.height??16,c=t.path.length===1,l=`${o}.svg`,p=qt.default.join(e,l),d=!1;if(!gt.default.existsSync(p)){let h=t.path.map((y,v)=>{var m,b,w,k;let x="currentColor";if(!c){let E=((b=(m=t.fills)==null?void 0:m[v])==null?void 0:b.color)??((k=(w=t.strokes)==null?void 0:w[v])==null?void 0:k.color);E&&(x=`rgb(${Math.round((E.r??0)*255)},${Math.round((E.g??0)*255)},${Math.round((E.b??0)*255)})`)}return` <path d="${y}" fill="${x}"/>`}).join(`
|
|
1253
1253
|
`);gt.default.writeFileSync(p,`<svg width="${i}" height="${s}" viewBox="0 0 ${i} ${s}" xmlns="http://www.w3.org/2000/svg">
|
|
1254
1254
|
${h}
|
|
1255
|
-
</svg>`),d=!0}let f=qt.default.join(n,l);return gt.default.existsSync(f)||gt.default.copyFileSync(p,f),{flutterPath:`${r}/${l}`,localPath:p,needsColorFilter:c,created:d}}function z$(t,e,n,r,o){let i=f4(t,e,n,r);i&&(t.imageUrls=t.imageUrls??[],t.imageUrls.push({flutterPath:i.flutterPath,needsColorFilter:i.needsColorFilter}),o.push({token:`vector.${Ji(String(t.id??"icon"))}`,sourceUrl:"",localPath:i.localPath,flutterPath:i.flutterPath,format:"svg",status:i.created?"downloaded":"skipped",needsColorFilter:i.needsColorFilter}),delete t.path),Array.isArray(t==null?void 0:t.children)&&t.children.forEach(s=>z$(s,e,n,r,o))}function my(t,e){if(!(!t||typeof t!="object")){if(Array.isArray(t)){t.forEach(n=>my(n,e));return}for(let[n,r]of Object.entries(t))if(typeof r=="string")if(n==="cssCode")t[n]=r.replace(/url\(\s*(?:"([^"]*)"|'([^']*)'|([^)]*))\s*\)/gi,(o,i,s,a)=>{let c=(i??s??a??"").trim(),l=c.startsWith("//")?`https:${c}`:c,p=e.get(l)??e.get(c);return p?`url(${p})`:o});else{let o=r.startsWith("//")?`https:${r}`:r,i=e.get(o)??e.get(r);i&&(t[n]=i)}else r&&typeof r=="object"&&my(r,e)}}var mu=class extends ht{constructor(){super();this.name=e4;this.description=t4;this.schema=Y.object({rootPath:Y.string().describe("The root path of the Flutter project, if the user does not provide, you can use the current directory as the root path"),fileId:Y.string().describe("MasterGo design file ID (format: file/<fileId> in MasterGo URL)"),layerId:Y.string().describe("Layer ID of the specific component or element to retrieve (format: ?layer_id=<layerId> / file=<fileId> in MasterGo URL)"),sourceLayerId:Y.string().optional().describe("Source layer ID from URL parameter source_layer_id. When provided, use this instead of layerId for all queries."),featureName:Y.string().optional().describe("Optional feature directory name under assets/image/ and the Flutter feature module. Defaults to the root component name.")})}async execute({rootPath:n,fileId:r,layerId:o,sourceLayerId:i,featureName:s}){let a=[],c=[],l=[];if(!qt.default.isAbsolute(n))return{isError:!0,content:[{type:"text",text:JSON.stringify({error:`rootPath must be an absolute path, got: "${n}". Please provide an absolute path to the Flutter project root.`})}]};let p=qt.default.resolve(n,".mastergo"),d=qt.default.join(p,"images");ly(p),ly(d);let f=await ot.getComponentStyleJson(r,o,i),h=(f==null?void 0:f[0])??{},y=h.name??"component";if(!f||f.length===0||!h.name)return{isError:!0,content:[{type:"text",text:JSON.stringify({error:`No component data returned from MasterGo API for fileId=${r} layerId=${o}. Please verify the fileId and layerId are correct.`})}]};let x=(s?Ji(s):"")||Ji(y)||Ji(o)||"component",m=qt.default.join(p,`${x}.json`),b=`assets/image/${x}`,w=qt.default.join(n,b);ly(w);let k=[];z$(h,d,w,b,k);let E=new Map;if(fy(h,"",E,l),l.length>0){let B=await p4(r,o,i,a);for(let qe of B)E.has(qe.url)||E.set(qe.url,qe)}let F=Array.from(E.values()),j={discovered:F.length,downloaded:0,skipped:0,failed:0,recovered:0,lost:l.length,byFormat:{}},de=await c4(F,r4,async B=>{var ge;let qe=o4(B.url),De=i4(B.url),it=`${Ji(B.token.replace(/:/g,"_"))||"asset"}_${qe}`;try{if(B.kind==="data"){let Tt=(ge=B.url.match(/^data:([^;]+);base64,/))==null?void 0:ge[1];De=py(Tt);let Et=`${it}.${De}`,Te=qt.default.join(d,Et);gt.default.existsSync(Te)||await a4(B.url,qt.default.join(d,it));let Bt=qt.default.join(w,Et);return gt.default.existsSync(Bt)||await gt.default.promises.copyFile(Te,Bt),j.downloaded++,j.byFormat[De]=(j.byFormat[De]??0)+1,{token:B.token,sourceUrl:B.url,localPath:Te,flutterPath:`${b}/${Et}`,format:De,status:"downloaded"}}if(!O$(B.url))throw new Error(`Blocked unsafe URL: ${B.url}`);if(!De)try{let Tt=await vt.head(B.url,{timeout:5e3,httpsAgent:P$,maxRedirects:5});De=py(String(Tt.headers["content-type"]??""))}catch{De="png"}let ke=`${it}.${De}`,ut=qt.default.join(d,ke);if(gt.default.existsSync(ut)){let Tt=qt.default.join(w,ke);return gt.default.existsSync(Tt)||await gt.default.promises.copyFile(ut,Tt),j.skipped++,j.byFormat[De]=(j.byFormat[De]??0)+1,{token:B.token,sourceUrl:B.url,localPath:ut,flutterPath:`${b}/${ke}`,format:De,status:"skipped"}}await s4(B.url,ut);let Oe=qt.default.join(w,ke);return await gt.default.promises.copyFile(ut,Oe),j.downloaded++,j.byFormat[De]=(j.byFormat[De]??0)+1,{token:B.token,sourceUrl:B.url,localPath:ut,flutterPath:`${b}/${ke}`,format:De,status:"downloaded"}}catch(ke){let ut=(ke==null?void 0:ke.message)??String(ke);return j.failed++,c.push({token:B.token,url:B.url,error:ut}),a.push(`Failed to download ${B.token}: ${ut}`),{token:B.token,sourceUrl:B.url,localPath:"",flutterPath:"",format:De??"unknown",status:"failed",error:ut}}});for(let B of k)j.discovered++,B.status==="downloaded"?j.downloaded++:j.skipped++,j.byFormat.svg=(j.byFormat.svg??0)+1;let oe=[...de,...k],Re=l4(n,b);Re==="no-pubspec"&&a.push("pubspec.yaml not found \u2014 asset directory was NOT registered. Add it manually.");let bt=new Map;for(let B of oe)B.status!=="failed"&&B.flutterPath&&B.sourceUrl&&bt.set(B.sourceUrl,B.flutterPath);my(h,bt);let Ve=oe.filter(B=>B.token.startsWith("dsl.styles.paint_")&&B.status!=="failed"&&!!B.flutterPath).map(B=>B.flutterPath),ae=d4(h,Ve);j.recovered=ae,j.lost=Math.max(0,j.lost-ae),ae>0&&a.push(`Recovered ${ae} lost image placeholder(s) via DSL styles paint fallback.`);let yt=l.slice(ae);gt.default.writeFileSync(m,JSON.stringify(h,null,2));let V=qt.default.join(p,"flutter-component-workflow.md");gt.default.existsSync(V)||gt.default.writeFileSync(V,E$);let At=qt.default.join(p,"assets-manifest.json"),Zt={fileId:r,layerId:o,featureName:x,generatedAt:new Date().toISOString(),summary:j,assets:oe.map(B=>({token:B.token,sourceUrl:B.sourceUrl,localPath:B.localPath,flutterPath:B.flutterPath,format:B.format,status:B.status,...B.needsColorFilter!==void 0?{needsColorFilter:B.needsColorFilter}:{},...B.error?{error:B.error}:{}})),lostImageRefs:yt};gt.default.writeFileSync(At,JSON.stringify(Zt,null,2));let Vn=b,Pe=yt.length>0?`WARNING: ${yt.length} image references were LOST by the MasterGo upstream (cssCode contains url([object Object])). These cannot be recovered from the style API. Affected node IDs: ${Array.from(new Set(yt.map(B=>B.nodeId))).slice(0,20).join(", ")}${yt.length>20?" \u2026":""}. Use placeholder widgets (Container with grey background + Icon) or ask the user to re-export via mcp__getD2c for those nodes.`:null;return{content:[{type:"text",text:JSON.stringify({files:{workflow:V,componentSpec:m,assetDir:d,flutterAssetDir:w,assetManifest:At},assetSummary:j,failedAssets:c,lostImageRefs:yt.slice(0,50),warnings:a,message:`Flutter component files created. ${j.downloaded} downloaded, ${j.skipped} skipped, ${j.failed} failed, ${j.recovered} recovered, ${j.lost} still lost. Assets copied to ${b}/${Re==="added"?" and registered in pubspec.yaml.":Re==="exists"?"; pubspec entry already present.":"; pubspec.yaml NOT updated (file missing)."}`,rules:[`Follow the Flutter component workflow process defined in file://${V} for structured Flutter development. This workflow contains DSL-to-Flutter mapping rules, you'll need to read it carefully.`,`Implement the Flutter widget according to the specifications in file://${m}, ensuring all properties and states are properly handled.`,`All image URLs in the component spec have been replaced with Flutter asset paths under ${Vn}/. Use Image.asset()/SvgPicture.asset() with these paths directly.`,"SVG icons with needsColorFilter=true should use SvgPicture.asset with ColorFilter.mode(..., BlendMode.srcIn); those with needsColorFilter=false should render without color override.",`An asset manifest is available at file://${At} listing every resource and its status (downloaded/skipped/failed/lost).`,"Use flutter_screenutil for screen adaptation: width/height/padding/margin/radius use .w; font sizes use .sp.","Use standard Flutter Color(0xFFxxxxxx) for colors. Do NOT create custom color utility classes.",...c.length>0?[`WARNING: ${c.length} assets failed to download. See failedAssets for details; substitute placeholders.`]:[],...Pe?[Pe]:[]]})}]}}};var Yi={name:"@mastergo/magic-mcp",version:"0.2.3",description:"MasterGo MCP standalone service",homepage:"https://github.com/mastergo-design/mastergo-magic-mcp#readme",repository:{type:"git",url:"git+https://github.com/mastergo-design/mastergo-magic-mcp.git"},bugs:{url:"https://github.com/mastergo-design/mastergo-magic-mcp/issues"},main:"dist/index.js",bin:{"mastergo-magic-mcp":"dist/index.js"},files:["dist/**/*","!**/*.map","!**/.DS_Store","!**/.idea","!**/.vscode"],engines:{node:">=18"},scripts:{build:"node build.js","build:watch":"node build.js --watch",lint:"eslint src --ext .ts","lint:fix":"eslint src --ext .ts --fix",test:"esbuild test/format.test.ts test/headers.test.ts test/url-safety.test.ts --bundle --platform=node --format=cjs --outdir=.test --out-extension:.js=.cjs && node --test .test/format.test.cjs .test/headers.test.cjs .test/url-safety.test.cjs",start:"node dist/index.js --token=test --url=http://localhost:3000 --debug",prepare:"npm run build",prepublishOnly:"npm run build"},keywords:["mastergo","mcp","ai"],author:"",license:"ISC",private:!1,dependencies:{"@modelcontextprotocol/sdk":"^1.6.1",axios:"1.18.1","https-proxy-agent":"^9.0.0","js-yaml":"^4.2.0",zod:"^3.22.4"},devDependencies:{"@types/js-yaml":"^4.0.9","@types/node":"^20.8.10","@typescript-eslint/eslint-plugin":"^8.62.0","@typescript-eslint/parser":"^8.62.0",esbuild:"^0.25.1","esbuild-plugin-tsc":"^0.5.0",eslint:"^8.57.1",prettier:"^3.0.3","ts-node":"^10.9.1",typescript:"^5.2.2"},overrides:{hono:"^4.12.27","form-data":"^4.0.6","fast-uri":"^3.1.2","ip-address":"^10.2.0",qs:"^6.15.3"},packageManager:"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"};var h4=`version_${Yi.version.replace(/\./g,"_")}`,g4=`the current version is ${Yi.version}`,hu=class extends ht{constructor(){super();this.name=h4;this.description=g4;this.schema=Y.object({})}async execute(){return{content:[{type:"text",text:JSON.stringify(Yi.version)}]}}};var y4="mcp__getDesignSections",x4=`
|
|
1255
|
+
</svg>`),d=!0}let f=qt.default.join(n,l);return gt.default.existsSync(f)||gt.default.copyFileSync(p,f),{flutterPath:`${r}/${l}`,localPath:p,needsColorFilter:c,created:d}}function z$(t,e,n,r,o){let i=f4(t,e,n,r);i&&(t.imageUrls=t.imageUrls??[],t.imageUrls.push({flutterPath:i.flutterPath,needsColorFilter:i.needsColorFilter}),o.push({token:`vector.${Ji(String(t.id??"icon"))}`,sourceUrl:"",localPath:i.localPath,flutterPath:i.flutterPath,format:"svg",status:i.created?"downloaded":"skipped",needsColorFilter:i.needsColorFilter}),delete t.path),Array.isArray(t==null?void 0:t.children)&&t.children.forEach(s=>z$(s,e,n,r,o))}function my(t,e){if(!(!t||typeof t!="object")){if(Array.isArray(t)){t.forEach(n=>my(n,e));return}for(let[n,r]of Object.entries(t))if(typeof r=="string")if(n==="cssCode")t[n]=r.replace(/url\(\s*(?:"([^"]*)"|'([^']*)'|([^)]*))\s*\)/gi,(o,i,s,a)=>{let c=(i??s??a??"").trim(),l=c.startsWith("//")?`https:${c}`:c,p=e.get(l)??e.get(c);return p?`url(${p})`:o});else{let o=r.startsWith("//")?`https:${r}`:r,i=e.get(o)??e.get(r);i&&(t[n]=i)}else r&&typeof r=="object"&&my(r,e)}}var mu=class extends ht{constructor(){super();this.name=e4;this.description=t4;this.schema=Y.object({rootPath:Y.string().describe("The root path of the Flutter project, if the user does not provide, you can use the current directory as the root path"),fileId:Y.string().describe("MasterGo design file ID (format: file/<fileId> in MasterGo URL)"),layerId:Y.string().describe("Layer ID of the specific component or element to retrieve (format: ?layer_id=<layerId> / file=<fileId> in MasterGo URL)"),sourceLayerId:Y.string().optional().describe("Source layer ID from URL parameter source_layer_id. When provided, use this instead of layerId for all queries."),featureName:Y.string().optional().describe("Optional feature directory name under assets/image/ and the Flutter feature module. Defaults to the root component name.")})}async execute({rootPath:n,fileId:r,layerId:o,sourceLayerId:i,featureName:s}){let a=[],c=[],l=[];if(!qt.default.isAbsolute(n))return{isError:!0,content:[{type:"text",text:JSON.stringify({error:`rootPath must be an absolute path, got: "${n}". Please provide an absolute path to the Flutter project root.`})}]};let p=qt.default.resolve(n,".mastergo"),d=qt.default.join(p,"images");ly(p),ly(d);let f=await ot.getComponentStyleJson(r,o,i),h=(f==null?void 0:f[0])??{},y=h.name??"component";if(!f||f.length===0||!h.name)return{isError:!0,content:[{type:"text",text:JSON.stringify({error:`No component data returned from MasterGo API for fileId=${r} layerId=${o}. Please verify the fileId and layerId are correct.`})}]};let x=(s?Ji(s):"")||Ji(y)||Ji(o)||"component",m=qt.default.join(p,`${x}.json`),b=`assets/image/${x}`,w=qt.default.join(n,b);ly(w);let k=[];z$(h,d,w,b,k);let E=new Map;if(fy(h,"",E,l),l.length>0){let B=await p4(r,o,i,a);for(let qe of B)E.has(qe.url)||E.set(qe.url,qe)}let F=Array.from(E.values()),j={discovered:F.length,downloaded:0,skipped:0,failed:0,recovered:0,lost:l.length,byFormat:{}},de=await c4(F,r4,async B=>{var ge;let qe=o4(B.url),De=i4(B.url),it=`${Ji(B.token.replace(/:/g,"_"))||"asset"}_${qe}`;try{if(B.kind==="data"){let Tt=(ge=B.url.match(/^data:([^;]+);base64,/))==null?void 0:ge[1];De=py(Tt);let Et=`${it}.${De}`,Te=qt.default.join(d,Et);gt.default.existsSync(Te)||await a4(B.url,qt.default.join(d,it));let Bt=qt.default.join(w,Et);return gt.default.existsSync(Bt)||await gt.default.promises.copyFile(Te,Bt),j.downloaded++,j.byFormat[De]=(j.byFormat[De]??0)+1,{token:B.token,sourceUrl:B.url,localPath:Te,flutterPath:`${b}/${Et}`,format:De,status:"downloaded"}}if(!O$(B.url))throw new Error(`Blocked unsafe URL: ${B.url}`);if(!De)try{let Tt=await vt.head(B.url,{timeout:5e3,httpsAgent:P$,maxRedirects:5});De=py(String(Tt.headers["content-type"]??""))}catch{De="png"}let ke=`${it}.${De}`,ut=qt.default.join(d,ke);if(gt.default.existsSync(ut)){let Tt=qt.default.join(w,ke);return gt.default.existsSync(Tt)||await gt.default.promises.copyFile(ut,Tt),j.skipped++,j.byFormat[De]=(j.byFormat[De]??0)+1,{token:B.token,sourceUrl:B.url,localPath:ut,flutterPath:`${b}/${ke}`,format:De,status:"skipped"}}await s4(B.url,ut);let Oe=qt.default.join(w,ke);return await gt.default.promises.copyFile(ut,Oe),j.downloaded++,j.byFormat[De]=(j.byFormat[De]??0)+1,{token:B.token,sourceUrl:B.url,localPath:ut,flutterPath:`${b}/${ke}`,format:De,status:"downloaded"}}catch(ke){let ut=(ke==null?void 0:ke.message)??String(ke);return j.failed++,c.push({token:B.token,url:B.url,error:ut}),a.push(`Failed to download ${B.token}: ${ut}`),{token:B.token,sourceUrl:B.url,localPath:"",flutterPath:"",format:De??"unknown",status:"failed",error:ut}}});for(let B of k)j.discovered++,B.status==="downloaded"?j.downloaded++:j.skipped++,j.byFormat.svg=(j.byFormat.svg??0)+1;let oe=[...de,...k],Re=l4(n,b);Re==="no-pubspec"&&a.push("pubspec.yaml not found \u2014 asset directory was NOT registered. Add it manually.");let bt=new Map;for(let B of oe)B.status!=="failed"&&B.flutterPath&&B.sourceUrl&&bt.set(B.sourceUrl,B.flutterPath);my(h,bt);let Ve=oe.filter(B=>B.token.startsWith("dsl.styles.paint_")&&B.status!=="failed"&&!!B.flutterPath).map(B=>B.flutterPath),ae=d4(h,Ve);j.recovered=ae,j.lost=Math.max(0,j.lost-ae),ae>0&&a.push(`Recovered ${ae} lost image placeholder(s) via DSL styles paint fallback.`);let yt=l.slice(ae);gt.default.writeFileSync(m,JSON.stringify(h,null,2));let V=qt.default.join(p,"flutter-component-workflow.md");gt.default.existsSync(V)||gt.default.writeFileSync(V,E$);let At=qt.default.join(p,"assets-manifest.json"),Zt={fileId:r,layerId:o,featureName:x,generatedAt:new Date().toISOString(),summary:j,assets:oe.map(B=>({token:B.token,sourceUrl:B.sourceUrl,localPath:B.localPath,flutterPath:B.flutterPath,format:B.format,status:B.status,...B.needsColorFilter!==void 0?{needsColorFilter:B.needsColorFilter}:{},...B.error?{error:B.error}:{}})),lostImageRefs:yt};gt.default.writeFileSync(At,JSON.stringify(Zt,null,2));let Vn=b,Pe=yt.length>0?`WARNING: ${yt.length} image references were LOST by the MasterGo upstream (cssCode contains url([object Object])). These cannot be recovered from the style API. Affected node IDs: ${Array.from(new Set(yt.map(B=>B.nodeId))).slice(0,20).join(", ")}${yt.length>20?" \u2026":""}. Use placeholder widgets (Container with grey background + Icon) or ask the user to re-export via mcp__getD2c for those nodes.`:null;return{content:[{type:"text",text:JSON.stringify({files:{workflow:V,componentSpec:m,assetDir:d,flutterAssetDir:w,assetManifest:At},assetSummary:j,failedAssets:c,lostImageRefs:yt.slice(0,50),warnings:a,message:`Flutter component files created. ${j.downloaded} downloaded, ${j.skipped} skipped, ${j.failed} failed, ${j.recovered} recovered, ${j.lost} still lost. Assets copied to ${b}/${Re==="added"?" and registered in pubspec.yaml.":Re==="exists"?"; pubspec entry already present.":"; pubspec.yaml NOT updated (file missing)."}`,rules:[`Follow the Flutter component workflow process defined in file://${V} for structured Flutter development. This workflow contains DSL-to-Flutter mapping rules, you'll need to read it carefully.`,`Implement the Flutter widget according to the specifications in file://${m}, ensuring all properties and states are properly handled.`,`All image URLs in the component spec have been replaced with Flutter asset paths under ${Vn}/. Use Image.asset()/SvgPicture.asset() with these paths directly.`,"SVG icons with needsColorFilter=true should use SvgPicture.asset with ColorFilter.mode(..., BlendMode.srcIn); those with needsColorFilter=false should render without color override.",`An asset manifest is available at file://${At} listing every resource and its status (downloaded/skipped/failed/lost).`,"Use flutter_screenutil for screen adaptation: width/height/padding/margin/radius use .w; font sizes use .sp.","Use standard Flutter Color(0xFFxxxxxx) for colors. Do NOT create custom color utility classes.",...c.length>0?[`WARNING: ${c.length} assets failed to download. See failedAssets for details; substitute placeholders.`]:[],...Pe?[Pe]:[]]})}]}}};var Yi={name:"@mastergo/magic-mcp",version:"0.2.4",description:"MasterGo MCP standalone service",homepage:"https://github.com/mastergo-design/mastergo-magic-mcp#readme",repository:{type:"git",url:"git+https://github.com/mastergo-design/mastergo-magic-mcp.git"},bugs:{url:"https://github.com/mastergo-design/mastergo-magic-mcp/issues"},main:"dist/index.js",bin:{"mastergo-magic-mcp":"dist/index.js"},files:["dist/**/*","!**/*.map","!**/.DS_Store","!**/.idea","!**/.vscode"],engines:{node:">=18"},scripts:{build:"node build.js","build:watch":"node build.js --watch",lint:"eslint src --ext .ts","lint:fix":"eslint src --ext .ts --fix",test:"esbuild test/format.test.ts test/headers.test.ts test/url-safety.test.ts --bundle --platform=node --format=cjs --outdir=.test --out-extension:.js=.cjs && node --test .test/format.test.cjs .test/headers.test.cjs .test/url-safety.test.cjs",start:"node dist/index.js --token=test --url=http://localhost:3000 --debug",prepare:"npm run build",prepublishOnly:"npm run build"},keywords:["mastergo","mcp","ai"],author:"",license:"ISC",private:!1,dependencies:{"@modelcontextprotocol/sdk":"^1.6.1",axios:"1.18.1","https-proxy-agent":"^9.0.0","js-yaml":"^4.2.0",zod:"^3.22.4"},devDependencies:{"@types/js-yaml":"^4.0.9","@types/node":"^20.8.10","@typescript-eslint/eslint-plugin":"^8.62.0","@typescript-eslint/parser":"^8.62.0",esbuild:"^0.25.1","esbuild-plugin-tsc":"^0.5.0",eslint:"^8.57.1",prettier:"^3.0.3","ts-node":"^10.9.1",typescript:"^5.2.2"},overrides:{hono:"^4.12.27","form-data":"^4.0.6","fast-uri":"^3.1.2","ip-address":"^10.2.0",qs:"^6.15.3"},packageManager:"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"};var h4=`version_${Yi.version.replace(/\./g,"_")}`,g4=`the current version is ${Yi.version}`,hu=class extends ht{constructor(){super();this.name=h4;this.description=g4;this.schema=Y.object({})}async execute(){return{content:[{type:"text",text:JSON.stringify(Yi.version)}]}}};var y4="mcp__getDesignSections",x4=`
|
|
1256
1256
|
[PRIMARY] This is the main tool for all designs. Operates in TWO modes:
|
|
1257
1257
|
|
|
1258
1258
|
Mode 1 \u2014 Get layout overview (sectionIndex NOT provided):
|
|
@@ -1319,7 +1319,7 @@ You can provide either:
|
|
|
1319
1319
|
2. a short link (like https://{domain}/goto/LhGgBAK)
|
|
1320
1320
|
|
|
1321
1321
|
IMPORTANT: Call this tool with the COMPLETE code string. After the tool writes the file, you are DONE \u2014 do NOT output or edit the code further.
|
|
1322
|
-
`,xu=class extends ht{constructor(){super();this.name=w4;this.description=S4;this.schema=Y.object({fileId:Y.string().optional().describe("MasterGo design file ID. Required if shortLink is not provided. Must match the fileId used in getDesignSections."),layerId:Y.string().optional().describe("Root layer ID of the design. Required if shortLink is not provided. Must match the layerId used in getDesignSections."),sourceLayerId:Y.string().optional().describe("Source layer ID from URL parameter source_layer_id. When provided, use this instead of layerId for all queries."),shortLink:Y.string().optional().describe("Short link (like https://{domain}/goto/LhGgBAK)."),code:Y.string().describe("The COMPLETE generated code containing @@SVG:{svgKey}@@ and/or T{sectionIndex}|{nodeId} placeholders."),outDir:Y.string().describe("Output directory where the final file will be written. The finalized code (with all placeholders replaced by real data) is written directly to this directory \u2014 do NOT re-output or edit the code after this tool runs. Example: '/Users/you/project/output' or './output'."),outputFileName:Y.string().optional().describe("Output file name (default: 'index.html'). Include extension. Example: 'snmp-agent.html'."),targetLang:Y.enum(["html","dart"]).optional().describe("Target language of the generated code, decides placeholder escaping. 'html' (default, also for Vue): SVG inserted as-is into element content, long text HTML-escaped. 'dart' (Flutter): SVG/text escaped for single-quoted string literals (SvgPicture.string('...'), Text('...')).")})}async execute(n){var r,o,i;try{let{fileId:s,layerId:a,sourceLayerId:c,shortLink:l,code:p,outDir:d,outputFileName:f,targetLang:h}=n;if(!l&&(!s||!a&&!c))throw new Error("Either provide fileId with layerId (or sourceLayerId), or provide a shortLink");let y=this.normalizeFileId(s),v=a,x=c;if(l){let Ve=await ot.extractIdsFromUrl(l);y=this.normalizeFileId(Ve.fileId),v=Ve.layerId,x=Ve.sourceLayerId??c}let m=x||v;if(!y||!m)throw new Error("Could not determine fileId or layerId (need layerId or sourceLayerId)");if(typeof p!="string"||!p.trim())throw new Error("code must be a non-empty string of the generated code");if(!d||!d.trim())throw new Error("outDir is required \u2014 the finalized code must be written directly to disk to prevent LLM re-processing");let b=await ot.applyDesign(p,y,m,x,h),w=b.patchedCode;if(typeof w!="string"||!w)throw new Error("Server did not return patchedCode. Check that frontend-mcp-server is up to date.");let k=ar.default.basename((f==null?void 0:f.trim())||"index.html"),E=ar.default.resolve(process.env.MG_OUTPUT_ROOT||process.cwd()),F=ar.default.isAbsolute(d)?ar.default.resolve(d):ar.default.resolve(E,d),j=ar.default.relative(E,F);if(j===".."||j.startsWith(".."+ar.default.sep)||ar.default.isAbsolute(j))throw new Error(`outDir "${d}" resolves outside the allowed output root (${E}). Use a path inside it, or set the MG_OUTPUT_ROOT environment variable to permit a different base.`);let me=F;(0,N$.existsSync)(me)||await(0,vu.mkdir)(me,{recursive:!0});let de=ar.default.join(me,k);await(0,vu.writeFile)(de,w,"utf8"),_$(y,m);let oe=b.report||{},Re={success:!0,filePath:de,fileName:k,report:oe};if(b.warning&&(Re.warning=b.warning),b.error&&(Re.error=b.error),!Re.warning){let Ve=(((r=oe.svgUnresolved)==null?void 0:r.length)||0)+(((o=oe.textUnresolved)==null?void 0:o.length)||0);Ve>0&&(Re.warning=`${Ve} placeholder(s) unresolved \u2014 check svgKey/text keys.`)}let bt=oe.fabricatedPaths??[];return!Re.error&&bt.length>0&&(Re.error=`${bt.length} fabricated path(s) detected \u2014 replace them with @@SVG:{svgKey}@@ placeholders and re-run.`),{content:[{type:"text",text:JSON.stringify(Re)}]}}catch(s){let a=((i=s.response)==null?void 0:i.data)??(s==null?void 0:s.message);return{isError:!0,content:[{type:"text",text:JSON.stringify(a)}]}}}};var k4='\n## MasterGo Design DSL - Section-by-Section Workflow\n\n### Step 0: Get Layout Overview (MANDATORY)\nCall `mcp__getDesignSections` WITHOUT sectionIndex first.\nThe response contains `sections` array with `nodeCount` per section, `totalSections`, and `totalNodes`.\nEach `sections[]` entry ALSO carries a **page-absolute bounding box**: `x`, `y` (top-left corner relative to the root container\'s origin), `width`, `height`. This tells you exactly where each section sits on the canvas.\nUse this to understand the design scope before fetching details.\n\n`rootMetadata` (if present) provides the root layer\'s dimensions (width, height), name, type, and optional fill/styles. Use these as the page frame size and background.\n`splitContainers` (if present) lists containers that were too large and split into child sections. Each entry provides the container\'s name, type, id, x, y, width, height, layout properties (layoutMode, itemSpacing, padding), **and now a `background` color** (resolved hex/css value, e.g. `"#055DDC"`) plus `fill` reference (e.g. `"paint_1:4829"`). Use these to understand how the split sections should be arranged \u2014 they share the container\'s width, layout direction and spacing. IMPORTANT: sections from the same split container MUST share the container\'s width. Apply the container\'s `background` to the parent wrapper that encloses its child sections \u2014 this gives the container its correct visual background without each section needing to carry it.\n\n**Structure grouping** \u2014 Each section entry carries two fields to help you avoid redundant work:\n\n1. **`structureHash`** \u2014 structural fingerprint. Sections with identical hashes have the **exact same node-tree skeleton** (same type tree + layout attributes). Only **leaf values differ** (text, fill colors, icon paths). Fetch the DSL for the **first section in each hash group** and reuse its rendered structure for the rest \u2014 just swap in different text/color/icon values. Sections without a structureHash have unique structures and must be rendered individually.\n\n2. **`containerId`** \u2014 links to a `splitContainers` entry. All sections sharing a containerId inherit that container\'s width, flexDirection, gap, and padding. When wrapping these sections in a parent element, match the container\'s width and layout properties \u2014 don\'t repeat them on each child.\n\n### Step 1: Fetch Each Section DSL (MANDATORY - ALL N sections)\nFor i = 0 to N-1, call `mcp__getDesignSections` with `sectionIndex=i`.\nYou MUST call this tool N times. Do NOT skip any section.\nCRITICAL: Fetch sections in BATCHES of 3-5 at a time. Do NOT request all sections simultaneously \u2014 too many concurrent requests will cause timeouts. Send 3-5 sectionIndex calls, wait for all results, then send the next batch.\n\n### Step 2: Understand SVG Data Model (MANDATORY)\nAfter ALL N sections have been fetched, understand how icons work:\n\n**PATH Nodes \u2014 ALL carry a `svgKey` field:**\nEvery PATH node (icon) in the DSL has a `svgKey` field (a short sequential ID like `#0`, `#1`, `#25`) AND a `svgName` field (a semantic name like `\u901A\u7528/\u5237\u65B0`, `\u901A\u7528/\u5411\u5DE6`, `\u641C\u7D22`, `\u9F7F\u8F6E`). The actual SVG markup is NOT in the DSL \u2014 it lives in a server-side cache, retrieved at the end via `mcp__applyDesign`.\n\n**You do NOT copy SVG markup during code generation.** Instead:\n1. When you encounter a PATH node, note its `svgKey` (for the placeholder) AND its `svgName` (to understand WHAT icon it is and WHERE it should go).\n2. In your generated code, place a placeholder `@@SVG:{svgKey}@@` where the icon goes. Use `svgName` to match each icon to its correct UI position \u2014 e.g. an icon with `svgName: "\u901A\u7528/\u5411\u5DE6"` belongs in a collapse/fold button, not a "add" button.\n3. After the complete code is generated, call `mcp__applyDesign` \u2014 it replaces all placeholders with real high-precision SVG.\n\n**Why this design**: copying SVG path data through LLM generation causes precision loss (17.522848 \u2192 17.52), dropped subpaths, and shape corruption. The placeholder approach ensures path data never passes through generation \u2014 the server does deterministic string substitution.\n\n**CRITICAL \u2014 SVG UNIQUENESS:** Each PATH node has its OWN unique `svgKey` (e.g. `#0`, `#13`). NEVER reuse a svgKey from one PATH node for another \u2014 even if two icons look similar (e.g. two arrow icons), they are DIFFERENT vectors with DIFFERENT svgKeys. Always use the exact `svgKey` from the PATH node where the icon appears.\n\n**Text Data** \u2014 Long text (>50 chars) in the DSL appears as `T{sectionIndex}|{nodeId}` placeholders. These are automatically replaced by `mcp__applyDesign` server-side. Just leave the `T{si}|{nodeId}` placeholder in your code where the text should appear, and applyDesign will inject the real text.\n- Short text already inlined in the DSL (`node.text` / `dsl.rowTexts`) must be inserted VERBATIM \u2014 do NOT paraphrase, translate, summarize, or invent text.\n\n**`dsl.rowTexts`** \u2014 An array of `{text, parentType?, parentName?}` objects for all leaf TEXT values in this section, in tree order. Each item carries `parentType` and `parentName` to indicate which container the text belongs to (e.g. `{text: "8", parentType: "INSTANCE", parentName: "\u5220\u9664"}` means "8" is inside a delete button \u2014 it\'s a badge count, NOT an independent notification dot). Use parentType/parentName for context; do NOT reassign text to unrelated UI elements.\n\n### Step 3: Generate Complete Code\nAfter ALL N sections have been fetched:\n- MANDATORY: Use `rootContainer` from the section list response to create the root container div. Apply ALL its CSS properties (width, minHeight, background, overflow, position:relative) to a wrapping div. ALL sections MUST be placed inside this root container.\n- CRITICAL \u2014 Position each section ABSOLUTELY: every section entry has a page-absolute bbox (x, y, width, height) from Step 0. Wrap each section in a container with `position:absolute; left:{x}px; top:{y}px; width:{width}px` inside the root container. Do NOT reconstruct the page by stacking sections in a flex column with guessed `margin-top` / `gap` values. Many designs are spatially OVERLAID (status bar, title bar, form card, decorative curves, floating text, background layers) and only reconstruct correctly with absolute positioning.\n- CRITICAL \u2014 Overflow clipping: some design elements (brand logos, decorative shapes) are LARGER than their visible area \u2014 the design deliberately clips them via `overflow: hidden` on the parent. When a node\'s `layoutStyle.width/height` is smaller than its SVG content, you MUST preserve this clipping: set the parent container to the node\'s `layoutStyle` dimensions AND add `overflow: hidden`, then let the SVG render at its natural size inside. Do NOT shrink the SVG to fit the container (that distorts the logo) and do NOT enlarge the container (that breaks the layout).\n\n### Step 4: SVG Placeholder Workflow (FINAL step \u2014 MANDATORY)\nEvery icon in the design is a PATH node with a `svgKey`. The SVG markup is NOT in the DSL \u2014 you cannot copy it even if you wanted to. You MUST use placeholders.\n\n**During code generation** \u2014 wherever an icon/SVG should appear, place a placeholder `@@SVG:{svgKey}@@`:\n- Read the `svgKey` from the PATH node in the section DSL.\n- Place `@@SVG:` + that exact svgKey + `@@` where the icon goes.\n- **CRITICAL \u2014 Icon container sizing**: the placeholder MUST be placed inside a container whose width and height match the PATH node\'s `layoutStyle.width` and `layoutStyle.height`. The injected SVG uses `width="100%" height="100%"`, so it fills its direct parent. If you place it directly inside a large button container (e.g. 32\xD732px) instead of the icon\'s own size (e.g. 16\xD716px), the icon will render too large. Always wrap the placeholder in an element sized to the PATH node\'s dimensions:\n - **HTML/Vue**: `<span style="width:{layoutStyle.width}px;height:{layoutStyle.height}px;display:flex;align-items:center;justify-content:center">@@SVG:{svgKey}@@</span>`\n - **JSX/React**: `<span style={{width:\'{w}px\',height:\'{h}px\'}}>{/*@@SVG:{svgKey}@@*/}</span>`\n - **Flutter**: `SizedBox(width:{w},height:{h},child: SvgPicture.string(\'@@SVG:{svgKey}@@\'))`\n- Use `svgName` to match each icon to its correct UI position \u2014 e.g. an icon with `svgName: "\u901A\u7528/\u5411\u5DE6"` belongs in a collapse/fold button, not a "add" button.\n\n**After generating the COMPLETE code** \u2014 call `mcp__applyDesign` with the full code string AND an `outDir` parameter. The tool substitutes every `@@SVG:...@@` with the real high-precision `<svg>` markup from the cache (character-for-character exact, no rounding) AND writes the final file directly to disk. **You MUST provide `outDir`** \u2014 this writes the patched code to a file WITHOUT it passing back through your generation, preventing any re-processing or precision loss. After the tool writes the file, you are DONE \u2014 do NOT output, copy, or edit the code further.\n\n### Intra-Section Layout Rules (node-level positioning):\nEvery node in a section\'s DSL has TWO pieces of layout data:\n\n1. **`flexContainerInfo`** \u2014 If a node HAS this field, it is a flex container. Its direct children are laid out by flex rules, NOT by absolute positioning. Generate CSS: `display: flex; flex-direction: {flexDirection}; justify-content: {justifyContent}; align-items: {alignItems}; gap: {gap}; padding: {padding};`. Do NOT add `position: absolute` or `left/top` to flex container nodes or their direct children.\n\n2. **`layoutStyle.relativeX/relativeY`** \u2014 Use these ONLY for leaf/free nodes that are NOT inside a flex container. For those nodes, apply `position: absolute; left: {relativeX}px; top: {relativeY}px;`.\n\n3. **Nested flex containers** \u2014 A flex container can contain a child that is ALSO a flex container (e.g. a horizontal toolbar with a vertical menu inside). Each level independently uses its own `flexContainerInfo`. **You MUST preserve ALL nesting levels** \u2014 do NOT flatten a two-level flex structure into one. For example, a table header cell where "label + sort-icon" form an inner group and "action-icon" sits at the outer level MUST be rendered as TWO nested flex containers, not one flat flex with all three items side by side. Flattening loses the visual grouping (label+sort tightly paired, action-icon separated) and causes layout breakage.\n\n4. **When a child has `flexGrow` / `flexShrink`** \u2014 These are flex item properties. Apply `flex: {flexGrow} 1 0` on the child element. Do NOT position it absolutely.\n\n5. **CRITICAL \u2014 Flex column with fixed-height children**: When a container uses `flex-direction: column` with a FIXED height and `overflow: hidden`, ALL children with fixed heights (tabs, headers, pagination bars, footers, scrollbars) MUST have `flex-shrink: 0`. Only ONE child \u2014 the flexible content area (table body, scrollable region) \u2014 should use `flex: 1`. If you forget `flex-shrink: 0` on fixed-height children, flex layout will squeeze them out of the visible area and they get clipped by `overflow: hidden` (e.g. pagination bar becomes invisible).\n\n6. **CRITICAL \u2014 Nested FRAME dimensions and spacing**: When a FRAME contains child FRAMEs (e.g. a card panel with an inner content container), the outer element\'s width/height MUST come from the OUTER node\'s `layoutStyle.width/height` \u2014 NOT from the inner content container. A common error is using the inner container\'s width (e.g. 285px) for the card itself (which should be 317px). Always trace to the correct node: if the DSL shows `\u5BB9\u5668A (317\xD7107) > \u5BB9\u5668B (285\xD775, relativeX:16, relativeY:16)`, the rendered card is 317\xD7107 with 16px padding, and the content inside is 285\xD775.\n\n7. **CRITICAL \u2014 Precise vertical positioning inside cards**: Inside small fixed-height containers (stat cards, info panels, badge boxes), do NOT invent `gap` values. Use each child\'s `layoutStyle.relativeY` to position elements precisely. For example, if a card\'s DSL shows child A at `relativeY:0` and child B at `relativeY:32`, the vertical gap is 32px (minus child A\'s height) \u2014 NOT a guessed `gap:16px` or `gap:20px`. Inventing large gaps in small cards pushes content apart and breaks the compact layout. When `flexContainerInfo.gap` is present, use that exact value; when it is absent, use `relativeY` differences to calculate spacing.\n\n8. **CRITICAL \u2014 Overlapping elements in the same container (Switch toggle, icon badges, layered decorations)**: When a container holds multiple sibling elements that visually OVERLAP (one on top of another), the container MUST use `position: relative` and each child MUST use `position: absolute` with its own `layoutStyle.relativeX/relativeY`. Do NOT use `display: flex` on the container \u2014 flex will place the children SIDE BY SIDE instead of overlapping, shrinking them and destroying the composition. The canonical example is a Switch toggle: the DSL shows a track PATH (`relativeX:0, relativeY:0, w:40, h:24`) and a knob circle (`relativeX:17.5, relativeY:1.5, w:21, h:21`) as siblings. Generate EXACTLY this structure:\n```\n<div style="position:relative; width:40px; height:24px;">\n <div style="position:absolute; left:0px; top:0px;">@@SVG:{trackSvgKey}@@</div>\n <div style="position:absolute; left:17.5px; top:1.5px;">@@SVG:{knobSvgKey}@@</div>\n</div>\n```\nEach child\'s `left` and `top` come from that child\'s own `layoutStyle.relativeX` and `layoutStyle.relativeY`. Never use a shared `left:0; top:0` for all children. Never use flex.\n\n9. **Fallback** \u2014 Nodes with NEITHER `flexContainerInfo` NOR being inside a flex container: use `position: absolute; left: {relativeX}px; top: {relativeY}px;`.\n- Generate a single complete HTML file containing ALL sections in order, nested inside the root container.\n- token fields must be generated as CSS variables with comments indicating the token name.\n- If componentDocumentLinks exists, call mcp__getComponentLink to fetch documentation.\n- When splitContainers is present, sections that were split from the same container must share that container\'s width and be wrapped together. **Apply the container\'s `background` to the parent wrapper**: splitContainer entries now include `background` (resolved CSS color) and `fill` (paint reference).\n- CRITICAL \u2014 Table container boundary: when a design has a table (header + data rows), wrap the ENTIRE table area (header row + all data rows + any empty space below the last row down to the pagination) in a single container with the design\'s background color (usually white) and the table\'s border. The table may have only 1 data row but the container must extend to fill the design\'s allocated height \u2014 do NOT leave the area below the last row as page background showing through. The pagination bar sits BELOW this container as a sibling, not inside it.\n\n### Text Provenance Self-Check (MANDATORY before finalizing output):\n- Before writing the final HTML, enumerate every visible text string you plan to emit.\n- For EACH string, verify it exists in `rootMetadata.allTexts` (the section LIST response carries this closed-set whitelist of all text in the design) OR in some section\'s `dsl.rowTexts` / `node.text`.\n- Any string with NO provenance (typical offenders: fabricated column headers like "\u7528\u6237\u540D\u79F0/\u6240\u5C5E\u7EC4/\u8FDC\u7A0BIP", invented cell data like "1.1.3.543.4" or "AES-128", brand-watermark tokens like "Hillstone Design", generic menu labels not in the design) MUST be deleted or replaced with an empty placeholder.\n- If you find yourself generating MORE distinct text strings than `allTexts.length`, STOP and re-check \u2014 you are hallucinating.\n\n### Row Count Self-Check (MANDATORY for tables/lists):\n- For every table, list, or repeated-row section in your output, look up its `structureSiblingCount`. This field appears in BOTH the section list entry AND each section DSL response (top-level `structureSiblingCount`).\n- The number of data rows you render MUST equal `structureSiblingCount`. This is a hard constraint, not a suggestion.\n- `structureSiblingCount: 1` means render EXACTLY 1 data row. Do NOT add rows "for visual density", "to look complete", or "because a pagination label says \u517110\u9879". Pagination labels reflect a UI control state, NOT a data-row count \u2014 they must never inflate the row count.\n- Before outputting any table, verify: count your `<tr>` (data rows, excluding header) \u2192 it MUST equal `structureSiblingCount`. If you rendered more, delete the extras now.\n\n### Tool Selection Rules:\n- `mcp__getDesignSections` is the PRIMARY tool for full-page design-to-code generation. Always start here when you need to generate a complete HTML page from a design.\n- `mcp__extractSvg` is a STANDALONE tool. Use it DIRECTLY when you only need to extract SVG icons from a design \u2014 do NOT call `getDesignSections` before it.\n- `mcp__getDsl` is a FALLBACK \u2014 call it ONLY if `getDesignSections` returns an error (e.g. tool not available on older servers).\n- NEVER call both `getDesignSections` AND `getDsl` for the same design.\n- NEVER combine the section workflow with `extractSvg`. If you only need SVG icons, use `extractSvg` alone. If you need a full page, use the section workflow (which uses `@@SVG:{svgKey}@@` placeholders + `mcp__applyDesign` for SVG data).\n- The section workflow provides COMPLETE data. Do NOT call `getDsl` to "verify".\n\n### Output Format:\n- The design-data tools (`getDesignSections`, `getDsl`, `extractSvg`, `getMeta`) accept an optional `format` parameter: `json` (default), `yaml`, or `tree`. `yaml`/`tree` use fewer tokens for large designs; all three round-trip without data loss. Set a session-wide default with the `--format` CLI flag or `DEFAULT_FORMAT` env var.\n\n### Text Fidelity Rules:\n- TEXT nodes contain actual text in node.text array. Read EACH node\'s text and use it EXACTLY.\n- Do NOT duplicate text from one node to another \u2014 each TEXT node has unique content.\n- Do NOT skip any child nodes. Render ALL nodes: every tab, every button, every text element.\n\n### Background & Color Rules:\n- **PREFER the `_color` field**: every node with a resolved fill carries a `_color` field containing the computed CSS hex/rgb value. Use this value DIRECTLY in CSS \u2014 no styles-table lookup needed. Example: `color: #4E5969` from `"_color": "#4E5969"`.\n- The `fill` field (e.g. `paint_1:7200`) remains for reference. Use `_token` (e.g. `"Text/Text-4"`) for CSS variable naming like `var(--text-text-4, #4E5969)`.\n- If a node has both `_color` and `fill`, `_color` is authoritative for the visual color value.\n- The DSL `styles` map contains fill/stroke style definitions. Use the node\'s `fillStyleId`/`strokeStyleId` to look up the actual color from `styles`.\n- The root/frame node\'s background comes from its fill style. Do NOT invent gradient or solid backgrounds \u2014 use ONLY the colors from the DSL data.\n- If a node has no fill or the fill style is empty/transparent, do NOT add a background color. Leave it transparent or inherit from parent.\n- Status bar, title bar, and other container backgrounds MUST match the DSL fill data exactly.\n- **NEVER hardcode LLM-default colors** (e.g. `#1D2129`, `#000`, `#333`) when `_color` is present. The `_color` value is the design truth \u2014 copying it requires zero cognitive effort and zero styles-table lookup.\n- **CRITICAL \u2014 splitContainers[].background IS the exact CSS background-color.** Copy it verbatim: `background-color: <value>;`. MUST NOT add gradients, MUST NOT change the color. The designer chose this color deliberately.\n- **CRITICAL \u2014 OPACITY ON FRAME**: a FRAME\'s `opacity` field applies ONLY to its own background, NOT children. Use `background-color: rgba(R, G, B, <opacity>)` \u2014 NEVER use CSS `opacity: X` on the parent, which makes child text/icons translucent.\n- **CRITICAL \u2014 NEVER promote a child node\'s gradient/fill onto its parent container.** A gradient `linear-gradient(...)` in the DSL is computed against THAT node\'s own bounding box \u2014 its stop offsets (e.g. `#0063BA 83%`) are percentages of that specific node\'s height, NOT the parent\'s height. If you copy such a gradient onto a differently-sized parent (e.g. a 88px navbar that contains a 195px-tall decorative oval), the stops map to the WRONG size and the visible color shifts or disappears entirely (blue appears only in the bottom 15px, leaving the top transparent). Rules:\n - The background/fill of a node applies to THAT node\'s element only, at THAT node\'s size. Render each node at its own `layoutStyle.width/height`.\n - A FRAME/GROUP/INSTANCE with NO `_color`/`fill` (empty) has NO background \u2014 leave it transparent. Do NOT borrow a child\'s fill to fill the parent.\n - Decorative layers with `filter: blur(...)` (e.g. `filter: blur(81.6px)`) or very low alpha (`rgba(..., 0.0x)`) are visual overlay accents (glow, bloom), NOT the container\'s base background. Keep them as positioned overlays inside the container \u2014 never extract their gradient as the container background.\n - If a container (navbar, card, header) needs a solid base background that the DSL doesn\'t directly provide on the FRAME node, derive it from the dominant opaque color among its children (e.g. the most common solid `_color`), not from a decorative gradient overlay.\n\n### Anti-Hallucination Rules:\n- You MUST use EXACT text content from the DSL data. NEVER invent, translate, or paraphrase text.\n- If a section has empty or missing text data, render it as an empty placeholder \u2014 do NOT fabricate text.\n- NEVER generate placeholder values, generic tags, fabricated amounts, or invented statistics.\n- Every piece of text, every number, every label in your output MUST come directly from the DSL data.\n- NEVER fabricate SVG path data for icons or vector shapes \u2014 use `@@SVG:{svgKey}@@` placeholders for ALL icons, then call `mcp__applyDesign`.\n- NEVER fabricate background colors, gradients, or decorations that are not present in the DSL data.\n\n### Empty Design Tolerance Rules (CLOSED-SET TEXT):\n- Many designs are UNFINISHED wireframes or component-library showcases with sparse text. This is NORMAL, not missing data.\n- The ONLY allowed text strings in your output are those present in `dsl.rowTexts` or `node.text` of some fetched section. The section list response carries `rootMetadata.allTexts` \u2014 the complete closed set of text strings in this design. Treat it as a whitelist: any string NOT in allTexts is a hallucination and MUST be removed.\n- Sparse text is especially common when the design reuses a component library: the design itself may have only ~10 distinct text strings total, even though the rendered page looks dense. Do NOT infer more content from visual density or the page\'s apparent purpose.\n- If a section has `textTotal=0` or empty `rowTexts`, render its STRUCTURE with EMPTY placeholders (`<td></td>`, blank labels, empty menu items) \u2014 do NOT invent column headers, menu item labels, IP addresses, algorithm names, or any data values to fill it.\n- A table with 1 data row in the DSL renders as 1 data row in HTML. Do NOT pad with fabricated rows. Pagination labels like "\u5171 10 \u9879" reflect a UI control state, NOT a data-row count \u2014 never synthesize rows to match them.\n- Brand-name leakage is forbidden: do NOT generate library/watermark tokens (e.g. "Hillstone Design", "Ant Design", "Material UI") even if they appear in component node names or you recognize the brand from training data. Only render text that appears in the design\'s own TEXT nodes.\n- When in doubt about whether a text string is real: it is NOT real unless you can cite the sectionIndex it came from.\n\n### SVG Icon Anti-Simplification Rules:\n- PATH nodes carry a `svgKey` \u2014 the SVG markup is injected by `mcp__applyDesign` at the end. You MUST use `@@SVG:{svgKey}@@` placeholders \u2014 never hand-write `<path d="...">`.\n- **SVG UNIQUENESS:** Each icon in the DSL is a distinct design artifact \u2014 different sections may have DIFFERENT icons even if they look similar (e.g. "\u641C\u7D22" in section 2 vs "\u641C\u7D22" in section 40 are DIFFERENT SVGs). NEVER reuse a `svgKey` from one section in another. Always use the exact `svgKey` from the PATH node in its own section.\n- **NEVER substitute vector paths with simplified shapes** \u2014 a `<path>` containing a house icon is NOT replaceable by a `<rect>` + `<polygon>`. The designer chose every anchor point; your simplified version WILL look different.\n- **VERIFY after copying each SVG**: count the number of `M` characters in the source path `d` attribute. Your copy MUST have exactly the same count. Fewer `M` \u2192 you corrupted the icon \u2192 redo.\n- **SHAPE CHECK**: if the source uses `<path>`, your output MUST use `<path>`. NOT `<rect>`, NOT `<circle>`, NOT `<ellipse>`. Shape type changes ARE visual changes.\n- The only acceptable SVG operation is: copy the complete `<svg>...</svg>` block from the DSL data and paste it into your HTML. Nothing else.\n- **Common failure pattern**: you saw a complex path and thought "this looks roughly like 4 rectangles" \u2192 you drew 4 `<rect>`s \u2192 the result is visually WRONG. The designer chose a vector path for a reason. Trust the data.\n- **COMPOSITE ICONS (logos, multi-subpath marks):** when a logo/brand mark is split into multiple sub-paths and stripped to svgCache, the SVG that `mcp__applyDesign` injects for the `@@SVG:{svgKey}@@` placeholder is the complete `<svg>...</svg>`. Keep it whole. The node\'s `relativeX`/`relativeY` are canvas placement coordinates \u2014 they are NOT to be reused as `transform="translate(x,y) scale(...)"` inside a hand-assembled `<svg>`. Doing so warps the glyph out of its viewBox.\n\n### INSTANCE Variant State Rules:\n- INSTANCE nodes may carry a **`_variantProps`** object with semantic state labels extracted from component variant properties (e.g. `{"\u72B6\u6001": "\u9009\u4E2D", "\u5206\u7C7B": "\u5E7D\u7075\u6309\u94AE", "\u5C3A\u5BF8": "24"}`).\n- **Active/selected state**: compare `_variantProps` across sibling INSTANCE nodes to find which one has `"\u72B6\u6001": "\u9009\u4E2D"` or similar active-state values. Apply the `.active` CSS class ONLY to that node \u2014 NEVER default to the first item in a list.\n- **Sidebar menu items**: each menu item (e.g. 22 submenu entries) is a separate section containing an INSTANCE with `_variantProps`. The item with `"\u72B6\u6001": "\u9009\u4E2D"` in its `_variantProps` is the currently active page \u2014 the corresponding section\'s `rowTexts[0]` (or TEXT child) is its label. Render this item with `class="submenu-item active"`.\n- **Button states**: `"\u5206\u7C7B": "\u5E7D\u7075\u6309\u94AE"` vs `"\u5206\u7C7B": "\u4E3B\u8981\u6309\u94AE"` determines the button\'s visual style (outline vs filled). Multiple buttons in the same toolbar may have different variant props \u2014 respect each one individually.\n- If `_variantProps` is absent from all siblings, assume all are in `default` state \u2014 do NOT invent active states.\n\n### Repeat / Row-Count Rules:\n- Each section entry carries `structureSiblingCount` = the exact number of times this structure appears in the design.\n- For data/table sections: the number of rendered rows MUST equal `structureSiblingCount`. A count of 1 means ONE row total \u2014 do not pad with fabricated rows "for visual density" or "to fill the table". The single row in the DSL IS the complete dataset.\n- For `structureSiblingCount >= 2`: reuse the `structureHash` template, render exactly that many instances, swap per-instance text/colors from each section\'s own data.\n- Pagination controls, "load more" buttons, and empty-state rows are CONTROLS, not data rows \u2014 never counted toward the dataset.\n\n### Placeholder Text Rules:\n- TEXT nodes may carry `_placeholder: true`. This flag marks text whose node name equals its content \u2014 the universal signature of component-library placeholder text (the slot name WAS the placeholder string, e.g. `{name: "Hillstone Design", text: "Hillstone Design"}`). This works across ALL component libraries without brand-specific tokens.\n- `_placeholder: true` is a HINT, not a deletion. Read the surrounding context: if the flagged text does not map to a real column header, label, or content slot in this specific design, treat it as boilerplate and omit it. If it does map to real content, render it normally.\n- Never blanket-render every `_placeholder` text as visible headers/columns.\n\n### Data Completeness Rules:\n- You MUST fetch ALL sections (0..totalSections-1). If totalSections=48, you must call sectionIndex=0 through 47 \u2014 no exceptions.\n- Some sections may have nodeCount=3 and no visible TEXT nodes (text is in component property overrides). Do NOT skip them \u2014 the TEXT is resolved during DSL transfer. These sections contribute real content.\n- **textPreview**: each section list entry carries a `textPreview` field (first TEXT node found, truncated to 20 chars). If two sections both have nodeCount=3 and empty name, use `textPreview` to tell them apart \u2014 they are different menu items (e.g. "\u7CFB\u7EDF\u4FE1\u606F" / "\u6743\u9650\u8BBE\u7F6E"), NOT duplicates.\n- Keep a checklist: track which section indices have been requested. Do not stop until every index 0..N-1 has been fetched.\n- If you accidentally skipped a section, go back and request the missing indices. An incomplete section set WILL cause missing content in the final HTML.\n\n\n\n### Critical Rendering Checklist (MANDATORY \u2014 verify each item before finalizing):\nBefore declaring the HTML complete, enumerate every structural element below and confirm it is rendered. Missing ANY item is a fidelity defect.\n\n1. **Sidebar menu item icons**: each sidebar menu section carries a PATH icon with a `svgKey`. Did you place `@@SVG:{svgKey}@@` for each? If you used a `<rect>` or `<circle>` or hand-wrote `<path d="...">`, DELETE it \u2014 the DSL does NOT contain path data. Use the placeholder.\n\n2. **Table header column icons** (sort/filter/search): each table header cell may carry sort-arrow, filter-funnel, and search-lens PATH icons. Did you place `@@SVG:{svgKey}@@` for each? If a header cell has no icons, you may have skipped them.\n\n3. **Pagination icons** (refresh, prev/next arrows, dropdown): the pagination section has MULTIPLE PATH icons. Did you place `@@SVG:{svgKey}@@` for EACH one?\n\n4. **Brand/logo area text**: the brand section has a TEXT node with the actual brand name (present in `allTexts`). Did you render it as visible text?\n\n5. **Every PATH node has a placeholder**: walk through every section\'s DSL \u2014 every PATH node must have a corresponding `@@SVG:{svgKey}@@` in your code. Count: the number of `@@SVG:` placeholders in your code MUST equal the total number of PATH nodes across all sections.\n\n6. **Text provenance**: every text string in your output MUST be traceable to `rootMetadata.allTexts` or a section\'s `dsl.rowTexts`/`node.text`. If you cannot cite the exact source, the text is a hallucination \u2014 delete it.\n\n7. **SVG placeholder replacement (HARD GATE)**: your HTML is INVALID and must NOT be output until you have called `mcp__applyDesign` with the complete code and used the returned `patchedCode`. This is not optional \u2014 it is the FINAL mandatory step. If you wrote ANY `<path d="...">` by hand instead of using `@@SVG:{svgKey}@@` placeholders, the `mcp__applyDesign` tool will detect it as a FABRICATED path and return an error. You MUST then replace those hand-written paths with placeholders and call `mcp__applyDesign` again. The ONLY acceptable output is the `patchedCode` returned by `mcp__applyDesign` \u2014 never your pre-replacement code.\n\nIf any item above is unchecked, your HTML is INCOMPLETE. Fix it before outputting.\n\n### Data Interpretation Rules:\n- Pagination/table-footer labels (e.g. "\u5171 10 \u9879", "X rows/page", "items per page") reflect UI control state \u2014 NOT data to replicate.\n- "\u5171 X \u9879" is the pagination widget showing "total X items". The actual data rows come from the table body sections (preceding the pagination section).\n- Do NOT fabricate data rows based on pagination "total" values. Render ONLY the actual data rows present in the DSL.\n- If the DSL contains 1 data row, output exactly 1 table row. Do NOT multiply rows to match a pagination label.\n- **CRITICAL \u2014 SVG icons for table actions**: table action columns (\u64CD\u4F5C\u5217) use PATH icon nodes with `svgKey` fields. Place `@@SVG:{svgKey}@@` for each action button. NEVER render action buttons as `<p>\u7F16\u8F91</p>` or `<p>\u5220\u9664</p>` plain text or hand-drawn shapes.\n- **CRITICAL \u2014 Persistent sidebars**: render all sidebar levels as static visible columns positioned via splitContainers coordinates. Do NOT hide or toggle sidebar levels.\n- **CRITICAL \u2014 NEVER reuse an SVG from one section in another**: each icon position has its OWN `svgKey` (e.g. `#5`) in the DSL. A collapse/fold button icon is a DIFFERENT vector from a menu navigation arrow even if both look like arrows. You MUST use the exact `svgKey` from the PATH node where the icon appears \u2014 never use a svgKey from a different PATH node.\n';function T4(){let{token:t,baseUrl:e,rules:n,debug:r,noRule:o,proxy:i,format:s}=hE();if(s!==void 0){let c=iu(s);c?process.env.DEFAULT_FORMAT=c:console.warn(`Invalid --format value: "${s}". Must be one of: json, yaml, tree. Falling back to json.`)}if(r){process.env.DEBUG="true",console.log("Debug information:"),console.log(`Token: ${t?"set":"not set"}`),console.log(`API URL: ${e||"default"}`),console.log(`Rules: ${n.length>0?n.join(", "):"none"}`),console.log(`No Rule: ${o?"enabled":"disabled"}`),console.log(`Proxy: ${i||"none"}`);let c=Xl();console.log(`Custom Headers: ${Object.keys(c).length>0?JSON.stringify(mE(c)):"none"}`),console.log(`Format: ${process.env.DEFAULT_FORMAT||"json (default)"}`),console.log("Debug mode: enabled")}let a=new vl({name:"MasterGoMcpServer",version:Yi.version},{instructions:k4});new hu().register(a),new gu().register(a),new au().register(a),new lu().register(a),new uu().register(a),new pu().register(a),new du().register(a),new fu().register(a),new mu().register(a),new yu().register(a),new xu().register(a),a.connect(new _l)}T4();
|
|
1322
|
+
`,xu=class extends ht{constructor(){super();this.name=w4;this.description=S4;this.schema=Y.object({fileId:Y.string().optional().describe("MasterGo design file ID. Required if shortLink is not provided. Must match the fileId used in getDesignSections."),layerId:Y.string().optional().describe("Root layer ID of the design. Required if shortLink is not provided. Must match the layerId used in getDesignSections."),sourceLayerId:Y.string().optional().describe("Source layer ID from URL parameter source_layer_id. When provided, use this instead of layerId for all queries."),shortLink:Y.string().optional().describe("Short link (like https://{domain}/goto/LhGgBAK)."),code:Y.string().describe("The COMPLETE generated code containing @@SVG:{svgKey}@@ and/or T{sectionIndex}|{nodeId} placeholders."),outDir:Y.string().describe("Output directory where the final file will be written. The finalized code (with all placeholders replaced by real data) is written directly to this directory \u2014 do NOT re-output or edit the code after this tool runs. Example: '/Users/you/project/output' or './output'."),outputFileName:Y.string().optional().describe("Output file name (default: 'index.html'). Include extension. Example: 'snmp-agent.html'."),targetLang:Y.enum(["html","dart"]).optional().describe("Target language of the generated code, decides placeholder escaping. 'html' (default, also for Vue): SVG inserted as-is into element content, long text HTML-escaped. 'dart' (Flutter): SVG/text escaped for single-quoted string literals (SvgPicture.string('...'), Text('...')).")})}async execute(n){var r,o,i;try{let{fileId:s,layerId:a,sourceLayerId:c,shortLink:l,code:p,outDir:d,outputFileName:f,targetLang:h}=n;if(!l&&(!s||!a&&!c))throw new Error("Either provide fileId with layerId (or sourceLayerId), or provide a shortLink");let y=this.normalizeFileId(s),v=a,x=c;if(l){let Ve=await ot.extractIdsFromUrl(l);y=this.normalizeFileId(Ve.fileId),v=Ve.layerId,x=Ve.sourceLayerId??c}let m=x||v;if(!y||!m)throw new Error("Could not determine fileId or layerId (need layerId or sourceLayerId)");if(typeof p!="string"||!p.trim())throw new Error("code must be a non-empty string of the generated code");if(!d||!d.trim())throw new Error("outDir is required \u2014 the finalized code must be written directly to disk to prevent LLM re-processing");let b=await ot.applyDesign(p,y,m,x,h),w=b.patchedCode;if(typeof w!="string"||!w)throw new Error("Server did not return patchedCode. Check that frontend-mcp-server is up to date.");let k=ar.default.basename((f==null?void 0:f.trim())||"index.html"),E=ar.default.resolve(process.env.MG_OUTPUT_ROOT||process.cwd()),F=ar.default.isAbsolute(d)?ar.default.resolve(d):ar.default.resolve(E,d),j=ar.default.relative(E,F);if(j===".."||j.startsWith(".."+ar.default.sep)||ar.default.isAbsolute(j))throw new Error(`outDir "${d}" resolves outside the allowed output root (${E}). Use a path inside it, or set the MG_OUTPUT_ROOT environment variable to permit a different base.`);let me=F;(0,N$.existsSync)(me)||await(0,vu.mkdir)(me,{recursive:!0});let de=ar.default.join(me,k);await(0,vu.writeFile)(de,w,"utf8"),_$(y,m);let oe=b.report||{},Re={success:!0,filePath:de,fileName:k,report:oe};if(b.warning&&(Re.warning=b.warning),b.error&&(Re.error=b.error),!Re.warning){let Ve=(((r=oe.svgUnresolved)==null?void 0:r.length)||0)+(((o=oe.textUnresolved)==null?void 0:o.length)||0);Ve>0&&(Re.warning=`${Ve} placeholder(s) unresolved \u2014 check svgKey/text keys.`)}let bt=oe.fabricatedPaths??[];return!Re.error&&bt.length>0&&(Re.error=`${bt.length} fabricated path(s) detected \u2014 replace them with @@SVG:{svgKey}@@ placeholders and re-run.`),{content:[{type:"text",text:JSON.stringify(Re)}]}}catch(s){let a=((i=s.response)==null?void 0:i.data)??(s==null?void 0:s.message);return{isError:!0,content:[{type:"text",text:JSON.stringify(a)}]}}}};var k4='\n## MasterGo Design DSL - Section-by-Section Workflow\n\n### Step 0: Get Layout Overview (MANDATORY)\nCall `mcp__getDesignSections` WITHOUT sectionIndex first.\nThe response contains `sections` array with `nodeCount` per section, `totalSections`, and `totalNodes`.\nEach `sections[]` entry ALSO carries a **page-absolute bounding box**: `x`, `y` (top-left corner relative to the root container\'s origin), `width`, `height`. This tells you exactly where each section sits on the canvas.\nUse this to understand the design scope before fetching details.\n\n`rootMetadata` (if present) provides the root layer\'s dimensions (width, height), name, type, and optional fill/styles. Use these as the page frame size and background.\n`splitContainers` (if present) lists containers that were too large and split into child sections. Each entry provides the container\'s name, type, id, x, y, width, height, layout properties (layoutMode, itemSpacing, padding), **and now a `background` color** (resolved hex/css value, e.g. `"#055DDC"`) plus `fill` reference (e.g. `"paint_1:4829"`). Use these to understand how the split sections should be arranged \u2014 they share the container\'s width, layout direction and spacing. IMPORTANT: sections from the same split container MUST share the container\'s width. Apply the container\'s `background` to the parent wrapper that encloses its child sections \u2014 this gives the container its correct visual background without each section needing to carry it.\n\n**Structure grouping** \u2014 Each section entry carries two fields to help you avoid redundant work:\n\n1. **`structureHash`** \u2014 structural fingerprint. Sections with identical hashes have the **exact same node-tree skeleton** (same type tree + layout attributes). Only **leaf values differ** (text, fill colors, icon paths). Fetch the DSL for the **first section in each hash group** and reuse its rendered structure for the rest \u2014 just swap in different text/color/icon values. Sections without a structureHash have unique structures and must be rendered individually.\n\n2. **`containerId`** \u2014 links to a `splitContainers` entry. All sections sharing a containerId inherit that container\'s width, flexDirection, gap, and padding. When wrapping these sections in a parent element, match the container\'s width and layout properties \u2014 don\'t repeat them on each child.\n\n### Step 1: Fetch Each Section DSL (MANDATORY - ALL N sections)\nFor i = 0 to N-1, call `mcp__getDesignSections` with `sectionIndex=i`.\nYou MUST call this tool N times. Do NOT skip any section.\nCRITICAL: Fetch sections in BATCHES of 3-5 at a time. Do NOT request all sections simultaneously \u2014 too many concurrent requests will cause timeouts. Send 3-5 sectionIndex calls, wait for all results, then send the next batch.\n\n### Step 2: Understand SVG Data Model (MANDATORY)\nAfter ALL N sections have been fetched, understand how icons work:\n\n**PATH Nodes \u2014 ALL carry a `svgKey` field:**\nEvery PATH node (icon) in the DSL has a `svgKey` field (e.g. `S3:\u5587\u53ED-\u8F6C\u66F2|31:5068`) AND a `svgName` field (a semantic name like `\u901A\u7528/\u5237\u65B0`, `\u901A\u7528/\u5411\u5DE6`, `\u641C\u7D22`, `\u9F7F\u8F6E`). The actual SVG markup is NOT in the DSL \u2014 it lives in a server-side cache, retrieved at the end via `mcp__applyDesign`.\n\n**You do NOT copy SVG markup during code generation.** Instead:\n1. When you encounter a PATH node, note its `svgKey` (for the placeholder) AND its `svgName` (to understand WHAT icon it is and WHERE it should go).\n2. In your generated code, place a placeholder `@@SVG:{svgKey}@@` where the icon goes. Use `svgName` to match each icon to its correct UI position \u2014 e.g. an icon with `svgName: "\u901A\u7528/\u5411\u5DE6"` belongs in a collapse/fold button, not a "add" button.\n3. After the complete code is generated, call `mcp__applyDesign` \u2014 it replaces all placeholders with real high-precision SVG.\n\n**Why this design**: copying SVG path data through LLM generation causes precision loss (17.522848 \u2192 17.52), dropped subpaths, and shape corruption. The placeholder approach ensures path data never passes through generation \u2014 the server does deterministic string substitution.\n\n**CRITICAL \u2014 SVG UNIQUENESS:** Each PATH node has its OWN unique `svgKey` (e.g. `S0:\u901A\u7528/\u7F16\u8F91|1:5454`, `S3:\u5587\u53ED-\u8F6C\u66F2|31:5068`). NEVER reuse a svgKey from one PATH node for another \u2014 even if two icons look similar (e.g. two arrow icons), they are DIFFERENT vectors with DIFFERENT svgKeys. Always use the exact `svgKey` from the PATH node where the icon appears.\n\n**Text Data** \u2014 Long text (>50 chars) in the DSL appears as `T{sectionIndex}|{nodeId}` placeholders. These are automatically replaced by `mcp__applyDesign` server-side. Just leave the `T{si}|{nodeId}` placeholder in your code where the text should appear, and applyDesign will inject the real text.\n- Short text already inlined in the DSL (`node.text` / `dsl.rowTexts`) must be inserted VERBATIM \u2014 do NOT paraphrase, translate, summarize, or invent text.\n\n**`dsl.rowTexts`** \u2014 An array of `{text, parentType?, parentName?}` objects for all leaf TEXT values in this section, in tree order. Each item carries `parentType` and `parentName` to indicate which container the text belongs to (e.g. `{text: "8", parentType: "INSTANCE", parentName: "\u5220\u9664"}` means "8" is inside a delete button \u2014 it\'s a badge count, NOT an independent notification dot). Use parentType/parentName for context; do NOT reassign text to unrelated UI elements.\n\n### Step 3: Generate Complete Code\nAfter ALL N sections have been fetched:\n- MANDATORY: Use `rootContainer` from the section list response to create the root container div. Apply ALL its CSS properties (width, minHeight, background, overflow, position:relative) to a wrapping div. ALL sections MUST be placed inside this root container.\n- CRITICAL \u2014 Position each section ABSOLUTELY: every section entry has a page-absolute bbox (x, y, width, height) from Step 0. Wrap each section in a container with `position:absolute; left:{x}px; top:{y}px; width:{width}px` inside the root container. Do NOT reconstruct the page by stacking sections in a flex column with guessed `margin-top` / `gap` values. Many designs are spatially OVERLAID (status bar, title bar, form card, decorative curves, floating text, background layers) and only reconstruct correctly with absolute positioning.\n- CRITICAL \u2014 Overflow clipping: some design elements (brand logos, decorative shapes) are LARGER than their visible area \u2014 the design deliberately clips them via `overflow: hidden` on the parent. When a node\'s `layoutStyle.width/height` is smaller than its SVG content, you MUST preserve this clipping: set the parent container to the node\'s `layoutStyle` dimensions AND add `overflow: hidden`, then let the SVG render at its natural size inside. Do NOT shrink the SVG to fit the container (that distorts the logo) and do NOT enlarge the container (that breaks the layout).\n\n### Step 4: SVG Placeholder Workflow (FINAL step \u2014 MANDATORY)\nEvery icon in the design is a PATH node with a `svgKey`. The SVG markup is NOT in the DSL \u2014 you cannot copy it even if you wanted to. You MUST use placeholders.\n\n**During code generation** \u2014 wherever an icon/SVG should appear, place a placeholder `@@SVG:{svgKey}@@`:\n- Read the `svgKey` from the PATH node in the section DSL.\n- Place `@@SVG:` + that exact svgKey + `@@` where the icon goes.\n- **CRITICAL \u2014 Icon container sizing**: the placeholder MUST be placed inside a container whose width and height match the PATH node\'s `layoutStyle.width` and `layoutStyle.height`. The injected SVG uses `width="100%" height="100%"`, so it fills its direct parent. If you place it directly inside a large button container (e.g. 32\xD732px) instead of the icon\'s own size (e.g. 16\xD716px), the icon will render too large. Always wrap the placeholder in an element sized to the PATH node\'s dimensions:\n - **HTML/Vue**: `<span style="width:{layoutStyle.width}px;height:{layoutStyle.height}px;display:flex;align-items:center;justify-content:center">@@SVG:{svgKey}@@</span>`\n - **JSX/React**: `<span style={{width:\'{w}px\',height:\'{h}px\'}}>{/*@@SVG:{svgKey}@@*/}</span>`\n - **Flutter**: `SizedBox(width:{w},height:{h},child: SvgPicture.string(\'@@SVG:{svgKey}@@\'))`\n- Use `svgName` to match each icon to its correct UI position \u2014 e.g. an icon with `svgName: "\u901A\u7528/\u5411\u5DE6"` belongs in a collapse/fold button, not a "add" button.\n\n**After generating the COMPLETE code** \u2014 call `mcp__applyDesign` with the full code string AND an `outDir` parameter. The tool substitutes every `@@SVG:...@@` with the real high-precision `<svg>` markup from the cache (character-for-character exact, no rounding) AND writes the final file directly to disk. **You MUST provide `outDir`** \u2014 this writes the patched code to a file WITHOUT it passing back through your generation, preventing any re-processing or precision loss. After the tool writes the file, you are DONE \u2014 do NOT output, copy, or edit the code further.\n\n### Intra-Section Layout Rules (node-level positioning):\nEvery node in a section\'s DSL has TWO pieces of layout data:\n\n1. **`flexContainerInfo`** \u2014 If a node HAS this field, it is a flex container. Its direct children are laid out by flex rules, NOT by absolute positioning. Generate CSS: `display: flex; flex-direction: {flexDirection}; justify-content: {justifyContent}; align-items: {alignItems}; gap: {gap}; padding: {padding};`. Do NOT add `position: absolute` or `left/top` to flex container nodes or their direct children.\n\n2. **`layoutStyle.relativeX/relativeY`** \u2014 Use these ONLY for leaf/free nodes that are NOT inside a flex container. For those nodes, apply `position: absolute; left: {relativeX}px; top: {relativeY}px;`.\n\n3. **Nested flex containers** \u2014 A flex container can contain a child that is ALSO a flex container (e.g. a horizontal toolbar with a vertical menu inside). Each level independently uses its own `flexContainerInfo`. **You MUST preserve ALL nesting levels** \u2014 do NOT flatten a two-level flex structure into one. For example, a table header cell where "label + sort-icon" form an inner group and "action-icon" sits at the outer level MUST be rendered as TWO nested flex containers, not one flat flex with all three items side by side. Flattening loses the visual grouping (label+sort tightly paired, action-icon separated) and causes layout breakage.\n\n4. **When a child has `flexGrow` / `flexShrink`** \u2014 These are flex item properties. Apply `flex: {flexGrow} 1 0` on the child element. Do NOT position it absolutely.\n\n5. **CRITICAL \u2014 Flex column with fixed-height children**: When a container uses `flex-direction: column` with a FIXED height and `overflow: hidden`, ALL children with fixed heights (tabs, headers, pagination bars, footers, scrollbars) MUST have `flex-shrink: 0`. Only ONE child \u2014 the flexible content area (table body, scrollable region) \u2014 should use `flex: 1`. If you forget `flex-shrink: 0` on fixed-height children, flex layout will squeeze them out of the visible area and they get clipped by `overflow: hidden` (e.g. pagination bar becomes invisible).\n\n6. **CRITICAL \u2014 Nested FRAME dimensions and spacing**: When a FRAME contains child FRAMEs (e.g. a card panel with an inner content container), the outer element\'s width/height MUST come from the OUTER node\'s `layoutStyle.width/height` \u2014 NOT from the inner content container. A common error is using the inner container\'s width (e.g. 285px) for the card itself (which should be 317px). Always trace to the correct node: if the DSL shows `\u5BB9\u5668A (317\xD7107) > \u5BB9\u5668B (285\xD775, relativeX:16, relativeY:16)`, the rendered card is 317\xD7107 with 16px padding, and the content inside is 285\xD775.\n\n7. **CRITICAL \u2014 Precise vertical positioning inside cards**: Inside small fixed-height containers (stat cards, info panels, badge boxes), do NOT invent `gap` values. Use each child\'s `layoutStyle.relativeY` to position elements precisely. For example, if a card\'s DSL shows child A at `relativeY:0` and child B at `relativeY:32`, the vertical gap is 32px (minus child A\'s height) \u2014 NOT a guessed `gap:16px` or `gap:20px`. Inventing large gaps in small cards pushes content apart and breaks the compact layout. When `flexContainerInfo.gap` is present, use that exact value; when it is absent, use `relativeY` differences to calculate spacing.\n\n8. **CRITICAL \u2014 Overlapping elements in the same container (Switch toggle, icon badges, layered decorations)**: When a container holds multiple sibling elements that visually OVERLAP (one on top of another), the container MUST use `position: relative` and each child MUST use `position: absolute` with its own `layoutStyle.relativeX/relativeY`. Do NOT use `display: flex` on the container \u2014 flex will place the children SIDE BY SIDE instead of overlapping, shrinking them and destroying the composition. The canonical example is a Switch toggle: the DSL shows a track PATH (`relativeX:0, relativeY:0, w:40, h:24`) and a knob circle (`relativeX:17.5, relativeY:1.5, w:21, h:21`) as siblings. Generate EXACTLY this structure:\n```\n<div style="position:relative; width:40px; height:24px;">\n <div style="position:absolute; left:0px; top:0px;">@@SVG:{trackSvgKey}@@</div>\n <div style="position:absolute; left:17.5px; top:1.5px;">@@SVG:{knobSvgKey}@@</div>\n</div>\n```\nEach child\'s `left` and `top` come from that child\'s own `layoutStyle.relativeX` and `layoutStyle.relativeY`. Never use a shared `left:0; top:0` for all children. Never use flex.\n\n9. **Fallback** \u2014 Nodes with NEITHER `flexContainerInfo` NOR being inside a flex container: use `position: absolute; left: {relativeX}px; top: {relativeY}px;`.\n- Generate a single complete HTML file containing ALL sections in order, nested inside the root container.\n- token fields must be generated as CSS variables with comments indicating the token name.\n- If componentDocumentLinks exists, call mcp__getComponentLink to fetch documentation.\n- When splitContainers is present, sections that were split from the same container must share that container\'s width and be wrapped together. **Apply the container\'s `background` to the parent wrapper**: splitContainer entries now include `background` (resolved CSS color) and `fill` (paint reference).\n- CRITICAL \u2014 Table container boundary: when a design has a table (header + data rows), wrap the ENTIRE table area (header row + all data rows + any empty space below the last row down to the pagination) in a single container with the design\'s background color (usually white) and the table\'s border. The table may have only 1 data row but the container must extend to fill the design\'s allocated height \u2014 do NOT leave the area below the last row as page background showing through. The pagination bar sits BELOW this container as a sibling, not inside it.\n\n### Text Provenance Self-Check (MANDATORY before finalizing output):\n- Before writing the final HTML, enumerate every visible text string you plan to emit.\n- For EACH string, verify it exists in `rootMetadata.allTexts` (the section LIST response carries this closed-set whitelist of all text in the design) OR in some section\'s `dsl.rowTexts` / `node.text`.\n- Any string with NO provenance (typical offenders: fabricated column headers like "\u7528\u6237\u540D\u79F0/\u6240\u5C5E\u7EC4/\u8FDC\u7A0BIP", invented cell data like "1.1.3.543.4" or "AES-128", brand-watermark tokens like "Hillstone Design", generic menu labels not in the design) MUST be deleted or replaced with an empty placeholder.\n- If you find yourself generating MORE distinct text strings than `allTexts.length`, STOP and re-check \u2014 you are hallucinating.\n\n### Row Count Self-Check (MANDATORY for tables/lists):\n- For every table, list, or repeated-row section in your output, look up its `structureSiblingCount`. This field appears in BOTH the section list entry AND each section DSL response (top-level `structureSiblingCount`).\n- The number of data rows you render MUST equal `structureSiblingCount`. This is a hard constraint, not a suggestion.\n- `structureSiblingCount: 1` means render EXACTLY 1 data row. Do NOT add rows "for visual density", "to look complete", or "because a pagination label says \u517110\u9879". Pagination labels reflect a UI control state, NOT a data-row count \u2014 they must never inflate the row count.\n- Before outputting any table, verify: count your `<tr>` (data rows, excluding header) \u2192 it MUST equal `structureSiblingCount`. If you rendered more, delete the extras now.\n\n### Tool Selection Rules:\n- `mcp__getDesignSections` is the PRIMARY tool for full-page design-to-code generation. Always start here when you need to generate a complete HTML page from a design.\n- `mcp__extractSvg` is a STANDALONE tool. Use it DIRECTLY when you only need to extract SVG icons from a design \u2014 do NOT call `getDesignSections` before it.\n- `mcp__getDsl` is a FALLBACK \u2014 call it ONLY if `getDesignSections` returns an error (e.g. tool not available on older servers).\n- NEVER call both `getDesignSections` AND `getDsl` for the same design.\n- NEVER combine the section workflow with `extractSvg`. If you only need SVG icons, use `extractSvg` alone. If you need a full page, use the section workflow (which uses `@@SVG:{svgKey}@@` placeholders + `mcp__applyDesign` for SVG data).\n- The section workflow provides COMPLETE data. Do NOT call `getDsl` to "verify".\n\n### Output Format:\n- The design-data tools (`getDesignSections`, `getDsl`, `extractSvg`, `getMeta`) accept an optional `format` parameter: `json` (default), `yaml`, or `tree`. `yaml`/`tree` use fewer tokens for large designs; all three round-trip without data loss. Set a session-wide default with the `--format` CLI flag or `DEFAULT_FORMAT` env var.\n\n### Text Fidelity Rules:\n- TEXT nodes contain actual text in node.text array. Read EACH node\'s text and use it EXACTLY.\n- Do NOT duplicate text from one node to another \u2014 each TEXT node has unique content.\n- Do NOT skip any child nodes. Render ALL nodes: every tab, every button, every text element.\n\n### Background & Color Rules:\n- **PREFER the `_color` field**: every node with a resolved fill carries a `_color` field containing the computed CSS hex/rgb value. Use this value DIRECTLY in CSS \u2014 no styles-table lookup needed. Example: `color: #4E5969` from `"_color": "#4E5969"`.\n- The `fill` field (e.g. `paint_1:7200`) remains for reference. Use `_token` (e.g. `"Text/Text-4"`) for CSS variable naming like `var(--text-text-4, #4E5969)`.\n- If a node has both `_color` and `fill`, `_color` is authoritative for the visual color value.\n- The DSL `styles` map contains fill/stroke style definitions. Use the node\'s `fillStyleId`/`strokeStyleId` to look up the actual color from `styles`.\n- The root/frame node\'s background comes from its fill style. Do NOT invent gradient or solid backgrounds \u2014 use ONLY the colors from the DSL data.\n- If a node has no fill or the fill style is empty/transparent, do NOT add a background color. Leave it transparent or inherit from parent.\n- Status bar, title bar, and other container backgrounds MUST match the DSL fill data exactly.\n- **NEVER hardcode LLM-default colors** (e.g. `#1D2129`, `#000`, `#333`) when `_color` is present. The `_color` value is the design truth \u2014 copying it requires zero cognitive effort and zero styles-table lookup.\n- **CRITICAL \u2014 splitContainers[].background IS the exact CSS background-color.** Copy it verbatim: `background-color: <value>;`. MUST NOT add gradients, MUST NOT change the color. The designer chose this color deliberately.\n- **CRITICAL \u2014 OPACITY ON FRAME**: a FRAME\'s `opacity` field applies ONLY to its own background, NOT children. Use `background-color: rgba(R, G, B, <opacity>)` \u2014 NEVER use CSS `opacity: X` on the parent, which makes child text/icons translucent.\n- **CRITICAL \u2014 NEVER promote a child node\'s gradient/fill onto its parent container.** A gradient `linear-gradient(...)` in the DSL is computed against THAT node\'s own bounding box \u2014 its stop offsets (e.g. `#0063BA 83%`) are percentages of that specific node\'s height, NOT the parent\'s height. If you copy such a gradient onto a differently-sized parent (e.g. a 88px navbar that contains a 195px-tall decorative oval), the stops map to the WRONG size and the visible color shifts or disappears entirely (blue appears only in the bottom 15px, leaving the top transparent). Rules:\n - The background/fill of a node applies to THAT node\'s element only, at THAT node\'s size. Render each node at its own `layoutStyle.width/height`.\n - A FRAME/GROUP/INSTANCE with NO `_color`/`fill` (empty) has NO background \u2014 leave it transparent. Do NOT borrow a child\'s fill to fill the parent.\n - Decorative layers with `filter: blur(...)` (e.g. `filter: blur(81.6px)`) or very low alpha (`rgba(..., 0.0x)`) are visual overlay accents (glow, bloom), NOT the container\'s base background. Keep them as positioned overlays inside the container \u2014 never extract their gradient as the container background.\n - If a container (navbar, card, header) needs a solid base background that the DSL doesn\'t directly provide on the FRAME node, derive it from the dominant opaque color among its children (e.g. the most common solid `_color`), not from a decorative gradient overlay.\n\n### Anti-Hallucination Rules:\n- You MUST use EXACT text content from the DSL data. NEVER invent, translate, or paraphrase text.\n- If a section has empty or missing text data, render it as an empty placeholder \u2014 do NOT fabricate text.\n- NEVER generate placeholder values, generic tags, fabricated amounts, or invented statistics.\n- Every piece of text, every number, every label in your output MUST come directly from the DSL data.\n- NEVER fabricate SVG path data for icons or vector shapes \u2014 use `@@SVG:{svgKey}@@` placeholders for ALL icons, then call `mcp__applyDesign`.\n- NEVER fabricate background colors, gradients, or decorations that are not present in the DSL data.\n\n### Empty Design Tolerance Rules (CLOSED-SET TEXT):\n- Many designs are UNFINISHED wireframes or component-library showcases with sparse text. This is NORMAL, not missing data.\n- The ONLY allowed text strings in your output are those present in `dsl.rowTexts` or `node.text` of some fetched section. The section list response carries `rootMetadata.allTexts` \u2014 the complete closed set of text strings in this design. Treat it as a whitelist: any string NOT in allTexts is a hallucination and MUST be removed.\n- Sparse text is especially common when the design reuses a component library: the design itself may have only ~10 distinct text strings total, even though the rendered page looks dense. Do NOT infer more content from visual density or the page\'s apparent purpose.\n- If a section has `textTotal=0` or empty `rowTexts`, render its STRUCTURE with EMPTY placeholders (`<td></td>`, blank labels, empty menu items) \u2014 do NOT invent column headers, menu item labels, IP addresses, algorithm names, or any data values to fill it.\n- A table with 1 data row in the DSL renders as 1 data row in HTML. Do NOT pad with fabricated rows. Pagination labels like "\u5171 10 \u9879" reflect a UI control state, NOT a data-row count \u2014 never synthesize rows to match them.\n- Brand-name leakage is forbidden: do NOT generate library/watermark tokens (e.g. "Hillstone Design", "Ant Design", "Material UI") even if they appear in component node names or you recognize the brand from training data. Only render text that appears in the design\'s own TEXT nodes.\n- When in doubt about whether a text string is real: it is NOT real unless you can cite the sectionIndex it came from.\n\n### SVG Icon Anti-Simplification Rules:\n- PATH nodes carry a `svgKey` \u2014 the SVG markup is injected by `mcp__applyDesign` at the end. You MUST use `@@SVG:{svgKey}@@` placeholders \u2014 never hand-write `<path d="...">`.\n- **SVG UNIQUENESS:** Each icon in the DSL is a distinct design artifact \u2014 different sections may have DIFFERENT icons even if they look similar (e.g. "\u641C\u7D22" in section 2 vs "\u641C\u7D22" in section 40 are DIFFERENT SVGs). NEVER reuse a `svgKey` from one section in another. Always use the exact `svgKey` from the PATH node in its own section.\n- **NEVER substitute vector paths with simplified shapes** \u2014 a `<path>` containing a house icon is NOT replaceable by a `<rect>` + `<polygon>`. The designer chose every anchor point; your simplified version WILL look different.\n- **VERIFY after copying each SVG**: count the number of `M` characters in the source path `d` attribute. Your copy MUST have exactly the same count. Fewer `M` \u2192 you corrupted the icon \u2192 redo.\n- **SHAPE CHECK**: if the source uses `<path>`, your output MUST use `<path>`. NOT `<rect>`, NOT `<circle>`, NOT `<ellipse>`. Shape type changes ARE visual changes.\n- The only acceptable SVG operation is: copy the complete `<svg>...</svg>` block from the DSL data and paste it into your HTML. Nothing else.\n- **Common failure pattern**: you saw a complex path and thought "this looks roughly like 4 rectangles" \u2192 you drew 4 `<rect>`s \u2192 the result is visually WRONG. The designer chose a vector path for a reason. Trust the data.\n- **COMPOSITE ICONS (logos, multi-subpath marks):** when a logo/brand mark is split into multiple sub-paths and stripped to svgCache, the SVG that `mcp__applyDesign` injects for the `@@SVG:{svgKey}@@` placeholder is the complete `<svg>...</svg>`. Keep it whole. The node\'s `relativeX`/`relativeY` are canvas placement coordinates \u2014 they are NOT to be reused as `transform="translate(x,y) scale(...)"` inside a hand-assembled `<svg>`. Doing so warps the glyph out of its viewBox.\n\n### INSTANCE Variant State Rules:\n- INSTANCE nodes may carry a **`_variantProps`** object with semantic state labels extracted from component variant properties (e.g. `{"\u72B6\u6001": "\u9009\u4E2D", "\u5206\u7C7B": "\u5E7D\u7075\u6309\u94AE", "\u5C3A\u5BF8": "24"}`).\n- **Active/selected state**: compare `_variantProps` across sibling INSTANCE nodes to find which one has `"\u72B6\u6001": "\u9009\u4E2D"` or similar active-state values. Apply the `.active` CSS class ONLY to that node \u2014 NEVER default to the first item in a list.\n- **Sidebar menu items**: each menu item (e.g. 22 submenu entries) is a separate section containing an INSTANCE with `_variantProps`. The item with `"\u72B6\u6001": "\u9009\u4E2D"` in its `_variantProps` is the currently active page \u2014 the corresponding section\'s `rowTexts[0]` (or TEXT child) is its label. Render this item with `class="submenu-item active"`.\n- **Button states**: `"\u5206\u7C7B": "\u5E7D\u7075\u6309\u94AE"` vs `"\u5206\u7C7B": "\u4E3B\u8981\u6309\u94AE"` determines the button\'s visual style (outline vs filled). Multiple buttons in the same toolbar may have different variant props \u2014 respect each one individually.\n- If `_variantProps` is absent from all siblings, assume all are in `default` state \u2014 do NOT invent active states.\n\n### Repeat / Row-Count Rules:\n- Each section entry carries `structureSiblingCount` = the exact number of times this structure appears in the design.\n- For data/table sections: the number of rendered rows MUST equal `structureSiblingCount`. A count of 1 means ONE row total \u2014 do not pad with fabricated rows "for visual density" or "to fill the table". The single row in the DSL IS the complete dataset.\n- For `structureSiblingCount >= 2`: reuse the `structureHash` template, render exactly that many instances, swap per-instance text/colors from each section\'s own data.\n- Pagination controls, "load more" buttons, and empty-state rows are CONTROLS, not data rows \u2014 never counted toward the dataset.\n\n### Placeholder Text Rules:\n- TEXT nodes may carry `_placeholder: true`. This flag marks text whose node name equals its content \u2014 the universal signature of component-library placeholder text (the slot name WAS the placeholder string, e.g. `{name: "Hillstone Design", text: "Hillstone Design"}`). This works across ALL component libraries without brand-specific tokens.\n- `_placeholder: true` is a HINT, not a deletion. Read the surrounding context: if the flagged text does not map to a real column header, label, or content slot in this specific design, treat it as boilerplate and omit it. If it does map to real content, render it normally.\n- Never blanket-render every `_placeholder` text as visible headers/columns.\n\n### Data Completeness Rules:\n- You MUST fetch ALL sections (0..totalSections-1). If totalSections=48, you must call sectionIndex=0 through 47 \u2014 no exceptions.\n- Some sections may have nodeCount=3 and no visible TEXT nodes (text is in component property overrides). Do NOT skip them \u2014 the TEXT is resolved during DSL transfer. These sections contribute real content.\n- **textPreview**: each section list entry carries a `textPreview` field (first TEXT node found, truncated to 20 chars). If two sections both have nodeCount=3 and empty name, use `textPreview` to tell them apart \u2014 they are different menu items (e.g. "\u7CFB\u7EDF\u4FE1\u606F" / "\u6743\u9650\u8BBE\u7F6E"), NOT duplicates.\n- Keep a checklist: track which section indices have been requested. Do not stop until every index 0..N-1 has been fetched.\n- If you accidentally skipped a section, go back and request the missing indices. An incomplete section set WILL cause missing content in the final HTML.\n\n\n\n### Critical Rendering Checklist (MANDATORY \u2014 verify each item before finalizing):\nBefore declaring the HTML complete, enumerate every structural element below and confirm it is rendered. Missing ANY item is a fidelity defect.\n\n1. **Sidebar menu item icons**: each sidebar menu section carries a PATH icon with a `svgKey`. Did you place `@@SVG:{svgKey}@@` for each? If you used a `<rect>` or `<circle>` or hand-wrote `<path d="...">`, DELETE it \u2014 the DSL does NOT contain path data. Use the placeholder.\n\n2. **Table header column icons** (sort/filter/search): each table header cell may carry sort-arrow, filter-funnel, and search-lens PATH icons. Did you place `@@SVG:{svgKey}@@` for each? If a header cell has no icons, you may have skipped them.\n\n3. **Pagination icons** (refresh, prev/next arrows, dropdown): the pagination section has MULTIPLE PATH icons. Did you place `@@SVG:{svgKey}@@` for EACH one?\n\n4. **Brand/logo area text**: the brand section has a TEXT node with the actual brand name (present in `allTexts`). Did you render it as visible text?\n\n5. **Every PATH node has a placeholder**: walk through every section\'s DSL \u2014 every PATH node must have a corresponding `@@SVG:{svgKey}@@` in your code. Count: the number of `@@SVG:` placeholders in your code MUST equal the total number of PATH nodes across all sections.\n\n6. **Text provenance**: every text string in your output MUST be traceable to `rootMetadata.allTexts` or a section\'s `dsl.rowTexts`/`node.text`. If you cannot cite the exact source, the text is a hallucination \u2014 delete it.\n\n7. **SVG placeholder replacement (HARD GATE)**: your HTML is INVALID and must NOT be output until you have called `mcp__applyDesign` with the complete code and used the returned `patchedCode`. This is not optional \u2014 it is the FINAL mandatory step. If you wrote ANY `<path d="...">` by hand instead of using `@@SVG:{svgKey}@@` placeholders, the `mcp__applyDesign` tool will detect it as a FABRICATED path and return an error. You MUST then replace those hand-written paths with placeholders and call `mcp__applyDesign` again. The ONLY acceptable output is the `patchedCode` returned by `mcp__applyDesign` \u2014 never your pre-replacement code.\n\nIf any item above is unchecked, your HTML is INCOMPLETE. Fix it before outputting.\n\n### Data Interpretation Rules:\n- Pagination/table-footer labels (e.g. "\u5171 10 \u9879", "X rows/page", "items per page") reflect UI control state \u2014 NOT data to replicate.\n- "\u5171 X \u9879" is the pagination widget showing "total X items". The actual data rows come from the table body sections (preceding the pagination section).\n- Do NOT fabricate data rows based on pagination "total" values. Render ONLY the actual data rows present in the DSL.\n- If the DSL contains 1 data row, output exactly 1 table row. Do NOT multiply rows to match a pagination label.\n- **CRITICAL \u2014 SVG icons for table actions**: table action columns (\u64CD\u4F5C\u5217) use PATH icon nodes with `svgKey` fields. Place `@@SVG:{svgKey}@@` for each action button. NEVER render action buttons as `<p>\u7F16\u8F91</p>` or `<p>\u5220\u9664</p>` plain text or hand-drawn shapes.\n- **CRITICAL \u2014 Persistent sidebars**: render all sidebar levels as static visible columns positioned via splitContainers coordinates. Do NOT hide or toggle sidebar levels.\n- **CRITICAL \u2014 NEVER reuse an SVG from one section in another**: each icon position has its OWN `svgKey` (e.g. `#5`) in the DSL. A collapse/fold button icon is a DIFFERENT vector from a menu navigation arrow even if both look like arrows. You MUST use the exact `svgKey` from the PATH node where the icon appears \u2014 never use a svgKey from a different PATH node.\n';function T4(){let{token:t,baseUrl:e,rules:n,debug:r,noRule:o,proxy:i,format:s}=hE();if(s!==void 0){let c=iu(s);c?process.env.DEFAULT_FORMAT=c:console.warn(`Invalid --format value: "${s}". Must be one of: json, yaml, tree. Falling back to json.`)}if(r){process.env.DEBUG="true",console.log("Debug information:"),console.log(`Token: ${t?"set":"not set"}`),console.log(`API URL: ${e||"default"}`),console.log(`Rules: ${n.length>0?n.join(", "):"none"}`),console.log(`No Rule: ${o?"enabled":"disabled"}`),console.log(`Proxy: ${i||"none"}`);let c=Xl();console.log(`Custom Headers: ${Object.keys(c).length>0?JSON.stringify(mE(c)):"none"}`),console.log(`Format: ${process.env.DEFAULT_FORMAT||"json (default)"}`),console.log("Debug mode: enabled")}let a=new vl({name:"MasterGoMcpServer",version:Yi.version},{instructions:k4});new hu().register(a),new gu().register(a),new au().register(a),new lu().register(a),new uu().register(a),new pu().register(a),new du().register(a),new fu().register(a),new mu().register(a),new yu().register(a),new xu().register(a),a.connect(new _l)}T4();
|
|
1323
1323
|
/*! Bundled license information:
|
|
1324
1324
|
|
|
1325
1325
|
mime-db/index.js:
|