@bettercms-ai/mcp 0.76.5 → 0.77.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.
@@ -297,3 +297,70 @@ fields, submitUrl). After the binding pass, run the codemod's forms mode (`npx
297
297
  @bettercms-ai/convert --forms`, with the brief and a receipt file) to wire them into the
298
298
  repository's own `<form>` elements. Read `forms.pending`, and publish every form `forms.notes` names in the Forms tab: a draft
299
299
  form rejects every submission with a 403.
300
+
301
+ ## Editor setup, proposals and binding decisions
302
+
303
+ `editor_setup` derives what a build no longer imports: a build brings in SEO/meta, media, brand and
304
+ the models `bcms-content.json` declares; editor setup adds pages, collections, forms, bindings,
305
+ button and section components (when the authoring preference is components), Component Groups and
306
+ the Content sidebar. `get_deploy_status` `editorSetup` reports its state.
307
+
308
+ The complete brief's `proposals` (page 1, at most 50; `proposalsMore` when there are more) list
309
+ what the last convert found and no field owns: `{ id, kind, target, text, suggested?, evidence? }`.
310
+ `id` is `pr_` and 16 hex and survives re-runs; `target` is a `file:line:col` locator only. Kinds:
311
+ `unaddressable` and `code-candidate` (copy no field owns), `inert` (declared, nothing reads it),
312
+ `mismatch` (declares one path, reads another), `flatten` (two leaves in one element).
313
+
314
+ Answer them with `editor_setup { declare: [item, …] }` (at most 100 items, one result each;
315
+ `check: true` with `declare` is a dry run that stores nothing):
316
+
317
+ - `{ op: "accept", ids }` takes each proposal's `suggested` op. A proposal with none refuses.
318
+ - `{ op: "bind", id, path, owner? }` binds the copy to an existing field; `owner` is a route or
319
+ `layout`. The next convert writes it into the source (a mismatch's declaration is rewritten; an
320
+ attribute or an expression is reported `manual` in `receipt.decisionsApplied`). A `bind` waits as
321
+ `decision-pending` until a build proves the new read; one still pending after the next release
322
+ blocks the gate. A declared element is corrected through its `mismatch` proposal id.
323
+ - `{ op: "code", id, why, system? }` keeps it in code. `why` is one of `runtime`, `external`,
324
+ `derived`, `stylesheet`, `decorative`, `embed`, `legal`, and the system checks its evidence;
325
+ without it the item refuses `evidence-missing` (bind it, pick the reason that fits, or a person
326
+ marks it in Overview). The next convert writes `data-bcms-code-owned="text why:<id>"`; the
327
+ `code` counts once a build carries it. Each convert re-checks the
328
+ facts: one whose reason no longer holds becomes `evidence-lost`, blocks the gate, and returns to
329
+ the proposals to decide again. Facts are same-file only: a value from another file needs a person.
330
+ - `{ op: "reject", ids }` drops the suggestion; the copy stays unaddressable. A person's reject of
331
+ an AI `code` is its Undo: the next convert removes the token.
332
+ - `{ op: "clear", decisionId }` undoes a decision.
333
+
334
+ A person's decision beats yours: add `force: true` and a `reason` (shown to them) only when they
335
+ asked for it. Refusals per item: `target-unknown`, `path-not-in-schema`, `owner-mismatch`,
336
+ `locked-by-person`, `slot-mismatch`, `evidence-missing`, `declaration-conflict`, `invalid-item`.
337
+ Until a convert that emits proposals has submitted its receipt, every id refuses `target-unknown`.
338
+ `get_next_steps` `receipt.decisions` counts `stored`, `materialized`, `proven`, `pending` (open
339
+ proposals) and `lost`; stop when `pending` is 0.
340
+
341
+ ### Archive (ZIP) sites
342
+
343
+ A project with no connected repository and no receipt carrying proposals is an ARCHIVE site: no
344
+ codemod runs, so each release scan mints the proposals itself. `target` is then
345
+ `template|owner|textHash` (owner `page`, `layout` or `entry:<collection>`; Layout copy has template
346
+ `*`, an entry route its collection's `/blog/*`), and translations of a page share one template.
347
+ Decisions are not written into source: every release stamps them into the built HTML wherever
348
+ their anchors (structure, text, nearest declared field) agree 2 of 3, else the row is `lost`
349
+ (`anchor-lost`). A `bind` stamps only when the element's text equals the field's stored value; an
350
+ uploaded copy change loses it (`anchor-text-changed`) and its copy is proposed again. An AI `code`
351
+ for `runtime`, `external`, `derived` or `stylesheet` refuses `evidence-missing` here (there is no
352
+ source to check); `decorative`, `embed` and `legal` are checked on the page, and a person may mark
353
+ any reason. Each such decision lives in BetterCMS, not in the site's code: recommend connecting a
354
+ repository.
355
+
356
+ Archive sites also take `{ op: "rule", template, match, then }`, one row for every element it
357
+ matches on every route of `template`:
358
+ - `template`: `/`-segments literal or `*`, a trailing `/**`, or `*` alone (every route). No regex.
359
+ - `match`: at least one of `struct` (a proposal's structure anchor), `cls` (one class token),
360
+ `text` (exact copy); `owner` (`page`, `layout`, `entry`) narrows.
361
+ - `then`: `{ op: "code", why }` or `{ op: "bind", path }`. A bind rule names a `layout` or `entry`
362
+ owner, and matching more than one element on a route is `ambiguous` there.
363
+ A person beats an AI, then a per-id decision beats a rule; two rules saying different things about
364
+ one element are `declaration-conflict`. On a git site a `rule` refuses `invalid-item`. A lane change
365
+ (a repository connected, or a convert's receipt arriving) loses the other lane's decisions
366
+ (`lane-changed`): decide again on the new proposals.
@@ -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 `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.
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. It also carries the entry's rules (showIf, limits, patterns, options, required) onto props that have none of their own. A component whose props still lack some gets a `gate.kit` row with `drift` listing each one as `path.key=value`: add them with `update_component { props }`, or record `kit-drift-accepted` with a note. 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
@@ -35,7 +35,7 @@ row has the field `key`, a `reason` and, for a look set by several props, the si
35
35
  merge into the stored `ui`:
36
36
  `update_content_model { modelId | pageId, fieldUi: { "<path>": { input: { name, writes } } }, ifMatch, confirmed: true }`,
37
37
  `update_component { componentId, propUi: { "<key>": { input: { name, writes } } }, ifMatch, confirmed: true }`.
38
- `update_field`'s `ui` REPLACES the field's whole `ui`: send every key you read with it.
38
+ `update_field`'s `ui` MERGES per key into the stored `ui`, as `fieldUi` does: send `null` for a key to clear it.
39
39
  4. On no: leave it. Nothing is broken.
40
40
 
41
41
  A write through the agent tools that sets or changes `ui.input` without `confirmed: true` is
@@ -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, shopify reference, variants.
117
+ Not carried by a stored component: ai, category, kind:global, shopify reference, slot allow: ctaCard, imageBlock, productCard, videoBlock, variants.
118
118
 
119
119
  ### Docs sidebar navigation (`nav-docs-sidebar`)
120
120
 
@@ -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, variants.
647
+ Not carried by a stored component: ai, category, slot allow: featureBlock, statBlock, imageBlock, videoBlock, quoteBlock, ctaCard, textBlock, variants.
648
648
 
649
649
  ### Steps / how it works (`steps-how-it-works`)
650
650
 
@@ -922,7 +922,7 @@ Tags: repeater, variants, a11y, validation, conditional, media-heavy. Proves: Gr
922
922
  - Alt text like “logo” or empty alt on linked logos fails a11y; the required name fixes it.
923
923
  - Conditions on `_variant` work today because the variant is stored on the block value — this is a schema-language gap worth making official.
924
924
 
925
- Not carried by a stored component: category, item openMode, variants.
925
+ Not carried by a stored component: category, item openMode, showIf on _variant, variants.
926
926
 
927
927
  ### Press mentions (`press-mentions`)
928
928
 
@@ -1145,7 +1145,7 @@ Tags: media-heavy, a11y, responsive-layout, variants, conditional. Proves: Art-d
1145
1145
  - Text over a busy photo fails contrast; the overlay help gives a range and the renderer checks contrast.
1146
1146
  - A background-image has no alt — converting to an `<img>` with alt (or decorative) is part of the import.
1147
1147
 
1148
- Not carried by a stored component: ai, category, variants.
1148
+ Not carried by a stored component: ai, category, showIf on _variant, variants.
1149
1149
 
1150
1150
  ### Social photo feed (UGC) (`ugc-social-feed`)
1151
1151
 
@@ -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, variants.
2776
+ Not carried by a stored component: ai, category, slot allow: layoutColumns, accordionBlock, textBlock, imageBlock, videoBlock, ctaCard, variants.
2777
2777
 
2778
2778
  ### Any-block module list (`polymorphic-modules`)
2779
2779
 
@@ -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, variants.
2931
+ Not carried by a stored component: ai, category, slot allow: imageBlock, productCard, quoteBlock, textBlock, ctaCard, statBlock, videoBlock, featureBlock, variants.
2932
2932
 
2933
2933
  ### References web (`references-web`)
2934
2934
 
@@ -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, slot allow: textBlock, imageBlock, videoBlock, ctaCard, quoteBlock, featureBlock.
3045
3045
 
3046
3046
  ### Sticky scroll story (`scrollytelling`)
3047
3047
 
@@ -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, variants.
3175
+ Not carried by a stored component: ai, category, slot allow: textBlock, imageBlock, featureBlock, statBlock, quoteBlock, ctaCard, productCard, videoBlock, 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, variants.
3217
+ Not carried by a stored component: ai, category, slot allow: imageBlock, statBlock, quoteBlock, textBlock, ctaCard, productCard, videoBlock, variants.
3218
3218
 
3219
3219
  ### Journal story (`core-journalStory`)
3220
3220
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/mcp",
3
- "version": "0.76.5",
3
+ "version": "0.77.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": {