aem-eds-kit 0.4.48 → 0.4.57

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/README.md CHANGED
@@ -12,13 +12,23 @@
12
12
 
13
13
  **Turn a design into an EDS block** - JS, CSS and a Universal Editor model - without leaving your terminal.
14
14
 
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.
15
+ `aem-eds-kit` gives you the `eds` command. Paste a design link (a Figma frame, a Framer or Google Stitch page, or any web page) and it hands the design to the AI agent you already use: Claude Code, Cursor or Codex, or a local model through Ollama / oMLX. The agent writes the block straight into your repo. Figma is read through its REST API or MCP; web pages are **scraped with headless Chromium**, no token needed.
16
16
 
17
- It lives next to `@adobe/aem-cli` (your local dev server) and handles everything around it.
17
+ It lives next to `@adobe/aem-cli` (your `aem up` dev server) and handles everything around it: new projects, blocks, migration from AEM, previews, checks and publishing.
18
+
19
+ ```bash
20
+ npm install -g aem-eds-kit
21
+ eds new my-site && cd my-site # the latest Adobe boilerplate
22
+ eds block from-design "<design link>" --name hero # design → blocks/hero/
23
+ eds block preview hero # see it in the browser
24
+ ```
25
+
26
+ **Contents:** [What it does](#what-it-does) · [Install](#install) · [Try it](#try-it-in-30-seconds-no-figma-account-no-token) · [Interactive mode](#interactive-mode) · [Commands](#commands) · [Figma](#how-figma-integration-works) · [Local models](#local-models-ollama-omlx) · [Configuration](#configuration) · [Roadmap](#roadmap)
18
27
 
19
28
  ## What it does
20
29
 
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()`.
30
+ - **A new project in one command.** `eds new` clones Adobe's latest boilerplate (Document Authoring, Universal Editor or Commerce) without a GitHub login, and `eds init` sets it up for your authoring model.
31
+ - **Blocks from a design.** A Figma frame (REST or MCP), a Framer / Google Stitch page or any other web 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, or a [local model](#local-models-ollama-omlx) through Ollama or oMLX. Content Fragment blocks (`--source cf` / `mixed`) get an async, fetching `decorate()`.
22
32
  - **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
33
  - **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
34
  - **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.
@@ -26,6 +36,17 @@ It lives next to `@adobe/aem-cli` (your local dev server) and handles everything
26
36
 
27
37
  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
38
 
39
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/design-vs-block.webp" alt="A Google Stitch hero design next to the EDS block eds generated from it: same layout, type scale, colours and buttons, with placeholder copy" width="100%"></p>
40
+
41
+ <details>
42
+ <summary><strong>The whole screen</strong>: design vs. the 11 generated blocks</summary>
43
+
44
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/design-vs-page.webp" alt="The full example page design next to the page built from 11 generated EDS blocks" width="100%"></p>
45
+
46
+ Generated blocks ship with placeholder copy (and empty image slots) until authors fill them in; the layout, spacing, type and colours come from the design.
47
+
48
+ </details>
49
+
29
50
  ## Install
30
51
 
31
52
  ```bash
@@ -70,7 +91,7 @@ eds block from-design "<figma-url>" --name hero
70
91
 
71
92
  ## Try it in 30 seconds (no Figma account, no token)
72
93
 
73
- From inside an EDS project (or spin a throwaway one up with `eds sandbox new demo`):
94
+ From inside an EDS project (or clone a fresh one with `eds new demo && cd demo`):
74
95
 
75
96
  ```bash
76
97
  eds block from-design --sample --name hero --dry-run # see the prompt - zero setup
@@ -78,19 +99,32 @@ eds block from-design --sample --name hero # generate it with your A
78
99
  eds block preview hero # see it live in the browser
79
100
  ```
80
101
 
81
- `--sample` uses a **bundled "Kiri Bloom" hero design**, read straight from disk - **no Figma token, no MCP call, no network**. (`--dry-run` needs no AI agent either - it just prints the prompt.)
102
+ `--sample` uses the **hero of the project's example design**, bundled as an SVG and read straight from disk - **no Figma token, no MCP call, no network**. (`--dry-run` needs no AI agent either - it just prints the prompt.)
103
+
104
+ A real run (Claude Code): the agent's live log, a verification pass over the files it wrote, then a menu to refine, preview or finish.
105
+
106
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/cli-fd.png" alt="Terminal: eds block from-design --sample (the example hero), showing the design source, the agent's live log, the files it wrote, a verification table and the refine / preview / finish menu" width="760"></p>
107
+
108
+ `eds block preview` serves the block at the design's own widths, with live reload:
109
+
110
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/block-preview.webp" alt="Browser: the eds block preview harness showing the hero block at 1440 px with a breakpoint dropdown" width="100%"></p>
82
111
 
83
- Ready for the real thing? Point it at the official **Kiri Bloom AEM EDS Kit** training file in Figma:
112
+ Ready for the real thing? The same example design exists as a page you can build every block from, and as a Figma file:
84
113
 
85
114
  ```bash
86
- eds block from-design \
87
- "https://www.figma.com/design/vwlEKTFhcrlwuA8dRgN5SD/Kiri-Bloom-AEM-EDS-Kit-Example?node-id=0-1" \
88
- --name hero
115
+ # the example page (11 sections: hero, stats, cards, …) - read like a Framer / Stitch page
116
+ eds block from-design "https://piotrgodycki.github.io/aem-eds-kit/example/" --name cards
89
117
  ```
90
118
 
119
+ The Figma version is built by the plugin in [`examples/figma-kit`](https://github.com/piotrgodycki/aem-eds-kit/tree/main/examples/figma-kit) (run it once in Figma desktop); then pass any of its frame links.
120
+
91
121
  ## Interactive mode
92
122
 
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.
123
+ 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: new project (clone the boilerplate), set up project, page template, sandbox repo, block from design, migrate component, scaffold UE, empty block, integration, model fields, analytics, structured data, Universal Editor, preview block, pages (preview / publish), audits and Figma MCP.
124
+
125
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/cli-menu.png" alt="Terminal: the eds interactive menu with Block from design selected" width="560"></p>
126
+
127
+ 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.
94
128
 
95
129
  A full A-Z reference of every command lives on the docs page: **https://piotrgodycki.github.io/aem-eds-kit/docs.html**
96
130
 
@@ -99,6 +133,9 @@ A full A-Z reference of every command lives on the docs page: **https://piotrgod
99
133
  ```bash
100
134
  eds # interactive menu
101
135
 
136
+ # Start from the latest boilerplate (DA, Universal Editor or Commerce)
137
+ eds new my-site
138
+
102
139
  # Just cloned an EDS boilerplate? Set it up for your authoring model
103
140
  eds init
104
141
 
@@ -131,7 +168,8 @@ The full path, command by command. This example targets **DA (da.live)** authori
131
168
  # 1. Install the CLI
132
169
  npm i -g aem-eds-kit
133
170
 
134
- # 2. Set up the project (pick DA, enter org + site). Writes fstab + CI + naming.
171
+ # 2. Clone the latest boilerplate, then set it up (pick DA, enter org + site)
172
+ eds new my-site && cd my-site
135
173
  eds init --authoring da --org my-org --site my-site
136
174
 
137
175
  # 3. Scaffold the Universal Editor config + helper functions
@@ -160,6 +198,32 @@ Every step is also interactive when you omit the flags - run `eds` for the menu.
160
198
 
161
199
  ## Commands
162
200
 
201
+ ### `eds new [dir]`
202
+
203
+ Clone the **current EDS boilerplate** into a local folder. No GitHub auth needed, and nothing is created on GitHub (for a repo on GitHub, see [`eds sandbox`](#eds-sandbox)). Choose Document Authoring / DA (`adobe/aem-boilerplate`), Universal Editor / crosswalk (`adobe-rnd/aem-boilerplate-xwalk`), the Adobe Commerce storefront (`hlxsites/aem-boilerplate-commerce`), or any repo or git URL.
204
+
205
+ By default the copy starts a **fresh git history**, with one initial commit naming the boilerplate commit it came from. `--keep-history` keeps the boilerplate's history with its remote named `upstream`, so `git pull upstream main` brings in later boilerplate changes. It refuses a folder that isn't empty, then offers `npm install` and `eds init`, with Universal Editor preselected for the crosswalk boilerplate.
206
+
207
+ ```bash
208
+ eds new # guided
209
+ eds new my-site --yes # DA boilerplate, fresh history
210
+ eds new my-site --ue --keep-history # crosswalk, with an upstream remote
211
+ eds new shop --boilerplate commerce --install
212
+ eds new my-site --remote git@github.com:me/my-site.git
213
+ ```
214
+
215
+ | Flag | Description |
216
+ |---|---|
217
+ | `--boilerplate <repo>` | `da` \| `ue` \| `commerce`, `owner/repo` on GitHub, or any git URL / path |
218
+ | `--ue` | The crosswalk / Universal Editor boilerplate |
219
+ | `--ref <ref>` | Branch or tag to clone |
220
+ | `--keep-history` | Keep the boilerplate's history (remote renamed to `upstream`) |
221
+ | `--remote <url>` | Set `origin` to your own repo |
222
+ | `--install` | Run `npm install` after cloning |
223
+ | `--yes` | Skip the guided prompts |
224
+
225
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/cli-new-picker.png" alt="Terminal: eds new asking for a folder and offering the DA, Universal Editor and Commerce boilerplates" width="660"></p>
226
+
163
227
  ### `eds init`
164
228
 
165
229
  Adapt a freshly cloned EDS boilerplate to your setup in one interactive wizard. Pick the authoring model - **Universal Editor (crosswalk), DA (da.live), Google Drive or SharePoint** - and `eds` sets the project name (`package.json` + boilerplate placeholders), writes `fstab.yaml` **only when the model needs it** (UE/crosswalk doesn't), scaffolds the crosswalk config + `paths.json` for UE, optionally adds the CI workflow, then walks the **external steps** (AEM Code Sync app, content-source share, Sidekick) as a clickable checklist.
@@ -171,15 +235,18 @@ By default it also writes, out of the box:
171
235
 
172
236
  Opt out with `--no-env` / `--no-xwalk`, or (re)generate either later with `eds scaffold env` / `eds scaffold xwalk`.
173
237
 
238
+ **Non-interactive (`--yes`).** The project name defaults to the folder name (or `package.json`'s, unless that's still the boilerplate's own). The authoring model is detected from the `fstab.yaml` mountpoint (an AEM author → Universal Editor, `content.da.live` → DA, Google Drive, SharePoint) or a crosswalk `paths.json`, and preselected in the interactive picker. When it can't be told (the DA boilerplate ships no `fstab.yaml`), `--yes` stops with exit 1 and asks for `--authoring`.
239
+
174
240
  ```bash
175
241
  eds init # interactive
242
+ eds init --yes # detect everything (e.g. right after `eds new --ue`)
176
243
  eds init --name my-site --authoring da --org my-org --site my-site --yes
177
244
  ```
178
245
 
179
246
  | Flag | Description |
180
247
  |---|---|
181
248
  | `--name <name>` | Project name (kebab-case) |
182
- | `--authoring <model>` | `ue` \| `da` \| `gdrive` \| `sharepoint` |
249
+ | `--authoring <model>` | `ue` \| `da` \| `gdrive` \| `sharepoint` (else detected from `fstab.yaml` / `paths.json`) |
183
250
  | `--mountpoint <url>` | Content source URL (document models) |
184
251
  | `--org <org>` / `--site <site>` | DA org / site (`--authoring da`) |
185
252
  | `--no-ci` | Skip the GitHub Actions workflow |
@@ -216,18 +283,21 @@ Spin up and tear down **disposable EDS sandbox repos** on GitHub - a rapid, thro
216
283
  eds sandbox login # authorize GitHub (device flow or token)
217
284
  eds sandbox new my-test # guided: boilerplate, visibility, Code Sync, eds init
218
285
  eds sandbox new my-test --ue --private --yes
286
+ eds sandbox new shop --boilerplate hlxsites/aem-boilerplate-commerce # any template repo
219
287
  eds sandbox list # your sandboxes (tagged eds-sandbox) + preview URLs
220
288
  eds sandbox rm my-test # delete it (with confirmation)
221
289
  ```
222
290
 
223
- `sandbox new` creates the repo from a boilerplate (Document Authoring `adobe/aem-boilerplate` or Universal Editor `adobe/aem-boilerplate-xwalk`) via the GitHub API, clones it, tags it `eds-sandbox`, then walks you through opening the AEM Code Sync install page and running `eds init`. The preview URL is `https://main--<repo>--<owner>.aem.page/`.
291
+ `sandbox new` creates the repo from a boilerplate (Document Authoring `adobe/aem-boilerplate`, Universal Editor `adobe-rnd/aem-boilerplate-xwalk`, or any template repo with `--boilerplate <owner/repo>`) via the GitHub API, clones it, tags it `eds-sandbox`, then walks you through opening the AEM Code Sync install page and running `eds init`. The preview URL is `https://main--<repo>--<owner>.aem.page/`.
224
292
 
225
293
  Sandboxes are **throwaway test repos** - stand one up to debug or try an integration, then delete it; they work fine on a personal account. Two safety guarantees:
226
294
 
227
295
  - **Never overwrites an existing repo.** `sandbox new` checks first and refuses if `<owner>/<name>` already exists (and the GitHub template API never clobbers either way).
228
296
  - **Least privilege.** Scope the token to just your sandboxes - a fine-grained token limited to one repo, or a dedicated sandbox org used via `--org`. `eds sandbox login` links you straight to the token page with the minimal permissions. See the [Secure GitHub sandboxes guide](https://piotrgodycki.github.io/aem-eds-kit/secure-github-sandboxes.html).
229
297
 
230
- The token is stored owner-only (mode `0600`) in `~/.eds/github.json`; `eds sandbox logout` removes it. `list` only ever shows `eds-sandbox` repos and `rm` deletes only the named repo, with confirmation.
298
+ The token is stored owner-only (mode `0600`) in `~/.eds/github.json`; `eds sandbox logout` removes it. `list` only ever shows `eds-sandbox` repos and `rm` deletes only the named repo (under `--org <org>` when it lives in an org), with confirmation.
299
+
300
+ Just want the code on your machine, no GitHub repo? Use [`eds new`](#eds-new-dir).
231
301
 
232
302
  ### `eds migrate component [dir]`
233
303
 
@@ -244,6 +314,8 @@ eds migrate component ./ui.apps/.../apps/wknd/components/teaser \
244
314
  --super-root ../aem-core-wcm-components/content/src/content/jcr_root # proxy → Core Component dialog
245
315
  ```
246
316
 
317
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/cli-mig.png" alt="Terminal: eds migrate component on the WKND teaser proxy component; the dialog is inherited from the Core Components teaser and its 13 fields are mapped to Universal Editor field types" width="760"></p>
318
+
247
319
  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.
248
320
 
249
321
  ### `eds track block <name>`
@@ -306,9 +378,9 @@ The generated `_<name>.json` uses the EDS block-plugin (xwalk) format (`definiti
306
378
 
307
379
  ### `eds block from-design [design-url]`
308
380
 
309
- Translates a design - **a Figma URL, a Framer / Google Stitch page, or a local SVG/PNG export** - into an EDS block. Run with **no URL** for a step-by-step wizard (design source, name, link, content source, UE model, screenshot, run mode). It builds a prompt with EDS conventions + your project's design tokens and hands it to your AI agent (Claude Code, Cursor, or Codex). *(This was `from-figma` before it went design-agnostic; Figma is the most battle-tested source and stays pixel-perfect.)*
381
+ Translates a design - **a Figma URL, a Framer / Google Stitch page, or a local SVG/PNG export** - into an EDS block. Run with **no URL** for a step-by-step wizard (design source, name, link, content source, UE model, screenshot, run mode). It builds a prompt with EDS conventions + your project's design tokens and hands it to your AI agent (Claude Code, Cursor or Codex, or a [local model](#local-models-ollama-omlx)). *(This was `from-figma` before it went design-agnostic; Figma is the most battle-tested source and stays pixel-perfect.)*
310
382
 
311
- **Figma vs. web sources.** Figma paints to a WebGL canvas, so it's read through the **REST API** (with a token) or **MCP**. Framer and Google Stitch render **real HTML**, so `eds` **scrapes** them with headless Chromium — reading computed layout, typography, colours and geometry straight off the page (no token, no MCP). Canva and Sketch are canvas/image-based and aren't scrapeable — export a frame and pass it as a local SVG/PNG. The provider is detected from the URL host, or set with `--provider`.
383
+ **Figma vs. web sources.** Figma paints to a WebGL canvas, so it's read through the **REST API** (with a token) or **MCP**. Framer, Google Stitch and **any other web page** (a live site you're rebuilding, an HTML mock-up) render **real HTML**, so `eds` **scrapes** them with headless Chromium — reading computed layout, typography, colours and geometry straight off the page (no token, no MCP). On a page with several sections, the block is built from the one matching `--name`: try `eds block from-design https://piotrgodycki.github.io/aem-eds-kit/example/ --name cards`. Canva and Sketch are canvas/image-based and aren't scrapeable — export a frame and pass it as a local SVG/PNG. The provider is detected from the URL (Figma, Framer, Stitch, else a web page), or set with `--provider`.
312
384
 
313
385
  **Gated sources (`--auth`).** A Google Stitch project (and a private Framer page) sits behind a login, so an anonymous scrape only sees the sign-in shell. Pass `--auth` and `eds` opens a **headed** browser once — you log in by hand, it saves the session, and every later scrape reuses it. The session (cookies/localStorage) is stored owner-only under `~/.eds/auth/<provider>.json`; re-login with `--auth-refresh`. (The saved session is a secret — it's never written to the repo.)
314
386
 
@@ -340,18 +412,20 @@ eds block from-design # interactive wizard
340
412
  eds block from-design "<figma-url>" --name hero # non-interactive (REST if a token is set, else MCP)
341
413
  eds block from-design "<framer-url>" --name hero # Framer/Stitch → scraped with headless Chromium
342
414
  eds block from-design "<stitch-url>" --name hero --auth # gated source → log in once, reuse the session
415
+ eds block from-design "https://piotrgodycki.github.io/aem-eds-kit/example/" --name cards # any web page, one section
343
416
  eds block from-design ./hero.svg --name hero # from a local export (no network)
344
- eds block from-design --sample --name hero # bundled Kiri Bloom sample (no token, no MCP)
417
+ eds block from-design --sample --name hero # bundled example hero (no token, no MCP)
345
418
  eds block from-design "<figma-url>" --dry-run # just build the prompt
346
419
  ```
347
420
 
348
421
  | Flag | Description |
349
422
  |---|---|
350
423
  | `--name <name>` | Override the inferred block name |
351
- | `--provider <type>` | Design source: `figma` \| `framer` \| `stitch` (else detected from the URL) |
424
+ | `--provider <type>` | Design source: `figma` \| `framer` \| `stitch` \| `web` (else detected from the URL) |
352
425
  | `--source <type>` | Content source: `document` \| `ue` \| `cf` \| `mixed` (`cf` / `mixed` default to the `sonnet` model) |
353
426
  | `--widths <list>` | Design frame widths for preview breakpoints (e.g. `390,768,1440`) |
354
- | `--agent <type>` | Force `claude` \| `cursor` \| `codex` \| `none` (a prompt too large for one argument reaches Cursor / Codex as its file) |
427
+ | `--agent <type>` | Force `claude` \| `cursor` \| `codex` \| `ollama` \| `omlx` \| `local` \| `none` (a prompt too large for one argument reaches Cursor / Codex as its file; see [Local models](#local-models-ollama-omlx)) |
428
+ | `--model <name>` | Model to run: a Claude alias / id, or a local model such as `qwen2.5-coder:14b` |
355
429
  | `--dry-run` | Build the prompt only |
356
430
  | `--no-ue-model` | Skip the Universal Editor model |
357
431
  | `--screenshot` | Add a screenshot MCP call for a pixel check (opt-in — costs a call) |
@@ -359,7 +433,7 @@ eds block from-design "<figma-url>" --dry-run # just build the prompt
359
433
  | `--auth` | Scrape with a logged-in session (Framer/Stitch): log in once, reuse it |
360
434
  | `--auth-refresh` | Force a fresh scrape login even if a session is saved |
361
435
  | `--refresh` | Ignore the cached snapshot and re-fetch |
362
- | `--sample` | Use the bundled Kiri Bloom sample design (no URL, token or MCP) |
436
+ | `--sample` | Use the bundled sample design, the example file's hero (no URL, token or MCP) |
363
437
  | `--serve` | Auto-start the live preview (non-interactive runs only) |
364
438
  | `--yes` | Skip confirmation prompts |
365
439
 
@@ -376,7 +450,7 @@ The generated block records the **design's frame widths** in its `.eds-meta.json
376
450
  ### `eds figma setup`
377
451
 
378
452
  Interactive wizard that:
379
- 1. Detects installed AI agents (Claude Code, Cursor, Codex)
453
+ 1. Detects installed AI agents (Claude Code, Cursor, Codex) and running local model servers (Ollama, oMLX)
380
454
  2. Checks if Figma MCP is configured for your agent
381
455
  3. Shows install commands if not
382
456
  4. Saves preferences to `~/.eds/config.json`
@@ -403,6 +477,13 @@ eds block preview hero --widths 375,768,1280 # custom breakpoints
403
477
  eds block preview hero --port 9000 --no-open
404
478
  ```
405
479
 
480
+ - A dropdown switches the block between breakpoints inside an `<iframe>`, so the block's media queries fire against the chosen width - a **width-honest** comparison that isn't distorted by your monitor size.
481
+ - Breakpoints come from the block's `.eds-meta.json` (`breakpoints`, marking which widths have a real Figma frame → pixel-perfect) and fall back to `375 / 768 / 1280` or `--widths`.
482
+ - If the block has a `.eds-meta.json` with a Figma source, an **Open in Figma** link is shown.
483
+ - Authored sample content is read from `blocks/<name>/_<name>.preview.html` if present; otherwise a placeholder is used (and the chrome tells you to add one).
484
+
485
+ > Not to be confused with `eds preview [paths...]` (lower down), which previews **pages** via the AEM Admin API.
486
+
406
487
  ### `eds block test [name]` · `eds block check [name]`
407
488
 
408
489
  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.
@@ -417,6 +498,11 @@ eds block test hero --design # rendered block vs its Figma design imag
417
498
  eds block test --threshold 0.02 # allow 2% changed pixels
418
499
  ```
419
500
 
501
+ A CSS change that moved the hero's buttons and text, caught at 1440 px, with the diff image it wrote:
502
+
503
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/cli-test.png" alt="Terminal: eds block test hero reporting 2.48% changed pixels at 1440px and the diff PNG path" width="760"></p>
504
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/visual-diff.webp" alt="Diff image: the changed pixels of the hero block highlighted in red and yellow" width="760"></p>
505
+
420
506
  | Flag | Description |
421
507
  |---|---|
422
508
  | `--update` | (Re)write baseline screenshots instead of comparing |
@@ -433,6 +519,8 @@ eds block check hero # one block
433
519
  eds block check --strict # fail on warnings too
434
520
  ```
435
521
 
522
+ <p align="center"><img src="https://raw.githubusercontent.com/piotrgodycki/aem-eds-kit/main/.github/assets/readme/cli-check.png" alt="Terminal: eds block check hero warning that the preview mock nests cell content one div deeper than EDS markup" width="760"></p>
523
+
436
524
  | Flag | Description |
437
525
  |---|---|
438
526
  | `--strict` | Fail on warnings too, not just errors |
@@ -473,28 +561,23 @@ eds integrate # interactive
473
561
  eds integrate gtm # gtm · ga4 · chat · cookiebot · custom
474
562
  ```
475
563
 
476
- - A dropdown switches the block between breakpoints inside an `<iframe>`, so the block's media queries fire against the chosen width - a **width-honest** comparison that isn't distorted by your monitor size.
477
- - Breakpoints come from the block's `.eds-meta.json` (`breakpoints`, marking which widths have a real Figma frame → pixel-perfect) and fall back to `375 / 768 / 1280` or `--widths`.
478
- - If the block has a `.eds-meta.json` with a Figma source, an **Open in Figma** link is shown.
479
- - Authored sample content is read from `blocks/<name>/_<name>.preview.html` if present; otherwise a placeholder is used (and the chrome tells you to add one).
480
-
481
- > Not to be confused with `eds preview <paths...>` (lower down), which previews **pages** via the AEM Admin API.
564
+ ### `eds preview [paths...]`
482
565
 
483
- ### `eds preview <path...>`
484
-
485
- Preview pages via the AEM Admin API (`admin.hlx.page`).
566
+ Preview pages via the AEM Admin API (`admin.hlx.page`). Run it with no paths for a wizard (pick the action, the paths and the org / site / ref).
486
567
 
487
568
  ```bash
569
+ eds preview # wizard
488
570
  eds preview /index
489
571
  eds preview /blog/my-post /about
490
572
  eds preview /index --org my-org --site my-repo --ref main
491
573
  ```
492
574
 
493
- ### `eds publish <path...>`
575
+ ### `eds publish [paths...]`
494
576
 
495
- Publish pages to live via the AEM Admin API.
577
+ Publish pages to live via the AEM Admin API (a wizard when run with no paths).
496
578
 
497
579
  ```bash
580
+ eds publish # wizard
498
581
  eds publish /index
499
582
  eds publish /blog/my-post /about
500
583
  ```
@@ -571,7 +654,8 @@ The design is fetched **once** into a cached snapshot, then the agent generates
571
654
  ┌─ local SVG/PNG ─┐
572
655
  ├─ cache hit ──────┤ design.json ┌─────────────┐ block files
573
656
  design reference ──┼─ Figma REST ─────┼───→ (cached) ───────→│ Claude Code │ ───────────────→ repo
574
- (url / file) └─ Figma MCP ──────┘ snapshot │ /Cursor/Codex│
657
+ (url / file) ├─ web scrape ─────┤ snapshot │ Cursor/Codex│
658
+ └─ Figma MCP ──────┘ │ Ollama/oMLX │
575
659
  (1 call, agent dumps to cache) └─────────────┘
576
660
  ```
577
661
 
@@ -587,6 +671,35 @@ The prompt includes:
587
671
  - Lighthouse performance requirements + a single structural self-verification pass
588
672
  - Output file structure
589
673
 
674
+ ## Local models (Ollama, oMLX)
675
+
676
+ Keep designs and code on your machine: `eds block from-design` can run a local model instead of Claude Code / Cursor / Codex.
677
+
678
+ ```bash
679
+ ollama pull qwen2.5-coder:14b && ollama serve # or: omlx start (Apple Silicon)
680
+ eds block from-design "<framer-url>" --name hero --agent ollama
681
+ eds block from-design ./hero.png --name hero --agent ollama --model qwen2.5vl:7b # PNG → vision model
682
+ eds block from-design ./hero.svg --name hero --agent omlx
683
+ ```
684
+
685
+ | Agent | Server (default) | API |
686
+ |---|---|---|
687
+ | `ollama` | `http://127.0.0.1:11434` | native `/api/chat` (so `num_ctx` can be raised) |
688
+ | `omlx` | `http://127.0.0.1:8000/v1` | OpenAI-compatible `/v1/chat/completions` |
689
+ | `local` | `local.baseUrl` | any OpenAI-compatible server (LM Studio, llama.cpp, vLLM…) |
690
+
691
+ - **No tools, so the CLI does the I/O.** A local model can't read files or call MCP. `eds` sends the whole prompt - a scraped page or Figma REST spec embedded, an SVG export inlined, a PNG / JPG attached as an image - and asks for every file in a `=== FILE: … ===` format. It then writes those files itself, **only inside `blocks/<name>/`**. The raw reply is kept in `tmp/eds-cli/local-reply-*.md`.
692
+ - **Figma needs REST or an export.** A Figma link without a token would need MCP, which a local model can't call: set `FIGMA_TOKEN`, or export the frame as PNG/SVG.
693
+ - **Model.** `--model`, else `local.model`, else a coder model the server has (`*coder*`, Codestral/Devstral, Qwen, DeepSeek…). A PNG/JPG design needs a vision model.
694
+ - **Context.** A design prompt is ~20-40k tokens. Ollama is asked for `local.contextTokens` (default **32768**, raised automatically when the prompt needs more); for other servers set the context length on the server. `eds` warns when the prompt won't fit.
695
+ - **Auto-detect.** With no CLI agent installed, `eds` uses a running Ollama or oMLX server. Refine passes work too: the model gets the block's current files and returns the changed ones.
696
+
697
+ ```json
698
+ { "agent": "ollama", "local": { "model": "qwen2.5-coder:14b", "contextTokens": 49152 } }
699
+ ```
700
+
701
+ `local.baseUrl` points at a different host or port, and `local.apiKey` is sent as a bearer token for servers that want one.
702
+
590
703
  ## Configuration
591
704
 
592
705
  Priority: CLI flags → env vars → `.edsrc.json` (project) → `~/.eds/config.json` (global)
@@ -596,10 +709,11 @@ Priority: CLI flags → env vars → `.edsrc.json` (project) → `~/.eds/config.
596
709
  {
597
710
  "agent": "claude",
598
711
  "model": "haiku",
599
- "figma": { "token": "figd_…", "restPerMinute": 10 }
712
+ "figma": { "token": "figd_…", "restPerMinute": 10 },
713
+ "local": { "model": "qwen2.5-coder:14b", "contextTokens": 49152 }
600
714
  }
601
715
  ```
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.
716
+ `agent` picks the agent (`claude`, `cursor`, `codex`, `ollama`, `omlx`, `local`); `model` sets the block-generation model (default: fastest / Haiku). `local.*` configures a [local model](#local-models-ollama-omlx). `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.
603
717
 
604
718
  `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
719
 
@@ -620,13 +734,13 @@ Priority: CLI flags → env vars → `.edsrc.json` (project) → `~/.eds/config.
620
734
  |---|---|
621
735
  | `--verbose` | Debug-level output |
622
736
  | `--quiet` | Errors only |
623
- | `--json` | Machine-readable JSON output |
737
+ | `--json` | Machine-readable JSON output (`doctor`, `audit loading`, `audit security`, `block list`) |
624
738
  | `--no-color` | Disable colors (also respects `NO_COLOR` env) |
625
739
 
626
740
  ## Development
627
741
 
628
742
  ```bash
629
- git clone <repo-url> && cd eds-cli
743
+ git clone https://github.com/piotrgodycki/aem-eds-kit.git && cd aem-eds-kit
630
744
  npm install
631
745
  ```
632
746
 
@@ -698,11 +812,21 @@ Tests use fixtures in `tests/fixtures/` - a sample EDS project and recorded Figm
698
812
 
699
813
  ## Roadmap
700
814
 
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.
703
- - **Screenshot-to-block** - build a block from a plain image (harder: no structured layout/measurements, so pixel-perfect is tougher).
704
- - **Tokens & sync** - design variables → CSS custom properties, and incremental re-sync of an existing block (`--update`).
705
- - **Headless & CI** - a direct MCP client (no agent needed) for CI/CD, plus `eds lighthouse`, `eds rum` and `eds migrate page`.
815
+ **Next**
816
+ - **Previews that look like the design.** The preview gets the design's real copy and images, so it matches 1:1; the block itself still reads authored content.
817
+ - **A self-check against the design.** Render the block, compare it with the Figma frame or the page, and fix what differs in a second pass.
818
+ - **Every breakpoint.** Read the design at mobile, tablet and desktop widths, not just one.
819
+
820
+ **Then**
821
+ - **Whole screens in one go.** Every section of a frame or page becomes a block, plus the page that puts them together.
822
+ - **Blocks that follow the design.** When the design changes, update the existing block instead of regenerating it.
823
+ - **Design tokens for the project.** Figma Variables become the CSS custom properties in `styles.css`.
824
+
825
+ **Later**
826
+ - **Deeper AEM migration.** HTL logic ported to `decorate()`, CSS taken from the rendered page, whole pages migrated.
827
+ - **Performance in the loop.** Lighthouse and real-user data (RUM) checked for every block.
828
+
829
+ Something missing? [Open an issue](https://github.com/piotrgodycki/aem-eds-kit/issues): the roadmap follows what people need.
706
830
 
707
831
  ## Trademarks & affiliation
708
832