aem-eds-kit 0.4.57 → 0.4.58
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 +16 -0
- package/README.md +18 -0
- package/dist/bin/eds.js +123 -116
- package/package.json +1 -1
package/dist/bin/eds.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var Pl=Object.defineProperty;var v=(e,t)=>()=>(e&&(t=e(e=0)),t);var U=(e,t)=>{for(var n in t)Pl(e,n,{get:t[n],enumerable:!0})};import Zf from"path";import{fileURLToPath as tg}from"url";var f=v(()=>{"use strict"});import H from"chalk";function mn(e){return X[e]}function wr(e){return e.replace(Cl,"").length}function St(e,t){let n=t-wr(e);return n>0?e+" ".repeat(n):e}function Tl(){return H.bgHex("#ff5a36").hex("#0d0d0c").bold(" >_ ")}function fr(){return`${Tl()} ${H.bold("aem-eds-kit")}`}function Rl(){return Array.from({length:Al},()=>I.accent("\u25CF")).join(" ")}function Dl(e,t=""){return t?`${fr()} ${e} ${H.dim(t)}`:`${fr()} ${e}`}function gr(e){let t=e.replace("#","");return[Number.parseInt(t.slice(0,2),16),Number.parseInt(t.slice(2,4),16),Number.parseInt(t.slice(4,6),16)]}function Fl(e,t,n){let[o,i,r]=gr(e),[s,c,l]=gr(t),d=Math.round(o+(s-o)*n),m=Math.round(i+(c-i)*n),p=Math.round(r+(l-r)*n);return`#${[d,m,p].map(u=>u.toString(16).padStart(2,"0")).join("")}`}function Ll(e,t,n){let o=[...e],i=Math.max(n-1,1);return o.map((r,s)=>{if(r===" ")return r;let c=s/i*(t.length-1),l=Math.min(Math.floor(c),t.length-2);return H.hex(Fl(t[l],t[l+1],c-l))(r)}).join("")}function Nl(){let e=_(hr);return hr.map(t=>` ${Ll(t,Ol,e)}`).join(`
|
|
3
3
|
`)}function A(e="AEM Edge Delivery Services"){return`
|
|
4
|
-
${
|
|
4
|
+
${Nl()}
|
|
5
5
|
|
|
6
|
-
${
|
|
7
|
-
`}function j(e,t){let n=
|
|
8
|
-
${n} ${
|
|
9
|
-
`}function R(e,t,n,o=0){let i=o?
|
|
6
|
+
${Dl(Rl(),e)}
|
|
7
|
+
`}function j(e,t){let n=I.red("\u258A"),o=t?` ${H.dim(t)}`:"";return`
|
|
8
|
+
${n} ${H.bold(e)}${o}
|
|
9
|
+
`}function R(e,t,n,o=0){let i=o?St(t,o):t,r=n?` ${H.dim(n)}`:"";return` ${X[e]} ${i}${r}`}function P(e,t,n=0){let o=n?St(e,n):e,i=t?` ${H.dim(t)}`:"";return` ${I.accent("\u2714")} ${o}${i}`}function _(e){return e.reduce((t,n)=>Math.max(t,wr(n)),0)}function W(e,t=I.red){let n=_(e),o=t(`\u256D${"\u2500".repeat(n+2)}\u256E`),i=t(`\u2570${"\u2500".repeat(n+2)}\u256F`),r=e.map(s=>`${t("\u2502")} ${St(s,n)} ${t("\u2502")}`).join(`
|
|
10
10
|
`);return`${o}
|
|
11
11
|
${r}
|
|
12
|
-
${i}`}function $e(e){let t=[];return e.pass&&t.push(`${X.pass} ${e.pass} passed`),e.warn&&t.push(`${X.warn} ${e.warn} ${
|
|
13
|
-
`).pop()||m.shortMessage||String(d);throw/could not read Username|Repository not found|not found/i.test(p)?new Error(`Couldn't clone ${e.label}: the repo doesn't exist, or it's private (check the name; for a private repo use an SSH URL or set up git credentials).`):new Error(`Couldn't clone ${e.label}: ${p}`)}let
|
|
12
|
+
${i}`}function $e(e){let t=[];return e.pass&&t.push(`${X.pass} ${e.pass} passed`),e.warn&&t.push(`${X.warn} ${e.warn} ${Ml(e.warn,"warning")}`),e.fail&&t.push(`${X.fail} ${e.fail} failed`),e.info&&t.push(`${X.info} ${e.info} info`),t.join(H.dim(" "))}function Ml(e,t){return e===1?t:`${t}s`}var I,X,Cl,Al,br,hr,Ol,B=v(()=>{"use strict";f();I={red:H.hex("#FA0F00"),ember:H.hex("#FF4B1F"),orange:H.hex("#FF7B00"),blue:H.hex("#2680EB"),accent:H.hex("#ff5a36"),dotOrange:H.hex("#F24E1E"),dotPurple:H.hex("#A259FF"),dotBlue:H.hex("#1ABCFE"),dotGreen:H.hex("#0ACF83"),dotPink:H.hex("#FF7262"),ok:H.hex("#2D9D78"),warn:H.hex("#E68619"),err:H.hex("#D7373F"),info:H.hex("#2680EB")},X={pass:I.ok("\u2713"),warn:I.warn("\u26A0"),fail:I.err("\u2717"),info:I.info("\u2139"),bullet:H.dim("\u2022"),arrow:H.dim("\u21B3"),figma:I.dotPurple("\u25C6")};Cl=/\[[0-9;]*m/g;Al=5;br={prefix:"",style:{highlight:e=>H.hex("#ff5a36").bold(e)}};hr=["\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588","\u2588 \u2588 \u2588 \u2588 ","\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588\u2588\u2588\u2588\u2588","\u2588 \u2588 \u2588 \u2588","\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"],Ol=["#ff3b1e","#ff5a36","#ff7d52"]});import pn from"chalk";function Il(){let e=process.env.EDS_LOG_LEVEL?.toLowerCase();return e&&e in co?e:"info"}function Ie(e){return vr?e==="error":co[e]>=co[yr]}var co,yr,vr,un,a,O=v(()=>{"use strict";f();B();co={debug:0,info:1,warn:2,error:3,silent:4};yr=Il(),vr=!1,un=!1;a={setLevel(e){yr=e},setQuiet(e){vr=e},debug(...e){Ie("debug")&&console.error(pn.gray("[debug]"),...e)},info(...e){Ie("info")&&console.error(...e)},logoOnce(e){un||(un=!0,Ie("info")&&console.error(e))},async logoOnceAnimated(e){un||(un=!0,Ie("info")&&console.error(A(e)))},success(...e){Ie("info")&&console.error(pn.green("\u2713"),...e)},warn(...e){Ie("warn")&&console.error(pn.yellow("\u26A0"),...e)},error(...e){Ie("error")&&console.error(pn.red("\u2717"),...e)}}});function lo(e,t,n="main"){return`https://${n}--${t}--${e}.aem.page/`}function mo(){return"https://github.com/apps/aem-code-sync/installations/new"}function kr(e,t){return["repo","create",e,"--template",t.template,t.private?"--private":"--public",...t.clone?["--clone"]:[]]}var Qe,Q,fn=v(()=>{"use strict";f();Qe="eds-sandbox",Q={document:"adobe/aem-boilerplate",ue:"adobe-rnd/aem-boilerplate-xwalk"}});import{existsSync as uo}from"fs";import{readdir as $r,rm as po}from"fs/promises";import xr from"path";function Sr(e,t=!1){let n=(e??(t?Q.ue:Q.document)).trim(),o=_l[n.toLowerCase()]??n,i=s=>/xwalk/i.test(s);if(/^[\w.-]+\/[\w.-]+$/.test(o)&&!uo(o))return{url:`https://github.com/${o}.git`,label:o,ue:i(o)};let r=o.match(/github\.com[/:]([\w.-]+\/[\w.-]+?)(?:\.git)?\/?$/)?.[1];return{url:o,label:r??o,ue:i(o)}}async function jr(e){if(!uo(e))return!0;try{return(await $r(e)).length===0}catch{return!1}}async function Pr(e,t,n={}){let{execa:o}=await import("execa"),i=(d,m,p="pipe")=>o("git",d,{cwd:m,stdio:p}),r=uo(t),s=n.ref?["--branch",n.ref]:[];try{n.keepHistory?await i(["clone",...s,"--origin","upstream",e.url,t],void 0,n.stdio):await i(["clone","--depth","1",...s,e.url,t],void 0,n.stdio)}catch(d){if(!r)await po(t,{recursive:!0,force:!0});else for(let u of await $r(t))await po(xr.join(t,u),{recursive:!0,force:!0});let m=d;if(m.code==="ENOENT")throw new Error("git isn't installed (or not on PATH).");let p=(m.stderr??"").trim().split(`
|
|
13
|
+
`).pop()||m.shortMessage||String(d);throw/could not read Username|Repository not found|not found/i.test(p)?new Error(`Couldn't clone ${e.label}: the repo doesn't exist, or it's private (check the name; for a private repo use an SSH URL or set up git credentials).`):new Error(`Couldn't clone ${e.label}: ${p}`)}let c=(await i(["rev-parse","HEAD"],t)).stdout.trim(),l=!1;if(!n.keepHistory){await po(xr.join(t,".git"),{recursive:!0,force:!0}),await i(["init","--quiet"],t),await i(["symbolic-ref","HEAD","refs/heads/main"],t),await i(["add","-A"],t);try{await i(["commit","--quiet","-m",`Initial commit from ${e.label}@${c.slice(0,7)}`],t)}catch{l=!0}}return n.remote&&await i(["remote","add","origin",n.remote],t),{commit:c,uncommitted:l}}var gn,_l,Er=v(()=>{"use strict";f();fn();gn="hlxsites/aem-boilerplate-commerce",_l={commerce:gn,document:Q.document,doc:Q.document,da:Q.document,ue:Q.ue,xwalk:Q.ue,crosswalk:Q.ue}});var J={};U(J,{checkbox:()=>Xl,confirm:()=>Vl,input:()=>Kl,isEscape:()=>zl,isExit:()=>Jl,select:()=>ql});import{emitKeypressEvents as Ul}from"readline";import{checkbox as Bl,confirm as Hl,input as Gl,select as Wl}from"@inquirer/prompts";function hn(e){let t={...br,...e.theme??{}};return{...e,theme:t}}function wn(e,t){let n=process.stdin;if(!n.isTTY)return e(t??{});let o=new AbortController;t?.signal?.addEventListener("abort",()=>o.abort(),{once:!0}),Ul(n);let i=(s,c)=>{c?.name==="escape"&&o.abort()};n.on("keypress",i);let r=e({...t,signal:o.signal});return Promise.resolve(r).catch(()=>{}).finally(()=>n.off("keypress",i)),r}function zl(e){return e instanceof Error&&e.name==="AbortPromptError"}function Jl(e){return e instanceof Error&&e.name==="ExitPromptError"}var ql,Kl,Vl,Xl,q=v(()=>{"use strict";f();B();ql=(e,t)=>wn(n=>Wl(hn(e),n),t),Kl=(e,t)=>wn(n=>Gl(hn(e),n),t),Vl=(e,t)=>wn(n=>Hl(hn(e),n),t),Xl=(e,t)=>wn(n=>Bl(hn(e),n),t)});import{z as L}from"zod";var xg,fo,Cr,$g,_e,Ze=v(()=>{"use strict";f();xg=L.object({fileKey:L.string().min(1),nodeId:L.string().optional(),fileName:L.string().optional()}),fo=L.object({agent:L.enum(["claude","cursor","codex","ollama","omlx","local"]).optional(),local:L.object({baseUrl:L.string().url().optional(),model:L.string().optional(),contextTokens:L.number().int().positive().optional(),apiKey:L.string().optional()}).optional(),model:L.string().optional(),figma:L.object({mcpEndpoint:L.string().url().optional(),token:L.string().optional(),restPerMinute:L.number().int().positive().optional()}).optional(),admin:L.object({org:L.string().optional(),site:L.string().optional(),ref:L.string().default("main")}).optional()}),Cr=L.object({root:L.string(),hasFstab:L.boolean(),hasBlocks:L.boolean(),hasHeadHtml:L.boolean()}),$g=L.object({figmaFileKey:L.string(),figmaNodeId:L.string().optional(),lastSyncedAt:L.string().datetime(),promptVersion:L.string(),agentUsed:L.string().optional(),breakpoints:L.array(L.object({width:L.number(),label:L.string().optional(),source:L.enum(["figma","scrape","default"]).optional()})).optional()}),_e=/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/});import{existsSync as jt}from"fs";import Se from"path";function E(e=process.cwd()){let t=Se.resolve(e),{root:n}=Se.parse(t);for(;t!==n;){if(Tr.some(o=>jt(Se.join(t,o))))return t;t=Se.dirname(t)}if(Tr.some(o=>jt(Se.join(n,o))))return n}function Ar(e){return Cr.parse({root:e,hasFstab:jt(Se.join(e,"fstab.yaml")),hasBlocks:jt(Se.join(e,"blocks")),hasHeadHtml:jt(Se.join(e,"head.html"))})}var Tr,K=v(()=>{"use strict";f();Ze();Tr=["fstab.yaml","head.html","helix-query.yaml","component-definition.json","paths.json","scripts/scripts.js","scripts/aem.js"]});import{existsSync as Yl}from"fs";import{mkdir as Ql,writeFile as Zl}from"fs/promises";import Rr from"path";async function bn(e){let t=Rr.join(e,".github","workflows","eds.yml");return Yl(t)?{path:Dr,created:!1}:(await Ql(Rr.dirname(t),{recursive:!0}),await Zl(t,ed),{path:Dr,created:!0})}var Dr,ed,go=v(()=>{"use strict";f();Dr=".github/workflows/eds.yml",ed=`name: EDS checks
|
|
14
14
|
|
|
15
15
|
# Generated by aem-eds-kit (\`eds scaffold ci\`). Runs the project's own
|
|
16
16
|
# lint/build plus the eds audits as a gatekeeper on every PR and push to main.
|
|
@@ -53,18 +53,18 @@ jobs:
|
|
|
53
53
|
run: npx --yes aem-eds-kit@latest audit loading
|
|
54
54
|
- name: Security & exploit scan
|
|
55
55
|
run: npx --yes aem-eds-kit@latest audit security
|
|
56
|
-
`});import{existsSync as
|
|
56
|
+
`});import{existsSync as Fr}from"fs";import{readFile as td,writeFile as Lr}from"fs/promises";import Or from"path";function nd(e={}){let t=e.open??"/",n=e.port??3007,o=e.pagesUrl??"";return`AEM_OPEN=${t}
|
|
57
57
|
AEM_PORT=${n}
|
|
58
58
|
AEM_PAGES_URL=${o}
|
|
59
|
-
`}async function
|
|
59
|
+
`}async function od(e){let t=Or.join(e,".gitignore"),n="";if(Fr(t)&&(n=await td(t,"utf-8")),n.split(/\r?\n/).some(i=>i.trim()===".env"))return!1;let o=n&&!n.endsWith(`
|
|
60
60
|
`)?`
|
|
61
|
-
`:"";return await
|
|
62
|
-
`),!0}async function
|
|
61
|
+
`:"";return await Lr(t,`${n}${o}.env
|
|
62
|
+
`),!0}async function yn(e,t={}){let n=Or.join(e,".env"),o=!Fr(n);o&&await Lr(n,nd(t));let i=await od(e);return{path:".env",created:o,gitignoreUpdated:i}}var ho=v(()=>{"use strict";f()});import{existsSync as Nr}from"fs";import{readFile as id,writeFile as Mr}from"fs/promises";import vn from"path";function kn(e){return e!=="ue"}function Ir(e,t){return`https://content.da.live/${e}/${t}/`}function rd(e){return`mountpoints:
|
|
63
63
|
/: ${e}
|
|
64
|
-
`}async function
|
|
65
|
-
`}async function
|
|
66
|
-
`}async function
|
|
67
|
-
`}function
|
|
64
|
+
`}async function _r(e,t){return await Mr(vn.join(e,"fstab.yaml"),rd(t)),"fstab.yaml"}function ad(e){return`${JSON.stringify({mappings:[`/content/${e}/:/`],includes:[`/content/${e}/`]},null,2)}
|
|
65
|
+
`}async function Ur(e,t){return await Mr(vn.join(e,"paths.json"),ad(t)),"paths.json"}function sd(e){if(/content\.da\.live|\/\/da\.live\//i.test(e))return"da";if(/drive\.google\.com|docs\.google\.com/i.test(e))return"gdrive";if(/sharepoint\.com|onedrive\.live\.com|1drv\.ms/i.test(e))return"sharepoint";if(/adobeaemcloud\.(com|net)|\/bin\/franklin\.delivery/i.test(e))return"ue"}async function Br(e){let t=vn.join(e,"fstab.yaml");if(Nr(t)){let n=(await id(t,"utf-8")).match(/https?:\/\/[^\s"']+/)?.[0],o=n&&sd(n);if(o)return o}if(Nr(vn.join(e,"paths.json")))return"ue"}var je,Hr=v(()=>{"use strict";f();je={ue:"Universal Editor (crosswalk)",da:"Document Authoring (da.live)",gdrive:"Document Authoring (Google Drive)",sharepoint:"Document Authoring (SharePoint)"}});import{existsSync as cd}from"fs";import{writeFile as ld}from"fs/promises";import dd from"path";function pd(){return`${JSON.stringify(md,null,2)}
|
|
66
|
+
`}async function xn(e){let t=dd.join(e,"xwalk.json");return cd(t)?{path:"xwalk.json",created:!1}:(await ld(t,pd()),{path:"xwalk.json",created:!0})}var md,wo=v(()=>{"use strict";f();md={public:{xwalk:{"multi-field":{enabled:!0}}}}});function et(e){let t=e.trim().match(/github\.com[:/]([^/]+)\/(.+?)(?:\.git)?\/?$/i);return t?{owner:t[1],repo:t[2]}:null}function tt(e,t,n="main"){return`${n}--${t}--${e}.aem.page`}function Gr({host:e,path:t="/",org:n}){let o=e.replace(/^https?:\/\//,"").replace(/\/+$/,""),i=t.startsWith("/")?t:`/${t}`;return`https://experience.adobe.com/#/${n?`@${n}/`:""}aem/editor/canvas/${o}${i}`}var $n=v(()=>{"use strict";f()});function Pt(e){return`${JSON.stringify(e,null,2)}
|
|
67
|
+
`}function yo(e){return Ue.find(t=>t.id===e)}var bo,Wr,zr,Ue,vo=v(()=>{"use strict";f();bo=(e,t,n)=>({title:e,id:t,plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:e,model:n}}}}}),Wr=(e,t,n)=>({title:e,id:t,plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:e,filter:n}}}}}),zr=(e,t,n)=>({title:e,id:t,plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block/item",template:{name:e,model:n}}}}}),Ue=[{id:"hero",title:"Hero",js:`// Block: hero
|
|
68
68
|
export default function decorate(block) {
|
|
69
69
|
block.classList.add('hero');
|
|
70
70
|
const picture = block.querySelector('picture');
|
|
@@ -93,7 +93,7 @@ export default function decorate(block) {
|
|
|
93
93
|
margin: 0 auto;
|
|
94
94
|
padding: 0 var(--spacing-m, 16px);
|
|
95
95
|
}
|
|
96
|
-
`,model:
|
|
96
|
+
`,model:Pt({definitions:[bo("Hero","hero","hero")],models:[{id:"hero",fields:[{component:"reference",valueType:"string",name:"image",label:"Image"},{component:"text",valueType:"string",name:"imageAlt",label:"Alt"},{component:"text",valueType:"string",name:"title",label:"Title"},{component:"richtext",valueType:"string",name:"text",value:"",label:"Text"}]}],filters:[]})},{id:"cards",title:"Cards",js:`// Block: cards
|
|
97
97
|
export default function decorate(block) {
|
|
98
98
|
const ul = document.createElement('ul');
|
|
99
99
|
[...block.children].forEach((row) => {
|
|
@@ -132,7 +132,7 @@ export default function decorate(block) {
|
|
|
132
132
|
.cards .cards-card-body {
|
|
133
133
|
padding: var(--spacing-m, 16px);
|
|
134
134
|
}
|
|
135
|
-
`,model:
|
|
135
|
+
`,model:Pt({definitions:[Wr("Cards","cards","cards"),zr("Card","card","card")],models:[{id:"card",fields:[{component:"reference",valueType:"string",name:"image",label:"Image"},{component:"text",valueType:"string",name:"imageAlt",label:"Alt"},{component:"text",valueType:"string",name:"title",label:"Title"},{component:"richtext",valueType:"string",name:"text",value:"",label:"Text"},{component:"aem-content",name:"link",label:"Link"}]}],filters:[{id:"cards",components:["card"]}]})},{id:"columns",title:"Columns",js:`// Block: columns
|
|
136
136
|
export default function decorate(block) {
|
|
137
137
|
const cols = [...block.firstElementChild.children];
|
|
138
138
|
block.classList.add(\`columns-\${cols.length}-cols\`);
|
|
@@ -159,7 +159,7 @@ export default function decorate(block) {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
.columns img { width: 100%; height: auto; }
|
|
162
|
-
`,model:
|
|
162
|
+
`,model:Pt({definitions:[bo("Columns","columns","columns")],models:[{id:"columns",fields:[{component:"richtext",valueType:"string",name:"content",value:"",label:"Content"}]}],filters:[]})},{id:"accordion",title:"Accordion",js:`// Block: accordion
|
|
163
163
|
export default function decorate(block) {
|
|
164
164
|
[...block.children].forEach((row) => {
|
|
165
165
|
const [label, body] = row.children;
|
|
@@ -192,7 +192,7 @@ export default function decorate(block) {
|
|
|
192
192
|
.accordion .accordion-item-body {
|
|
193
193
|
padding-bottom: var(--spacing-m, 16px);
|
|
194
194
|
}
|
|
195
|
-
`,model:
|
|
195
|
+
`,model:Pt({definitions:[Wr("Accordion","accordion","accordion"),zr("Accordion Item","accordion-item","accordion-item")],models:[{id:"accordion-item",fields:[{component:"text",valueType:"string",name:"label",label:"Label"},{component:"richtext",valueType:"string",name:"body",value:"",label:"Body"}]}],filters:[{id:"accordion",components:["accordion-item"]}]})},{id:"embed",title:"Embed",js:`// Block: embed
|
|
196
196
|
export default function decorate(block) {
|
|
197
197
|
const link = block.querySelector('a');
|
|
198
198
|
const url = link?.href;
|
|
@@ -221,12 +221,12 @@ export default function decorate(block) {
|
|
|
221
221
|
height: 100%;
|
|
222
222
|
border: 0;
|
|
223
223
|
}
|
|
224
|
-
`,model:
|
|
224
|
+
`,model:Pt({definitions:[bo("Embed","embed","embed")],models:[{id:"embed",fields:[{component:"aem-content",name:"link",label:"Embed URL"}]}],filters:[]})}]});import{existsSync as ud}from"fs";import{mkdir as fd,writeFile as gd}from"fs/promises";import Jr from"path";function Kr(e){return Et.find(t=>t.id===e)}function Vr(e){let t=new Set,n=o=>{if(t.has(o))return;let i=Kr(o);if(i){for(let r of i.deps??[])n(r);t.add(o)}};for(let o of e)n(o);return Et.filter(o=>t.has(o.id)).map(o=>o.id)}function hd(e){return`// scripts/utils.js - common EDS helpers (generated by \`eds scaffold helpers\`).
|
|
225
225
|
|
|
226
|
-
${
|
|
226
|
+
${Vr(e).map(o=>Kr(o)).filter(o=>!!o).map(o=>o.code).join(`
|
|
227
227
|
|
|
228
228
|
`)}
|
|
229
|
-
`}async function
|
|
229
|
+
`}async function Xr(e,t=ko){let n=Vr(t),o=Jr.join(e,"scripts","utils.js");return ud(o)?{path:qr,created:!1,helpers:n}:(await fd(Jr.dirname(o),{recursive:!0}),await gd(o,hd(t)),{path:qr,created:!0,helpers:n})}var qr,Et,ko,Yr=v(()=>{"use strict";f();qr="scripts/utils.js",Et=[{id:"getMetadata",label:"getMetadata (read a page meta value)",code:`/**
|
|
230
230
|
* Reads a page metadata value by name (meta[name] or meta[property]).
|
|
231
231
|
* @param {string} name The metadata name.
|
|
232
232
|
* @returns {string} The value, or an empty string.
|
|
@@ -323,8 +323,8 @@ export function isUEPreview() {
|
|
|
323
323
|
*/
|
|
324
324
|
export function isUE() {
|
|
325
325
|
return isUEEdit() || isUEPreview();
|
|
326
|
-
}`}],
|
|
327
|
-
`}function
|
|
326
|
+
}`}],ko=Et.map(e=>e.id)});function wd(){return[{component:"tab",name:"basics",label:"Basics"},{component:"text",valueType:"string",name:"text",label:"Text (single line)"},{component:"textarea",valueType:"string",name:"textarea",label:"Textarea (multi-line)"},{component:"richtext",valueType:"string",name:"richtext",value:"",label:"Rich text"},{component:"number",valueType:"number",name:"number",label:"Number"},{component:"boolean",valueType:"boolean",name:"boolean",value:!1,label:"Boolean"},{component:"date-time",valueType:"date",name:"date",label:"Date / time"},{component:"tab",name:"selection",label:"Selection"},{component:"select",valueType:"string",name:"select",label:"Select",value:"a",options:[{name:"Option A",value:"a"},{name:"Option B",value:"b"}]},{component:"radio-group",valueType:"string",name:"radio",label:"Radio group",value:"x",options:[{name:"X",value:"x"},{name:"Y",value:"y"}]},{component:"multiselect",valueType:"string",name:"classes",label:"Multiselect (CSS classes)",options:[{name:"Highlight",value:"highlight"},{name:"Dark",value:"dark"}]},{component:"checkbox-group",valueType:"string[]",name:"toggles",label:"Checkbox group",options:[{name:"Show title",value:"show-title"},{name:"Show image",value:"show-image"}]},{component:"tab",name:"media",label:"Media & content"},{component:"reference",valueType:"string",name:"image",label:"Image (DAM asset)"},{component:"text",valueType:"string",name:"imageAlt",label:"Image alt"},{component:"aem-content",name:"link",label:"Link (page / URL)"},{component:"aem-content-fragment",name:"contentFragment",label:"Content Fragment"},{component:"aem-experience-fragment",name:"experienceFragment",label:"Experience Fragment"},{component:"aem-tag",valueType:"string",name:"tags",label:"Tags"},{component:"tab",name:"repeatable",label:"Multifield"},{component:"container",name:"items",label:"Items (repeatable)",multi:!0,collapsible:!0,fields:[{component:"text",valueType:"string",name:"itemTitle",label:"Title"},{component:"richtext",valueType:"string",name:"itemText",value:"",label:"Text"},{component:"aem-content",name:"itemLink",label:"Link"}]}]}function xo(){let e={definitions:[{title:"Field Reference",id:"field-reference",plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:"Field Reference",model:"field-reference"}}}}}],models:[{id:"field-reference",fields:wd()}],filters:[]};return`${JSON.stringify(e,null,2)}
|
|
327
|
+
`}function $o(e,t){let n=new Set(e.map(o=>o.id));return[...e,...t.filter(o=>!n.has(o.id))]}function na(e,t,n){let o=e?.groups?[...e.groups]:[],i=(r,s,c)=>{let l=o.find(d=>d.id===r);l||(l={id:r,title:s,components:[]},o.push(l)),l.components=$o(l.components,c)};return i("default","Default Content",t),i("blocks","Blocks",n),{groups:o}}function Ct(e,t){let n=e?[...e]:[],o=n.find(i=>i.id==="section");return o||(o={id:"section",components:["text","image","button","title"]},n.push(o)),o.components=[...new Set([...o.components,...t])],n}var Qr,Zr,ea,ta,So=v(()=>{"use strict";f();Qr=[{title:"Text",id:"text",plugins:{xwalk:{page:{resourceType:"core/franklin/components/text/v1/text",template:{text:"<p>Text</p>"}}}}},{title:"Image",id:"image",plugins:{xwalk:{page:{resourceType:"core/franklin/components/image/v1/image",template:{image:"",imageAlt:""}}}}},{title:"Button",id:"button",plugins:{xwalk:{page:{resourceType:"core/franklin/components/button/v1/button",template:{text:"Button",href:"",type:""}}}}},{title:"Title",id:"title",plugins:{xwalk:{page:{resourceType:"core/franklin/components/title/v1/title",template:{title:"Title",type:"h2"}}}}}],Zr=[{id:"title",fields:[{component:"text",valueType:"string",name:"title",label:"Title"},{component:"select",valueType:"string",name:"type",label:"Type",value:"h2",options:[{name:"H1",value:"h1"},{name:"H2",value:"h2"},{name:"H3",value:"h3"},{name:"H4",value:"h4"},{name:"H5",value:"h5"},{name:"H6",value:"h6"}]}]},{id:"image",fields:[{component:"reference",valueType:"string",name:"image",label:"Image",multi:!1},{component:"text",valueType:"string",name:"imageAlt",label:"Alt Text"}]},{id:"button",fields:[{component:"text",valueType:"string",name:"text",label:"Text"},{component:"aem-content",name:"href",label:"Link"},{component:"select",valueType:"string",name:"type",label:"Type",options:[{name:"Default",value:""},{name:"Primary",value:"primary"},{name:"Secondary",value:"secondary"}]}]}];ea=`// Block: field-reference
|
|
328
328
|
// A living reference of every Universal Editor field type (see _field-reference.json).
|
|
329
329
|
// Authors use it to see what's available; delete it before launch.
|
|
330
330
|
export default function decorate(block) {
|
|
@@ -333,31 +333,31 @@ export default function decorate(block) {
|
|
|
333
333
|
// are what you drop and edit.
|
|
334
334
|
block.classList.add('field-reference');
|
|
335
335
|
}
|
|
336
|
-
`,
|
|
336
|
+
`,ta=`/* Block: field-reference */
|
|
337
337
|
.field-reference {
|
|
338
338
|
display: grid;
|
|
339
339
|
gap: var(--spacing-m, 16px);
|
|
340
340
|
padding: var(--spacing-l, 32px) 0;
|
|
341
341
|
}
|
|
342
|
-
`});var
|
|
343
|
-
`)}async function
|
|
344
|
-
`),!0}catch{return!1}}async function
|
|
345
|
-
`)[0]}`)}if(n&&await r({message:`Configure authoring now (eds init in ${s})?`,default:!0})){let g=process.cwd();try{process.chdir(d);let{initProject:h}=await Promise.resolve().then(()=>(
|
|
346
|
-
`,{mode:384})}async function
|
|
347
|
-
`).filter(Boolean):[]}}catch(o){a.error(`List failed: ${o.message}`),process.exitCode=1;return}if(a.info(j("Sandboxes",`${t.length} tagged ${
|
|
342
|
+
`});var he={};U(he,{scaffoldBlocks:()=>ra,scaffoldCi:()=>aa,scaffoldEnv:()=>ca,scaffoldHelpers:()=>sa,scaffoldInteractive:()=>yd,scaffoldUe:()=>Pn,scaffoldXwalk:()=>la});import{existsSync as oa}from"fs";import{mkdir as ia,readFile as bd,writeFile as Be}from"fs/promises";import de from"path";async function Sn(e){if(!oa(e))return null;try{return JSON.parse(await bd(e,"utf-8"))}catch{return null}}async function jn(e,t){await Be(e,`${JSON.stringify(t,null,2)}
|
|
343
|
+
`)}async function Pn(){let e=E();if(!e){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Scaffold - Universal Editor"));let t=[],n=de.join(e,"blocks","field-reference");await ia(n,{recursive:!0}),await Be(de.join(n,"field-reference.js"),ea),await Be(de.join(n,"field-reference.css"),ta),await Be(de.join(n,"_field-reference.json"),xo()),t.push("blocks/field-reference/ (all 17 fields + multifield)");let o=de.join(e,"component-definition.json"),i=de.join(e,"component-models.json"),r=de.join(e,"component-filters.json"),s=[{title:"Field Reference",id:"field-reference",plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:"Field Reference",model:"field-reference"}}}}}],c=na(await Sn(o),Qr,s);await jn(o,c),t.push("component-definition.json (default content + field-reference)");let l=await Sn(i)??[],d=JSON.parse(xo()).models[0],m=$o(l,[...Zr,d]);await jn(i,m),t.push("component-models.json (title / image / button / field-reference)");let p=Ct(await Sn(r),["field-reference"]);await jn(r,p),t.push("component-filters.json (section filter)"),a.info(j("Created / merged"));let u=t.map(h=>h.split(" ")[0]),g=_(u);for(let h of t){let[$,...w]=h.split(" ");a.info(P($,w.join(" ").replace(/^\((.*)\)$/,"$1"),g))}a.info(""),a.info(W(["Universal Editor scaffold ready"]))}async function ra(e){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Scaffold \u2014 standard blocks"));let n;if(e?.length){n=e.map(d=>yo(d.trim())).filter(d=>!!d);let l=e.filter(d=>!yo(d.trim()));l.length&&a.warn(`Unknown block(s): ${l.join(", ")}. Available: ${Ue.map(d=>d.id).join(", ")}`)}else n=Ue;let o=[],i=[];for(let l of n){let d=de.join(t,"blocks",l.id);if(oa(d)){i.push(l.id);continue}await ia(d,{recursive:!0}),await Be(de.join(d,`${l.id}.js`),l.js),await Be(de.join(d,`${l.id}.css`),l.css),await Be(de.join(d,`_${l.id}.json`),l.model),o.push(l.id)}let r=de.join(t,"component-filters.json"),s=Ct(await Sn(r),n.map(l=>l.id));await jn(r,s),a.info(j("Blocks"));let c=_([...o,...i,"component-filters"]);for(let l of o)a.info(P(l,"created",c));for(let l of i)a.info(R("warn",l,"already exists \u2014 skipped",c));a.info(""),a.info(W([`${o.length} block(s) scaffolded + registered`]))}async function aa(){let e=E();if(!e){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Scaffold - CI workflow"));let t=await bn(e);a.info(j("GitHub Actions")),t.created?a.info(P(t.path,"doctor + audit loading + audit security + lint/build")):a.info(R("warn",t.path,"already exists - skipped")),a.info(""),a.info(W([t.created?"CI workflow scaffolded - commit it and it runs on every PR":"CI workflow left untouched"]))}async function sa(e){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Scaffold - helpers"));let n=e?.length?e:void 0;if(!n)if(process.stdout.isTTY){let{checkbox:i}=await Promise.resolve().then(()=>(q(),J));n=await i({message:"Which helpers?",choices:Et.map(r=>({name:r.label,value:r.id,checked:!0}))})}else n=ko;if(!n.length){a.info("Nothing selected.");return}let o=await Xr(t,n);a.info(j("Helpers")),o.created?a.info(P(o.path,o.helpers.join(", "))):a.info(R("warn",o.path,"already exists - skipped")),a.info(""),a.info(W([o.created?`${o.helpers.length} helper(s) -> scripts/utils.js`:"Helpers left untouched"]))}async function ca(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Scaffold - .env"));let n=e.pagesUrl;if(n===void 0)try{let{execa:s}=await import("execa"),c=await s("git",["remote","get-url","origin"],{cwd:t}),l=et(c.stdout.trim());n=l?`https://${tt(l.owner,l.repo)}`:""}catch{n=""}let o=e.open??"/",i=e.port??"3007";if(!e.yes&&process.stdout.isTTY){let{input:s}=await Promise.resolve().then(()=>(q(),J));o=await s({message:"AEM_OPEN (path opened on start)",default:o}),i=await s({message:"AEM_PORT",default:String(i)}),n=await s({message:"AEM_PAGES_URL (content origin)",default:n})}let r=await yn(t,{open:o,port:i,pagesUrl:n});a.info(j(".env")),r.created?a.info(P(r.path,`AEM_OPEN=${o} AEM_PORT=${i}`)):a.info(R("warn",r.path,"already exists - left untouched")),r.gitignoreUpdated&&a.info(P(".gitignore","added .env")),a.info(""),a.info(W([r.created?".env ready for `aem up`":".env left untouched"]))}async function la(){let e=E();if(!e){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Scaffold - xwalk.json"));let t=await xn(e);a.info(j("xwalk.json")),t.created?a.info(P(t.path,"multi-field enabled")):a.info(R("warn",t.path,"already exists - left untouched")),a.info(""),a.info(W([t.created?"xwalk.json ready (UE multi-field)":"xwalk.json left untouched"]))}async function yd(){let{select:e,checkbox:t}=await Promise.resolve().then(()=>(q(),J));a.logoOnce(A("Scaffold"));let n=await e({message:"What do you want to scaffold?",choices:[{name:"Universal Editor config + field-reference (all 17 field types)",value:"ue"},{name:"Standard blocks (hero, cards, columns, accordion, embed)",value:"blocks"},{name:"GitHub Actions CI (doctor + audits + lint/build)",value:"ci"},{name:"Helper functions (scripts/utils.js)",value:"helpers"},{name:"Local-dev .env (aem up: port / open / pages URL)",value:"env"},{name:"xwalk.json (enable Universal Editor multi-field)",value:"xwalk"},{name:"UE config + standard blocks",value:"both"}]});if(n==="env")return ca();if(n==="xwalk")return la();if((n==="ue"||n==="both")&&await Pn(),n==="blocks"||n==="both"){let o=await t({message:"Which blocks?",choices:Ue.map(i=>({name:i.title,value:i.id,checked:!0}))});await ra(o)}n==="ci"&&await aa(),n==="helpers"&&await sa()}var pe=v(()=>{"use strict";f();O();K();vo();go();ho();Yr();So();wo();$n();B()});var Tt={};U(Tt,{initProject:()=>Sd});import{existsSync as jo}from"fs";import{readFile as Po,writeFile as da}from"fs/promises";import Cn from"path";import En from"chalk";async function vd(e){try{let{execa:t}=await import("execa"),n=await t("git",["remote","get-url","origin"],{cwd:e}),o=et(n.stdout.trim());return o?`https://${tt(o.owner,o.repo)}`:""}catch{return""}}async function kd(e,t){let n=Cn.join(e,"package.json");if(!jo(n))return!1;try{let o=JSON.parse(await Po(n,"utf-8"));return o.name=t,await da(n,`${JSON.stringify(o,null,2)}
|
|
344
|
+
`),!0}catch{return!1}}async function xd(e,t){let n=[];for(let o of["README.md","index.html","head.html"]){let i=Cn.join(e,o);if(jo(i))try{let r=await Po(i,"utf-8"),s=r.replace(/aem-boilerplate/gi,t);s!==r&&(await da(i,s),n.push(o))}catch{}}return n}async function $d(e){let{confirm:t}=await Promise.resolve().then(()=>(q(),J)),n=[{title:"Install the AEM Code Sync GitHub app",url:"https://github.com/apps/aem-code-sync/installations/new",note:"Connects your repo to the Edge Delivery pipeline (preview/publish)."}];e==="gdrive"&&n.push({title:"Share your content folder",note:"Share the Google Drive folder with the AEM service and set it as the mountpoint."}),e==="sharepoint"&&n.push({title:"Share your content folder",note:"Grant the SharePoint/OneDrive folder to the AEM service account."}),e==="da"&&n.push({title:"Author in DA",url:"https://da.live",note:"Create documents at da.live."}),e==="ue"&&n.push({title:"Open the Universal Editor",url:"https://experience.adobe.com",note:"Author in-context once the repo is connected to AEM."}),n.push({title:"Install the AEM Sidekick extension",url:"https://chromewebstore.google.com/detail/aem-sidekick/igkmdomcgoebiipaifhmpfjhbjccggml",note:"Preview and publish from the browser."}),n.push({title:"Run the local dev server",note:"npm install, then `aem up` (from @adobe/aem-cli)."}),a.info(j("Next steps (outside the repo)"));for(let o=0;o<n.length;o++){let i=n[o];a.info(` ${I.accent(String(o+1))} ${En.bold(i.title)}`),i.url&&a.info(` ${En.cyan(i.url)}`),a.info(` ${En.dim(i.note)}`),await t({message:" Done / skip?",default:!0})}}async function Sd(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found). Clone an EDS boilerplate first, then run this from its root."),process.exitCode=1;return}await a.logoOnceAnimated("Project setup");let{input:n,select:o,confirm:i}=await Promise.resolve().then(()=>(q(),J)),r=!e.yes,s=Cn.basename(t),c=Cn.join(t,"package.json");if(jo(c))try{let w=JSON.parse(await Po(c,"utf-8")).name??"";w&&!/aem-boilerplate/i.test(w)&&(s=w)}catch{}let l=e.name&&nt(e.name)||nt(r?await n({message:"1/4 Project name",default:nt(s),validate:w=>!!nt(w)||"Use letters, numbers and dashes"}):s),d=e.authoring?void 0:await Br(t);if(!e.authoring&&!r&&!d){a.error("Couldn't detect the authoring model (no fstab.yaml mountpoint or paths.json). Pass --authoring ue|da|gdrive|sharepoint."),process.exitCode=1;return}d&&a.info(En.dim(` Detected: ${je[d]}`));let m=e.authoring??(r?await o({message:"2/4 Authoring model",default:d,choices:[{name:je.ue,value:"ue"},{name:je.da,value:"da"},{name:je.gdrive,value:"gdrive"},{name:je.sharepoint,value:"sharepoint"}]}):d),p=e.mountpoint;if(kn(m)&&!p)if(m==="da"&&(e.org||r)){let w=e.org??await n({message:" DA org",validate:b=>!!b.trim()||"Required"}),y=e.site??(r?await n({message:" DA site",default:l}):l);p=Ir(w.trim(),nt(y))}else m!=="da"&&r&&(p=(await n({message:` ${m==="gdrive"?"Google Drive folder URL":"SharePoint folder URL"}`,validate:y=>/^https?:\/\//.test(y.trim())||"Paste the folder URL"})).trim());let u=e.ci??(r?await i({message:"4/4 Add GitHub Actions CI (audits gatekeeper)?",default:!0}):!0);a.info(j("Summary"));let g=_(["name","authoring","mountpoint","ci"]);if(a.info(P("name",l,g)),a.info(P("authoring",je[m],g)),p?a.info(P("mountpoint",p,g)):kn(m)&&a.info(P("mountpoint","(skipped - set it in fstab.yaml later)",g)),a.info(P("ci",u?"yes":"no",g)),a.info(""),r&&!await i({message:"Apply this setup?",default:!0})){a.info("Cancelled.");return}let h=[];await kd(t,l)&&h.push("package.json (name)");for(let w of await xd(t,l))h.push(`${w} (renamed)`);if(kn(m)&&p&&h.push(await _r(t,p)),m==="ue"&&(await Pn(),h.push(await Ur(t,l))),u){let w=await bn(t);h.push(w.created?w.path:`${w.path} (exists, skipped)`)}if(e.env!==!1){let w=await yn(t,{pagesUrl:await vd(t)});h.push(w.created?".env (aem up config)":".env (exists, skipped)")}if(e.xwalk!==!1&&m==="ue"){let w=await xn(t);h.push(w.created?`${w.path} (UE multi-field)`:`${w.path} (exists, skipped)`)}a.info(j("Configured"));let $=_(h.map(w=>w.split(" ")[0]));for(let w of h){let[y,...b]=w.split(" ");a.info(P(y,b.join(" ").replace(/^\((.*)\)$/,"$1"),$))}a.info(""),r&&await $d(m),a.info(W([`"${l}" set up for ${je[m]}`]))}var nt,At=v(()=>{"use strict";f();O();K();go();ho();Hr();wo();$n();B();pe();nt=e=>e.trim().toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"")});var Eo={};U(Eo,{newProject:()=>jd});import ma from"path";import pa from"chalk";async function jd(e,t={}){await a.logoOnceAnimated("New project");let n=!t.yes,{input:o,select:i,confirm:r}=await Promise.resolve().then(()=>(q(),J)),s=e?.trim();if(!s){if(!n){a.error("Pass a folder: `eds new <dir>`."),process.exitCode=1;return}s=(await o({message:"Folder for the new project",default:"my-eds-site",validate:g=>!!g.trim()||"Required"})).trim()}let c=t.boilerplate;!c&&!t.ue&&n&&(c=await i({message:"Which boilerplate?",choices:[{name:`Document Authoring / DA (${Q.document})`,value:Q.document},{name:`Universal Editor / crosswalk (${Q.ue})`,value:Q.ue},{name:`Adobe Commerce storefront (${gn})`,value:gn}]}));let l=Sr(c,t.ue),d=ma.resolve(s);if(!await jr(d)){a.error(`${s} already exists and isn't empty - refusing to clone into it.`),process.exitCode=1;return}a.info(j("Cloning",`${l.label}${t.ref?`@${t.ref}`:""} \u2192 ${s}`));let m;try{m=await Pr(l,d,{ref:t.ref,keepHistory:t.keepHistory,remote:t.remote,stdio:n?"inherit":"pipe"})}catch(g){a.error(g.message),process.exitCode=1;return}let p=_(["folder","source","history","origin"]);if(a.info(j("Project ready")),a.info(P("folder",d,p)),a.info(P("source",`${l.label} @ ${m.commit.slice(0,7)}`,p)),a.info(P("history",t.keepHistory?"boilerplate history kept (remote: upstream)":m.uncommitted?"fresh, files staged (set git user.name / user.email, then commit)":"fresh (one initial commit)",p)),a.info(P("origin",t.remote??"not set (git remote add origin <url>)",p)),a.info(""),t.install??(n?await r({message:"Install dependencies (npm install)?",default:!0}):!1))try{let{execa:g}=await import("execa");await g("npm",["install"],{cwd:d,stdio:n?"inherit":"pipe"}),a.success("Dependencies installed.")}catch(g){a.warn(`npm install failed: ${g.message.split(`
|
|
345
|
+
`)[0]}`)}if(n&&await r({message:`Configure authoring now (eds init in ${s})?`,default:!0})){let g=process.cwd();try{process.chdir(d);let{initProject:h}=await Promise.resolve().then(()=>(At(),Tt));await h({name:ma.basename(d),...l.ue?{authoring:"ue"}:{}})}finally{process.chdir(g)}return}a.info(pa.dim(` Next: cd ${s} && eds init`)),a.info(pa.dim(" Then push it to your own GitHub repo and install AEM Code Sync to get a preview URL."))}var Co=v(()=>{"use strict";f();Er();O();fn();B()});function it(e){return{Authorization:`Bearer ${e}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28","User-Agent":"aem-eds-kit","Content-Type":"application/json"}}function Pd(e){return`${ot}/repos/${e}/generate`}async function Tn(e){let t=await fetch(`${ot}/user`,{headers:it(e)});if(!t.ok)throw new Error(`GitHub auth failed: ${t.status}`);return(await t.json()).login}async function ua(e,t,n){let o=await fetch(`${ot}/repos/${t}/${n}`,{headers:it(e)});if(o.status===404)return!1;if(o.ok)return!0;throw new Error(`existence check failed: ${o.status} ${await o.text()}`)}async function fa(e,t,n){let o=await fetch(Pd(t),{method:"POST",headers:it(e),body:JSON.stringify({owner:n.owner,name:n.name,private:!!n.private,include_all_branches:!1})});if(!o.ok)throw new Error(`create failed: ${o.status} ${await o.text()}`);let i=await o.json();return{fullName:i.full_name,htmlUrl:i.html_url,cloneUrl:i.clone_url}}async function ga(e,t,n,o){await fetch(`${ot}/repos/${t}/${n}/topics`,{method:"PUT",headers:it(e),body:JSON.stringify({names:o})})}async function ha(e,t,n){let o=await fetch(`${ot}/repos/${t}/${n}`,{method:"DELETE",headers:it(e)});if(!o.ok&&o.status!==204)throw new Error(`delete failed: ${o.status} ${await o.text()}`)}async function wa(e,t,n){let o=encodeURIComponent(`user:${t} topic:${n} fork:true`),i=await fetch(`${ot}/search/repositories?q=${o}&per_page=100`,{headers:it(e)});if(!i.ok)throw new Error(`search failed: ${i.status}`);return(await i.json()).items.map(s=>s.full_name)}var ot,ba=v(()=>{"use strict";f();ot="https://api.github.com"});import{existsSync as ya}from"fs";import{mkdir as Ed,readFile as Cd,rm as Td,writeFile as Ad}from"fs/promises";import Rd from"os";import va from"path";async function xa(){let e=process.env.GITHUB_TOKEN||process.env.GH_TOKEN;if(e)return e;if(ya(Rt))try{return JSON.parse(await Cd(Rt,"utf-8")).token??null}catch{return null}return null}async function To(e){await Ed(ka,{recursive:!0,mode:448}),await Ad(Rt,`${JSON.stringify({token:e},null,2)}
|
|
346
|
+
`,{mode:384})}async function $a(){ya(Rt)&&await Td(Rt)}async function Sa(e){let t=await fetch("https://github.com/login/device/code",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({client_id:An,scope:e.join(" ")})});if(!t.ok)throw new Error(`device code request failed: ${t.status}`);return await t.json()}async function ja(e,t,n){let o=Math.max(t,1),i=Date.now()+n*1e3;for(;Date.now()<i;){await new Promise(c=>setTimeout(c,o*1e3));let s=await(await fetch("https://github.com/login/oauth/access_token",{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({client_id:An,device_code:e,grant_type:"urn:ietf:params:oauth:grant-type:device_code"})})).json();if(s.access_token)return s.access_token;if(s.error==="slow_down")o+=5;else if(s.error!=="authorization_pending")throw new Error(s.error??"device flow failed")}throw new Error("device flow timed out")}var ka,Rt,An,Pa=v(()=>{"use strict";f();ka=va.join(Rd.homedir(),".eds"),Rt=va.join(ka,"github.json"),An=process.env.EDS_GITHUB_CLIENT_ID??""});var He={};U(He,{sandboxList:()=>Id,sandboxLogin:()=>Od,sandboxLogout:()=>Nd,sandboxNew:()=>Md,sandboxRm:()=>_d});import Dd from"path";import ae from"chalk";async function we(e,t,n={}){let{execa:o}=await import("execa");return((await o(e,t,n)).stdout??"").toString().trim()}async function Ao(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{await we(t,[e],{stdio:"ignore"})}catch{}}async function Fd(){try{return await we("gh",["auth","status"]),await we("gh",["api","user","-q",".login"])}catch{return null}}async function Ro(){let e=await xa();if(e)try{return{mode:"api",token:e,login:await Tn(e)}}catch{}let t=await Fd();return t?{mode:"gh",login:t}:null}async function Ld(e,t,n){if(e.mode==="api")return ua(e.token,t,n);try{return await we("gh",["repo","view",`${t}/${n}`,"--json","name"]),!0}catch{return!1}}function Do(){a.error("Not authenticated with GitHub."),a.info(" Run `eds sandbox login` to authorize GitHub, or install + `gh auth login`."),process.exitCode=1}async function Od(){await a.logoOnceAnimated("Sandbox - GitHub login");let{input:e}=await Promise.resolve().then(()=>(q(),J));if(An){let n=await Sa(["repo","delete_repo"]);a.info(j("Authorize GitHub")),a.info(P("code",n.user_code)),a.info(P("open",n.verification_uri)),a.info(""),await Ao(n.verification_uri),a.info(ae.dim(" Waiting for you to authorize in the browser..."));try{let o=await ja(n.device_code,n.interval,n.expires_in);await To(o),a.success(`Authorized as ${await Tn(o)}.`)}catch(o){a.error(`Device flow failed: ${o.message}`),process.exitCode=1}return}a.info(j("Authorize GitHub (least-privilege token)")),a.info(" Create a fine-grained token limited to your sandboxes only:"),a.info(` ${ae.cyan("https://github.com/settings/personal-access-tokens/new")}`),a.info(ae.dim(" - Resource owner: a dedicated sandbox org (recommended) or your account")),a.info(ae.dim(" - Repository access: All repositories in that org (to create new sandboxes),")),a.info(ae.dim(" or Only select repositories to manage existing ones")),a.info(ae.dim(" - Permissions: Administration = Read and write, Contents = Read and write,")),a.info(ae.dim(" Metadata = Read. Set a short expiry.")),a.info(ae.dim(" Tip: `eds sandbox new --org <sandbox-org>` so nothing in your personal account is touched.")),a.info(""),await(await Promise.resolve().then(()=>(q(),J))).confirm({message:"Open the token page?",default:!0})&&await Ao("https://github.com/settings/personal-access-tokens/new");let t=(await e({message:"Paste the token",validate:n=>!!n.trim()||"Required"})).trim();try{let n=await Tn(t);await To(t),a.success(`Authorized as ${n}.`)}catch{a.error("That token didn't work (check the scopes)."),process.exitCode=1}}async function Nd(){await $a(),a.success("Signed out (stored GitHub token removed).")}async function Md(e,t={}){let n=await Ro();if(!n)return Do();await a.logoOnceAnimated("Sandbox");let o=!t.yes,{select:i,confirm:r}=await Promise.resolve().then(()=>(q(),J)),s=t.boilerplate;s||(t.ue?s=Q.ue:o?s=await i({message:"Which boilerplate?",choices:[{name:"Document Authoring (adobe/aem-boilerplate)",value:Q.document},{name:"Universal Editor / crosswalk (adobe-rnd/aem-boilerplate-xwalk)",value:Q.ue}]}):s=Q.document);let c=t.private??!1;t.private===void 0&&o&&(c=await i({message:"Visibility?",choices:[{name:"Public",value:!1},{name:"Private",value:!0}],default:!1}));let l=t.org??n.login;if(await Ld(n,l,e)){a.error(`A repository ${l}/${e} already exists - refusing to touch it.`),a.info(ae.dim(" Pick another name, or remove it first (e.g. `eds sandbox rm` for a sandbox).")),process.exitCode=1;return}a.info(j("Creating sandbox",`${l}/${e} \xB7 ${s}`));try{if(n.mode==="api"){let d=await fa(n.token,s,{owner:l,name:e,private:c});await ga(n.token,l,e,[Qe]),a.info(ae.dim(" Cloning...")),await we("git",["clone",d.cloneUrl,e],{stdio:"inherit"})}else{let d=t.org?`${t.org}/${e}`:e;await we("gh",kr(d,{template:s,private:c,clone:!0}),{stdio:"inherit"});try{await we("gh",["repo","edit",`${l}/${e}`,"--add-topic",Qe])}catch{}}}catch(d){a.error(`Create failed: ${d.message}`),process.exitCode=1;return}if(a.info(""),a.info(j("Sandbox ready")),a.info(P("repo",`https://github.com/${l}/${e}`)),a.info(P("preview",lo(l,e))),a.info(""),o){if(await r({message:"Open the AEM Code Sync install page now?",default:!0})&&await Ao(mo()),await r({message:`Configure authoring now (eds init in ./${e})?`,default:!0})){let d=process.cwd();try{process.chdir(Dd.join(d,e));let{initProject:m}=await Promise.resolve().then(()=>(At(),Tt));await m({})}finally{process.chdir(d)}}}else a.info(ae.dim(` Install AEM Code Sync: ${mo()}`)),a.info(ae.dim(` Configure authoring: cd ${e} && eds init`));a.info(""),a.info(W([`Sandbox "${e}" ready - tear down with \`eds sandbox rm ${e}\``]))}async function Id(){let e=await Ro();if(!e)return Do();let t=[];try{if(e.mode==="api")t=await wa(e.token,e.login,Qe);else{let o=await we("gh",["repo","list","--topic",Qe,"--limit","100","--json","nameWithOwner","-q",".[].nameWithOwner"]);t=o?o.split(`
|
|
347
|
+
`).filter(Boolean):[]}}catch(o){a.error(`List failed: ${o.message}`),process.exitCode=1;return}if(a.info(j("Sandboxes",`${t.length} tagged ${Qe}`)),t.length===0){a.info(ae.dim(" None yet. Create one with `eds sandbox new <name>`."));return}let n=_(t);for(let o of t){let[i,r]=o.split("/");a.info(P(o,lo(i,r),n))}}async function _d(e,t={}){let n=await Ro();if(!n)return Do();let o=t.org??n.login,i=`${o}/${e}`;if(!t.yes){let{confirm:r}=await Promise.resolve().then(()=>(q(),J));if(!await r({message:`Permanently delete ${i}? This cannot be undone.`,default:!1})){a.info("Cancelled.");return}}try{n.mode==="api"?await ha(n.token,o,e):await we("gh",["repo","delete",i,"--yes"])}catch(r){a.error(`Delete failed: ${r.message}`),a.info(ae.dim(" Deleting needs the delete_repo scope (re-run `eds sandbox login`, or `gh auth refresh -s delete_repo`).")),process.exitCode=1;return}a.info(j("Deleted")),a.info(P(i,"removed"))}var Ge=v(()=>{"use strict";f();O();ba();Pa();fn();B()});import{existsSync as Ud}from"fs";import{readFile as Bd}from"fs/promises";import Hd from"path";import{parse as Gd}from"yaml";async function Ea(e){let t=Hd.join(e,"fstab.yaml");if(Ud(t))try{let o=(Gd(await Bd(t,"utf-8"))??{}).mountpoints?.["/"],i=typeof o=="string"?o:o?.url??"",r=i.match(/content\.da\.live\/([^/]+)\/([^/]+)/);return r?{model:"da",org:r[1],site:r[2],mountpoint:i}:/drive\.google\.com/.test(i)?{model:"gdrive",mountpoint:i}:/sharepoint\.com|-my\.sharepoint/.test(i)?{model:"sharepoint",mountpoint:i}:{model:"document",mountpoint:i}}catch{}return{model:"ue"}}var Ca=v(()=>{"use strict";f()});function Wd(e,t,n){let o=n.replace(/^\/+/,"").replace(/\.html$/i,"");return`https://admin.da.live/source/${e}/${t}/${o}.html`}function Ta(e,t,n){let o=n.replace(/^\/+/,"").replace(/\.html$/i,"");return`https://da.live/edit#/${e}/${t}/${o}`}async function Aa(e,t,n,o,i){let r=Wd(e,t,n),s=new FormData;s.append("data",new Blob([o],{type:"text/html"}),"content.html");let c={};i&&(c.Authorization=`Bearer ${i}`);let l=await fetch(r,{method:"POST",body:s,headers:c});if(!l.ok)throw new Error(`DA push failed: ${l.status} ${l.statusText}`);return r}var Ra=v(()=>{"use strict";f()});function zd(e){return` <div class="${e}">
|
|
348
348
|
<div>
|
|
349
349
|
<div>${e} content</div>
|
|
350
350
|
</div>
|
|
351
|
-
</div>`}function
|
|
351
|
+
</div>`}function Jd(e){let t=[` <div><div>Title</div><div>${e.title}</div></div>`,` <div><div>Description</div><div>${e.description??""}</div></div>`];return e.area&&t.push(` <div><div>Template</div><div>${e.area}</div></div>`),` <div class="metadata">
|
|
352
352
|
${t.join(`
|
|
353
353
|
`)}
|
|
354
|
-
</div>`}function
|
|
354
|
+
</div>`}function Da(e){let t=e.blocks??[],n=` <div>
|
|
355
355
|
<h1>${e.title}</h1>
|
|
356
356
|
<p>${e.description??"Intro copy goes here."}</p>
|
|
357
357
|
</div>`,o=t.map(r=>` <div>
|
|
358
|
-
${
|
|
358
|
+
${zd(r)}
|
|
359
359
|
</div>`),i=` <div>
|
|
360
|
-
${
|
|
360
|
+
${Jd(e)}
|
|
361
361
|
</div>`;return`<body>
|
|
362
362
|
<header></header>
|
|
363
363
|
<main>
|
|
@@ -366,13 +366,13 @@ ${[n,...o,i].join(`
|
|
|
366
366
|
</main>
|
|
367
367
|
<footer></footer>
|
|
368
368
|
</body>
|
|
369
|
-
`}var
|
|
370
|
-
`}var
|
|
371
|
-
`),!0}async function
|
|
372
|
-
`).map(d=>d.trim()),
|
|
369
|
+
`}var Fa=v(()=>{"use strict";f()});import{existsSync as qd}from"fs";import{readFile as Kd}from"fs/promises";import Vd from"path";function Xd(e){if(e.value!==void 0)return e.value;switch(e.valueType){case"boolean":return!1;case"number":return 0;case"string[]":return[];default:return""}}async function Yd(e,t){let n=Vd.join(e,"blocks",t,`_${t}.json`);if(!qd(n))return{};try{let o=JSON.parse(await Kd(n,"utf-8")),i=Array.isArray(o.models)?o.models:[],s=(i.find(l=>l.id===t)??i[0])?.fields??[],c={};for(let l of s)l.component!=="tab"&&(c[l.name]=l.component==="container"?[]:Xd(l));return c}catch{return{}}}async function La(e,t){let n=[];for(let i of t.blocks)n.push({name:i,model:i,fields:await Yd(e,i)});let o={title:t.title,template:t.name,components:n};return`${JSON.stringify(o,null,2)}
|
|
370
|
+
`}var Oa=v(()=>{"use strict";f()});var Oo={};U(Oo,{templateNew:()=>im});import{existsSync as Lo}from"fs";import{mkdir as Qd,readFile as Na,readdir as Zd,writeFile as Fo}from"fs/promises";import Pe from"path";import Dt from"chalk";async function tm(e){let t=Pe.join(e,"blocks");return Lo(t)?(await Zd(t,{withFileTypes:!0})).filter(n=>n.isDirectory()).map(n=>n.name):[]}async function nm(e){let t=Pe.join(e,".edsrc.json");if(!Lo(t))return{};try{return JSON.parse(await Na(t,"utf-8")).admin??{}}catch{return{}}}async function om(e,t){if(!t.length)return!1;let n=Pe.join(e,"component-filters.json"),o=null;if(Lo(n))try{o=JSON.parse(await Na(n,"utf-8"))}catch{o=null}let i=Ct(o,t);return await Fo(n,`${JSON.stringify(i,null,2)}
|
|
371
|
+
`),!0}async function im(e,t={}){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}await a.logoOnceAnimated("Page template");let{input:o,select:i,confirm:r}=await Promise.resolve().then(()=>(q(),J)),s=!t.yes,c=await Ea(n),l=t.authoring??c.model,d=em(e),m=t.title??(s?await o({message:"Page title",default:e}):e),p=t.description??(s?await o({message:"Description (optional)"}):""),u=t.path??`/templates/${d}`,g=t.blocks;if(!g&&s){let y=await tm(n),b=y.length?y:Ue.map(N=>N.id),T=[],F=!0;for(;F;){let N=await i({message:`Add a block in order (${T.length} so far)`,choices:[...b.map(te=>({name:te,value:te})),{name:T.length?"- done -":"- done (empty page) -",value:"__done"}]});N==="__done"?F=!1:T.push(N)}g=T}let h=g??[],$=Da({title:m,description:p||void 0,blocks:h,area:t.area}),w=Pe.join("templates",`${d}.html`);if(await Qd(Pe.join(n,"templates"),{recursive:!0}),await Fo(Pe.join(n,w),$),a.info(j("Page template",`${u} \xB7 ${l}`)),a.info(P(w,`${h.length} block(s) + metadata`)),l==="da"){let y=await nm(n),b=t.org??y.org??c.org,T=t.site??y.site??c.site;if(t.push??(s?await r({message:"Push to DA (da.live)?",default:!0}):!0))if(!b||!T)a.warn("No DA org/site. Pass --org/--site or set admin in .edsrc.json.");else try{await Aa(b,T,u,$,process.env.DA_TOKEN),a.info(P("pushed to DA",Ta(b,T,u)))}catch(N){a.error(`DA push failed: ${N.message}`),a.info(Dt.dim(" Open projects allow anonymous writes; others need DA_TOKEN."))}}else if(l==="gdrive"||l==="sharepoint"){let y=l==="gdrive"?"a Google Doc":"a Word doc";a.info(""),a.info(Dt.dim(` Document model: import ${w} into ${y} in your mounted folder,`)),a.info(Dt.dim(" then preview/publish. (Share the folder + install aem-code-sync first.)"))}else if(l==="ue"){let y=Pe.join("templates",`${d}.json`);await Fo(Pe.join(n,y),await La(n,{title:m,name:d,blocks:h})),a.info(P(y,`initial content (${h.length} component(s), in order)`)),await om(n,h)&&a.info(P("component-filters.json","seeded blocks allowed in Universal Editor")),a.info(""),a.info(Dt.dim(" Universal Editor: use the template JSON as the page's initial content, then")),a.info(Dt.dim(" author it in the Universal Editor (wire the repo to AEM)."))}a.info(""),a.info(W([`"${d}" template (${l}) - preview with \`eds preview ${u}\``]))}var em,No=v(()=>{"use strict";f();O();K();vo();So();Ca();Ra();Fa();Oa();B();em=e=>e.trim().toLowerCase().replace(/[^a-z0-9-/]+/g,"-").replace(/^-+|-+$/g,"")});import{existsSync as Rn}from"fs";import{readFile as Ma,readdir as Ia}from"fs/promises";import We from"path";async function rm(e){let t=[],n=async o=>{for(let i of await Ia(o,{withFileTypes:!0})){let r=We.join(o,i.name);i.isDirectory()?await n(r):t.push(r)}};return Rn(e)&&await n(e),t}async function _a(e){if(!Rn(e))return null;let t=await Ia(e,{withFileTypes:!0}),n=t.find(i=>i.isDirectory()&&/clientlib/i.test(i.name));return n?We.join(e,n.name):t.some(i=>i.isFile()&&i.name.endsWith(".css"))?e:null}async function Ua(e){let t=await rm(e),n=t.filter(s=>/\.(less|scss|sass)$/i.test(s)).map(s=>We.relative(e,s)),o,i=We.join(e,"css.txt");if(Rn(i)){let s=(await Ma(i,"utf-8")).split(`
|
|
372
|
+
`).map(d=>d.trim()),c=e,l=[];for(let d of s){if(!d)continue;let m=d.match(/^#base\s*=\s*(.+)$/);m?c=We.join(e,m[1].trim()):d.startsWith("#")||l.push(d)}o=l.map(d=>We.join(c,d)).filter(d=>Rn(d)&&d.endsWith(".css"))}else o=t.filter(s=>s.endsWith(".css"));let r=[];for(let s of o)r.push(await Ma(s,"utf-8"));return{css:r.join(`
|
|
373
373
|
|
|
374
|
-
`),files:o.map(s=>Be.relative(e,s)),preprocessed:n}}var wa=k(()=>{"use strict";f()});import{XMLParser as Cd}from"fast-xml-parser";function ee(e){return Object.keys(e).find(t=>t!==":@")??""}function Y(e){let t=ee(e),n=e[t];return Array.isArray(n)?n:[]}function Td(e){return e[":@"]??{}}function Ad(e){return typeof e=="string"?e.replace(/^\{[^}]+\}/,""):e}function C(e,t){return Ad(Td(e)[`@_${t}`])}function Rd(e,t){let n=C(t,"multiple")==="true"||C(t,"multiple")==="{Boolean}true";return e.endsWith("/form/pagefield")?"aem-content":e.includes("experience-fragment")||e.endsWith("/xffield")?"aem-experience-fragment":e.endsWith("/cfpicker")?"aem-content-fragment":e.endsWith("/form/textfield")||e.endsWith("/form/colorfield")||e.includes("/autocomplete")?"text":e.endsWith("/form/textarea")?"textarea":e.includes("/richtext")?"richtext":e.endsWith("/form/numberfield")?"number":e.endsWith("/form/checkbox")?"boolean":e.endsWith("/form/radiogroup")?"radio-group":e.endsWith("/form/select")?n?"multiselect":"select":e.endsWith("/form/datepicker")?"date-time":e.endsWith("/form/pathfield")||e.endsWith("/form/pathbrowser")?"aem-content":e.includes("/fileupload")||e.endsWith("/form/fileupload")?"reference":e.includes("tagfield")||e.includes("tagpicker")||e.includes("tagbrowser")?"aem-tag":e.includes("contentfragment")?"aem-content-fragment":e.includes("experiencefragment")?"aem-experience-fragment":null}function Fd(e){return e.endsWith("/form/hidden")||e.endsWith("/foundation/heading")||e.endsWith("/foundation/text")}function Ld(e){return e.includes("/foundation/container")||e.includes("/foundation/fixedcolumns")||e.includes("/foundation/well")||e.includes("/foundation/tabs")||e.includes("/foundation/form/fieldset")||e.includes("/foundation/accordion")}function vo(e){switch(e){case"number":return"number";case"boolean":return"boolean";case"date-time":return"date";case"checkbox-group":return"string[]";case"aem-content":case"aem-content-fragment":case"aem-experience-fragment":return;default:return"string"}}function He(e,t){return(e??"").replace(/^\.\//,"").trim()||t}function Od(e){let t=Y(e).find(n=>ee(n)==="items");return t?Y(t).map(n=>{let o=C(n,"value")??"";return{name:C(n,"text")??C(n,"jcr:title")??o,value:o}}):[]}function jt(e,t,n){let{unmapped:o,counter:i}=n;for(let r of e){let s=C(r,"sling:resourceType")??"";if(s.endsWith("/foundation/include")){let c=n.includeDepth<8?n.resolveInclude?.(C(r,"path")??""):null;c&&jt(c,t,{...n,includeDepth:n.includeDepth+1});continue}if(Fd(s))continue;if(s.endsWith("/foundation/tabs")){let c=Y(r).find(d=>ee(d)==="items");for(let d of c?Y(c):[]){let m=C(d,"jcr:title");t.push({component:"tab",name:He(void 0,ee(d)),label:m}),jt(Y(d),t,n)}continue}if(s.endsWith("/form/multifield")){let c=[];jt(Y(r),c,n);let d=Y(r).find(p=>ee(p)==="field"),m=He(C(r,"name")??(d?C(d,"name"):void 0),`items${i.i++}`);t.push({component:"container",name:m,label:C(r,"fieldLabel")??"Items",multi:!0,collapsible:!0,fields:c});continue}let l=s?Rd(s,r):null;if(l){let c=He(C(r,"name"),`field${i.i++}`),d={component:l,name:c},m=vo(l);m&&(d.valueType=m);let p=C(r,"fieldLabel")??C(r,"text");if(p&&(d.label=p),l==="select"||l==="radio-group"||l==="multiselect"){let g=Od(r),h=Y(r).find(w=>ee(w)==="datasource"),v=h?C(h,"sling:resourceType")??"":"";g.length?d.options=g:/heading|allowedtypes/i.test(v)?d.options=Dd:(d.component="text",d.valueType="string",n.datasourced.add(c))}let u=l==="boolean"?C(r,"checked"):C(r,"value");u!==void 0&&u!==""&&(d.value=l==="boolean"?u==="true":u),t.push(d);continue}s&&C(r,"name")&&!Ld(s)&&o.add(s),jt(Y(r),t,n)}}function ko(e){return e.filter((t,n)=>t.component!=="tab"||e[n+1]&&e[n+1].component!=="tab")}function bn(e){let t=new Set,n=[];for(let o of e){if(o.component!=="tab"){if(t.has(o.name))continue;t.add(o.name)}n.push(o.fields?{...o,fields:bn(o.fields)}:o)}return n}function Pt(e){return new Cd({ignoreAttributes:!1,attributeNamePrefix:"@_",preserveOrder:!0,removeNSPrefix:!1,trimValues:!0}).parse(e)}function ba(e,t={}){let n=Pt(e).find(s=>ee(s)==="jcr:root"),o=[],i=new Set,r=new Set;return n&&jt(Y(n),o,{unmapped:i,datasourced:r,counter:{i:1},resolveInclude:t.resolveInclude,includeDepth:0}),{fields:ko(bn(o)),unmapped:[...i],datasourced:[...r]}}function ot(e){let t=0;for(let n of e)n.component!=="tab"&&(t+=1,n.fields&&(t+=ot(n.fields)));return t}var Dd,yn=k(()=>{"use strict";f();Dd=["h1","h2","h3","h4","h5","h6"].map(e=>({name:e.toUpperCase(),value:e}))});function Et(e){return(C(e,"xtype")??"").toLowerCase()}function Ct(e){let t=Y(e).find(n=>ee(n)==="items");return t?C(t,"jcr:primaryType")==="cq:WidgetCollection"||!C(t,"xtype")?Y(t):[t]:Y(e).filter(n=>/^cq:/.test(C(n,"jcr:primaryType")??""))}function Md(e){let t=Y(e).find(n=>ee(n)==="options");return t?Y(t).map(n=>{let o=C(n,"value")??"";return{name:C(n,"text")??o,value:o}}):[]}function ya(e,t,n){let o=C(e,"name")??C(e,"key"),i=null,r,s=He(o,`field${n.counter.i++}`);switch(t){case"textfield":case"colorfield":case"":i="text";break;case"textarea":i="textarea";break;case"richtext":i="richtext";break;case"numberfield":i="number";break;case"checkbox":i="boolean";break;case"datetime":case"datefield":i="date-time";break;case"pathfield":case"browsefield":i="aem-content";break;case"tags":case"tagsinputfield":i="aem-tag";break;case"smartimage":case"html5smartimage":case"smartfile":case"html5smartfile":case"fileupload":i="reference",s=He(C(e,"fileReferenceParameter")??o,s);break;case"selection":{let p=(C(e,"type")??"select").toLowerCase();r=Md(e),p==="checkbox"?i=r.length?"checkbox-group":"boolean":p==="radio"?i="radio-group":i="select",i!=="boolean"&&!r.length&&(i="text",n.datasourced.add(s));break}default:return null}let l={component:i,name:s},c=vo(i);c&&(l.valueType=c);let d=C(e,"fieldLabel")??C(e,"boxLabel")??C(e,"title");d&&(l.label=d),r?.length&&i!=="text"&&(l.options=r);let m=i==="boolean"?C(e,"checked")??C(e,"defaultValue"):C(e,"defaultValue")??C(e,"value");return m!==void 0&&m!==""&&(l.value=i==="boolean"?m==="true":m),l}function Ge(e,t,n){for(let o of e){let i=Et(o);if(Nd.has(i))continue;if(ee(o)==="items"||C(o,"jcr:primaryType")==="cq:WidgetCollection"){Ge(Y(o),t,n);continue}if(i==="slingscriptinclude"){/^rte\./.test(C(o,"script")??"")?t.push({component:"richtext",name:"text",valueType:"string",label:"Text"}):n.unmapped.add("xtype:slingscriptinclude");continue}if(i==="cqinclude"){let s=(C(o,"path")??"").replace(/\.(infinity|\d+)?\.?json$/,""),l=n.depth<8?n.resolveInclude?.(s):null;l&&Ge(l,t,{...n,depth:n.depth+1});continue}if(i==="tabpanel"){for(let s of Ct(o)){if(Et(s)==="cqinclude"){Ge([s],t,n);continue}t.push({component:"tab",name:ee(s),label:C(s,"title")}),Ge(Ct(s),t,n)}continue}if(i==="multifield"){let s=Y(o).find(d=>ee(d)==="fieldConfig"),l=He(C(o,"name"),`items${n.counter.i++}`);if(s&&!xo.has(Et(s))&&!C(s,"name")&&!C(s,"key")){let d=ya(s,Et(s),n);if(d){t.push({...d,name:l,label:C(o,"fieldLabel")??d.label,multi:!0});continue}}let c=[];s&&Ge(xo.has(Et(s))?Ct(s):[s],c,n),t.push({component:"container",name:l,label:C(o,"fieldLabel")??"Items",multi:!0,collapsible:!0,fields:c});continue}if(xo.has(i)||C(o,"jcr:primaryType")==="cq:Panel"||!i&&!C(o,"name")&&Ct(o).length){Ge(Ct(o),t,n);continue}let r=C(o,"name")||C(o,"key")?ya(o,i,n):null;r?t.push(r):i&&n.unmapped.add(`xtype:${i}`)}}function va(e){return/jcr:primaryType="cq:(Dialog|TabPanel|Panel|Widget)"/.test(e)||/\sxtype="/.test(e)}function ka(e,t={}){let n=Pt(e).find(r=>ee(r)==="jcr:root"),o=[],i={unmapped:new Set,datasourced:new Set,counter:{i:1},resolveInclude:t.resolveInclude,depth:0};return n&&Ge([n],o,i),{fields:ko(bn(o)),unmapped:[...i.unmapped],datasourced:[...i.datasourced]}}var xo,Nd,xa=k(()=>{"use strict";f();yn();xo=new Set(["dialog","panel","dialogfieldset","multifieldpanel","fieldset"]),Nd=new Set(["hidden","static","displayfield","label","box","componentstyles"])});import{existsSync as it,readFileSync as $a}from"fs";import{readFile as _d}from"fs/promises";import te from"path";import{XMLParser as Id}from"fast-xml-parser";function Ud(e){return[te.join(e,"_cq_dialog",".content.xml"),te.join(e,"_cq_dialog.xml"),te.join(e,"cq:dialog",".content.xml")].find(n=>it(n))??null}function Bd(e){return[te.join(e,"dialog.xml"),te.join(e,"dialog",".content.xml")].find(n=>it(n))??null}function Sa(e,t){let n=te.join(e,".content.xml");if(it(n))try{let r=(new Id({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse($a(n,"utf-8"))["jcr:root"]??{})[`@_${t}`];return typeof r=="string"?r.replace(/^\{[^}]+\}/,""):void 0}catch{return}}async function ja(e){return Sa(e,"jcr:title")}function $o(e){return Sa(e,"sling:resourceSuperType")}function Hd(e){let t=te.resolve(e);for(;t!==te.dirname(t);){if(te.basename(t)==="jcr_root")return t;t=te.dirname(t)}return null}function Pa(e,t){let n=e.replace(/^\/mnt\/overlay\//,"/").replace(/^\/(apps|libs)\//,"").replace(/^\//,"").split("/").map(i=>i.replace(/^([a-z]+):/,"_$1_")).join("/"),o=[];for(let i of t)o.push(te.join(i,"apps",n),te.join(i,"libs",n),te.join(i,n));return o}function Gd(e){let t=new Map,n=o=>{if(!t.has(o))try{let i=Pt($a(o,"utf-8")).find(r=>ee(r)==="jcr:root");t.set(o,i?Y(i):null)}catch{t.set(o,null)}return t.get(o)??null};return o=>{if(!o||o.includes("${"))return null;for(let i of Pa(o,e)){let r=i.split(te.sep);for(let s=r.length;s>1;s--){let l=r.slice(0,s).join(te.sep),c=it(te.join(l,".content.xml"))?te.join(l,".content.xml"):it(`${l}.xml`)?`${l}.xml`:null;if(!c)continue;let d=n(c);for(let m of r.slice(s)){let p=d?.find(u=>ee(u)===m);d=p?[p]:null}if(d)return d;break}}return null}}async function Ea(e,t=[]){let n=Hd(e),o=[...n?[n]:[],...t],i=Gd(o),r=e,s,l=null;for(let c=0;c<8;c++){let d=Ud(r),m=d?null:Bd(r),p=d??m;if(p){let h=await _d(p,"utf-8"),v=m&&va(h)?"classic":"touch",w=v==="classic"?ka(h,{resolveInclude:i}):ba(h,{resolveInclude:i});if(ot(w.fields)>0)return{...w,inheritedFrom:s,dialogKind:v};l??={...w,dialogKind:v}}let u=$o(r),g=u?Pa(u,o).find(h=>it(h)):void 0;if(!u||!g)break;r=g,s=u}return l}function Ca(e,t,n){return`${JSON.stringify({definitions:[{title:t,id:e,plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:t,model:e}}}}}],models:[{id:e,fields:n}],filters:[]},null,2)}
|
|
375
|
-
`}function
|
|
374
|
+
`),files:o.map(s=>We.relative(e,s)),preprocessed:n}}var Ba=v(()=>{"use strict";f()});import{XMLParser as am}from"fast-xml-parser";function ne(e){return Object.keys(e).find(t=>t!==":@")??""}function Y(e){let t=ne(e),n=e[t];return Array.isArray(n)?n:[]}function sm(e){return e[":@"]??{}}function cm(e){return typeof e=="string"?e.replace(/^\{[^}]+\}/,""):e}function C(e,t){return cm(sm(e)[`@_${t}`])}function lm(e,t){let n=C(t,"multiple")==="true"||C(t,"multiple")==="{Boolean}true";return e.endsWith("/form/pagefield")?"aem-content":e.includes("experience-fragment")||e.endsWith("/xffield")?"aem-experience-fragment":e.endsWith("/cfpicker")?"aem-content-fragment":e.endsWith("/form/textfield")||e.endsWith("/form/colorfield")||e.includes("/autocomplete")?"text":e.endsWith("/form/textarea")?"textarea":e.includes("/richtext")?"richtext":e.endsWith("/form/numberfield")?"number":e.endsWith("/form/checkbox")?"boolean":e.endsWith("/form/radiogroup")?"radio-group":e.endsWith("/form/select")?n?"multiselect":"select":e.endsWith("/form/datepicker")?"date-time":e.endsWith("/form/pathfield")||e.endsWith("/form/pathbrowser")?"aem-content":e.includes("/fileupload")||e.endsWith("/form/fileupload")?"reference":e.includes("tagfield")||e.includes("tagpicker")||e.includes("tagbrowser")?"aem-tag":e.includes("contentfragment")?"aem-content-fragment":e.includes("experiencefragment")?"aem-experience-fragment":null}function dm(e){return e.endsWith("/form/hidden")||e.endsWith("/foundation/heading")||e.endsWith("/foundation/text")}function mm(e){return e.includes("/foundation/container")||e.includes("/foundation/fixedcolumns")||e.includes("/foundation/well")||e.includes("/foundation/tabs")||e.includes("/foundation/form/fieldset")||e.includes("/foundation/accordion")}function Mo(e){switch(e){case"number":return"number";case"boolean":return"boolean";case"date-time":return"date";case"checkbox-group":return"string[]";case"aem-content":case"aem-content-fragment":case"aem-experience-fragment":return;default:return"string"}}function ze(e,t){return(e??"").replace(/^\.\//,"").trim()||t}function um(e){let t=Y(e).find(n=>ne(n)==="items");return t?Y(t).map(n=>{let o=C(n,"value")??"";return{name:C(n,"text")??C(n,"jcr:title")??o,value:o}}):[]}function Ft(e,t,n){let{unmapped:o,counter:i}=n;for(let r of e){let s=C(r,"sling:resourceType")??"";if(s.endsWith("/foundation/include")){let l=n.includeDepth<8?n.resolveInclude?.(C(r,"path")??""):null;l&&Ft(l,t,{...n,includeDepth:n.includeDepth+1});continue}if(dm(s))continue;if(s.endsWith("/foundation/tabs")){let l=Y(r).find(d=>ne(d)==="items");for(let d of l?Y(l):[]){let m=C(d,"jcr:title");t.push({component:"tab",name:ze(void 0,ne(d)),label:m}),Ft(Y(d),t,n)}continue}if(s.endsWith("/form/multifield")){let l=[];Ft(Y(r),l,n);let d=Y(r).find(p=>ne(p)==="field"),m=ze(C(r,"name")??(d?C(d,"name"):void 0),`items${i.i++}`);t.push({component:"container",name:m,label:C(r,"fieldLabel")??"Items",multi:!0,collapsible:!0,fields:l});continue}let c=s?lm(s,r):null;if(c){let l=ze(C(r,"name"),`field${i.i++}`),d={component:c,name:l},m=Mo(c);m&&(d.valueType=m);let p=C(r,"fieldLabel")??C(r,"text");if(p&&(d.label=p),c==="select"||c==="radio-group"||c==="multiselect"){let g=um(r),h=Y(r).find(w=>ne(w)==="datasource"),$=h?C(h,"sling:resourceType")??"":"";g.length?d.options=g:/heading|allowedtypes/i.test($)?d.options=pm:(d.component="text",d.valueType="string",n.datasourced.add(l))}let u=c==="boolean"?C(r,"checked"):C(r,"value");u!==void 0&&u!==""&&(d.value=c==="boolean"?u==="true":u),t.push(d);continue}s&&C(r,"name")&&!mm(s)&&o.add(s),Ft(Y(r),t,n)}}function Io(e){return e.filter((t,n)=>t.component!=="tab"||e[n+1]&&e[n+1].component!=="tab")}function Dn(e){let t=new Set,n=[];for(let o of e){if(o.component!=="tab"){if(t.has(o.name))continue;t.add(o.name)}n.push(o.fields?{...o,fields:Dn(o.fields)}:o)}return n}function Lt(e){return new am({ignoreAttributes:!1,attributeNamePrefix:"@_",preserveOrder:!0,removeNSPrefix:!1,trimValues:!0}).parse(e)}function Ha(e,t={}){let n=Lt(e).find(s=>ne(s)==="jcr:root"),o=[],i=new Set,r=new Set;return n&&Ft(Y(n),o,{unmapped:i,datasourced:r,counter:{i:1},resolveInclude:t.resolveInclude,includeDepth:0}),{fields:Io(Dn(o)),unmapped:[...i],datasourced:[...r]}}function rt(e){let t=0;for(let n of e)n.component!=="tab"&&(t+=1,n.fields&&(t+=rt(n.fields)));return t}var pm,Fn=v(()=>{"use strict";f();pm=["h1","h2","h3","h4","h5","h6"].map(e=>({name:e.toUpperCase(),value:e}))});function Ot(e){return(C(e,"xtype")??"").toLowerCase()}function Nt(e){let t=Y(e).find(n=>ne(n)==="items");return t?C(t,"jcr:primaryType")==="cq:WidgetCollection"||!C(t,"xtype")?Y(t):[t]:Y(e).filter(n=>/^cq:/.test(C(n,"jcr:primaryType")??""))}function gm(e){let t=Y(e).find(n=>ne(n)==="options");return t?Y(t).map(n=>{let o=C(n,"value")??"";return{name:C(n,"text")??o,value:o}}):[]}function Ga(e,t,n){let o=C(e,"name")??C(e,"key"),i=null,r,s=ze(o,`field${n.counter.i++}`);switch(t){case"textfield":case"colorfield":case"":i="text";break;case"textarea":i="textarea";break;case"richtext":i="richtext";break;case"numberfield":i="number";break;case"checkbox":i="boolean";break;case"datetime":case"datefield":i="date-time";break;case"pathfield":case"browsefield":i="aem-content";break;case"tags":case"tagsinputfield":i="aem-tag";break;case"smartimage":case"html5smartimage":case"smartfile":case"html5smartfile":case"fileupload":i="reference",s=ze(C(e,"fileReferenceParameter")??o,s);break;case"selection":{let p=(C(e,"type")??"select").toLowerCase();r=gm(e),p==="checkbox"?i=r.length?"checkbox-group":"boolean":p==="radio"?i="radio-group":i="select",i!=="boolean"&&!r.length&&(i="text",n.datasourced.add(s));break}default:return null}let c={component:i,name:s},l=Mo(i);l&&(c.valueType=l);let d=C(e,"fieldLabel")??C(e,"boxLabel")??C(e,"title");d&&(c.label=d),r?.length&&i!=="text"&&(c.options=r);let m=i==="boolean"?C(e,"checked")??C(e,"defaultValue"):C(e,"defaultValue")??C(e,"value");return m!==void 0&&m!==""&&(c.value=i==="boolean"?m==="true":m),c}function Je(e,t,n){for(let o of e){let i=Ot(o);if(fm.has(i))continue;if(ne(o)==="items"||C(o,"jcr:primaryType")==="cq:WidgetCollection"){Je(Y(o),t,n);continue}if(i==="slingscriptinclude"){/^rte\./.test(C(o,"script")??"")?t.push({component:"richtext",name:"text",valueType:"string",label:"Text"}):n.unmapped.add("xtype:slingscriptinclude");continue}if(i==="cqinclude"){let s=(C(o,"path")??"").replace(/\.(infinity|\d+)?\.?json$/,""),c=n.depth<8?n.resolveInclude?.(s):null;c&&Je(c,t,{...n,depth:n.depth+1});continue}if(i==="tabpanel"){for(let s of Nt(o)){if(Ot(s)==="cqinclude"){Je([s],t,n);continue}t.push({component:"tab",name:ne(s),label:C(s,"title")}),Je(Nt(s),t,n)}continue}if(i==="multifield"){let s=Y(o).find(d=>ne(d)==="fieldConfig"),c=ze(C(o,"name"),`items${n.counter.i++}`);if(s&&!_o.has(Ot(s))&&!C(s,"name")&&!C(s,"key")){let d=Ga(s,Ot(s),n);if(d){t.push({...d,name:c,label:C(o,"fieldLabel")??d.label,multi:!0});continue}}let l=[];s&&Je(_o.has(Ot(s))?Nt(s):[s],l,n),t.push({component:"container",name:c,label:C(o,"fieldLabel")??"Items",multi:!0,collapsible:!0,fields:l});continue}if(_o.has(i)||C(o,"jcr:primaryType")==="cq:Panel"||!i&&!C(o,"name")&&Nt(o).length){Je(Nt(o),t,n);continue}let r=C(o,"name")||C(o,"key")?Ga(o,i,n):null;r?t.push(r):i&&n.unmapped.add(`xtype:${i}`)}}function Wa(e){return/jcr:primaryType="cq:(Dialog|TabPanel|Panel|Widget)"/.test(e)||/\sxtype="/.test(e)}function za(e,t={}){let n=Lt(e).find(r=>ne(r)==="jcr:root"),o=[],i={unmapped:new Set,datasourced:new Set,counter:{i:1},resolveInclude:t.resolveInclude,depth:0};return n&&Je([n],o,i),{fields:Io(Dn(o)),unmapped:[...i.unmapped],datasourced:[...i.datasourced]}}var _o,fm,Ja=v(()=>{"use strict";f();Fn();_o=new Set(["dialog","panel","dialogfieldset","multifieldpanel","fieldset"]),fm=new Set(["hidden","static","displayfield","label","box","componentstyles"])});import{existsSync as at,readFileSync as qa}from"fs";import{readFile as hm}from"fs/promises";import oe from"path";import{XMLParser as wm}from"fast-xml-parser";function bm(e){return[oe.join(e,"_cq_dialog",".content.xml"),oe.join(e,"_cq_dialog.xml"),oe.join(e,"cq:dialog",".content.xml")].find(n=>at(n))??null}function ym(e){return[oe.join(e,"dialog.xml"),oe.join(e,"dialog",".content.xml")].find(n=>at(n))??null}function Ka(e,t){let n=oe.join(e,".content.xml");if(at(n))try{let r=(new wm({ignoreAttributes:!1,attributeNamePrefix:"@_"}).parse(qa(n,"utf-8"))["jcr:root"]??{})[`@_${t}`];return typeof r=="string"?r.replace(/^\{[^}]+\}/,""):void 0}catch{return}}async function Va(e){return Ka(e,"jcr:title")}function Uo(e){return Ka(e,"sling:resourceSuperType")}function vm(e){let t=oe.resolve(e);for(;t!==oe.dirname(t);){if(oe.basename(t)==="jcr_root")return t;t=oe.dirname(t)}return null}function Xa(e,t){let n=e.replace(/^\/mnt\/overlay\//,"/").replace(/^\/(apps|libs)\//,"").replace(/^\//,"").split("/").map(i=>i.replace(/^([a-z]+):/,"_$1_")).join("/"),o=[];for(let i of t)o.push(oe.join(i,"apps",n),oe.join(i,"libs",n),oe.join(i,n));return o}function km(e){let t=new Map,n=o=>{if(!t.has(o))try{let i=Lt(qa(o,"utf-8")).find(r=>ne(r)==="jcr:root");t.set(o,i?Y(i):null)}catch{t.set(o,null)}return t.get(o)??null};return o=>{if(!o||o.includes("${"))return null;for(let i of Xa(o,e)){let r=i.split(oe.sep);for(let s=r.length;s>1;s--){let c=r.slice(0,s).join(oe.sep),l=at(oe.join(c,".content.xml"))?oe.join(c,".content.xml"):at(`${c}.xml`)?`${c}.xml`:null;if(!l)continue;let d=n(l);for(let m of r.slice(s)){let p=d?.find(u=>ne(u)===m);d=p?[p]:null}if(d)return d;break}}return null}}async function Ya(e,t=[]){let n=vm(e),o=[...n?[n]:[],...t],i=km(o),r=e,s,c=null;for(let l=0;l<8;l++){let d=bm(r),m=d?null:ym(r),p=d??m;if(p){let h=await hm(p,"utf-8"),$=m&&Wa(h)?"classic":"touch",w=$==="classic"?za(h,{resolveInclude:i}):Ha(h,{resolveInclude:i});if(rt(w.fields)>0)return{...w,inheritedFrom:s,dialogKind:$};c??={...w,dialogKind:$}}let u=Uo(r),g=u?Xa(u,o).find(h=>at(h)):void 0;if(!u||!g)break;r=g,s=u}return c}function Qa(e,t,n){return`${JSON.stringify({definitions:[{title:t,id:e,plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:t,model:e}}}}}],models:[{id:e,fields:n}],filters:[]},null,2)}
|
|
375
|
+
`}function Za(e,t){let o=t.some(i=>i.component==="container"&&i.multi)?` // This block was migrated from a classic AEM component with a multifield.
|
|
376
376
|
// Each child row is one repeated item - enhance them here.
|
|
377
377
|
[...block.children].forEach((row) => {
|
|
378
378
|
row.classList.add('${e}-item');
|
|
@@ -384,25 +384,25 @@ export default function decorate(block) {
|
|
|
384
384
|
block.classList.add('${e}');
|
|
385
385
|
${o}
|
|
386
386
|
}
|
|
387
|
-
`}function
|
|
387
|
+
`}function es(e){return`/* Block: ${e} */
|
|
388
388
|
/* Migrated from a classic AEM component. Bring the component's styles here */
|
|
389
389
|
/* (from its clientlib or the rendered page) and keep them scoped to the block. */
|
|
390
390
|
.${e} {
|
|
391
391
|
}
|
|
392
|
-
`}var
|
|
393
|
-
`)}function
|
|
394
|
-
${
|
|
392
|
+
`}var ts=v(()=>{"use strict";f();Ja();Fn()});function xm(e,t,n){let o=[` // --- ${os} ---`];return n.click&&o.push(` ${t}.addEventListener('click', (ev) => {`," const el = ev.target.closest('a, button');"," if (!el) return;",` trackEvent({ event: 'block_click', block: '${e}', label: el.dataset.track || el.textContent.trim() });`," });"),n.submit&&o.push(` ${t}.addEventListener('submit', () => {`,` trackEvent({ event: 'form_submit', block: '${e}' });`," });"),o.join(`
|
|
393
|
+
`)}function is(e,t,n){if(e.includes(os))return{js:e,changed:!1,reason:"already instrumented"};if(!n.click&&!n.submit)return{js:e,changed:!1,reason:"no events selected"};let o=e.match(/export default (?:async )?function decorate\s*\(\s*([A-Za-z_$][\w$]*)?[^)]*\)\s*\{/);if(!o||o.index===void 0)return{js:e,changed:!1,reason:"no `export default function decorate(...)` found"};let i=o[1]||"block",r=e;if(!r.includes("scripts/analytics.js")){let d=[...r.matchAll(/^import .*$/gm)];if(d.length){let m=d[d.length-1],p=(m.index??0)+m[0].length;r=`${r.slice(0,p)}
|
|
394
|
+
${ns}${r.slice(p)}`}else r=`${ns}
|
|
395
395
|
|
|
396
|
-
${r}`}let s=r.match(/export default (?:async )?function decorate\s*\(\s*([A-Za-z_$][\w$]*)?[^)]*\)\s*\{/);if(!s||s.index===void 0)return{js:r,changed:!1,reason:"decorate not found"};let
|
|
397
|
-
${
|
|
398
|
-
${r.slice(
|
|
396
|
+
${r}`}let s=r.match(/export default (?:async )?function decorate\s*\(\s*([A-Za-z_$][\w$]*)?[^)]*\)\s*\{/);if(!s||s.index===void 0)return{js:r,changed:!1,reason:"decorate not found"};let c=s.index+s[0].length,l=xm(t,i,n);return r=`${r.slice(0,c)}
|
|
397
|
+
${l}
|
|
398
|
+
${r.slice(c)}`,{js:r,changed:!0}}var os,ns,rs=v(()=>{"use strict";f();os="analytics (eds track)",ns="import { trackEvent } from '../../scripts/analytics.js';"});var Mt={};U(Mt,{trackBlock:()=>Pm});import{existsSync as as}from"fs";import{readFile as $m,writeFile as Sm}from"fs/promises";import ss from"path";import jm from"chalk";async function Pm(e,t={}){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Track block"));let o=ss.join(n,"blocks",e,`${e}.js`);if(!as(o)){a.error(`Block "${e}" not found (no blocks/${e}/${e}.js).`),process.exitCode=1;return}let i={click:t.click!==!1,submit:t.submit!==!1},r=is(await $m(o,"utf-8"),e,i);if(!r.changed){a.warn(`Not instrumented: ${r.reason}.`);return}await Sm(o,r.js),a.info(j("Instrumented"));let s=[i.click?"block_click":null,i.submit?"form_submit":null].filter(Boolean);a.info(P(`blocks/${e}/${e}.js`,s.join(" + "))),as(ss.join(n,"scripts","analytics.js"))||(a.info(""),a.warn("scripts/analytics.js is missing - run `eds integrate gtm` to create it.")),a.info(""),a.info(jm.dim(" Events push to window.dataLayer via trackEvent - GTM picks them up."))}var It=v(()=>{"use strict";f();O();K();rs();B()});var Go={};U(Go,{migrateComponent:()=>Tm});import{existsSync as Bo}from"fs";import{mkdir as Em,writeFile as Ho}from"fs/promises";import Ee from"path";function Cm(e,t,n){return`/* Block: ${e} */
|
|
399
399
|
/* Migrated from the component clientlib: ${n.join(", ")}. */
|
|
400
400
|
/* TODO: review selectors and scope them under .${e} (and port any LESS/SCSS). */
|
|
401
401
|
|
|
402
402
|
${t.trim()}
|
|
403
|
-
`}function
|
|
404
|
-
`),a.info(j("Model updated",`blocks/${
|
|
405
|
-
// --- ${
|
|
403
|
+
`}function cs(e,t=0){let n=[];for(let o of e){let i=" ".repeat(t);if(o.component==="tab")n.push(`${i}${I.blue("\u25B8")} ${o.label??o.name}`);else{let r=o.options?.length?` (${o.options.length} options)`:"",s=o.multi?" \xB7multi":"",c=o.label?`- ${o.label}`:"";n.push(`${i}${I.accent(o.component)}${s} ${o.name}${r} ${c}`),o.fields?.length&&n.push(...cs(o.fields,t+1))}}return n}async function Tm(e,t={}){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}await a.logoOnceAnimated("Migrate component");let{input:o,confirm:i}=await Promise.resolve().then(()=>(q(),J)),r=!t.yes,s=e;if(!s&&r&&(s=await o({message:"Path to the classic component folder",validate:b=>Bo(b.trim())||"Folder not found"})),!s){a.error("Provide the path to the classic component folder."),process.exitCode=1;return}s=Ee.resolve(s.trim());let c=(t.superRoot??"").split(",").map(b=>b.trim()).filter(Boolean).map(b=>Ee.resolve(b)),l=await Ya(s,c);if(!l){let b=Uo(s);b?(a.error(`No dialog here: this is a proxy of ${b}, and that component isn't under ${c.length?"the given --super-root":"this jcr_root"}.`),a.info(" Pass --super-root <jcr_root that contains it>, e.g. a checkout of adobe/aem-core-wcm-components (content/src/content/jcr_root).")):a.error(`No Touch UI dialog (_cq_dialog/.content.xml) found in ${s}.`),process.exitCode=1;return}if(rt(l.fields)===0){a.warn("Dialog found but no mappable fields were detected."),l.unmapped.length&&a.info(`Unmapped resourceTypes: ${l.unmapped.join(", ")}`),process.exitCode=1;return}let d=await Va(s)??Ee.basename(s),m=t.name&&Ln(t.name)||Ln(r?await o({message:"Block name",default:Ln(d)}):d);l.dialogKind==="classic"&&a.info(` ${I.blue("\u21B3")} Classic UI dialog (dialog.xml) - mapped from its xtypes`),l.inheritedFrom&&a.info(` ${I.blue("\u21B3")} Dialog inherited from ${l.inheritedFrom} (proxy component; overlay changes not applied)`),a.info(j("Mapped fields",`${rt(l.fields)} from dialog`));for(let b of cs(l.fields))a.info(` ${b}`);if(l.unmapped.length&&(a.info(""),a.warn(`Skipped (unrecognised): ${l.unmapped.join(", ")}`)),l.datasourced.length&&a.warn(`Options come from a datasource, migrated as text (add static options if needed): ${l.datasourced.join(", ")}`),a.info(""),r&&!await i({message:`Generate block "${m}"?`,default:!0})){a.info("Cancelled.");return}let p=Ee.join(n,"blocks",m);if(Bo(p)){a.error(`Block "${m}" already exists at blocks/${m}. Use --name to pick another.`),process.exitCode=1;return}let u=t.clientlib?Ee.resolve(t.clientlib.trim()):await _a(s),g=es(m),h="empty - add styles from clientlib / rendered CSS",$=[];if(u&&Bo(u)){let b=await Ua(u);b.css.trim()&&(g=Cm(m,b.css,b.files),h=`from clientlib (${b.files.length} file(s)) - review & scope`),$=b.preprocessed}await Em(p,{recursive:!0}),await Ho(Ee.join(p,`${m}.js`),Za(m,l.fields)),await Ho(Ee.join(p,`${m}.css`),g),await Ho(Ee.join(p,`_${m}.json`),Qa(m,d,l.fields)),a.info(j("Created"));let w=[`${m}.js`,`${m}.css`,`_${m}.json`],y=_(w);if(a.info(P(`${m}.js`,"decorator stub (port HTL logic)",y)),a.info(P(`${m}.css`,h,y)),a.info(P(`_${m}.json`,"Universal Editor model",y)),$.length&&(a.info(""),a.warn(`LESS/SCSS found (needs a build, not copied): ${$.join(", ")}`)),a.info(""),r&&await i({message:"Instrument this block for analytics (dataLayer)?",default:!1})){let{trackBlock:T}=await Promise.resolve().then(()=>(It(),Mt));await T(m,{})}a.info(W([`"${m}" migrated. Next: add CSS, then \`eds block preview ${m}\``]))}var Ln,Wo=v(()=>{"use strict";f();O();Ba();ts();Fn();K();B();Ln=e=>e.trim().toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"")});function re(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):t}var ie,ls=v(()=>{"use strict";f();ie={text:(e,t)=>({component:"text",valueType:"string",name:e,label:t}),textarea:(e,t)=>({component:"textarea",valueType:"string",name:e,label:t}),richtext:(e,t)=>({component:"richtext",valueType:"string",name:e,value:"",label:t}),number:(e,t)=>({component:"number",valueType:"number",name:e,label:t}),boolean:(e,t,n=!1)=>({component:"boolean",valueType:"boolean",name:e,value:n,label:t}),dateTime:(e,t)=>({component:"date-time",valueType:"date",name:e,label:t}),select:(e,t,n,o)=>({component:"select",valueType:"string",name:e,label:t,options:n,...o!==void 0?{value:o}:{}}),multiselect:(e,t,n)=>({component:"multiselect",valueType:"string",name:e,label:t,options:n}),radioGroup:(e,t,n,o)=>({component:"radio-group",valueType:"string",name:e,label:t,options:n,...o!==void 0?{value:o}:{}}),checkboxGroup:(e,t,n)=>({component:"checkbox-group",valueType:"string[]",name:e,label:t,options:n}),reference:(e,t)=>({component:"reference",valueType:"string",name:e,label:t}),aemContent:(e,t)=>({component:"aem-content",name:e,label:t}),aemContentFragment:(e,t)=>({component:"aem-content-fragment",name:e,label:t}),aemExperienceFragment:(e,t)=>({component:"aem-experience-fragment",name:e,label:t}),aemTag:(e,t)=>({component:"aem-tag",valueType:"string",name:e,label:t}),tab:(e,t)=>({component:"tab",name:e,label:t}),container:(e,t,n,o=!0)=>({component:"container",name:e,label:t,multi:!0,collapsible:o,fields:n})}});function Ko(e){return st.find(t=>t.id===e)}var Am,Rm,Dm,Fm,ds,ms,zo,ps,Jo,qo,Lm,Om,Nm,Mm,Im,st,Vo=v(()=>{"use strict";f();ls();Am=[{name:"H1",value:"h1"},{name:"H2",value:"h2"},{name:"H3",value:"h3"},{name:"H4",value:"h4"},{name:"H5",value:"h5"},{name:"H6",value:"h6"}],Rm=[{name:"Same tab",value:"_self"},{name:"New tab",value:"_blank"}],Dm=[{name:"Default",value:""},{name:"Primary",value:"primary"},{name:"Secondary",value:"secondary"}],Fm=[{name:"Highlight",value:"highlight"},{name:"Dark",value:"dark"},{name:"Centered",value:"centered"},{name:"Full width",value:"full-width"}],ds=(e="")=>[ie.text(re(e,"title"),"Title"),ie.select(re(e,"titleType"),"Heading level",Am,"h2")],ms=(e="")=>[ie.text(re(e,"eyebrow"),"Eyebrow")],zo=(e="")=>[ie.reference(re(e,"image"),"Image"),ie.text(re(e,"imageAlt"),"Alt text")],ps=(e="")=>[ie.richtext(re(e,"text"),"Text")],Jo=(e="")=>[ie.text(re(e,"linkText"),"Link text"),ie.aemContent(re(e,"link"),"Link"),ie.select(re(e,"linkTarget"),"Open in",Rm,"_self")],qo=(e="")=>[...Jo(e),ie.select(re(e,"ctaStyle"),"Style",Dm,"")],Lm=(e="")=>[ie.container(re(e,"ctas")||"ctas","Buttons",qo())],Om=(e="")=>[ie.multiselect(re(e,"classes"),"Styles",Fm)],Nm=(e="")=>[ie.aemContent(re(e,"url"),"URL (video / embed)")],Mm=(e="")=>[...zo(e),...ms(e),...ds(e),...ps(e),...qo(e)],Im=(e="")=>[...zo(e),ie.text(re(e,"title"),"Title"),ie.richtext(re(e,"description"),"Description"),...Jo(e)],st=[{id:"heading",label:"Heading (title + level)",build:ds},{id:"eyebrow",label:"Eyebrow (kicker line)",build:ms},{id:"image",label:"Image (reference + alt)",build:zo},{id:"richtext",label:"Rich text body",build:ps},{id:"link",label:"Link (text + url + target)",build:Jo},{id:"cta",label:"CTA (link + style)",build:qo},{id:"cta-group",label:"CTA group (repeatable buttons)",build:Lm},{id:"classes",label:"Section styles (CSS modifiers)",build:Om},{id:"embed",label:"Embed / video (URL)",build:Nm},{id:"teaser",label:"Teaser (image + eyebrow + title + text + CTA)",build:Mm},{id:"card",label:"Card (image + title + description + link)",build:Im}]});var Qo={};U(Qo,{modelAdd:()=>Bm});import{existsSync as Xo}from"fs";import{readFile as _m,writeFile as Um}from"fs/promises";import Yo from"path";async function Bm(e,t,n={}){let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Model - add partials"));let{select:i,checkbox:r}=await Promise.resolve().then(()=>(q(),J)),s=!n.yes,c=e;if(!c&&s){let{readdir:b}=await import("fs/promises"),T=Yo.join(o,"blocks"),F=Xo(T)?(await b(T,{withFileTypes:!0})).filter(N=>N.isDirectory()&&Xo(Yo.join(T,N.name,`_${N.name}.json`))).map(N=>N.name):[];if(F.length===0){a.error("No block with a _<name>.json model found. Create one with `eds block create`."),process.exitCode=1;return}c=await i({message:"Which block's model?",choices:F.map(N=>({name:N,value:N}))})}if(!c){a.error("Provide a block name."),process.exitCode=1;return}let l=Yo.join(o,"blocks",c,`_${c}.json`);if(!Xo(l)){a.error(`No model at blocks/${c}/_${c}.json. Create the block first.`),process.exitCode=1;return}let d=t;d.length===0&&s&&(d=await r({message:"Which partials to add?",choices:st.map(b=>({name:b.label,value:b.id}))}));let m=d.map(b=>Ko(b.trim())).filter(b=>!!b),p=d.filter(b=>!Ko(b.trim()));if(p.length&&a.warn(`Unknown partial(s): ${p.join(", ")}. Available: ${st.map(b=>b.id).join(", ")}`),m.length===0){a.info("Nothing to add.");return}let u;try{u=JSON.parse(await _m(l,"utf-8"))}catch{a.error(`Could not parse ${l}.`),process.exitCode=1;return}let g=Array.isArray(u.models)?u.models:[],h=g.find(b=>b.id===c)??g[0];if(!h){a.error("Model has no `models[]` entry to add fields to."),process.exitCode=1;return}h.fields=Array.isArray(h.fields)?h.fields:[];let $=new Set(h.fields.map(b=>b.name)),w=[],y=[];for(let b of m)for(let T of b.build()){if($.has(T.name)){y.push(T.name);continue}$.add(T.name),h.fields.push(T),w.push(T.name)}await Um(l,`${JSON.stringify(u,null,2)}
|
|
404
|
+
`),a.info(j("Model updated",`blocks/${c}/_${c}.json`)),a.info(P("partials",m.map(b=>b.id).join(", "))),a.info(P("fields added",w.length?w.join(", "):"(none)")),y.length&&a.info(R("warn","skipped (exists)",y.join(", "))),a.info(""),a.info(W([`${w.length} field(s) added to "${c}"`]))}var Zo=v(()=>{"use strict";f();O();Vo();K();B()});function fs(e){return On.find(t=>t.id.toLowerCase()===e.toLowerCase())}function gs(e,t){if(e.includes(us))return{js:e,changed:!1,reason:"already has JSON-LD"};let n=e.match(/export default (?:async )?function decorate\s*\(\s*([A-Za-z_$][\w$]*)?[^)]*\)\s*\{/);if(!n||n.index===void 0)return{js:e,changed:!1,reason:"no `export default function decorate(...)` found"};let o=n[1]||"block",i=n.index+n[0].length,r=`
|
|
405
|
+
// --- ${us}: ${t.id}) ---
|
|
406
406
|
{
|
|
407
407
|
const root = ${o};
|
|
408
408
|
const ld = ${t.object};
|
|
@@ -411,7 +411,7 @@ ${t.trim()}
|
|
|
411
411
|
ldScript.textContent = JSON.stringify(ld);
|
|
412
412
|
document.head.append(ldScript);
|
|
413
413
|
}
|
|
414
|
-
`;return{js:`${e.slice(0,i)}${r}${e.slice(i)}`,changed:!0}}var
|
|
414
|
+
`;return{js:`${e.slice(0,i)}${r}${e.slice(i)}`,changed:!0}}var us,On,hs=v(()=>{"use strict";f();us="json-ld (eds schema",On=[{id:"Article",label:"Article / BlogPosting",object:`{
|
|
415
415
|
'@context': 'https://schema.org',
|
|
416
416
|
'@type': 'Article',
|
|
417
417
|
headline: root.querySelector('h1, h2, h3')?.textContent?.trim() || document.title,
|
|
@@ -490,16 +490,16 @@ ${t.trim()}
|
|
|
490
490
|
position: i + 1,
|
|
491
491
|
text: li.textContent?.trim(),
|
|
492
492
|
})),
|
|
493
|
-
}`}]});var
|
|
494
|
-
`}async function
|
|
493
|
+
}`}]});var ei={};U(ei,{schemaBlock:()=>qm});import{existsSync as Hm}from"fs";import{readFile as Gm,writeFile as Wm}from"fs/promises";import zm from"path";import Jm from"chalk";async function qm(e,t={}){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Schema - JSON-LD"));let o=zm.join(n,"blocks",e,`${e}.js`);if(!Hm(o)){a.error(`Block "${e}" not found (no blocks/${e}/${e}.js).`),process.exitCode=1;return}let i=t.type;if(!i&&!t.yes){let{select:c}=await Promise.resolve().then(()=>(q(),J));i=await c({message:"Which schema.org type?",choices:On.map(l=>({name:`${l.id} - ${l.label}`,value:l.id}))})}let r=i?fs(i):void 0;if(!r){a.error(`Unknown schema type "${i}". Options: ${On.map(c=>c.id).join(", ")}`),process.exitCode=1;return}let s=gs(await Gm(o,"utf-8"),r);if(!s.changed){a.warn(`Not added: ${s.reason}.`);return}await Wm(o,s.js),a.info(j("JSON-LD added")),a.info(P(`blocks/${e}/${e}.js`,`${r.id} (${r.label})`)),a.info(""),a.info(Jm.dim(" Review the generated object - some fields are heuristic or TODO. Validate at search.google.com/test/rich-results."))}var ti=v(()=>{"use strict";f();O();K();hs();B()});function Vm(e,t){for(let n of e.match(/<meta\b[^>]*>/gi)??[])if(n.match(/\bname=["']([^"']+)["']/i)?.[1]===t)return n.match(/\bcontent=["']([^"']*)["']/i)?.[1]??"";return null}function ws(e){return Vm(e,Km)!==null}function bs(e){return Array.isArray(e)?e.map(t=>t&&typeof t=="object"?t.id:void 0).filter(t=>typeof t=="string"):[]}function ys(e){let t=!!e.configPresent["component-definition.json"]&&!!e.configPresent["component-models.json"],n=new Set(e.modelIds),o=e.blocks.map(i=>{let r=i.hasModelFile||n.has(i.name);return{name:i.name,editable:r,reason:r?void 0:"no UE model (_<name>.json or component-models entry)"}});return{isUeProject:t,blocks:o}}var ni,Km,vs=v(()=>{"use strict";f();ni=["component-definition.json","component-models.json","component-filters.json"],Km="urn:adobe:aue:system:aemconnection"});var Bt={};U(Bt,{ueCheck:()=>tp,ueOpen:()=>np});import{existsSync as Ut}from"fs";import{readFile as ks,readdir as Xm}from"fs/promises";import _t from"path";import Nn from"chalk";async function Ym(e){if(!Ut(e))return null;try{return JSON.parse(await ks(e,"utf-8"))}catch{return null}}async function Qm(e){let t=_t.join(e,"blocks");return Ut(t)?(await Xm(t,{withFileTypes:!0})).filter(o=>o.isDirectory()).map(o=>({name:o.name,hasModelFile:Ut(_t.join(t,o.name,`_${o.name}.json`))})):[]}async function Zm(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{let{execa:n}=await import("execa");await n(t,[e],{stdio:"ignore"})}catch{}}async function ep(e){try{let{execa:t}=await import("execa");return(await t("git",["remote","get-url","origin"],{cwd:e})).stdout.trim()||null}catch{return null}}async function tp(){let e=E();if(!e){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Universal Editor - readiness"));let t={};for(let p of ni)t[p]=Ut(_t.join(e,p));let n=await Ym(_t.join(e,"component-models.json")),o=await Qm(e),{isUeProject:i,blocks:r}=ys({configPresent:t,blocks:o,modelIds:bs(n)});a.info(j("Universal Editor config"));let s=[...ni],c=_(s);for(let p of s)a.info(R(t[p]?"pass":"fail",p,void 0,c));if(!i){a.info(""),a.warn("This doesn't look like a Universal Editor (crosswalk) project - run `eds scaffold ue` first."),process.exitCode=1;return}let l=_t.join(e,"head.html");if(Ut(l)){let p=ws(await ks(l,"utf-8"));a.info(R(p?"pass":"info","head.html",p?"aemconnection present":"no aemconnection (fine for cloud author)"))}if(a.info(j("Blocks",`${r.length} found`)),r.length===0)a.info(Nn.dim(" No blocks yet."));else{let p=_(r.map(u=>u.name));for(let u of r)a.info(R(u.editable?"pass":"warn",u.name,u.reason,p))}let d=r.filter(p=>p.editable).length,m=r.length-d;a.info(""),a.info($e({pass:d,warn:m})),a.info(Nn.dim(" Open a page in the editor with `eds ue open <path>`."))}async function np(e,t={}){let n=E()??process.cwd(),o=e??t.path??"/",i=t.url;if(!i){let s=await ep(n),c=s?et(s):null;if(!c){a.error("Couldn't determine the preview host from git."),a.info(Nn.dim(" Pass it explicitly: `eds ue open <path> --url main--<repo>--<owner>.aem.page`")),process.exitCode=1;return}i=tt(c.owner,c.repo,t.ref??"main")}let r=Gr({host:i,path:o,org:t.org});a.info(j("Universal Editor")),a.info(P("page",`${i}${o.startsWith("/")?"":"/"}${o}`)),a.info(P("open",r)),t.open!==!1?await Zm(r):a.info(Nn.dim(" (use without --no-open to launch the browser)"))}var Ht=v(()=>{"use strict";f();O();K();vs();$n();B()});var ii={};U(ii,{createBlock:()=>ap,ueModelFor:()=>$s});import{existsSync as op}from"fs";import{mkdir as ip,writeFile as oi}from"fs/promises";import Gt from"path";import xs from"chalk";function rp(e){return e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}function $s(e){let t=rp(e);return`${JSON.stringify({definitions:[{title:t,id:e,plugins:{xwalk:{page:{resourceType:"core/franklin/components/block/v1/block",template:{name:t,model:e}}}}}],models:[{id:e,fields:[{component:"text",name:"title",label:"Title",valueType:"string"},{component:"select",name:"titleType",label:"Title Type",valueType:"string",value:"h2",options:[{name:"H1",value:"h1"},{name:"H2",value:"h2"},{name:"H3",value:"h3"},{name:"H4",value:"h4"}]},{component:"richtext",name:"text",value:"",label:"Text",valueType:"string"}]}],filters:[]},null,2)}
|
|
494
|
+
`}async function ap(e,t={}){if(!_e.test(e)){a.error(`Invalid block name "${e}". Use kebab-case (e.g., "hero-banner", "card-list").`),process.exitCode=1;return}let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found). Run this from your project root."),process.exitCode=1;return}let o=Gt.join(n,"blocks",e);if(op(o)){a.error(`Block "${e}" already exists at ${o}`),process.exitCode=1;return}await ip(o,{recursive:!0});let i=`export default function decorate(block) {
|
|
495
495
|
// TODO: implement ${e} block
|
|
496
496
|
}
|
|
497
497
|
`,r=`.${e} {
|
|
498
498
|
/* TODO: style ${e} block */
|
|
499
499
|
}
|
|
500
|
-
`;await
|
|
500
|
+
`;await oi(Gt.join(o,`${e}.js`),i),await oi(Gt.join(o,`${e}.css`),r);let s=t.ueModel!==!1;s&&await oi(Gt.join(o,`_${e}.json`),$s(e)),a.success(`Block "${e}" created at ${xs.cyan(Gt.relative(n,o))}${s?xs.dim(" (+ Universal Editor model)"):""}`)}var ri=v(()=>{"use strict";f();O();K();Ze()});import{existsSync as sp}from"fs";import{readFile as cp}from"fs/promises";import{homedir as lp}from"os";import ai from"path";async function Ss(e){try{let t=await cp(e,"utf-8");return JSON.parse(t)}catch{return}}async function se(e){let t=await Ss(si),n=e?await Ss(ai.join(e,dp)):void 0,o={...typeof t=="object"&&t!==null?t:{},...typeof n=="object"&&n!==null?n:{}},i=fo.safeParse(o);return i.success?i.data:(a.debug("Config validation issues:",i.error.flatten()),fo.parse({}))}function Ps(){return js}function ci(){return si}function li(){return sp(si)}var js,si,dp,ue=v(()=>{"use strict";f();O();Ze();js=ai.join(lp(),".eds"),si=ai.join(js,"config.json"),dp=".edsrc.json"});import{existsSync as mp}from"fs";import{mkdir as pp,readFile as up,readdir as fp,writeFile as gp}from"fs/promises";import qe from"path";function be(e){return Mn.includes(e)}async function Cs(e,t=Wt[e],n=1500){let o=e==="ollama"?`${di(t)}/api/tags`:`${di(t)}/models`;try{let i=await fetch(o,{signal:AbortSignal.timeout(n)});if(!i.ok)return null;let r=await i.json();return(e==="ollama"?(r.models??[]).map(c=>c.name??c.model??""):(r.data??[]).map(c=>c.id??"")).filter(Boolean)}catch{return null}}function Ts(e){let t=[/coder/i,/codestral|devstral/i,/code/i,/qwen/i,/deepseek/i,/llama/i];for(let n of t){let o=e.find(i=>n.test(i));if(o)return o}return e[0]}function As(e){return Math.ceil(e.length/3.5)}async function*hp(e){let t=e.getReader(),n=new TextDecoder,o="";for(;;){let{value:i,done:r}=await t.read();if(r)break;o+=n.decode(i,{stream:!0});let s=o.indexOf(`
|
|
501
501
|
`);for(;s>=0;)yield o.slice(0,s),o=o.slice(s+1),s=o.indexOf(`
|
|
502
|
-
`)}o.trim()&&(yield o)}async function
|
|
502
|
+
`)}o.trim()&&(yield o)}async function Rs(e){let t=di(e.baseUrl),n={"content-type":"application/json"};e.apiKey&&(n.authorization=`Bearer ${e.apiKey}`);let o,i;if(e.type==="ollama")o=`${t}/api/chat`,i={model:e.model,stream:!0,messages:[{role:"user",content:e.prompt,...e.images?.length?{images:e.images.map(l=>l.data.toString("base64"))}:{}}],options:{num_ctx:e.contextTokens??mi,temperature:.2}};else{o=`${t}/chat/completions`;let l=e.images?.length?[{type:"text",text:e.prompt},...e.images.map(d=>({type:"image_url",image_url:{url:`data:${d.mime};base64,${d.data.toString("base64")}`}}))]:e.prompt;i={model:e.model,stream:!0,temperature:.2,messages:[{role:"user",content:l}]}}let r=await fetch(o,{method:"POST",headers:n,body:JSON.stringify(i),signal:e.signal});if(!r.ok||!r.body){let l=await r.text().catch(()=>"");throw new Error(`${Ce[e.type]} ${r.status} ${r.statusText}${l?` \u2014 ${l.slice(0,200)}`:""}`)}let s="",c={text:""};for await(let l of hp(r.body)){let d=l.trim();if(d)if(e.type==="ollama"){let m=JSON.parse(d);if(m.error)throw new Error(`Ollama: ${m.error}`);let p=m.message?.content??"";p&&(s+=p,e.onToken?.(p)),m.done&&(c.promptTokens=m.prompt_eval_count,c.outputTokens=m.eval_count)}else{if(!d.startsWith("data:"))continue;let m=d.slice(5).trim();if(m==="[DONE]")break;let p=JSON.parse(m);if(p.error)throw new Error(`${Ce[e.type]}: ${p.error.message}`);let u=p.choices?.[0]?.delta?.content??"";u&&(s+=u,e.onToken?.(u)),p.usage&&(c.promptTokens=p.usage.prompt_tokens,c.outputTokens=p.usage.completion_tokens)}}return c.text=s,c}function Ds(e){let t=`blocks/${e}`;return`
|
|
503
503
|
|
|
504
504
|
## Output format for this run (local model, no tools) \u2014 this overrides the instructions above
|
|
505
505
|
You cannot read files, run commands, call MCP or use editing tools: everything you need is in this message. Ignore any instruction above to read a file, fetch the design or call a tool.
|
|
@@ -509,32 +509,38 @@ Reply with **every file you create, complete**, each wrapped exactly like this (
|
|
|
509
509
|
...the whole file...
|
|
510
510
|
=== END FILE ===
|
|
511
511
|
|
|
512
|
-
Write \`${t}/${e}.js\`, \`${t}/${e}.css\`, the Universal Editor model \`${t}/_${e}.json\` (unless told to skip it), the preview mock \`${t}/_${e}.preview.html\` and \`${t}/.eds-meta.json\`. Only paths under \`${t}/\` are saved. After the files, at most 3 lines of summary.`}function
|
|
513
|
-
`)}),o={path:s[1].replace(/^`|`$/g,""),body:[]};continue}if(o&&
|
|
512
|
+
Write \`${t}/${e}.js\`, \`${t}/${e}.css\`, the Universal Editor model \`${t}/_${e}.json\` (unless told to skip it), the preview mock \`${t}/_${e}.preview.html\` and \`${t}/.eds-meta.json\`. Only paths under \`${t}/\` are saved. After the files, at most 3 lines of summary.`}function Fs(e){let t=[],n=e.split(/\r?\n/),o=null;for(let r of n){let s=r.match(wp);if(s&&!Es.test(r)){o&&t.push({path:o.path,content:o.body.join(`
|
|
513
|
+
`)}),o={path:s[1].replace(/^`|`$/g,""),body:[]};continue}if(o&&Es.test(r)){t.push({path:o.path,content:o.body.join(`
|
|
514
514
|
`)}),o=null;continue}o&&o.body.push(r)}if(o&&t.push({path:o.path,content:o.body.join(`
|
|
515
|
-
`)}),t.length)return t.map(
|
|
515
|
+
`)}),t.length)return t.map(bp);let i=/(?:^|\n)(?:[#*`\s]*([\w./-]+\.(?:js|css|json|html))[`*:\s]*\n)?```[\w-]*[ \t]*([\w./-]+\.(?:js|css|json|html))?[^\n]*\n([\s\S]*?)\n```/g;for(let r of e.matchAll(i)){let s=r[2]??r[1];s&&t.push({path:s,content:r[3]})}return t}function bp(e){let t=e.content.match(/^\s*```[\w-]*\n([\s\S]*?)\n```\s*$/);return t?{...e,content:t[1]}:e}async function Ls(e,t,n){let o=qe.join(e,"blocks",t),i={written:[],rejected:[]};for(let r of n){let s=r.path.trim().replace(/^\.?\//,""),c=s.includes("/")?qe.resolve(e,s):qe.join(o,s);if(qe.dirname(c)!==o){i.rejected.push(r.path);continue}await pp(o,{recursive:!0}),await gp(c,r.content.endsWith(`
|
|
516
516
|
`)?r.content:`${r.content}
|
|
517
|
-
`),i.written.push(
|
|
517
|
+
`),i.written.push(qe.relative(e,c))}return i}async function Os(e,t){let n=qe.join(e,"blocks",t);if(!mp(n))return"";let o=[];for(let i of(await fp(n)).sort()){if(!/\.(js|css|json|html)$/.test(i))continue;let r=await up(qe.join(n,i),"utf-8");o.push(`=== FILE: blocks/${t}/${i} ===
|
|
518
518
|
${r.trimEnd()}
|
|
519
519
|
=== END FILE ===`)}return o.join(`
|
|
520
520
|
|
|
521
|
-
`)}var
|
|
522
|
-
`)[0].slice(0,300);return a.error(`Agent ${e.type} failed: ${
|
|
521
|
+
`)}var Mn,Wt,Ce,mi,di,wp,Es,zt=v(()=>{"use strict";f();Mn=["ollama","omlx","local"],Wt={ollama:"http://127.0.0.1:11434",omlx:"http://127.0.0.1:8000/v1",local:"http://127.0.0.1:8080/v1"},Ce={ollama:"Ollama",omlx:"oMLX",local:"local OpenAI-compatible server"},mi=32768;di=e=>e.replace(/\/+$/,"");wp=/^=+\s*FILE:\s*(.+?)\s*=+\s*$/,Es=/^=+\s*END FILE\s*=+\s*$/});import{existsSync as In}from"fs";import{readFile as yp}from"fs/promises";import{homedir as ct}from"os";import lt from"path";async function ui(e){let{execaCommand:t}=await import("execa");try{return(await t(`which ${e}`)).stdout.trim()||void 0}catch{return}}function Ns(e){if(!e||typeof e!="object")return;let t=e,n=t.mcpServers;if(n&&typeof n=="object"){for(let o of Object.keys(n))if(o.toLowerCase().includes("figma"))return o}for(let o of Object.values(t)){let i=Ns(o);if(i)return i}}async function fi(e){for(let t of e)try{if(!In(t))continue;let n=await yp(t,"utf-8");try{let o=Ns(JSON.parse(n));if(o)return o}catch{}if(n.toLowerCase().includes("figma"))return"figma"}catch{}}async function gi(e){let t=E()??void 0,n=(await se(t)).local,o=n?.baseUrl??Wt[e],i=await Cs(e,o);if(!i)return;let r=n?.model??Ts(i);if(!r){a.warn(`${Ce[e]} at ${o} has no models - pull one first (e.g. \`ollama pull qwen2.5-coder:14b\`).`);return}return{type:e,path:o,baseUrl:o,model:r,hasFigmaMcp:!1}}async function _n(e){if(e&&be(e)){let t=await gi(e);if(t)return t;a.warn(`${Ce[e]} isn't reachable - is it running?`);return}if(e){let t=pi.find(n=>n.type===e);if(t){let n=await ui(t.binary);if(n){let o=await fi(t.mcpConfigPaths);return{type:t.type,path:n,configDir:In(t.configDir)?t.configDir:void 0,hasFigmaMcp:!!o,figmaMcpServerName:o}}a.warn(`Preferred agent "${e}" not found in PATH`)}}for(let t of pi){let n=await ui(t.binary);if(n){let o=await fi(t.mcpConfigPaths);return{type:t.type,path:n,configDir:In(t.configDir)?t.configDir:void 0,hasFigmaMcp:!!o,figmaMcpServerName:o}}}for(let t of Mn.filter(n=>n!=="local")){let n=await gi(t);if(n)return n}}async function Un(){let e=[];for(let t of pi){let n=await ui(t.binary);if(n){let o=await fi(t.mcpConfigPaths);e.push({type:t.type,path:n,configDir:In(t.configDir)?t.configDir:void 0,hasFigmaMcp:!!o,figmaMcpServerName:o})}}for(let t of Mn.filter(n=>n!=="local")){let n=await gi(t);n&&e.push(n)}return e}var pi,Bn=v(()=>{"use strict";f();ue();O();K();zt();pi=[{type:"claude",binary:"claude",configDir:lt.join(ct(),".claude"),mcpConfigPaths:[lt.join(ct(),".claude","plugins.json"),lt.join(ct(),".claude.json")]},{type:"cursor",binary:"cursor",configDir:lt.join(ct(),".cursor"),mcpConfigPaths:[lt.join(ct(),".cursor","mcp.json")]},{type:"codex",binary:"codex",configDir:lt.join(ct(),".codex"),mcpConfigPaths:[]}]});import{mkdir as _s,readFile as hi,writeFile as Us}from"fs/promises";import{tmpdir as vp}from"os";import fe from"path";import kp from"readline";import Z from"chalk";async function Jt(e,t){let n=t?fe.join(t,"tmp"):vp(),o=fe.join(n,"eds-cli");await _s(o,{recursive:!0});let i=`from-design-${Date.now()}.md`,r=fe.join(o,i);return await Us(r,e,"utf-8"),r}function Ms(e,t){return Buffer.byteLength(e,"utf-8")<=xp?e:`Your full task is in the file ${t}. Read that whole file first and follow its instructions exactly - it replaces this message.`}async function dt(e,t,n,o,i){let{execa:r}=await import("execa"),s=await hi(t,"utf-8");try{if(be(e.type))return await $p(e,s,n,o,i);switch(e.type){case"claude":{a.info(`Running Claude Code ${Z.dim("- live log:")}`);let c=[...e.figmaMcpServerName?[e.figmaMcpServerName]:[],"figma-sse","figma-desktop","figma","Figma","plugin_figma_figma"],l=[...new Set(c.map(p=>`mcp__${p}`)),"Edit","Write","Read"].join(","),m=r("claude",["-p","--model",o??"haiku","--output-format","stream-json","--verbose","--allowedTools",l],{cwd:n,buffer:!1,input:s,stdio:["pipe","pipe","inherit"]});await jp(m,n);break}case"cursor":{a.info("Running Cursor agent..."),await r("cursor",["--prompt",Ms(s,t)],{cwd:n,stdio:"inherit"});break}case"codex":{a.info("Running Codex..."),await r("codex",[Ms(s,t)],{cwd:n,stdio:"inherit"});break}}return!0}catch(c){let l=(c instanceof Error?c.message:String(c)).split(`
|
|
522
|
+
`)[0].slice(0,300);return a.error(`Agent ${e.type} failed: ${l}`),!1}}async function $p(e,t,n,o,i){let r=e.type,s=i?.blockName;if(!s)throw new Error("A local model needs the block name to save its files.");let c=o??e.model;if(!c)throw new Error(`No model chosen for ${Ce[r]} - set local.model in config.`);let l=t,d=[];if(i?.designFile){let D=fe.resolve(n,i.designFile),ke=fe.extname(D).toLowerCase();ke===".svg"?l+=`
|
|
523
523
|
|
|
524
524
|
## The design (${i.designFile})
|
|
525
525
|
\`\`\`svg
|
|
526
|
-
${await
|
|
527
|
-
\`\`\``:
|
|
526
|
+
${await hi(D,"utf-8")}
|
|
527
|
+
\`\`\``:Is[ke]&&(d.push({data:await hi(D),mime:Is[ke]}),l+=`
|
|
528
528
|
|
|
529
529
|
## The design
|
|
530
|
-
The design (${i.designFile}) is attached as an image. A model without vision can't see it - use a vision model (e.g. qwen2.5vl, llama3.2-vision).`)}i?.refine&&(
|
|
530
|
+
The design (${i.designFile}) is attached as an image. A model without vision can't see it - use a vision model (e.g. qwen2.5vl, llama3.2-vision).`)}i?.refine&&(l+=`
|
|
531
531
|
|
|
532
532
|
## The block as it is now
|
|
533
533
|
Change these files; reply with every file you change, complete.
|
|
534
534
|
|
|
535
|
-
${await
|
|
536
|
-
`)[0].slice(0,100);y&&d(Z.dim(y))}else if(w.type==="tool_use"&&"name"in w){let y="id"in w&&w.id?w.id:`${Math.random()}`;
|
|
537
|
-
`)[0].slice(0,70):"";return Z.dim(`$ ${i}`)}default:return`${M.blue("\u2192")} ${e}`}}var Wm,gs,bs=k(()=>{"use strict";f();D();B();Sn();Wm=96*1024;gs={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp"}});function ys(e){return e<=480?`${e} mobile`:e<=1024?`${e} tablet`:`${e} desktop`}function Xm(e,t="figma"){return e?e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0).map(n=>({width:n,label:ys(n),source:t})):[]}function vs(e,t){let n=Xm(e,"figma");return n.length?n:Vm(t)}function Vm(e){if(!Array.isArray(e))return[];let t=new Set,n=[];for(let o of e){let i=Number(o?.width);if(!Number.isFinite(i)||i<=0||t.has(i))continue;t.add(i);let r=o.source,s=r==="figma"||r==="scrape"?r:"default";n.push({width:i,label:ys(i),source:s})}return n}var ks=k(()=>{"use strict";f()});import{existsSync as Ym}from"fs";import{createRequire as Qm}from"module";import Zm from"path";import{pathToFileURL as xs}from"url";async function $s(e){try{return(await import("playwright")).chromium}catch{}let t=[e,process.cwd()].filter(n=>!!n);if(t.length)try{let o=Qm(xs(Zm.join(t[0],"package.json")).href).resolve("playwright",{paths:t});return(await import(xs(o).href)).chromium}catch{}throw new Error("Scraping needs Playwright. Install it in your project (`npm i -D playwright`) or globally (`npm i -g playwright`), then `npx playwright install chromium`.")}async function Ss(e){let t=e.width??1440,n=await $s(e.projectRoot),o;try{o=await n.launch({headless:!0})}catch(i){let r=i instanceof Error?i.message:String(i);throw/Executable doesn't exist|install/i.test(r)?new Error("Chromium isn't installed for Playwright. Run `npx playwright install chromium`."):i}try{let i=e.storageStatePath&&Ym(e.storageStatePath),s=await(await o.newContext({viewport:{width:t,height:900},deviceScaleFactor:1,...i?{storageState:e.storageStatePath}:{}})).newPage();await s.goto(e.url,{waitUntil:"networkidle",timeout:45e3}),await s.waitForTimeout(700);let l=await s.evaluate(ep,{maxNodes:320,maxDepth:14,textCap:200}),c={source:`scrape:${e.provider}`,url:e.url,viewport:t,authenticated:!!i,title:l.title,root:l.root,nodeCount:l.nodeCount,truncated:l.truncated};return JSON.stringify(c,null,2)}finally{await o.close()}}async function js(e){let n=await(await $s(e.projectRoot)).launch({headless:!1});try{let o=await n.newContext();await(await o.newPage()).goto(e.loginUrl,{waitUntil:"domcontentloaded",timeout:6e4}),await e.waitForUser(),await o.storageState({path:e.statePath})}finally{await n.close()}}function ep(e){let t=new Set(["SCRIPT","STYLE","NOSCRIPT","LINK","META","HEAD","BR","TEMPLATE"]),n=0,o=!1,i=d=>!d||d==="none"||d==="normal"||d==="auto"||d==="0px"||d==="rgba(0, 0, 0, 0)"||d==="transparent";function r(d){let m="";for(let p of Array.from(d.childNodes))p.nodeType===3&&(m+=p.textContent??"");return m=m.replace(/\s+/g," ").trim(),m.length>e.textCap?`${m.slice(0,e.textCap)}\u2026`:m}function s(d){let m=getComputedStyle(d),p={},u=(h,v)=>{i(v)||(p[h]=v)};u("display",m.display),(m.display.includes("flex")||m.display.includes("grid"))&&(u("flexDirection",m.flexDirection),u("justifyContent",m.justifyContent),u("alignItems",m.alignItems),u("gap",m.gap)),u("padding",m.padding),u("margin",m.margin),u("color",m.color),u("background",m.backgroundColor),m.backgroundImage&&m.backgroundImage!=="none"&&(p.backgroundImage=m.backgroundImage.slice(0,160)),u("fontFamily",m.fontFamily),u("fontSize",m.fontSize),u("fontWeight",m.fontWeight),u("lineHeight",m.lineHeight),u("letterSpacing",m.letterSpacing),u("textAlign",m.textAlign);let g=h=>h&&!h.startsWith("0px")&&!h.includes(" none")?h:"";if(m.border)g(m.border)&&(p.border=m.border);else for(let h of["borderTop","borderRight","borderBottom","borderLeft"])g(m[h])&&(p[h]=m[h]);return u("borderRadius",m.borderRadius),u("boxShadow",m.boxShadow),m.opacity&&m.opacity!=="1"&&(p.opacity=m.opacity),m.position&&m.position!=="static"&&(p.position=m.position),p}function l(d,m,p=""){if(n>=e.maxNodes)return o=!0,null;if(t.has(d.tagName))return null;let u=d.getBoundingClientRect(),g=getComputedStyle(d);if(g.display==="none"||g.visibility==="hidden"||g.opacity==="0"||u.width<1||u.height<1)return null;n++;let v={tag:d.tagName.toLowerCase(),rect:{x:Math.round(u.x),y:Math.round(u.y),w:Math.round(u.width),h:Math.round(u.height)}},w=(d.getAttribute("class")||"").trim().split(/\s+/).filter(Boolean).slice(0,3);w.length&&(v.class=w.join(" "));let y=s(d);!y.background&&p&&u.width>=window.innerWidth*.9&&(y.inheritedBackground=p),Object.keys(y).length&&(v.style=y);let b=y.background??p;if(d.tagName==="IMG"){let O=d;v.img={src:(O.currentSrc||O.src||"").slice(0,200),alt:O.alt||"",w:O.naturalWidth,h:O.naturalHeight}}let T=r(d);if(T&&(v.text=T),m<e.maxDepth){let O=[];for(let H of Array.from(d.children)){let ae=l(H,m+1,b);ae&&O.push(ae)}O.length&&(v.children=O)}return v}let c=l(document.body,0);return{title:document.title,root:c,nodeCount:n,truncated:o}}var oi=k(()=>{"use strict";f()});import{mkdir as Ps,readFile as tp,rm as Es,stat as np,writeFile as op}from"fs/promises";import Ts from"path";function En(e){return Ts.join(e,"tmp","eds-cli","figma-rest-calls.json")}async function rp(e,t,n){let o=`${e}.lock`;for(await Ps(Ts.dirname(e),{recursive:!0});;)try{await Ps(o);break}catch{await np(o).then(r=>t()-r.mtimeMs,()=>0)>ip?await Es(o,{recursive:!0,force:!0}):await new Promise(r=>setTimeout(r,25))}try{return await n()}finally{await Es(o,{recursive:!0,force:!0})}}async function ap(e){try{let t=JSON.parse(await tp(e,"utf-8"));return Array.isArray(t)?t.filter(n=>typeof n=="number"):[]}catch{return[]}}async function Cn(e){let t=Math.max(1,e.perMinute??ii),n=e.now??Date.now,o=e.sleep??(i=>new Promise(r=>setTimeout(r,i)));for(;;){let i=await rp(e.logPath,n,async()=>{let r=n(),s=(await ap(e.logPath)).filter(l=>r-l<Cs);return s.length<t?(s.push(r),await op(e.logPath,JSON.stringify(s)),0):Math.min(...s)+Cs-r+50});if(i<=0)return;e.onWait?.(i),await o(i)}}var ii,Cs,ip,Tn=k(()=>{"use strict";f();ii=10,Cs=6e4,ip=1e4});function sp(e){let t=Math.max(0,Math.round(e));if(t<60)return`${t} s`;if(t<3600)return`${Math.round(t/60)} min`;if(t<86400){let o=Math.round(t%3600/60);return`${Math.floor(t/3600)} h${o?` ${o} min`:""}`}let n=Math.round(t%86400/3600);return`${Math.floor(t/86400)} d${n?` ${n} h`:""}`}async function si(e,t,n,o=!1){await n?.();let i=await fetch(e,{headers:{"X-Figma-Token":t}});if(i.status!==429)return i;let r=c=>i.headers.get(c)??void 0,s=r("retry-after"),l=s!==void 0&&/^\d+$/.test(s)?Number(s):void 0;if(!o&&l!==void 0&&l<=60)return await cp.sleep(l*1e3),si(e,t,n,!0);throw new Mt(l,r("x-figma-plan-tier"),r("x-figma-rate-limit-type"),r("x-figma-upgrade-link"))}async function Fs(e){let{fileKey:t,nodeId:n,token:o}=e,i=n?`${ri}/files/${t}/nodes?ids=${encodeURIComponent(n)}`:`${ri}/files/${t}`,r=await si(i,o,e.pace);if(!r.ok){let s=await r.text().catch(()=>""),l=r.status===403?" (check the token scope: it needs file_content:read, and access to this file)":r.status===404?" (file or node not found \u2014 check the URL)":"";throw new Error(`Figma REST ${r.status} ${r.statusText}${l}${s?` \u2014 ${s.slice(0,200)}`:""}`)}return r.json()}async function Ls(e){let{fileKey:t,nodeId:n,token:o,scale:i=1}=e;if(!n)throw new Error("A node id is required to render a Figma image.");let r=`${ri}/images/${t}?ids=${encodeURIComponent(n)}&format=png&scale=${i}`,s=await si(r,o,e.pace);if(!s.ok){let m=await s.text().catch(()=>"");throw new Error(`Figma images ${s.status} ${s.statusText}${m?` \u2014 ${m.slice(0,200)}`:""}`)}let l=await s.json();if(l.err)throw new Error(`Figma images: ${l.err}`);let c=l.images?.[n]??Object.values(l.images??{}).find(Boolean);if(!c)throw new Error("Figma returned no image URL for that node.");let d=await fetch(c);if(!d.ok)throw new Error(`Fetching the rendered image failed: ${d.status} ${d.statusText}`);return Buffer.from(await d.arrayBuffer())}function ai(e){if(!e)return;let t=o=>Math.round(Math.max(0,Math.min(1,o))*255).toString(16).padStart(2,"0"),n=`#${t(e.r)}${t(e.g)}${t(e.b)}`;return e.a!==void 0&&e.a<1?`${n}${t(e.a)}`:n}function Rs(e){let t=e?.find(n=>n.visible!==!1);if(t){if(t.type==="SOLID")return ai(t.color);if(t.type?.startsWith("GRADIENT")){let n=(t.gradientStops??[]).map(o=>ai(o.color)).filter(Boolean);return n.length?`gradient(${n.join(" \u2192 ")})`:"gradient"}return t.type==="IMAGE"?"image(placeholder)":t.type?.toLowerCase()}}function Ds(e,t){if(!e||typeof e!="object")return null;let n={name:e.name,type:e.type};if(e.absoluteBoundingBox){let{width:s,height:l}=e.absoluteBoundingBox;s!=null&&l!=null&&(n.size={w:Math.round(s),h:Math.round(l)})}e.layoutMode&&e.layoutMode!=="NONE"&&(n.layout={direction:e.layoutMode==="HORIZONTAL"?"row":"column",gap:e.itemSpacing,padding:[e.paddingTop,e.paddingRight,e.paddingBottom,e.paddingLeft],align:[e.primaryAxisAlignItems,e.counterAxisAlignItems].filter(Boolean).join("/")});let o=Rs(e.fills);o&&(n.fill=o);let i=Rs(e.strokes);i&&(n.stroke={color:i,weight:e.strokeWeight}),e.cornerRadius&&(n.radius=e.cornerRadius);let r=(e.effects??[]).filter(s=>s.visible!==!1&&(s.type==="DROP_SHADOW"||s.type==="INNER_SHADOW")).map(s=>`${s.type==="INNER_SHADOW"?"inset ":""}${s.offset?.x??0} ${s.offset?.y??0} ${s.radius??0} ${ai(s.color)??""}`.trim());if(r.length&&(n.shadows=r),e.type==="TEXT"&&e.characters!==void 0){n.text=e.characters;let s=e.style??{};n.font={family:s.fontFamily,size:s.fontSize,weight:s.fontWeight,lineHeight:s.lineHeightPx,letterSpacing:s.letterSpacing,align:s.textAlignHorizontal}}if(e.children?.length&&t<lp){let s=e.children.slice(0,As).map(l=>Ds(l,t+1)).filter(Boolean);s.length&&(n.children=s),e.children.length>As&&(n.childrenTruncated=e.children.length)}return n}function Os(e,t){let n=e,o;if(t&&n.nodes){let r=Object.keys(n.nodes)[0];o=r?n.nodes[r]?.document:void 0}if(o??=n.document,!o)throw new Error("Figma REST response had no document node to serialize.");let i={source:"figma-rest",file:n.name,root:Ds(o,0)};return JSON.stringify(i,null,2)}var ri,Mt,cp,lp,As,ci=k(()=>{"use strict";f();ri="https://api.figma.com/v1",Mt=class extends Error{constructor(n,o,i,r){let s=[o&&`plan tier: ${o}`,i&&`limit type: ${i}`].filter(Boolean).join(", ");super(`Figma REST rate limit reached${s?` (${s})`:""}${n!==void 0?`; resets in ${sp(n)}`:""}`);this.retryAfterSeconds=n;this.planTier=o;this.limitType=i;this.upgradeLink=r;this.name="FigmaRateLimitError"}retryAfterSeconds;planTier;limitType;upgradeLink};cp={sleep:e=>new Promise(t=>setTimeout(t,e))};lp=12,As=60});import{existsSync as dp}from"fs";import{mkdir as mp,readFile as pp,writeFile as up}from"fs/promises";import _t from"path";function fp(e,t,n){let o=r=>r.replace(/[^a-z0-9._-]/gi,"-"),i=`${o(t)}__${o(n??"file")}.json`;return _t.join(e,"tmp","eds-cli","design-cache",i)}function gp(e,t){let n=`scrape__${t.replace(/[^a-z0-9._-]/gi,"-").slice(0,120)}.json`;return _t.join(e,"tmp","eds-cli","design-cache",n)}function li(e){return e==="framer"||e==="stitch"||e==="web"}async function Ns(e){if(!dp(e))return null;try{return await pp(e,"utf-8")}catch{return null}}async function Ms(e,t){await mp(_t.dirname(e),{recursive:!0}),await up(e,t,"utf-8")}async function _s(e){let{figma:t,projectRoot:n}=e;if(e.localFile)return{design:{mode:"file",filePath:e.localFile},summary:`local file ${e.localFile}`};if(li(e.provider)&&e.designUrl){let r=gp(n,e.designUrl),s=_t.relative(n,r);if(e.dryRun)return{design:{mode:"scrape",spec:`{ "note": "dry run \u2014 the live ${e.provider} page is scraped at generate time", "url": "${e.designUrl}" }`,cachePath:s},summary:`scrape (dry run) ${e.designUrl}`};if(!e.refresh){let l=await Ns(r);if(l)return{design:{mode:"scrape",spec:l,cachePath:s},summary:`cache ${s}`}}try{let l=await Ss({url:e.designUrl,provider:e.provider,projectRoot:n,storageStatePath:e.storageStatePath});return await Ms(r,l),{design:{mode:"scrape",spec:l,cachePath:s},summary:`scrape \u2192 ${s}`}}catch(l){return{summary:"scrape failed",scrapeError:l instanceof Error?l.message:String(l)}}}if(!t?.fileKey)return{summary:"no design source"};let o=fp(n,t.fileKey,t.nodeId),i=_t.relative(n,o);if(!e.refresh){let r=await Ns(o);if(r)return{design:{mode:"spec",spec:r,cachePath:i},summary:`cache ${i}`}}if(e.token&&!e.preferMcp)try{let r=await Fs({fileKey:t.fileKey,nodeId:t.nodeId,token:e.token,pace:()=>Cn({logPath:En(n),perMinute:e.restPerMinute,onWait:e.onRestWait})}),s=Os(r,t.nodeId);return await Ms(o,s),{design:{mode:"spec",spec:s,cachePath:i},summary:`REST \u2192 ${i}`}}catch(r){return r instanceof Mt?{summary:"REST rate-limited",restError:r.message,rateLimit:r}:{design:{mode:"mcp",cachePath:i},summary:"MCP (REST failed \u2014 1 call)",restError:r instanceof Error?r.message:String(r)}}return{design:{mode:"mcp",cachePath:i},summary:"MCP (1 call, cached)"}}var Is=k(()=>{"use strict";f();oi();Tn();ci()});function An(e){if(/^\d+[-:]\d+$/.test(e.trim()))throw new Error(`Input "${e}" looks like a node-id but not a full URL. Provide a Figma URL or use --file-key.`);let t;try{t=new URL(e.trim())}catch{throw new Error(`Invalid Figma URL: "${e}"`)}if(!t.hostname.endsWith("figma.com"))throw new Error(`Not a Figma URL: "${e}"`);let n=t.pathname.split("/").filter(Boolean);if(n.length<2)throw new Error(`Cannot extract fileKey from URL: "${e}"`);let o=n[0];if(!hp.has(o))throw new Error(`Not a Figma file URL: "${e}". Use a design link (figma.com/design/<file>/\u2026?node-id=\u2026).`);let i,r;n[2]==="branch"&&n[3]?(i=n[3],r=n[4]?decodeURIComponent(n[4]):void 0):(i=n[1],r=n[2]?decodeURIComponent(n[2]):void 0);let s=t.searchParams.get("node-id"),l=s?wp(s):void 0;return{fileKey:i,nodeId:l,fileName:r}}function wp(e){return decodeURIComponent(e).replace(/-/g,":")}var hp,Us=k(()=>{"use strict";f();hp=new Set(["design","file","board","make","slides","proto"])});import{existsSync as bp}from"fs";import{readFile as yp}from"fs/promises";import vp from"path";function Bs(e){try{return JSON.stringify(JSON.parse(e))}catch{return e}}function kp(e,t,n){if(!e||e==="document"||e==="ue")return"";let o=t?` (model / persisted query: \`${t}\`)`:"",i="`${window.location.origin}/graphql/execute.json/<project>/<query>;path=<cfPath>`";return e==="cf"?`
|
|
535
|
+
${await Os(n,s)}`),l+=Ds(s);let m=i?.contextTokens??mi,p=As(l)+d.length*1500+6e3;p>m&&a.warn(`The prompt needs about ${p} tokens of context but ${m} are configured - raise local.contextTokens${r==="ollama"?"":" and the server's own context length"}, or use a smaller design.`);let u=(await import("ora")).default,g=Date.now(),h=()=>`${Math.round((Date.now()-g)/1e3)}s`;a.info(`Running ${Ce[r]} ${Z.dim(`${c} \xB7 ${e.baseUrl}`)}`);let $=u({text:`waiting for the model ${Z.dim(h())}`,color:"yellow"}).start(),w=0,y=setInterval(()=>{$.text=`${w?`writing \xB7 ${w} chars`:"reading the prompt"} ${Z.dim(h())}`},300),b;try{b=await Rs({type:r,baseUrl:e.baseUrl??Wt[r],model:c,prompt:l,images:d,apiKey:i?.apiKey,contextTokens:Math.max(m,r==="ollama"?p:0),onToken:D=>{w+=D.length}})}finally{clearInterval(y),$.stop()}let T=fe.join(n,"tmp","eds-cli",`local-reply-${Date.now()}.md`);await _s(fe.dirname(T),{recursive:!0}),await Us(T,b.text,"utf-8");let F=Fs(b.text),{written:N,rejected:te}=await Ls(n,s,F),Ne=[h(),b.outputTokens?`${b.outputTokens} tokens out`:`${b.text.length} chars`].join(" \xB7 ");for(let D of N)a.info(` ${I.accent("\u270E")} ${Z.cyan(D)}`);for(let D of te)a.warn(`Ignored a file outside blocks/${s}/: ${D}`);return N.length?a.info(`${I.accent("\u2713")} ${I.accent("model finished")} ${Z.dim(Ne)}`):a.warn(`The model replied but no files could be read from it (${Ne}). Raw reply: ${fe.relative(n,T)}`),!0}function Sp(e){return e.includes("figma")?e.split("__").pop()??e:e.toLowerCase()}async function jp(e,t){let n=(await import("ora")).default,o=Date.now(),i=()=>`${Math.round((Date.now()-o)/1e3)}s`,r=n({text:`thinking ${Z.dim(i())}`,color:"yellow"}).start(),s="thinking",c=setInterval(()=>{r.text=`${s} ${Z.dim(i())}`},300),l=new Map,d=p=>{r.stop(),a.info(` ${p}`),r.start()},m;try{if(e.stdout){let p=kp.createInterface({input:e.stdout});for await(let u of p){let g=u.trim();if(!g)continue;let h;try{h=JSON.parse(g)}catch{continue}let $=Array.isArray(h.message?.content)?h.message.content:[];if(h.type==="assistant"){for(let w of $)if(w.type==="text"&&"text"in w){let y=w.text.trim().split(`
|
|
536
|
+
`)[0].slice(0,100);y&&d(Z.dim(y))}else if(w.type==="tool_use"&&"name"in w){let y="id"in w&&w.id?w.id:`${Math.random()}`;l.set(y,{label:Pp(w.name,w.input,t),start:Date.now()}),s=Sp(w.name)}}else if(h.type==="user"){for(let w of $)if(w.type==="tool_result"&&"tool_use_id"in w&&w.tool_use_id){let y=l.get(w.tool_use_id);if(y){let b=`${((Date.now()-y.start)/1e3).toFixed(1)}s`,T="is_error"in w&&w.is_error?` ${Z.red("failed")}`:"";d(`${y.label} ${Z.dim(b)}${T}`),l.delete(w.tool_use_id)}}}else if(h.type==="result"){let w=typeof h.duration_ms=="number"?`${(h.duration_ms/1e3).toFixed(1)}s`:"",y=typeof h.total_cost_usd=="number"?`$${h.total_cost_usd.toFixed(3)}`:"";m=[w,y].filter(Boolean).join(" \xB7 ")||"done"}}}for(let p of l.values())d(`${p.label} ${Z.dim("\u2026")}`);clearInterval(c),m?r.succeed(`${I.accent("agent finished")} ${Z.dim(m)}`):r.stop()}catch(p){throw clearInterval(c),r.stop(),p}await e}function Pp(e,t,n){let o=i=>{let r=t?.[i];return typeof r!="string"?"":r.startsWith(n)?fe.relative(n,r):fe.basename(r)};if(e.includes("figma")){let i=e.split("__").pop()??e;return`${X.figma} ${Z.bold(i)} ${Z.dim("Figma MCP")}`}switch(e){case"Write":case"Edit":case"NotebookEdit":return`${I.accent("\u270E")} ${Z.cyan(o("file_path"))}`;case"Read":return Z.dim(`\xB7 read ${o("file_path")}`);case"Bash":{let i=typeof t?.command=="string"?t.command.split(`
|
|
537
|
+
`)[0].slice(0,70):"";return Z.dim(`$ ${i}`)}default:return`${I.blue("\u2192")} ${e}`}}var xp,Is,wi=v(()=>{"use strict";f();O();B();zt();xp=96*1024;Is={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp"}});import{existsSync as Hn}from"fs";import{cp as bi,mkdir as yi,readFile as Ep,readdir as Hs,rename as Bs,rm as qt,writeFile as Cp}from"fs/promises";import Te from"path";async function pt(e,t){let n=Ws(e,t);return Hn(n)?JSON.parse(await Ep(n,"utf-8")):null}async function ki(e,t){await yi(Kt(e,t.name),{recursive:!0}),await Cp(Ws(e,t.name),`${JSON.stringify(t,null,2)}
|
|
538
|
+
`)}async function zs(e){let t=Gs(e);if(!Hn(t))return[];let n=[];for(let o of await Hs(t,{withFileTypes:!0})){if(!o.isDirectory())continue;let i=await pt(e,o.name);i&&n.push(i)}return n.sort((o,i)=>o.name.localeCompare(i.name))}async function Js(e,t,n){let o=vi(e,t),i=Te.join(Kt(e,t),".stash");await qt(i,{recursive:!0,force:!0});let r=Hn(o);return r&&(await yi(Te.dirname(i),{recursive:!0}),await Bs(o,i)),n!==void 0&&await bi(mt(e,t,n),o,{recursive:!0}),async()=>{await qt(o,{recursive:!0,force:!0}),r&&await Bs(i,o)}}async function qs(e,t,n){let o=await pt(e,t)??{name:t,status:"open",source:n.source,versions:[]},i=(o.versions.at(-1)?.version??0)+1,r=mt(e,t,i);await qt(r,{recursive:!0,force:!0}),await yi(Te.dirname(r),{recursive:!0}),await bi(vi(e,t),r,{recursive:!0});let s=(await Hs(r)).sort();return o.status="open",o.versions.push({version:i,createdAt:new Date().toISOString(),...n.feedback?{feedback:n.feedback}:{},ok:n.ok,files:s}),await ki(e,o),i}async function Ks(e,t,n){let o=await pt(e,t);if(!o)throw new Error(`No draft "${t}".`);let i=n??o.versions.at(-1)?.version;if(!i||!o.versions.some(s=>s.version===i))throw new Error(`Draft "${t}" has no version ${n??""}.`.trim());let r=vi(e,t);return await qt(r,{recursive:!0,force:!0}),await bi(mt(e,t,i),r,{recursive:!0}),o.status="accepted",o.accepted={version:i,at:new Date().toISOString()},await ki(e,o),{draft:o,version:i}}async function Vs(e,t,n){let o=await pt(e,t);o?.accepted&&(o.accepted.commit=n,await ki(e,o))}async function Xs(e,t){let n=Kt(e,t);return Hn(n)?(await qt(n,{recursive:!0,force:!0}),!0):!1}function Ys(e,t){let n=e.source.designRef?` from ${e.source.designRef}`:"",o=e.versions.filter(i=>i.version<=t).map(i=>`- v${i.version}: ${i.feedback?`"${i.feedback}"`:"first version"}`);return`feat(blocks): ${e.name}${n}
|
|
539
|
+
|
|
540
|
+
Accepted draft v${t} after ${o.length===1?"one version":`${o.length} versions`}:
|
|
541
|
+
${o.join(`
|
|
542
|
+
`)}
|
|
543
|
+
`}var Gs,Kt,Ws,mt,vi,xi=v(()=>{"use strict";f();Gs=e=>Te.join(e,"tmp","eds-cli","drafts"),Kt=(e,t)=>Te.join(Gs(e),t),Ws=(e,t)=>Te.join(Kt(e,t),"draft.json"),mt=(e,t,n)=>Te.join(Kt(e,t),`v${n}`),vi=(e,t)=>Te.join(e,"blocks",t)});function Qs(e){return e<=480?`${e} mobile`:e<=1024?`${e} tablet`:`${e} desktop`}function Tp(e,t="figma"){return e?e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0).map(n=>({width:n,label:Qs(n),source:t})):[]}function Zs(e,t){let n=Tp(e,"figma");return n.length?n:Ap(t)}function Ap(e){if(!Array.isArray(e))return[];let t=new Set,n=[];for(let o of e){let i=Number(o?.width);if(!Number.isFinite(i)||i<=0||t.has(i))continue;t.add(i);let r=o.source,s=r==="figma"||r==="scrape"?r:"default";n.push({width:i,label:Qs(i),source:s})}return n}var ec=v(()=>{"use strict";f()});import{existsSync as Rp}from"fs";import{createRequire as Dp}from"module";import Fp from"path";import{pathToFileURL as tc}from"url";async function nc(e){try{return(await import("playwright")).chromium}catch{}let t=[e,process.cwd()].filter(n=>!!n);if(t.length)try{let o=Dp(tc(Fp.join(t[0],"package.json")).href).resolve("playwright",{paths:t});return(await import(tc(o).href)).chromium}catch{}throw new Error("Scraping needs Playwright. Install it in your project (`npm i -D playwright`) or globally (`npm i -g playwright`), then `npx playwright install chromium`.")}async function oc(e){let t=e.width??1440,n=await nc(e.projectRoot),o;try{o=await n.launch({headless:!0})}catch(i){let r=i instanceof Error?i.message:String(i);throw/Executable doesn't exist|install/i.test(r)?new Error("Chromium isn't installed for Playwright. Run `npx playwright install chromium`."):i}try{let i=e.storageStatePath&&Rp(e.storageStatePath),s=await(await o.newContext({viewport:{width:t,height:900},deviceScaleFactor:1,...i?{storageState:e.storageStatePath}:{}})).newPage();await s.goto(e.url,{waitUntil:"networkidle",timeout:45e3}),await s.waitForTimeout(700);let c=await s.evaluate(Lp,{maxNodes:320,maxDepth:14,textCap:200}),l={source:`scrape:${e.provider}`,url:e.url,viewport:t,authenticated:!!i,title:c.title,root:c.root,nodeCount:c.nodeCount,truncated:c.truncated};return JSON.stringify(l,null,2)}finally{await o.close()}}async function ic(e){let n=await(await nc(e.projectRoot)).launch({headless:!1});try{let o=await n.newContext();await(await o.newPage()).goto(e.loginUrl,{waitUntil:"domcontentloaded",timeout:6e4}),await e.waitForUser(),await o.storageState({path:e.statePath})}finally{await n.close()}}function Lp(e){let t=new Set(["SCRIPT","STYLE","NOSCRIPT","LINK","META","HEAD","BR","TEMPLATE"]),n=0,o=!1,i=d=>!d||d==="none"||d==="normal"||d==="auto"||d==="0px"||d==="rgba(0, 0, 0, 0)"||d==="transparent";function r(d){let m="";for(let p of Array.from(d.childNodes))p.nodeType===3&&(m+=p.textContent??"");return m=m.replace(/\s+/g," ").trim(),m.length>e.textCap?`${m.slice(0,e.textCap)}\u2026`:m}function s(d){let m=getComputedStyle(d),p={},u=(h,$)=>{i($)||(p[h]=$)};u("display",m.display),(m.display.includes("flex")||m.display.includes("grid"))&&(u("flexDirection",m.flexDirection),u("justifyContent",m.justifyContent),u("alignItems",m.alignItems),u("gap",m.gap)),u("padding",m.padding),u("margin",m.margin),u("color",m.color),u("background",m.backgroundColor),m.backgroundImage&&m.backgroundImage!=="none"&&(p.backgroundImage=m.backgroundImage.slice(0,160)),u("fontFamily",m.fontFamily),u("fontSize",m.fontSize),u("fontWeight",m.fontWeight),u("lineHeight",m.lineHeight),u("letterSpacing",m.letterSpacing),u("textAlign",m.textAlign);let g=h=>h&&!h.startsWith("0px")&&!h.includes(" none")?h:"";if(m.border)g(m.border)&&(p.border=m.border);else for(let h of["borderTop","borderRight","borderBottom","borderLeft"])g(m[h])&&(p[h]=m[h]);return u("borderRadius",m.borderRadius),u("boxShadow",m.boxShadow),m.opacity&&m.opacity!=="1"&&(p.opacity=m.opacity),m.position&&m.position!=="static"&&(p.position=m.position),p}function c(d,m,p=""){if(n>=e.maxNodes)return o=!0,null;if(t.has(d.tagName))return null;let u=d.getBoundingClientRect(),g=getComputedStyle(d);if(g.display==="none"||g.visibility==="hidden"||g.opacity==="0"||u.width<1||u.height<1)return null;n++;let $={tag:d.tagName.toLowerCase(),rect:{x:Math.round(u.x),y:Math.round(u.y),w:Math.round(u.width),h:Math.round(u.height)}},w=(d.getAttribute("class")||"").trim().split(/\s+/).filter(Boolean).slice(0,3);w.length&&($.class=w.join(" "));let y=s(d);!y.background&&p&&u.width>=window.innerWidth*.9&&(y.inheritedBackground=p),Object.keys(y).length&&($.style=y);let b=y.background??p;if(d.tagName==="IMG"){let F=d;$.img={src:(F.currentSrc||F.src||"").slice(0,200),alt:F.alt||"",w:F.naturalWidth,h:F.naturalHeight}}let T=r(d);if(T&&($.text=T),m<e.maxDepth){let F=[];for(let N of Array.from(d.children)){let te=c(N,m+1,b);te&&F.push(te)}F.length&&($.children=F)}return $}let l=c(document.body,0);return{title:document.title,root:l,nodeCount:n,truncated:o}}var $i=v(()=>{"use strict";f()});import{mkdir as rc,readFile as Op,rm as ac,stat as Np,writeFile as Mp}from"fs/promises";import cc from"path";function Gn(e){return cc.join(e,"tmp","eds-cli","figma-rest-calls.json")}async function _p(e,t,n){let o=`${e}.lock`;for(await rc(cc.dirname(e),{recursive:!0});;)try{await rc(o);break}catch{await Np(o).then(r=>t()-r.mtimeMs,()=>0)>Ip?await ac(o,{recursive:!0,force:!0}):await new Promise(r=>setTimeout(r,25))}try{return await n()}finally{await ac(o,{recursive:!0,force:!0})}}async function Up(e){try{let t=JSON.parse(await Op(e,"utf-8"));return Array.isArray(t)?t.filter(n=>typeof n=="number"):[]}catch{return[]}}async function Wn(e){let t=Math.max(1,e.perMinute??Si),n=e.now??Date.now,o=e.sleep??(i=>new Promise(r=>setTimeout(r,i)));for(;;){let i=await _p(e.logPath,n,async()=>{let r=n(),s=(await Up(e.logPath)).filter(c=>r-c<sc);return s.length<t?(s.push(r),await Mp(e.logPath,JSON.stringify(s)),0):Math.min(...s)+sc-r+50});if(i<=0)return;e.onWait?.(i),await o(i)}}var Si,sc,Ip,zn=v(()=>{"use strict";f();Si=10,sc=6e4,Ip=1e4});function Bp(e){let t=Math.max(0,Math.round(e));if(t<60)return`${t} s`;if(t<3600)return`${Math.round(t/60)} min`;if(t<86400){let o=Math.round(t%3600/60);return`${Math.floor(t/3600)} h${o?` ${o} min`:""}`}let n=Math.round(t%86400/3600);return`${Math.floor(t/86400)} d${n?` ${n} h`:""}`}async function Ei(e,t,n,o=!1){await n?.();let i=await fetch(e,{headers:{"X-Figma-Token":t}});if(i.status!==429)return i;let r=l=>i.headers.get(l)??void 0,s=r("retry-after"),c=s!==void 0&&/^\d+$/.test(s)?Number(s):void 0;if(!o&&c!==void 0&&c<=60)return await Hp.sleep(c*1e3),Ei(e,t,n,!0);throw new Vt(c,r("x-figma-plan-tier"),r("x-figma-rate-limit-type"),r("x-figma-upgrade-link"))}async function mc(e){let{fileKey:t,nodeId:n,token:o}=e,i=n?`${ji}/files/${t}/nodes?ids=${encodeURIComponent(n)}`:`${ji}/files/${t}`,r=await Ei(i,o,e.pace);if(!r.ok){let s=await r.text().catch(()=>""),c=r.status===403?" (check the token scope: it needs file_content:read, and access to this file)":r.status===404?" (file or node not found \u2014 check the URL)":"";throw new Error(`Figma REST ${r.status} ${r.statusText}${c}${s?` \u2014 ${s.slice(0,200)}`:""}`)}return r.json()}async function pc(e){let{fileKey:t,nodeId:n,token:o,scale:i=1}=e;if(!n)throw new Error("A node id is required to render a Figma image.");let r=`${ji}/images/${t}?ids=${encodeURIComponent(n)}&format=png&scale=${i}`,s=await Ei(r,o,e.pace);if(!s.ok){let m=await s.text().catch(()=>"");throw new Error(`Figma images ${s.status} ${s.statusText}${m?` \u2014 ${m.slice(0,200)}`:""}`)}let c=await s.json();if(c.err)throw new Error(`Figma images: ${c.err}`);let l=c.images?.[n]??Object.values(c.images??{}).find(Boolean);if(!l)throw new Error("Figma returned no image URL for that node.");let d=await fetch(l);if(!d.ok)throw new Error(`Fetching the rendered image failed: ${d.status} ${d.statusText}`);return Buffer.from(await d.arrayBuffer())}function Pi(e){if(!e)return;let t=o=>Math.round(Math.max(0,Math.min(1,o))*255).toString(16).padStart(2,"0"),n=`#${t(e.r)}${t(e.g)}${t(e.b)}`;return e.a!==void 0&&e.a<1?`${n}${t(e.a)}`:n}function dc(e){let t=e?.find(n=>n.visible!==!1);if(t){if(t.type==="SOLID")return Pi(t.color);if(t.type?.startsWith("GRADIENT")){let n=(t.gradientStops??[]).map(o=>Pi(o.color)).filter(Boolean);return n.length?`gradient(${n.join(" \u2192 ")})`:"gradient"}return t.type==="IMAGE"?"image(placeholder)":t.type?.toLowerCase()}}function uc(e,t){if(!e||typeof e!="object")return null;let n={name:e.name,type:e.type};if(e.absoluteBoundingBox){let{width:s,height:c}=e.absoluteBoundingBox;s!=null&&c!=null&&(n.size={w:Math.round(s),h:Math.round(c)})}e.layoutMode&&e.layoutMode!=="NONE"&&(n.layout={direction:e.layoutMode==="HORIZONTAL"?"row":"column",gap:e.itemSpacing,padding:[e.paddingTop,e.paddingRight,e.paddingBottom,e.paddingLeft],align:[e.primaryAxisAlignItems,e.counterAxisAlignItems].filter(Boolean).join("/")});let o=dc(e.fills);o&&(n.fill=o);let i=dc(e.strokes);i&&(n.stroke={color:i,weight:e.strokeWeight}),e.cornerRadius&&(n.radius=e.cornerRadius);let r=(e.effects??[]).filter(s=>s.visible!==!1&&(s.type==="DROP_SHADOW"||s.type==="INNER_SHADOW")).map(s=>`${s.type==="INNER_SHADOW"?"inset ":""}${s.offset?.x??0} ${s.offset?.y??0} ${s.radius??0} ${Pi(s.color)??""}`.trim());if(r.length&&(n.shadows=r),e.type==="TEXT"&&e.characters!==void 0){n.text=e.characters;let s=e.style??{};n.font={family:s.fontFamily,size:s.fontSize,weight:s.fontWeight,lineHeight:s.lineHeightPx,letterSpacing:s.letterSpacing,align:s.textAlignHorizontal}}if(e.children?.length&&t<Gp){let s=e.children.slice(0,lc).map(c=>uc(c,t+1)).filter(Boolean);s.length&&(n.children=s),e.children.length>lc&&(n.childrenTruncated=e.children.length)}return n}function fc(e,t){let n=e,o;if(t&&n.nodes){let r=Object.keys(n.nodes)[0];o=r?n.nodes[r]?.document:void 0}if(o??=n.document,!o)throw new Error("Figma REST response had no document node to serialize.");let i={source:"figma-rest",file:n.name,root:uc(o,0)};return JSON.stringify(i,null,2)}var ji,Vt,Hp,Gp,lc,Ci=v(()=>{"use strict";f();ji="https://api.figma.com/v1",Vt=class extends Error{constructor(n,o,i,r){let s=[o&&`plan tier: ${o}`,i&&`limit type: ${i}`].filter(Boolean).join(", ");super(`Figma REST rate limit reached${s?` (${s})`:""}${n!==void 0?`; resets in ${Bp(n)}`:""}`);this.retryAfterSeconds=n;this.planTier=o;this.limitType=i;this.upgradeLink=r;this.name="FigmaRateLimitError"}retryAfterSeconds;planTier;limitType;upgradeLink};Hp={sleep:e=>new Promise(t=>setTimeout(t,e))};Gp=12,lc=60});import{existsSync as Wp}from"fs";import{mkdir as zp,readFile as Jp,writeFile as qp}from"fs/promises";import Xt from"path";function Kp(e,t,n){let o=r=>r.replace(/[^a-z0-9._-]/gi,"-"),i=`${o(t)}__${o(n??"file")}.json`;return Xt.join(e,"tmp","eds-cli","design-cache",i)}function Vp(e,t){let n=`scrape__${t.replace(/[^a-z0-9._-]/gi,"-").slice(0,120)}.json`;return Xt.join(e,"tmp","eds-cli","design-cache",n)}function Ti(e){return e==="framer"||e==="stitch"||e==="web"}async function gc(e){if(!Wp(e))return null;try{return await Jp(e,"utf-8")}catch{return null}}async function hc(e,t){await zp(Xt.dirname(e),{recursive:!0}),await qp(e,t,"utf-8")}async function wc(e){let{figma:t,projectRoot:n}=e;if(e.localFile)return{design:{mode:"file",filePath:e.localFile},summary:`local file ${e.localFile}`};if(Ti(e.provider)&&e.designUrl){let r=Vp(n,e.designUrl),s=Xt.relative(n,r);if(e.dryRun)return{design:{mode:"scrape",spec:`{ "note": "dry run \u2014 the live ${e.provider} page is scraped at generate time", "url": "${e.designUrl}" }`,cachePath:s},summary:`scrape (dry run) ${e.designUrl}`};if(!e.refresh){let c=await gc(r);if(c)return{design:{mode:"scrape",spec:c,cachePath:s},summary:`cache ${s}`}}try{let c=await oc({url:e.designUrl,provider:e.provider,projectRoot:n,storageStatePath:e.storageStatePath});return await hc(r,c),{design:{mode:"scrape",spec:c,cachePath:s},summary:`scrape \u2192 ${s}`}}catch(c){return{summary:"scrape failed",scrapeError:c instanceof Error?c.message:String(c)}}}if(!t?.fileKey)return{summary:"no design source"};let o=Kp(n,t.fileKey,t.nodeId),i=Xt.relative(n,o);if(!e.refresh){let r=await gc(o);if(r)return{design:{mode:"spec",spec:r,cachePath:i},summary:`cache ${i}`}}if(e.token&&!e.preferMcp)try{let r=await mc({fileKey:t.fileKey,nodeId:t.nodeId,token:e.token,pace:()=>Wn({logPath:Gn(n),perMinute:e.restPerMinute,onWait:e.onRestWait})}),s=fc(r,t.nodeId);return await hc(o,s),{design:{mode:"spec",spec:s,cachePath:i},summary:`REST \u2192 ${i}`}}catch(r){return r instanceof Vt?{summary:"REST rate-limited",restError:r.message,rateLimit:r}:{design:{mode:"mcp",cachePath:i},summary:"MCP (REST failed \u2014 1 call)",restError:r instanceof Error?r.message:String(r)}}return{design:{mode:"mcp",cachePath:i},summary:"MCP (1 call, cached)"}}var bc=v(()=>{"use strict";f();$i();zn();Ci()});function Jn(e){if(/^\d+[-:]\d+$/.test(e.trim()))throw new Error(`Input "${e}" looks like a node-id but not a full URL. Provide a Figma URL or use --file-key.`);let t;try{t=new URL(e.trim())}catch{throw new Error(`Invalid Figma URL: "${e}"`)}if(!t.hostname.endsWith("figma.com"))throw new Error(`Not a Figma URL: "${e}"`);let n=t.pathname.split("/").filter(Boolean);if(n.length<2)throw new Error(`Cannot extract fileKey from URL: "${e}"`);let o=n[0];if(!Xp.has(o))throw new Error(`Not a Figma file URL: "${e}". Use a design link (figma.com/design/<file>/\u2026?node-id=\u2026).`);let i,r;n[2]==="branch"&&n[3]?(i=n[3],r=n[4]?decodeURIComponent(n[4]):void 0):(i=n[1],r=n[2]?decodeURIComponent(n[2]):void 0);let s=t.searchParams.get("node-id"),c=s?Yp(s):void 0;return{fileKey:i,nodeId:c,fileName:r}}function Yp(e){return decodeURIComponent(e).replace(/-/g,":")}var Xp,yc=v(()=>{"use strict";f();Xp=new Set(["design","file","board","make","slides","proto"])});import{existsSync as Qp}from"fs";import{readFile as Zp}from"fs/promises";import eu from"path";function vc(e){try{return JSON.stringify(JSON.parse(e))}catch{return e}}function tu(e,t,n){if(!e||e==="document"||e==="ue")return"";let o=t?` (model / persisted query: \`${t}\`)`:"",i="`${window.location.origin}/graphql/execute.json/<project>/<query>;path=<cfPath>`";return e==="cf"?`
|
|
538
544
|
## Content source: Content Fragment
|
|
539
545
|
This block renders an AEM **Content Fragment**${o} - not inline-authored copy.
|
|
540
546
|
- UE model: use an \`aem-content-fragment\` field (e.g. \`name: "fragment"\`) for the CF reference.
|
|
@@ -547,22 +553,22 @@ This block mixes **two sources in one model and one \`decorate(block)\`**:
|
|
|
547
553
|
- **Inline (UE-authored)** parts \u2192 normal fields (text / richtext / image / select) read straight from the authored DOM cells, with semantic collapsing.
|
|
548
554
|
- **Content Fragment** part${o} \u2192 an \`aem-content-fragment\` field; \`decorate()\` is **async** and also fetches that CF via a GraphQL persisted query (${i}) and renders its fields.
|
|
549
555
|
- Field order in the model = cell order in the authored DOM. Read the inline cells by position; detect the CF reference by its \`/content/dam/\` link. Merge both into the final markup, and handle the CF loading/empty/error states.
|
|
550
|
-
`}async function
|
|
556
|
+
`}async function kc(e){let t=await nu(e.projectRoot),n=tu(e.contentSource,e.cfHint,e.blockName),o=e.screenshot===!0,i=e.provider??"figma",r=ut[i],s=e.design,c=s?.mode==="file"?/\.(png|jpe?g|webp)$/i.test(s.filePath):!1,d=`## Step 5 \u2014 One Verification Pass (single pass, then stop)
|
|
551
557
|
Do **exactly one** self-check \u2014 do **not** loop:
|
|
552
|
-
1. Compare your implementation to ${s?.mode==="spec"?"the exact values in the embedded design data from Step 1":s?.mode==="scrape"?"the exact values in the scraped design data from Step 1":s?.mode==="file"?
|
|
558
|
+
1. Compare your implementation to ${s?.mode==="spec"?"the exact values in the embedded design data from Step 1":s?.mode==="scrape"?"the exact values in the scraped design data from Step 1":s?.mode==="file"?c?"the local design image":"the exact values in the local SVG":s?.mode==="mcp"?"the exact values from the `get_design_context` you cached":o?"the `get_screenshot` image":"the exact values from `get_design_context`"} once, across: spacing, fonts, colors, radius, shadows, alignment and proportions.
|
|
553
559
|
2. Apply **one** round of corrections, then **stop** \u2014 don't iterate to "pixel perfect". The author reviews the result in the live preview (\`eds block preview\`) and will request another pass with specific feedback if needed.
|
|
554
560
|
3. Briefly state what you checked and any value you had to infer.`,m=`Target: fileKey \`${e.figma?.fileKey}\`${e.figma?.nodeId?`, node \`${e.figma.nodeId}\``:" (no node selected \u2014 use the full page)"}.`,p;s?.mode==="spec"?p=`## Step 1 \u2014 Use the Provided Design Data (no MCP)
|
|
555
561
|
The design was already fetched for you and is embedded below \u2014 **do not call any Figma MCP tool** (\`get_design_context\`, \`get_variable_defs\`, \`get_screenshot\`). Parse it for the exact structure, layout, spacing, colors, typography, radius and effects.
|
|
556
562
|
|
|
557
563
|
\`\`\`json
|
|
558
|
-
${
|
|
564
|
+
${vc(s.spec)}
|
|
559
565
|
\`\`\`
|
|
560
566
|
|
|
561
567
|
Image fills are placeholders (the data references assets, not pixels) \u2014 render a placeholder at the right aspect-ratio per the Placeholders section; authors supply the real image.`:s?.mode==="scrape"?p=`## Step 1 \u2014 Use the Scraped Design Data (no MCP)
|
|
562
568
|
The design was scraped from the live **${r}** page (${e.designRef??"the URL"}) with headless Chromium and is embedded below \u2014 **do not call any MCP tool** and **do not fetch the URL yourself**. The tree holds **computed** values: geometry (\`rect\` x/y/w/h, px), layout (\`display\`/\`flexDirection\`/\`gap\`/\`padding\`), colours, typography, radius and shadows. Use them verbatim (convert px\u2192rem where appropriate) and regroup the flattened DOM into semantic structure yourself (Step 3).
|
|
563
569
|
|
|
564
570
|
\`\`\`json
|
|
565
|
-
${
|
|
571
|
+
${vc(s.spec)}
|
|
566
572
|
\`\`\`
|
|
567
573
|
|
|
568
574
|
If the page holds several sections, build **only** the one for \`${e.blockName}\` (the element whose class or \`data-block\` matches the block name) and read the rest only for shared tokens.
|
|
@@ -572,7 +578,7 @@ A section with \`inheritedBackground\` has no background of its own: that colour
|
|
|
572
578
|
The scraped **text and images are reference content**, not authored copy \u2014 reproduce the layout/styling exactly, but read real content from the authored DOM at runtime and fall back to placeholders (see the Placeholders section). Do **not** hardcode the scraped copy or ship the scraped image URLs.`:s?.mode==="file"?p=`## Step 1 \u2014 Read the Local Design Export (no MCP)
|
|
573
579
|
Read \`${s.filePath}\` with your **Read** tool. Do **not** call any Figma MCP tool.
|
|
574
580
|
|
|
575
|
-
${
|
|
581
|
+
${c?"It's a raster image (PNG/JPG) \u2014 open it and reproduce it visually: infer spacing, colors, typography, radius, shadows and layout as precisely as you can from the pixels.":"It's an **SVG** \u2014 read it as text and parse the **exact** values: geometry and positions (x/y/width/height, `viewBox`), text and typography (font-family / font-size / font-weight on `<text>`/`<tspan>`), fills and gradients, strokes, and effects. Use the numbers verbatim, converting px\u2192rem where appropriate. The SVG is flattened \u2014 regroup into semantic structure yourself (Step 3), don't mirror raw `<g>`/`<path>` nesting."}`:s?.mode==="mcp"?p=`## Step 1 \u2014 Fetch the Design Once, Then Cache It (single MCP call)
|
|
576
582
|
Call **\`get_design_context\` exactly once** for the target node. Do **not** call \`get_variable_defs\` or \`get_screenshot\` \u2014 each extra MCP call burns the Figma plan's scarce tool-call budget; derive colors and tokens from the context you already got.
|
|
577
583
|
**Immediately after**, \`Write\` the raw design data you received to \`${s.cachePath}\` (pretty JSON) so re-runs and refine passes reuse it without another MCP call. Then generate from it.
|
|
578
584
|
|
|
@@ -655,7 +661,7 @@ Rules:
|
|
|
655
661
|
If the project uses a **single aggregated model file** (\`component-definition.json\` + \`component-models.json\` + \`component-filters.json\`) instead of per-block \`_${e.blockName}.json\`, detect that convention and add the block's definition/model/filter to those files instead (and register the block in the \`section\` filter). Prefer the per-block \`_${e.blockName}.json\` when neither exists. Full field reference and a repeatable-cards round-trip example: \`docs/universal-editor-fields.md\`.
|
|
656
662
|
|
|
657
663
|
**Reusable field groups (partials):** when the design shows one of these common shapes, reuse the standard group instead of inventing fields \u2014 same groups \`eds model add\` uses, so the model stays consistent across the project:
|
|
658
|
-
${
|
|
664
|
+
${st.map($=>`- \`${$.id}\` \u2014 ${$.label}`).join(`
|
|
659
665
|
`)}
|
|
660
666
|
`:"",g=s?.mode==="file"?"a design export":r,h=s?.mode==="file"?"design":`${r} design`;return`# Pixel-Perfect EDS Block from ${g}
|
|
661
667
|
|
|
@@ -739,8 +745,8 @@ ${t}
|
|
|
739
745
|
Finally, record the design's frame width(s) you read in Step 1 into \`blocks/${e.blockName}/.eds-meta.json\` as \`{ "breakpoints": [{ "width": <px>, "source": "${s?.mode==="scrape"?"scrape":i}" }] }\` (one entry per distinct frame width). The CLI merges this so \`eds block preview\` shows the block at the **real design widths**, not a fixed device set.
|
|
740
746
|
|
|
741
747
|
---
|
|
742
|
-
*Prompt version: ${
|
|
743
|
-
`}function
|
|
748
|
+
*Prompt version: ${Yt}*
|
|
749
|
+
`}function qn(e){let t=e.provider??"figma",n=t==="figma"&&e.figma?.fileKey?`If the change needs design values, re-read **only what you need** from Figma (fileKey \`${e.figma.fileKey}\`${e.figma.nodeId?`, node \`${e.figma.nodeId}\``:""}) \u2014 don't re-fetch the whole design.`:"Use the values already in the files (and the cached design snapshot under `tmp/eds-cli/design-cache/` if present); infer sensibly if the request is purely stylistic.";return`# Refine the \`${e.blockName}\` EDS block
|
|
744
750
|
|
|
745
751
|
The block already exists in \`blocks/${e.blockName}/\` and the author reviewed it in the live preview. Apply **this change** and nothing else:
|
|
746
752
|
|
|
@@ -759,8 +765,8 @@ The block already exists in \`blocks/${e.blockName}/\` and the author reviewed i
|
|
|
759
765
|
- **No shell access:** only read/write files${t==="figma"?" and call the Figma MCP":""}. Do **not** run \`eslint\`, \`stylelint\`, \`npm\`, \`npx\`, \`tsc\`, a build, or any Bash command \u2014 they aren't granted and just fail.
|
|
760
766
|
- **Minimise chat output:** edit files directly, don't paste code back. End with a **\u22642-line** summary of what changed.
|
|
761
767
|
|
|
762
|
-
*Prompt version: ${
|
|
763
|
-
`}async function
|
|
768
|
+
*Prompt version: ${Yt}*
|
|
769
|
+
`}async function nu(e){let t=eu.join(e,"styles","styles.css");if(!Qp(t))return"";try{let o=(await Zp(t,"utf-8")).match(/:root\s*\{([^}]+)\}/);if(!o)return"";let i=o[1].split(`
|
|
764
770
|
`).filter(r=>r.trim().startsWith("--")).map(r=>r.trim()).join(`
|
|
765
771
|
`);return i?`
|
|
766
772
|
## Existing Project Tokens
|
|
@@ -772,7 +778,7 @@ Reuse them instead of hardcoding values:
|
|
|
772
778
|
${i}
|
|
773
779
|
}
|
|
774
780
|
\`\`\`
|
|
775
|
-
`:""}catch{return""}}var
|
|
781
|
+
`:""}catch{return""}}var Yt,ut,Ai=v(()=>{"use strict";f();Vo();Yt="0.7.2",ut={figma:"Figma",framer:"Framer",stitch:"Google Stitch",web:"Web page"}});import{existsSync as ou}from"fs";import{chmod as iu,mkdir as ru}from"fs/promises";import{homedir as au}from"os";import xc from"path";function Ri(e){return xc.join(au(),".eds","auth",`${e}.json`)}function $c(e){return ou(Ri(e))}async function Sc(e){await ru(xc.dirname(e),{recursive:!0,mode:448})}async function jc(e){try{await iu(e,384)}catch{}}var Pc=v(()=>{"use strict";f()});import{emitKeypressEvents as su}from"readline";async function Qt(e){let t=process.stdin,n=Kn.menu&&t.isTTY;await new Promise(o=>{let i=!1,r=async l=>{i||(i=!0,process.off("SIGINT",s),process.off("SIGTERM",s),n&&(t.off("keypress",c),t.setRawMode(!1),t.pause()),await e(),l&&process.exit(0),o())},s=()=>{r(!0)},c=(l,d)=>{d?.ctrl&&d.name==="c"?r(!0):(d?.name==="escape"||d?.name==="return")&&r(!1)};process.on("SIGINT",s),process.on("SIGTERM",s),n&&(su(t),t.setRawMode(!0),t.resume(),t.on("keypress",c))})}function Zt(){return Kn.menu&&process.stdin.isTTY?"Press Esc or Enter to stop and go back to the menu (Ctrl+C quits).":"Press Ctrl+C to stop."}var Kn,Vn=v(()=>{"use strict";f();Kn={menu:!1}});function ge(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function cu(e){let t=e,n=t.match(/<body[^>]*>([\s\S]*?)<\/body>/i);return n&&(t=n[1]),t.replace(/<!DOCTYPE[^>]*>/gi,"").replace(/<\/?(?:html|head|body)[^>]*>/gi,"").replace(/<link\b[^>]*>/gi,"").replace(/<style[\s\S]*?<\/style>/gi,"").replace(/<script[\s\S]*?<\/script>/gi,"").replace(/<!--[\s\S]*?-->/g,"").trim()}function Xn(e){let{blockName:t}=e,n=cu(e.sampleContent);return`<!DOCTYPE html>
|
|
776
782
|
<html lang="en">
|
|
777
783
|
<head>
|
|
778
784
|
<meta charset="utf-8" />
|
|
@@ -808,19 +814,19 @@ ${n}
|
|
|
808
814
|
try { new EventSource('/__eds_events').onmessage = () => location.reload(); } catch (e) { /* no SSE */ }
|
|
809
815
|
</script>
|
|
810
816
|
</body>
|
|
811
|
-
</html>`}function
|
|
817
|
+
</html>`}function lu(e){let t=e.filter(n=>n.figma);return(t.length?t:e).reduce((n,o)=>o.width>n.width?o:n,e[0])}function Ec(e){let t=e.map((o,i)=>{let r=lu(o.breakpoints),s=o.breakpoints.map(d=>`<option value="${d.width}"${d.width===r.width?" selected":""}>${ge(d.label)}</option>`).join(""),c=o.figmaUrl?`<a class="figma-link" href="${ge(o.figmaUrl)}" target="_blank" rel="noopener">Figma \u2197</a>`:"",l=o.placeholder?'<span class="hint">placeholder content</span>':"";return`<section class="card">
|
|
812
818
|
<div class="cardbar">
|
|
813
|
-
<span class="block">${
|
|
819
|
+
<span class="block">${ge(o.blockName)}</span>
|
|
814
820
|
<select class="bp" data-i="${i}">
|
|
815
821
|
${s}
|
|
816
822
|
<option value="full">Full</option>
|
|
817
823
|
</select>
|
|
818
|
-
${c}
|
|
819
824
|
${l}
|
|
825
|
+
${c}
|
|
820
826
|
</div>
|
|
821
827
|
<div class="stage">
|
|
822
828
|
<div class="device" data-i="${i}" data-w="${r.width}" style="width:${r.width}px">
|
|
823
|
-
<iframe src="${
|
|
829
|
+
<iframe src="${ge(o.frameRoute)}" title="${ge(o.blockName)} preview" loading="lazy"></iframe>
|
|
824
830
|
</div>
|
|
825
831
|
</div>
|
|
826
832
|
</section>`}).join(`
|
|
@@ -869,8 +875,8 @@ ${n}
|
|
|
869
875
|
try { new EventSource('/__eds_events').onmessage = () => location.reload(); } catch (e) { /* no SSE */ }
|
|
870
876
|
</script>
|
|
871
877
|
</body>
|
|
872
|
-
</html>`}function
|
|
873
|
-
`),d=o?`<a class="figma-link" href="${
|
|
878
|
+
</html>`}function Cc(e){let{blockName:t,breakpoints:n,figmaUrl:o,frameRoute:i,placeholder:r}=e,s=n.filter(p=>p.figma),c=(s.length?s:n).reduce((p,u)=>u.width>p.width?u:p,n[0]),l=n.map(p=>`<option value="${p.width}"${p.width===c.width?" selected":""}>${ge(p.label)}</option>`).join(`
|
|
879
|
+
`),d=o?`<a class="figma-link" href="${ge(o)}" target="_blank" rel="noopener">
|
|
874
880
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>
|
|
875
881
|
Open in Figma
|
|
876
882
|
</a>`:"",m=r?`<span class="hint">placeholder content \u2014 add <code>blocks/${t}/_${t}.preview.html</code></span>`:"";return`<!DOCTYPE html>
|
|
@@ -878,7 +884,7 @@ ${n}
|
|
|
878
884
|
<head>
|
|
879
885
|
<meta charset="utf-8" />
|
|
880
886
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
881
|
-
<title>eds preview \u2014 ${
|
|
887
|
+
<title>eds preview \u2014 ${ge(t)}</title>
|
|
882
888
|
<style>
|
|
883
889
|
*{box-sizing:border-box}
|
|
884
890
|
html,body{margin:0;padding:0;background:#1f1f1f;color:#eaeaea;font-family:ui-sans-serif,-apple-system,"Segoe UI",sans-serif}
|
|
@@ -900,18 +906,18 @@ ${n}
|
|
|
900
906
|
</head>
|
|
901
907
|
<body>
|
|
902
908
|
<div class="bar">
|
|
903
|
-
<span class="label">Block</span><span class="block">${
|
|
909
|
+
<span class="label">Block</span><span class="block">${ge(t)}</span>
|
|
904
910
|
<label class="label" for="bp" style="margin-left:8px">Breakpoint</label>
|
|
905
911
|
<select id="bp">
|
|
906
|
-
${
|
|
912
|
+
${l}
|
|
907
913
|
<option value="full">Full ca\u0142a szeroko\u015B\u0107</option>
|
|
908
914
|
</select>
|
|
909
915
|
${m}
|
|
910
916
|
${d}
|
|
911
917
|
</div>
|
|
912
918
|
<div class="stage">
|
|
913
|
-
<div class="device" id="device" data-w="${
|
|
914
|
-
<iframe id="frame" src="${i}" title="${
|
|
919
|
+
<div class="device" id="device" data-w="${c.width}" style="width:${c.width}px">
|
|
920
|
+
<iframe id="frame" src="${i}" title="${ge(t)} preview"></iframe>
|
|
915
921
|
</div>
|
|
916
922
|
</div>
|
|
917
923
|
<script>
|
|
@@ -925,24 +931,25 @@ ${n}
|
|
|
925
931
|
setWidth(Number(bp.value));
|
|
926
932
|
</script>
|
|
927
933
|
</body>
|
|
928
|
-
</html>`}var
|
|
934
|
+
</html>`}var Tc=v(()=>{"use strict";f()});import{createReadStream as du,existsSync as mu,statSync as pu}from"fs";import uu from"http";import Di from"path";function Yn(e,t,n,o="127.0.0.1",i){let r=Di.resolve(e),s=new Set,c=uu.createServer(async(l,d)=>{let m=decodeURIComponent((l.url??"/").split("?")[0]);if(m===gu){d.writeHead(200,{"content-type":"application/json"}),d.end(JSON.stringify({eds:!0}));return}if(m===hu){d.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"}),d.write(`: connected
|
|
929
935
|
|
|
930
|
-
`),s.add(d),
|
|
936
|
+
`),s.add(d),l.on("close",()=>s.delete(d));return}let p=t[m];if(p){d.writeHead(200,{"content-type":p.type}),d.end(p.body);return}if(i)try{let g=await i(m);if(g){d.writeHead(200,{"content-type":g.type}),d.end(g.body);return}}catch(g){d.writeHead(500,{"content-type":"text/plain"}),d.end(`Preview error: ${g instanceof Error?g.message:String(g)}`);return}let u=Di.join(r,m);if(!u.startsWith(r)){d.writeHead(403),d.end("Forbidden");return}if(!mu(u)||!pu(u).isFile()){d.writeHead(404,{"content-type":"text/plain"}),d.end(`Not found: ${m}`);return}d.writeHead(200,{"content-type":fu[Di.extname(u).toLowerCase()]??"application/octet-stream"}),du(u).pipe(d)});return new Promise((l,d)=>{let m=0,p=u=>{c.once("error",g=>{g.code==="EADDRINUSE"&&m<10?(m++,p(u+1)):d(g)}),c.listen(u,o,()=>{l({url:`http://${o}:${u}/`,port:u,reload:()=>{for(let g of s)g.write(`data: reload
|
|
931
937
|
|
|
932
|
-
`)},close:()=>new Promise(g=>{for(let h of s)h.end();
|
|
938
|
+
`)},close:()=>new Promise(g=>{for(let h of s)h.end();c.close(()=>g())})})})};p(n)})}var fu,gu,hu,Ac=v(()=>{"use strict";f();fu={".html":"text/html; charset=utf-8",".js":"text/javascript; charset=utf-8",".mjs":"text/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".avif":"image/avif",".woff":"font/woff",".woff2":"font/woff2",".ico":"image/x-icon"},gu="/__eds_ping",hu="/__eds_events"});var gt={};U(gt,{FRAME_PREFIX:()=>Re,galleryPreview:()=>$u,listPreviewableBlocks:()=>Ke,loadBlockForPreview:()=>ye,previewBlock:()=>xu,startFrameServer:()=>ft,startPreview:()=>Nc});import{existsSync as le,watch as Rc}from"fs";import{readFile as en,readdir as wu}from"fs/promises";import ee from"path";import Ae from"chalk";function Fi(e){return e<=480?`${e} mobile`:e<=1024?`${e} tablet`:`${e} desktop`}function Dc(e,t){if(e){let o=e.split(",").map(i=>Number.parseInt(i.trim(),10)).filter(i=>Number.isFinite(i)&&i>0);if(o.length)return o.map(i=>({width:i,label:Fi(i),figma:!1}))}let n=t?.breakpoints;return Array.isArray(n)&&n.length?n.map(o=>({width:Number(o.width),label:typeof o.label=="string"?o.label:Fi(Number(o.width)),figma:o.source==="figma"||o.source==="scrape"})).filter(o=>Number.isFinite(o.width)&&o.width>0):yu.map(o=>({width:o,label:Fi(o),figma:!1}))}function Fc(e){if(!e?.figmaFileKey||typeof e.figmaFileKey!="string")return;let t=typeof e.figmaNodeId=="string"?e.figmaNodeId.replace(":","-"):void 0,n=`https://www.figma.com/design/${e.figmaFileKey}/preview`;return t?`${n}?node-id=${t}`:n}function Lc(e){return`<div class="${e} block">
|
|
933
939
|
<div><div>
|
|
934
940
|
<h2>${e} heading</h2>
|
|
935
941
|
<p>Sample body copy for the preview. Replace with real authored content.</p>
|
|
936
942
|
<p><a href="#">Primary action</a></p>
|
|
937
943
|
<p><a href="#">Secondary action</a></p>
|
|
938
944
|
</div></div>
|
|
939
|
-
</div>`}async function
|
|
940
|
-
`)),await
|
|
941
|
-
`)),e.open!==!1&&await ic(r.url),await Ut(async()=>{c.close(),await r.close()})}var _p,Ip,Ae,qe=k(()=>{"use strict";f();D();Qs();Zs();K();Fn();B();_p=new Set(["header","footer"]),Ip=[375,768,1280];Ae="/__eds_frame/"});var fi={};_(fi,{blockFromDesign:()=>Vp,detectProvider:()=>sc});import{existsSync as me}from"fs";import{readFile as Re,writeFile as Hp}from"fs/promises";import V from"path";import{fileURLToPath as Gp}from"url";import S from"chalk";import Nn from"ora";function Wp(){let e=V.dirname(Gp(import.meta.url));return[V.resolve(e,"../../samples/hero.svg"),V.resolve(e,"../../../samples/hero.svg")].find(n=>me(n))??null}async function zp(e=8777){try{let t=new AbortController,n=setTimeout(()=>t.abort(),400),o=await fetch(`http://127.0.0.1:${e}/__eds_ping`,{signal:t.signal});return clearTimeout(n),o.ok?(await o.json())?.eds===!0:!1}catch{return!1}}async function Jp(e){let{input:t,select:n,confirm:o}=await Promise.resolve().then(()=>(z(),W)),i=await n({message:"1/7 Design source",choices:[{name:"Figma (REST / MCP / local)",value:"figma"},{name:"Framer (scraped, headless Chromium)",value:"framer"},{name:"Google Stitch (scraped, headless Chromium)",value:"stitch"},{name:"Any web page (a live site or HTML mock-up, scraped)",value:"web"}],default:"figma"}),r=await t({message:"2/7 Component name",validate:b=>Ne.test(b.trim())||"Use kebab-case, e.g. hero-banner"}),s=e??await t({message:`3/7 ${ct[i]} link`,validate:b=>{if(!b.trim())return"Paste the design link";if(i!=="figma")return/^https?:\/\//i.test(b.trim())||"Paste a public http(s) URL to the page";try{return An(b.trim()),!0}catch(T){return T.message}}}),l=await n({message:"4/7 Where does the content come from?",choices:[{name:"Document authoring (default EDS)",value:"document"},{name:"Universal Editor",value:"ue"},{name:"Content Fragment",value:"cf"},{name:"Mixed - Universal Editor + Content Fragment",value:"mixed"}],default:"document"}),c;(l==="cf"||l==="mixed")&&(c=(await t({message:" CF model / GraphQL persisted-query name (optional)"})).trim()||void 0);let d=await o({message:"5/7 Generate the Universal Editor model?",default:!0}),m=await o({message:"6/7 Add a screenshot MCP call for a pixel check? (off = one fewer MCP call)",default:!1}),p=await Pn(),u=await n({message:"7/7 Run with",choices:[...p.map(b=>({name:b.model?`${b.type} \xB7 ${b.model} (local)`:`${b.type}${i==="figma"&&!b.hasFigmaMcp?" (Figma MCP not detected)":""}`,value:`agent:${b.type}`})),{name:"Preview the prompt only (--dry-run)",value:"dry-run"},{name:"Save the prompt, run it later (--agent none)",value:"none"}],default:p[0]?`agent:${p[0].type}`:"dry-run"}),g=ct[i].toLowerCase();a.info(j("Summary"));let h=U(["component",g,"content","ue model","screenshot","run"]);a.info(P("component",r,h));let v=i==="figma"?(()=>{let b=An(s.trim());return b.nodeId?`node ${b.nodeId}`:b.fileKey})():s.trim();if(a.info(P(g,v,h)),a.info(P("content",l+(c?` (${c})`:""),h)),a.info(P("ue model",d?"yes":"no",h)),a.info(P("screenshot",m?"yes":"no (token-lean)",h)),a.info(P("run",u.replace("agent:",""),h)),a.info(""),!await o({message:"Generate this block?",default:!0}))return null;let y={figmaUrl:s.trim(),name:r,provider:i,source:l,cfHint:c,ueModel:d,screenshot:m};return u==="dry-run"?y.dryRun=!0:u==="none"?y.agent="none":(y.agent=u.replace("agent:",""),y.yes=!0),y}function ui(e){return e&&e.replace(/[-_\s]+/g,"-").replace(/[^a-z0-9-]/gi,"").toLowerCase().replace(/^-+|-+$/g,"")||"design-block"}function qp(e){try{let t=new URL(e);return t.pathname.split("/").filter(Boolean).pop()||t.hostname.split(".")[0]}catch{return""}}function sc(e){if(e)try{let t=new URL(e),n=t.hostname.toLowerCase();if(n.includes("figma.com"))return"figma";if(n.includes("framer"))return"framer";if(n.includes("stitch"))return"stitch";if(t.protocol==="http:"||t.protocol==="https:")return"web"}catch{}}function Xp(e){if(/^[a-z][a-z0-9+.-]*:\/\//i.test(e))return null;let t=V.isAbsolute(e)?e:V.resolve(process.cwd(),e);return!me(t)||!Kp.has(V.extname(t).toLowerCase())?null:t}async function Vp(e,t){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found). Run this from your project root."),process.exitCode=1;return}await a.logoOnceAnimated("Design \u2192 EDS block");let o=e,i=t;if(!o&&i.sample){let N=Wp();if(!N){a.error("Bundled sample design not found (samples/hero.svg)."),process.exitCode=1;return}o=N,i={name:"hero",provider:"figma",...i},a.info(` ${X.pass} Sample design ${S.dim("aem-eds-kit example hero")} ${S.dim("(bundled \xB7 no token \xB7 no MCP)")}`)}if(!o){let N=await Jp(o);if(!N){a.info("Cancelled.");return}o=N.figmaUrl,i={...i,...N}}let r=i.provider;if(r&&!(r in ct)){a.error(`Unknown --provider "${r}". Use: figma, framer, stitch or web.`),process.exitCode=1;return}if(i.source&&!ac.includes(i.source)){a.error(`Unknown --source "${i.source}". Use: ${ac.join(", ")}.`),process.exitCode=1;return}let s=r??sc(o)??"figma",l=ct[s],c=Xp(o),d=c?c.startsWith(n+V.sep)?V.relative(n,c):c:void 0,m=null,p=d??o;if(c)a.info(` ${X.pass} Local design file ${S.dim(d)} ${S.dim("(no Figma MCP)")}`);else if(s==="figma"){let N=Nn("Parsing Figma URL...").start();try{m=An(o),N.succeed(`Parsed Figma URL ${S.dim(m.nodeId?`node ${m.nodeId}`:`file ${m.fileKey}`)}`)}catch(pe){N.fail(pe.message),process.exitCode=1;return}}else a.info(` ${X.pass} ${l} design ${S.dim(p)}`);let u=i.name||(c?ui(V.basename(c,V.extname(c))):m?ui(m.fileName):o?ui(qp(o)):"");if(!Ne.test(u)){a.error(`Invalid block name "${u}". Use --name with a kebab-case name (e.g., --name hero-banner).`),process.exitCode=1;return}!i.name&&m?.nodeId&&(a.warn(`Block name "${u}" came from the Figma file name, not the selected frame.`),a.info(S.dim(` Pass ${S.cyan("--name <kebab-case>")} for a cleaner block name.`)));let g=await le(n),h=g.figma?.token??process.env.FIGMA_TOKEN??process.env.FIGMA_PAT,v;if(li(s)&&!c&&!i.dryRun&&(i.auth||i.authRefresh))if(v=di(s),i.authRefresh||!Js(s)){let N=(()=>{try{return new URL(o).origin}catch{return o}})();a.info(` ${S.dim("\u2192")} Opening ${S.cyan(l)} \u2014 click ${S.cyan("Sign In")} and log in, then come back here.`);let{input:pe}=await Promise.resolve().then(()=>(z(),W));try{await qs(v),await js({loginUrl:N,statePath:v,projectRoot:n,waitForUser:async()=>{await pe({message:"Press Enter once you're signed in (you don't need to open the design)"})}}),await Ks(v),a.info(` ${X.pass} Session saved ${S.dim(v)}`)}catch(se){a.error(`Could not capture the ${l} session: ${se instanceof Error?se.message:String(se)}`),process.exitCode=1;return}}else a.info(` ${X.pass} Using saved ${l} session ${S.dim(v)} ${S.dim("(--auth-refresh to re-login)")}`);let w=Nn("Resolving design source...").start(),y=await _s({figma:m,localFile:d,token:h,projectRoot:n,preferMcp:i.mcp,refresh:i.refresh,provider:s,designUrl:c?void 0:o,storageStatePath:v,dryRun:i.dryRun,restPerMinute:g.figma?.restPerMinute,onRestWait:N=>{w.text=`Resolving design source... waiting ${Math.ceil(N/1e3)} s for a Figma REST slot (${g.figma?.restPerMinute??ii}/min)`}});if(y.scrapeError){w.fail(`Scrape failed: ${y.scrapeError}`),a.info(S.dim(` Check the URL is a public ${l} page, and that Chromium is installed (${S.cyan("npx playwright install chromium")}).`)),process.exitCode=1;return}if(y.rateLimit){w.fail(y.rateLimit.message),a.info(S.dim(" The limit follows the plan that owns the file: 20 calls/month on Starter or with a View/Collab seat, 10-20/min with a Dev/Full seat on a paid plan.")),a.info(S.dim(` Not falling back to Figma MCP (its budget is the same or smaller). Re-run after the reset, pass ${S.cyan("--mcp")} to spend an MCP call instead, or export the frame as PNG/SVG (no quota).`)),y.rateLimit.upgradeLink&&a.info(S.dim(` Plan details: ${y.rateLimit.upgradeLink}`)),process.exitCode=1;return}if(w.succeed(`Design source ${S.dim(y.summary)}`),y.restError&&a.warn(`Figma REST fetch failed, using MCP fallback: ${y.restError}`),y.design?.mode==="scrape"&&!i.dryRun)try{let N=JSON.parse(y.design.spec),pe=(N.title??"").toLowerCase(),se=y.design.spec.toLowerCase(),Xt=/isn'?t shared|doesn'?t exist|page not found|\b404\b/;(Xt.test(pe)||Xt.test(se)||/\bsign[ -]?in\b|\blog[ -]?in\b/.test(pe)||(N.nodeCount??0)<8)&&(a.warn(`The scraped page looks like a login / error shell${N.title?` ("${N.title}")`:""} \u2014 the design may be gated or the URL wrong.`),a.info(S.dim(` Use ${S.cyan("--auth")} to log in once (or ${S.cyan("--auth-refresh")} to re-login), and confirm the URL opens the design when you're signed in.`)))}catch{}let b=Nn("Reading design tokens & building prompt...").start(),T=await Hs({provider:s,figma:m,designRef:p,blockName:u,projectRoot:n,withUeModel:i.ueModel!==!1,contentSource:i.source??"document",cfHint:i.cfHint,screenshot:i.screenshot===!0,design:y.design}),O=await ti(T,n),H=me(V.join(n,"styles","styles.css"));if(b.succeed(H?`Loaded design tokens ${S.dim("styles/styles.css")}`:`Built prompt ${S.dim("no project tokens found")}`),a.info(S.dim(` prompt \u2192 ${O}`)),i.dryRun){a.info(""),a.info(S.yellow("Dry run mode \u2014 prompt generated but agent not invoked.")),a.info(`Prompt file: ${S.cyan(O)}`),a.info(`Block name: ${S.cyan(u)}`),a.info(`Prompt version: ${It}`),a.info(""),a.info("Preview:"),a.info(S.dim("\u2500".repeat(60))),console.log(T);return}let ae=i.agent||g.agent;if(i.agent==="none"){a.info("Agent skipped (--agent none). Use the prompt file manually:"),a.info(` ${S.cyan(O)}`);return}let De=Nn("Detecting AI agent...").start(),L=await us(ae);if(!L){De.fail("No AI agent found (claude, cursor, codex, or a local Ollama / oMLX server)."),a.info(`Install Claude Code: ${S.cyan("npm install -g @anthropic-ai/claude-code")}`),a.info(`Or run a local model: ${S.cyan("ollama serve")} / ${S.cyan("omlx start")}, then ${S.cyan("--agent ollama")} or ${S.cyan("--agent omlx")}.`),a.info(`Or use the prompt file manually: ${S.cyan(O)}`),process.exitCode=1;return}let xe=ze(L.type);De.succeed(`Agent ready ${S.cyan(L.type)} ${S.dim(xe?`${i.model??L.model} \xB7 ${L.path}`:L.path)}`);let Bi=y.design?.mode==="mcp"||!y.design&&s==="figma";if(xe&&Bi){a.error("A local model can't read a Figma design through MCP."),a.info(S.dim(` Set a Figma token (${S.cyan("FIGMA_TOKEN")}) so eds fetches it over REST, export the frame as PNG/SVG, or scrape a Framer / Stitch page. Prompt saved: ${O}`)),process.exitCode=1;return}if(Bi&&s==="figma"&&!L.hasFigmaMcp&&(a.warn(`Figma MCP may not be configured for ${L.type}.`),a.info(`Run ${S.cyan("eds figma setup")} to configure it, or set a Figma token for REST.`)),!i.yes){let{confirm:N}=await Promise.resolve().then(()=>(z(),W));if(!await N({message:`Run ${L.type} with the generated prompt?`,default:!0})){a.info(`Prompt saved to: ${S.cyan(O)}`);return}}let Wc=y.design?.mode==="spec"?"embedded design (no MCP)":y.design?.mode==="scrape"?`scraped ${l} page (no MCP)`:y.design?.mode==="file"?`reading ${d}`:y.design?.mode==="mcp"?`via ${l} MCP (1 call, cached)`:`via ${l} MCP`;a.info(` ${S.dim("\u2192")} Handing off to ${S.cyan(L.type)} ${S.dim(Wc)}`),y.design?.mode==="mcp"&&a.info(S.dim(" get_design_context \xD71 \u2192 cache"));let zc=i.source==="cf"||i.source==="mixed",Wn=xe?i.model??L.model:i.model??g.model??(zc&&L.type==="claude"?"sonnet":void 0);Wn&&!xe&&!i.model&&!g.model&&a.info(S.dim(` Model: ${Wn} (Content Fragment source)`));let Jc={blockName:u,designFile:y.design?.mode==="file"?d:void 0,contextTokens:g.local?.contextTokens,apiKey:g.local?.apiKey};if(!await ni(L,O,n,Wn,Jc)){process.exitCode=1;return}let gt=V.join(n,"blocks",u);if(!(me(V.join(gt,`${u}.js`))||me(V.join(gt,`${u}.css`)))){a.warn(`No block files were written to blocks/${u}/ \u2014 nothing to preview.`),y.design?.mode==="mcp"&&!L.hasFigmaMcp?(a.info(S.dim(` The agent couldn't read the design: no ${l} MCP is configured for ${L.type}.`)),a.info(S.dim(` Run ${S.cyan("eds figma setup")}, or set a Figma token (FIGMA_TOKEN) to use REST, then re-run.`))):y.design?.mode==="mcp"?(a.info(S.dim(" The agent couldn't read the design, so it generated nothing. Common cause: the")),a.info(S.dim(` ${l} MCP tool-call limit (e.g. Figma Starter plan). See the log above.`)),a.info(S.dim(" Wait for the limit to reset or upgrade the plan, then re-run the same command."))):a.info(S.dim(" The agent generated nothing \u2014 see the log above for why.")),process.exitCode=1;return}let qc=await Qp(gt,u,i.ueModel!==!1,i.source??"document");if(me(gt)){let N=V.join(gt,".eds-meta.json"),pe;if(me(N))try{pe=JSON.parse(await Re(N,"utf-8")).breakpoints}catch{}let se=vs(i.widths,pe),Xt={provider:s,designRef:p,figmaFileKey:m?.fileKey??null,figmaNodeId:m?.nodeId??null,lastSyncedAt:new Date().toISOString(),promptVersion:It,agentUsed:L.type,...se.length?{breakpoints:se}:{}};await Hp(N,`${JSON.stringify(Xt,null,2)}
|
|
942
|
-
`),
|
|
943
|
-
`)),await
|
|
944
|
-
|
|
945
|
-
npm i -D playwright && npx playwright install chromium`,
|
|
945
|
+
</div>`}async function ye(e,t,n){let o=ee.join(e,"blocks",t);if(!le(ee.join(o,`${t}.css`))&&!le(ee.join(o,`${t}.js`)))return null;let i=null,r=ee.join(o,".eds-meta.json");if(le(r))try{i=JSON.parse(await en(r,"utf-8"))}catch{}let s=ee.join(o,`_${t}.preview.html`),c,l=!1;return le(s)?c=await en(s,"utf-8"):(c=Lc(t),l=!0),{name:t,sampleContent:c,breakpoints:Dc(n,i),figmaUrl:Fc(i),placeholder:l}}async function ft(e,t,n){return Yn(e,{},n,"127.0.0.1",async i=>{if(!i.startsWith(Re))return;let r=i.slice(Re.length);if(!/^[a-z0-9-]+$/i.test(r))return;let s=await ye(e,r,t);if(s)return{body:Xn({blockName:r,breakpoints:s.breakpoints,sampleContent:s.sampleContent,frameRoute:Re+r}),type:"text/html; charset=utf-8"}})}async function Ke(e){let t=ee.join(e,"blocks");if(!le(t))return[];let n=await wu(t,{withFileTypes:!0}),o=[];for(let i of n){if(!i.isDirectory()||bu.has(i.name))continue;let r=ee.join(t,i.name);(le(ee.join(r,`${i.name}.css`))||le(ee.join(r,`${i.name}.js`)))&&o.push(i.name)}return o.sort()}async function Oc(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{let{execa:n}=await import("execa");await n(t,[e],{stdio:"ignore",shell:process.platform==="win32"})}catch{}}async function Nc(e,t={}){let n=E();if(!n)return a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1,null;let o=t.blockDir??ee.join(n,"blocks",e);if(!le(o))return a.error(`Block "${e}" not found at ${ee.relative(n,o)}/.`),process.exitCode=1,null;if(!le(ee.join(o,`${e}.css`))&&!le(ee.join(o,`${e}.js`)))return a.error(`Block "${e}" has no ${e}.css / ${e}.js to preview.`),process.exitCode=1,null;(e==="header"||e==="footer")&&(a.warn(`"${e}" is page chrome, not a content block \u2014 it won't render standalone here.`),a.info(Ae.dim(` It fetches the ${e==="header"?"nav":"footer"} fragment and needs the full page runtime.`)),a.info(Ae.dim(" Preview a content block instead (e.g. a block generated from a design).")));let i=null,r=ee.join(o,".eds-meta.json");if(le(r))try{i=JSON.parse(await en(r,"utf-8"))}catch{}let s=ee.join(o,`_${e}.preview.html`),c,l=!1;le(s)?c=await en(s,"utf-8"):(c=Lc(e),l=!0);let d=Dc(t.widths,i),m=Fc(i),p="/__eds_preview_frame",u=Xn({blockName:e,breakpoints:d,sampleContent:c,frameRoute:p}),g=Cc({blockName:e,breakpoints:d,sampleContent:c,figmaUrl:m,frameRoute:p,placeholder:l}),h=Number.parseInt(t.port??"8777",10),$=t.blockDir,w=$?async F=>{let N=`/blocks/${e}/`;if(!F.startsWith(N))return;let te=ee.join($,F.slice(N.length));if(!(!te.startsWith($)||!le(te)))return{body:await en(te,"utf-8"),type:ku(te)}}:void 0,y=await Yn(n,{"/":{body:g,type:"text/html; charset=utf-8"},[p]:{body:u,type:"text/html; charset=utf-8"}},Number.isFinite(h)?h:8777,void 0,w);a.logoOnce(A(`Preview \u2014 ${e}`)),a.info(j("Live preview",y.url)),a.info(R("pass","breakpoints",`${d.map(F=>`${F.width}${F.figma?"\u2713":""}`).join(", ")}, Full`)),l&&a.info(R("warn","content",`placeholder \u2014 add blocks/${e}/_${e}.preview.html for real content`));let b,T=Rc(o,{recursive:!0},()=>{clearTimeout(b),b=setTimeout(()=>y.reload(),150)});return a.info(""),a.info(` ${Ae.bold("\u279C")} ${Ae.cyan(y.url)}`),a.info(R("pass","live reload","edits to the block refresh the browser")),t.open!==!1&&await Oc(y.url),{url:y.url,close:async()=>{T.close(),await y.close()}}}async function xu(e,t={}){let n=await Nc(e,t);n&&(a.info(Ae.dim(` ${Zt()}
|
|
946
|
+
`)),await Qt(n.close))}async function $u(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n="/__eds_frame/",o=async d=>{if(d==="/"){let m=await Ke(t),p=[];for(let u of m){let g=await ye(t,u,e.widths);g&&p.push({blockName:u,breakpoints:g.breakpoints,frameRoute:n+u,figmaUrl:g.figmaUrl,placeholder:g.placeholder})}return{body:Ec(p),type:"text/html; charset=utf-8"}}if(d.startsWith(n)){let m=d.slice(n.length);if(!/^[a-z0-9-]+$/i.test(m))return;let p=await ye(t,m,e.widths);return p?{body:Xn({blockName:m,breakpoints:p.breakpoints,sampleContent:p.sampleContent,frameRoute:n+m}),type:"text/html; charset=utf-8"}:void 0}},i=Number.parseInt(e.port??"8777",10),r=await Yn(t,{},Number.isFinite(i)?i:8777,"127.0.0.1",o),s=await Ke(t);a.logoOnce(A("Preview \u2014 gallery")),a.info(j("Live gallery",r.url)),a.info(R(s.length?"pass":"warn","blocks",s.length?s.join(", "):"none yet \u2014 generate one with eds block from-design"));let c,l=Rc(ee.join(t,"blocks"),{recursive:!0},()=>{clearTimeout(c),c=setTimeout(()=>r.reload(),150)});a.info(""),a.info(` ${Ae.bold("\u279C")} ${Ae.cyan(r.url)}`),a.info(R("pass","live reload","new & edited blocks refresh the browser")),a.info(Ae.dim(` ${Zt()}
|
|
947
|
+
`)),e.open!==!1&&await Oc(r.url),await Qt(async()=>{l.close(),await r.close()})}var bu,yu,vu,ku,Re,De=v(()=>{"use strict";f();O();Tc();Ac();K();Vn();B();bu=new Set(["header","footer"]),yu=[375,768,1280],vu={".css":"text/css; charset=utf-8",".js":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".html":"text/html; charset=utf-8",".svg":"image/svg+xml"},ku=e=>vu[ee.extname(e).toLowerCase()]??"text/plain";Re="/__eds_frame/"});var Zn={};U(Zn,{blockFromDesign:()=>Du,detectProvider:()=>Ic,generateDraft:()=>_c,verifyGeneratedBlock:()=>Ni,writeBlockMeta:()=>Oi});import{existsSync as ce}from"fs";import{readFile as Fe,writeFile as Su}from"fs/promises";import V from"path";import{fileURLToPath as ju}from"url";import S from"chalk";import Qn from"ora";function Pu(){let e=V.dirname(ju(import.meta.url));return[V.resolve(e,"../../samples/hero.svg"),V.resolve(e,"../../../samples/hero.svg")].find(n=>ce(n))??null}async function Eu(e=8777){try{let t=new AbortController,n=setTimeout(()=>t.abort(),400),o=await fetch(`http://127.0.0.1:${e}/__eds_ping`,{signal:t.signal});return clearTimeout(n),o.ok?(await o.json())?.eds===!0:!1}catch{return!1}}async function Cu(e){let{input:t,select:n,confirm:o}=await Promise.resolve().then(()=>(q(),J)),i=await n({message:"1/7 Design source",choices:[{name:"Figma (REST / MCP / local)",value:"figma"},{name:"Framer (scraped, headless Chromium)",value:"framer"},{name:"Google Stitch (scraped, headless Chromium)",value:"stitch"},{name:"Any web page (a live site or HTML mock-up, scraped)",value:"web"}],default:"figma"}),r=await t({message:"2/7 Component name",validate:b=>_e.test(b.trim())||"Use kebab-case, e.g. hero-banner"}),s=e??await t({message:`3/7 ${ut[i]} link`,validate:b=>{if(!b.trim())return"Paste the design link";if(i!=="figma")return/^https?:\/\//i.test(b.trim())||"Paste a public http(s) URL to the page";try{return Jn(b.trim()),!0}catch(T){return T.message}}}),c=await n({message:"4/7 Where does the content come from?",choices:[{name:"Document authoring (default EDS)",value:"document"},{name:"Universal Editor",value:"ue"},{name:"Content Fragment",value:"cf"},{name:"Mixed - Universal Editor + Content Fragment",value:"mixed"}],default:"document"}),l;(c==="cf"||c==="mixed")&&(l=(await t({message:" CF model / GraphQL persisted-query name (optional)"})).trim()||void 0);let d=await o({message:"5/7 Generate the Universal Editor model?",default:!0}),m=await o({message:"6/7 Add a screenshot MCP call for a pixel check? (off = one fewer MCP call)",default:!1}),p=await Un(),u=await n({message:"7/7 Run with",choices:[...p.map(b=>({name:b.model?`${b.type} \xB7 ${b.model} (local)`:`${b.type}${i==="figma"&&!b.hasFigmaMcp?" (Figma MCP not detected)":""}`,value:`agent:${b.type}`})),{name:"Preview the prompt only (--dry-run)",value:"dry-run"},{name:"Save the prompt, run it later (--agent none)",value:"none"}],default:p[0]?`agent:${p[0].type}`:"dry-run"}),g=ut[i].toLowerCase();a.info(j("Summary"));let h=_(["component",g,"content","ue model","screenshot","run"]);a.info(P("component",r,h));let $=i==="figma"?(()=>{let b=Jn(s.trim());return b.nodeId?`node ${b.nodeId}`:b.fileKey})():s.trim();if(a.info(P(g,$,h)),a.info(P("content",c+(l?` (${l})`:""),h)),a.info(P("ue model",d?"yes":"no",h)),a.info(P("screenshot",m?"yes":"no (token-lean)",h)),a.info(P("run",u.replace("agent:",""),h)),a.info(""),!await o({message:"Generate this block?",default:!0}))return null;let y={figmaUrl:s.trim(),name:r,provider:i,source:c,cfHint:l,ueModel:d,screenshot:m};return u==="dry-run"?y.dryRun=!0:u==="none"?y.agent="none":(y.agent=u.replace("agent:",""),y.yes=!0),y}function Li(e){return e&&e.replace(/[-_\s]+/g,"-").replace(/[^a-z0-9-]/gi,"").toLowerCase().replace(/^-+|-+$/g,"")||"design-block"}function Tu(e){try{let t=new URL(e);return t.pathname.split("/").filter(Boolean).pop()||t.hostname.split(".")[0]}catch{return""}}function Ic(e){if(e)try{let t=new URL(e),n=t.hostname.toLowerCase();if(n.includes("figma.com"))return"figma";if(n.includes("framer"))return"framer";if(n.includes("stitch"))return"stitch";if(t.protocol==="http:"||t.protocol==="https:")return"web"}catch{}}function Ru(e){if(/^[a-z][a-z0-9+.-]*:\/\//i.test(e))return null;let t=V.isAbsolute(e)?e:V.resolve(process.cwd(),e);return!ce(t)||!Au.has(V.extname(t).toLowerCase())?null:t}async function Du(e,t){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found). Run this from your project root."),process.exitCode=1;return}await a.logoOnceAnimated("Design \u2192 EDS block");let o=e,i=t;if(!o&&i.sample){let M=Pu();if(!M){a.error("Bundled sample design not found (samples/hero.svg)."),process.exitCode=1;return}o=M,i={name:"hero",provider:"figma",...i},a.info(` ${X.pass} Sample design ${S.dim("aem-eds-kit example hero")} ${S.dim("(bundled \xB7 no token \xB7 no MCP)")}`)}if(!o){let M=await Cu(o);if(!M){a.info("Cancelled.");return}o=M.figmaUrl,i={...i,...M}}let r=i.provider;if(r&&!(r in ut)){a.error(`Unknown --provider "${r}". Use: figma, framer, stitch or web.`),process.exitCode=1;return}if(i.source&&!Mc.includes(i.source)){a.error(`Unknown --source "${i.source}". Use: ${Mc.join(", ")}.`),process.exitCode=1;return}let s=r??Ic(o)??"figma",c=ut[s],l=Ru(o),d=l?l.startsWith(n+V.sep)?V.relative(n,l):l:void 0,m=null,p=d??o;if(l)a.info(` ${X.pass} Local design file ${S.dim(d)} ${S.dim("(no Figma MCP)")}`);else if(s==="figma"){let M=Qn("Parsing Figma URL...").start();try{m=Jn(o),M.succeed(`Parsed Figma URL ${S.dim(m.nodeId?`node ${m.nodeId}`:`file ${m.fileKey}`)}`)}catch(xe){M.fail(xe.message),process.exitCode=1;return}}else a.info(` ${X.pass} ${c} design ${S.dim(p)}`);let u=i.name||(l?Li(V.basename(l,V.extname(l))):m?Li(m.fileName):o?Li(Tu(o)):"");if(!_e.test(u)){a.error(`Invalid block name "${u}". Use --name with a kebab-case name (e.g., --name hero-banner).`),process.exitCode=1;return}!i.name&&m?.nodeId&&(a.warn(`Block name "${u}" came from the Figma file name, not the selected frame.`),a.info(S.dim(` Pass ${S.cyan("--name <kebab-case>")} for a cleaner block name.`)));let g=await se(n),h=g.figma?.token??process.env.FIGMA_TOKEN??process.env.FIGMA_PAT,$;if(Ti(s)&&!l&&!i.dryRun&&(i.auth||i.authRefresh))if($=Ri(s),i.authRefresh||!$c(s)){let M=(()=>{try{return new URL(o).origin}catch{return o}})();a.info(` ${S.dim("\u2192")} Opening ${S.cyan(c)} \u2014 click ${S.cyan("Sign In")} and log in, then come back here.`);let{input:xe}=await Promise.resolve().then(()=>(q(),J));try{await Sc($),await ic({loginUrl:M,statePath:$,projectRoot:n,waitForUser:async()=>{await xe({message:"Press Enter once you're signed in (you don't need to open the design)"})}}),await jc($),a.info(` ${X.pass} Session saved ${S.dim($)}`)}catch(Me){a.error(`Could not capture the ${c} session: ${Me instanceof Error?Me.message:String(Me)}`),process.exitCode=1;return}}else a.info(` ${X.pass} Using saved ${c} session ${S.dim($)} ${S.dim("(--auth-refresh to re-login)")}`);let w=Qn("Resolving design source...").start(),y=await wc({figma:m,localFile:d,token:h,projectRoot:n,preferMcp:i.mcp,refresh:i.refresh,provider:s,designUrl:l?void 0:o,storageStatePath:$,dryRun:i.dryRun,restPerMinute:g.figma?.restPerMinute,onRestWait:M=>{w.text=`Resolving design source... waiting ${Math.ceil(M/1e3)} s for a Figma REST slot (${g.figma?.restPerMinute??Si}/min)`}});if(y.scrapeError){w.fail(`Scrape failed: ${y.scrapeError}`),a.info(S.dim(` Check the URL is a public ${c} page, and that Chromium is installed (${S.cyan("npx playwright install chromium")}).`)),process.exitCode=1;return}if(y.rateLimit){w.fail(y.rateLimit.message),a.info(S.dim(" The limit follows the plan that owns the file: 20 calls/month on Starter or with a View/Collab seat, 10-20/min with a Dev/Full seat on a paid plan.")),a.info(S.dim(` Not falling back to Figma MCP (its budget is the same or smaller). Re-run after the reset, pass ${S.cyan("--mcp")} to spend an MCP call instead, or export the frame as PNG/SVG (no quota).`)),y.rateLimit.upgradeLink&&a.info(S.dim(` Plan details: ${y.rateLimit.upgradeLink}`)),process.exitCode=1;return}if(w.succeed(`Design source ${S.dim(y.summary)}`),y.restError&&a.warn(`Figma REST fetch failed, using MCP fallback: ${y.restError}`),y.design?.mode==="scrape"&&!i.dryRun)try{let M=JSON.parse(y.design.spec),xe=(M.title??"").toLowerCase(),Me=y.design.spec.toLowerCase(),pr=/isn'?t shared|doesn'?t exist|page not found|\b404\b/;(pr.test(xe)||pr.test(Me)||/\bsign[ -]?in\b|\blog[ -]?in\b/.test(xe)||(M.nodeCount??0)<8)&&(a.warn(`The scraped page looks like a login / error shell${M.title?` ("${M.title}")`:""} \u2014 the design may be gated or the URL wrong.`),a.info(S.dim(` Use ${S.cyan("--auth")} to log in once (or ${S.cyan("--auth-refresh")} to re-login), and confirm the URL opens the design when you're signed in.`)))}catch{}let b=Qn("Reading design tokens & building prompt...").start(),T=await kc({provider:s,figma:m,designRef:p,blockName:u,projectRoot:n,withUeModel:i.ueModel!==!1,contentSource:i.source??"document",cfHint:i.cfHint,screenshot:i.screenshot===!0,design:y.design}),F=await Jt(T,n),N=ce(V.join(n,"styles","styles.css"));if(b.succeed(N?`Loaded design tokens ${S.dim("styles/styles.css")}`:`Built prompt ${S.dim("no project tokens found")}`),a.info(S.dim(` prompt \u2192 ${F}`)),i.dryRun){a.info(""),a.info(S.yellow("Dry run mode \u2014 prompt generated but agent not invoked.")),a.info(`Prompt file: ${S.cyan(F)}`),a.info(`Block name: ${S.cyan(u)}`),a.info(`Prompt version: ${Yt}`),a.info(""),a.info("Preview:"),a.info(S.dim("\u2500".repeat(60))),console.log(T);return}let te=i.agent||g.agent;if(i.agent==="none"){a.info("Agent skipped (--agent none). Use the prompt file manually:"),a.info(` ${S.cyan(F)}`);return}let Ne=Qn("Detecting AI agent...").start(),D=await _n(te);if(!D){Ne.fail("No AI agent found (claude, cursor, codex, or a local Ollama / oMLX server)."),a.info(`Install Claude Code: ${S.cyan("npm install -g @anthropic-ai/claude-code")}`),a.info(`Or run a local model: ${S.cyan("ollama serve")} / ${S.cyan("omlx start")}, then ${S.cyan("--agent ollama")} or ${S.cyan("--agent omlx")}.`),a.info(`Or use the prompt file manually: ${S.cyan(F)}`),process.exitCode=1;return}let ke=be(D.type);Ne.succeed(`Agent ready ${S.cyan(D.type)} ${S.dim(ke?`${i.model??D.model} \xB7 ${D.path}`:D.path)}`);let dr=y.design?.mode==="mcp"||!y.design&&s==="figma";if(ke&&dr){a.error("A local model can't read a Figma design through MCP."),a.info(S.dim(` Set a Figma token (${S.cyan("FIGMA_TOKEN")}) so eds fetches it over REST, export the frame as PNG/SVG, or scrape a Framer / Stitch page. Prompt saved: ${F}`)),process.exitCode=1;return}if(dr&&s==="figma"&&!D.hasFigmaMcp&&(a.warn(`Figma MCP may not be configured for ${D.type}.`),a.info(`Run ${S.cyan("eds figma setup")} to configure it, or set a Figma token for REST.`)),!i.yes){let{confirm:M}=await Promise.resolve().then(()=>(q(),J));if(!await M({message:`Run ${D.type} with the generated prompt?`,default:!0})){a.info(`Prompt saved to: ${S.cyan(F)}`);return}}let $l=y.design?.mode==="spec"?"embedded design (no MCP)":y.design?.mode==="scrape"?`scraped ${c} page (no MCP)`:y.design?.mode==="file"?`reading ${d}`:y.design?.mode==="mcp"?`via ${c} MCP (1 call, cached)`:`via ${c} MCP`;a.info(` ${S.dim("\u2192")} Handing off to ${S.cyan(D.type)} ${S.dim($l)}`),y.design?.mode==="mcp"&&a.info(S.dim(" get_design_context \xD71 \u2192 cache"));let Sl=i.source==="cf"||i.source==="mixed",$t=ke?i.model??D.model:i.model??g.model??(Sl&&D.type==="claude"?"sonnet":void 0);$t&&!ke&&!i.model&&!g.model&&a.info(S.dim(` Model: ${$t} (Content Fragment source)`));let mr={blockName:u,designFile:y.design?.mode==="file"?d:void 0,contextTokens:g.local?.contextTokens,apiKey:g.local?.apiKey};if(i.draft){await _c({projectRoot:n,blockName:u,run:()=>dt(D,F,n,$t,mr),verify:M=>Ni(M,u,i.ueModel!==!1,i.source??"document"),writeMeta:M=>Oi(M,{widths:i.widths,provider:s,designRef:p,figma:m,agentType:D.type}),source:{provider:s,designRef:p,figma:m,agent:D.type,model:$t}});return}if(!await dt(D,F,n,$t,mr)){process.exitCode=1;return}let dn=V.join(n,"blocks",u);if(!(ce(V.join(dn,`${u}.js`))||ce(V.join(dn,`${u}.css`)))){a.warn(`No block files were written to blocks/${u}/ \u2014 nothing to preview.`),y.design?.mode==="mcp"&&!D.hasFigmaMcp?(a.info(S.dim(` The agent couldn't read the design: no ${c} MCP is configured for ${D.type}.`)),a.info(S.dim(` Run ${S.cyan("eds figma setup")}, or set a Figma token (FIGMA_TOKEN) to use REST, then re-run.`))):y.design?.mode==="mcp"?(a.info(S.dim(" The agent couldn't read the design, so it generated nothing. Common cause: the")),a.info(S.dim(` ${c} MCP tool-call limit (e.g. Figma Starter plan). See the log above.`)),a.info(S.dim(" Wait for the limit to reset or upgrade the plan, then re-run the same command."))):a.info(S.dim(" The agent generated nothing \u2014 see the log above for why.")),process.exitCode=1;return}let jl=await Ni(dn,u,i.ueModel!==!1,i.source??"document");if(await Oi(dn,{widths:i.widths,provider:s,designRef:p,figma:m,agentType:D.type}),!jl){a.warn(`Block "${u}" generated with issues \u2014 review the output above before publishing.`),process.exitCode=1;return}if(a.success(`Block "${u}" generation complete.`),!i.yes){let{confirm:M}=await Promise.resolve().then(()=>(q(),J));if(await M({message:"Instrument this block for analytics (dataLayer)?",default:!1})){let{trackBlock:Me}=await Promise.resolve().then(()=>(It(),Mt));await Me(u,{})}}if(!i.yes)await Fu({blockName:u,projectRoot:n,agent:D,model:be(D.type)?i.model??D.model:i.model??g.model,contextTokens:g.local?.contextTokens,apiKey:g.local?.apiKey,provider:s,figma:m,designRef:p});else if(i.serve){let{previewBlock:M}=await Promise.resolve().then(()=>(De(),gt));await M(u,{})}else a.info(` ${S.dim("\u2192")} Next: ${S.cyan(`eds block preview ${u}`)}`)}async function _c(e){let{projectRoot:t,blockName:n}=e,o=V.join(t,"blocks",n),i=await Js(t,n,e.from),r,s;try{let c=await e.run(),l=ce(V.join(o,`${n}.js`))||ce(V.join(o,`${n}.css`));if(!c||!l)return a.warn(`No draft was produced for "${n}" \u2014 see the log above.`),process.exitCode=1,null;s=await e.verify(o),await e.writeMeta(o),r=await qs(t,n,{source:e.source,feedback:e.feedback,ok:s})}finally{await i()}return s||(process.exitCode=1),a.success(`Draft "${n}" v${r} ready${s?"":" (with issues \u2014 see above)"}. blocks/${n}/ is unchanged.`),a.info(` ${S.dim("\u2192")} Review: ${S.cyan(`eds draft preview ${n}`)}`),a.info(` ${S.dim("\u2192")} Change: ${S.cyan(`eds draft refine ${n} "<what to change>"`)}`),a.info(` ${S.dim("\u2192")} Accept: ${S.cyan(`eds draft accept ${n} --commit`)}`),r}async function Oi(e,t){if(ce(e)){let n=V.join(e,".eds-meta.json"),o;if(ce(n))try{o=JSON.parse(await Fe(n,"utf-8")).breakpoints}catch{}let i=Zs(t.widths,o),r={provider:t.provider,designRef:t.designRef,figmaFileKey:t.figma?.fileKey??null,figmaNodeId:t.figma?.nodeId??null,lastSyncedAt:new Date().toISOString(),promptVersion:Yt,agentUsed:t.agentType,...i.length?{breakpoints:i}:{}};await Su(n,`${JSON.stringify(r,null,2)}
|
|
948
|
+
`),i.length&&a.info(S.dim(` Preview breakpoints: ${i.map(s=>s.width).join(" \xB7 ")}`))}}async function Fu(e){let{select:t,input:n}=await Promise.resolve().then(()=>(q(),J)),{startPreview:o}=await Promise.resolve().then(()=>(De(),gt)),i=null;for(a.info("");;){let r=await t({message:"Block ready \u2014 what next?",choices:[{name:"Refine \u2014 describe a change",value:"refine"},{name:i?`Preview open at ${i.url} (reloads on change)`:"Open live preview",value:"preview",disabled:i?"running":!1},{name:"Finish",value:"done"}],default:"refine"});if(r==="done")break;if(r==="preview"){await Eu()?a.info(S.dim(" A preview server is already running at http://127.0.0.1:8777.")):i=await o(e.blockName,{});continue}let s=(await n({message:"Describe the change:"})).trim();if(!s)continue;let c=qn({blockName:e.blockName,feedback:s,provider:e.provider,figma:e.figma,designRef:e.designRef}),l=await Jt(c,e.projectRoot);a.info(` ${S.dim("\u2192")} Applying your change with ${S.cyan(e.agent.type)}\u2026`),await dt(e.agent,l,e.projectRoot,e.model,{blockName:e.blockName,refine:!0,contextTokens:e.contextTokens,apiKey:e.apiKey})}if(i){let r=i;a.info(S.dim(` Preview still live at ${r.url}. ${Zt()}
|
|
949
|
+
`)),await Qt(r.close)}}async function Ni(e,t,n,o="document"){let i=[],r=V.join(e,`${t}.js`),s=V.join(e,`${t}.css`),c=ce(r),l=ce(s);if(i.push({status:c?"pass":"fail",name:`${t}.js`,message:c?"created":"missing \u2014 agent did not write the JS file"}),i.push({status:l?"pass":"fail",name:`${t}.css`,message:l?"created":"missing \u2014 agent did not write the CSS file"}),c){let m=await Fe(r,"utf-8");i.push({status:/export\s+default/.test(m)?"pass":"fail",name:"decorate export",message:/export\s+default/.test(m)?"found":"no default export \u2014 block won't load"}),m.includes("console.log")&&i.push({status:"warn",name:"no console.log",message:"found console.log \u2014 remove before production"})}if(l){let m=await Fe(s,"utf-8");i.push({status:m.includes(`.${t}`)?"pass":"warn",name:"scoped CSS",message:m.includes(`.${t}`)?`scoped to .${t}`:`no .${t} selector \u2014 styles may leak`})}if(n){let m=ce(V.join(e,`_${t}.json`)),p=V.join(e,"..","..","component-models.json"),u=!1;if(!m&&ce(p))try{u=(await Fe(p,"utf-8")).includes(`"${t}"`)}catch{}let g=m||u;if(i.push({status:g?"pass":"warn",name:"Universal Editor model",message:g?m?`_${t}.json created`:"added to component-models.json":`missing \u2014 no _${t}.json (run with default UE generation, or --no-ue-model to skip)`}),m&&c)try{let h=await Fe(V.join(e,`_${t}.json`),"utf-8"),$=await Fe(r,"utf-8"),w=/"resourceType"\s*:\s*"[^"]*\/item"/.test(h)||/"filter"\s*:/.test(h)||/"multi"\s*:\s*true/.test(h),y=/\.children/.test($)||/\bfor\s*\(/.test($)||/\.forEach\s*\(/.test($);w&&i.push({status:y?"pass":"warn",name:"multifield wired",message:y?"decorate() iterates items":"repeatable model but decorate() never iterates block.children \u2014 only one item will render"})}catch{}}if((o==="cf"||o==="mixed")&&c){let m=await Fe(r,"utf-8"),p=V.join(e,`_${t}.json`),g=(ce(p)?await Fe(p,"utf-8"):"").includes("aem-content-fragment"),h=/\bfetch\s*\(/.test(m);i.push({status:g&&h?"pass":"warn",name:"content fragment",message:g&&h?"CF field in the model, fetched in decorate()":[!g&&"no aem-content-fragment field in the model",!h&&"decorate() never fetches the fragment"].filter(Boolean).join("; ")})}a.info(j("Verification"));let d=_(i.map(m=>m.name));for(let m of i)a.info(R(m.status,m.name,m.message,d));return a.info(""),!i.some(m=>m.status==="fail")}var Mc,Au,eo=v(()=>{"use strict";f();Bn();wi();zt();ue();xi();ec();bc();yc();zn();Ai();O();K();Ze();Pc();$i();Vn();B();Mc=["document","ue","cf","mixed"],Au=new Set([".svg",".png",".jpg",".jpeg",".webp"])});var ht={};U(ht,{draftAccept:()=>Iu,draftDiscard:()=>_u,draftList:()=>Ou,draftPreview:()=>Nu,draftRefine:()=>Mu});import{existsSync as Lu}from"fs";import Uc from"path";import Ve from"chalk";function tn(){let e=E();return e||(a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1),e??null}async function Mi(e,t){let n=await pt(e,t);return n||(a.error(`No draft "${t}". Create one with: eds block from-design <design> --name ${t} --draft`),process.exitCode=1),n}async function Ou(){let e=tn();if(!e)return;let t=await zs(e);if(a.info(j("Drafts",`${t.length} in tmp/eds-cli/drafts/`)),!t.length){a.info(Ve.dim(" None. Start one with: eds block from-design <design> --name <block> --draft"));return}let n=_(t.map(o=>o.name));for(let o of t){let i=o.versions.at(-1),r=o.status==="accepted"?`accepted v${o.accepted?.version}`:`${o.versions.length} version${o.versions.length===1?"":"s"}, latest v${i?.version}${i?.ok===!1?" (issues)":""}`;a.info(P(o.name,`${r}${i?.feedback?` \xB7 "${i.feedback}"`:""}`,n))}}async function Nu(e,t){let n=tn();if(!n)return;let o=await Mi(n,e);if(!o)return;let i=Ii(t.version)??o.versions.at(-1)?.version;if(!i||!Lu(mt(n,e,i))){a.error(`Draft "${e}" has no version ${t.version??""}.`.trim()),process.exitCode=1;return}a.info(Ve.dim(` Draft "${e}" v${i} (not in blocks/ until accepted)`));let{previewBlock:r}=await Promise.resolve().then(()=>(De(),gt));await r(e,{...t,blockDir:mt(n,e,i)})}async function Mu(e,t,n){let o=tn();if(!o)return;let i=await Mi(o,e);if(!i)return;if(!t?.trim()){a.error('Say what to change: eds draft refine <name> "<what to change>"'),process.exitCode=1;return}let r=Ii(n.version)??i.versions.at(-1)?.version;if(!r){a.error(`Draft "${e}" has no versions.`),process.exitCode=1;return}let s=await se(o),c=await _n(n.agent||i.source.agent||s.agent);if(!c){a.error("No AI agent found (claude, cursor, codex, or a local Ollama / oMLX server)."),process.exitCode=1;return}let l=be(c.type)?n.model??c.model:n.model??i.source.model??s.model,d=qn({blockName:e,feedback:t.trim(),provider:i.source.provider,figma:i.source.figma??null,designRef:i.source.designRef}),m=await Jt(d,o);a.info(` ${Ve.dim("\u2192")} Round on v${r} with ${Ve.cyan(c.type)}: ${Ve.dim(t.trim())}`);let{generateDraft:p,verifyGeneratedBlock:u,writeBlockMeta:g}=await Promise.resolve().then(()=>(eo(),Zn));await p({projectRoot:o,blockName:e,from:r,feedback:t.trim(),source:{...i.source,agent:c.type,model:l},run:()=>dt(c,m,o,l,{blockName:e,refine:!0,contextTokens:s.local?.contextTokens,apiKey:s.local?.apiKey}),verify:h=>u(h,e,!0,"document"),writeMeta:h=>g(h,{provider:i.source.provider,designRef:i.source.designRef,figma:i.source.figma??null,agentType:c.type})})}async function Iu(e,t){let n=tn();if(!n||!await Mi(n,e))return;let o;try{o=await Ks(n,e,Ii(t.version))}catch(i){a.error(i.message),process.exitCode=1;return}if(a.success(`Accepted "${e}" v${o.version} \u2192 blocks/${e}/`),!t.commit&&!t.branch){a.info(Ve.dim(" Not committed. Commit it yourself, or re-run with --commit [--branch <name>]."));return}try{let{execa:i}=await import("execa"),r=c=>i("git",c,{cwd:n});if(t.branch){let c=await r(["rev-parse","--verify","--quiet",`refs/heads/${t.branch}`]).then(()=>!0,()=>!1);await r(c?["switch",t.branch]:["switch","-c",t.branch])}await r(["add","--",Uc.join("blocks",e)]),await r(["commit","-m",Ys(o.draft,o.version),"--",Uc.join("blocks",e)]);let s=(await r(["rev-parse","--short","HEAD"])).stdout.trim();await Vs(n,e,s),a.success(`Committed ${s}${t.branch?` on ${t.branch}`:""}.`)}catch(i){let r=i;a.error(`Commit failed: ${(r.stderr||r.message).trim().split(`
|
|
950
|
+
`).pop()}`),a.info(Ve.dim(` The files are in blocks/${e}/; commit them yourself.`)),process.exitCode=1}}async function _u(e){let t=tn();t&&(await Xs(t,e)?a.success(`Discarded draft "${e}". blocks/ is unchanged.`):(a.error(`No draft "${e}".`),process.exitCode=1))}var Ii,wt=v(()=>{"use strict";f();Bn();wi();zt();ue();xi();Ai();O();K();B();Ii=e=>e?Number.parseInt(e.replace(/^v/i,""),10):void 0});var Bc={};U(Bc,{listBlocks:()=>Hu});import{existsSync as nn}from"fs";import{readFile as Uu,readdir as Bu}from"fs/promises";import bt from"path";import yt from"chalk";async function Hu(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n=bt.join(t,"blocks");if(!nn(n)){a.info("No blocks/ directory found.");return}let o=await Bu(n,{withFileTypes:!0}),i=[];for(let s of o){if(!s.isDirectory())continue;let c=s.name,l=bt.join(n,c),d={name:c,hasJs:nn(bt.join(l,`${c}.js`)),hasCss:nn(bt.join(l,`${c}.css`)),hasUeModel:nn(bt.join(l,`_${c}.json`))},m=bt.join(l,".eds-meta.json");if(nn(m))try{let p=JSON.parse(await Uu(m,"utf-8"));d.figmaSource={fileKey:p.figmaFileKey,nodeId:p.figmaNodeId,lastSyncedAt:p.lastSyncedAt}}catch{}i.push(d)}if(e.json){console.log(JSON.stringify(i,null,2));return}if(i.length===0){a.info("No blocks found.");return}a.info(j("Blocks",`${i.length} in project`));let r=_(i.map(s=>s.name));for(let s of i){let c=[s.hasJs?I.ok("js"):yt.dim.strikethrough("js"),s.hasCss?I.ok("css"):yt.dim.strikethrough("css")];s.hasUeModel&&c.push(I.blue("ue-model")),s.figmaSource&&c.push(`${X.figma} ${I.dotPurple("figma")}`);let l=St(yt.bold(s.name),r);if(a.info(` ${l} ${yt.dim("[")}${c.join(" ")}${yt.dim("]")}`),s.figmaSource){let d=new Date(s.figmaSource.lastSyncedAt).toLocaleDateString();a.info(` ${" ".repeat(r)} ${X.arrow} ${yt.dim(`figma:${s.figmaSource.fileKey} \xB7 synced ${d}`)}`)}}a.info("")}var Hc=v(()=>{"use strict";f();O();K();B()});import Gc from"path";function _i(e,t){return Gc.join(e,"blocks",t,"__snapshots__")}function zc(e,t,n){return Gc.join(_i(e,t),`${t}-${n}.png`)}function on(e){return`${(e*100).toFixed(2)}%`}async function Ui(e,t,n,o=900){let i;try{({chromium:i}=await import("playwright"))}catch{throw new Error(Wc)}let r=await i.launch();try{let s=await r.newPage({viewport:{width:t,height:o}});await s.goto(e,{waitUntil:"networkidle"}),await s.waitForTimeout(300);let c=n?s.locator(n).first():null;return c&&await c.count()?await c.screenshot():await s.screenshot({fullPage:!0})}finally{await r.close()}}async function Jc(){try{let e="pngjs",t="pixelmatch",{PNG:n}=await import(e),o=(await import(t)).default;return{PNG:n,pixelmatch:o}}catch{throw new Error(Wc)}}async function qc(e,t){let{PNG:n,pixelmatch:o}=await Jc(),i=n.sync.read(e),r=n.sync.read(t);if(i.width!==r.width||i.height!==r.height)return{diffPixels:-1,totalPixels:0,ratio:1,sizeMismatch:!0,width:i.width,height:i.height,otherWidth:r.width,otherHeight:r.height};let{width:s,height:c}=i,l=new n({width:s,height:c}),d=o(i.data,r.data,l.data,s,c,{threshold:.1}),m=s*c;return{diffPixels:d,totalPixels:m,ratio:m?d/m:0,width:s,height:c,diffPng:n.sync.write(l)}}async function Kc(e,t){let{PNG:n,pixelmatch:o}=await Jc(),i=n.sync.read(e),r=n.sync.read(t),s=Math.min(i.width,r.width),c=Math.min(i.height,r.height),l=new n({width:s,height:c}),d=new n({width:s,height:c});n.bitblt(i,l,0,0,s,c,0,0),n.bitblt(r,d,0,0,s,c,0,0);let m=new n({width:s,height:c}),p=o(l.data,d.data,m.data,s,c,{threshold:.1}),u=s*c;return{diffPixels:p,totalPixels:u,ratio:u?p/u:0,width:s,height:c,diffPng:n.sync.write(m)}}var Wc,Vc=v(()=>{"use strict";f();Wc=`Visual testing needs extra tools. Install them with:
|
|
951
|
+
npm i -D playwright pixelmatch pngjs && npx playwright install chromium`});var el={};U(el,{visualTest:()=>Wu});import{existsSync as Xc}from"fs";import{mkdir as Bi,readFile as Yc,writeFile as rn}from"fs/promises";import ve from"path";import Hi from"chalk";async function Wu(e,t={}){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}if(t.design){await zu(n,e,t);return}let o=e?[e]:await Ke(n);if(!o.length){a.warn("No previewable blocks to test.");return}let i=Number.parseInt(t.port??"8788",10),r=await ft(n,t.widths,Number.isFinite(i)?i:8788),s=Number.parseFloat(t.threshold??"0.01"),c=ve.join(n,"tmp","eds-cli","visual-diff");a.logoOnce(A("Visual test"));let l=0,d=0,m=0,p=0;try{for(let u of o){let g=await ye(n,u,t.widths);if(g){a.info(j(u));for(let h of g.breakpoints){let $=await Ui(Qc(r.url,u),h.width,Zc(u)),w=zc(n,u,h.width),y=Xc(w);if(t.update||!y){await Bi(_i(n,u),{recursive:!0}),await rn(w,$),y?(p++,a.info(R("pass",`${h.width}px`,"baseline updated"))):(m++,a.info(R("pass",`${h.width}px`,"baseline created")));continue}let b=await qc(await Yc(w),$);if(b.sizeMismatch){d++;let T=b.height===Gu&&(b.otherHeight??0)<b.height;a.info(R("fail",`${h.width}px`,T?`baseline is an older full-page shot (${b.width}\xD7${b.height}) \u2014 re-run with --update`:`size changed ${b.width}\xD7${b.height} \u2192 ${b.otherWidth}\xD7${b.otherHeight}`));continue}if(b.ratio>s){d++,await Bi(c,{recursive:!0});let T=ve.join(c,`${u}-${h.width}.diff.png`);b.diffPng&&await rn(T,b.diffPng),a.info(R("fail",`${h.width}px`,`${on(b.ratio)} changed \u2192 ${ve.relative(n,T)}`))}else l++,a.info(R("pass",`${h.width}px`,b.ratio>0?`${on(b.ratio)} (within ${on(s)})`:"identical"))}}}}catch(u){a.error(u instanceof Error?u.message:String(u)),process.exitCode=1;return}finally{await r.close()}a.info(""),a.info(`${Hi.green(`${l} passed`)} \xB7 ${Hi.yellow(`${d} changed`)} \xB7 ${m} new \xB7 ${p} updated`),d>0&&(a.warn(`${d} visual change(s). Review the diff PNGs in tmp/eds-cli/visual-diff/, then re-run with --update to accept.`),process.exitCode=1)}async function zu(e,t,n){if(!t){a.error("Design diff needs a block name: eds block test <name> --design"),process.exitCode=1;return}let o=await ye(e,t,n.widths);if(!o){a.error(`Block "${t}" has no css/js to render.`),process.exitCode=1;return}let i,r,s=ve.join(e,"blocks",t,".eds-meta.json");if(Xc(s))try{let g=JSON.parse(await Yc(s,"utf-8"));i=g.figmaFileKey??void 0,r=g.figmaNodeId??void 0}catch{}if(!i||!r){a.error(`"${t}" has no Figma source in .eds-meta.json \u2014 can't fetch the design image.`),process.exitCode=1;return}let c=await se(e),l=c.figma?.token??process.env.FIGMA_TOKEN??process.env.FIGMA_PAT;if(!l){a.error("Design diff needs a Figma token (FIGMA_TOKEN or figma.token) to render the node."),process.exitCode=1;return}let d=o.breakpoints.filter(g=>g.figma),m=(d.length?d:o.breakpoints).reduce((g,h)=>h.width>g.width?h:g,o.breakpoints[0]).width,p=Number.parseInt(n.port??"8788",10),u=await ft(e,n.widths,Number.isFinite(p)?p:8788);a.logoOnce(A("Design \u2194 render")),a.info(j(t,`${m}px`));try{let g=await Ui(Qc(u.url,t),m,Zc(t));a.info(R("pass","render","block screenshot captured"));let h=await pc({fileKey:i,nodeId:r,token:l,scale:1,pace:()=>Wn({logPath:Gn(e),perMinute:c.figma?.restPerMinute,onWait:y=>a.info(R("warn","design",`waiting ${Math.ceil(y/1e3)} s for a Figma REST slot`))})});a.info(R("pass","design","Figma image fetched (REST)"));let $=await Kc(h,g),w=ve.join(e,"tmp","eds-cli","visual-diff");await Bi(w,{recursive:!0}),await rn(ve.join(w,`${t}-design.png`),h),await rn(ve.join(w,`${t}-render.png`),g),$.diffPng&&await rn(ve.join(w,`${t}-design-diff.png`),$.diffPng),a.info(R("warn","diff",`~${on($.ratio)} different over ${$.width}\xD7${$.height} (approximate)`)),a.info(""),a.info(Hi.dim(` Saved design / render / diff to ${ve.relative(e,w)}/${t}-*.png \u2014 compare side by side.`))}catch(g){a.error(g instanceof Error?g.message:String(g)),process.exitCode=1}finally{await u.close()}}var Qc,Zc,Gu,tl=v(()=>{"use strict";f();ue();zn();Ci();O();Vc();K();B();De();Qc=(e,t)=>`${e}${Re.slice(1)}${t}`,Zc=e=>`.${e}-wrapper > .${e}`,Gu=900});async function nl(e,t,n){let o;try{({chromium:o}=await import("playwright"))}catch{throw new Error(Ju)}let i=await o.launch();try{let r=await i.newPage({viewport:{width:t,height:900}});await r.goto(e,{waitUntil:"networkidle"}),await r.waitForTimeout(200);let s=await r.evaluate(qu);return n&&s.push(...await r.evaluate(`(${Ku})(${JSON.stringify(n)})`)),s}finally{await i.close()}}var Ju,qu,Ku,ol=v(()=>{"use strict";f();Ju=`Content checks need Playwright. Install it with:
|
|
952
|
+
npm i -D playwright && npx playwright install chromium`,qu=`(() => {
|
|
946
953
|
const out = [];
|
|
947
954
|
const root = document.querySelector('[class$="block"]') || document.body;
|
|
948
955
|
const trunc = (s) => (s || '').slice(0, 60);
|
|
@@ -988,7 +995,7 @@ ${n}
|
|
|
988
995
|
}
|
|
989
996
|
}
|
|
990
997
|
return out;
|
|
991
|
-
})()`,
|
|
998
|
+
})()`,Ku=`(html) => {
|
|
992
999
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
993
1000
|
const root = doc.querySelector('.block') || doc.body.firstElementChild;
|
|
994
1001
|
if (!root) return [];
|
|
@@ -1002,14 +1009,14 @@ ${n}
|
|
|
1002
1009
|
}
|
|
1003
1010
|
}
|
|
1004
1011
|
return wrapped ? [{ level: 'warn', rule: 'mock-nesting', detail: wrapped + ' of ' + cells + ' cells in the preview mock wrap their content in an extra <div>; EDS delivers row > cell > content' }] : [];
|
|
1005
|
-
}`});var
|
|
1012
|
+
}`});var il={};U(il,{blockCheck:()=>Vu});import Gi from"chalk";async function Vu(e,t={}){let n=E();if(!n){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let o=e?[e]:await Ke(n);if(!o.length){a.warn("No previewable blocks to check.");return}let i=Number.parseInt(t.port??"8789",10),r=await ft(n,t.widths,Number.isFinite(i)?i:8789);a.logoOnce(A("Content check"));let s=0,c=0,l=0;try{for(let d of o){let m=await ye(n,d,t.widths);if(!m)continue;let p=m.breakpoints.reduce((g,h)=>h.width>g.width?h:g,m.breakpoints[0]).width,u=await nl(`${r.url}${Re.slice(1)}${d}`,p,m.placeholder?void 0:m.sampleContent);if(a.info(j(d,`${p}px`)),!u.length){l++,a.info(R("pass","clean","no issues"));continue}for(let g of u)g.level==="error"?s++:c++,a.info(R(g.level==="error"?"fail":"warn",g.rule,g.detail))}}catch(d){a.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}finally{await r.close()}a.info(""),a.info(`${Gi.green(`${l} clean`)} \xB7 ${Gi.red(`${s} error(s)`)} \xB7 ${Gi.yellow(`${c} warning(s)`)}`),(s>0||t.strict&&c>0)&&(process.exitCode=1)}var rl=v(()=>{"use strict";f();O();ol();K();B();De()});function al(e){return to.find(t=>t.id===e)}function sl(e,t){return`
|
|
1006
1013
|
// \u2500\u2500 ${e} (eds integrate) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1007
1014
|
{
|
|
1008
1015
|
${t.split(`
|
|
1009
1016
|
`).map(n=>n&&` ${n}`).join(`
|
|
1010
1017
|
`)}
|
|
1011
1018
|
}
|
|
1012
|
-
`}var
|
|
1019
|
+
`}var to,cl=v(()=>{"use strict";f();to=[{id:"gtm",name:"Google Tag Manager",fields:[{name:"id",message:"GTM container ID",placeholder:"GTM-XXXXXXX"}],code:()=>`// Google Tag Manager - loaded from ./analytics.js (delayed phase, after LCP).
|
|
1013
1020
|
import { loadGTM } from './analytics.js';
|
|
1014
1021
|
import pageMetaPush from './page-meta.js';
|
|
1015
1022
|
|
|
@@ -1100,19 +1107,19 @@ document.head.appendChild(cb);`},{id:"custom",name:"Custom third-party script",f
|
|
|
1100
1107
|
const s = document.createElement('script');
|
|
1101
1108
|
s.async = true;
|
|
1102
1109
|
s.src = ${JSON.stringify(e.url||"")};
|
|
1103
|
-
document.head.appendChild(s);`}]});var
|
|
1110
|
+
document.head.appendChild(s);`}]});var zi={};U(zi,{integrate:()=>Zu});import{existsSync as Xu}from"fs";import{mkdir as ll,readFile as Yu,writeFile as dl}from"fs/promises";import no from"path";import Wi from"chalk";async function Zu(e){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Integrate - third-party service"));let{select:n,input:o}=await Promise.resolve().then(()=>(q(),J)),i=e||await n({message:"Which service do you want to add?",choices:to.map(p=>({name:p.name,value:p.id}))}),r=al(i);if(!r){a.error(`Unknown integration "${i}". Options: ${to.map(p=>p.id).join(", ")}`),process.exitCode=1;return}let s={};for(let p of r.fields){let u=await o({message:` ${p.message}`,default:p.placeholder});s[p.name]=u.trim()}let c=[];if(r.module)for(let p of r.module(s)){let u=no.join(t,p.file);await ll(no.dirname(u),{recursive:!0}),await dl(u,p.content),c.push(p.file)}let l=r.module?`
|
|
1104
1111
|
// ${r.name} (eds integrate)
|
|
1105
1112
|
${r.code(s)}
|
|
1106
|
-
`:
|
|
1107
|
-
${
|
|
1113
|
+
`:sl(r.name,r.code(s)),d=no.join(t,"scripts","delayed.js");await ll(no.dirname(d),{recursive:!0});let m=Xu(d)?await Yu(d,"utf-8"):Qu;await dl(d,`${m.replace(/\s*$/,"")}
|
|
1114
|
+
${l}`),a.info(j("Added"));for(let p of c)a.info(P(r.name,`wrote ${p}`));a.info(P(r.name,"wired into scripts/delayed.js")),a.info(""),a.info(Wi.dim(" Loads after LCP (delayed phase) - zero impact on your Core Web Vitals.")),(r.id==="gtm"||r.id==="ga4")&&a.info(Wi.dim(" Tip: gate analytics behind user consent (add the Cookiebot integration).")),r.id==="chat"&&a.info(Wi.dim(" The widget loads only when the visitor clicks the button (facade pattern).")),a.info(""),a.info(W(["Integration added"]))}var Qu,Ji=v(()=>{"use strict";f();cl();O();K();B();Qu=`// delayed.js - third-party / non-critical scripts.
|
|
1108
1115
|
// Loaded in the EDS delayed phase (after LCP), so nothing here blocks the page.
|
|
1109
|
-
`});var
|
|
1116
|
+
`});var qi={};U(qi,{figmaSetup:()=>of});import{existsSync as ef}from"fs";import{mkdir as tf,writeFile as nf}from"fs/promises";import me from"chalk";async function of(){let{select:e,confirm:t}=await Promise.resolve().then(()=>(q(),J));a.logoOnce(A()),a.info(j("Figma MCP Setup Wizard")),a.info("Detecting installed AI agents...");let n=await Un(),o;if(n.length===0?(a.warn("No AI agents found (claude, cursor, codex)."),a.info(`Install Claude Code: ${me.cyan("npm install -g @anthropic-ai/claude-code")}`),o="none"):(a.success(`Found: ${n.map(r=>me.cyan(r.type)).join(", ")}`),o=await e({message:"Which agent do you want to use with eds-cli?",choices:[...n.map(r=>({name:`${r.type}${r.hasFigmaMcp?me.green(" (Figma MCP detected)"):""}`,value:r.type})),{name:"None (manual mode)",value:"none"}]})),o!=="none"){let r=n.find(s=>s.type===o);if(r&&!r.hasFigmaMcp){switch(a.warn(`Figma MCP is not configured for ${o}.
|
|
1110
1117
|
`),a.info(`Install it with one of these methods:
|
|
1111
|
-
`),o){case"claude":a.info(` ${
|
|
1112
|
-
Note: Figma MCP requires a Figma seat (Dev or Full on paid plans for desktop server).`)),await t({message:"Save preferences to ~/.eds/config.json?",default:!0})){let r=
|
|
1113
|
-
`,{mode:384}),a.success(`Config saved to ${
|
|
1114
|
-
Setup complete!`)),o!=="none"&&a.info(`Try: ${
|
|
1115
|
-
`);for(let
|
|
1116
|
-
`),r=/function\s+loadEager|loadEager\s*=/i.test(o),s=/function\s+loadLazy|loadLazy\s*=/i.test(o),
|
|
1117
|
-
`),d=["jquery","lodash","moment","rxjs","d3","three","gsap","anime","chart.js","swiper"];for(let u=0;u<
|
|
1118
|
-
`);for(let r=0;r<i.length;r++){let s=i[r],l=!1;for(let c of Ru)c.ext.includes(n)&&(c.id==="innerhtml-static"&&l||c.re.test(s)&&(c.extra&&!c.extra(s)||(c.id==="innerhtml-dynamic"&&(l=!0),o.push({severity:c.severity,rule:c.id,message:c.message,file:t,line:r+1,snippet:s.trim().slice(0,100)}))))}return o}async function Nu(e){if(!In(Xe.join(e,"package.json")))return{status:"skipped",note:"no package.json"};if(!(In(Xe.join(e,"package-lock.json"))||In(Xe.join(e,"npm-shrinkwrap.json")))&&!In(Xe.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??{},s={critical:r.critical??0,high:r.high??0,moderate:r.moderate??0,low:r.low??0};return{status:s.critical+s.high+s.moderate+s.low>0?"vulnerable":"ok",counts:s}}catch(n){return{status:"skipped",note:`npm audit failed: ${n.message}`}}}async function Mu(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n=[];for await(let c of Oc(t)){let d=Xe.extname(c).slice(1).toLowerCase();if(!Du.has(d))continue;let m=Xe.relative(t,c);if(m.endsWith("aem.js")||m.endsWith("lib-franklin.js"))continue;let p=await Tu(c,"utf-8");n.push(...Ou(p,m,d))}let o=await Nu(t),i=c=>n.filter(d=>d.severity===c),r={critical:i("critical").length,high:i("high").length,moderate:i("moderate").length,low:i("low").length},s=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)),s&&(process.exitCode=1);return}if(a.logoOnce(A("Security Audit")),a.info(j("Dependencies","npm audit")),o.status==="skipped")a.info(R("info","npm audit",o.note??"skipped"));else if(o.status==="ok")a.info(R("pass","npm audit","no known vulnerabilities"));else{let c=o.counts??{critical:0,high:0,moderate:0,low:0};a.info(R(c.critical+c.high>0?"fail":"warn","npm audit",`${c.critical} critical, ${c.high} high, ${c.moderate} moderate, ${c.low} low \u2014 run \`npm audit fix\``))}if(a.info(j("Exploit scan","XSS \xB7 secrets \xB7 injection \xB7 tabnabbing")),n.length===0)a.info(R("pass","code","no risky patterns found"));else{let c=[...n].sort((d,m)=>Dc.indexOf(d.severity)-Dc.indexOf(m.severity));for(let d of c){let m=Fu[d.severity],p=Ri.dim(`${d.file}:${d.line}`);a.info(` ${Vt(m.status)} ${Ri.bold(m.label)} ${d.message} ${p}`),a.info(Ri.dim(` ${d.snippet}`))}}let l=$e({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)});a.info(""),a.info(G([l||`${X.pass} no vulnerabilities or risky patterns found`])),s&&(process.exitCode=1)}var Ru,Dc,Fu,Lu,Du,Li=k(()=>{"use strict";f();D();K();B();Ru=[{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"]}],Dc=["critical","high","moderate","low"],Fu={critical:{status:"fail",label:"CRIT"},high:{status:"fail",label:"HIGH"},moderate:{status:"warn",label:"MOD "},low:{status:"info",label:"LOW "}},Lu=new Set(["node_modules",".git","dist","build",".vscode","coverage"]),Du=new Set(["js","mjs","html","json","pem","txt"])});async function Nc(e,t,n){let o=t.ref||"main",i=n.startsWith("/")?n:`/${n}`,r=`${_u}/${e}/${t.org}/${t.site}/${o}${i}`;a.debug(`POST ${r}`);let s=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"}}),l=await s.json().catch(()=>({})),c=l;return s.ok?{ok:!0,status:s.status,path:i,previewUrl:c.preview?.url,liveUrl:c.live?.url}:{ok:!1,status:s.status,path:i,message:l.message||`HTTP ${s.status}`}}async function Di(e,t){return Nc("preview",e,t)}async function Oi(e,t){return Nc("live",e,t)}async function Mc(e,t){return Promise.all(t.map(n=>Di(e,n)))}async function _c(e,t){return Promise.all(t.map(n=>Oi(e,n)))}var _u,Ni=k(()=>{"use strict";f();D();_u="https://admin.hlx.page"});var Mi={};_(Mi,{preview:()=>Uu,resolveAdminConfig:()=>Un});import Ic from"chalk";import Iu from"ora";async function Uu(e,t){let n=E(),o=await le(n),i=Un(o,t);if(!i)return;let r=Iu(`Previewing ${e.length} path(s)...`).start(),s=e.length===1?[await Di(i,e[0])]:await Mc(i,e);r.stop();let l=!1;for(let c of s)c.ok?a.success(`${c.path} \u2192 ${Ic.cyan(c.previewUrl||"preview updated")}`):(a.error(`${c.path} \u2014 ${c.message}`),l=!0);l&&(process.exitCode=1)}function Un(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){a.error("Missing --org and --site. Set them via flags or in .edsrc.json:"),a.info(Ic.dim(' { "admin": { "org": "my-org", "site": "my-site" } }')),process.exitCode=1;return}return{org:n,site:o,ref:i}}var Bn=k(()=>{"use strict";f();Ni();ye();D();K()});var _i={};_(_i,{publish:()=>Gu});import Bu from"chalk";import Hu from"ora";async function Gu(e,t){let n=E(),o=await le(n),i=Un(o,t);if(!i)return;let r=Hu(`Publishing ${e.length} path(s)...`).start(),s=e.length===1?[await Oi(i,e[0])]:await _c(i,e);r.stop();let l=!1;for(let c of s)c.ok?a.success(`${c.path} \u2192 ${Bu.cyan(c.liveUrl||"published")}`):(a.error(`${c.path} \u2014 ${c.message}`),l=!0);l&&(process.exitCode=1)}var Ii=k(()=>{"use strict";f();Ni();ye();D();K();Bn()});var Hn={};_(Hn,{adminWizard:()=>Wu});async function Wu(e){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Admin API \u2014 preview / publish"));let{select:n,input:o,confirm:i}=await Promise.resolve().then(()=>(z(),W)),s=(await le(t)).admin??{},l=e??await n({message:"What do you want to do?",choices:[{name:"Preview pages (staging)",value:"preview"},{name:"Publish pages (go live)",value:"publish"}]}),c=(await o({message:"GitHub org / owner",default:s.org})).trim(),d=(await o({message:"Repository / site",default:s.site})).trim(),m=(await o({message:"Git ref",default:s.ref||"main"})).trim(),u=(await o({message:"Paths (space- or comma-separated)",default:"/"})).split(/[\s,]+/).filter(Boolean);if(!c||!d||u.length===0){a.error("org, site and at least one path are required."),process.exitCode=1;return}a.info(j("Summary"));let g=U(["operation","org","site","ref","paths"]);if(a.info(P("operation",l,g)),a.info(P("org",c,g)),a.info(P("site",d,g)),a.info(P("ref",m,g)),a.info(P("paths",u.join(", "),g)),a.info(""),l==="publish"&&!await i({message:`Publish ${u.length} path(s) to LIVE?`,default:!1})){a.info("Cancelled.");return}let h={org:c,site:d,ref:m};if(l==="preview"){let{preview:v}=await Promise.resolve().then(()=>(Bn(),Mi));await v(u,h)}else{let{publish:v}=await Promise.resolve().then(()=>(Ii(),_i));await v(u,h)}}var Gn=k(()=>{"use strict";f();ye();D();K();B()});var Uc={};_(Uc,{mainMenu:()=>Vu});import{existsSync as zu}from"fs";import{readdir as Ju}from"fs/promises";import qu from"path";import Ku from"chalk";async function Ui(e){let t=qu.join(e,"blocks");return zu(t)?(await Ju(t,{withFileTypes:!0})).filter(o=>o.isDirectory()).map(o=>o.name):[]}async function Vu(){let{select:e,isEscape:t,isExit:n}=await Promise.resolve().then(()=>(z(),W));Rn.menu=!0,await a.logoOnceAnimated("");let o;for(;;){a.info(Ku.dim(" Esc quits here \xB7 goes back to this menu from any step"));let i;try{i=await e({message:"Choose an action",choices:Xu,default:o})}catch(r){if(t(r)||n(r))return;throw r}if(i==="exit")return;o=i;try{await Yu(i)}catch(r){if(n(r))return;t(r)||a.error(r instanceof Error?r.message:String(r))}process.exitCode=void 0,a.info("")}}async function Yu(e){let{select:t,input:n}=await Promise.resolve().then(()=>(z(),W));switch(e){case"new":{let{newProject:o}=await Promise.resolve().then(()=>(mo(),lo));await o(void 0,{});return}case"init":{let{initProject:o}=await Promise.resolve().then(()=>(xt(),kt));await o({});return}case"template":{let o=await n({message:"Template name",validate:r=>!!r.trim()||"Required"}),{templateNew:i}=await Promise.resolve().then(()=>(yo(),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(()=>(Ue(),Ie));await i(o.trim(),{});return}case"from-design":{let{blockFromDesign:o}=await Promise.resolve().then(()=>(gi(),fi));await o(void 0,{});return}case"migrate":{let{migrateComponent:o}=await Promise.resolve().then(()=>(Eo(),Po));await o(void 0,{});return}case"scaffold":{let{scaffoldInteractive:o}=await Promise.resolve().then(()=>(fe(),we));await o();return}case"create":{let o=await n({message:"Block name",validate:r=>Ne.test(r.trim())||"Use kebab-case, e.g. hero-banner"}),{createBlock:i}=await Promise.resolve().then(()=>(Ho(),Bo));await i(o.trim(),{});return}case"integrate":{let{integrate:o}=await Promise.resolve().then(()=>($i(),xi));await o(void 0);return}case"preview-block":{let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found).");return}let i=await Ui(o);if(i.length===0){a.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(l=>({name:l,value:l}))}),{previewBlock:s}=await Promise.resolve().then(()=>(qe(),Ht));await s(r,{});return}case"model":{let{modelAdd:o}=await Promise.resolve().then(()=>(No(),Oo));await o(void 0,[],{});return}case"track":{let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found).");return}let i=await Ui(o);if(i.length===0){a.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block to instrument?",choices:i.map(l=>({name:l,value:l}))}),{trackBlock:s}=await Promise.resolve().then(()=>(At(),Tt));await s(r,{});return}case"schema":{let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found).");return}let i=await Ui(o);if(i.length===0){a.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(l=>({name:l,value:l}))}),{schemaBlock:s}=await Promise.resolve().then(()=>(_o(),Mo));await s(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(()=>(Dt(),Lt));await i()}else{let i=await n({message:"Page path",default:"/"}),{ueOpen:r}=await Promise.resolve().then(()=>(Dt(),Lt));await r(i.trim()||"/",{})}return}case"admin":{let{adminWizard:o}=await Promise.resolve().then(()=>(Gn(),Hn));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(()=>(Ei(),Pi));await i({})}else if(o==="loading"){let{auditLoading:i}=await Promise.resolve().then(()=>(Ai(),Ti));await i({})}else{let{auditSecurity:i}=await Promise.resolve().then(()=>(Li(),Fi));await i({})}return}case"figma-setup":{let{figmaSetup:o}=await Promise.resolve().then(()=>(ji(),Si));await o();return}}}var Xu,Bc=k(()=>{"use strict";f();D();K();Ye();Fn();Xu=[{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 Qu from"chalk";import{Command as Zu}from"commander";var Gi={name:"aem-eds-kit",version:"0.4.57",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"}};D();B();var J=new Zu;J.name("eds").description("CLI for AEM Edge Delivery Services: blocks from Figma, Framer or Stitch designs, AEM migration, Universal Editor models and QA").version(Gi.version).option("--verbose","Enable verbose output").option("--quiet","Suppress non-error output").option("--json","Output in JSON format").option("--no-color","Disable color output").showHelpAfterError("(add --help for usage)").hook("preAction",e=>{let t=e.opts();t.verbose&&a.setLevel("debug"),t.quiet&&a.setQuiet(!0),t.color===!1&&(Qu.level=0)});J.addHelpText("beforeAll",()=>A());J.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(()=>(mo(),lo));await n(e,t)});var Kt=J.command("sandbox").description("Disposable EDS sandbox repos on GitHub");Kt.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(()=>(Ue(),Ie));await n(e,t)});Kt.command("login").description("Authorize GitHub (OAuth device flow or a token) - no gh needed").action(async()=>{let{sandboxLogin:e}=await Promise.resolve().then(()=>(Ue(),Ie));await e()});Kt.command("logout").description("Remove the stored GitHub token").action(async()=>{let{sandboxLogout:e}=await Promise.resolve().then(()=>(Ue(),Ie));await e()});Kt.command("list").description("List your EDS sandboxes (repos tagged eds-sandbox)").action(async()=>{let{sandboxList:e}=await Promise.resolve().then(()=>(Ue(),Ie));await e()});Kt.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(()=>(Ue(),Ie));await n(e,t)});var ef=J.command("template").description("Generate page templates / initial content");ef.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(()=>(yo(),bo));await n(e,t)});J.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(()=>(xt(),kt));await t(e)});var tf=J.command("migrate").description("Migrate from classic AEM to EDS");tf.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(()=>(Eo(),Po));await n(e,t)});var nf=J.command("model").description("Compose Universal Editor models");nf.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(()=>(No(),Oo));await o(e,t,n)});var of=J.command("schema").description("Structured data (JSON-LD) for blocks");of.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(()=>(_o(),Mo));await n(e,t)});var rf=J.command("track").description("Instrument blocks for analytics");rf.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(()=>(At(),Tt));await n(e,t)});var Hc=J.command("ue").description("Universal Editor - readiness check + editor deep link");Hc.command("check").description("Check whether blocks are Universal-Editor-ready (offline)").action(async()=>{let{ueCheck:e}=await Promise.resolve().then(()=>(Dt(),Lt));await e()});Hc.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(()=>(Dt(),Lt));await n(e,t)});var ut=J.command("block").description("Manage EDS blocks");ut.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(()=>(Ho(),Bo));await n(e,t)});ut.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("--yes","Skip confirmation prompts").action(async(e,t)=>{let{blockFromDesign:n}=await Promise.resolve().then(()=>(gi(),fi));await n(e,t)});ut.command("list").description("List all blocks in the project").action(async e=>{let{listBlocks:t}=await Promise.resolve().then(()=>(lc(),cc));await t({...e,json:J.opts().json})});ut.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(()=>(qe(),Ht));e?await n.previewBlock(e,t):await n.galleryPreview(t)});ut.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(()=>(xc(),kc));await n(e,t)});ut.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(()=>(Pc(),jc));await n(e,t)});var ft=J.command("scaffold").description("Scaffold standard UE components and blocks").action(async()=>{let{scaffoldInteractive:e}=await Promise.resolve().then(()=>(fe(),we));await e()});ft.command("ue").description("Scaffold default-content UE components + a field-reference block (all 17 fields)").action(async()=>{let{scaffoldUe:e}=await Promise.resolve().then(()=>(fe(),we));await e()});ft.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(()=>(fe(),we));await t(e)});ft.command("ci").description("Scaffold a GitHub Actions workflow (doctor + audits + project lint/build)").action(async()=>{let{scaffoldCi:e}=await Promise.resolve().then(()=>(fe(),we));await e()});ft.command("helpers [names...]").description("Scaffold scripts/utils.js with chosen EDS helpers (interactive picker)").action(async e=>{let{scaffoldHelpers:t}=await Promise.resolve().then(()=>(fe(),we));await t(e)});ft.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(()=>(fe(),we));await t(e)});ft.command("xwalk").description("Write xwalk.json enabling Universal Editor multi-field support").action(async()=>{let{scaffoldXwalk:e}=await Promise.resolve().then(()=>(fe(),we));await e()});J.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(()=>($i(),xi));await t(e)});var af=J.command("figma").description("Figma MCP integration");af.command("setup").description("Configure Figma MCP for your AI agent").action(async()=>{let{figmaSetup:e}=await Promise.resolve().then(()=>(ji(),Si));await e()});J.command("doctor").description("Audit your EDS project for common issues").action(async()=>{let{doctor:e}=await Promise.resolve().then(()=>(Ei(),Pi));await e({json:J.opts().json})});var Gc=J.command("audit").description("Run project audits");Gc.command("loading").description("Check loading order (eager/lazy/delayed phases, LCP budget)").action(async()=>{let{auditLoading:e}=await Promise.resolve().then(()=>(Ai(),Ti));await e({json:J.opts().json})});Gc.command("security").description("Scan for vulnerabilities (npm audit) and exploit patterns (XSS, secrets, tabnabbing)").action(async()=>{let{auditSecurity:e}=await Promise.resolve().then(()=>(Li(),Fi));await e({json:J.opts().json})});J.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(()=>(Gn(),Hn));await o("preview");return}let{preview:n}=await Promise.resolve().then(()=>(Bn(),Mi));await n(e,t)});J.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(()=>(Gn(),Hn));await o("publish");return}let{publish:n}=await Promise.resolve().then(()=>(Ii(),_i));await n(e,t)});(async()=>{try{if(process.argv.slice(2).length===0)if(process.stdout.isTTY){let{mainMenu:e}=await Promise.resolve().then(()=>(Bc(),Uc));await e()}else J.outputHelp();else await J.parseAsync()}catch(e){a.error(e instanceof Error?e.message:String(e)),process.exitCode=1}})();
|
|
1118
|
+
`),o){case"claude":a.info(` ${me.cyan("claude mcp add --transport sse figma-sse https://mcp.figma.com/sse")}`),a.info(" or for Figma Desktop app:"),a.info(` ${me.cyan("claude mcp add --transport http figma-desktop http://127.0.0.1:3845/mcp")}`);break;case"cursor":a.info(` Add to ${me.cyan("~/.cursor/mcp.json")}:`),a.info(me.dim(JSON.stringify({mcpServers:{figma:{url:"https://mcp.figma.com/sse"}}},null,2)));break;case"codex":a.info(" See Figma MCP docs: https://help.figma.com/hc/en-us/articles/32132100833559");break}a.info("")}else r?.hasFigmaMcp&&a.success(`Figma MCP is already configured for ${o}!`)}if(a.info(me.dim(`
|
|
1119
|
+
Note: Figma MCP requires a Figma seat (Dev or Full on paid plans for desktop server).`)),await t({message:"Save preferences to ~/.eds/config.json?",default:!0})){let r=Ps();ef(r)||await tf(r,{recursive:!0});let s={};o!=="none"&&(s.agent=o),await nf(ci(),`${JSON.stringify(s,null,2)}
|
|
1120
|
+
`,{mode:384}),a.success(`Config saved to ${me.cyan(ci())}`)}a.info(me.bold(`
|
|
1121
|
+
Setup complete!`)),o!=="none"&&a.info(`Try: ${me.cyan('eds block from-design "<figma-url>" --dry-run')}`)}var Ki=v(()=>{"use strict";f();Bn();ue();O();B()});var Vi={};U(Vi,{doctor:()=>af});import{existsSync as an}from"fs";import{readFile as sn,readdir as rf}from"fs/promises";import Xe from"path";import{parse as ml}from"yaml";async function af(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n=Ar(t);e.json||(a.logoOnce(A("Doctor")),a.info(j("Doctor",t)));let o=[];if(o.push({name:"fstab.yaml exists",status:n.hasFstab?"pass":"warn",message:n.hasFstab?"Found":"Missing - fine for Universal Editor / DA; required for document-mounted setups"}),n.hasFstab)try{let p=await sn(Xe.join(t,"fstab.yaml"),"utf-8");ml(p),o.push({name:"fstab.yaml valid YAML",status:"pass",message:"Valid"})}catch{o.push({name:"fstab.yaml valid YAML",status:"fail",message:"Invalid YAML syntax"})}if(o.push({name:"head.html exists",status:n.hasHeadHtml?"pass":"warn",message:n.hasHeadHtml?"Found":"Missing - recommended for metadata/scripts"}),o.push({name:"blocks/ directory",status:n.hasBlocks?"pass":"warn",message:n.hasBlocks?"Found":"Missing - no blocks yet"}),n.hasBlocks){let p=Xe.join(t,"blocks"),u=await rf(p,{withFileTypes:!0}),g="",h=Xe.join(t,"component-models.json");if(an(h))try{g=await sn(h,"utf-8")}catch{}for(let $ of u){if(!$.isDirectory())continue;let w=$.name,y=Xe.join(p,w,`${w}.js`),b=an(y);o.push({name:`blocks/${w} has JS`,status:b?"pass":"warn",message:b?"Found":`Missing ${w}.js`}),b&&(await sn(y,"utf-8")).includes("console.log")&&o.push({name:`blocks/${w} no console.log`,status:"warn",message:"Found console.log - remove before production"});let T=an(Xe.join(p,w,`_${w}.json`)),F=g.includes(`"${w}"`);o.push({name:`blocks/${w} UE model`,status:T||F?"pass":"warn",message:T||F?T?`_${w}.json`:"in component-models.json":"no Universal Editor model - authors can't edit this block in UE"});let N=Xe.join(p,w,".eds-meta.json");if(an(N))try{let te=JSON.parse(await sn(N,"utf-8")),Ne=new Date(te.lastSyncedAt),D=Math.floor((Date.now()-Ne.getTime())/(1e3*60*60*24));o.push({name:`blocks/${w} Figma sync`,status:D>30?"warn":"pass",message:D>30?`Last synced ${D} days ago - design may have changed`:`Synced ${D} days ago`})}catch{o.push({name:`blocks/${w} .eds-meta.json`,status:"warn",message:"Invalid metadata file"})}}}let i=Xe.join(t,"helix-query.yaml");if(an(i))try{let p=await sn(i,"utf-8");ml(p),o.push({name:"helix-query.yaml valid",status:"pass",message:"Valid YAML"})}catch{o.push({name:"helix-query.yaml valid",status:"fail",message:"Invalid YAML syntax"})}o.push({name:"~/.eds/config.json",status:li()?"pass":"warn",message:li()?"Found":'Missing - run "eds figma setup" to configure'});let r=o.filter(p=>p.status==="fail"),s=o.filter(p=>p.status==="warn");if(e.json){let p={pass:o.filter(u=>u.status==="pass").length,warn:s.length,fail:r.length};console.log(JSON.stringify({projectRoot:t,results:o,summary:p},null,2)),r.length>0&&(process.exitCode=1);return}let c=_(o.map(p=>p.name));for(let p of o)a.info(R(p.status,p.name,p.message,c));let l=o.filter(p=>p.status==="fail"),d=o.filter(p=>p.status==="warn"),m=o.filter(p=>p.status==="pass");a.info(""),a.info(W([$e({pass:m.length,warn:d.length,fail:l.length})])),l.length>0&&(process.exitCode=1)}var Xi=v(()=>{"use strict";f();ue();O();K();B()});var Qi={};U(Qi,{auditLoading:()=>cf});import{existsSync as Le}from"fs";import{readFile as vt,readdir as sf,stat as pl}from"fs/promises";import Oe from"path";import Yi from"chalk";async function cf(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}e.json||(a.logoOnce(A("Loading Audit")),a.info(j("Loading Order Audit",t)));let n=[];if(await lf(t,n),await df(t,n),await mf(t,n),await pf(t,n),await uf(t,n),await ff(t,n),e.json){let o={pass:n.filter(i=>i.status==="pass").length,warn:n.filter(i=>i.status==="warn").length,fail:n.filter(i=>i.status==="fail").length,info:n.filter(i=>i.status==="info").length};console.log(JSON.stringify({projectRoot:t,results:n,summary:o},null,2)),o.fail>0&&(process.exitCode=1);return}hf(n)}async function lf(e,t){let n=Oe.join(e,"head.html");if(!Le(n)){t.push({rule:"head.html exists",status:"warn",message:"Missing head.html"});return}let o=await vt(n,"utf-8"),i=o.split(`
|
|
1122
|
+
`);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 s=(o.match(/<link[^>]+rel=["']stylesheet["'][^>]*>/gi)||[]).filter(l=>!l.includes("styles/styles.css")&&!l.includes("styles.css"));s.length>0&&t.push({rule:"No extra stylesheets in head.html",status:"warn",message:`${s.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 df(e,t){let n=Oe.join(e,"scripts","scripts.js");if(!Le(n)){t.push({rule:"scripts/scripts.js exists",status:"warn",message:"Missing scripts.js \u2014 cannot audit loading phases"});return}let o=await vt(n,"utf-8"),i=o.split(`
|
|
1123
|
+
`),r=/function\s+loadEager|loadEager\s*=/i.test(o),s=/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:s?"pass":"fail",message:s?"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=gf(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 mf(e,t){let n=Oe.join(e,"styles","styles.css");if(!Le(n))return;let i=(await pl(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 vt(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 pf(e,t){let n=Oe.join(e,"scripts","delayed.js");if(!Le(n)){t.push({rule:"scripts/delayed.js exists",status:"info",message:"No delayed.js \u2014 third-party scripts should go here"});return}(await vt(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 uf(e,t){let n=Oe.join(e,"blocks");if(!Le(n))return;let o=await sf(n,{withFileTypes:!0});for(let i of o){if(!i.isDirectory())continue;let r=i.name,s=Oe.join(n,r,`${r}.js`);if(!Le(s))continue;let c=await vt(s,"utf-8"),l=c.split(`
|
|
1124
|
+
`),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 pl(s)).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,s=Oe.join(n,r,`${r}.css`);if(!Le(s))continue;let c=await vt(s,"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 ff(e,t){let n=Oe.join(e,"scripts","aem.js");if(!Le(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 gf(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,s=r;for(;r<e.length&&i>0;)e[r]==="{"?i++:e[r]==="}"&&i--,r++;return e.slice(s,r-1)}function hf(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){a.info(` ${X.bullet} ${Yi.underline(o)}`);for(let r of i){let s=r.line?Yi.dim(`:${r.line}`):"";a.info(` ${mn(r.status)} ${r.rule}${s}`),r.status!=="pass"&&a.info(Yi.dim(` ${r.message}`))}a.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};a.info(W([$e(n)])),n.fail>0&&(process.exitCode=1)}var Zi=v(()=>{"use strict";f();O();K();B()});var tr={};U(tr,{auditSecurity:()=>jf});import{existsSync as oo}from"fs";import{readFile as wf,readdir as bf}from"fs/promises";import Ye from"path";import er from"chalk";async function*fl(e){let t=await bf(e,{withFileTypes:!0});for(let n of t){let o=Ye.join(e,n.name);if(n.isDirectory()){if(kf.has(n.name))continue;yield*fl(o)}else n.isFile()&&(yield o)}}function $f(e,t,n){let o=[],i=e.split(`
|
|
1125
|
+
`);for(let r=0;r<i.length;r++){let s=i[r],c=!1;for(let l of yf)l.ext.includes(n)&&(l.id==="innerhtml-static"&&c||l.re.test(s)&&(l.extra&&!l.extra(s)||(l.id==="innerhtml-dynamic"&&(c=!0),o.push({severity:l.severity,rule:l.id,message:l.message,file:t,line:r+1,snippet:s.trim().slice(0,100)}))))}return o}async function Sf(e){if(!oo(Ye.join(e,"package.json")))return{status:"skipped",note:"no package.json"};if(!(oo(Ye.join(e,"package-lock.json"))||oo(Ye.join(e,"npm-shrinkwrap.json")))&&!oo(Ye.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??{},s={critical:r.critical??0,high:r.high??0,moderate:r.moderate??0,low:r.low??0};return{status:s.critical+s.high+s.moderate+s.low>0?"vulnerable":"ok",counts:s}}catch(n){return{status:"skipped",note:`npm audit failed: ${n.message}`}}}async function jf(e={}){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}let n=[];for await(let l of fl(t)){let d=Ye.extname(l).slice(1).toLowerCase();if(!xf.has(d))continue;let m=Ye.relative(t,l);if(m.endsWith("aem.js")||m.endsWith("lib-franklin.js"))continue;let p=await wf(l,"utf-8");n.push(...$f(p,m,d))}let o=await Sf(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},s=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)),s&&(process.exitCode=1);return}if(a.logoOnce(A("Security Audit")),a.info(j("Dependencies","npm audit")),o.status==="skipped")a.info(R("info","npm audit",o.note??"skipped"));else if(o.status==="ok")a.info(R("pass","npm audit","no known vulnerabilities"));else{let l=o.counts??{critical:0,high:0,moderate:0,low:0};a.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(a.info(j("Exploit scan","XSS \xB7 secrets \xB7 injection \xB7 tabnabbing")),n.length===0)a.info(R("pass","code","no risky patterns found"));else{let l=[...n].sort((d,m)=>ul.indexOf(d.severity)-ul.indexOf(m.severity));for(let d of l){let m=vf[d.severity],p=er.dim(`${d.file}:${d.line}`);a.info(` ${mn(m.status)} ${er.bold(m.label)} ${d.message} ${p}`),a.info(er.dim(` ${d.snippet}`))}}let c=$e({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)});a.info(""),a.info(W([c||`${X.pass} no vulnerabilities or risky patterns found`])),s&&(process.exitCode=1)}var yf,ul,vf,kf,xf,nr=v(()=>{"use strict";f();O();K();B();yf=[{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"]}],ul=["critical","high","moderate","low"],vf={critical:{status:"fail",label:"CRIT"},high:{status:"fail",label:"HIGH"},moderate:{status:"warn",label:"MOD "},low:{status:"info",label:"LOW "}},kf=new Set(["node_modules",".git","dist","build",".vscode","coverage"]),xf=new Set(["js","mjs","html","json","pem","txt"])});async function gl(e,t,n){let o=t.ref||"main",i=n.startsWith("/")?n:`/${n}`,r=`${Pf}/${e}/${t.org}/${t.site}/${o}${i}`;a.debug(`POST ${r}`);let s=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"}}),c=await s.json().catch(()=>({})),l=c;return s.ok?{ok:!0,status:s.status,path:i,previewUrl:l.preview?.url,liveUrl:l.live?.url}:{ok:!1,status:s.status,path:i,message:c.message||`HTTP ${s.status}`}}async function or(e,t){return gl("preview",e,t)}async function ir(e,t){return gl("live",e,t)}async function hl(e,t){return Promise.all(t.map(n=>or(e,n)))}async function wl(e,t){return Promise.all(t.map(n=>ir(e,n)))}var Pf,rr=v(()=>{"use strict";f();O();Pf="https://admin.hlx.page"});var ar={};U(ar,{preview:()=>Cf,resolveAdminConfig:()=>io});import bl from"chalk";import Ef from"ora";async function Cf(e,t){let n=E(),o=await se(n),i=io(o,t);if(!i)return;let r=Ef(`Previewing ${e.length} path(s)...`).start(),s=e.length===1?[await or(i,e[0])]:await hl(i,e);r.stop();let c=!1;for(let l of s)l.ok?a.success(`${l.path} \u2192 ${bl.cyan(l.previewUrl||"preview updated")}`):(a.error(`${l.path} \u2014 ${l.message}`),c=!0);c&&(process.exitCode=1)}function io(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){a.error("Missing --org and --site. Set them via flags or in .edsrc.json:"),a.info(bl.dim(' { "admin": { "org": "my-org", "site": "my-site" } }')),process.exitCode=1;return}return{org:n,site:o,ref:i}}var ro=v(()=>{"use strict";f();rr();ue();O();K()});var sr={};U(sr,{publish:()=>Rf});import Tf from"chalk";import Af from"ora";async function Rf(e,t){let n=E(),o=await se(n),i=io(o,t);if(!i)return;let r=Af(`Publishing ${e.length} path(s)...`).start(),s=e.length===1?[await ir(i,e[0])]:await wl(i,e);r.stop();let c=!1;for(let l of s)l.ok?a.success(`${l.path} \u2192 ${Tf.cyan(l.liveUrl||"published")}`):(a.error(`${l.path} \u2014 ${l.message}`),c=!0);c&&(process.exitCode=1)}var cr=v(()=>{"use strict";f();rr();ue();O();K();ro()});var ao={};U(ao,{adminWizard:()=>Df});async function Df(e){let t=E();if(!t){a.error("Not inside an EDS project (no EDS project markers found)."),process.exitCode=1;return}a.logoOnce(A("Admin API \u2014 preview / publish"));let{select:n,input:o,confirm:i}=await Promise.resolve().then(()=>(q(),J)),s=(await se(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:s.org})).trim(),d=(await o({message:"Repository / site",default:s.site})).trim(),m=(await o({message:"Git ref",default:s.ref||"main"})).trim(),u=(await o({message:"Paths (space- or comma-separated)",default:"/"})).split(/[\s,]+/).filter(Boolean);if(!l||!d||u.length===0){a.error("org, site and at least one path are required."),process.exitCode=1;return}a.info(j("Summary"));let g=_(["operation","org","site","ref","paths"]);if(a.info(P("operation",c,g)),a.info(P("org",l,g)),a.info(P("site",d,g)),a.info(P("ref",m,g)),a.info(P("paths",u.join(", "),g)),a.info(""),c==="publish"&&!await i({message:`Publish ${u.length} path(s) to LIVE?`,default:!1})){a.info("Cancelled.");return}let h={org:l,site:d,ref:m};if(c==="preview"){let{preview:$}=await Promise.resolve().then(()=>(ro(),ar));await $(u,h)}else{let{publish:$}=await Promise.resolve().then(()=>(cr(),sr));await $(u,h)}}var so=v(()=>{"use strict";f();ue();O();K();B()});var yl={};U(yl,{mainMenu:()=>If});import{existsSync as Ff}from"fs";import{readdir as Lf}from"fs/promises";import Of from"path";import Nf from"chalk";async function lr(e){let t=Of.join(e,"blocks");return Ff(t)?(await Lf(t,{withFileTypes:!0})).filter(o=>o.isDirectory()).map(o=>o.name):[]}async function If(){let{select:e,isEscape:t,isExit:n}=await Promise.resolve().then(()=>(q(),J));Kn.menu=!0,await a.logoOnceAnimated("");let o;for(;;){a.info(Nf.dim(" Esc quits here \xB7 goes back to this menu from any step"));let i;try{i=await e({message:"Choose an action",choices:Mf,default:o})}catch(r){if(t(r)||n(r))return;throw r}if(i==="exit")return;o=i;try{await _f(i)}catch(r){if(n(r))return;t(r)||a.error(r instanceof Error?r.message:String(r))}process.exitCode=void 0,a.info("")}}async function _f(e){let{select:t,input:n}=await Promise.resolve().then(()=>(q(),J));switch(e){case"new":{let{newProject:o}=await Promise.resolve().then(()=>(Co(),Eo));await o(void 0,{});return}case"init":{let{initProject:o}=await Promise.resolve().then(()=>(At(),Tt));await o({});return}case"template":{let o=await n({message:"Template name",validate:r=>!!r.trim()||"Required"}),{templateNew:i}=await Promise.resolve().then(()=>(No(),Oo));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(()=>(Ge(),He));await i(o.trim(),{});return}case"from-design":{let{blockFromDesign:o}=await Promise.resolve().then(()=>(eo(),Zn));await o(void 0,{});return}case"migrate":{let{migrateComponent:o}=await Promise.resolve().then(()=>(Wo(),Go));await o(void 0,{});return}case"scaffold":{let{scaffoldInteractive:o}=await Promise.resolve().then(()=>(pe(),he));await o();return}case"create":{let o=await n({message:"Block name",validate:r=>_e.test(r.trim())||"Use kebab-case, e.g. hero-banner"}),{createBlock:i}=await Promise.resolve().then(()=>(ri(),ii));await i(o.trim(),{});return}case"integrate":{let{integrate:o}=await Promise.resolve().then(()=>(Ji(),zi));await o(void 0);return}case"preview-block":{let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found).");return}let i=await lr(o);if(i.length===0){a.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(c=>({name:c,value:c}))}),{previewBlock:s}=await Promise.resolve().then(()=>(De(),gt));await s(r,{});return}case"model":{let{modelAdd:o}=await Promise.resolve().then(()=>(Zo(),Qo));await o(void 0,[],{});return}case"track":{let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found).");return}let i=await lr(o);if(i.length===0){a.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:s}=await Promise.resolve().then(()=>(It(),Mt));await s(r,{});return}case"schema":{let o=E();if(!o){a.error("Not inside an EDS project (no EDS project markers found).");return}let i=await lr(o);if(i.length===0){a.warn("No blocks found in blocks/.");return}let r=await t({message:"Which block?",choices:i.map(c=>({name:c,value:c}))}),{schemaBlock:s}=await Promise.resolve().then(()=>(ti(),ei));await s(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(()=>(Ht(),Bt));await i()}else{let i=await n({message:"Page path",default:"/"}),{ueOpen:r}=await Promise.resolve().then(()=>(Ht(),Bt));await r(i.trim()||"/",{})}return}case"admin":{let{adminWizard:o}=await Promise.resolve().then(()=>(so(),ao));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(()=>(Xi(),Vi));await i({})}else if(o==="loading"){let{auditLoading:i}=await Promise.resolve().then(()=>(Zi(),Qi));await i({})}else{let{auditSecurity:i}=await Promise.resolve().then(()=>(nr(),tr));await i({})}return}case"figma-setup":{let{figmaSetup:o}=await Promise.resolve().then(()=>(Ki(),qi));await o();return}}}var Mf,vl=v(()=>{"use strict";f();O();K();Ze();Vn();Mf=[{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 Uf from"chalk";import{Command as Bf}from"commander";var ur={name:"aem-eds-kit",version:"0.4.58",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"}};O();B();var G=new Bf;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(ur.version).option("--verbose","Enable verbose output").option("--quiet","Suppress non-error output").option("--json","Output in JSON format").option("--no-color","Disable color output").showHelpAfterError("(add --help for usage)").hook("preAction",e=>{let t=e.opts();t.verbose&&a.setLevel("debug"),t.quiet&&a.setQuiet(!0),t.color===!1&&(Uf.level=0)});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(()=>(Co(),Eo));await n(e,t)});var cn=G.command("sandbox").description("Disposable EDS sandbox repos on GitHub");cn.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(()=>(Ge(),He));await n(e,t)});cn.command("login").description("Authorize GitHub (OAuth device flow or a token) - no gh needed").action(async()=>{let{sandboxLogin:e}=await Promise.resolve().then(()=>(Ge(),He));await e()});cn.command("logout").description("Remove the stored GitHub token").action(async()=>{let{sandboxLogout:e}=await Promise.resolve().then(()=>(Ge(),He));await e()});cn.command("list").description("List your EDS sandboxes (repos tagged eds-sandbox)").action(async()=>{let{sandboxList:e}=await Promise.resolve().then(()=>(Ge(),He));await e()});cn.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(()=>(Ge(),He));await n(e,t)});var Hf=G.command("template").description("Generate page templates / initial content");Hf.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(()=>(No(),Oo));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(()=>(At(),Tt));await t(e)});var Gf=G.command("migrate").description("Migrate from classic AEM to EDS");Gf.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(()=>(Wo(),Go));await n(e,t)});var Wf=G.command("model").description("Compose Universal Editor models");Wf.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(()=>(Zo(),Qo));await o(e,t,n)});var zf=G.command("schema").description("Structured data (JSON-LD) for blocks");zf.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(()=>(ti(),ei));await n(e,t)});var Jf=G.command("track").description("Instrument blocks for analytics");Jf.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(()=>(It(),Mt));await n(e,t)});var kl=G.command("ue").description("Universal Editor - readiness check + editor deep link");kl.command("check").description("Check whether blocks are Universal-Editor-ready (offline)").action(async()=>{let{ueCheck:e}=await Promise.resolve().then(()=>(Ht(),Bt));await e()});kl.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(()=>(Ht(),Bt));await n(e,t)});var kt=G.command("block").description("Manage EDS blocks");kt.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(()=>(ri(),ii));await n(e,t)});kt.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)=>{let{blockFromDesign:n}=await Promise.resolve().then(()=>(eo(),Zn));await n(e,t)});var ln=G.command("draft").description("Review drafts from `block from-design --draft`: preview, refine, accept or discard");ln.command("list").description("List drafts and their versions").action(async()=>{let{draftList:e}=await Promise.resolve().then(()=>(wt(),ht));await e()});ln.command("preview <name>").description("Preview a draft version in the browser (latest unless --version)").option("--version <n>","Draft version (default: latest)").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)=>{let{draftPreview:n}=await Promise.resolve().then(()=>(wt(),ht));await n(e,t)});ln.command("refine <name> <feedback>").description("One more agent round on the draft; the result is the next version").option("--version <n>","Start from this version (default: 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)=>{let{draftRefine:o}=await Promise.resolve().then(()=>(wt(),ht));await o(e,t,n)});ln.command("accept <name>").description("Copy a draft version into blocks/<name>/ (optionally commit it)").option("--version <n>","Version to accept (default: latest)").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)=>{let{draftAccept:n}=await Promise.resolve().then(()=>(wt(),ht));await n(e,t)});ln.command("discard <name>").description("Drop a draft and its versions; blocks/ is untouched").action(async e=>{let{draftDiscard:t}=await Promise.resolve().then(()=>(wt(),ht));await t(e)});kt.command("list").description("List all blocks in the project").action(async e=>{let{listBlocks:t}=await Promise.resolve().then(()=>(Hc(),Bc));await t({...e,json:G.opts().json})});kt.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(()=>(De(),gt));e?await n.previewBlock(e,t):await n.galleryPreview(t)});kt.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(()=>(tl(),el));await n(e,t)});kt.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(()=>(rl(),il));await n(e,t)});var xt=G.command("scaffold").description("Scaffold standard UE components and blocks").action(async()=>{let{scaffoldInteractive:e}=await Promise.resolve().then(()=>(pe(),he));await e()});xt.command("ue").description("Scaffold default-content UE components + a field-reference block (all 17 fields)").action(async()=>{let{scaffoldUe:e}=await Promise.resolve().then(()=>(pe(),he));await e()});xt.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(()=>(pe(),he));await t(e)});xt.command("ci").description("Scaffold a GitHub Actions workflow (doctor + audits + project lint/build)").action(async()=>{let{scaffoldCi:e}=await Promise.resolve().then(()=>(pe(),he));await e()});xt.command("helpers [names...]").description("Scaffold scripts/utils.js with chosen EDS helpers (interactive picker)").action(async e=>{let{scaffoldHelpers:t}=await Promise.resolve().then(()=>(pe(),he));await t(e)});xt.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(()=>(pe(),he));await t(e)});xt.command("xwalk").description("Write xwalk.json enabling Universal Editor multi-field support").action(async()=>{let{scaffoldXwalk:e}=await Promise.resolve().then(()=>(pe(),he));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(()=>(Ji(),zi));await t(e)});var qf=G.command("figma").description("Figma MCP integration");qf.command("setup").description("Configure Figma MCP for your AI agent").action(async()=>{let{figmaSetup:e}=await Promise.resolve().then(()=>(Ki(),qi));await e()});G.command("doctor").description("Audit your EDS project for common issues").action(async()=>{let{doctor:e}=await Promise.resolve().then(()=>(Xi(),Vi));await e({json:G.opts().json})});var xl=G.command("audit").description("Run project audits");xl.command("loading").description("Check loading order (eager/lazy/delayed phases, LCP budget)").action(async()=>{let{auditLoading:e}=await Promise.resolve().then(()=>(Zi(),Qi));await e({json:G.opts().json})});xl.command("security").description("Scan for vulnerabilities (npm audit) and exploit patterns (XSS, secrets, tabnabbing)").action(async()=>{let{auditSecurity:e}=await Promise.resolve().then(()=>(nr(),tr));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(()=>(so(),ao));await o("preview");return}let{preview:n}=await Promise.resolve().then(()=>(ro(),ar));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(()=>(so(),ao));await o("publish");return}let{publish:n}=await Promise.resolve().then(()=>(cr(),sr));await n(e,t)});(async()=>{try{if(process.argv.slice(2).length===0)if(process.stdout.isTTY){let{mainMenu:e}=await Promise.resolve().then(()=>(vl(),yl));await e()}else G.outputHelp();else await G.parseAsync()}catch(e){a.error(e instanceof Error?e.message:String(e)),process.exitCode=1}})();
|