@bettercms-ai/mcp 0.62.1 → 0.63.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 +17 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2515,6 +2515,8 @@ var fieldType = z.enum([
|
|
|
2515
2515
|
// `modular` needs config.blockSlugs; `location` takes no config.
|
|
2516
2516
|
"modular",
|
|
2517
2517
|
"location",
|
|
2518
|
+
// One button as one value: { label, href, variant?, size?, arrow?, icon?, newTab? }. A leaf.
|
|
2519
|
+
"button",
|
|
2518
2520
|
// All LEAF types, so the pass-through branch above covers them. `document` is THE article
|
|
2519
2521
|
// body — the rich document canvas, pages or collections, at most one per schema, top level
|
|
2520
2522
|
// only. It was the conspicuous omission: the dashboard shipped an editor for it while no
|
|
@@ -2728,7 +2730,7 @@ function toField(f) {
|
|
|
2728
2730
|
};
|
|
2729
2731
|
}
|
|
2730
2732
|
var BRAND_KIT_NOTE = "`brandKit` (colors, typography, radius and any typeScale/spacing/elevation/motion/graphics) is edited in the BetterCMS dashboard AND by set_brand_assets and set_brand_graphics; every write is a version a person can restore. ASSETS: a media asset OF THIS PROJECT by id; null clears one; a slot a person chose needs `replace: true`. GRAPHICS: `kind`, optional `angle`, 2-8 stops naming `colors.*` or `extras` keys \u2014 never a CSS string and never a hex. CONSUME, DO NOT COPY: a hosted page exposes `--brand-color-<key>`, `--brand-shadow-<key>` and `--brand-gradient-<key>`; style sections with their `style` tokens (`nav.backgroundGradient` and `footer.backgroundGradient` take a gradient key), never copied values. Never invent brand facts: read them from get_project.";
|
|
2731
|
-
var UPDATE_MODEL_DESCRIPTION = "Edit a content model: rename it, change description/slug/urlPattern, set its `fieldsets`, or reshape how its EXISTING fields look in the editor. Never adds, removes or retypes a field (use add_field). Send modelId, or pageId for the model a page's schema lives in. `fieldsets` REPLACES the list (null drops all); a field joins one with fieldFieldset or add_field's `fieldsetId`. The field* args address fields by dotted key path ('hero.title'). A taken slug is 409 `slug_taken`. Section 14 of bettercms://playbook/schema.";
|
|
2733
|
+
var UPDATE_MODEL_DESCRIPTION = "Edit a content model: rename it, change description/slug/urlPattern, set its `fieldsets`, or reshape how its EXISTING fields look in the editor. Never adds, removes or retypes a field (use add_field). Send modelId, or pageId for the model a page's schema lives in. `fieldsets` REPLACES the list (null drops all); a field joins one with fieldFieldset or add_field's `fieldsetId`. The field* args address fields by dotted key path ('hero.title'). Read with get_content_model, then pass `ifMatch` = the version from that read. A taken slug is 409 `slug_taken`. Section 14 of bettercms://playbook/schema.";
|
|
2732
2734
|
var MODEL_IF_MATCH_NOTE = "optimisticVersion from get_content_model (with pageId: get_page backingModel). The write applies only at that version; a 409 version-conflict means it changed since: read it again and re-apply, never retry blindly. REQUIRED with field*, override or a fieldset kind/tab/icon/collapsed (428 without); otherwise, omitted, the last write wins.";
|
|
2733
2735
|
var COMPONENT_IF_MATCH_NOTE = "optimisticVersion from get_component. The write applies only at that version; a 409 version-conflict means it changed since: read it again and re-apply. REQUIRED with prop*, override or a prop ui icon/itemLabel/group (428 without).";
|
|
2734
2736
|
var PROP_UI_ARG_NOTE = "top-level prop key \u2192 ui patch, the same vocabulary as a prop's `ui`: each key merges, a null key clears it, null clears the whole ui";
|
|
@@ -2973,7 +2975,7 @@ function buildToolDefs(deps) {
|
|
|
2973
2975
|
]).describe("block type; section/slider/tabs/columns nest child blocks"),
|
|
2974
2976
|
id: z.string().min(1).describe("stable unique block id"),
|
|
2975
2977
|
props: z.record(z.string(), z.unknown()).describe(
|
|
2976
|
-
"per-type props: heading {text, level}; text/richtext {html} (NOT {text}), and both also take level 1-6, rendering the html AS that <hN> with inline marks kept (one line of inline copy only) \u2014 use it for a title that carries a styled span; image {src, alt}; button {text, href, variant? primary|secondary|tertiary|brand|dark|light|outline|link, size? sm|md|lg, fullWidth?, arrow? boolean, icon?
|
|
2978
|
+
"per-type props: heading {text, level}; text/richtext {html} (NOT {text}), and both also take level 1-6, rendering the html AS that <hN> with inline marks kept (one line of inline copy only) \u2014 use it for a title that carries a styled span; image {src, alt}; button {text, href, variant? primary|secondary|tertiary|brand|dark|light|outline|link, size? sm|md|lg, fullWidth?, arrow? boolean, icon? ui.icon name, newTab? boolean}; spacer {height}; video {url}; form {formId}; component {componentId, overrides?}; navbar {links:[{label,href}], logo?, cta?}; footer {columns, copyright?}; section {children: block[]}; columns {columns: block[][], gap} \u2014 a column may hold ANY block; slider {slides:[{id,children}]}; tabs {tabs:[{id,label,children}]}; collection {cardComponentId?, detailComponentId?, titleField?, excerptField?, limit?, order?, emptyText?} \u2014 lists this page's published entries as cards, and renders ONE entry on /<page>/<entrySlug>"
|
|
2977
2979
|
),
|
|
2978
2980
|
style: z.record(z.string(), z.unknown()).optional().describe(
|
|
2979
2981
|
"design tokens: theme, bg (none|surface|muted|accent|dark|custom), bgCustom hex, paddingTop/paddingBottom/paddingSides px, contentWidth (narrow|default|wide|full), align, corner, shadow, borderTop/borderBottom, border (all four sides, in the text colour). A real marketing band is a `section` block carrying bg + padding + contentWidth."
|
|
@@ -3317,6 +3319,7 @@ function buildToolDefs(deps) {
|
|
|
3317
3319
|
propUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(PROP_UI_ARG_NOTE),
|
|
3318
3320
|
propGroup: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe("prop key \u2192 its ui.group ({id, label?, kind?, icon?, collapsed?}), null takes it out"),
|
|
3319
3321
|
propLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe("prop key \u2192 label"),
|
|
3322
|
+
propHelpText: z.record(z.string(), z.string().max(200).nullable()).optional().describe("prop key \u2192 help text, null clears it"),
|
|
3320
3323
|
override: z.boolean().optional().describe(OVERRIDE_NOTE),
|
|
3321
3324
|
ifMatch: z.number().int().min(0).optional().describe(COMPONENT_IF_MATCH_NOTE)
|
|
3322
3325
|
});
|
|
@@ -3946,7 +3949,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3946
3949
|
fieldsets: fieldsetsArg.nullable(),
|
|
3947
3950
|
fieldUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(FIELD_UI_ARG_NOTE),
|
|
3948
3951
|
fieldFieldset: z.record(z.string(), z.string().min(1).nullable()).optional().describe("path \u2192 fieldset id, null takes it out"),
|
|
3949
|
-
fieldOrder: z.strictObject({ parentPath: z.string().min(1).optional(), order: z.array(z.string().min(1)).min(1).max(200) }).optional().describe("the full new order of one parent's child keys (top level without parentPath)"),
|
|
3952
|
+
fieldOrder: z.strictObject({ parentPath: z.string().min(1).optional(), order: z.array(z.string().min(1)).min(1).max(200) }).optional().describe("the full new order of one parent's child keys (top level without parentPath). An array with both zones needs 'KEY.zones.nonRepeatable' or 'KEY.zones.repeatable'; its bare key is a 400"),
|
|
3950
3953
|
fieldLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe("path \u2192 label"),
|
|
3951
3954
|
fieldHelpText: z.record(z.string(), z.string().max(500).nullable()).optional().describe("path \u2192 help text, null clears it"),
|
|
3952
3955
|
override: z.boolean().optional().describe(OVERRIDE_NOTE),
|
|
@@ -4167,7 +4170,7 @@ ${res.warnings.join("\n")}` : summary, res.data);
|
|
|
4167
4170
|
def(
|
|
4168
4171
|
"get_binding_report",
|
|
4169
4172
|
"Check what on the live site is editable",
|
|
4170
|
-
"The receipt for 'is this site actually EDITABLE?'. Each release scans the built HTML for the element rendering each CMS field value; per slot this returns `mode` ('text-match' = guessed from rendered text, 'declared' = template-declared), what was bound, and `unmatched`: each path with its reason \u2014 not-declared, ambiguous-text, no-element, declared-only, needs-wrap, refused, layout-owned, page-owned, layout-locator-stale, locale-unvarianted, svg-unavailable, report-outdated. DEPLOY FIRST: before any release there is no report (pages 0, mode null, refreshRequired true). `refreshReason`: `never-generated` \u2014 only a release BetterCMS builds and serves writes a report, so a HEADLESS site never gets one, redeploy or not; `outdated` \u2014 the next release rewrites it. It certifies only that every non-empty field has SOME element carrying its path. `unaddressable` is the copy it cannot see: visible live text no field owns, by route and bucket, biggest first (null = unmeasured: diff visible text against entry values). Over `count / visible > 0.02`, fix it in the SOURCE (wrap the run in an element the codemod can bind, or declare `<BcmsField path=\u2026>`), deploy, re-read \u2014 playbook \xA711. `builtRoutes`: routes the live build has HTML for (null = cannot say). `layoutIncomplete`: Layout paths the last content apply could not write (their publish waits); `layoutUnread`: Layout fields no route reads (`layoutUnreadJudged` false = not judged). `canvas.lane`: the editor's live-preview lane (`bridge`, `draft-route`; `none` \u2192 get_next_steps). `coverage.error` `nothing-bound`: no element of this build is bound, so its percentage describes another site.",
|
|
4173
|
+
"The receipt for 'is this site actually EDITABLE?'. Each release scans the built HTML for the element rendering each CMS field value; per slot this returns `mode` ('text-match' = guessed from rendered text, 'declared' = template-declared), what was bound, and `unmatched`: each path with its reason \u2014 not-declared, ambiguous-text, no-element, declared-only, needs-wrap, refused, layout-owned, page-owned, layout-locator-stale, locale-unvarianted, svg-unavailable, partial and unstamped (a page list the content apply left as built: `kind` `list <bound>/<total>`), mismatch (a text-match stamp whose element shows MORE than the value: never written), report-outdated. DEPLOY FIRST: before any release there is no report (pages 0, mode null, refreshRequired true). `refreshReason`: `never-generated` \u2014 only a release BetterCMS builds and serves writes a report, so a HEADLESS site never gets one, redeploy or not; `outdated` \u2014 the next release rewrites it. It certifies only that every non-empty field has SOME element carrying its path. `unaddressable` is the copy it cannot see: visible live text no field owns, by route and bucket, biggest first (null = unmeasured: diff visible text against entry values). Over `count / visible > 0.02`, fix it in the SOURCE (wrap the run in an element the codemod can bind, or declare `<BcmsField path=\u2026>`), deploy, re-read \u2014 playbook \xA711. `builtRoutes`: routes the live build has HTML for (null = cannot say). `layoutIncomplete`: Layout paths the last content apply could not write (their publish waits); `layoutUnread`: Layout fields no route reads (`layoutUnreadJudged` false = not judged). `canvas.lane`: the editor's live-preview lane (`bridge`, `draft-route`; `none` \u2192 get_next_steps). `coverage.error` `nothing-bound`: no element of this build is bound, so its percentage describes another site.",
|
|
4171
4174
|
z.object({ slot: z.enum(["current", "staging"]).optional().describe("which release tree to read \u2014 everything here, `unaddressable` included, is measured PER SLOT, so on a promote-gated project pass 'current' to read the tree the editor frames. Defaults to the slot this project's releases land in. The response's `sha` is the build the report describes; `refreshRequired` is true when that is not the build this slot serves.") }).shape,
|
|
4172
4175
|
async (c, a) => ok("Binding report.", await data(c, "GET", `/management/projects/current/binding-report${q({ slot: a.slot })}`))
|
|
4173
4176
|
),
|
|
@@ -5259,7 +5262,7 @@ ${lines.join("\n")}`, found);
|
|
|
5259
5262
|
name: "update_component",
|
|
5260
5263
|
config: {
|
|
5261
5264
|
title: "Update a reusable component",
|
|
5262
|
-
description: "Update a component by id \u2014 blockJson, props, name, or category. Read get_component
|
|
5265
|
+
description: "Update a component by id \u2014 blockJson, props, name, or category. Read with get_component, then pass `ifMatch` = the version from that read. Passing `blockJson`/`props` REPLACES them. This writes the DRAFT: call publish_component to push the change live.",
|
|
5263
5266
|
inputSchema: updateComponentInput.shape
|
|
5264
5267
|
},
|
|
5265
5268
|
handler: guard(
|
|
@@ -6217,10 +6220,12 @@ conversion is yours to write.
|
|
|
6217
6220
|
load. Bind each item's fields on that item's OWN route (\`/blog/<slug>\`); on the index,
|
|
6218
6221
|
render from the CMS and declare nothing.
|
|
6219
6222
|
5b. **Where the content comes from at build time.** Two lanes, and they differ:
|
|
6220
|
-
- GIT-CONNECTED (recommended for a converted site): the platform's
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6223
|
+
- GIT-CONNECTED (recommended for a converted site): the platform's build writes
|
|
6224
|
+
\`bcms-content.json\` into the repo root before \`build\`, with a key it mints per build: no
|
|
6225
|
+
repo secret feeds it. (The secret a connect sets, \`BCMS_API_KEY_<RUNG>\` such as
|
|
6226
|
+
\`BCMS_API_KEY_PROD\`, is the validation workflows' key; they fall back to the shared
|
|
6227
|
+
\`BCMS_API_KEY\` only for a repo whose last connect predates it.) Read that file, with in-code
|
|
6228
|
+
fallbacks so a local or CI build without it still renders.
|
|
6224
6229
|
- ARCHIVE (\`deploy_project\` / \`deploy_from_upload\`): the sandbox build runs with no env
|
|
6225
6230
|
and no network content step, by design. So the archive MUST SHIP its own
|
|
6226
6231
|
\`bcms-content.json\` \u2014 generate it locally with a delivery key and commit it. Without
|
|
@@ -6397,7 +6402,8 @@ Importance orders a screen: required fields first, then array order.
|
|
|
6397
6402
|
\`fieldLabel\`, \`fieldHelpText\` (keyed by dotted key path, \`'hero.title'\`) and \`fieldsets\`. A page's
|
|
6398
6403
|
schema: the same call with \`pageId\` instead of \`modelId\`, and the version from \`get_page\`'s
|
|
6399
6404
|
\`backingModel\`.
|
|
6400
|
-
- A component's props: \`update_component\` with \`propUi\`, \`propGroup\`, \`propLabel\` (keyed by prop key).
|
|
6405
|
+
- A component's props: \`update_component\` with \`propUi\`, \`propGroup\`, \`propLabel\`, \`propHelpText\` (keyed by prop key).
|
|
6406
|
+
Name props from the code (\`plan.cents\` \u2192 Cents), help text as \`e.g. "49"\`; repeated cards are one \`table\` prop.
|
|
6401
6407
|
They write the DRAFT props; no publish is needed for the editor to show them.
|
|
6402
6408
|
- Always send \`ifMatch\`, the \`optimisticVersion\` you read.
|
|
6403
6409
|
- A NEW field carries its chrome in the same \`add_field\` / \`add_page_field\` call.
|
|
@@ -6521,7 +6527,7 @@ shape, then ask me, once and batched). Icon names are in bettercms://icons/dock.
|
|
|
6521
6527
|
- fields that exist: \`update_content_model\` fieldUi / fieldFieldset / fieldOrder / fieldLabel /
|
|
6522
6528
|
fieldHelpText by field path, plus \`fieldsets\`. A singleton page: send \`pageId\` instead of
|
|
6523
6529
|
modelId, with its backingModel's version;
|
|
6524
|
-
- component props: \`update_component\` propUi / propGroup / propLabel;
|
|
6530
|
+
- component props: \`update_component\` propUi / propGroup / propLabel / propHelpText;
|
|
6525
6531
|
- a NEW field: ui / helpText / showIf in the same \`add_field\` / \`add_page_field\` call, with \`after\`.
|
|
6526
6532
|
A 409 \`ui_human_owned\` names chrome a person set: leave it, or ask me and send \`override: true\`
|
|
6527
6533
|
only on my word.
|