aem-eds-kit 0.4.33 → 0.4.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
  ## [Unreleased]
8
8
 
9
9
  ### Changed
10
+ - **README rewritten for the npm page** (EDS-047): absolute links (relative
11
+ ones break on npmjs.com), a docs / changelog / e2e links row, a "What it does"
12
+ list, a wider package description and keywords.
13
+ - **Figma REST specs are embedded as compact JSON** (part of EDS-020), as
14
+ scraped specs already were - fewer prompt tokens, same data.
15
+ - **`eds block test` screenshots just the block** (EDS-021). Baselines used to
16
+ be full-page shots of a 900 px tall viewport, so a short block carried
17
+ hundreds of pixels of white and a height change inside them went unnoticed.
18
+ Existing baselines need one `eds block test --update`; a run against an old
19
+ baseline says so instead of reporting a size change.
10
20
  - **`block from-design` now fetches the design once into a cached snapshot,
11
21
  then generates from it** (fetch → cache → generate). The CLI resolves the
12
22
  design via the cheapest adapter - local SVG/PNG export, a cached snapshot
@@ -17,7 +27,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
17
27
  - **MCP usage cut to one call per block.** The prompt now uses only
18
28
  `get_design_context` (dropped `get_variable_defs`; `get_screenshot` is opt-in
19
29
  via `--screenshot`) - the Figma Dev Mode MCP server meters tool calls per plan
20
- (Starter/View/Collab: ~6-20/month). Set a Figma token to skip MCP via REST.
30
+ (20/month on Starter or with a View/Collab seat; 200-600/day with Dev/Full on
31
+ paid plans). Set a Figma token to fetch via REST instead, on its own budget.
21
32
  - **Block generation defaults to the fastest model (Haiku)**, overridable with
22
33
  `model` in config - block codegen is structured, bounded work.
23
34
  - **`eds block preview` no longer auto-launches.** After `from-design` you get a
@@ -31,6 +42,28 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
31
42
  bundled binary (`dist/bin/eds.js` 265 kB → ~170 kB).
32
43
 
33
44
  ### Fixed
45
+ - **Figma limits described correctly** (EDS-040). Code comments, README, docs
46
+ and site said REST had a "far larger quota on every plan". Its Tier 1
47
+ endpoints are 20 calls/month on Starter or with a View/Collab seat, and
48
+ 10-20/min with Dev/Full on paid plans. The README now has the REST and MCP
49
+ limits table, with links to Figma's pages.
50
+ - **A Figma REST rate limit no longer spends your MCP budget** (EDS-039). A 429
51
+ used to fall back to Figma MCP silently. Now a short `Retry-After` (≤ 60 s)
52
+ is waited out and retried once; a plan cap stops with when it resets, the
53
+ plan tier, and the options (`--mcp`, a PNG/SVG export). `--design` reports
54
+ the same.
55
+ - **Content Fragment blocks are generated as Content Fragment blocks**
56
+ (EDS-019). With `--source cf` / `mixed`, Claude Code now defaults to
57
+ `sonnet` (a `model` in config still wins) and the prompt makes the CF field
58
+ plus an async, fetching `decorate()` a hard requirement. On the fast default
59
+ model both sources produced plain document blocks.
60
+ - **Migrated checkboxes no longer default to ticked** (EDS-032). The default
61
+ now comes from `checked`, not from `value` (which is the value a ticked box
62
+ submits), for Touch UI and Classic UI dialogs.
63
+ - **Cursor and Codex get a large prompt through its file** (EDS-017). They
64
+ take the prompt as one command-line argument; past 96 KB (a scraped page of
65
+ ~30 sections) it's replaced by a short instruction to read the saved prompt
66
+ file, so the spawn can't hit Linux's 128 KB per-argument limit (E2BIG).
34
67
  - **Block preview blank-screen cases.** The harness now (a) reduces a full-HTML
35
68
  `_<name>.preview.html` mock to its `<body>` contents, (b) reveals the body past
36
69
  the EDS `body.appear` visibility gate (which `scripts.js` would normally flip),
@@ -46,6 +79,29 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
46
79
  is a CLI, exposed via its `bin`.
47
80
 
48
81
  ### Added
