@bettercms-ai/mcp 0.31.0 → 0.32.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/README.md CHANGED
File without changes
package/dist/index.js CHANGED
@@ -2965,7 +2965,7 @@ function buildToolDefs(deps) {
2965
2965
  def(
2966
2966
  "deploy_project",
2967
2967
  "Deploy new source/build",
2968
- "Deploy new source/build for the connected project and make it live at its <handle>.bettercms.site. Pass a .tgz or .zip of the project as a base64 string in `data`: SOURCE (has package.json) is built server-side in an isolated sandbox; a prebuilt static site is served as-is. Returns the release id + sha \u2014 then poll get_deploy_status until it is live. IMPORTANT \u2014 you MUST exclude node_modules, .git, and build output/caches (dist, build, .next, .astro, .cache) BEFORE creating the archive: a source deploy is reinstalled and built server-side, so those are never needed, and the upload has a hard size ceiling (~100 MB) enforced before the request reaches the server \u2014 an archive that includes node_modules is rejected in transit (a 413/502 with no server-side detail). Keep the archive to your own source files. Server-side stripping exists as a safety net, but it runs AFTER the upload and cannot rescue an over-limit body. For a LARGE archive (or if this returns a 413/502), use create_deploy_upload + deploy_from_upload instead \u2014 that path uploads straight to storage with no size ceiling.",
2968
+ "Deploy new source/build for the connected project and make it live at its <handle>.bettercms.site. Pass a .tgz or .zip of the project as a base64 string in `data`: SOURCE (has package.json) is built server-side in an isolated sandbox; a prebuilt static site is served as-is. Returns the release id + sha \u2014 then poll get_deploy_status until it is live. IMPORTANT \u2014 you MUST exclude node_modules, .git, and build output/caches (dist, build, .next, .astro, .cache) BEFORE creating the archive: a source deploy is reinstalled and built server-side, so those are never needed, and the upload has a hard size ceiling (~100 MB) enforced before the request reaches the server \u2014 an archive that includes node_modules is rejected in transit (a 413/502 with no server-side detail). Keep the archive to your own source files. Server-side stripping exists as a safety net, but it runs AFTER the upload and cannot rescue an over-limit body. For a LARGE archive (or if this returns a 413/502), use create_deploy_upload + deploy_from_upload instead \u2014 that path uploads straight to storage with no size ceiling. Returns `canvas.lane` \u2014 which live-preview lane the last release gave the editor (`bridge` / `draft-route` / `none`; see the playbook's section 11) \u2014 and `editorUrl`, the visual editor to hand the user.",
2969
2969
  z.object({ data: z.string().min(1).describe("base64 .tgz/.zip of the project"), mimeType: z.string().optional() }).shape,
2970
2970
  async (c, a) => ok("Deploy queued.", await raw(c, `/management/projects/deploy`, s(a.data), a.mimeType))
2971
2971
  ),
@@ -3008,7 +3008,7 @@ function buildToolDefs(deps) {
3008
3008
  def(
3009
3009
  "get_binding_report",
3010
3010
  "Check what on the live site is editable",
3011
- "The receipt for 'is this site actually EDITABLE?'. Every release scans the built HTML for the element that renders each CMS field value; this returns what that scan found, per slot: `mode` ('text-match' = bindings guessed from rendered text, 'declared' = the template declares them), `pagesInspected`, `bound` (elements carrying a binding), and `unmatched` \u2014 per page, each path with its kind and the reason it failed (not-declared / ambiguous-text / no-element). DEPLOY FIRST: before any release there is no report and this answers pages 0, mode null, refreshRequired true. It certifies exactly one thing \u2014 that every non-empty field of every page has SOME element carrying its path. It cannot see copy that was never modelled, so diff each route's visible text against its entry values yourself before calling a page done. Pass `slot` ('current' or 'staging') to read the other tree; the default is the slot this project's releases land in.",
3011
+ "The receipt for 'is this site actually EDITABLE?'. Every release scans the built HTML for the element that renders each CMS field value; this returns what that scan found, per slot: `mode` ('text-match' = bindings guessed from rendered text, 'declared' = the template declares them), `pagesInspected`, `bound` (elements carrying a binding), and `unmatched` \u2014 per page, each path with its kind and the reason it failed (not-declared / ambiguous-text / no-element). DEPLOY FIRST: before any release there is no report and this answers pages 0, mode null, refreshRequired true. It certifies exactly one thing \u2014 that every non-empty field of every page has SOME element carrying its path. It cannot see copy that was never modelled, so diff each route's visible text against its entry values yourself before calling a page done. `builtRoutes` lists the routes the live build has HTML for (null when unknown: runtime release, >500 routes, or a report older than this field). `canvas.lane` names the live-preview lane this build gives the editor \u2014 `bridge` (the build ships BcmsDraftBridge), `draft-route` (a node runtime rendering drafts server-side) or `none`, in which case get_next_steps carries the recipe (playbook section 11); null means the report predates the field. `unaddressable` counts visible text on the live site that no field owns, as the editor's x-ray measured it against the sha now serving \u2014 the one thing `unmatched` structurally cannot see; absent means nobody has turned that control on for this build. `unaddressable` is measured PER SLOT by the editor, which frames `current`; on a promote-gated project pass slot:'current' to read it. Pass `slot` ('current' or 'staging') to read the other tree; the default is the slot this project's releases land in.",
3012
3012
  z.object({ slot: z.enum(["current", "staging"]).optional().describe("which release tree to read; defaults to the one this project deploys to") }).shape,
3013
3013
  async (c, a) => ok("Binding report.", await data(c, "GET", `/management/projects/current/binding-report${q({ slot: a.slot })}`))
3014
3014
  ),
@@ -3218,7 +3218,7 @@ function buildToolDefs(deps) {
3218
3218
  def(
3219
3219
  "get_deploy_status",
3220
3220
  "Get deploy/build status",
3221
- "Get the connected project's deploy/build status: state (idle|queued|building|failed), whether it's publishing, the live commit sha, when it went live, and any build error. Poll this after deploy_project until state is idle with your sha live.",
3221
+ "Get the connected project's deploy/build status: state (idle|queued|building|failed), whether it's publishing, the live commit sha, when it went live, and any build error. Poll this after deploy_project until state is idle with your sha live. Also returns `canvas.lane` (the editor's live-preview lane for this site: `bridge` / `draft-route` / `none`) and `editorUrl`, the visual editor to hand the user.",
3222
3222
  z.object({}).shape,
3223
3223
  async (c) => ok("Deploy status.", await data(c, "GET", `/management/projects/deploy-status`))
3224
3224
  )
@@ -3984,6 +3984,10 @@ in this order:
3984
3984
  4. list_extraction_candidates / extract_component
3985
3985
  now that blocks exist, fold any section repeated 3+ times
3986
3986
 
3987
+ Step 2 is not a formality: \`componentize_sections\` and \`create_component\` both land components
3988
+ as DRAFTS, so \`publish_component\` each one and publish the page \u2014 otherwise the canvas keeps
3989
+ painting the PUBLISHED copy and the editor reports N components unpublished.
3990
+
3987
3991
  **Answering \`fields\` is a real answer, not a deferral.** A blog, a catalogue or a directory
3988
3992
  is schema-first by design (\xA71) and should stay that way. Say so and move on.
3989
3993
 
@@ -3996,16 +4000,38 @@ the user rather than describing the choice in the abstract.
3996
4000
  A deploy makes a site LIVE. It does not make it editable \u2014 those are different states, and the
3997
4001
  gap between them is the single most common disappointment after an import.
3998
4002
 
3999
- **The canvas is the real site when it can be.** When a page's draft matches its published copy
4000
- structurally, the visual editor frames the project's OWN deployed build and paints unpublished
4001
- text over it. Structural drafts (new sections, unpublished pages, changed components) render on
4002
- the platform's own renderer instead \u2014 and that renderer previews in a GENERIC theme unless the
4003
- deploy artifact declares \`bcms-presentation.json\` at its root. Put the file in \`public/\`
4003
+ **The canvas is the real site.** A PUBLISHED page of a DEPLOYED site with DECLARED bindings
4004
+ frames the project's OWN build, with unpublished text painted over it, whether or not the draft
4005
+ has drifted from the published copy. STRUCTURAL drafts (new
4006
+ sections, reordering, a changed component definition) are the one thing that build cannot show,
4007
+ and there are four ways to see them: publish and redeploy; the editor's **Draft render** toggle,
4008
+ which swaps in the platform renderer on demand (approximate theme, one click back); live, through
4009
+ the draft bridge below (Next); or \u2014 for server-rendered sites \u2014 the node lane, coming.
4010
+
4011
+ Only FOUR states use the platform renderer by default: an UNPUBLISHED page, a page whose route
4012
+ the last build does not carry (\`get_binding_report.builtRoutes\`), a project with NO build at
4013
+ all, and a \`mode: "text-match"\` site whose draft has drifted (its elements are found by matching
4014
+ page text to stored values, so drifted text may be unclickable \u2014 declare the bindings, \xA713).
4015
+ Those are exactly where \`bcms-presentation.json\` matters \u2014 the renderer previews in a
4016
+ GENERIC theme unless the deploy artifact declares one at its root. Put the file in \`public/\`
4004
4017
  (the build lands it at the artifact root) declaring the site's presentation \u2014 container width,
4005
4018
  type scale, nav position and background, footer surface \u2014 as DTCG \`{"$type": ..., "$value": ...}\`
4006
4019
  entries. Redeclare it on every deploy; absent means "declared nothing" and previews fall back
4007
4020
  to platform defaults that will not look like this site.
4008
4021
 
4022
+ **Which live-preview lane THIS site has, and what it costs not to have one.**
4023
+ \`get_binding_report.canvas.lane\` names it: \`bridge\` (the build ships \`BcmsDraftBridge\` from
4024
+ \`@bettercms-ai/next/draft-bridge\`, so a structural draft re-renders inside the site's own
4025
+ build), \`draft-route\` (a node runtime whose app renders drafts server-side), or \`none\` \u2014 no
4026
+ lane, so every structural draft falls back to the platform renderer and its generic theme.
4027
+ \`null\` means the report predates the field; redeploy to learn. When it is \`none\`,
4028
+ \`get_next_steps\` names the recipe for this project's framework (\`canvas-lane-missing\`), and
4029
+ \xA713 step 5c has both. The same report carries \`unaddressable\`: how much VISIBLE text on the
4030
+ live site no field owns, counted against the sha now serving when an author turns the visual
4031
+ editor's **"Unbound text"** control on \u2014 \`unmatched\` cannot see it, because it only ever speaks
4032
+ about fields that already exist. Absent means nobody has turned that control on for this build,
4033
+ not that the site is clean.
4034
+
4009
4035
  **A site built in the CMS with NO deployed build has only that renderer** \u2014 live and in the
4010
4036
  editor \u2014 so the generic theme IS the site until you theme it. Theme it without a deploy:
4011
4037
  \`update_project { presentation: { "page.maxWidth": { "$type": "dimension", "$value": 1200 },
@@ -4059,13 +4085,14 @@ renders. Three consequences, each load-bearing:
4059
4085
  content. Div-built chrome outside \`<main>\` is still excluded; div-built chrome with no
4060
4086
  \`<main>\` anywhere loses that protection.
4061
4087
 
4062
- **Structural drafts can render on the real site too \u2014 the draft bridge.** Wrap your page's
4088
+ **Structural drafts can render on the real site too, LIVE \u2014 the draft bridge.** Wrap your page's
4063
4089
  blocks in \`BcmsDraftBridge\` (\`@bettercms-ai/next/draft-bridge\`) instead of calling
4064
4090
  \`BcmsBlocks\` directly: standalone it renders identically, and inside the visual editor it
4065
4091
  receives the DRAFT block tree over a same-origin postMessage handshake and re-renders it with
4066
4092
  the site's own components \u2014 so adding, removing or reordering sections previews in the site's
4067
- real design instead of the platform's approximate renderer. Sites without the bridge keep the
4068
- approximate fallback; unpublished ROUTES always fall back (a static build has no file to frame).
4093
+ real design, with no publish and no Draft render detour. A bridge that answers wins over the
4094
+ toggle. Sites without one keep Draft render's approximate fallback, and a route the build does
4095
+ not carry falls back always (a static build has no file to frame).
4069
4096
 
4070
4097
  **Hosting decides whether a canvas exists at all.** A site deployed here is framed through a
4071
4098
  same-origin proxy \u2014 that is what the canvas requires. A site hosted elsewhere (your own Vercel,
@@ -4226,6 +4253,17 @@ conversion is yours to write.
4226
4253
  and no network content step, by design. So the archive MUST SHIP its own
4227
4254
  \`bcms-content.json\` \u2014 generate it locally with a delivery key and commit it. Without
4228
4255
  one the site renders its fallbacks and the report says \`no-element\` for every path.
4256
+ 5c. **Live preview lane.** Static HTML makes a page click-to-edit; it cannot show a STRUCTURAL
4257
+ draft \u2014 a new section, a reorder, a changed component \u2014 so those fall back to the platform
4258
+ renderer's generic theme unless the build can render drafts itself. Give it a lane:
4259
+ - NEXT: wrap the page's \`BcmsBlocks\` in \`BcmsDraftBridge\` from
4260
+ \`@bettercms-ai/next/draft-bridge\` and redeploy. The bridge marks its output
4261
+ \`data-bcms-canvas="bridge"\`, which is what the release scan records.
4262
+ - ASTRO: switch the pages to \`output: 'server'\` with the node adapter, mount
4263
+ \`@bettercms-ai/astro\`'s draft routes under \`src/pages/api/bcms/draft/\`, set
4264
+ \`BCMS_DRAFT_SECRET\`, redeploy, then switch the project to "Run as a server app" on the
4265
+ Hosting page. Never migrate a static site to SSR without asking the human first.
4266
+ Then \`get_binding_report.canvas.lane\` reads \`bridge\` or \`draft-route\` instead of \`none\`.
4229
4267
  6. Push, or \`deploy_project\`; poll \`get_deploy_status\` until it is live. Then
4230
4268
  \`get_binding_report\` \u2014 still \`text-match\`, and \`unmatched\` should be EMPTY because the
4231
4269
  values are byte-equal to what the build renders. On a converted site read \`coverage\` too: it