aem-eds-kit 0.4.60 → 0.4.61

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/CHANGELOG.md CHANGED
@@ -6,6 +6,13 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ### Fixed
10
+ - **`eds` run by Electron as Node** (EDS-093), as the aem-eds-studio desktop
11
+ app does, failed every command with "unknown command '…/eds.js'": commander
12
+ read the script path as the command. argv is now always parsed Node-style.
13
+
14
+ ## [0.4.60] - 2026-11-06
15
+
9
16
  ### Changed
10
17
  - **Illustrations on the site** (EDS-077): design sources → `eds` → block,
11
18
  the command workflow (start → build → check → ship), one per audit card,
@@ -533,6 +540,7 @@ Initial CLI scaffold: `block create`, `block from-figma`, `block list`,
533
540
  `figma setup`, `doctor`, `preview`, `publish`. Not published.
534
541
 
535
542
  [Unreleased]: https://github.com/piotrgodycki/aem-eds-kit/commits/main
543
+ [0.4.60]: https://www.npmjs.com/package/aem-eds-kit/v/0.4.60
536
544
  [0.4.48]: https://www.npmjs.com/package/aem-eds-kit/v/0.4.48
537
545
  [0.4.26]: https://www.npmjs.com/package/aem-eds-kit/v/0.4.26
538
546
  [0.4.25]: https://www.npmjs.com/package/aem-eds-kit/v/0.4.25
package/README.md CHANGED
@@ -471,7 +471,7 @@ eds draft discard hero # drop it; blocks/ u
471
471
 
472
472
  `accept --commit` (or `--branch <name>`, created if missing) commits only `blocks/<name>/`, with the review rounds in the message (`v1: first version`, `v2: "bigger headline, orange buttons"`). `preview` and `accept` take a version (`eds draft preview hero 2`, `eds draft accept hero 1 --branch feature/hero`; default: the latest). `refine` starts from the latest version, or `--from <n>`, and reuses the agent and model that made the draft unless you pass `--agent` / `--model`.
473
473
 