82
+ - **Changelog page on the site** (EDS-048): `site/changelog.html` is generated
83
+ from this file by `scripts/site-changelog.mjs` in the Pages workflow, with
84
+ EDS-NNN references linked to their issues. It's in the nav on every page,
85
+ the docs sidebar, the footers and the sitemap.
86
+ - **The interactive menu stays open** (EDS-042). `eds` with no command now
87
+ returns to the menu after each action (or its failure). Arrows move, Enter
88
+ runs, **Esc** goes back to the menu from any prompt and quits from the menu
89
+ itself (or pick *Exit*); Ctrl+C quits anywhere. A preview opened from the
90
+ menu stops on Esc / Enter and returns. Commands run with arguments still run
91
+ once and exit.
92
+ - **Figma REST calls are paced per minute** (EDS-041). All `eds` runs in a
93
+ project share a call log (`tmp/eds-cli/figma-rest-calls.json`) and wait for a
94
+ free slot, so generating many blocks at once doesn't trip Tier 1's per-minute
95
+ limit. `figma.restPerMinute` in config, default 10 (Professional; 15
96
+ Organization, 20 Enterprise). Twelve parallel runs: ten fetch at once, the
97
+ last two at ~61 s, no 429.
98
+ - **`eds migrate component` reads Classic UI dialogs** (EDS-018). A component
99
+ with only a `dialog.xml` (AEM 6.5) is mapped from its ExtJS xtypes - text,
100
+ textarea, richtext (incl. the foundation `rte.*` include), pathfield,
101
+ numberfield, selection (checkbox / select / radio, static options or
102
+ datasource → text), smartimage, multifield (plain multi-value, or ACS
103
+ `multifieldpanel` → container), tabpanel and `cqinclude`. Tested on the 22
104
+ Classic UI dialogs of ACS Commons 3.14: 21 migrate, 63 valid fields.
49
105
  - **`eds block preview` with no name → a live gallery of every content block**,
50
106
  each in its own width-honest iframe. Routes are computed per request, so a
51
107
  block generated while the gallery is open appears on the next reload
