@bettercms-ai/mcp 0.64.1 → 0.65.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.
@@ -54,7 +54,9 @@ These hold on every task. The reference in brackets has the detail and the codes
54
54
  Its `authoringPreference` (components, fields, or null while owed) is asked once, can be
55
55
  re-answered, and is the user's answer, never yours.
56
56
  2. **Never create SEO fields** (§5b). Page and entry meta are native columns. [seo.md]
57
- 3. **A page is a list of sections**, never loose top-level blocks. [components.md]
57
+ 3. **A page is a list of sections**, never loose top-level blocks, and never a nav, footer or
58
+ modal: chrome is the Layout. A call to action is one `button` field, never a text field
59
+ beside a link field. [components.md, content-modeling.md]
58
60
  4. **Nothing is live until it is published, and a page is not its content.** A draft form,
59
61
  component or entry renders nothing live. Read `warnings` on every write: `ENTRY_STILL_DRAFT`
60
62
  and `ENTRY_SEED_FAILED` mean content did not ship. [publishing.md]
@@ -42,6 +42,7 @@ build. Pass `apiUrl` and `workspace` as options, or let the snapshot supply them
42
42
  | `@bettercms-ai/astro/components/BcmsBlocks.astro` | Server render of a block tree. Pass `components` or instances render nothing |
43
43
  | `@bettercms-ai/astro/components/BcmsLiveBlocks.astro` | Same tree as a hydrated island that follows the editor's draft bridge |
44
44
  | `@bettercms-ai/astro/components/BcmsField.astro` | `path`, `kind` (`richtext`/`image`), `as`; emits `data-bcms-field` + `data-bcms-kind` |
45
+ | `@bettercms-ai/astro/components/BcmsButton.astro` | A `button` field: `path`, `value`, `class`. One `<a>` with the label bound, the href in `data-bcms-props` and `data-variant` / `data-size` for your CSS; renders nothing without a label |
45
46
  | `@bettercms-ai/astro/components/BcmsForm.astro` | Renders a delivered form and submits it ([forms-and-interactions.md](forms-and-interactions.md)) |
46
47
 
47
48
  `BcmsLiveBlocks` rules:
@@ -52,6 +53,10 @@ build. Pass `apiUrl` and `workspace` as options, or let the snapshot supply them
52
53
 
53
54
  ## Bindings
54
55
 