474
- **For tools: `--json`.** `block from-design` and the `draft` commands take the global `--json` flag and print **one JSON event per line on stdout** (the usual output stays on stderr). It never prompts, so pass the design, the name and `--draft`. Every event has `v` (the schema version, currently `1`) and `type`, and the stream ends with one `result`. [aem-eds-studio](https://github.com/piotrgodycki/aem-eds-studio) reads it.
474
+ **For tools: `--json`.** `block from-design` and the `draft` commands take the global `--json` flag and print **one JSON event per line on stdout** (the usual output stays on stderr). It never prompts, so pass the design, the name and `--draft`. Every event has `v` (the schema version, currently `1`) and `type`, and the stream ends with one `result`. [aem-eds-studio](https://github.com/piotrgodycki/aem-eds-studio) reads it. A tool can run `dist/bin/eds.js` with Node or with Electron as Node (`ELECTRON_RUN_AS_NODE=1`), as the studio's desktop app does.
475
475
 
476
476
  ```bash
477
477
  eds --json block from-design "<design link>" --name hero --draft
package/dist/bin/eds.js CHANGED
@@ -1123,4 +1123,4 @@ Setup complete!`)),o!=="none"&&s.info(`Try: ${pe.cyan('eds block from-design "<f
1123
1123
  `);for(let l=0;l<i.length;l++){let d=i[l];/<script\b/i.test(d)&&!/type\s*=\s*["']module["']/i.test(d)&&!/<\/script>/.test(d)&&t.push({rule:"No render-blocking scripts in head.html",status:"fail",message:'Script without type="module" blocks rendering',file:"head.html",line:l+1})}let a=(o.match(/<link[^>]+rel=["']stylesheet["'][^>]*>/gi)||[]).filter(l=>!l.includes("styles/styles.css")&&!l.includes("styles.css"));a.length>0&&t.push({rule:"No extra stylesheets in head.html",status:"warn",message:`${a.length} extra stylesheet(s) \u2014 each competes with LCP budget`,file:"head.html"}),/<link[^>]+rel=["'](preload|preconnect)["']/i.test(o)&&t.push({rule:"No preload/preconnect in head.html",status:"warn",message:"preload/preconnect can hurt EDS LCP \u2014 resources compete with the 100KB budget",file:"head.html"}),/<script\b[^>]*>[\s\S]*?[^\s<][\s\S]*?<\/script>/i.test(o)&&t.push({rule:"No inline scripts in head.html",status:"warn",message:"Inline scripts block rendering \u2014 move to delayed.js",file:"head.html"});let c=/(?:src|href)=["'](https?:\/\/(?!(?:localhost|127\.0\.0\.1))[^"']+)["']/gi;for(let l of o.matchAll(c)){let d=l[1];d.includes("fonts.googleapis.com")||t.push({rule:"No third-party resources in head.html",status:"warn",message:`Third-party resource: ${d} \u2014 move to delayed.js`,file:"head.html"})}/<link[^>]+as=["']font["']/i.test(o)&&t.push({rule:"No font preloads in head.html",status:"warn",message:"Font preloads consume LCP bandwidth budget \u2014 let loadFonts() handle them",file:"head.html"}),t.some(l=>l.file==="head.html")||t.push({rule:"head.html is clean",status:"pass",message:"No render-blocking issues found",file:"head.html"})}async function vf(e,t){let n=Ie.join(e,"scripts","scripts.js");if(!_e(n)){t.push({rule:"scripts/scripts.js exists",status:"warn",message:"Missing scripts.js \u2014 cannot audit loading phases"});return}let o=await xt(n,"utf-8"),i=o.split(`
1124
1124
  `),r=/function\s+loadEager|loadEager\s*=/i.test(o),a=/function\s+loadLazy|loadLazy\s*=/i.test(o),c=/function\s+loadDelayed|loadDelayed\s*=/i.test(o);t.push({rule:"loadEager phase exists",status:r?"pass":"fail",message:r?"Found":"Missing loadEager \u2014 LCP optimization depends on it",file:"scripts/scripts.js"}),t.push({rule:"loadLazy phase exists",status:a?"pass":"fail",message:a?"Found":"Missing loadLazy \u2014 below-fold content won't load properly",file:"scripts/scripts.js"}),t.push({rule:"loadDelayed phase exists",status:c?"pass":"warn",message:c?"Found":"Missing loadDelayed \u2014 third-party scripts may block LCP",file:"scripts/scripts.js"});let l=o.match(/setTimeout\s*\([^,]+,\s*(\d+)\s*\)/);if(c&&l){let d=Number.parseInt(l[1],10);d<3e3?t.push({rule:"Delayed phase waits >= 3s",status:"warn",message:`delayed.js loads after ${d}ms \u2014 should be >= 3000ms for LCP safety`,file:"scripts/scripts.js"}):t.push({rule:"Delayed phase waits >= 3s",status:"pass",message:`${d}ms delay before loading delayed.js`,file:"scripts/scripts.js"})}if(r){let d=o.match(/loadEager[\s\S]*?(?=function\s|const\s+load|$)/)?.[0]||"";/loadSections\s*\(/.test(d)&&t.push({rule:"loadEager loads only first section",status:"fail",message:"loadEager calls loadSections() \u2014 should only load first section for fast LCP",file:"scripts/scripts.js"})}for(let d=0;d<i.length;d++){let m=i[d];/import\s.*from\s+['"]https?:\/\//i.test(m)&&t.push({rule:"No third-party imports at top level",status:"warn",message:`Third-party import at line ${d+1} \u2014 move to delayed.js if not critical`,file:"scripts/scripts.js",line:d+1})}if(r){let d=jf(o,"loadEager");d&&/loadHeader|loadFooter/.test(d)&&t.push({rule:"Header/footer not in loadEager",status:"warn",message:"Header/footer in loadEager delays LCP \u2014 move to loadLazy",file:"scripts/scripts.js"})}}async function kf(e,t){let n=Ie.join(e,"styles","styles.css");if(!_e(n))return;let i=(await bl(n)).size/1024;t.push({rule:"styles.css size within LCP budget",status:i>40?"warn":"pass",message:`${i.toFixed(1)} KB${i>40?" \u2014 large CSS competes with 100KB LCP budget":""}`,file:"styles/styles.css"});let r=await xt(n,"utf-8");/@import\s/.test(r)&&t.push({rule:"No @import in styles.css",status:"warn",message:"@import creates a request chain \u2014 inline the CSS or use lazy-styles.css",file:"styles/styles.css"})}async function xf(e,t){let n=Ie.join(e,"scripts","delayed.js");if(!_e(n)){t.push({rule:"scripts/delayed.js exists",status:"info",message:"No delayed.js \u2014 third-party scripts should go here"});return}(await xt(n,"utf-8")).replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"").trim()||t.push({rule:"delayed.js has content",status:"info",message:"delayed.js is empty \u2014 add analytics/martech here",file:"scripts/delayed.js"})}async function $f(e,t){let n=Ie.join(e,"blocks");if(!_e(n))return;let o=await wf(n,{withFileTypes:!0});for(let i of o){if(!i.isDirectory())continue;let r=i.name,a=Ie.join(n,r,`${r}.js`);if(!_e(a))continue;let c=await xt(a,"utf-8"),l=c.split(`
1125
1125
  `),d=["jquery","lodash","moment","rxjs","d3","three","gsap","anime","chart.js","swiper"];for(let u=0;u<l.length;u++){let g=l[u].toLowerCase();for(let h of d)g.includes("from")&&g.includes(h)&&/import\s/.test(g)&&t.push({rule:"No heavy imports in blocks",status:"warn",message:`Imports "${h}" \u2014 heavy library delays section loading`,file:`blocks/${r}/${r}.js`,line:u+1})}/document\.write/i.test(c)&&t.push({rule:"No document.write in blocks",status:"fail",message:"document.write blocks parsing and can break the page",file:`blocks/${r}/${r}.js`});let p=(await bl(a)).size/1024;p>20&&t.push({rule:"Block JS size reasonable",status:"warn",message:`${p.toFixed(1)} KB \u2014 consider splitting or lazy-loading parts`,file:`blocks/${r}/${r}.js`})}for(let i of o){if(!i.isDirectory())continue;let r=i.name,a=Ie.join(n,r,`${r}.css`);if(!_e(a))continue;let c=await xt(a,"utf-8"),l=/^([a-z][a-z0-9-]*)\s*\{/gm;for(let d of c.matchAll(l)){let m=d[1];["body","html","main"].includes(m)||t.push({rule:"Block CSS is scoped",status:"warn",message:`Bare element selector "${m}" \u2014 may leak styles and cause CLS. Use .${r} prefix`,file:`blocks/${r}/${r}.css`})}}}async function Sf(e,t){let n=Ie.join(e,"scripts","aem.js");if(!_e(n)){t.push({rule:"scripts/aem.js exists",status:"warn",message:"Missing aem.js (or lib-franklin.js) \u2014 the EDS framework library"});return}t.push({rule:"aem.js present",status:"pass",message:"Found \u2014 remember: never modify this file",file:"scripts/aem.js"})}function jf(e,t){let o=new RegExp(`(?:async\\s+)?function\\s+${t}\\s*\\([^)]*\\)\\s*\\{`).exec(e);if(!o)return null;let i=1,r=o.index+o[0].length,a=r;for(;r<e.length&&i>0;)e[r]==="{"?i++:e[r]==="}"&&i--,r++;return e.slice(a,r-1)}function Pf(e){let t=new Map;for(let o of e){let i=o.file||"general",r=t.get(i)??[];r.push(o),t.set(i,r)}for(let[o,i]of t){s.info(` ${Y.bullet} ${or.underline(o)}`);for(let r of i){let a=r.line?or.dim(`:${r.line}`):"";s.info(` ${gn(r.status)} ${r.rule}${a}`),r.status!=="pass"&&s.info(or.dim(` ${r.message}`))}s.info("")}let n={pass:e.filter(o=>o.status==="pass").length,warn:e.filter(o=>o.status==="warn").length,fail:e.filter(o=>o.status==="fail").length,info:e.filter(o=>o.status==="info").length};s.info(J([je(n)])),n.fail>0&&(process.exitCode=1)}var rr=v(()=>{"use strict";f();N();V();H()});var ar={};U(ar,{auditSecurity:()=>Nf});import{existsSync as ao}from"fs";import{readFile as Ef,readdir as Cf}from"fs/promises";import et from"path";import sr from"chalk";async function*vl(e){let t=await Cf(e,{withFileTypes:!0});for(let n of t){let o=et.join(e,n.name);if(n.isDirectory()){if(Rf.has(n.name))continue;yield*vl(o)}else n.isFile()&&(yield o)}}function Ff(e,t,n){let o=[],i=e.split(`
1126
- `);for(let r=0;r<i.length;r++){let a=i[r],c=!1;for(let l of Tf)l.ext.includes(n)&&(l.id==="innerhtml-static"&&c||l.re.test(a)&&(l.extra&&!l.extra(a)||(l.id==="innerhtml-dynamic"&&(c=!0),o.push({severity:l.severity,rule:l.id,message:l.message,file:t,line:r+1,snippet:a.trim().slice(0,100)}))))}return o}async function Lf(e){if(!ao(et.join(e,"package.json")))return{status:"skipped",note:"no package.json"};if(!(ao(et.join(e,"package-lock.json"))||ao(et.join(e,"npm-shrinkwrap.json")))&&!ao(et.join(e,"node_modules")))return{status:"skipped",note:"no package-lock.json / node_modules \u2014 run npm install"};try{let{execa:n}=await import("execa"),{stdout:o}=await n("npm",["audit","--json"],{cwd:e,reject:!1}),r=JSON.parse(o)?.metadata?.vulnerabilities??{},a={critical:r.critical??0,high:r.high??0,moderate:r.moderate??0,low:r.low??0};return{status:a.critical+a.high+a.moderate+a.low>0?"vulnerable":"ok",counts:a}}catch(n){return{status:"skipped",note:`npm audit failed: ${n.message}`}}}async function Nf(e={}){let t=E();if(!t){s.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n=[];for await(let l of vl(t)){let d=et.extname(l).slice(1).toLowerCase();if(!Df.has(d))continue;let m=et.relative(t,l);if(m.endsWith("aem.js")||m.endsWith("lib-franklin.js"))continue;let p=await Ef(l,"utf-8");n.push(...Ff(p,m,d))}let o=await Lf(t),i=l=>n.filter(d=>d.severity===l),r={critical:i("critical").length,high:i("high").length,moderate:i("moderate").length,low:i("low").length},a=r.critical>0||r.high>0||(o.counts?.critical??0)>0||(o.counts?.high??0)>0;if(e.json){console.log(JSON.stringify({projectRoot:t,dependencies:o,findings:n,summary:{code:r}},null,2)),a&&(process.exitCode=1);return}if(s.logoOnce(A("Security Audit")),s.info(j("Dependencies","npm audit")),o.status==="skipped")s.info(R("info","npm audit",o.note??"skipped"));else if(o.status==="ok")s.info(R("pass","npm audit","no known vulnerabilities"));else{let l=o.counts??{critical:0,high:0,moderate:0,low:0};s.info(R(l.critical+l.high>0?"fail":"warn","npm audit",`${l.critical} critical, ${l.high} high, ${l.moderate} moderate, ${l.low} low \u2014 run \`npm audit fix\``))}if(s.info(j("Exploit scan","XSS \xB7 secrets \xB7 injection \xB7 tabnabbing")),n.length===0)s.info(R("pass","code","no risky patterns found"));else{let l=[...n].sort((d,m)=>yl.indexOf(d.severity)-yl.indexOf(m.severity));for(let d of l){let m=Af[d.severity],p=sr.dim(`${d.file}:${d.line}`);s.info(` ${gn(m.status)} ${sr.bold(m.label)} ${d.message} ${p}`),s.info(sr.dim(` ${d.snippet}`))}}let c=je({fail:r.critical+r.high+(o.counts?.critical??0)+(o.counts?.high??0),warn:r.moderate+(o.counts?.moderate??0),info:r.low+(o.counts?.low??0)});s.info(""),s.info(J([c||`${Y.pass} no vulnerabilities or risky patterns found`])),a&&(process.exitCode=1)}var Tf,yl,Af,Rf,Df,cr=v(()=>{"use strict";f();N();V();H();Tf=[{id:"eval",severity:"critical",re:/\beval\s*\(/,message:"eval() executes arbitrary code \u2014 prime XSS / RCE vector",ext:["js","mjs","html"]},{id:"aws-key",severity:"critical",re:/\bAKIA[0-9A-Z]{16}\b/,message:"Hardcoded AWS access key id",ext:["js","mjs","html","json"]},{id:"private-key",severity:"critical",re:/-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/,message:"Embedded private key material",ext:["js","mjs","html","json","pem","txt"]},{id:"new-function",severity:"high",re:/\bnew\s+Function\s*\(/,message:"new Function() runs strings as code",ext:["js","mjs","html"]},{id:"document-write",severity:"high",re:/document\.write(?:ln)?\s*\(/,message:"document.write() enables XSS and blocks parsing",ext:["js","mjs","html"]},{id:"innerhtml-dynamic",severity:"high",re:/\.(?:inner|outer)HTML\s*=\s*[^;\n]*(?:\$\{|\+|concat)/,message:"Dynamic innerHTML assignment \u2014 sanitize or use textContent / DOM APIs",ext:["js","mjs"]},{id:"insert-adjacent-html",severity:"high",re:/insertAdjacentHTML\s*\(/,message:"insertAdjacentHTML with untrusted data is an XSS vector",ext:["js","mjs"]},{id:"js-url",severity:"high",re:/(?:href|src)\s*=\s*["']?\s*javascript:/i,message:"javascript: URL \u2014 XSS vector",ext:["js","mjs","html"]},{id:"secret",severity:"high",re:/(?:api[_-]?key|secret|access[_-]?token|auth[_-]?token|client[_-]?secret|passwd|password)\s*[:=]\s*["'][^"']{8,}["']/i,message:"Possible hardcoded secret / credential",ext:["js","mjs","html","json"],extra:e=>!/(example|placeholder|your[-_]|changeme|xxxx|<[^>]+>|\$\{)/i.test(e)},{id:"bearer-token",severity:"high",re:/Bearer\s+[A-Za-z0-9\-._~+/]{20,}/,message:"Hardcoded bearer token",ext:["js","mjs","html","json"]},{id:"innerhtml-static",severity:"moderate",re:/\.(?:inner|outer)HTML\s*=/,message:"innerHTML assignment \u2014 confirm the content is trusted / sanitized",ext:["js","mjs"]},{id:"insecure-url",severity:"moderate",re:/(?:href|src)\s*=\s*["']http:\/\/(?!localhost|127\.0\.0\.1)/i,message:"Insecure http:// resource \u2014 mixed content, use https://",ext:["html","js","mjs"]},{id:"target-blank",severity:"moderate",re:/target\s*=\s*["']_blank["']/,message:'target="_blank" without rel="noopener" \u2014 reverse tabnabbing',ext:["html","js","mjs"],extra:e=>!/rel\s*=\s*["'][^"']*noopener/i.test(e)},{id:"postmessage-wildcard",severity:"moderate",re:/postMessage\s*\([^,]+,\s*["']\*["']\s*\)/,message:"postMessage to '*' origin \u2014 restrict the target origin",ext:["js","mjs"]},{id:"inline-handler",severity:"low",re:/\son[a-z]+\s*=\s*["']/i,message:"Inline event handler \u2014 move to addEventListener (CSP-unfriendly)",ext:["html"]},{id:"console-log",severity:"low",re:/console\.(?:log|debug)\s*\(/,message:"console.log / debug left in code \u2014 potential info leak",ext:["js","mjs"]}],yl=["critical","high","moderate","low"],Af={critical:{status:"fail",label:"CRIT"},high:{status:"fail",label:"HIGH"},moderate:{status:"warn",label:"MOD "},low:{status:"info",label:"LOW "}},Rf=new Set(["node_modules",".git","dist","build",".vscode","coverage"]),Df=new Set(["js","mjs","html","json","pem","txt"])});async function kl(e,t,n){let o=t.ref||"main",i=n.startsWith("/")?n:`/${n}`,r=`${Of}/${e}/${t.org}/${t.site}/${o}${i}`;s.debug(`POST ${r}`);let a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"}}),c=await a.json().catch(()=>({})),l=c;return a.ok?{ok:!0,status:a.status,path:i,previewUrl:l.preview?.url,liveUrl:l.live?.url}:{ok:!1,status:a.status,path:i,message:c.message||`HTTP ${a.status}`}}async function lr(e,t){return kl("preview",e,t)}async function dr(e,t){return kl("live",e,t)}async function xl(e,t){return Promise.all(t.map(n=>lr(e,n)))}async function $l(e,t){return Promise.all(t.map(n=>dr(e,n)))}var Of,mr=v(()=>{"use strict";f();N();Of="https://admin.hlx.page"});var pr={};U(pr,{preview:()=>_f,resolveAdminConfig:()=>co});import Sl from"chalk";import Mf from"ora";async function _f(e,t){let n=E(),o=await ce(n),i=co(o,t);if(!i)return;let r=Mf(`Previewing ${e.length} path(s)...`).start(),a=e.length===1?[await lr(i,e[0])]:await xl(i,e);r.stop();let c=!1;for(let l of a)l.ok?s.success(`${l.path} \u2192 ${Sl.cyan(l.previewUrl||"preview updated")}`):(s.error(`${l.path} \u2014 ${l.message}`),c=!0);c&&(process.exitCode=1)}function co(e,t){let n=t.org||e.admin?.org,o=t.site||e.admin?.site,i=t.ref||e.admin?.ref||"main";if(!n||!o){s.error("Missing --org and --site. Set them via flags or in .edsrc.json:"),s.info(Sl.dim(' { "admin": { "org": "my-org", "site": "my-site" } }')),process.exitCode=1;return}return{org:n,site:o,ref:i}}var lo=v(()=>{"use strict";f();mr();fe();N();V()});var ur={};U(ur,{publish:()=>Bf});import If from"chalk";import Uf from"ora";async function Bf(e,t){let n=E(),o=await ce(n),i=co(o,t);if(!i)return;let r=Uf(`Publishing ${e.length} path(s)...`).start(),a=e.length===1?[await dr(i,e[0])]:await $l(i,e);r.stop();let c=!1;for(let l of a)l.ok?s.success(`${l.path} \u2192 ${If.cyan(l.liveUrl||"published")}`):(s.error(`${l.path} \u2014 ${l.message}`),c=!0);c&&(process.exitCode=1)}var fr=v(()=>{"use strict";f();mr();fe();N();V();lo()});var mo={};U(mo,{adminWizard:()=>Hf});async function Hf(e){let t=E();if(!t){s.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}s.logoOnce(A("Admin API \u2014 preview / publish"));let{select:n,input:o,confirm:i}=await Promise.resolve().then(()=>(K(),q)),a=(await ce(t)).admin??{},c=e??await n({message:"What do you want to do?",choices:[{name:"Preview pages (staging)",value:"preview"},{name:"Publish pages (go live)",value:"publish"}]}),l=(await o({message:"GitHub org / owner",default:a.org})).trim(),d=(await o({message:"Repository / site",default:a.site})).trim(),m=(await o({message:"Git ref",default:a.ref||"main"})).trim(),u=(await o({message:"Paths (space- or comma-separated)",default:"/"})).split(/[\s,]+/).filter(Boolean);if(!l||!d||u.length===0){s.error("org, site and at least one path are required."),process.exitCode=1;return}s.info(j("Summary"));let g=I(["operation","org","site","ref","paths"]);if(s.info(P("operation",c,g)),s.info(P("org",l,g)),s.info(P("site",d,g)),s.info(P("ref",m,g)),s.info(P("paths",u.join(", "),g)),s.info(""),c==="publish"&&!await i({message:`Publish ${u.length} path(s) to LIVE?`,default:!1})){s.info("Cancelled.");return}let h={org:l,site:d,ref:m};if(c==="preview"){let{preview:$}=await Promise.resolve().then(()=>(lo(),pr));await $(u,h)}else{let{publish:$}=await Promise.resolve().then(()=>(fr(),ur));await $(u,h)}}var po=v(()=>{"use strict";f();fe();N();V();H()});var jl={};U(jl,{mainMenu:()=>Kf});import{existsSync as Gf}from"fs";import{readdir as Wf}from"fs/promises";import Jf from"path";import zf from"chalk";async function gr(e){let t=Jf.join(e,"blocks");return Gf(t)?(await Wf(t,{withFileTypes:!0})).filter(o=>o.isDirectory()).map(o=>o.name):[]}async function Kf(){let{select:e,isEscape:t,isExit:n}=await Promise.resolve().then(()=>(K(),q));Qn.menu=!0,await s.logoOnceAnimated("");let o;for(;;){s.info(zf.dim(" Esc quits here \xB7 goes back to this menu from any step"));let i;try{i=await e({message:"Choose an action",choices:qf,default:o})}catch(r){if(t(r)||n(r))return;throw r}if(i==="exit")return;o=i;try{await Vf(i)}catch(r){if(n(r))return;t(r)||s.error(r instanceof Error?r.message:String(r))}process.exitCode=void 0,s.info("")}}async function Vf(e){let{select:t,input:n}=await Promise.resolve().then(()=>(K(),q));switch(e){case"new":{let{newProject:o}=await Promise.resolve().then(()=>(Lo(),Fo));await o(void 0,{});return}case"init":{let{initProject:o}=await Promise.resolve().then(()=>(Lt(),Ft));await o({});return}case"template":{let o=await n({message:"Template name",validate:r=>!!r.trim()||"Required"}),{templateNew:i}=await Promise.resolve().then(()=>(Ho(),Bo));await i(o.trim(),{});return}case"sandbox":{let o=await n({message:"Sandbox repo name",validate:r=>/^[a-z0-9][a-z0-9._-]*$/i.test(r.trim())||"Use a valid repo name"}),{sandboxNew:i}=await Promise.resolve().then(()=>(ze(),Je));await i(o.trim(),{});return}case"from-design":{let{blockFromDesign:o}=await Promise.resolve().then(()=>(io(),oo));await o(void 0,{});return}case"migrate":{let{migrateComponent:o}=await Promise.resolve().then(()=>(Xo(),Vo));await o(void 0,{});return}case"scaffold":{let{scaffoldInteractive:o}=await Promise.resolve().then(()=>(ue(),we));await o();return}case"create":{let o=await n({message:"Block name",validate:r=>He.test(r.trim())||"Use kebab-case, e.g. hero-banner"}),{createBlock:i}=await Promise.resolve().then(()=>(mi(),di));await i(o.trim(),{});return}case"integrate":{let{integrate:o}=await Promise.resolve().then(()=>(Qi(),Yi));await o(void 0);return}case"preview-block":{let o=E();if(!o){s.error("Not inside an EDS project (no EDS project markers found).");return}let i=await gr(o);if(i.length===0){s.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(c=>({name:c,value:c}))}),{previewBlock:a}=await Promise.resolve().then(()=>(Oe(),wt));await a(r,{});return}case"model":{let{modelAdd:o}=await Promise.resolve().then(()=>(ri(),ii));await o(void 0,[],{});return}case"track":{let o=E();if(!o){s.error("Not inside an EDS project (no EDS project markers found).");return}let i=await gr(o);if(i.length===0){s.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block to instrument?",choices:i.map(c=>({name:c,value:c}))}),{trackBlock:a}=await Promise.resolve().then(()=>(Ht(),Bt));await a(r,{});return}case"schema":{let o=E();if(!o){s.error("Not inside an EDS project (no EDS project markers found).");return}let i=await gr(o);if(i.length===0){s.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(c=>({name:c,value:c}))}),{schemaBlock:a}=await Promise.resolve().then(()=>(ai(),si));await a(r,{});return}case"ue":{if(await t({message:"Universal Editor:",choices:[{name:"Check readiness (which blocks are editable)",value:"check"},{name:"Open a page in the editor",value:"open"}]})==="check"){let{ueCheck:i}=await Promise.resolve().then(()=>(zt(),Jt));await i()}else{let i=await n({message:"Page path",default:"/"}),{ueOpen:r}=await Promise.resolve().then(()=>(zt(),Jt));await r(i.trim()||"/",{})}return}case"admin":{let{adminWizard:o}=await Promise.resolve().then(()=>(po(),mo));await o();return}case"audit":{let o=await t({message:"Which audit?",choices:[{name:"Doctor \u2014 overall project health",value:"doctor"},{name:"Loading \u2014 three-phase / LCP budget",value:"loading"},{name:"Security \u2014 vulnerabilities & exploit patterns",value:"security"}]});if(o==="doctor"){let{doctor:i}=await Promise.resolve().then(()=>(nr(),tr));await i({})}else if(o==="loading"){let{auditLoading:i}=await Promise.resolve().then(()=>(rr(),ir));await i({})}else{let{auditSecurity:i}=await Promise.resolve().then(()=>(cr(),ar));await i({})}return}case"figma-setup":{let{figmaSetup:o}=await Promise.resolve().then(()=>(er(),Zi));await o();return}}}var qf,Pl=v(()=>{"use strict";f();N();V();nt();Zn();qf=[{name:"New project",value:"new",description:"Clone the latest EDS boilerplate"},{name:"Set up project",value:"init",description:"Authoring model, CI, naming"},{name:"Page template",value:"template",description:"Generate initial content"},{name:"Sandbox repo",value:"sandbox",description:"Disposable GitHub repo"},{name:"Block from design",value:"from-design",description:"Figma, Framer or Google Stitch"},{name:"Migrate component",value:"migrate",description:"Classic AEM component \u2192 EDS"},{name:"Scaffold UE",value:"scaffold",description:"Universal Editor components"},{name:"Empty block",value:"create",description:"Create a bare block"},{name:"Integration",value:"integrate",description:"GTM, chat, consent\u2026"},{name:"Model fields",value:"model",description:"Add fields to a block model (partials)"},{name:"Analytics",value:"track",description:"Instrument a block (dataLayer)"},{name:"Structured data",value:"schema",description:"Add JSON-LD to a block"},{name:"Universal Editor",value:"ue",description:"Check readiness / open the editor"},{name:"Preview block",value:"preview-block",description:"Live preview in the browser"},{name:"Pages",value:"admin",description:"Preview / publish (Admin API)"},{name:"Audit",value:"audit",description:"Doctor / loading / security"},{name:"Figma MCP",value:"figma-setup",description:"Configure the connection"},{name:"Exit",value:"exit",description:"Quit eds (or press Esc)"}]});f();import Xf from"chalk";import{Command as Yf}from"commander";var uo={name:"aem-eds-kit",version:"0.4.60",description:"CLI for AEM Edge Delivery Services: blocks from Figma, Framer or Google Stitch designs, AEM component migration (AEMaaCS and 6.5), Universal Editor models and QA",type:"module",engines:{node:">=20"},bin:{eds:"dist/bin/eds.js"},files:["dist","samples","CHANGELOG.md"],scripts:{dev:"tsx src/bin/eds.ts",build:"tsup",test:"vitest run","test:watch":"vitest",lint:"biome check src/ tests/","lint:fix":"biome check --write src/ tests/",typecheck:"tsc --noEmit",prepare:"git config core.hooksPath .githooks || true",prepublishOnly:"npm run build"},keywords:["aem","edge-delivery-services","helix","figma","mcp","cli","adobe","aem-edge-delivery","universal-editor","aemaacs","aem-migration","framer","google-stitch","design-to-code","claude-code"],author:"Piotr Godycki <piotrgodycki@yahoo.com>",license:"MIT",repository:{type:"git",url:"git+https://github.com/piotrgodycki/aem-eds-kit.git"},homepage:"https://piotrgodycki.github.io/aem-eds-kit/",bugs:{url:"https://github.com/piotrgodycki/aem-eds-kit/issues"},dependencies:{"@inquirer/prompts":"^7.0.0",chalk:"^5.4.0",commander:"^13.0.0",execa:"^9.5.0","fast-xml-parser":"^5.11.2",ora:"^8.1.0",yaml:"^2.6.0",zod:"^3.24.0"},devDependencies:{"@biomejs/biome":"^1.9.0","@types/node":"^22.0.0",tsup:"^8.3.0",tsx:"^4.19.0",typescript:"^5.7.0",vitest:"^2.1.0"},optionalDependencies:{"@modelcontextprotocol/sdk":"^1.29.0",pixelmatch:"^6.0.0",playwright:"^1.64.0",pngjs:"^7.0.0"}};Se();N();H();var G=new Yf;G.name("eds").description("CLI for AEM Edge Delivery Services: blocks from Figma, Framer or Stitch designs, AEM migration, Universal Editor models and QA").version(uo.version).option("--verbose","Enable verbose output").option("--quiet","Suppress non-error output").option("--json","Machine-readable output (block from-design and draft: JSON-lines events on stdout)").option("--no-color","Disable color output").showHelpAfterError("(add --help for usage)").hook("preAction",e=>{let t=e.opts();t.verbose&&s.setLevel("debug"),t.quiet&&s.setQuiet(!0),t.color===!1&&(Xf.level=0)});async function $t(e,t){G.opts().json&&(B.enable(),B.emit({type:"start",command:e,cli:uo.version}));try{await t()}catch(n){s.error(n instanceof Error?n.message:String(n)),process.exitCode=1}finally{let n=Number(process.exitCode??0);B.emit({type:"result",ok:n===0,exitCode:n})}}G.addHelpText("beforeAll",()=>A());G.command("new [dir]").description("Clone the latest EDS boilerplate into a local folder (no GitHub auth)").option("--boilerplate <repo>","da | ue | commerce, owner/repo on GitHub, or any git URL (default adobe/aem-boilerplate)").option("--ue","Use the crosswalk / Universal Editor boilerplate").option("--ref <ref>","Branch or tag to clone").option("--keep-history","Keep the boilerplate's git history (remote renamed to upstream)").option("--remote <url>","Set origin to your own repo").option("--install","Run npm install after cloning").option("--yes","Skip the guided prompts").action(async(e,t)=>{let{newProject:n}=await Promise.resolve().then(()=>(Lo(),Fo));await n(e,t)});var pn=G.command("sandbox").description("Disposable EDS sandbox repos on GitHub");pn.command("new <name>").description("Create a disposable EDS repo from a boilerplate (GitHub auth, no gh required)").option("--org <org>","Create under a GitHub org (else your account)").option("--boilerplate <repo>","Template repo (default adobe/aem-boilerplate)").option("--ue","Use the crosswalk / Universal Editor boilerplate").option("--private","Create a private repo").option("--yes","Skip the guided prompts (use flags/defaults)").action(async(e,t)=>{let{sandboxNew:n}=await Promise.resolve().then(()=>(ze(),Je));await n(e,t)});pn.command("login").description("Authorize GitHub (OAuth device flow or a token) - no gh needed").action(async()=>{let{sandboxLogin:e}=await Promise.resolve().then(()=>(ze(),Je));await e()});pn.command("logout").description("Remove the stored GitHub token").action(async()=>{let{sandboxLogout:e}=await Promise.resolve().then(()=>(ze(),Je));await e()});pn.command("list").description("List your EDS sandboxes (repos tagged eds-sandbox)").action(async()=>{let{sandboxList:e}=await Promise.resolve().then(()=>(ze(),Je));await e()});pn.command("rm <name>").description("Delete a sandbox repo (destructive)").option("--org <org>","Owner org (else your account)").option("--yes","Skip the confirmation").action(async(e,t)=>{let{sandboxRm:n}=await Promise.resolve().then(()=>(ze(),Je));await n(e,t)});var Qf=G.command("template").description("Generate page templates / initial content");Qf.command("new <name>").description("Generate EDS page initial content (sections + blocks + metadata), DA push optional").option("--path <path>","Content path (default: /templates/<name>)").option("--title <title>","Page title").option("--description <text>","Page description").option("--blocks <list>","Comma-separated block ids to seed",e=>e.split(",").map(t=>t.trim())).option("--area <area>","Site area / template label (stored in metadata)").option("--authoring <model>","Force authoring model: da | gdrive | sharepoint | ue").option("--push","Push the page to DA (da.live)").option("--org <org>","DA org (else from .edsrc.json)").option("--site <site>","DA site (else from .edsrc.json)").option("--yes","Skip prompts").action(async(e,t)=>{let{templateNew:n}=await Promise.resolve().then(()=>(Ho(),Bo));await n(e,t)});G.command("init").description("Set up a freshly cloned EDS boilerplate for your authoring model (interactive)").option("--name <name>","Project name (kebab-case)").option("--authoring <model>","Authoring model: ue | da | gdrive | sharepoint").option("--mountpoint <url>","Content source URL (document models)").option("--org <org>","DA org (authoring=da)").option("--site <site>","DA site (authoring=da)").option("--no-ci","Skip the GitHub Actions CI workflow").option("--no-env","Skip the local-dev .env (aem up config)").option("--no-xwalk","Skip xwalk.json (UE multi-field)").option("--yes","Skip prompts; apply with flags/defaults").action(async e=>{let{initProject:t}=await Promise.resolve().then(()=>(Lt(),Ft));await t(e)});var Zf=G.command("migrate").description("Migrate from classic AEM to EDS");Zf.command("component [dir]").description("Migrate a classic AEM component's dialog into an EDS block + UE model").option("--name <name>","Block name (otherwise inferred from the component)").option("--clientlib <dir>","Path to the component's clientlib (otherwise auto-detected)").option("--super-root <dirs>","jcr_root folder(s), comma-separated, holding a proxy component's super type (e.g. a Core Components checkout)").option("--yes","Skip confirmation prompts").action(async(e,t)=>{let{migrateComponent:n}=await Promise.resolve().then(()=>(Xo(),Vo));await n(e,t)});var eg=G.command("model").description("Compose Universal Editor models");eg.command("add <block> [partials...]").description("Add reusable field groups (partials) to a block's UE model").option("--yes","Skip prompts").action(async(e,t,n)=>{let{modelAdd:o}=await Promise.resolve().then(()=>(ri(),ii));await o(e,t,n)});var tg=G.command("schema").description("Structured data (JSON-LD) for blocks");tg.command("block <name>").description("Inject a JSON-LD (schema.org) builder into a block's decorate()").option("--type <type>","schema.org type (Article, FAQPage, Product, ...)").option("--yes","Skip prompts").action(async(e,t)=>{let{schemaBlock:n}=await Promise.resolve().then(()=>(ai(),si));await n(e,t)});var ng=G.command("track").description("Instrument blocks for analytics");ng.command("block <name>").description("Add dataLayer tracking (click + form submit) to a block's decorate()").option("--no-click","Skip click tracking").option("--no-submit","Skip form-submit tracking").action(async(e,t)=>{let{trackBlock:n}=await Promise.resolve().then(()=>(Ht(),Bt));await n(e,t)});var El=G.command("ue").description("Universal Editor - readiness check + editor deep link");El.command("check").description("Check whether blocks are Universal-Editor-ready (offline)").action(async()=>{let{ueCheck:e}=await Promise.resolve().then(()=>(zt(),Jt));await e()});El.command("open [path]").description("Open a page in the hosted Universal Editor (preview host from git)").option("--org <slug>","IMS org slug (skips the org picker)").option("--ref <branch>","Branch/ref for the preview host (default: main)").option("--url <host>","Override the delivery host (e.g. main--repo--owner.aem.page)").option("--no-open","Print the link without opening the browser").action(async(e,t)=>{let{ueOpen:n}=await Promise.resolve().then(()=>(zt(),Jt));await n(e,t)});var St=G.command("block").description("Manage EDS blocks");St.command("create <name>").description("Scaffold a new EDS block (with Universal Editor model by default)").option("--no-ue-model","Skip the Universal Editor model (generated by default)").action(async(e,t)=>{let{createBlock:n}=await Promise.resolve().then(()=>(mi(),di));await n(e,t)});St.command("from-design [design]").description("Generate an EDS block from a design: a Figma URL, a Framer/Stitch or any web page (scraped with headless Chromium), or a local SVG/PNG export (quota-free, no MCP). Interactive wizard when run with no argument.").option("--name <name>","Override the inferred block name").option("--provider <type>","Design source: figma | framer | stitch | web (else detected from the URL)").option("--agent <type>","Force agent type: claude | cursor | codex | ollama | omlx | local (any OpenAI-compatible server) | none").option("--model <name>","Model to run (Claude alias/id, or a local model, e.g. qwen2.5-coder:14b)").option("--dry-run","Generate prompt only, do not invoke agent").option("--source <type>","Content source: document|ue|cf|mixed (default: document)").option("--widths <list>","Design frame widths for preview breakpoints (e.g. 390,768,1440)").option("--no-ue-model","Skip the Universal Editor model (generated by default)").option("--screenshot","Add a screenshot MCP call for pixel verification (opt-in; costs a call)").option("--mcp","Force the Figma MCP adapter even when a REST token is set").option("--refresh","Ignore the cached design snapshot and re-fetch").option("--auth","Scrape with a logged-in session (Framer/Stitch) \u2014 login captured once, then reused").option("--auth-refresh","Force a fresh scrape login even if a session is saved").option("--sample","Use the bundled sample design (the example file's hero) \u2014 no URL, no token, no MCP").option("--serve","Auto-start the live preview after generating (non-interactive runs only)").option("--draft","Generate a draft (tmp/eds-cli/drafts/<name>/vN) for review; blocks/ changes only on eds draft accept").option("--yes","Skip confirmation prompts").action(async(e,t)=>{await $t("block from-design",async()=>{let{blockFromDesign:n}=await Promise.resolve().then(()=>(io(),oo));await n(e,t)})});var un=G.command("draft").description("Review drafts from `block from-design --draft`: preview, refine, accept or discard");un.command("list").description("List drafts and their versions").action(async()=>{await $t("draft list",async()=>{let{draftList:e}=await Promise.resolve().then(()=>(yt(),bt));await e()})});un.command("preview <name> [version]").description("Preview a draft version in the browser (default: the latest), e.g. hero 2").option("--port <port>","Port to serve on (default 8777)").option("--widths <list>","Breakpoint widths").option("--no-open","Don't open the browser").action(async(e,t,n)=>{await $t("draft preview",async()=>{let{draftPreview:o}=await Promise.resolve().then(()=>(yt(),bt));await o(e,{...n,version:t})})});un.command("refine <name> <feedback>").description("One more agent round on the draft; the result is the next version").option("--from <n>","Start from this version (default: the latest)").option("--agent <type>","Agent (default: the one that made the draft)").option("--model <name>","Model (default: the one that made the draft)").action(async(e,t,n)=>{await $t("draft refine",async()=>{let{draftRefine:o}=await Promise.resolve().then(()=>(yt(),bt)),{from:i,...r}=n;await o(e,t,{...r,version:i})})});un.command("accept <name> [version]").description("Copy a draft version (default: the latest) into blocks/<name>/, optionally commit it").option("--commit","Commit blocks/<name>/ with the review rounds in the message").option("--branch <name>","Commit on this branch (created if missing; implies --commit)").action(async(e,t,n)=>{await $t("draft accept",async()=>{let{draftAccept:o}=await Promise.resolve().then(()=>(yt(),bt));await o(e,{...n,version:t})})});un.command("discard <name>").description("Drop a draft and its versions; blocks/ is untouched").action(async e=>{await $t("draft discard",async()=>{let{draftDiscard:t}=await Promise.resolve().then(()=>(yt(),bt));await t(e)})});St.command("list").description("List all blocks in the project").action(async e=>{let{listBlocks:t}=await Promise.resolve().then(()=>(Kc(),qc));await t({...e,json:G.opts().json})});St.command("preview [name]").description("Serve a live, breakpoint-switchable preview of a block \u2014 or a gallery of all blocks when no name is given").option("--port <port>","Port to serve on (default: 8777, falls back if taken)").option("--widths <list>","Comma-separated breakpoint widths (e.g. 375,768,1280)").option("--no-open","Do not open the browser automatically").action(async(e,t)=>{let n=await Promise.resolve().then(()=>(Oe(),wt));e?await n.previewBlock(e,t):await n.galleryPreview(t)});St.command("test [name]").description("Visual-regression test a block (or all blocks) against committed baselines").option("--update","(Re)write the baseline screenshots instead of comparing").option("--threshold <ratio>","Max changed-pixel ratio before failing (default 0.01 = 1%)").option("--design","Compare the rendered block against its Figma design image (needs a token)").option("--widths <list>","Comma-separated breakpoint widths (e.g. 375,768,1280)").option("--port <port>","Port for the internal preview server (default: 8788)").action(async(e,t)=>{let{visualTest:n}=await Promise.resolve().then(()=>(al(),sl));await n(e,t)});St.command("check [name]").description("Content, link and a11y check on a block's rendered DOM (or all blocks)").option("--strict","Fail on warnings too, not just errors").option("--widths <list>","Comma-separated breakpoint widths (uses the widest)").option("--port <port>","Port for the internal preview server (default: 8789)").action(async(e,t)=>{let{blockCheck:n}=await Promise.resolve().then(()=>(ml(),dl));await n(e,t)});var jt=G.command("scaffold").description("Scaffold standard UE components and blocks").action(async()=>{let{scaffoldInteractive:e}=await Promise.resolve().then(()=>(ue(),we));await e()});jt.command("ue").description("Scaffold default-content UE components + a field-reference block (all 17 fields)").action(async()=>{let{scaffoldUe:e}=await Promise.resolve().then(()=>(ue(),we));await e()});jt.command("blocks [names...]").description("Scaffold standard blocks (hero, cards, columns, accordion, embed) with UE models").action(async e=>{let{scaffoldBlocks:t}=await Promise.resolve().then(()=>(ue(),we));await t(e)});jt.command("ci").description("Scaffold a GitHub Actions workflow (doctor + audits + project lint/build)").action(async()=>{let{scaffoldCi:e}=await Promise.resolve().then(()=>(ue(),we));await e()});jt.command("helpers [names...]").description("Scaffold scripts/utils.js with chosen EDS helpers (interactive picker)").action(async e=>{let{scaffoldHelpers:t}=await Promise.resolve().then(()=>(ue(),we));await t(e)});jt.command("env").description("Write a local-dev .env for `aem up` (AEM_OPEN / AEM_PORT / AEM_PAGES_URL)").option("--open <path>","AEM_OPEN - path opened on start (default: /)").option("--port <port>","AEM_PORT - proxy port (default: 3007)").option("--pages-url <url>","AEM_PAGES_URL - content origin (default: from git remote)").option("--yes","Skip prompts; use flags/defaults").action(async e=>{let{scaffoldEnv:t}=await Promise.resolve().then(()=>(ue(),we));await t(e)});jt.command("xwalk").description("Write xwalk.json enabling Universal Editor multi-field support").action(async()=>{let{scaffoldXwalk:e}=await Promise.resolve().then(()=>(ue(),we));await e()});G.command("integrate [type]").description("Add a third-party service (GTM, GA4, chat, consent) to scripts/delayed.js").action(async e=>{let{integrate:t}=await Promise.resolve().then(()=>(Qi(),Yi));await t(e)});var og=G.command("figma").description("Figma MCP integration");og.command("setup").description("Configure Figma MCP for your AI agent").action(async()=>{let{figmaSetup:e}=await Promise.resolve().then(()=>(er(),Zi));await e()});G.command("doctor").description("Audit your EDS project for common issues").action(async()=>{let{doctor:e}=await Promise.resolve().then(()=>(nr(),tr));await e({json:G.opts().json})});var Cl=G.command("audit").description("Run project audits");Cl.command("loading").description("Check loading order (eager/lazy/delayed phases, LCP budget)").action(async()=>{let{auditLoading:e}=await Promise.resolve().then(()=>(rr(),ir));await e({json:G.opts().json})});Cl.command("security").description("Scan for vulnerabilities (npm audit) and exploit patterns (XSS, secrets, tabnabbing)").action(async()=>{let{auditSecurity:e}=await Promise.resolve().then(()=>(cr(),ar));await e({json:G.opts().json})});G.command("preview [paths...]").description("Preview pages via Admin API (interactive wizard when run with no paths)").option("--org <org>","GitHub org/owner").option("--site <site>","Repository name").option("--ref <ref>","Git ref (default: main)").action(async(e,t)=>{if(!e||e.length===0){let{adminWizard:o}=await Promise.resolve().then(()=>(po(),mo));await o("preview");return}let{preview:n}=await Promise.resolve().then(()=>(lo(),pr));await n(e,t)});G.command("publish [paths...]").description("Publish pages to live via Admin API (interactive wizard when run with no paths)").option("--org <org>","GitHub org/owner").option("--site <site>","Repository name").option("--ref <ref>","Git ref (default: main)").action(async(e,t)=>{if(!e||e.length===0){let{adminWizard:o}=await Promise.resolve().then(()=>(po(),mo));await o("publish");return}let{publish:n}=await Promise.resolve().then(()=>(fr(),ur));await n(e,t)});(async()=>{try{if(process.argv.slice(2).length===0)if(process.stdout.isTTY){let{mainMenu:e}=await Promise.resolve().then(()=>(Pl(),jl));await e()}else G.outputHelp();else await G.parseAsync()}catch(e){s.error(e instanceof Error?e.message:String(e)),process.exitCode=1}})();
1126
+ `);for(let r=0;r<i.length;r++){let a=i[r],c=!1;for(let l of Tf)l.ext.includes(n)&&(l.id==="innerhtml-static"&&c||l.re.test(a)&&(l.extra&&!l.extra(a)||(l.id==="innerhtml-dynamic"&&(c=!0),o.push({severity:l.severity,rule:l.id,message:l.message,file:t,line:r+1,snippet:a.trim().slice(0,100)}))))}return o}async function Lf(e){if(!ao(et.join(e,"package.json")))return{status:"skipped",note:"no package.json"};if(!(ao(et.join(e,"package-lock.json"))||ao(et.join(e,"npm-shrinkwrap.json")))&&!ao(et.join(e,"node_modules")))return{status:"skipped",note:"no package-lock.json / node_modules \u2014 run npm install"};try{let{execa:n}=await import("execa"),{stdout:o}=await n("npm",["audit","--json"],{cwd:e,reject:!1}),r=JSON.parse(o)?.metadata?.vulnerabilities??{},a={critical:r.critical??0,high:r.high??0,moderate:r.moderate??0,low:r.low??0};return{status:a.critical+a.high+a.moderate+a.low>0?"vulnerable":"ok",counts:a}}catch(n){return{status:"skipped",note:`npm audit failed: ${n.message}`}}}async function Nf(e={}){let t=E();if(!t){s.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n=[];for await(let l of vl(t)){let d=et.extname(l).slice(1).toLowerCase();if(!Df.has(d))continue;let m=et.relative(t,l);if(m.endsWith("aem.js")||m.endsWith("lib-franklin.js"))continue;let p=await Ef(l,"utf-8");n.push(...Ff(p,m,d))}let o=await Lf(t),i=l=>n.filter(d=>d.severity===l),r={critical:i("critical").length,high:i("high").length,moderate:i("moderate").length,low:i("low").length},a=r.critical>0||r.high>0||(o.counts?.critical??0)>0||(o.counts?.high??0)>0;if(e.json){console.log(JSON.stringify({projectRoot:t,dependencies:o,findings:n,summary:{code:r}},null,2)),a&&(process.exitCode=1);return}if(s.logoOnce(A("Security Audit")),s.info(j("Dependencies","npm audit")),o.status==="skipped")s.info(R("info","npm audit",o.note??"skipped"));else if(o.status==="ok")s.info(R("pass","npm audit","no known vulnerabilities"));else{let l=o.counts??{critical:0,high:0,moderate:0,low:0};s.info(R(l.critical+l.high>0?"fail":"warn","npm audit",`${l.critical} critical, ${l.high} high, ${l.moderate} moderate, ${l.low} low \u2014 run \`npm audit fix\``))}if(s.info(j("Exploit scan","XSS \xB7 secrets \xB7 injection \xB7 tabnabbing")),n.length===0)s.info(R("pass","code","no risky patterns found"));else{let l=[...n].sort((d,m)=>yl.indexOf(d.severity)-yl.indexOf(m.severity));for(let d of l){let m=Af[d.severity],p=sr.dim(`${d.file}:${d.line}`);s.info(` ${gn(m.status)} ${sr.bold(m.label)} ${d.message} ${p}`),s.info(sr.dim(` ${d.snippet}`))}}let c=je({fail:r.critical+r.high+(o.counts?.critical??0)+(o.counts?.high??0),warn:r.moderate+(o.counts?.moderate??0),info:r.low+(o.counts?.low??0)});s.info(""),s.info(J([c||`${Y.pass} no vulnerabilities or risky patterns found`])),a&&(process.exitCode=1)}var Tf,yl,Af,Rf,Df,cr=v(()=>{"use strict";f();N();V();H();Tf=[{id:"eval",severity:"critical",re:/\beval\s*\(/,message:"eval() executes arbitrary code \u2014 prime XSS / RCE vector",ext:["js","mjs","html"]},{id:"aws-key",severity:"critical",re:/\bAKIA[0-9A-Z]{16}\b/,message:"Hardcoded AWS access key id",ext:["js","mjs","html","json"]},{id:"private-key",severity:"critical",re:/-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/,message:"Embedded private key material",ext:["js","mjs","html","json","pem","txt"]},{id:"new-function",severity:"high",re:/\bnew\s+Function\s*\(/,message:"new Function() runs strings as code",ext:["js","mjs","html"]},{id:"document-write",severity:"high",re:/document\.write(?:ln)?\s*\(/,message:"document.write() enables XSS and blocks parsing",ext:["js","mjs","html"]},{id:"innerhtml-dynamic",severity:"high",re:/\.(?:inner|outer)HTML\s*=\s*[^;\n]*(?:\$\{|\+|concat)/,message:"Dynamic innerHTML assignment \u2014 sanitize or use textContent / DOM APIs",ext:["js","mjs"]},{id:"insert-adjacent-html",severity:"high",re:/insertAdjacentHTML\s*\(/,message:"insertAdjacentHTML with untrusted data is an XSS vector",ext:["js","mjs"]},{id:"js-url",severity:"high",re:/(?:href|src)\s*=\s*["']?\s*javascript:/i,message:"javascript: URL \u2014 XSS vector",ext:["js","mjs","html"]},{id:"secret",severity:"high",re:/(?:api[_-]?key|secret|access[_-]?token|auth[_-]?token|client[_-]?secret|passwd|password)\s*[:=]\s*["'][^"']{8,}["']/i,message:"Possible hardcoded secret / credential",ext:["js","mjs","html","json"],extra:e=>!/(example|placeholder|your[-_]|changeme|xxxx|<[^>]+>|\$\{)/i.test(e)},{id:"bearer-token",severity:"high",re:/Bearer\s+[A-Za-z0-9\-._~+/]{20,}/,message:"Hardcoded bearer token",ext:["js","mjs","html","json"]},{id:"innerhtml-static",severity:"moderate",re:/\.(?:inner|outer)HTML\s*=/,message:"innerHTML assignment \u2014 confirm the content is trusted / sanitized",ext:["js","mjs"]},{id:"insecure-url",severity:"moderate",re:/(?:href|src)\s*=\s*["']http:\/\/(?!localhost|127\.0\.0\.1)/i,message:"Insecure http:// resource \u2014 mixed content, use https://",ext:["html","js","mjs"]},{id:"target-blank",severity:"moderate",re:/target\s*=\s*["']_blank["']/,message:'target="_blank" without rel="noopener" \u2014 reverse tabnabbing',ext:["html","js","mjs"],extra:e=>!/rel\s*=\s*["'][^"']*noopener/i.test(e)},{id:"postmessage-wildcard",severity:"moderate",re:/postMessage\s*\([^,]+,\s*["']\*["']\s*\)/,message:"postMessage to '*' origin \u2014 restrict the target origin",ext:["js","mjs"]},{id:"inline-handler",severity:"low",re:/\son[a-z]+\s*=\s*["']/i,message:"Inline event handler \u2014 move to addEventListener (CSP-unfriendly)",ext:["html"]},{id:"console-log",severity:"low",re:/console\.(?:log|debug)\s*\(/,message:"console.log / debug left in code \u2014 potential info leak",ext:["js","mjs"]}],yl=["critical","high","moderate","low"],Af={critical:{status:"fail",label:"CRIT"},high:{status:"fail",label:"HIGH"},moderate:{status:"warn",label:"MOD "},low:{status:"info",label:"LOW "}},Rf=new Set(["node_modules",".git","dist","build",".vscode","coverage"]),Df=new Set(["js","mjs","html","json","pem","txt"])});async function kl(e,t,n){let o=t.ref||"main",i=n.startsWith("/")?n:`/${n}`,r=`${Of}/${e}/${t.org}/${t.site}/${o}${i}`;s.debug(`POST ${r}`);let a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"}}),c=await a.json().catch(()=>({})),l=c;return a.ok?{ok:!0,status:a.status,path:i,previewUrl:l.preview?.url,liveUrl:l.live?.url}:{ok:!1,status:a.status,path:i,message:c.message||`HTTP ${a.status}`}}async function lr(e,t){return kl("preview",e,t)}async function dr(e,t){return kl("live",e,t)}async function xl(e,t){return Promise.all(t.map(n=>lr(e,n)))}async function $l(e,t){return Promise.all(t.map(n=>dr(e,n)))}var Of,mr=v(()=>{"use strict";f();N();Of="https://admin.hlx.page"});var pr={};U(pr,{preview:()=>_f,resolveAdminConfig:()=>co});import Sl from"chalk";import Mf from"ora";async function _f(e,t){let n=E(),o=await ce(n),i=co(o,t);if(!i)return;let r=Mf(`Previewing ${e.length} path(s)...`).start(),a=e.length===1?[await lr(i,e[0])]:await xl(i,e);r.stop();let c=!1;for(let l of a)l.ok?s.success(`${l.path} \u2192 ${Sl.cyan(l.previewUrl||"preview updated")}`):(s.error(`${l.path} \u2014 ${l.message}`),c=!0);c&&(process.exitCode=1)}function co(e,t){let n=t.org||e.admin?.org,o=t.site||e.admin?.site,i=t.ref||e.admin?.ref||"main";if(!n||!o){s.error("Missing --org and --site. Set them via flags or in .edsrc.json:"),s.info(Sl.dim(' { "admin": { "org": "my-org", "site": "my-site" } }')),process.exitCode=1;return}return{org:n,site:o,ref:i}}var lo=v(()=>{"use strict";f();mr();fe();N();V()});var ur={};U(ur,{publish:()=>Bf});import If from"chalk";import Uf from"ora";async function Bf(e,t){let n=E(),o=await ce(n),i=co(o,t);if(!i)return;let r=Uf(`Publishing ${e.length} path(s)...`).start(),a=e.length===1?[await dr(i,e[0])]:await $l(i,e);r.stop();let c=!1;for(let l of a)l.ok?s.success(`${l.path} \u2192 ${If.cyan(l.liveUrl||"published")}`):(s.error(`${l.path} \u2014 ${l.message}`),c=!0);c&&(process.exitCode=1)}var fr=v(()=>{"use strict";f();mr();fe();N();V();lo()});var mo={};U(mo,{adminWizard:()=>Hf});async function Hf(e){let t=E();if(!t){s.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}s.logoOnce(A("Admin API \u2014 preview / publish"));let{select:n,input:o,confirm:i}=await Promise.resolve().then(()=>(K(),q)),a=(await ce(t)).admin??{},c=e??await n({message:"What do you want to do?",choices:[{name:"Preview pages (staging)",value:"preview"},{name:"Publish pages (go live)",value:"publish"}]}),l=(await o({message:"GitHub org / owner",default:a.org})).trim(),d=(await o({message:"Repository / site",default:a.site})).trim(),m=(await o({message:"Git ref",default:a.ref||"main"})).trim(),u=(await o({message:"Paths (space- or comma-separated)",default:"/"})).split(/[\s,]+/).filter(Boolean);if(!l||!d||u.length===0){s.error("org, site and at least one path are required."),process.exitCode=1;return}s.info(j("Summary"));let g=I(["operation","org","site","ref","paths"]);if(s.info(P("operation",c,g)),s.info(P("org",l,g)),s.info(P("site",d,g)),s.info(P("ref",m,g)),s.info(P("paths",u.join(", "),g)),s.info(""),c==="publish"&&!await i({message:`Publish ${u.length} path(s) to LIVE?`,default:!1})){s.info("Cancelled.");return}let h={org:l,site:d,ref:m};if(c==="preview"){let{preview:$}=await Promise.resolve().then(()=>(lo(),pr));await $(u,h)}else{let{publish:$}=await Promise.resolve().then(()=>(fr(),ur));await $(u,h)}}var po=v(()=>{"use strict";f();fe();N();V();H()});var jl={};U(jl,{mainMenu:()=>Kf});import{existsSync as Gf}from"fs";import{readdir as Wf}from"fs/promises";import Jf from"path";import zf from"chalk";async function gr(e){let t=Jf.join(e,"blocks");return Gf(t)?(await Wf(t,{withFileTypes:!0})).filter(o=>o.isDirectory()).map(o=>o.name):[]}async function Kf(){let{select:e,isEscape:t,isExit:n}=await Promise.resolve().then(()=>(K(),q));Qn.menu=!0,await s.logoOnceAnimated("");let o;for(;;){s.info(zf.dim(" Esc quits here \xB7 goes back to this menu from any step"));let i;try{i=await e({message:"Choose an action",choices:qf,default:o})}catch(r){if(t(r)||n(r))return;throw r}if(i==="exit")return;o=i;try{await Vf(i)}catch(r){if(n(r))return;t(r)||s.error(r instanceof Error?r.message:String(r))}process.exitCode=void 0,s.info("")}}async function Vf(e){let{select:t,input:n}=await Promise.resolve().then(()=>(K(),q));switch(e){case"new":{let{newProject:o}=await Promise.resolve().then(()=>(Lo(),Fo));await o(void 0,{});return}case"init":{let{initProject:o}=await Promise.resolve().then(()=>(Lt(),Ft));await o({});return}case"template":{let o=await n({message:"Template name",validate:r=>!!r.trim()||"Required"}),{templateNew:i}=await Promise.resolve().then(()=>(Ho(),Bo));await i(o.trim(),{});return}case"sandbox":{let o=await n({message:"Sandbox repo name",validate:r=>/^[a-z0-9][a-z0-9._-]*$/i.test(r.trim())||"Use a valid repo name"}),{sandboxNew:i}=await Promise.resolve().then(()=>(ze(),Je));await i(o.trim(),{});return}case"from-design":{let{blockFromDesign:o}=await Promise.resolve().then(()=>(io(),oo));await o(void 0,{});return}case"migrate":{let{migrateComponent:o}=await Promise.resolve().then(()=>(Xo(),Vo));await o(void 0,{});return}case"scaffold":{let{scaffoldInteractive:o}=await Promise.resolve().then(()=>(ue(),we));await o();return}case"create":{let o=await n({message:"Block name",validate:r=>He.test(r.trim())||"Use kebab-case, e.g. hero-banner"}),{createBlock:i}=await Promise.resolve().then(()=>(mi(),di));await i(o.trim(),{});return}case"integrate":{let{integrate:o}=await Promise.resolve().then(()=>(Qi(),Yi));await o(void 0);return}case"preview-block":{let o=E();if(!o){s.error("Not inside an EDS project (no EDS project markers found).");return}let i=await gr(o);if(i.length===0){s.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(c=>({name:c,value:c}))}),{previewBlock:a}=await Promise.resolve().then(()=>(Oe(),wt));await a(r,{});return}case"model":{let{modelAdd:o}=await Promise.resolve().then(()=>(ri(),ii));await o(void 0,[],{});return}case"track":{let o=E();if(!o){s.error("Not inside an EDS project (no EDS project markers found).");return}let i=await gr(o);if(i.length===0){s.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block to instrument?",choices:i.map(c=>({name:c,value:c}))}),{trackBlock:a}=await Promise.resolve().then(()=>(Ht(),Bt));await a(r,{});return}case"schema":{let o=E();if(!o){s.error("Not inside an EDS project (no EDS project markers found).");return}let i=await gr(o);if(i.length===0){s.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(c=>({name:c,value:c}))}),{schemaBlock:a}=await Promise.resolve().then(()=>(ai(),si));await a(r,{});return}case"ue":{if(await t({message:"Universal Editor:",choices:[{name:"Check readiness (which blocks are editable)",value:"check"},{name:"Open a page in the editor",value:"open"}]})==="check"){let{ueCheck:i}=await Promise.resolve().then(()=>(zt(),Jt));await i()}else{let i=await n({message:"Page path",default:"/"}),{ueOpen:r}=await Promise.resolve().then(()=>(zt(),Jt));await r(i.trim()||"/",{})}return}case"admin":{let{adminWizard:o}=await Promise.resolve().then(()=>(po(),mo));await o();return}case"audit":{let o=await t({message:"Which audit?",choices:[{name:"Doctor \u2014 overall project health",value:"doctor"},{name:"Loading \u2014 three-phase / LCP budget",value:"loading"},{name:"Security \u2014 vulnerabilities & exploit patterns",value:"security"}]});if(o==="doctor"){let{doctor:i}=await Promise.resolve().then(()=>(nr(),tr));await i({})}else if(o==="loading"){let{auditLoading:i}=await Promise.resolve().then(()=>(rr(),ir));await i({})}else{let{auditSecurity:i}=await Promise.resolve().then(()=>(cr(),ar));await i({})}return}case"figma-setup":{let{figmaSetup:o}=await Promise.resolve().then(()=>(er(),Zi));await o();return}}}var qf,Pl=v(()=>{"use strict";f();N();V();nt();Zn();qf=[{name:"New project",value:"new",description:"Clone the latest EDS boilerplate"},{name:"Set up project",value:"init",description:"Authoring model, CI, naming"},{name:"Page template",value:"template",description:"Generate initial content"},{name:"Sandbox repo",value:"sandbox",description:"Disposable GitHub repo"},{name:"Block from design",value:"from-design",description:"Figma, Framer or Google Stitch"},{name:"Migrate component",value:"migrate",description:"Classic AEM component \u2192 EDS"},{name:"Scaffold UE",value:"scaffold",description:"Universal Editor components"},{name:"Empty block",value:"create",description:"Create a bare block"},{name:"Integration",value:"integrate",description:"GTM, chat, consent\u2026"},{name:"Model fields",value:"model",description:"Add fields to a block model (partials)"},{name:"Analytics",value:"track",description:"Instrument a block (dataLayer)"},{name:"Structured data",value:"schema",description:"Add JSON-LD to a block"},{name:"Universal Editor",value:"ue",description:"Check readiness / open the editor"},{name:"Preview block",value:"preview-block",description:"Live preview in the browser"},{name:"Pages",value:"admin",description:"Preview / publish (Admin API)"},{name:"Audit",value:"audit",description:"Doctor / loading / security"},{name:"Figma MCP",value:"figma-setup",description:"Configure the connection"},{name:"Exit",value:"exit",description:"Quit eds (or press Esc)"}]});f();import Xf from"chalk";import{Command as Yf}from"commander";var uo={name:"aem-eds-kit",version:"0.4.61",description:"CLI for AEM Edge Delivery Services: blocks from Figma, Framer or Google Stitch designs, AEM component migration (AEMaaCS and 6.5), Universal Editor models and QA",type:"module",engines:{node:">=20"},bin:{eds:"dist/bin/eds.js"},files:["dist","samples","CHANGELOG.md"],scripts:{dev:"tsx src/bin/eds.ts",build:"tsup",test:"vitest run","test:watch":"vitest",lint:"biome check src/ tests/","lint:fix":"biome check --write src/ tests/",typecheck:"tsc --noEmit",prepare:"git config core.hooksPath .githooks || true",prepublishOnly:"npm run build"},keywords:["aem","edge-delivery-services","helix","figma","mcp","cli","adobe","aem-edge-delivery","universal-editor","aemaacs","aem-migration","framer","google-stitch","design-to-code","claude-code"],author:"Piotr Godycki <piotrgodycki@yahoo.com>",license:"MIT",repository:{type:"git",url:"git+https://github.com/piotrgodycki/aem-eds-kit.git"},homepage:"https://piotrgodycki.github.io/aem-eds-kit/",bugs:{url:"https://github.com/piotrgodycki/aem-eds-kit/issues"},dependencies:{"@inquirer/prompts":"^7.0.0",chalk:"^5.4.0",commander:"^13.0.0",execa:"^9.5.0","fast-xml-parser":"^5.11.2",ora:"^8.1.0",yaml:"^2.6.0",zod:"^3.24.0"},devDependencies:{"@biomejs/biome":"^1.9.0","@types/node":"^22.0.0",tsup:"^8.3.0",tsx:"^4.19.0",typescript:"^5.7.0",vitest:"^2.1.0"},optionalDependencies:{"@modelcontextprotocol/sdk":"^1.29.0",pixelmatch:"^6.0.0",playwright:"^1.64.0",pngjs:"^7.0.0"}};Se();N();H();var G=new Yf;G.name("eds").description("CLI for AEM Edge Delivery Services: blocks from Figma, Framer or Stitch designs, AEM migration, Universal Editor models and QA").version(uo.version).option("--verbose","Enable verbose output").option("--quiet","Suppress non-error output").option("--json","Machine-readable output (block from-design and draft: JSON-lines events on stdout)").option("--no-color","Disable color output").showHelpAfterError("(add --help for usage)").hook("preAction",e=>{let t=e.opts();t.verbose&&s.setLevel("debug"),t.quiet&&s.setQuiet(!0),t.color===!1&&(Xf.level=0)});async function $t(e,t){G.opts().json&&(B.enable(),B.emit({type:"start",command:e,cli:uo.version}));try{await t()}catch(n){s.error(n instanceof Error?n.message:String(n)),process.exitCode=1}finally{let n=Number(process.exitCode??0);B.emit({type:"result",ok:n===0,exitCode:n})}}G.addHelpText("beforeAll",()=>A());G.command("new [dir]").description("Clone the latest EDS boilerplate into a local folder (no GitHub auth)").option("--boilerplate <repo>","da | ue | commerce, owner/repo on GitHub, or any git URL (default adobe/aem-boilerplate)").option("--ue","Use the crosswalk / Universal Editor boilerplate").option("--ref <ref>","Branch or tag to clone").option("--keep-history","Keep the boilerplate's git history (remote renamed to upstream)").option("--remote <url>","Set origin to your own repo").option("--install","Run npm install after cloning").option("--yes","Skip the guided prompts").action(async(e,t)=>{let{newProject:n}=await Promise.resolve().then(()=>(Lo(),Fo));await n(e,t)});var pn=G.command("sandbox").description("Disposable EDS sandbox repos on GitHub");pn.command("new <name>").description("Create a disposable EDS repo from a boilerplate (GitHub auth, no gh required)").option("--org <org>","Create under a GitHub org (else your account)").option("--boilerplate <repo>","Template repo (default adobe/aem-boilerplate)").option("--ue","Use the crosswalk / Universal Editor boilerplate").option("--private","Create a private repo").option("--yes","Skip the guided prompts (use flags/defaults)").action(async(e,t)=>{let{sandboxNew:n}=await Promise.resolve().then(()=>(ze(),Je));await n(e,t)});pn.command("login").description("Authorize GitHub (OAuth device flow or a token) - no gh needed").action(async()=>{let{sandboxLogin:e}=await Promise.resolve().then(()=>(ze(),Je));await e()});pn.command("logout").description("Remove the stored GitHub token").action(async()=>{let{sandboxLogout:e}=await Promise.resolve().then(()=>(ze(),Je));await e()});pn.command("list").description("List your EDS sandboxes (repos tagged eds-sandbox)").action(async()=>{let{sandboxList:e}=await Promise.resolve().then(()=>(ze(),Je));await e()});pn.command("rm <name>").description("Delete a sandbox repo (destructive)").option("--org <org>","Owner org (else your account)").option("--yes","Skip the confirmation").action(async(e,t)=>{let{sandboxRm:n}=await Promise.resolve().then(()=>(ze(),Je));await n(e,t)});var Qf=G.command("template").description("Generate page templates / initial content");Qf.command("new <name>").description("Generate EDS page initial content (sections + blocks + metadata), DA push optional").option("--path <path>","Content path (default: /templates/<name>)").option("--title <title>","Page title").option("--description <text>","Page description").option("--blocks <list>","Comma-separated block ids to seed",e=>e.split(",").map(t=>t.trim())).option("--area <area>","Site area / template label (stored in metadata)").option("--authoring <model>","Force authoring model: da | gdrive | sharepoint | ue").option("--push","Push the page to DA (da.live)").option("--org <org>","DA org (else from .edsrc.json)").option("--site <site>","DA site (else from .edsrc.json)").option("--yes","Skip prompts").action(async(e,t)=>{let{templateNew:n}=await Promise.resolve().then(()=>(Ho(),Bo));await n(e,t)});G.command("init").description("Set up a freshly cloned EDS boilerplate for your authoring model (interactive)").option("--name <name>","Project name (kebab-case)").option("--authoring <model>","Authoring model: ue | da | gdrive | sharepoint").option("--mountpoint <url>","Content source URL (document models)").option("--org <org>","DA org (authoring=da)").option("--site <site>","DA site (authoring=da)").option("--no-ci","Skip the GitHub Actions CI workflow").option("--no-env","Skip the local-dev .env (aem up config)").option("--no-xwalk","Skip xwalk.json (UE multi-field)").option("--yes","Skip prompts; apply with flags/defaults").action(async e=>{let{initProject:t}=await Promise.resolve().then(()=>(Lt(),Ft));await t(e)});var Zf=G.command("migrate").description("Migrate from classic AEM to EDS");Zf.command("component [dir]").description("Migrate a classic AEM component's dialog into an EDS block + UE model").option("--name <name>","Block name (otherwise inferred from the component)").option("--clientlib <dir>","Path to the component's clientlib (otherwise auto-detected)").option("--super-root <dirs>","jcr_root folder(s), comma-separated, holding a proxy component's super type (e.g. a Core Components checkout)").option("--yes","Skip confirmation prompts").action(async(e,t)=>{let{migrateComponent:n}=await Promise.resolve().then(()=>(Xo(),Vo));await n(e,t)});var eg=G.command("model").description("Compose Universal Editor models");eg.command("add <block> [partials...]").description("Add reusable field groups (partials) to a block's UE model").option("--yes","Skip prompts").action(async(e,t,n)=>{let{modelAdd:o}=await Promise.resolve().then(()=>(ri(),ii));await o(e,t,n)});var tg=G.command("schema").description("Structured data (JSON-LD) for blocks");tg.command("block <name>").description("Inject a JSON-LD (schema.org) builder into a block's decorate()").option("--type <type>","schema.org type (Article, FAQPage, Product, ...)").option("--yes","Skip prompts").action(async(e,t)=>{let{schemaBlock:n}=await Promise.resolve().then(()=>(ai(),si));await n(e,t)});var ng=G.command("track").description("Instrument blocks for analytics");ng.command("block <name>").description("Add dataLayer tracking (click + form submit) to a block's decorate()").option("--no-click","Skip click tracking").option("--no-submit","Skip form-submit tracking").action(async(e,t)=>{let{trackBlock:n}=await Promise.resolve().then(()=>(Ht(),Bt));await n(e,t)});var El=G.command("ue").description("Universal Editor - readiness check + editor deep link");El.command("check").description("Check whether blocks are Universal-Editor-ready (offline)").action(async()=>{let{ueCheck:e}=await Promise.resolve().then(()=>(zt(),Jt));await e()});El.command("open [path]").description("Open a page in the hosted Universal Editor (preview host from git)").option("--org <slug>","IMS org slug (skips the org picker)").option("--ref <branch>","Branch/ref for the preview host (default: main)").option("--url <host>","Override the delivery host (e.g. main--repo--owner.aem.page)").option("--no-open","Print the link without opening the browser").action(async(e,t)=>{let{ueOpen:n}=await Promise.resolve().then(()=>(zt(),Jt));await n(e,t)});var St=G.command("block").description("Manage EDS blocks");St.command("create <name>").description("Scaffold a new EDS block (with Universal Editor model by default)").option("--no-ue-model","Skip the Universal Editor model (generated by default)").action(async(e,t)=>{let{createBlock:n}=await Promise.resolve().then(()=>(mi(),di));await n(e,t)});St.command("from-design [design]").description("Generate an EDS block from a design: a Figma URL, a Framer/Stitch or any web page (scraped with headless Chromium), or a local SVG/PNG export (quota-free, no MCP). Interactive wizard when run with no argument.").option("--name <name>","Override the inferred block name").option("--provider <type>","Design source: figma | framer | stitch | web (else detected from the URL)").option("--agent <type>","Force agent type: claude | cursor | codex | ollama | omlx | local (any OpenAI-compatible server) | none").option("--model <name>","Model to run (Claude alias/id, or a local model, e.g. qwen2.5-coder:14b)").option("--dry-run","Generate prompt only, do not invoke agent").option("--source <type>","Content source: document|ue|cf|mixed (default: document)").option("--widths <list>","Design frame widths for preview breakpoints (e.g. 390,768,1440)").option("--no-ue-model","Skip the Universal Editor model (generated by default)").option("--screenshot","Add a screenshot MCP call for pixel verification (opt-in; costs a call)").option("--mcp","Force the Figma MCP adapter even when a REST token is set").option("--refresh","Ignore the cached design snapshot and re-fetch").option("--auth","Scrape with a logged-in session (Framer/Stitch) \u2014 login captured once, then reused").option("--auth-refresh","Force a fresh scrape login even if a session is saved").option("--sample","Use the bundled sample design (the example file's hero) \u2014 no URL, no token, no MCP").option("--serve","Auto-start the live preview after generating (non-interactive runs only)").option("--draft","Generate a draft (tmp/eds-cli/drafts/<name>/vN) for review; blocks/ changes only on eds draft accept").option("--yes","Skip confirmation prompts").action(async(e,t)=>{await $t("block from-design",async()=>{let{blockFromDesign:n}=await Promise.resolve().then(()=>(io(),oo));await n(e,t)})});var un=G.command("draft").description("Review drafts from `block from-design --draft`: preview, refine, accept or discard");un.command("list").description("List drafts and their versions").action(async()=>{await $t("draft list",async()=>{let{draftList:e}=await Promise.resolve().then(()=>(yt(),bt));await e()})});un.command("preview <name> [version]").description("Preview a draft version in the browser (default: the latest), e.g. hero 2").option("--port <port>","Port to serve on (default 8777)").option("--widths <list>","Breakpoint widths").option("--no-open","Don't open the browser").action(async(e,t,n)=>{await $t("draft preview",async()=>{let{draftPreview:o}=await Promise.resolve().then(()=>(yt(),bt));await o(e,{...n,version:t})})});un.command("refine <name> <feedback>").description("One more agent round on the draft; the result is the next version").option("--from <n>","Start from this version (default: the latest)").option("--agent <type>","Agent (default: the one that made the draft)").option("--model <name>","Model (default: the one that made the draft)").action(async(e,t,n)=>{await $t("draft refine",async()=>{let{draftRefine:o}=await Promise.resolve().then(()=>(yt(),bt)),{from:i,...r}=n;await o(e,t,{...r,version:i})})});un.command("accept <name> [version]").description("Copy a draft version (default: the latest) into blocks/<name>/, optionally commit it").option("--commit","Commit blocks/<name>/ with the review rounds in the message").option("--branch <name>","Commit on this branch (created if missing; implies --commit)").action(async(e,t,n)=>{await $t("draft accept",async()=>{let{draftAccept:o}=await Promise.resolve().then(()=>(yt(),bt));await o(e,{...n,version:t})})});un.command("discard <name>").description("Drop a draft and its versions; blocks/ is untouched").action(async e=>{await $t("draft discard",async()=>{let{draftDiscard:t}=await Promise.resolve().then(()=>(yt(),bt));await t(e)})});St.command("list").description("List all blocks in the project").action(async e=>{let{listBlocks:t}=await Promise.resolve().then(()=>(Kc(),qc));await t({...e,json:G.opts().json})});St.command("preview [name]").description("Serve a live, breakpoint-switchable preview of a block \u2014 or a gallery of all blocks when no name is given").option("--port <port>","Port to serve on (default: 8777, falls back if taken)").option("--widths <list>","Comma-separated breakpoint widths (e.g. 375,768,1280)").option("--no-open","Do not open the browser automatically").action(async(e,t)=>{let n=await Promise.resolve().then(()=>(Oe(),wt));e?await n.previewBlock(e,t):await n.galleryPreview(t)});St.command("test [name]").description("Visual-regression test a block (or all blocks) against committed baselines").option("--update","(Re)write the baseline screenshots instead of comparing").option("--threshold <ratio>","Max changed-pixel ratio before failing (default 0.01 = 1%)").option("--design","Compare the rendered block against its Figma design image (needs a token)").option("--widths <list>","Comma-separated breakpoint widths (e.g. 375,768,1280)").option("--port <port>","Port for the internal preview server (default: 8788)").action(async(e,t)=>{let{visualTest:n}=await Promise.resolve().then(()=>(al(),sl));await n(e,t)});St.command("check [name]").description("Content, link and a11y check on a block's rendered DOM (or all blocks)").option("--strict","Fail on warnings too, not just errors").option("--widths <list>","Comma-separated breakpoint widths (uses the widest)").option("--port <port>","Port for the internal preview server (default: 8789)").action(async(e,t)=>{let{blockCheck:n}=await Promise.resolve().then(()=>(ml(),dl));await n(e,t)});var jt=G.command("scaffold").description("Scaffold standard UE components and blocks").action(async()=>{let{scaffoldInteractive:e}=await Promise.resolve().then(()=>(ue(),we));await e()});jt.command("ue").description("Scaffold default-content UE components + a field-reference block (all 17 fields)").action(async()=>{let{scaffoldUe:e}=await Promise.resolve().then(()=>(ue(),we));await e()});jt.command("blocks [names...]").description("Scaffold standard blocks (hero, cards, columns, accordion, embed) with UE models").action(async e=>{let{scaffoldBlocks:t}=await Promise.resolve().then(()=>(ue(),we));await t(e)});jt.command("ci").description("Scaffold a GitHub Actions workflow (doctor + audits + project lint/build)").action(async()=>{let{scaffoldCi:e}=await Promise.resolve().then(()=>(ue(),we));await e()});jt.command("helpers [names...]").description("Scaffold scripts/utils.js with chosen EDS helpers (interactive picker)").action(async e=>{let{scaffoldHelpers:t}=await Promise.resolve().then(()=>(ue(),we));await t(e)});jt.command("env").description("Write a local-dev .env for `aem up` (AEM_OPEN / AEM_PORT / AEM_PAGES_URL)").option("--open <path>","AEM_OPEN - path opened on start (default: /)").option("--port <port>","AEM_PORT - proxy port (default: 3007)").option("--pages-url <url>","AEM_PAGES_URL - content origin (default: from git remote)").option("--yes","Skip prompts; use flags/defaults").action(async e=>{let{scaffoldEnv:t}=await Promise.resolve().then(()=>(ue(),we));await t(e)});jt.command("xwalk").description("Write xwalk.json enabling Universal Editor multi-field support").action(async()=>{let{scaffoldXwalk:e}=await Promise.resolve().then(()=>(ue(),we));await e()});G.command("integrate [type]").description("Add a third-party service (GTM, GA4, chat, consent) to scripts/delayed.js").action(async e=>{let{integrate:t}=await Promise.resolve().then(()=>(Qi(),Yi));await t(e)});var og=G.command("figma").description("Figma MCP integration");og.command("setup").description("Configure Figma MCP for your AI agent").action(async()=>{let{figmaSetup:e}=await Promise.resolve().then(()=>(er(),Zi));await e()});G.command("doctor").description("Audit your EDS project for common issues").action(async()=>{let{doctor:e}=await Promise.resolve().then(()=>(nr(),tr));await e({json:G.opts().json})});var Cl=G.command("audit").description("Run project audits");Cl.command("loading").description("Check loading order (eager/lazy/delayed phases, LCP budget)").action(async()=>{let{auditLoading:e}=await Promise.resolve().then(()=>(rr(),ir));await e({json:G.opts().json})});Cl.command("security").description("Scan for vulnerabilities (npm audit) and exploit patterns (XSS, secrets, tabnabbing)").action(async()=>{let{auditSecurity:e}=await Promise.resolve().then(()=>(cr(),ar));await e({json:G.opts().json})});G.command("preview [paths...]").description("Preview pages via Admin API (interactive wizard when run with no paths)").option("--org <org>","GitHub org/owner").option("--site <site>","Repository name").option("--ref <ref>","Git ref (default: main)").action(async(e,t)=>{if(!e||e.length===0){let{adminWizard:o}=await Promise.resolve().then(()=>(po(),mo));await o("preview");return}let{preview:n}=await Promise.resolve().then(()=>(lo(),pr));await n(e,t)});G.command("publish [paths...]").description("Publish pages to live via Admin API (interactive wizard when run with no paths)").option("--org <org>","GitHub org/owner").option("--site <site>","Repository name").option("--ref <ref>","Git ref (default: main)").action(async(e,t)=>{if(!e||e.length===0){let{adminWizard:o}=await Promise.resolve().then(()=>(po(),mo));await o("publish");return}let{publish:n}=await Promise.resolve().then(()=>(fr(),ur));await n(e,t)});(async()=>{try{if(process.argv.slice(2).length===0)if(process.stdout.isTTY){let{mainMenu:e}=await Promise.resolve().then(()=>(Pl(),jl));await e()}else G.outputHelp();else await G.parseAsync(process.argv,{from:"node"})}catch(e){s.error(e instanceof Error?e.message:String(e)),process.exitCode=1}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aem-eds-kit",
3
- "version": "0.4.60",
3
+ "version": "0.4.61",
4
4
  "description": "CLI for AEM Edge Delivery Services: blocks from Figma, Framer or Google Stitch designs, AEM component migration (AEMaaCS and 6.5), Universal Editor models and QA",
5
5
  "type": "module",
6
6
  "engines": {