@bettercms-ai/mcp 0.74.0 → 0.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +39 -8
- package/dist/index.js.map +1 -1
- package/dist/kit-catalog.json +53 -53
- package/dist/skills/bettercms/SKILL.md +7 -2
- package/dist/skills/bettercms/references/componentize.md +5 -0
- package/dist/skills/bettercms/references/finish-site.md +5 -1
- package/dist/skills/bettercms/references/getting-started.md +2 -0
- package/dist/skills/bettercms/references/kit-catalog.md +53 -53
- package/package.json +2 -2
|
@@ -43,7 +43,12 @@ Listing tools needs no sign-in; the first tool **call** does.
|
|
|
43
43
|
4. **A refusal for access: call `whoami` first.** It names the principal, the workspace, the
|
|
44
44
|
scope (project or workspace) and, where visible, the grants (publish, code and deploy,
|
|
45
45
|
sidebar schema), so you can tell the user which one is missing.
|
|
46
|
-
5. **
|
|
46
|
+
5. **"Invalid tool parameters" is the client, not BetterCMS.** A client with tool search (Claude
|
|
47
|
+
Code) lists most of the 150 tools by name and loads a schema on demand; a call to a tool whose
|
|
48
|
+
schema it has not loaded is refused before it is sent. Load the tool with the client's tool
|
|
49
|
+
search, every tool the step needs in one search, then make the same call again. Never change
|
|
50
|
+
the arguments because of it. The tools a setup starts with are always loaded.
|
|
51
|
+
6. **Unsure how a feature works: `search_docs` before guessing.** A tool that fails oddly, a
|
|
47
52
|
capability you needed and did not have, or docs that misled you: `give_feedback`, and tell the
|
|
48
53
|
user you sent it.
|
|
49
54
|
|
|
@@ -123,7 +128,7 @@ resources: `bettercms://skill/bettercms` for this file, and each reference under
|
|
|
123
128
|
| Move content out of another CMS (Cosmic, Contentful, Sanity, Strapi, Prismic, WordPress…) | [external-content.md](references/external-content.md) | a CMS SDK in package.json; `envWarning` on import; pages that render empty without a third-party key | Contentful, Sanity, Strapi, envWarning, missing key, empty pages |
|
|
124
129
|
| Read a source site before modelling it | [detection.md](references/detection.md) | converting from a URL or built HTML; deciding what a band, a repeat or a value is | detect, classify, section, repeat, global, carousel clone, hidden state |
|
|
125
130
|
| Pages vs collections, folders, fields, schema changes | [content-modeling.md](references/content-modeling.md) | modelling a route family; a model write returns 409 | schema, model, collection, field, folder, rename, remove field, listing, filter, locked field |
|
|
126
|
-
| Dock layout: groups, rows, tabs, icons, item names, showIf order | [editor-chrome.md](references/editor-chrome.md) | `
|
|
131
|
+
| Dock layout: groups, rows, tabs, icons, item names, showIf order | [editor-chrome.md](references/editor-chrome.md) | after any import, convert, componentize or extract (the gate's `dock` row); a `dock-*` rule; the `field-ui` prompt | dock, fieldset, tab, group, itemLabel, showIf, field-ui |
|
|
127
132
|
| A custom input for one field in the dock: when, the user's approval, the contract | [dock-input.md](references/dock-input.md) | `get_next_steps` lists `dock-input-candidate`; a 409 `input_needs_confirmation` | custom input, ui.input, dock input, confirmed, swatch |
|
|
128
133
|
| What the server does and does not check on a write | [write-limits.md](references/write-limits.md) | before relying on a limit; reading a refused write; a bulk load or re-run | validation, maxLength, unique, 400, refused write, dry run, externalKey, upsert, re-run |
|
|
129
134
|
| Plan a site by business type | [site-blueprints.md](references/site-blueprints.md) | the IA of a known site type, with its collections, forms and structured data | new site, IA, portfolio, agency, corporate, SaaS, ecommerce, directory, blog, docs, restaurant, events, course, jobs, real estate, nonprofit, multi-brand |
|
|
@@ -75,9 +75,14 @@ Never let a component contain itself, directly or through a child.
|
|
|
75
75
|
`set_component_source` per component is needed. Deploy. A page whose bands could not be
|
|
76
76
|
lifted is wrapped where it stands instead (§5).
|
|
77
77
|
7. Output validation, from step 3 of §6.
|
|
78
|
+
8. Editor chrome, last and not optional: the components this lane made have bare props. Load
|
|
79
|
+
[editor-chrome.md](editor-chrome.md) and run step 8 of the repair order in
|
|
80
|
+
[finish-site.md](finish-site.md) for each one; `extract_component` ends the same way.
|
|
78
81
|
|
|
79
82
|
## 3. Names and groups
|
|
80
83
|
|
|
84
|
+
Name each component's closest kit entry as its `kitEntry` (`bettercms://kit/entry/{id}`) and take that entry's ui. When the match is wrong, override it; the `no-kit-match` exemption needs a note.
|
|
85
|
+
|
|
81
86
|
Name a family by what it is (`Hero`, `CTA`, `Testimonials`) and each variant by how it looks
|
|
82
87
|
(`Hero / Split`, `CTA / Centered`). Never put a page name in a reusable definition; which pages
|
|
83
88
|
use it is a usage question (§8). The componentize lane files a section under its page's slug
|
|
@@ -69,6 +69,7 @@ line), which is what a script waiting on the setup reads.
|
|
|
69
69
|
| `buttons` | every button field is one of the site's live Button looks, the Button family is the looks setup measured on this build (the same looks, not the same count), and no look is named by a number or a build's class | `blocking.rows`, `route: null` |
|
|
70
70
|
| `components` | the authoring question is answered, and no section is left that a componentize run would place | `blocking.rows`, `route: null` |
|
|
71
71
|
| `forms` | every form of the customer's has an address to notify; a form setup ignored (sign-in, add to basket) is not counted | `blocking.rows`, `route: null` |
|
|
72
|
+
| `dock` | every component with props has at least one prop carrying V2 `ui`, and every list prop (`table`, `array`, `multi-reference`) titles its rows with `ui.preview.title` or `ui.itemLabel`; and every component with props names the `bettercms://kit` entry its dock UI was built from (`update_component { kitEntry }`, `set-kit-entry`), or records `no-kit-match` with a note on `route: "component/<slug>/kit"`; one row per component per half, Button looks not counted | `blocking.rows`, `route: null`, the component, its props and the `bettercms://kit/entry/{id}` to read in `detail` |
|
|
72
73
|
|
|
73
74
|
`pages` counts routes built, created and published. `coverage` sums `editable` of `total` across
|
|
74
75
|
the site, `svg`, `number` and `attribute` included, and `open` counts the rows still open per
|
|
@@ -106,6 +107,7 @@ The other rows name their fix the same way:
|
|
|
106
107
|
| `derive-buttons` | `editor_setup { force: true }` mints a Button for each look the build draws, retires one it no longer draws and maps each button to its look; rename a look with `update_component` ([components.md](components.md)) |
|
|
107
108
|
| `componentize` | `set_authoring_preference` when nobody answered, then `get_componentize_plan` and `componentize_sections` ([componentize.md](componentize.md)) |
|
|
108
109
|
| `set-form-recipient` | ask the user where the form's submissions go, then `update_form` with `notifyEmails`; `update_form { ignored: true }` when it is not one of their forms |
|
|
110
|
+
| `set-dock-ui` | the last step of the repair order below: `get_component`, then `update_component` with `propUi` and `propTab` for the props the row names ([editor-chrome.md](editor-chrome.md)) |
|
|
109
111
|
|
|
110
112
|
A row nothing measured reads `unmeasured: true` with `run-setup`, and `gate.unmeasured` lists the
|
|
111
113
|
checks that have one: a release older than a count, or a project set up before setup recorded
|
|
@@ -207,8 +209,9 @@ in a sentence a person can verify. `reason: null` withdraws one.
|
|
|
207
209
|
| `decorative` | `text`, `image`, `svg` |
|
|
208
210
|
| `duplicate-track` | `text`, `image`, `link`, `svg`, `number`, `attribute` (the cloned track of a marquee or slider) |
|
|
209
211
|
| `client-only-island` | nothing: it lists an island the build cannot show, and the route still meets the bar outside it |
|
|
210
|
-
| `user-declined` | `page`, `published`, `text`, `image`, `link`, `svg`, `number`, `attribute`, `seo`, `structuredData`, `collections`, and only with the user's own words quoted in `note` (`User: "leave pricing in code"`) |
|
|
212
|
+
| `user-declined` | `page`, `published`, `text`, `image`, `link`, `svg`, `number`, `attribute`, `seo`, `structuredData`, `collections`, `dock`, and only with the user's own words quoted in `note` (`User: "leave pricing in code"`) |
|
|
211
213
|
| `document-body` | `sections`, and only on a route that places no section at all: a page that is one document (a markdown post, a legal page) |
|
|
214
|
+
| `default-controls` | `dock`, on `route: "component/<slug>"`: a component whose props read right with the dock's default controls (one short heading, a toggle); `note` says why |
|
|
212
215
|
|
|
213
216
|
Nothing else excuses `sections`, and nothing excuses `style`, `twin`, `names`, `buttons`,
|
|
214
217
|
`components` or `forms`: not the user's decision either. A name is fixed by renaming, and a form
|
|
@@ -284,6 +287,7 @@ and add the new result. Update the file as each row moves, so a reset loses at m
|
|
|
284
287
|
| 5 | Bindings: the site reads BetterCMS data and each intended leaf or attribute is bound; build, preview and runtime agree | [bindings.md](bindings.md), [frameworks.md](frameworks.md) |
|
|
285
288
|
| 6 | Behaviour: forms, links, menus, accordions, modals, consent, custom code | [forms-and-interactions.md](forms-and-interactions.md) |
|
|
286
289
|
| 7 | Discoverability: native SEO, structured data, robots and sitemap, redirects, internal links | [seo.md](seo.md) |
|
|
290
|
+
| 8 | Editor chrome, MANDATORY and last, after any import, convert, componentize or extract: load the reference, and for every component set the V2 `ui` of each prop (control, tab, group, collapsed, layout, preview, itemLabel, icon, and `propHelpText`) by playbook §14 and the nearest `bettercms://kit` entry. The gate's `dock` row stays open until it is done | [editor-chrome.md](editor-chrome.md) |
|
|
287
291
|
|
|
288
292
|
Load the step's reference when the step starts, and let it go when the step's rows are verified.
|
|
289
293
|
|
|
@@ -87,6 +87,8 @@ and `get_componentize_plan` proposes nothing more.
|
|
|
87
87
|
5. Work the rest through [finish-site.md](finish-site.md) (gap ledger, repair order, proof loop).
|
|
88
88
|
The gate's `sections` and `style` rows are part of it: a setup whose pages cannot take a new
|
|
89
89
|
section, a new order or spacing is not finished.
|
|
90
|
+
6. End Phase 3 on the editor chrome of every component (step 8 of finish-site.md's repair order,
|
|
91
|
+
[editor-chrome.md](editor-chrome.md)): the gate's `dock` row blocks until each has its V2 `ui`.
|
|
90
92
|
|
|
91
93
|
### Phase 4 — Publish and verify
|
|
92
94
|
|
|
@@ -92,7 +92,7 @@ Tags: global-synced, conditional, repeater, localized. Proves: Three stacked row
|
|
|
92
92
|
- A rotating announcement (several messages cycling) is an array, not one string — switch `message` to an array of {message, link} rather than joining with ·.
|
|
93
93
|
- Don't put the account/cart icons in utility links — those are app state; see `nav-ecommerce-header`.
|
|
94
94
|
|
|
95
|
-
Not carried by a stored component: ai, category,
|
|
95
|
+
Not carried by a stored component: ai, category, item openMode, kind:global.
|
|
96
96
|
|
|
97
97
|
### Mega menu with featured cards + promo slot (`nav-mega-featured-promo`)
|
|
98
98
|
|
|
@@ -114,7 +114,7 @@ Tags: deep-nesting, slots, global-synced, conditional, references, variants, com
|
|
|
114
114
|
- If two menu items share the same panel content, that is still two panels in content; don't invent a shared-panel global for it.
|
|
115
115
|
- Hover-only panels fail keyboard users — the converter should default `openOn` to click when the source has no aria-expanded handling.
|
|
116
116
|
|
|
117
|
-
Not carried by a stored component: ai, category, kind:global, reference
|
|
117
|
+
Not carried by a stored component: ai, category, kind:global, shopify reference, variants.
|
|
118
118
|
|
|
119
119
|
### Docs sidebar navigation (`nav-docs-sidebar`)
|
|
120
120
|
|
|
@@ -156,7 +156,7 @@ Tags: global-synced, commerce, references, repeater, conditional, media-heavy. P
|
|
|
156
156
|
- Copying '(2)' from the cart badge into content is the most common converter mistake — it's session state.
|
|
157
157
|
- Free-shipping thresholds belong to commerce settings, not the header; reference them from the renderer.
|
|
158
158
|
|
|
159
|
-
Not carried by a stored component: category, kind:global, reference
|
|
159
|
+
Not carried by a stored component: category, kind:global, shopify reference, variants.
|
|
160
160
|
|
|
161
161
|
### Multi-locale header with switchers (`nav-locale-header`)
|
|
162
162
|
|
|
@@ -196,7 +196,7 @@ Tags: responsive-layout, conditional, validation, commerce. Proves: A per-templa
|
|
|
196
196
|
- 'Add to cart' is an ACTION, not a link — our button type only carries links (gap: action buttons).
|
|
197
197
|
- A bar covering the cookie banner or chat launcher: the renderer must stack them; nothing to model.
|
|
198
198
|
|
|
199
|
-
Not carried by a stored component: ai, category
|
|
199
|
+
Not carried by a stored component: ai, category.
|
|
200
200
|
|
|
201
201
|
### Announcement bar with countdown (`announcement-countdown`)
|
|
202
202
|
|
|
@@ -216,7 +216,7 @@ Tags: global-synced, conditional, validation, repeater, localized, a11y. Proves:
|
|
|
216
216
|
- Storing the countdown as text ('2 days left') — it's wrong the next day. Always a datetime with offset.
|
|
217
217
|
- Hide-after earlier than the countdown end can't be caught today (gap: cross-field validation).
|
|
218
218
|
|
|
219
|
-
Not carried by a stored component: ai, category,
|
|
219
|
+
Not carried by a stored component: ai, category, item openMode, kind:global.
|
|
220
220
|
|
|
221
221
|
### Cookie consent banner (`cookie-consent`)
|
|
222
222
|
|
|
@@ -338,7 +338,7 @@ Tags: variants, conditional, media-heavy, a11y, repeater. Proves: One media slot
|
|
|
338
338
|
- A hero with BOTH a background video and a side image is a different section (full-bleed video) — don't merge.
|
|
339
339
|
- Alt text on a decorative hero photo should still describe it when it shows the product.
|
|
340
340
|
|
|
341
|
-
Not carried by a stored component: ai, category,
|
|
341
|
+
Not carried by a stored component: ai, category, variants.
|
|
342
342
|
|
|
343
343
|
### Centered hero with gradient + screenshot (`hero-centered-gradient`)
|
|
344
344
|
|
|
@@ -359,7 +359,7 @@ Tags: variants, conditional, validation, media-heavy. Proves: Announcement chip
|
|
|
359
359
|
- Editing the headline can orphan the highlight — the renderer must ignore a highlight that no longer matches (no cross-field validation yet).
|
|
360
360
|
- Don't store raw CSS gradient strings — they can't be re-themed or validated.
|
|
361
361
|
|
|
362
|
-
Not carried by a stored component: ai, category,
|
|
362
|
+
Not carried by a stored component: ai, category, variants.
|
|
363
363
|
|
|
364
364
|
### Full-bleed video hero with captions (`hero-video-fullbleed`)
|
|
365
365
|
|
|
@@ -400,7 +400,7 @@ Tags: repeater, media-heavy, conditional, validation, a11y. Proves: Slides array
|
|
|
400
400
|
- Cloned slides doubling the count — dedupe by image URL + heading.
|
|
401
401
|
- Slide schedules that leave fewer than 2 live slides: the renderer should fall back to a static hero (min can't be enforced over time).
|
|
402
402
|
|
|
403
|
-
Not carried by a stored component: ai, category,
|
|
403
|
+
Not carried by a stored component: ai, category, fieldset (derived).
|
|
404
404
|
|
|
405
405
|
### Product hero with variant picker (`hero-product`)
|
|
406
406
|
|
|
@@ -421,7 +421,7 @@ Tags: references, commerce, media-heavy, conditional, repeater. Proves: Live com
|
|
|
421
421
|
- Hard-coding the price in the tagline ('Just $165!') — it goes stale; flag any currency in copy.
|
|
422
422
|
- Picker options are a fixed list here; a product with a 'Handle wrap' option can't be picked until options come from the reference (gap).
|
|
423
423
|
|
|
424
|
-
Not carried by a stored component: ai, category,
|
|
424
|
+
Not carried by a stored component: ai, category, shopify reference, variants.
|
|
425
425
|
|
|
426
426
|
### Search hero (`hero-search`)
|
|
427
427
|
|
|
@@ -460,7 +460,7 @@ Tags: form, references, conditional, validation, repeater. Proves: A form REFERE
|
|
|
460
460
|
- Copying inputs into the hero's schema — the form then can't be reused or receive submissions properly.
|
|
461
461
|
- Hidden values that contain personal data (an email from the URL) must not be stored in content.
|
|
462
462
|
|
|
463
|
-
Not carried by a stored component: ai, category, item openMode,
|
|
463
|
+
Not carried by a stored component: ai, category, item openMode, variants.
|
|
464
464
|
|
|
465
465
|
### App download hero (`hero-app-download`)
|
|
466
466
|
|
|
@@ -480,7 +480,7 @@ Tags: media-heavy, conditional, validation, global-synced, repeater. Proves: A f
|
|
|
480
480
|
- Uploading badge or QR images — they can't be updated and the QR silently breaks when the link changes.
|
|
481
481
|
- Ratings copied from the store go stale; the help text says so because there's no live source.
|
|
482
482
|
|
|
483
|
-
Not carried by a stored component: ai, category,
|
|
483
|
+
Not carried by a stored component: ai, category, item openMode.
|
|
484
484
|
|
|
485
485
|
### Stats hero (`hero-stats`)
|
|
486
486
|
|
|
@@ -623,7 +623,7 @@ Tags: repeater, conditional, media-heavy, variants, rich-text. Proves: Per-row m
|
|
|
623
623
|
- Storing `side` on every row breaks the zigzag the moment rows are reordered — store `auto` unless the source deliberately breaks the pattern.
|
|
624
624
|
- Autoplay videos without a poster flash black; always extract or generate a poster.
|
|
625
625
|
|
|
626
|
-
Not carried by a stored component: ai, category,
|
|
626
|
+
Not carried by a stored component: ai, category, variants.
|
|
627
627
|
|
|
628
628
|
### Feature bento (responsive spans) (`bento-feature-showcase`)
|
|
629
629
|
|
|
@@ -644,7 +644,7 @@ Tags: slots, responsive-layout, conditional, media-heavy, variants. Proves: Slot
|
|
|
644
644
|
- Phones stack cells; if the source reorders them with CSS `order`, capture it or the story reads out of order.
|
|
645
645
|
- 6-column variants need spans up to 6; validate spans against the variant's column count.
|
|
646
646
|
|
|
647
|
-
Not carried by a stored component: ai, category,
|
|
647
|
+
Not carried by a stored component: ai, category, variants.
|
|
648
648
|
|
|
649
649
|
### Steps / how it works (`steps-how-it-works`)
|
|
650
650
|
|
|
@@ -683,7 +683,7 @@ Tags: repeater, conditional, media-heavy, validation, rich-text. Proves: Date pr
|
|
|
683
683
|
- Storing “2014” in a date field becomes 2014-01-01 and later renders as “Jan 1, 2014”.
|
|
684
684
|
- Two milestones with the same year keep their array order as the tie-breaker — keep the array roughly sorted.
|
|
685
685
|
|
|
686
|
-
Not carried by a stored component: ai, category,
|
|
686
|
+
Not carried by a stored component: ai, category, variants.
|
|
687
687
|
|
|
688
688
|
### Tabs with media (`tabs-with-media`)
|
|
689
689
|
|
|
@@ -703,7 +703,7 @@ Tags: repeater, conditional, media-heavy, variants, a11y, localized. Proves: Fix
|
|
|
703
703
|
- Auto-advancing tabs must stop on interaction and respect reduced motion — the renderer handles it; never model a “pause” field.
|
|
704
704
|
- Tab labels longer than ~20 characters wrap on the top variant and break the underline.
|
|
705
705
|
|
|
706
|
-
Not carried by a stored component: ai, category,
|
|
706
|
+
Not carried by a stored component: ai, category, variants.
|
|
707
707
|
|
|
708
708
|
### Accordion features with image swap (`accordion-feature-image-swap`)
|
|
709
709
|
|
|
@@ -722,7 +722,7 @@ Tags: repeater, media-heavy, a11y, variants, rich-text. Proves: One required ima
|
|
|
722
722
|
- Images of different aspect ratios cause the layout to jump on every click — warn when the source images differ.
|
|
723
723
|
- Do not tag these rows as FAQ structured data — they are not questions.
|
|
724
724
|
|
|
725
|
-
Not carried by a stored component: ai, category,
|
|
725
|
+
Not carried by a stored component: ai, category, variants.
|
|
726
726
|
|
|
727
727
|
### Comparison vs competitors (`comparison-vs-competitors`)
|
|
728
728
|
|
|
@@ -783,7 +783,7 @@ Tags: conditional, rich-text, variants, localized. Proves: Mode select swaps an
|
|
|
783
783
|
- Quotation marks typed into content double up with the design's quotes — strip them.
|
|
784
784
|
- Lines split by `<br>` inside one paragraph are still separate lines.
|
|
785
785
|
|
|
786
|
-
Not carried by a stored component: category,
|
|
786
|
+
Not carried by a stored component: category, variants.
|
|
787
787
|
|
|
788
788
|
### Problem → solution (`problem-solution`)
|
|
789
789
|
|
|
@@ -982,7 +982,7 @@ Tags: seo-structured, references, conditional, validation, a11y, commerce. Prove
|
|
|
982
982
|
- Typed-in ratings drift from the real ones; prefer the connected source and show “Synced …” in the UI.
|
|
983
983
|
- Distribution counts that don't sum to the total look fake; validate the sum.
|
|
984
984
|
|
|
985
|
-
Not carried by a stored component: category, item openMode, itemNoun (derived), reference
|
|
985
|
+
Not carried by a stored component: category, item openMode, itemNoun (derived), shopify reference, variants.
|
|
986
986
|
|
|
987
987
|
## Media & galleries
|
|
988
988
|
|
|
@@ -1005,7 +1005,7 @@ Tags: media-heavy, a11y, responsive-layout, repeater, validation, localized. Pro
|
|
|
1005
1005
|
- Credits pasted into captions get translated; keep them in the credit object.
|
|
1006
1006
|
- Empty alt is right for decorative photos but wrong for a portfolio — flag empties for review.
|
|
1007
1007
|
|
|
1008
|
-
Not carried by a stored component: category,
|
|
1008
|
+
Not carried by a stored component: category, variants.
|
|
1009
1009
|
|
|
1010
1010
|
### Gallery with category filters (`lightbox-gallery-filters`)
|
|
1011
1011
|
|
|
@@ -1024,7 +1024,7 @@ Tags: media-heavy, a11y, repeater, validation, localized. Proves: Filters define
|
|
|
1024
1024
|
- A photo tagged with a key that no filter defines is invisible under every filter except All — validate keys against the filters.
|
|
1025
1025
|
- Free-typed keys are error-prone; a select fed by the section's filters is the right control (schema gap).
|
|
1026
1026
|
|
|
1027
|
-
Not carried by a stored component: category,
|
|
1027
|
+
Not carried by a stored component: category, item openMode, variants.
|
|
1028
1028
|
|
|
1029
1029
|
### Video section (YouTube · Vimeo · hosted) (`video-section`)
|
|
1030
1030
|
|
|
@@ -1064,7 +1064,7 @@ Tags: media-heavy, a11y, repeater, validation, variants, localized. Proves: Pair
|
|
|
1064
1064
|
- Before and after with different crops make the slider useless — dimensions should match (not enforceable in our schema yet).
|
|
1065
1065
|
- A slider built from a div with mouse events only is not keyboard accessible; the renderer must use a real range input.
|
|
1066
1066
|
|
|
1067
|
-
Not carried by a stored component: category,
|
|
1067
|
+
Not carried by a stored component: category, variants.
|
|
1068
1068
|
|
|
1069
1069
|
### Image with hotspots (shop the look) (`image-hotspots`)
|
|
1070
1070
|
|
|
@@ -1084,7 +1084,7 @@ Tags: media-heavy, conditional, references, commerce, a11y, validation, variants
|
|
|
1084
1084
|
- Copying product price into the note text goes stale; reference the product.
|
|
1085
1085
|
- Re-cropping the image after placing pins moves every pin. A visual point picker would prevent this (schema gap).
|
|
1086
1086
|
|
|
1087
|
-
Not carried by a stored component: category, reference
|
|
1087
|
+
Not carried by a stored component: category, shopify reference, variants.
|
|
1088
1088
|
|
|
1089
1089
|
### 3D model / Lottie / 360° embed (`interactive-3d-lottie-embed`)
|
|
1090
1090
|
|
|
@@ -1124,7 +1124,7 @@ Tags: polymorphic-array, media-heavy, a11y, responsive-layout, references, condi
|
|
|
1124
1124
|
- Loop mode clones slides in the DOM — import only originals.
|
|
1125
1125
|
- Autoplaying carousels need a pause control and must stop on focus (WCAG 2.2.2); the renderer adds both.
|
|
1126
1126
|
|
|
1127
|
-
Not carried by a stored component: category,
|
|
1127
|
+
Not carried by a stored component: category, shopify reference, variants.
|
|
1128
1128
|
|
|
1129
1129
|
### Full-bleed parallax image with overlay text (`parallax-image-overlay`)
|
|
1130
1130
|
|
|
@@ -1164,7 +1164,7 @@ Tags: dynamic-query, embed, conditional, media-heavy, references, commerce, vali
|
|
|
1164
1164
|
- Widget scripts from UGC vendors add 200–500 KB and third-party cookies — replace, don't import.
|
|
1165
1165
|
- Never mark rightsGranted true on import; only a person can confirm permission.
|
|
1166
1166
|
|
|
1167
|
-
Not carried by a stored component: category, reference
|
|
1167
|
+
Not carried by a stored component: category, shopify reference, variants.
|
|
1168
1168
|
|
|
1169
1169
|
## Commerce
|
|
1170
1170
|
|
|
@@ -1213,7 +1213,7 @@ Tags: commerce, deep-nesting, polymorphic-array, conditional, references, media-
|
|
|
1213
1213
|
- Variant combinations are typed strings; renaming an option value orphans gallery `forValues` and variant rows.
|
|
1214
1214
|
- Video posters are required: autoplaying video without a poster hurts LCP on the product page.
|
|
1215
1215
|
|
|
1216
|
-
Not carried by a stored component: ai, category,
|
|
1216
|
+
Not carried by a stored component: ai, category, kind:entry (props), shopify reference.
|
|
1217
1217
|
|
|
1218
1218
|
### Featured product spotlight (`commerce-featured-product`)
|
|
1219
1219
|
|
|
@@ -1336,7 +1336,7 @@ Tags: media-heavy, references, deep-nesting, repeater, commerce, a11y, validatio
|
|
|
1336
1336
|
- Coordinates are raw numbers today — there's no visual point picker bound to the image yet (gap).
|
|
1337
1337
|
- Dots without labels fail WCAG 4.1.2; the label is required for that reason.
|
|
1338
1338
|
|
|
1339
|
-
Not carried by a stored component: ai, category,
|
|
1339
|
+
Not carried by a stored component: ai, category, variants.
|
|
1340
1340
|
|
|
1341
1341
|
### Size guide table (`commerce-size-guide`)
|
|
1342
1342
|
|
|
@@ -1425,7 +1425,7 @@ Tags: commerce, conditional, validation, repeater, variants. Proves: Both cycle
|
|
|
1425
1425
|
- `inherits` is a free string, not a reference to a sibling plan — renaming a plan leaves stale 'Everything in' lines (gap: references within the same entry).
|
|
1426
1426
|
- Per-seat prices must say 'per seat' near the number, not only in the footnote.
|
|
1427
1427
|
|
|
1428
|
-
Not carried by a stored component: ai, category,
|
|
1428
|
+
Not carried by a stored component: ai, category, variants.
|
|
1429
1429
|
|
|
1430
1430
|
### Usage-based price calculator (`pricing-usage-calculator`)
|
|
1431
1431
|
|
|
@@ -1492,7 +1492,7 @@ Tags: commerce, repeater, conditional, validation, rich-text. Proves: One plan o
|
|
|
1492
1492
|
- A minimum term hidden in small print is a trust killer — it has its own field on purpose.
|
|
1493
1493
|
- Mixed units (per month + per session) can't be summed into one honest monthly number without an assumption; show the breakdown.
|
|
1494
1494
|
|
|
1495
|
-
Not carried by a stored component: category
|
|
1495
|
+
Not carried by a stored component: category.
|
|
1496
1496
|
|
|
1497
1497
|
### Enterprise contact card (`pricing-enterprise-card`)
|
|
1498
1498
|
|
|
@@ -1765,7 +1765,7 @@ Tags: repeater, a11y, variants, conditional, validation, media-heavy. Proves: Ty
|
|
|
1765
1765
|
- Payment icons for methods not enabled at checkout are a common trust-breaker.
|
|
1766
1766
|
- Icon-only badges need text; the title is required.
|
|
1767
1767
|
|
|
1768
|
-
Not carried by a stored component: category,
|
|
1768
|
+
Not carried by a stored component: category, variants.
|
|
1769
1769
|
|
|
1770
1770
|
## Listings & feeds
|
|
1771
1771
|
|
|
@@ -1903,7 +1903,7 @@ Tags: deep-nesting, repeater, conditional, rich-text, validation, dynamic-query,
|
|
|
1903
1903
|
- Version strings with spaces or dates as versions collide as anchors.
|
|
1904
1904
|
- 60+ releases inline makes the section slow to edit — move to the collection.
|
|
1905
1905
|
|
|
1906
|
-
Not carried by a stored component: category, segmented
|
|
1906
|
+
Not carried by a stored component: category, segmented fallback, variants.
|
|
1907
1907
|
|
|
1908
1908
|
### Public roadmap (`public-roadmap`)
|
|
1909
1909
|
|
|
@@ -1948,7 +1948,7 @@ Tags: dynamic-query, references, conditional, repeater, validation, a11y. Proves
|
|
|
1948
1948
|
- A label-less search input fails WCAG 1.3.1 / 4.1.2 — label is required.
|
|
1949
1949
|
- Search pages must be noindex — the platform does it natively; never add a field for it.
|
|
1950
1950
|
|
|
1951
|
-
Not carried by a stored component: category, reference
|
|
1951
|
+
Not carried by a stored component: category, shopify reference, variants.
|
|
1952
1952
|
|
|
1953
1953
|
## Long-form & docs
|
|
1954
1954
|
|
|
@@ -2042,7 +2042,7 @@ Tags: embed, repeater, validation, variants. Proves: One example in N languages
|
|
|
2042
2042
|
- API keys in sample code — replace real-looking secrets with $ENV placeholders.
|
|
2043
2043
|
- The `code` field's built-in language list (html/css/js/liquid/json) doesn't cover API languages — the select carries it.
|
|
2044
2044
|
|
|
2045
|
-
Not carried by a stored component: category,
|
|
2045
|
+
Not carried by a stored component: category, variants.
|
|
2046
2046
|
|
|
2047
2047
|
### Knowledge-base article (`kb-article`)
|
|
2048
2048
|
|
|
@@ -2086,7 +2086,7 @@ Tags: dynamic-query, repeater, conditional, references, seo-structured, a11y, va
|
|
|
2086
2086
|
- 300 inline terms is the ceiling — beyond that, use the collection.
|
|
2087
2087
|
- Localised term lists re-sort per language (Ä, Ø, Ł) — sort with the locale's collation.
|
|
2088
2088
|
|
|
2089
|
-
Not carried by a stored component: category,
|
|
2089
|
+
Not carried by a stored component: category, variants.
|
|
2090
2090
|
|
|
2091
2091
|
### Recipe (`recipe`)
|
|
2092
2092
|
|
|
@@ -2110,7 +2110,7 @@ Tags: deep-nesting, repeater, seo-structured, media-heavy, conditional, referenc
|
|
|
2110
2110
|
- Dietary claims set at recipe level while an optional ingredient breaks them.
|
|
2111
2111
|
- Timer fields filled but hasTimer off — hidden values still ship unless cleared on save.
|
|
2112
2112
|
|
|
2113
|
-
Not carried by a stored component: category, kind:entry (props), reference
|
|
2113
|
+
Not carried by a stored component: category, kind:entry (props), shopify reference.
|
|
2114
2114
|
|
|
2115
2115
|
### Course curriculum (`course-curriculum`)
|
|
2116
2116
|
|
|
@@ -2132,7 +2132,7 @@ Tags: deep-nesting, repeater, conditional, references, validation, media-heavy,
|
|
|
2132
2132
|
- Live lesson times stored in local time without a zone.
|
|
2133
2133
|
- Five levels inline (course → module → lesson → resource → file) — keep resources tiny and inline.
|
|
2134
2134
|
|
|
2135
|
-
Not carried by a stored component: category, segmented
|
|
2135
|
+
Not carried by a stored component: category, segmented fallback, variants.
|
|
2136
2136
|
|
|
2137
2137
|
### Legal / policy page (`legal-policy`)
|
|
2138
2138
|
|
|
@@ -2268,7 +2268,7 @@ Tags: repeater, media-heavy, variants, validation, a11y. Proves: Values with a r
|
|
|
2268
2268
|
- Perks with prices or policies that change — keep them short and dated in HR, not here.
|
|
2269
2269
|
- Nine-value lists — validation caps at eight; past five, nobody remembers them.
|
|
2270
2270
|
|
|
2271
|
-
Not carried by a stored component: ai, category,
|
|
2271
|
+
Not carried by a stored component: ai, category, variants.
|
|
2272
2272
|
|
|
2273
2273
|
### Careers list (`careers-list`)
|
|
2274
2274
|
|
|
@@ -2313,7 +2313,7 @@ Tags: seo-structured, conditional, references, repeater, validation, form. Prove
|
|
|
2313
2313
|
- Closed roles deleted instead of closed: their URLs 404 and lose links. Close them.
|
|
2314
2314
|
- Benefits retyped on every job drift — use the shared block.
|
|
2315
2315
|
|
|
2316
|
-
Not carried by a stored component: category,
|
|
2316
|
+
Not carried by a stored component: category, kind:entry (props).
|
|
2317
2317
|
|
|
2318
2318
|
### About & mission with timeline (`about-timeline`)
|
|
2319
2319
|
|
|
@@ -2356,7 +2356,7 @@ Tags: deep-nesting, repeater, media-heavy, conditional, validation, a11y. Proves
|
|
|
2356
2356
|
- Photos without credits get printed uncredited — credit is required for photos.
|
|
2357
2357
|
- A stale .zip that no longer matches the assets shown.
|
|
2358
2358
|
|
|
2359
|
-
Not carried by a stored component: category,
|
|
2359
|
+
Not carried by a stored component: category, variants.
|
|
2360
2360
|
|
|
2361
2361
|
## Events & places
|
|
2362
2362
|
|
|
@@ -2404,7 +2404,7 @@ Tags: deep-nesting, references, seo-structured, conditional, commerce, repeater,
|
|
|
2404
2404
|
- Cancelled events deleted rather than marked — Google keeps showing the old date.
|
|
2405
2405
|
- Sold-out early-bird tiers left 'On sale' after salesEnd — use the window, not the badge.
|
|
2406
2406
|
|
|
2407
|
-
Not carried by a stored component: category,
|
|
2407
|
+
Not carried by a stored component: category, kind:entry (props).
|
|
2408
2408
|
|
|
2409
2409
|
### Webinar registration (`webinar-registration`)
|
|
2410
2410
|
|
|
@@ -2426,7 +2426,7 @@ Tags: form, conditional, references, embed, validation, variants. Proves: One se
|
|
|
2426
2426
|
- Leaving stage 'live' after the event — the page shows a dead stream.
|
|
2427
2427
|
- Gating on-demand recordings of public talks lowers reach; gate deliberately.
|
|
2428
2428
|
|
|
2429
|
-
Not carried by a stored component: ai, category,
|
|
2429
|
+
Not carried by a stored component: ai, category, variants.
|
|
2430
2430
|
|
|
2431
2431
|
### Locations directory (`locations-directory`)
|
|
2432
2432
|
|
|
@@ -2523,7 +2523,7 @@ Tags: repeater, conditional, validation, a11y. Proves: Typed columns · rows fro
|
|
|
2523
2523
|
- Past ~60 rows, keep the data in CSV or a collection; the grid stays usable but the page gets heavy.
|
|
2524
2524
|
- Do not model 'striped' or 'compact' as booleans — they are variants.
|
|
2525
2525
|
|
|
2526
|
-
Not carried by a stored component: ai, category,
|
|
2526
|
+
Not carried by a stored component: ai, category, variants.
|
|
2527
2527
|
|
|
2528
2528
|
### Table (`table-comparison`)
|
|
2529
2529
|
|
|
@@ -2544,7 +2544,7 @@ Tags: validation, a11y, seo-structured, references, commerce. Proves: The `table
|
|
|
2544
2544
|
- A blank cell in a yes/no column is 'Not included'; a blank cell anywhere else is 'No value'.
|
|
2545
2545
|
- Don't retype units in cells — the column carries them.
|
|
2546
2546
|
|
|
2547
|
-
Not carried by a stored component: ai, category
|
|
2547
|
+
Not carried by a stored component: ai, category.
|
|
2548
2548
|
|
|
2549
2549
|
### Chart with annotations (`chart-attrition`)
|
|
2550
2550
|
|
|
@@ -2614,7 +2614,7 @@ Tags: commerce, deep-nesting, repeater, conditional, references, validation. Pro
|
|
|
2614
2614
|
- SCHEMA GAP: option keys need to be unique within their step only (scoped uniqueness) — `unique` is neither scoped nor enforced.
|
|
2615
2615
|
- Price deltas drift from Shopify variant prices; prefer reading the variant price and keeping priceDelta only for non-Shopify add-ons.
|
|
2616
2616
|
|
|
2617
|
-
Not carried by a stored component: ai, category, reference
|
|
2617
|
+
Not carried by a stored component: ai, category, shopify reference, variants.
|
|
2618
2618
|
|
|
2619
2619
|
### Map with markers (`stockist-map`)
|
|
2620
2620
|
|
|
@@ -2773,7 +2773,7 @@ Tags: deep-nesting, slots, repeater, variants, media-heavy. Proves: Guide › Ta
|
|
|
2773
2773
|
- Breadcrumb at 7 drills (Guide / Seasoning / Steps and kit / Steps / Season over fire… / Heat it upside down / Card / Button) must fold into the Pathway chip on a 380px inspector — this entry is the test case.
|
|
2774
2774
|
- Accordion item cards inside a 1/3 column are cramped; that's a variant decision, not a field.
|
|
2775
2775
|
|
|
2776
|
-
Not carried by a stored component: ai, category,
|
|
2776
|
+
Not carried by a stored component: ai, category, variants.
|
|
2777
2777
|
|
|
2778
2778
|
### Any-block module list (`polymorphic-modules`)
|
|
2779
2779
|
|
|
@@ -2817,7 +2817,7 @@ Tags: conditional, references, dynamic-query, commerce, validation. Proves: Manu
|
|
|
2817
2817
|
- SCHEMA GAP: required-if — `maxPrice` is required only when visible; that works because hidden fields skip validation, but 'required when price = between AND minPrice is set' can't be written.
|
|
2818
2818
|
- minPrice < maxPrice can't be validated (cross-field).
|
|
2819
2819
|
|
|
2820
|
-
Not carried by a stored component: ai, category, reference
|
|
2820
|
+
Not carried by a stored component: ai, category, shopify reference, variants.
|
|
2821
2821
|
|
|
2822
2822
|
### Global block with per-page overrides (`global-announcement-overrides`)
|
|
2823
2823
|
|
|
@@ -2885,7 +2885,7 @@ Tags: personalization, deep-nesting, conditional, repeater, validation. Proves:
|
|
|
2885
2885
|
- SCHEMA GAP: a variant's hidden `content` is still required-validated by its own rules if `isControl` flips — conditions hide but can't relax `required` declaratively.
|
|
2886
2886
|
- Personalized copy must not change the H1 for SEO purposes; the native page title stays the default's.
|
|
2887
2887
|
|
|
2888
|
-
Not carried by a stored component: ai, category,
|
|
2888
|
+
Not carried by a stored component: ai, category, variants.
|
|
2889
2889
|
|
|
2890
2890
|
### Responsive layout settings (`responsive-layout-settings`)
|
|
2891
2891
|
|
|
@@ -2928,7 +2928,7 @@ Tags: slots, variants, media-heavy, responsive-layout, commerce. Proves: Slot ce
|
|
|
2928
2928
|
- SCHEMA GAP: slotSettings can't be conditional on the child's block type (e.g. padding 'none' only for images) and can't vary per breakpoint.
|
|
2929
2929
|
- Dense packing changes the visual order but not the DOM order — screen readers follow the DOM.
|
|
2930
2930
|
|
|
2931
|
-
Not carried by a stored component: ai, category,
|
|
2931
|
+
Not carried by a stored component: ai, category, variants.
|
|
2932
2932
|
|
|
2933
2933
|
### References web (`references-web`)
|
|
2934
2934
|
|
|
@@ -2951,7 +2951,7 @@ Tags: references, dynamic-query, conditional, repeater, validation. Proves: Prod
|
|
|
2951
2951
|
- SCHEMA GAP: `unique` on reference arrays isn't enforced; the same story can be pinned twice.
|
|
2952
2952
|
- Referencing pages by id survives slug changes; storing hrefs doesn't.
|
|
2953
2953
|
|
|
2954
|
-
Not carried by a stored component: category, reference
|
|
2954
|
+
Not carried by a stored component: category, shopify reference.
|
|
2955
2955
|
|
|
2956
2956
|
### Changelog with nested validation (`changelog-nested-validation`)
|
|
2957
2957
|
|
|
@@ -3041,7 +3041,7 @@ Tags: slots, conditional, a11y, form, repeater, references. Proves: Overlays wit
|
|
|
3041
3041
|
- Exit-intent doesn't exist on touch devices; the label says '(desktop)' because the schema can't scope a trigger per device.
|
|
3042
3042
|
- Focus trap, Esc to close and focus return are renderer requirements, not fields — never make them toggles.
|
|
3043
3043
|
|
|
3044
|
-
Not carried by a stored component: category
|
|
3044
|
+
Not carried by a stored component: category.
|
|
3045
3045
|
|
|
3046
3046
|
### Sticky scroll story (`scrollytelling`)
|
|
3047
3047
|
|
|
@@ -3086,7 +3086,7 @@ Tags: a11y, media-heavy, form, validation, conditional. Proves: Captions per lan
|
|
|
3086
3086
|
- SCHEMA GAP: the sign-up form is modelled inline because forms are a separate system; ideally the block only references the form and the form owns labels/errors.
|
|
3087
3087
|
- Autoplay over 5 seconds without a pause control fails WCAG 2.2.2; the help warns, nothing blocks it.
|
|
3088
3088
|
|
|
3089
|
-
Not carried by a stored component: category
|
|
3089
|
+
Not carried by a stored component: category.
|
|
3090
3090
|
|
|
3091
3091
|
### Section theme tokens (`section-theme-tokens`)
|
|
3092
3092
|
|
|
@@ -3172,7 +3172,7 @@ Tags: slots, polymorphic-array, repeater, variants. Proves: Array of tabs, each
|
|
|
3172
3172
|
- Slot children are `{ componentId, overrides? }` with no `_variant`: a variant is its own component.
|
|
3173
3173
|
- Give every block, tab and instance a stable `id`; changing one orphans the edits made against it.
|
|
3174
3174
|
|
|
3175
|
-
Not carried by a stored component: ai, category,
|
|
3175
|
+
Not carried by a stored component: ai, category, variants.
|
|
3176
3176
|
|
|
3177
3177
|
### Pricing (`core-pricing`)
|
|
3178
3178
|
|
|
@@ -3214,7 +3214,7 @@ Tags: slots, polymorphic-array, variants, responsive-layout, media-heavy. Proves
|
|
|
3214
3214
|
- A slot child has no `_variant`: a variant is its own component.
|
|
3215
3215
|
- slotSettings are leaf fields only; a cell's own copy stays in the cell component's props.
|
|
3216
3216
|
|
|
3217
|
-
Not carried by a stored component: ai, category,
|
|
3217
|
+
Not carried by a stored component: ai, category, variants.
|
|
3218
3218
|
|
|
3219
3219
|
### Journal story (`core-journalStory`)
|
|
3220
3220
|
|
|
@@ -3235,7 +3235,7 @@ Tags: rich-text, references, media-heavy, seo-structured, localized, validation,
|
|
|
3235
3235
|
- Reading time is computed by the template; no field stores it today, so don't copy "7 min read" into readingTime.
|
|
3236
3236
|
- Bind the body wrapper as kind `document`, never `richtext`, or a save repaints the article from plain text.
|
|
3237
3237
|
|
|
3238
|
-
Not carried by a stored component: ai, kind:entry (props), reference
|
|
3238
|
+
Not carried by a stored component: ai, kind:entry (props), shopify reference.
|
|
3239
3239
|
|
|
3240
3240
|
### Hero (`core-hero`)
|
|
3241
3241
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bettercms-ai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.76.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "BetterCMS MCP server — schema, content, forms + components authoring tools over the Management API, authed via OAuth device-code.",
|
|
6
6
|
"bin": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@bettercms-ai/device-auth": "^0.2.0",
|
|
35
|
-
"@bettercms-ai/sdk": "^1.
|
|
35
|
+
"@bettercms-ai/sdk": "^1.32.0",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
37
37
|
"zod": "^4.3.6"
|
|
38
38
|
},
|