package/README.md CHANGED
@@ -5,15 +5,27 @@
5
5
  [![npm version](https://img.shields.io/npm/v/aem-eds-kit.svg)](https://www.npmjs.com/package/aem-eds-kit)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/aem-eds-kit.svg)](https://www.npmjs.com/package/aem-eds-kit)
7
7
  [![CI](https://github.com/piotrgodycki/aem-eds-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/piotrgodycki/aem-eds-kit/actions/workflows/ci.yml)
8
- [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/piotrgodycki/aem-eds-kit/blob/main/LICENSE)
9
9
  [![node](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)
10
10
 
11
+ **[Docs](https://piotrgodycki.github.io/aem-eds-kit/docs.html)** · **[Changelog](https://piotrgodycki.github.io/aem-eds-kit/changelog.html)** · **[End-to-end test](https://piotrgodycki.github.io/aem-eds-kit/e2e-example.html)** · **[GitHub](https://github.com/piotrgodycki/aem-eds-kit)** · **[Issues](https://github.com/piotrgodycki/aem-eds-kit/issues)**
12
+
11
13
  **Turn a design into an EDS block** - JS, CSS and a Universal Editor model - without leaving your terminal.
12
14
 
13
15
  `aem-eds-kit` gives you the `eds` command. Paste a design link - a Figma URL, or a Framer / Google Stitch page - and it hands the design to the AI agent you already use (Claude Code, Cursor or Codex), which writes production-ready code straight into your repo. Figma is read through MCP or the REST API; Framer and Stitch render real HTML, so they're **scraped with headless Chromium** (no token needed). It also scaffolds blocks, previews them in your browser, and keeps your project healthy with a few quick audits.
14
16
 
15
17
  It lives next to `@adobe/aem-cli` (your local dev server) and handles everything around it.
16
18
 
19
+ ## What it does
20
+
21
+ - **Blocks from a design.** A Figma frame (REST or MCP), a Framer / Google Stitch page (scraped with headless Chromium) or a local PNG / SVG export becomes `blocks/<name>/`: JS, CSS, a Universal Editor model and a preview mock. Works with Claude Code, Cursor and Codex. Content Fragment blocks (`--source cf` / `mixed`) get an async, fetching `decorate()`.
22
+ - **Migration from AEM.** `eds migrate component` turns a classic component's dialog into a block and a UE model, with no agent involved. It handles AEM as a Cloud Service proxy components (via `sling:resourceSuperType`, e.g. onto Core Components) and AEM 6.5 Classic UI `dialog.xml` files.
23
+ - **Within Figma's limits.** One REST or MCP call per block, then a cache. REST calls are paced per minute across parallel runs. A rate limit stops with the reset time; it never spends your MCP budget behind your back. [The limits](#how-figma-integration-works).
24
+ - **QA before review.** `eds block test` does visual regression on the block itself, plus a design↔render diff. `eds block check` covers content and a11y, including preview mocks nested deeper than real EDS markup. There are also `doctor`, loading and security audits.
25
+ - **An interactive menu that stays open.** Run `eds`, then use the arrows, Enter, and Esc to go back. Every command also runs non-interactively for CI.
26
+
27
+ Proof: the whole example screen (11 blocks) was generated from a scraped page and from Figma exports, screenshotted next to the design, and 163 + 22 real AEM components were migrated. See the [end-to-end test](https://piotrgodycki.github.io/aem-eds-kit/e2e-example.html).
28
+
17
29
  ## Install
18
30
 
19
31
  ```bash
@@ -78,7 +90,7 @@ eds block from-design \
78
90
 
79
91
  ## Interactive mode
80
92
 
81
- Run `eds` with no command and it opens an **interactive menu** that walks you through every feature (set up the project, generate a block from a design, migrate a classic AEM component, scaffold, create a block, add an integration, preview, Admin API, audits, Figma setup). Most commands are also interactive on their own when you omit arguments - e.g. `eds init`, `eds block from-design` (wizard), `eds migrate component`, `eds scaffold`, `eds integrate`, `eds preview`. Flags and subcommands still work for CI / power users.
93
+ Run `eds` with no command and it opens an **interactive menu** that stays open between actions (arrows to move, Enter to run, **Esc** to go back - or to quit from the menu itself; Ctrl+C quits anywhere). It walks you through every feature (set up the project, generate a block from a design, migrate a classic AEM component, scaffold, create a block, add an integration, preview, Admin API, audits, Figma setup). Most commands are also interactive on their own when you omit arguments - e.g. `eds init`, `eds block from-design` (wizard), `eds migrate component`, `eds scaffold`, `eds integrate`, `eds preview`. Flags and subcommands still work for CI / power users.
82
94
 
83
95
  A full A-Z reference of every command lives on the docs page: **https://piotrgodycki.github.io/aem-eds-kit/docs.html**
84
96
 
@@ -223,9 +235,13 @@ Start migrating a **classic AEM component** to EDS. Phase 1 is deterministic (no
223
235
 
224
236
  It also pulls the component's **clientlib CSS** off disk into the block's CSS when it can find one (auto-detected, or `--clientlib <dir>`): it honours `css.txt` ordering (and `#base=`), concatenates the `.css`, and flags any LESS/SCSS that needs a build. Treat it as a starting point - review the selectors and scope them under `.<block>`.
225
237
 
238
+ **AEM as a Cloud Service and AEM 6.5.** A *proxy component* (the usual AEMaaCS setup: no dialog of its own, just `sling:resourceSuperType` pointing at a Core Component) inherits its parent's dialog. The parent is looked up in the component's own `jcr_root`, and in any folder passed with `--super-root` (e.g. a checkout of `adobe/aem-core-wcm-components`, `content/src/content/jcr_root`). Granite `include`s are resolved from disk the same way. A component with only a **Classic UI** dialog (`dialog.xml`, still found on AEM 6.5) is read from its ExtJS `xtype`s: `textfield`, `textarea`, `richtext`, `pathfield`, `numberfield`, `selection`, `smartimage`, `multifield` (incl. ACS `multifieldpanel`), `tabpanel` and `cqinclude`.
239
+
226
240
  ```bash
227
241
  eds migrate component /path/to/apps/myproject/components/hero
228
242
  eds migrate component ./components/hero --name hero --clientlib ./ui.apps/.../hero/clientlib --yes
243
+ eds migrate component ./ui.apps/.../apps/wknd/components/teaser \
244
+ --super-root ../aem-core-wcm-components/content/src/content/jcr_root # proxy → Core Component dialog
229
245
  ```
230
246
 
231
247
  Dialogs map cleanly because Granite's `sling:resourceType` set is finite. The most faithful CSS actually comes from the **rendered page** (resolves LESS vars + cascade) - that capture lands in a later phase; for now the clientlib source gets you most of the way.
@@ -275,7 +291,7 @@ eds ue open / --org my-org --ref dev
275
291
  eds ue open /blog --url main--site--owner.aem.page --no-open
276
292
  ```
277
293
 
278
- Full workflow (proxy, `.env`, `xwalk.json`, editor deep link): [`docs/local-development.md`](docs/local-development.md).
294
+ Full workflow (proxy, `.env`, `xwalk.json`, editor deep link): [`docs/local-development.md`](https://github.com/piotrgodycki/aem-eds-kit/blob/main/docs/local-development.md).
279
295
 
280
296
  ### `eds block create <name>`
281
297
 
@@ -286,7 +302,7 @@ eds block create hero-banner # js + css + _hero-banner.json (UE mode
286
302
  eds block create hero-banner --no-ue-model # skip the UE model
287
303
  ```
288
304
 
289
- The generated `_<name>.json` uses the EDS block-plugin (xwalk) format (`definitions` / `models` / `filters`) with starter fields (title + heading-level select + rich text). Extend it from the **full catalog of all 17 Universal Editor field types** - see [`docs/universal-editor-fields.md`](docs/universal-editor-fields.md). `eds block from-design` picks the right field type per Figma layer automatically.
305
+ The generated `_<name>.json` uses the EDS block-plugin (xwalk) format (`definitions` / `models` / `filters`) with starter fields (title + heading-level select + rich text). Extend it from the **full catalog of all 17 Universal Editor field types** - see [`docs/universal-editor-fields.md`](https://github.com/piotrgodycki/aem-eds-kit/blob/main/docs/universal-editor-fields.md). `eds block from-design` picks the right field type per Figma layer automatically.
290
306
 
291
307
  ### `eds block from-design [design-url]`
292
308
 
@@ -301,12 +317,23 @@ Translates a design - **a Figma URL, a Framer / Google Stitch page, or a local S
301
317
  1. **Local file** — pass a path to an SVG/PNG export (`eds block from-design ./hero.svg`) → read from disk, no network.
302
318
  2. **Cache** — a snapshot already fetched for this design (`tmp/eds-cli/design-cache/`) is reused.
303
319
  3. **Web scrape (Framer / Stitch)** — the live page is rendered in headless Chromium and its computed layout/styles are extracted. Needs Playwright + a browser: `npx playwright install chromium`.
304
- 4. **Figma REST** — if a Figma token is set, `eds` fetches the node itself and embeds a compact design spec. Separate, generous quota; **does not touch the MCP limit**.
320
+ 4. **Figma REST** — if a Figma token is set, `eds` fetches the node itself and embeds a compact design spec. Its own budget, separate from MCP (see the limits below); **does not spend MCP calls**.
305
321
  5. **Figma MCP** — fallback: the agent makes **one** `get_design_context` call and caches it.
306
322
 
307
323
  The agent then generates pixel-perfect code (JS + CSS) **and its Universal Editor model** by default, with lightweight **placeholders** for not-yet-authored content. You see a **live, colour-coded log** with per-phase timings. On success you get a **menu** — refine the block with another pass, open the live preview, or finish (preview is **opt-in**, never auto-launched).
308
324
 
309
- > **Figma MCP limits:** the Dev Mode MCP server is metered per plan (Starter / View / Collab seats: ~6–20 **tool calls a month**). `eds` uses **one** MCP call per block and caches it; set a Figma token to skip MCP entirely via REST. See [How Figma integration works](#how-figma-integration-works).
325
+ > **Figma limits.** Figma meters both paths, and the limit follows the **plan that owns the file** (a Full seat elsewhere doesn't help a file in a Starter team).
326
+ >
327
+ > | | Starter | Professional | Organization | Enterprise |
328
+ > |---|---|---|---|---|
329
+ > | **REST** (Tier 1: file, nodes, image), Dev / Full seat | 20 / month | 10 / min | 15 / min | 20 / min |
330
+ > | **REST**, View / Collab seat | 20 / month | 20 / month | 20 / month | 20 / month |
331
+ > | **MCP**, Dev / Full seat | 20 / month | 200 / day, 10 / min | 200 / day, 15 / min | 600 / day, 20 / min |
332
+ > | **MCP**, View / Collab seat | 20 / month | 20 / month | 20 / month | 20 / month |
333
+ >
334
+ > `eds` spends **one** call per block (REST `file nodes`, or MCP `get_design_context`) and caches it; `--design` adds one REST `image` call, `--screenshot` one MCP call. A REST 429 with a short `Retry-After` is waited out; a plan cap stops instead of spending MCP calls. A local PNG/SVG export uses no quota. Figma can change these numbers - see its [REST](https://developers.figma.com/docs/rest-api/rate-limits/) and [MCP](https://developers.figma.com/docs/figma-mcp-server/rate-limits-access/) pages.
335
+ >
336
+ > See [How Figma integration works](#how-figma-integration-works).
310
337
 
311
338
  ```bash
312
339
  eds block from-design # interactive wizard
@@ -322,9 +349,9 @@ eds block from-design "<figma-url>" --dry-run # just build the prompt
322
349
  |---|---|
323
350
  | `--name <name>` | Override the inferred block name |
324
351
  | `--provider <type>` | Design source: `figma` \| `framer` \| `stitch` (else detected from the URL) |
325
- | `--source <type>` | Content source: `document` \| `ue` \| `cf` \| `mixed` |
352
+ | `--source <type>` | Content source: `document` \| `ue` \| `cf` \| `mixed` (`cf` / `mixed` default to the `sonnet` model) |
326
353
  | `--widths <list>` | Design frame widths for preview breakpoints (e.g. `390,768,1440`) |
327
- | `--agent <type>` | Force `claude` \| `cursor` \| `codex` \| `none` |
354
+ | `--agent <type>` | Force `claude` \| `cursor` \| `codex` \| `none` (a prompt too large for one argument reaches Cursor / Codex as its file) |
328
355
  | `--dry-run` | Build the prompt only |
329
356
  | `--no-ue-model` | Skip the Universal Editor model |
330
357
  | `--screenshot` | Add a screenshot MCP call for a pixel check (opt-in — costs a call) |
@@ -380,7 +407,7 @@ eds block preview hero --port 9000 --no-open
380
407
 
381
408
  Two deterministic QA passes over a block's **rendered** DOM (no agent) - one block, or **all** of them when you omit the name. Both render the block in headless Chromium (Playwright), so install the browser once: `npx playwright install chromium`. Wire them into CI next to the audits - both exit non-zero on failure.
382
409
 
383
- **`eds block test`** - **visual regression.** Screenshots each block at every breakpoint and diffs it (pixelmatch) against a committed baseline in `blocks/<name>/__snapshots__/`; it fails when the changed-pixel ratio crosses the threshold (default 1%) and writes the diff image to `tmp/eds-cli/visual-diff/`. `--update` (re)writes the baselines after an intended change. `--design` does a **design↔render** diff instead - the rendered block against its Figma design image (needs a Figma token and a Figma source in the block's `.eds-meta.json`).
410
+ **`eds block test`** - **visual regression.** Screenshots each block (the block element only, not the empty viewport) at every breakpoint and diffs it (pixelmatch) against a committed baseline in `blocks/<name>/__snapshots__/`; it fails when the changed-pixel ratio crosses the threshold (default 1%) and writes the diff image to `tmp/eds-cli/visual-diff/`. `--update` (re)writes the baselines after an intended change. `--design` does a **design↔render** diff instead - the rendered block against its Figma design image (needs a Figma token and a Figma source in the block's `.eds-meta.json`).
384
411
 
385
412
  ```bash
386
413
  eds block test # all blocks vs committed baselines
@@ -398,7 +425,7 @@ eds block test --threshold 0.02 # allow 2% changed pixels
398
425
  | `--widths <list>` | Breakpoint widths (e.g. `375,768,1280`) |
399
426
  | `--port <port>` | Port for the internal preview server (default `8788`) |
400
427
 
401
- **`eds block check`** - **content, link & a11y.** Renders each block (after `decorate()`) and flags missing image `alt`, missing image dimensions (CLS risk), links/buttons with no accessible name, empty `href`s and inline event handlers. Checks run at the widest breakpoint; it exits non-zero on any error, or on any warning with `--strict`.
428
+ **`eds block check`** - **content, link & a11y.** Renders each block (after `decorate()`) and flags missing image `alt`, missing image dimensions (CLS risk), links/buttons with no accessible name, empty `href`s and inline event handlers. It also warns when the preview mock (`_<name>.preview.html`) nests cell content one `<div>` deeper than real EDS markup (row > cell > content), which leaves `decorate()` written against the mock misreading real content. Checks run at the widest breakpoint; it exits non-zero on any error, or on any warning with `--strict`.
402
429
 
403
430
  ```bash
404
431
  eds block check # all blocks
@@ -549,7 +576,7 @@ The design is fetched **once** into a cached snapshot, then the agent generates
549
576
  ```
550
577
 
551
578
  - **No token needed** for the MCP path — the agent uses its own Figma MCP connection and makes **one** `get_design_context` call per block (then caches it).
552
- - **Set a Figma token** (`FIGMA_TOKEN` or `figma.token`) to use the **REST** path instead: `eds` fetches the node over HTTPS and embeds a compact spec — a **separate, far larger quota** than the MCP limit, so it works comfortably on Starter / Collab seats.
579
+ - **Set a Figma token** (`FIGMA_TOKEN` or `figma.token`) to use the **REST** path instead: `eds` fetches the node over HTTPS and embeds a compact spec, on REST's own budget instead of MCP's. With a Dev / Full seat on a paid plan that's a per-minute limit (10–20 / min) instead of MCP's daily cap; on Starter, or with a View / Collab seat, both are 20 calls a month.
553
580
  - **Local export** (`./file.svg|png`) reads straight from disk — zero network, best for vector/text-heavy frames.
554
581
 
555
582
  The prompt includes:
@@ -569,11 +596,13 @@ Priority: CLI flags → env vars → `.edsrc.json` (project) → `~/.eds/config.
569
596
  {
570
597
  "agent": "claude",
571
598
  "model": "haiku",
572
- "figma": { "token": "figd_…" }
599
+ "figma": { "token": "figd_…", "restPerMinute": 10 }
573
600
  }
574
601
  ```
575
602
  `model` sets the block-generation model (default: fastest / Haiku). `figma.token` (or the `FIGMA_TOKEN` env var) enables the REST fetch path — a Personal Access Token with scope `file_content:read`. Tokens are secrets; keep them out of the repo.
576
603
 
604
+ `figma.restPerMinute` paces Figma REST calls across every `eds` run in the project (they share `tmp/eds-cli/figma-rest-calls.json`), so a batch of blocks waits for a free slot instead of hitting a 429. Default **10** (Tier 1, Dev / Full seat on Professional); use 15 on Organization, 20 on Enterprise. On Starter or with a View / Collab seat the cap is monthly (20), so pacing can't help there.
605
+
577
606
  **`.edsrc.json`** (project root, optional):
578
607
  ```json
579
608
  {
@@ -669,7 +698,8 @@ Tests use fixtures in `tests/fixtures/` - a sample EDS project and recorded Figm
669
698
 
670
699
  ## Roadmap
671
700
 
672
- - **Design sources** - Figma (REST/MCP), Framer and Google Stitch (headless-Chromium scrape) are wired; next is deepening the scrape extractor (multi-breakpoint capture, component/variant detection) and a generic `eds setup` in place of `eds figma setup`. Canva/Sketch stay on the local-export path (canvas/image — not scrapeable).
701
+ - **Design sources** - Figma (REST/MCP), Framer and Google Stitch (headless-Chromium scrape) are wired; next is deepening the scrape extractor (multi-breakpoint capture, component/variant detection), a generic `eds setup` in place of `eds figma setup`, and an end-to-end run against a real Figma file ([EDS-020](https://github.com/piotrgodycki/aem-eds-kit/issues/20)). Canva/Sketch stay on the local-export path (canvas/image — not scrapeable).
702
+ - **Migration** - dialogs (Touch UI and Classic UI) map deterministically today; next is HTL → `decorate()` and capturing CSS from the rendered page.
673
703
  - **Screenshot-to-block** - build a block from a plain image (harder: no structured layout/measurements, so pixel-perfect is tougher).
674
704
  - **Tokens & sync** - design variables → CSS custom properties, and incremental re-sync of an existing block (`--update`).
675
705
  - **Headless & CI** - a direct MCP client (no agent needed) for CI/CD, plus `eds lighthouse`, `eds rum` and `eds migrate page`.
@@ -682,4 +712,4 @@ Adobe, AEM, Edge Delivery Services and Universal Editor are trademarks of Adobe
682
712
 
683
713
  ## License
684
714
 
685
- MIT - see [LICENSE](LICENSE).
715
+ MIT - see [LICENSE](https://github.com/piotrgodycki/aem-eds-kit/blob/main/LICENSE).