@bettercms-ai/mcp 0.28.0 → 0.29.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 +32 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3025,6 +3025,24 @@ function buildToolDefs(deps) {
|
|
|
3025
3025
|
z.object({}).shape,
|
|
3026
3026
|
async (c) => ok("Approved conversion plan.", await data(c, "GET", `/management/projects/current/conversion-plan`))
|
|
3027
3027
|
),
|
|
3028
|
+
def(
|
|
3029
|
+
"get_componentize_plan",
|
|
3030
|
+
"Get the plan for turning this site's sections into components",
|
|
3031
|
+
"What this site's SECTIONS would become as components \u2014 a proposal that creates nothing, changes nothing and is computed live on every call. For a site whose pages were DERIVED at import (the site get_conversion_brief describes), each top-level field GROUP is one section: `hero-*` and `faq-*` keys, and the repeaters the import already folded (`group-*`). Per page it returns each section's `groupKey`, its `sectionType` family (Hero, FAQ, CTA, Features, Social proof\u2026), its leaf `fields` (key, path, type, the value the CMS holds), a `shapeHash`, and either the component that already renders it (`reuse.componentId`) or the one this plan proposes (`reuse.proposedSlug`) \u2014 and the components themselves under `components`: a NEW one carries the exact `props` and `blockJson` create_component would take, while a row for a component that ALREADY EXISTS carries its `componentId`, `slug` and `name` and no definition, because nothing will be written for it. Groups with the SAME shape across pages collapse into ONE component with several placements. `pending` says why a group is not offered: `NO_GROUP_ROOT` (the page's field keys are still the derive lane's own \u2014 `h1-welcome`, `p-we-build-things` \u2014 so there is no family to group by; rename them into families first), `NOT_A_SECTION` (a lone scalar with no family, or the page's own metadata \u2014 a section is a group field, a repeater, or a family two or more leaves share, so a legal page of `title`/`metaDescription`/`intro` proposes nothing), `ALREADY_COMPONENTIZED`, `EMPTY_GROUP`, `NESTED_REPEATER` (a repeater inside a repeater \u2014 one prop cannot describe two levels of rows), `PAGE_NOT_EMPTY` (the page holds blocks this lane does not own and will not overwrite). Chrome is NEVER a section: `nav-`/`footer-` keys and everything promoted into the project Layout are edited through the Layout. Keep the `digest` \u2014 componentize_sections refuses any other.",
|
|
3032
|
+
z.object({}).shape,
|
|
3033
|
+
async (c) => ok("Componentize plan.", await data(c, "GET", `/management/projects/current/componentize-plan`))
|
|
3034
|
+
),
|
|
3035
|
+
def(
|
|
3036
|
+
"componentize_sections",
|
|
3037
|
+
"Turn this site's derived sections into components",
|
|
3038
|
+
"Turn this site's derived sections into components. CONFIRM WITH THE USER FIRST: show them get_componentize_plan's sections and say how many components it will create and which pages it will rewrite. It creates each proposed component as a DRAFT (its `sectionType` family, category 'section', placeable on any page) and replaces each page's DRAFT blocks with an ordered list of `component` instances \u2014 one per group, each carrying `props.bind: \"<groupKey>\"`, which points at the page field group that already holds the copy. So nothing is copied and nothing moves: the page keeps its `fields`, its values and its bindings, click-to-edit keeps working and the coverage meter does not change. Pass the plan's `digest`; a 409 `stale-plan` means the site changed since you read that plan, so read it again, show the user what changed and confirm again. Call it with `dryRun: true` first \u2014 same receipt, nothing written. Running it twice is safe: a group that already has a placement comes back in `sections.pending` as ALREADY_COMPONENTIZED and no second component is created. DRAFTS ONLY \u2014 an unpublished component renders as an EMPTY STRING on the live site, so publish_component each one and publish the pages before this reaches a visitor. Then run `npx @bettercms-ai/convert --componentize` in the repo so its templates render these sections from `pages[].blocks`.",
|
|
3039
|
+
z.object({
|
|
3040
|
+
digest: z.string().min(1).describe("The `digest` get_componentize_plan returned. A different one is refused with 409 stale-plan."),
|
|
3041
|
+
pageIds: z.array(z.string().min(1)).optional().describe("Componentize only these pages (ids from the plan). Omit for every page the plan lists."),
|
|
3042
|
+
dryRun: z.boolean().optional().describe("true = return the receipt without writing anything. Do this first.")
|
|
3043
|
+
}).shape,
|
|
3044
|
+
async (c, a) => ok("Componentized the sections.", await data(c, "POST", `/management/projects/current/componentize`, { digest: a.digest, pageIds: a.pageIds, dryRun: a.dryRun }))
|
|
3045
|
+
),
|
|
3028
3046
|
def(
|
|
3029
3047
|
"get_analytics_overview",
|
|
3030
3048
|
"Get traffic overview",
|
|
@@ -3809,6 +3827,20 @@ sibling calls it \`headline\` silently drops that content on the swap.
|
|
|
3809
3827
|
Pair \`sectionType\` with a library \`category\` (hero, content, social-proof, conversion) or
|
|
3810
3828
|
the component never appears in the editor's "Add a section" picker.
|
|
3811
3829
|
|
|
3830
|
+
**An IMPORTED site gets there without you writing any of that.** Its pages were derived at
|
|
3831
|
+
import \u2014 flat field groups (\`hero-title\`, \`faq-question\`, the repeaters folded as \`group-*\`)
|
|
3832
|
+
and an empty \`blockJson\` \u2014 so there is nothing in the picker and no section to swap. Read
|
|
3833
|
+
\`get_componentize_plan\`: it groups those fields into sections, names each family, and proposes
|
|
3834
|
+
one component per SHAPE (the same hero on two pages is one component with two placements),
|
|
3835
|
+
with every string, link and image already declared as a prop. Show the user the plan and
|
|
3836
|
+
**confirm before writing**, then \`componentize_sections { digest, dryRun: true }\` and, once the
|
|
3837
|
+
receipt reads right, without \`dryRun\`. Each page's blocks become ordered \`component\`
|
|
3838
|
+
instances carrying \`props.bind\` \u2014 the field group keeps the copy, so nothing moves and
|
|
3839
|
+
click-to-edit keeps working. Then run \`npx @bettercms-ai/convert --componentize\` in the repo
|
|
3840
|
+
so its templates render those sections from \`pages[].blocks\`, and finish with the publishes:
|
|
3841
|
+
\`publish_component\` every new component and publish the pages, or the site renders the
|
|
3842
|
+
sections as empty strings.
|
|
3843
|
+
|
|
3812
3844
|
## 5. Blocks and modular fields
|
|
3813
3845
|
|
|
3814
3846
|
A \`kind:'block'\` model holds no entries of its own; it exists to be stacked inside another
|