@bettercms-ai/mcp 0.76.4 → 0.76.6

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,43 @@ 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.
@@ -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
@@ -74,7 +74,7 @@ line), which is what a script waiting on the setup reads.
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
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
- | `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` |
77
+ | `forms` | every form of the customer's reaches somebody: its own address, else the project's default, else the workspace's owners, the order a submission is sent in; a form setup ignored (sign-in, add to basket) is not counted | `blocking.rows`, `route: null` |
78
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
@@ -112,7 +112,7 @@ The other rows name their fix the same way:
112
112
  | `model-collection` | not a row any more. Setup derives a collection wherever a family's pages share one template, with its fields, its entries and their bodies. A family it left as pages is listed as advice in `receipt.gate.families`: every route in it is an editable page. **Never `create_content_model` for it on an imported site.** One hand-written model reads the whole project as hand-authored, and the import then registers no further page, derives no collection and adds no field, which is where "the model holds only title and description" comes from. Mention the family to the owner as something a collection could hold later, and go on |
113
113
  | `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)) |
114
114
  | `componentize` | `set_authoring_preference` when nobody answered, then `get_componentize_plan` and `componentize_sections` ([componentize.md](componentize.md)) |
115
- | `set-form-recipient` | `update_form` with `notifyEmails` set to the address the owner gave when setup started (it is in your first prompt); `update_form { ignored: true }` when it is not one of their forms. Only a form the built site posts to BetterCMS is listed, and the release publishes it once it is wired. Never ask for an address at the end of a run |
115
+ | `set-form-recipient` | `update_form` with `notifyEmails` set to the address the owner gave when setup started (it is in your first prompt); `update_form { ignored: true }` when it is not one of their forms. Only a form the built site posts to BetterCMS is listed, and only when a submission would reach nobody at all (no address on the form, none on the project, no owner on the workspace); the release publishes it once it is wired. Never ask for an address at the end of a run |
116
116
  | `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)) |
117
117
 
118
118
  A row nothing measured reads `unmeasured: true` with `run-setup`, and `gate.unmeasured` lists the
@@ -125,7 +125,7 @@ value to its asset. Check it, never redo it: the binding report's `elementCovera
125
125
  |---|---|---|
126
126
  | `IMG_DATA_URI`, `IMG_NO_SOURCE` | An `<img>` inlined as `data:`, or filled in by a script | Ship it as a file with a real `src` |
127
127
  | `BG_PSEUDO_ELEMENT` | A background on `::before` / `::after` | Move it onto the element, or render an `<img>` |
128
- | `BG_ON_TEXT` | A background on an element that is itself a text field | Wrap the text, so the box and the words are two elements |
128
+ | `BG_ON_TEXT` | A background on an element that is itself a text field, or on a section whose copy sits directly in it. A section that keeps its copy in one wrapper is never listed: the picture is the section's field and the copy the wrapper's | Wrap the text, so the box and the words are two elements |
129
129
  | `SVG_TOO_LARGE` | An inline `<svg>` past 64 KB | Ship it as an `.svg` file in an `<img>` |
130
130
  | `SVG_SPRITE` | A `<use>` naming a symbol the page does not hold, or a sprite FILE the build does not ship (another host's, a relative path) | Inline the symbol in the page, serve the sprite from the site root, or ship the icon as its own `<svg>` |
131
131
  | `IMAGE_NOT_ASSET` | A header or footer picture the Media library holds no asset for | Nothing lost: the rest of the region is the Layout's and this picture stays a field of each page. Setup tries it again on the next build |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/mcp",
3
- "version": "0.76.4",
3
+ "version": "0.76.6",
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": {