@bettercms-ai/mcp 0.76.3 → 0.76.4

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.
@@ -81,7 +81,7 @@ Never let a component contain itself, directly or through a child.
81
81
 
82
82
  ## 3. Names and groups
83
83
 
84
- The import's kit entry (`kit: suggested <id> <score>`, the gate row's `hint`) is only a suggestion: nothing is recorded. For each component, read `bettercms://kit/entry/{id}`, check its `htmlSignals` against the section's own HTML and its pitfalls against the props, then confirm it or pick the right one from its category in `bettercms://kit` and name it with `update_component { kitEntry }`. Setting or changing `kitEntry` puts that entry's ui over the derived ui: where the entry specifies a tab, group, control or preview key for a prop, the entry wins; what it says nothing about stays as derived; ui you or a person set is kept. The `no-kit-match` exemption needs a note.
84
+ The import's kit entry (`kit: suggested <id> <score>`, the `hint` of its row in `receipt.gate.kit`) is only a suggestion: nothing is recorded, and nothing waits on it. The props already carry the ui that suggestion gives. For each component, read `bettercms://kit/entry/{id}`, check its `htmlSignals` against the section's own HTML and its pitfalls against the props, then confirm it or pick the right one from its category in `bettercms://kit` and name it with `update_component { kitEntry }`. Setting or changing `kitEntry` puts that entry's ui over the derived ui: where the entry specifies a tab, group, control or preview key for a prop, the entry wins; what it says nothing about stays as derived; ui you or a person set is kept. The `no-kit-match` exemption needs a note.
85
85
 
86
86
  Name a family by what it is (`Hero`, `CTA`, `Testimonials`) and each variant by how it looks
87
87
  (`Hero / Split`, `CTA / Centered`). Never put a page name in a reusable definition; which pages
@@ -65,17 +65,17 @@ line), which is what a script waiting on the setup reads.
65
65
  | `link` | 95% of the links have a field for the label or the destination | `routes.rows[].link` |
66
66
  | `sections` | every section the page places is a stamped root on the built page, none twice, none published after the build, and a section added in BetterCMS has somewhere to show (`accepts` `list` or `in-place`) | `routes.rows[].sections`: `accepts`, `renderer` (`sdk`, `registry`, `annotator`), and when it fails `refusal` (why the release cannot write the page) and `wrap` (`wrapped`, or `refused:<REASON>` from the sections conversion) |
67
67
  | `style` | every stamped section root carries the style marker (`data-bcms-style`, or `data-bcms-block-style` on a root that is a field's element) or is drawn by the route's block renderer, counted by setup on the served page, so a block's spacing, padding and background paint | `routes.rows[].style` |
68
- | `svg` | every inline SVG a visitor sees (a logo, an icon, an illustration) belongs to a field; a hidden symbol sheet is not counted | `routes.rows[].svg` |
68
+ | `svg` | every inline SVG a visitor sees (a logo, an icon, an illustration) belongs to a field; a hidden symbol sheet is not counted, nor the glyphs of a rating drawn as one image (`role="img"` round them) | `routes.rows[].svg` |
69
69
  | `number` | every element whose whole text is a number (a stat, a price, a rating) belongs to a field | `routes.rows[].number` |
70
- | `attribute` | every `alt`, `aria-label`, `title` and `placeholder` with words in it belongs to a field | `routes.rows[].attribute` |
71
- | `names` | no field of the page, and no component, has a name a person cannot read: a slug, a hash, a structural word (`Section 2`, `wrap`), or a number beside the same name (`Icon 2`) | `blocking.rows` |
72
- | `seo` | the page has a title of at most 70 characters and a description of at most 200, and a canonical where the build ships one for this site's origin; site-wide, every page has a share image, its own or the site's default | `blocking.rows` |
70
+ | `attribute` | every `alt`, `aria-label`, `title` and `placeholder` with words in it belongs to a field; copy inside a field's rich text is that field's, and a picture's or icon's name is its field's | `routes.rows[].attribute` |
71
+ | `names` | never a row: a name holds nothing open. A field, a section, a component or a prop whose name a person cannot read (a slug, a hash, a structural word such as `Section 2` or `wrap`, a number beside the same name such as `Icon 2`) is listed as advice with the call that renames it. The import already names a section by its own title, and a section's list by that title, where the markup gave it nothing better | `advice` (check `names`), and `naming` |
72
+ | `seo` | the page has a title and a description, and a canonical where the build ships one for this site's origin. A title over 70 characters or a description over 200 is the site's own copy as built, and a site with no default share image has none to give: both are advice (`receipt.gate.advice`), never rows | `blocking.rows` |
73
73
  | `structuredData` | JSON-LD the build ships on the route is on the page or the entry | `blocking.rows` |
74
74
  | `collections` | sibling routes that are one family (three under one parent, or two under `tags`, `category`, `author`) are a collection; reported on the family's listing route, built or not | `blocking.rows` |
75
75
  | `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` |
76
- | `components` | the authoring question is answered, and no section is left that a componentize run would place | `blocking.rows`, `route: null` |
76
+ | `components` | the authoring question is answered, and no section is left that a componentize run would place. A heading or paragraph that stands outside any section is a field of its page, not a section: advice (`receipt.gate.advice`) | `blocking.rows`, `route: null` |
77
77
  | `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` |
78
- | `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`; the import only suggests one, the row's `hint`: confirm or replace it after checking its htmlSignals and pitfalls, and the write rebuilds the derived ui), 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` |
78
+ | `dock` | no component is left with props the server's own ui derivation would still dress: one it has not reached has no prop carrying V2 `ui`, or a list prop (`table`, `array`, `multi-reference`) with no row title (`ui.preview.title` or `ui.itemLabel`). The import derives each prop's ui when it makes a component, from its closest `bettercms://kit` entry or the generic rules, so a fresh import has no such row; a component whose props it leaves to the default controls (two short texts) is done. Button looks are not counted. Which kit entry a component IS is not part of this check: it is advice, `receipt.gate.kit` (below) | `blocking.rows`, `route: null`, the component and its props in `detail` |
79
79
 
80
80
  `pages` counts routes built, created and published. `coverage` sums `editable` of `total` across
81
81
  the site, `svg`, `number` and `attribute` included, and `open` counts the rows still open per
@@ -172,7 +172,10 @@ of a row the release bound to its entry (a field's there too). The release binds
172
172
  each such row to its entry: the row carries `data-bcms-entry`, a part showing a field as stored
173
173
  carries `data-bcms-entry-field` (`entry:<id>:<path>`, written when that entry publishes), and a
174
174
  part the site's code made from a field (a cut excerpt, a reformatted date or price, a thumbnail,
175
- the item link) carries `data-bcms-entry-from` with the transform, read-only: edit the entry.
175
+ the item link) carries `data-bcms-entry-from` with the transform: edit the entry. When it publishes,
176
+ a picture (`|rendition`) and a number (`|format`) are written in place; any other such part that no
177
+ longer shows its value is reported `entry-derived` with why (`truncate`, `route`, `format`,
178
+ `art-direction`, `repo-path`, `format-unreadable`).
176
179
  Never add a field for a row to the listing page. A taxonomy's term routes (`/tags/<term>`, each