56
+ A section root your own code renders spreads `sectionRootAttrs(block)` from `@bettercms-ai/astro`
57
+ (`data-bcms-block`, `data-bcms-style` and the block's style), so the editor can move it and offer
58
+ its spacing handles ([components.md](components.md) §5).
59
+
55
60
  `bind` and `bindProps` from `@bettercms-ai/astro/bindings` produce the same attributes as the Next
56
61
  helpers. Use them inside component instances so addresses resolve to the instance
57
62
  ([bindings.md](bindings.md) §3).
@@ -41,8 +41,10 @@ Never let a component contain itself, directly or through a child.
41
41
  `NO_GROUP_ROOT` (keys are still the derive lane's own, such as `h1-welcome`: rename them into
42
42
  families first), `NOT_A_SECTION` (a lone scalar or page metadata; `detail: ENTRY_METADATA` is
43
43
  a template's frontmatter, `detail: DECLINED` a group the user declined) and `IMAGE_AS_TEXT`
44
- (a text field holding an image path; it plans once the field is an image). Author the real
45
- sections among those with `create_component` and `set_page_content` instead.
44
+ (a text field holding an image path; it plans once the field is an image). A nav, footer or
45
+ modal group is `NOT_A_SECTION` with `detail: LAYOUT_CHROME`: chrome is the Layout on every
46
+ site, never a page band. Author the real sections among those with `create_component` and
47
+ `set_page_content` instead.
46
48
  2. Show the user the sections, how many components it creates and which pages it rewrites.
47
49
  Confirm before writing. A group the user says is not a section: `componentize_sections
48
50
  { digest, sections: [groupKey], pageIds, decline: true }` (`decline: false` undoes it). The
@@ -141,6 +141,30 @@ page that renders its own header or footer does not get the Layout's copy on top
141
141
  Rule: if an instance renders empty, check that definitions were passed before debugging the
142
142
  component.
143
143
 
144
+ ### When the site's own code renders the sections
145
+
146
+ A code-built site ships only what its templates draw, whatever the page's `blockJson` says.
147
+
148
+ - **Render the page's block list, never hard-coded bands.** A section added or moved in the
149
+ editor reaches the live site only when the template loops over the page's blocks in order and
150
+ each section root carries its block id as `data-bcms-block`. The codemod's `--componentize` pass
151
+ generates `src/lib/bcms-sections.ts` for the loop and adds those attributes. Until it ships, the
152
+ editor locks Add section and reordering on that route, and `submit_conversion_receipt` keeps
153
+ `complete: false` with one `SECTIONS_UNSTAMPED` row per route.
154
+ - **No chrome placements on a page.** A nav, footer or modal placement the site's layout draws
155
+ renders nowhere, and the editor locks its outline row and skips it when it moves the sections
156
+ around it. Remove it.
157
+ - **Spread `sectionRootAttrs(block)` on each root you write by hand** (`@bettercms-ai/astro`,
158
+ `@bettercms-ai/next`): it adds `data-bcms-block`, `data-bcms-style` and the block's style. The
159
+ editor offers section spacing and style handles only when every stamped root carries
160
+ `data-bcms-style`. A site converted before it existed shows none and `get_next_steps` lists
161
+ `upgrade-section-roots`. The fix is the codemod's `--upgrade-sections` mode, latest version, at
162
+ the repo root (`--dry-run` first); give each root it reports as skipped (`OWN_STYLE`, `SPREAD`,
163
+ `BLOCK_ID_ONLY`, …) its block style by hand, confirm with `--verify-styles`, push and release.
164
+ - **A `button` field renders with `BcmsButton`** (`path`, `value`): one `<a>` carrying
165
+ `data-variant` and `data-size`, so the site's CSS decides what each look looks like and the
166
+ editor repaints it live.
167
+
144
168
  ## 6. Preview source
145
169
 
146
170
  - `set_component_source` records which file in the repo implements a component;
@@ -83,6 +83,16 @@ sitemap), RSS (dated by `publishedAt`), `llms.txt` (one link per published item)
83
83
  URL for links that leave the site.
84
84
  - A repeater for small, same-shaped items (cards, FAQ rows, links, social accounts); a nested
85
85
  component or slot when an item has its own layout or variants.
86
+ - **Model a call to action as a single `button` field.** It stores `{ label, href }` plus the
87
+ optional look keys `variant`, `size`, `arrow`, `icon` and `newTab`, and the site draws it with
88
+ `BcmsButton` ([astro.md](astro.md), [next.md](next.md)). Never a text
89
+ field beside a link field: the pair has nowhere to keep a look, and a new pair in the importer's
90
+ spelling (`hero-span-go` + `hero-a-go-href`) is refused with 400 `cta_pair` on `add_field`,
91
+ `create_page` and model writes. A page that already holds a pair (`primaryCtaText` +
92
+ `primaryCtaHref`) becomes one button with `update_field` `{ pageId, path: "primaryCtaText",
93
+ mergeHref: "primaryCtaHref" }`: each entry's DRAFT gets `{ label, href }` and keeps the old values,
94
+ so code still reading them keeps rendering; the live copy changes on publish. Inside a component
95
+ a CTA is a `button` block whose `props.text` and `props.href` two props target.
86
96
  - Never model SEO columns ([seo.md](seo.md)), Form questions (they live on the Form document) or
87
97
  Global Layout values as content fields.
88
98
  - Keep source ids, slugs, locale, status and previous URLs as migration metadata, stable across
@@ -41,6 +41,8 @@ webhook. Use the project's webhook secret from the dashboard (the package docs n
41
41
  | `BcmsBlocks` | Render a block tree; pass `components` from `readComponents()` |
42
42
  | `readComponents()` | Component definitions from `bcms-content.json` |
43
43
  | `BcmsField` | `path`, `kind` (`richtext`/`image`), `as`; server-safe |
44
+ | `BcmsButton` | A `button` field: `path`, `value`, `className`; one `<a>` with `data-variant` / `data-size` for your CSS; server-safe |
45
+ | `sectionRootAttrs(block)` | Spread on a section root your own code renders: `data-bcms-block`, `data-bcms-style` and the block's style ([components.md](components.md) §5) |
44
46
  | `bind`, `bindProps` | Binding attributes; instance-aware inside components |
45
47
  | `BcmsForm` + `getForm(idOrName)` | Forms from the snapshot ([forms-and-interactions.md](forms-and-interactions.md)) |
46
48
  | `buildMetadata(page, siteDefaults, location?)` | Next `Metadata` from native SEO fields |
@@ -43,7 +43,8 @@ intended UX; confirm each control exists in the connected editor before promisin
43
43
  | FAQ question | text | plain | inside an accessible trigger; the component owns the level |
44
44
  | FAQ answer, modal body | narrowed richtext | paragraphs, lists, links, emphasis | focus and ARIA live outside the value |
45
45
  | Image | image | asset, alt text, caption | bind `src` and `alt` separately |
46
- | Link or button | grouped fields | label, link, style variant | no raw HTML, no `javascript:` URL |
46
+ | Link | link | the destination | no raw HTML, no `javascript:` URL |
47
+ | Button / call to action | one `button` field | label, link, style, size, arrow, icon, new tab | render with `BcmsButton`; never a text + link pair |
47
48
 
48
49
  "Disabled" controls mean the field's accept list removes irrelevant formatting; the field stays
49
50
  editable. Keep a source's unusual but valid hierarchy when changing it would alter meaning, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/mcp",
3
- "version": "0.64.1",
3
+ "version": "0.65.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": {