@bettercms-ai/mcp 0.75.0 → 0.76.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 +27 -13
- package/dist/index.js.map +1 -1
- package/dist/skills/bettercms/references/componentize.md +2 -0
- package/dist/skills/bettercms/references/components.md +13 -2
- package/dist/skills/bettercms/references/content-modeling.md +10 -7
- package/dist/skills/bettercms/references/finish-site.md +43 -16
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2996,7 +2996,7 @@ var PARAM_TEXT = {
|
|
|
2996
2996
|
readOnly: "'developer' = the value and this lock change only with schema access (needs lockReason); true = an editor marker",
|
|
2997
2997
|
lockReason: "which system owns the value (\u2264 200 chars)",
|
|
2998
2998
|
lockClears: "as on add_field; null clears it",
|
|
2999
|
-
helpText: "shown under the field:
|
|
2999
|
+
helpText: "shown under the field. Most fields get none: write it only for a format or unit, a place the canvas cannot show, a real constraint or a fallback, as one plain sentence under 90 characters with no semicolons, no dashes and no values from the page, never its label or value. Omitted: the platform writes it where one of those reasons holds.",
|
|
3000
3000
|
helpMore: "longer help behind the \u24D8 next to the label, when one helpText line cannot carry it",
|
|
3001
3001
|
advanced: "true = a rare or developer setting: it collects in a closed 'Advanced' section",
|
|
3002
3002
|
recommendedMax: "a SOFT limit (characters, items or value): the editor warns past it, never refuses",
|
|
@@ -3005,6 +3005,7 @@ var PARAM_TEXT = {
|
|
|
3005
3005
|
componentPreview: "a slot row's look: {title?, subtitle?, media?} TOP-LEVEL prop keys, fallback?, icon?; null clears. \xA73 of bettercms://playbook/schema",
|
|
3006
3006
|
componentIcon: "the block icon, a dock icon name; null clears. \xA73 of bettercms://playbook/schema",
|
|
3007
3007
|
componentTabs: "/kit tabs no top-level prop sits in: [{id,label,icon?,order?}]. \xA73 of bettercms://playbook/schema",
|
|
3008
|
+
componentKitEntry: "the bettercms://kit entry id its V2 dock UI follows, confirmed by you: import only SUGGESTS one, so check its htmlSignals and pitfalls first (kit_entry_unknown otherwise); null clears. The setup gate's dock row needs one",
|
|
3008
3009
|
describes: "for editors: what it is and holds; omitted: written for you",
|
|
3009
3010
|
runtimeBundle: "instead of pageId: the server-app bundle cleanup",
|
|
3010
3011
|
pageRef: "page id or path ('/de/about'); a bare slug only when one page has it",
|
|
@@ -3047,6 +3048,7 @@ var SEO_KEY_TEXT = {
|
|
|
3047
3048
|
};
|
|
3048
3049
|
var VARIANT_GROUP_NOTE = "`variantGroup`: the family of looks it belongs to, if any, and its looks.";
|
|
3049
3050
|
var DETACHED_COPY_NOTE = "{overrides?}: a rich-text embed's separate-copy `fields` (playbook \xA75)";
|
|
3051
|
+
var KIT_ENTRY_REBUILD_NOTE = "Setting or changing `kitEntry` rebuilds that entry's ui on every prop whose ui the server derived (ui a person or an agent set is kept); `kitUiApplied` lists the props it changed.";
|
|
3050
3052
|
var UNPROPPED_COPY_NOTE = "A `warnings` entry UNPROPPED_COPY names copy no prop targets, which nobody can edit: add a prop with a `target` for each leaf it lists.";
|
|
3051
3053
|
var UPDATE_PAGE_IF_MATCH_NOTE = "get_page's `optimisticVersion`: the write applies only at that version, and a 409 means the page changed since, so read it again. Send it whenever you pass blockJson, which REPLACES the whole composition.";
|
|
3052
3054
|
var SLOT_MULTIPLE_NOTE = "'slot' with config.multiple holds a list [{componentId, overrides?}] (config.maxItems, default 12, at most 50): target.path 'props.children' on a section. V2 slots, 'table' mode 'types': playbook \xA75.";
|
|
@@ -4090,7 +4092,7 @@ function buildToolDefs(deps) {
|
|
|
4090
4092
|
"conversion"
|
|
4091
4093
|
]);
|
|
4092
4094
|
const sectionType = z.string().min(1).max(64).describe(
|
|
4093
|
-
"section family, e.g. 'Hero'
|
|
4095
|
+
"section family: what KIND of section this is, e.g. 'Hero', 'Logo cloud', 'Pricing', 'FAQ' (never its heading's words: a section's title is its own heading, shown as written). Set this with a library category to make the component selectable in the page editor's 'Add a section' picker. Components sharing one are layout variants of one section."
|
|
4094
4096
|
);
|
|
4095
4097
|
const allowedOn = z.array(z.string().regex(/^(\*|slug:[a-z0-9-]+|type:(singleton|dynamic|template))$/)).max(100).describe("placement allowlist: *, slug:<page-slug>, and/or type:singleton|dynamic|template");
|
|
4096
4098
|
const componentPreviewArg = z.strictObject({
|
|
@@ -4114,6 +4116,7 @@ function buildToolDefs(deps) {
|
|
|
4114
4116
|
preview: componentPreviewArg.optional(),
|
|
4115
4117
|
icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),
|
|
4116
4118
|
tabs: z.array(z.object({ id: z.string(), label: z.string(), icon: z.string().optional(), order: z.number().int().optional() })).nullable().optional().describe(PARAM_TEXT.componentTabs),
|
|
4119
|
+
kitEntry: z.string().min(1).max(100).nullable().optional().describe(PARAM_TEXT.componentKitEntry),
|
|
4117
4120
|
blockJson: z.array(blockObject).default([]).describe("the component's block tree"),
|
|
4118
4121
|
props: z.array(componentPropObject).default([]).describe(
|
|
4119
4122
|
"overridable fields. DECLARE A PROP \u2014 WITH A `target` \u2014 for every string, link and image a marketer will ever touch: only the leaves a prop targets are click-to-edit. Each one may carry `ui` to say how its control presents in the inspector \u2014 a collapsed group, what titles and thumbnails a table's rows, whether that table's rows can be dragged at all. 'button' is ONE unit {label, href, variant?, size?, arrow?, icon?, newTab?} on a button block's 'props', never a text prop plus a url prop. 'link' an href, 'date' YYYY-MM-DD, 'color' a hex, 'file' {url, name?}, 'icon' an icon name or an image, 'multiselect' a string[] from config.options (required). " + SLOT_MULTIPLE_NOTE + " " + PROP_V2_NOTE
|
|
@@ -4132,6 +4135,7 @@ function buildToolDefs(deps) {
|
|
|
4132
4135
|
description: z.string().optional(),
|
|
4133
4136
|
preview: componentPreviewArg.optional(),
|
|
4134
4137
|
icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),
|
|
4138
|
+
kitEntry: z.string().min(1).max(100).nullable().optional().describe(PARAM_TEXT.componentKitEntry),
|
|
4135
4139
|
blockJson: z.array(blockObject).optional().describe("REPLACES the block tree"),
|
|
4136
4140
|
props: z.array(componentPropObject).optional().describe(
|
|
4137
4141
|
"REPLACES the prop array \u2014 include every prop you want to keep, WITH its stored `ui`, or that prop's authoring chrome is dropped along with the prop. Read get_component first."
|
|
@@ -6252,10 +6256,12 @@ ${lines.join("\n")}`, found);
|
|
|
6252
6256
|
},
|
|
6253
6257
|
handler: guard(
|
|
6254
6258
|
async (args) => withClient(async (client) => {
|
|
6255
|
-
const
|
|
6259
|
+
const res = await client.extractComponent(args);
|
|
6260
|
+
const { component, replaced } = res;
|
|
6261
|
+
const kit = res.kit;
|
|
6256
6262
|
return ok(
|
|
6257
|
-
`Created component '${component.name}' (id ${component.id}) and repointed ${replaced} sections to it. Page drafts changed; publish those pages to make it live
|
|
6258
|
-
{ ...component, nextAction: DOCK_UI_NEXT }
|
|
6263
|
+
`Created component '${component.name}' (id ${component.id}) and repointed ${replaced} sections to it. Page drafts changed; publish those pages to make it live.${kit?.line ? ` ${kit.line}: only a suggestion, so check its htmlSignals and pitfalls, then confirm or replace it with update_component { kitEntry }.` : ""}`,
|
|
6264
|
+
{ ...component, ...kit ? { kit } : {}, nextAction: DOCK_UI_NEXT }
|
|
6259
6265
|
);
|
|
6260
6266
|
})
|
|
6261
6267
|
)
|
|
@@ -6264,18 +6270,20 @@ ${lines.join("\n")}`, found);
|
|
|
6264
6270
|
name: "update_component",
|
|
6265
6271
|
config: {
|
|
6266
6272
|
title: "Update a reusable component",
|
|
6267
|
-
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. " + UNPROPPED_COPY_NOTE,
|
|
6273
|
+
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. " + KIT_ENTRY_REBUILD_NOTE + " " + UNPROPPED_COPY_NOTE,
|
|
6268
6274
|
inputSchema: updateComponentInput.shape
|
|
6269
6275
|
},
|
|
6270
6276
|
handler: guard(
|
|
6271
6277
|
async (args) => withClient(async (client) => {
|
|
6272
6278
|
const { componentId, ifMatch, confirmed, ...input } = args;
|
|
6273
|
-
const
|
|
6279
|
+
const res = confirmed === true || typeof input.kitEntry === "string" ? await client.fetchJSON(client.url(`/management/components/${componentId}`), {
|
|
6274
6280
|
method: "PATCH",
|
|
6275
6281
|
body: JSON.stringify(input),
|
|
6276
|
-
headers: { ...ifMatch !== void 0 ? { "If-Match": `W/"${ifMatch}"` } : {}, ...confirmedHeaders(
|
|
6277
|
-
})
|
|
6278
|
-
|
|
6282
|
+
headers: { ...ifMatch !== void 0 ? { "If-Match": `W/"${ifMatch}"` } : {}, ...confirmedHeaders(confirmed) }
|
|
6283
|
+
}) : { data: await client.updateComponent(componentId, input, { ifMatch }), kitUiApplied: void 0 };
|
|
6284
|
+
const cmp = res.data;
|
|
6285
|
+
const rebuilt = res.kitUiApplied ? ` kitEntry set: rebuilt the derived ui of ${res.kitUiApplied.length} prop(s)${res.kitUiApplied.length ? ` (${res.kitUiApplied.join(", ")})` : ""}.` : "";
|
|
6286
|
+
return ok(`Updated component '${cmp.name}' (id ${cmp.id}).${rebuilt}`, res.kitUiApplied ? { ...cmp, kitUiApplied: res.kitUiApplied } : cmp);
|
|
6279
6287
|
})
|
|
6280
6288
|
)
|
|
6281
6289
|
},
|
|
@@ -6516,6 +6524,12 @@ DERIVED by \`editor_setup\`, where the componentize lane in \xA710 reuses every
|
|
|
6516
6524
|
mcp notes and avoid its pitfalls (tag rules below).
|
|
6517
6525
|
Its props carry NO target: give each one a target
|
|
6518
6526
|
into YOUR blockJson (\xA73) before create_component
|
|
6527
|
+
Every component names its kitEntry
|
|
6528
|
+
(bettercms://kit/entry/{id}). The import's entry
|
|
6529
|
+
is only a SUGGESTION: check its htmlSignals and
|
|
6530
|
+
pitfalls, confirm or replace it (update_component
|
|
6531
|
+
kitEntry rebuilds the derived ui); exempt with
|
|
6532
|
+
no-kit-match only with a note
|
|
6519
6533
|
Repeated visual region on a page? -> a COMPONENT with sectionType (a Section)
|
|
6520
6534
|
...and it comes in more than one look? -> siblings sharing that sectionType = VARIANTS
|
|
6521
6535
|
A stack of mixed, reorderable content? -> kind:'block' models + a \`modular\` field
|
|
@@ -7428,9 +7442,9 @@ delivered value \u2014 they change editor chrome only.
|
|
|
7428
7442
|
"fields": [ { "key": "author", ... }, { "key": "avatar", "type": "image", ... }, ... ] }
|
|
7429
7443
|
\`\`\`
|
|
7430
7444
|
|
|
7431
|
-
- **\`helpText\`** \u2014 the exception: most fields
|
|
7445
|
+
- **\`helpText\`** \u2014 the exception: most fields get none. Write it only when the author needs it to
|
|
7432
7446
|
type the right value: a format or unit ("Price in cents."), a placement the canvas cannot show, a
|
|
7433
|
-
real constraint, a fallback. Never restate the label ("The title field"), never coach ("Keep it short").
|
|
7447
|
+
real constraint, a fallback. One plain sentence under 90 characters, no semicolons, no dashes, no values copied from the page. Never restate the label ("The title field"), never coach ("Keep it short").
|
|
7434
7448
|
- **\`showIf\`** \u2014 hide a field until another has a value:
|
|
7435
7449
|
\`{match:'all',rules:[{field:'link_type',op:'eq',value:'external'}]}\`. Rules name fields by
|
|
7436
7450
|
BARE KEY, and the key namespace is FLAT across the model (\xA7 the duplicate-key rule), so the
|
|
@@ -7584,7 +7598,7 @@ An unknown \`openMode\` is refused with \`openMode_invalid\`, one on a leaf \`op
|
|
|
7584
7598
|
schema: the same call with \`pageId\` instead of \`modelId\`, and the version from \`get_page\`'s
|
|
7585
7599
|
\`backingModel\`.
|
|
7586
7600
|
- A component's props: \`update_component\` with \`propUi\`, \`propGroup\`, \`propTab\`, \`propLabel\`, \`propHelpText\` (keyed by prop key).
|
|
7587
|
-
Name props from the code (\`plan.cents\` \u2192 Cents); help text
|
|
7601
|
+
Name props from the code (\`plan.cents\` \u2192 Cents); help text only where a format, a hidden placement, a constraint or a fallback needs it ("Whole number, no currency symbol."), one plain sentence under 90 characters with no semicolons or dashes, never repeating
|
|
7588
7602
|
the value; repeated cards are one \`table\` prop. An icon (\`config.media: "icon"\`) is content: group it, never prune it.
|
|
7589
7603
|
They write the DRAFT props; no publish is needed for the editor to show them.
|
|
7590
7604
|
- Always send \`ifMatch\`, the \`optimisticVersion\` you read.
|