177
180
  listing another collection's entries) are a small collection of terms, and their rows are bound
178
181
  the same way. A term has a `body` only where its template has an article. Chrome the Layout
@@ -199,6 +202,14 @@ and use what it calls things (`plan.cents`, `billingFrequency`, `StatsBand.astro
199
202
  | A field or prop | what it HOLDS there, one to three words | `Dismiss key`, `Starter plan price`, `Dashboard screenshot`, `Billing frequency` | its own copy, a role with a number (`Text 4`), the section's name alone |
200
203
  | Help text | most fields get none. One plain sentence under 90 characters, only for a format or unit, a place the canvas cannot show, a real constraint or a fallback. No semicolons, no dashes, no values from the page | `Leave empty to use the page title.` | the label or the value said again, writing advice, a figure copied from another page |
201
204
 
205
+ **Advice is not work left.** `receipt.gate.advice`, `gate.families`, `gate.kit` and `gate.naming`
206
+ are things a person may want to change about the site's own content or build: a title longer than
207
+ a search result shows, no default share image, an element outside any section, a route family that
208
+ could be a collection, a kit entry to confirm, a name to sharpen. The site is fully editable with
209
+ every one of them standing. When `gate.complete` is true the setup is DONE: say so, list the
210
+ advice in a few lines as optional improvements, and never call any of it pending, blocked,
211
+ remaining or left over, and never end on a question about it.
212
+
202
213
  A section says two things: what it IS (its kind) and what it SAYS (its title). Only the kind is
203
214
  yours to judge. The import sets it from the band's shape or the site's own word for it; where it
204
215
  could read neither, the kind is the key's word, often the heading's first, and you correct it with
@@ -314,7 +325,7 @@ and add the new result. Update the file as each row moves, so a reset loses at m
314
325
  | 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) |
315
326
  | 6 | Behaviour: forms, links, menus, accordions, modals, consent, custom code | [forms-and-interactions.md](forms-and-interactions.md) |
316
327
  | 7 | Discoverability: native SEO, structured data, robots and sitemap, redirects, internal links | [seo.md](seo.md) |
317
- | 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) |
328
+ | 8 | Editor chrome, last and never a condition of being done. The import has already given each prop its V2 `ui`, from its closest `bettercms://kit` entry or the generic rules. `receipt.gate.kit` lists the components that name no kit entry, each with the import's closest match as `hint`: where you have the time, read the entry, check its htmlSignals and pitfalls against the section, and name it (`update_component { kitEntry }`), which rebuilds the ui from it. Do it after the gate is complete, one component at a time. Never report it as pending, blocked or left over | [editor-chrome.md](editor-chrome.md) |
318
329
 
319
330
  Load the step's reference when the step starts, and let it go when the step's rows are verified.
320
331
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/mcp",
3
- "version": "0.76.3",
3
+ "version": "0.76.4",
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": {