@bettercms-ai/mcp 0.74.0 → 0.75.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 +29 -7
- package/dist/index.js.map +1 -1
- package/dist/kit-catalog.json +53 -53
- package/dist/skills/bettercms/SKILL.md +7 -2
- package/dist/skills/bettercms/references/componentize.md +3 -0
- package/dist/skills/bettercms/references/finish-site.md +5 -1
- package/dist/skills/bettercms/references/getting-started.md +2 -0
- package/dist/skills/bettercms/references/kit-catalog.md +53 -53
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2936,6 +2936,19 @@ function listsTool(name, sets) {
|
|
|
2936
2936
|
if (ABM_TOOLS.has(name)) return sets.has("abm");
|
|
2937
2937
|
return !sets.has("core") || !LISTING_TAIL.has(name);
|
|
2938
2938
|
}
|
|
2939
|
+
var ALWAYS_LOADED = /* @__PURE__ */ new Set([
|
|
2940
|
+
"get_next_steps",
|
|
2941
|
+
"editor_setup",
|
|
2942
|
+
"get_deploy_status",
|
|
2943
|
+
"get_conversion_brief",
|
|
2944
|
+
"get_binding_report",
|
|
2945
|
+
"list_projects",
|
|
2946
|
+
"list_pages",
|
|
2947
|
+
"get_page",
|
|
2948
|
+
"list_content_models"
|
|
2949
|
+
]);
|
|
2950
|
+
var toolMeta = (name) => ALWAYS_LOADED.has(name) ? { "anthropic/alwaysLoad": true } : void 0;
|
|
2951
|
+
var TOOL_LOADING_INSTRUCTION = `TOOL SCHEMAS: a client with tool search lists most BetterCMS tools by name only. Before the first call to a tool whose schema you have not been shown, load it with the client's tool search, and load every tool the task needs in ONE search (for a renaming pass: update_field, update_content_model, update_component, list_components). A call made without the schema is refused by the client before it reaches BetterCMS ("Invalid tool parameters"): that is this, never a BetterCMS error, and never a reason to change the arguments.`;
|
|
2939
2952
|
|
|
2940
2953
|
// src/tool-text.ts
|
|
2941
2954
|
var ADD_FIELD_DESCRIPTION = "Append ONE field to a content model (`modelId`) or to a page's schema (`pageId`) \u2014 additive, never overwrites; a key already in use is refused. For a section/zone add ONE 'group' (fixed block) or 'repeater' (repeating list) carrying its child `fields`, not the zone's inner fields as separate top-level fields. Pass `after` to insert it after an existing top-level field instead of at the end; `ui`, `helpText`, `showIf`, `placement` and `fieldsetId` declare how it presents in the editor \u2014 read them back with get_content_model or get_page. On a page a 'group' is stored as type 'array' with `config.zones.nonRepeatable`: entry and delivery data carry `<key>.nonRepeatable.<sub>`, while data-bcms-field paths are `<key>.<sub>`. Schema only \u2014 never places a section; use componentize_sections to turn a group into a section. `multiselect` stores a string[] of `config.options`; `icon` is a BetterCMS icon name or an uploaded icon. To change a field that exists, use update_field. V2 keys (object, openMode, advanced, helpMore, recommendedMax, config.scale): \xA714 of bettercms://playbook/schema.";
|
|
@@ -2991,6 +3004,7 @@ var PARAM_TEXT = {
|
|
|
2991
3004
|
fromBuiltin: "a builtin:* id from list_components: copies it into the project; fields you send win",
|
|
2992
3005
|
componentPreview: "a slot row's look: {title?, subtitle?, media?} TOP-LEVEL prop keys, fallback?, icon?; null clears. \xA73 of bettercms://playbook/schema",
|
|
2993
3006
|
componentIcon: "the block icon, a dock icon name; null clears. \xA73 of bettercms://playbook/schema",
|
|
3007
|
+
componentTabs: "/kit tabs no top-level prop sits in: [{id,label,icon?,order?}]. \xA73 of bettercms://playbook/schema",
|
|
2994
3008
|
describes: "for editors: what it is and holds; omitted: written for you",
|
|
2995
3009
|
runtimeBundle: "instead of pageId: the server-app bundle cleanup",
|
|
2996
3010
|
pageRef: "page id or path ('/de/about'); a bare slug only when one page has it",
|
|
@@ -3565,6 +3579,7 @@ function publishedLines(outcome, summary) {
|
|
|
3565
3579
|
if (outcome.status !== "live") return [`${summary} Publish status: ${outcome.status}.`];
|
|
3566
3580
|
return [`${summary} Published: ${outcome.live > 0 ? `${outcome.live} ${outcome.live === 1 ? "value" : "values"} live on the served page` : "live"}.`];
|
|
3567
3581
|
}
|
|
3582
|
+
var DOCK_UI_NEXT = "Give every prop of this component its V2 ui (control, tab, group, collapsed, layout, preview, itemLabel, icon) by playbook \xA714 and the closest bettercms://kit entry: get_component, then ONE update_component with propUi, propTab and propHelpText (the field-ui prompt). The setup gate's dock row stays open until it is done.";
|
|
3568
3583
|
function ok(summary, data) {
|
|
3569
3584
|
return {
|
|
3570
3585
|
content: [
|
|
@@ -4098,6 +4113,7 @@ function buildToolDefs(deps) {
|
|
|
4098
4113
|
description: z.string().optional().describe(PARAM_TEXT.describes),
|
|
4099
4114
|
preview: componentPreviewArg.optional(),
|
|
4100
4115
|
icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),
|
|
4116
|
+
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),
|
|
4101
4117
|
blockJson: z.array(blockObject).default([]).describe("the component's block tree"),
|
|
4102
4118
|
props: z.array(componentPropObject).default([]).describe(
|
|
4103
4119
|
"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
|
|
@@ -6239,7 +6255,7 @@ ${lines.join("\n")}`, found);
|
|
|
6239
6255
|
const { component, replaced } = await client.extractComponent(args);
|
|
6240
6256
|
return ok(
|
|
6241
6257
|
`Created component '${component.name}' (id ${component.id}) and repointed ${replaced} sections to it. Page drafts changed; publish those pages to make it live.`,
|
|
6242
|
-
component
|
|
6258
|
+
{ ...component, nextAction: DOCK_UI_NEXT }
|
|
6243
6259
|
);
|
|
6244
6260
|
})
|
|
6245
6261
|
)
|
|
@@ -6466,7 +6482,8 @@ function registerTools(server, deps, tools = process.env.BETTERCMS_MCP_TOOLS) {
|
|
|
6466
6482
|
};
|
|
6467
6483
|
const sets = toolsetsOf(tools);
|
|
6468
6484
|
for (const def of buildToolDefs(withElicit).filter((d) => listsTool(d.name, sets))) {
|
|
6469
|
-
|
|
6485
|
+
const _meta = toolMeta(def.name);
|
|
6486
|
+
server.registerTool(def.name, _meta ? { ...def.config, _meta } : def.config, def.handler);
|
|
6470
6487
|
}
|
|
6471
6488
|
}
|
|
6472
6489
|
|
|
@@ -6579,8 +6596,9 @@ dashboard's prop editor renders. \`helpText\` is three-state: a string is yours,
|
|
|
6579
6596
|
purpose (send it for a prop whose /kit schema has no description; nothing refills it), and omitted
|
|
6580
6597
|
lets the platform write one. They are HINTS: nothing on the write path refuses a placement
|
|
6581
6598
|
that leaves a required prop empty, so \`get_site_composition\` is what reports one.
|
|
6582
|
-
A /kit schema's document-level \`preview\` \u2192 the component's \`preview\`: how ONE instance reads as a ROW in a parent's slot list. {title?, subtitle?, media?} each name a TOP-LEVEL prop key (422 \`preview_key_unknown\` otherwise), \`fallback?\` is a literal row label (\u2264 120) and \`icon?\` a dock icon name; null clears it.
|
|
6599
|
+
A /kit schema's document-level \`preview\` \u2192 the component's \`preview\`: how ONE instance reads as a ROW in a parent's slot list. {title?, subtitle?, media?} each name a TOP-LEVEL prop key or a dotted path into one (\`slides.0.heading\`; 422 \`preview_key_unknown\` otherwise), \`fallback?\` is a literal row label (\u2264 120) and \`icon?\` a dock icon name; null clears it.
|
|
6583
6600
|
A /kit schema's document-level \`icon\` \u2192 the component's \`icon\` (a dock icon name from bettercms://icons/dock, null clears): the block icon on the root crumb, slot rows and slot child frames.
|
|
6601
|
+
A /kit schema's \`groups\` \u2192 each prop's \`ui.tab\` (defined on the first top-level prop in it; a nested field's \`group\` \u2192 its \`ui.tab: {id}\`); a group NO top-level prop sits in \u2192 the component's \`tabs\` ([{id, label, icon?, order?}], 422 \`component_tab_invalid\` for a prop's own tab). A slot's \`of.allow\` \u2192 \`config.allow\` (block names); a scalar list's item settings (\`of[0]\` validation, description, localized) \u2192 \`config.item\`.
|
|
6584
6602
|
|
|
6585
6603
|
**Prop types, one rule each.** 'select' REQUIRES \`config.options\` (a default must be one of them). 'group'/'table'/'object' REQUIRE \`config.fields\` (\`[{key,label,type,options?,fields?}]\`); a group writes an object, a table an array of them (\`config.mode: 'data'\`: ONE V2 table value, no fields). 'number' takes optional \`config.min/max/step\`. 'slot' holds ONE nested component instance: \`target.path: 'props'\` on an EMPTY component block (\`props.componentId: ""\`), \`config.componentIds\` restricts fills, defaultValue \`{componentId, overrides?}\`. 'form' holds ONE Form document: \`target.path: 'props'\` on an EMPTY form block (\`props.formId: ""\`), defaultValue \`{formId}\`, never the hydrated \`{formId, form}\` (400); do NOT re-declare the form's FIELDS as props, the Form document owns them. '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).
|
|
6586
6604
|
|
|
@@ -7652,6 +7670,7 @@ disagrees with the array the moment anyone drags a row in the builder.
|
|
|
7652
7670
|
// src/prompts.ts
|
|
7653
7671
|
var STRUCTURE_RULE = `### Page structure (non-negotiable)
|
|
7654
7672
|
${SECTION_DOCTRINE}`;
|
|
7673
|
+
var DOCK_UI_STEP = "EDITOR CHROME: for every component, run the field-ui lane (the `field-ui` prompt, playbook \xA714): `get_component`, then one `update_component` with `propUi`, `propTab` and `propHelpText` giving each prop its V2 ui (control, tab, group, collapsed, layout, preview, itemLabel, icon) after the closest `bettercms://kit` entry. The gate's `dock` row stays open until each has it, or a true `default-controls` exception.";
|
|
7655
7674
|
var CONVERT_SITE_TEXT = (projectId) => `Convert my site so every visible element is editable in BetterCMS${projectId ? `, project ${projectId}` : ""}.
|
|
7656
7675
|
Do not stop at the plan or at a partial receipt \u2014 finish the whole site, never editing a class or style.
|
|
7657
7676
|
|
|
@@ -7682,8 +7701,8 @@ Do not stop at the plan or at a partial receipt \u2014 finish the whole site, ne
|
|
|
7682
7701
|
do the same with \`npx @bettercms-ai/convert@latest --upgrade-element-styles --root . --dry-run\`. Run \`--verify-styles\` again
|
|
7683
7702
|
and restore what it lists (the marker, and the inline style from \`block.style\` or \`fieldAttrs\`, are allowed; changing a class
|
|
7684
7703
|
or an existing style is not). Deploy, poll, call \`get_next_steps\` again and run \`receipt.gate.nextAction\` until \`receipt.complete\` is true; what else it lists, tell me by name. Not listed: say so; invent no work. Its \`receipt.gate\` fails a route on \`sections\` or \`style\` while I could not add a section to that page, reorder it or space it: run each such row's \`fix\` too. A write that answers \`held\`, or a publish whose \`outcome\` is \`partial\`, is not done until its action is taken.
|
|
7685
|
-
11.
|
|
7686
|
-
|
|
7704
|
+
11. ${DOCK_UI_STEP}
|
|
7705
|
+
12. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the next rebuild from my repo drops it). Touch git only as I answer.`;
|
|
7687
7706
|
var FIELD_UI_PROMPT = {
|
|
7688
7707
|
title: "Declare how fields LOOK in the editor (guided)",
|
|
7689
7708
|
description: "Set the editor chrome of an existing schema and its component props: groups, tabs, rows, icons, item names, what titles and thumbnails a list's rows, help text, conditional visibility. Derives it from your source, then from the field shapes, and asks only what it cannot know.",
|
|
@@ -8115,6 +8134,8 @@ ${COMPONENTIZE_SITE_FLOW}
|
|
|
8115
8134
|
|
|
8116
8135
|
${STRUCTURE_RULE}
|
|
8117
8136
|
|
|
8137
|
+
Last, before the summary: ${DOCK_UI_STEP}
|
|
8138
|
+
|
|
8118
8139
|
Confirm the component library with the user before creating it. End with the summary \xA712 asks
|
|
8119
8140
|
for: the group hierarchy, each family and its variants, what you left in the site's code because
|
|
8120
8141
|
the platform does not model it, and which components are still waiting for the owner's approval
|
|
@@ -8253,7 +8274,8 @@ Read bettercms://playbook/schema section 11 first, then work this order:
|
|
|
8253
8274
|
4. PRESENTATION MANIFEST \u2014 add bcms-presentation.json to public/ (container width, type
|
|
8254
8275
|
scale, nav position/background, footer surface as DTCG {"$type","$value"} entries) and
|
|
8255
8276
|
redeploy, or structural draft previews render in a generic theme, not this site's design.
|
|
8256
|
-
5.
|
|
8277
|
+
5. ${DOCK_UI_STEP}
|
|
8278
|
+
6. VERIFY \u2014 call get_next_steps and fix what it lists (it knows about missing manifests,
|
|
8257
8279
|
a setup that has not run, and placed-but-unpublished components). You are finished only
|
|
8258
8280
|
when its receipt.complete is true: run receipt.gate.nextAction, read it again after each
|
|
8259
8281
|
batch, and record an item you cannot close with editor_setup { exempt } only under an allowed
|
|
@@ -8451,7 +8473,7 @@ function buildServer(deps) {
|
|
|
8451
8473
|
// 🔴 The plain-language ask, routed — the stdio twin of the hosted connector's line
|
|
8452
8474
|
// (src/routes/mcp/index.ts MCP_INSTRUCTIONS). "Make my site editable" has one recipe and
|
|
8453
8475
|
// one definition of done; without this an agent converts the page it landed on and stops.
|
|
8454
|
-
instructions: RECEIPT_FIRST_INSTRUCTION + " When the user asks to make a site or all of its pages editable, to convert it, or to bind its fields: this is playbook \xA713. Read `bettercms://playbook/schema` \xA713, call get_binding_report and get_conversion_brief { complete: true }, convert EVERY route the brief lists, and finish only when get_binding_report shows coverage.pending empty on every route \u2014 not when the first page works. On a workspace-wide connection pass projectId on every call; never ask the user to re-scope the connection. " + LAYOUT_CHROME_INSTRUCTION + " " + CTA_BUTTON_INSTRUCTION + " When the user asks to componentize the whole site, to turn every section into a component, or to build a component library from the site: this is playbook \xA712. Read `bettercms://playbook/schema` \xA712, start with get_site_composition, and use the batch tools \u2014 componentize_sections, compose_pages, update_layout with `commands`, publish_components \u2014 rather than one call per component. Finish with get_site_composition and tell the user what the platform does not model (cookie banners, modals, breadcrumbs, pagination) and which components still need the owner's approval in the dashboard before they can be published. " + // The default after authoring (the structure standard): organise what you made. Same
|
|
8476
|
+
instructions: TOOL_LOADING_INSTRUCTION + " " + RECEIPT_FIRST_INSTRUCTION + " When the user asks to make a site or all of its pages editable, to convert it, or to bind its fields: this is playbook \xA713. Read `bettercms://playbook/schema` \xA713, call get_binding_report and get_conversion_brief { complete: true }, convert EVERY route the brief lists, and finish only when get_binding_report shows coverage.pending empty on every route \u2014 not when the first page works. On a workspace-wide connection pass projectId on every call; never ask the user to re-scope the connection. " + LAYOUT_CHROME_INSTRUCTION + " " + CTA_BUTTON_INSTRUCTION + " When the user asks to componentize the whole site, to turn every section into a component, or to build a component library from the site: this is playbook \xA712. Read `bettercms://playbook/schema` \xA712, start with get_site_composition, and use the batch tools \u2014 componentize_sections, compose_pages, update_layout with `commands`, publish_components \u2014 rather than one call per component. Finish with get_site_composition and tell the user what the platform does not model (cookie banners, modals, breadcrumbs, pagination) and which components still need the owner's approval in the dashboard before they can be published. " + // The default after authoring (the structure standard): organise what you made. Same
|
|
8455
8477
|
// sentence as the hosted connector's MCP_INSTRUCTIONS.
|
|
8456
8478
|
STRUCTURE_DEFAULT_INSTRUCTION + " " + SKILLS_ROUTING_INSTRUCTION + " " + DOCK_UI_ROUTING_INSTRUCTION + " " + PUBLISH_HOLD_INSTRUCTION
|
|
8457
8479
|
}
|