@bettercms-ai/mcp 0.62.2 → 0.63.1
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 +15 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2730,7 +2730,7 @@ function toField(f) {
|
|
|
2730
2730
|
};
|
|
2731
2731
|
}
|
|
2732
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.";
|
|
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'). 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.";
|
|
2734
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.";
|
|
2735
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).";
|
|
2736
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";
|
|
@@ -2975,7 +2975,7 @@ function buildToolDefs(deps) {
|
|
|
2975
2975
|
]).describe("block type; section/slider/tabs/columns nest child blocks"),
|
|
2976
2976
|
id: z.string().min(1).describe("stable unique block id"),
|
|
2977
2977
|
props: z.record(z.string(), z.unknown()).describe(
|
|
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
|
|
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>"
|
|
2979
2979
|
),
|
|
2980
2980
|
style: z.record(z.string(), z.unknown()).optional().describe(
|
|
2981
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."
|
|
@@ -3319,6 +3319,7 @@ function buildToolDefs(deps) {
|
|
|
3319
3319
|
propUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(PROP_UI_ARG_NOTE),
|
|
3320
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"),
|
|
3321
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"),
|
|
3322
3323
|
override: z.boolean().optional().describe(OVERRIDE_NOTE),
|
|
3323
3324
|
ifMatch: z.number().int().min(0).optional().describe(COMPONENT_IF_MATCH_NOTE)
|
|
3324
3325
|
});
|
|
@@ -3948,7 +3949,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3948
3949
|
fieldsets: fieldsetsArg.nullable(),
|
|
3949
3950
|
fieldUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(FIELD_UI_ARG_NOTE),
|
|
3950
3951
|
fieldFieldset: z.record(z.string(), z.string().min(1).nullable()).optional().describe("path \u2192 fieldset id, null takes it out"),
|
|
3951
|
-
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"),
|
|
3952
3953
|
fieldLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe("path \u2192 label"),
|
|
3953
3954
|
fieldHelpText: z.record(z.string(), z.string().max(500).nullable()).optional().describe("path \u2192 help text, null clears it"),
|
|
3954
3955
|
override: z.boolean().optional().describe(OVERRIDE_NOTE),
|
|
@@ -4169,7 +4170,7 @@ ${res.warnings.join("\n")}` : summary, res.data);
|
|
|
4169
4170
|
def(
|
|
4170
4171
|
"get_binding_report",
|
|
4171
4172
|
"Check what on the live site is editable",
|
|
4172
|
-
"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, or no longer the text it was matched on (`data-bcms-from`): 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.",
|
|
4173
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,
|
|
4174
4175
|
async (c, a) => ok("Binding report.", await data(c, "GET", `/management/projects/current/binding-report${q({ slot: a.slot })}`))
|
|
4175
4176
|
),
|
|
@@ -5261,7 +5262,7 @@ ${lines.join("\n")}`, found);
|
|
|
5261
5262
|
name: "update_component",
|
|
5262
5263
|
config: {
|
|
5263
5264
|
title: "Update a reusable component",
|
|
5264
|
-
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.",
|
|
5265
5266
|
inputSchema: updateComponentInput.shape
|
|
5266
5267
|
},
|
|
5267
5268
|
handler: guard(
|
|
@@ -6219,10 +6220,12 @@ conversion is yours to write.
|
|
|
6219
6220
|
load. Bind each item's fields on that item's OWN route (\`/blog/<slug>\`); on the index,
|
|
6220
6221
|
render from the CMS and declare nothing.
|
|
6221
6222
|
5b. **Where the content comes from at build time.** Two lanes, and they differ:
|
|
6222
|
-
- GIT-CONNECTED (recommended for a converted site): the platform's
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
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.
|
|
6226
6229
|
- ARCHIVE (\`deploy_project\` / \`deploy_from_upload\`): the sandbox build runs with no env
|
|
6227
6230
|
and no network content step, by design. So the archive MUST SHIP its own
|
|
6228
6231
|
\`bcms-content.json\` \u2014 generate it locally with a delivery key and commit it. Without
|
|
@@ -6399,7 +6402,8 @@ Importance orders a screen: required fields first, then array order.
|
|
|
6399
6402
|
\`fieldLabel\`, \`fieldHelpText\` (keyed by dotted key path, \`'hero.title'\`) and \`fieldsets\`. A page's
|
|
6400
6403
|
schema: the same call with \`pageId\` instead of \`modelId\`, and the version from \`get_page\`'s
|
|
6401
6404
|
\`backingModel\`.
|
|
6402
|
-
- 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.
|
|
6403
6407
|
They write the DRAFT props; no publish is needed for the editor to show them.
|
|
6404
6408
|
- Always send \`ifMatch\`, the \`optimisticVersion\` you read.
|
|
6405
6409
|
- A NEW field carries its chrome in the same \`add_field\` / \`add_page_field\` call.
|
|
@@ -6523,7 +6527,7 @@ shape, then ask me, once and batched). Icon names are in bettercms://icons/dock.
|
|
|
6523
6527
|
- fields that exist: \`update_content_model\` fieldUi / fieldFieldset / fieldOrder / fieldLabel /
|
|
6524
6528
|
fieldHelpText by field path, plus \`fieldsets\`. A singleton page: send \`pageId\` instead of
|
|
6525
6529
|
modelId, with its backingModel's version;
|
|
6526
|
-
- component props: \`update_component\` propUi / propGroup / propLabel;
|
|
6530
|
+
- component props: \`update_component\` propUi / propGroup / propLabel / propHelpText;
|
|
6527
6531
|
- a NEW field: ui / helpText / showIf in the same \`add_field\` / \`add_page_field\` call, with \`after\`.
|
|
6528
6532
|
A 409 \`ui_human_owned\` names chrome a person set: leave it, or ask me and send \`override: true\`
|
|
6529
6533
|
only on my word.
|