@bettercms-ai/mcp 0.37.1 → 0.38.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 CHANGED
@@ -2977,7 +2977,7 @@ function buildToolDefs(deps) {
2977
2977
  def(
2978
2978
  "submit_conversion_receipt",
2979
2979
  "Record what the conversion codemod could and could not do",
2980
- "Hand BetterCMS the codemod's own account of a conversion run, so the coverage meter can say WHY a path is not declared instead of only that it is not. Submit the receipt `npx @bettercms-ai/convert` wrote (`--receipt out.json`) for the SAME `briefDigest` get_conversion_brief { complete: true } returned: `{ briefDigest, receipt }`, where the receipt carries `paths: { declared, rewritten, alreadyDeclared, pending[{ route, scope, path, kind, file, reason, message }] }`. `paths.declared` must equal rewritten + alreadyDeclared + pending.length, and each pending `reason` is one of the converter's own (IN_EXPRESSION, AMBIGUOUS_LITERAL, REPEATER_FIXED_LENGTH, PARSE_ERROR, \u2026) \u2014 a path with no receipt row simply reads `not-declared`. It is a RECORD, not a release: it changes nothing about the site, and the meter picks it up on the next get_binding_report after the next deploy. A 404 `unknown-brief` means that digest was never issued here, so convert against a brief this project actually returned. Requires artifact:write, the same authority as set_binding_mode; on a workspace-wide connection pass `projectId`.",
2980
+ "Hand BetterCMS the codemod's own account of a conversion run, so the coverage meter can say WHY a path is not declared instead of only that it is not. Submit the receipt `npx @bettercms-ai/convert` wrote (`--receipt out.json`) for the SAME `briefDigest` get_conversion_brief { complete: true } returned: `{ briefDigest, receipt }`, where the receipt carries `paths: { declared, rewritten, alreadyDeclared, pending[{ route, scope, path, kind, file, reason, message }] }`. `paths.declared` must equal rewritten + alreadyDeclared + pending.length, and each pending `reason` is one of the converter's own (IN_EXPRESSION, AMBIGUOUS_LITERAL, REPEATER_FIXED_LENGTH, PARSE_ERROR, \u2026) \u2014 a path with no receipt row simply reads `not-declared`. It is a RECORD, not a release: it changes nothing about the site, and the meter picks it up on the next get_binding_report after the next deploy. A 404 `unknown-brief` means that digest was never issued here, so convert against a brief this project actually returned. \u{1F534} SUBMIT THE BINDING RECEIPT, NOT THE `--forms` ONE. A run of `npx @bettercms-ai/convert --forms` writes a receipt whose `paths` are all zero and whose account is in a `forms` block (`{ wired, alreadyWired, pending[{ id, name, reason }], notes }`); it passes this endpoint's arithmetic and would overwrite the real coverage with zeros. Write it to its own file (`--receipt forms-receipt.json`), read `forms.pending` and publish every form `forms.notes` names in the Forms tab, and submit the binding run's receipt here. Requires artifact:write, the same authority as set_binding_mode; on a workspace-wide connection pass `projectId`.",
2981
2981
  z.object({
2982
2982
  briefDigest: z.string().min(1).describe("The `briefDigest` get_conversion_brief { complete: true } returned. Must match the receipt's own."),
2983
2983
  receipt: z.record(z.string(), z.unknown()).describe("The receipt `npx @bettercms-ai/convert --receipt out.json` wrote, verbatim.")
@@ -3105,7 +3105,7 @@ function buildToolDefs(deps) {
3105
3105
  def(
3106
3106
  "get_conversion_brief",
3107
3107
  "Get the brief for making this site's bindings durable",
3108
- "The per-project brief for making this site's bindings DURABLE \u2014 read it before you touch the templates. Returns what already exists in the CMS: every live page with its route, and every bindable field path with its `label`, `kind`, the value the CMS holds now (`current`) and the copy the repo renders today (`original`, the field's defaultValue) \u2014 plus the exact attributes to declare, and the ordered steps. Call it for any site whose pages were DERIVED at import, and whenever get_next_steps reports `bindings-not-declared`. It REPLACES re-registering a schema: these pages, fields and values exist already, so create_page / add_page_field / create_content_model would build a second schema over the first \u2014 edit values with set_page_content instead. `lane` says how to get the source ('git-connected' = pull_project_source returns a repo; 'archive' = a tarball). The full recipe is section 13 of the bettercms://playbook/schema resource; get_binding_report is the receipt that says you finished. Pass `complete: true` when you are about to run the CODEMOD (`npx @bettercms-ai/convert`): that returns the brief UNCAPPED and paged \u2014 nothing truncated, no page omitted \u2014 and pins the full path list under a `briefDigest`, which is the list the coverage meter in get_binding_report measures the build against. Follow `cursor` until it stops coming back; a 409 `BRIEF_CHANGED` means the brief was re-derived while you paged, so start again.",
3108
+ "The per-project brief for making this site's bindings DURABLE \u2014 read it before you touch the templates. Returns what already exists in the CMS: every live page with its route, and every bindable field path with its `label`, `kind`, the value the CMS holds now (`current`) and the copy the repo renders today (`original`, the field's defaultValue) \u2014 plus the exact attributes to declare, and the ordered steps. Call it for any site whose pages were DERIVED at import, and whenever get_next_steps reports `bindings-not-declared`. It REPLACES re-registering a schema: these pages, fields and values exist already, so create_page / add_page_field / create_content_model would build a second schema over the first \u2014 edit values with set_page_content instead. `lane` says how to get the source ('git-connected' = pull_project_source returns a repo; 'archive' = a tarball). The full recipe is section 13 of the bettercms://playbook/schema resource; get_binding_report is the receipt that says you finished. Pass `complete: true` when you are about to run the CODEMOD (`npx @bettercms-ai/convert`): that returns the brief UNCAPPED and paged \u2014 nothing truncated, no page omitted \u2014 and pins the full path list under a `briefDigest`, which is the list the coverage meter in get_binding_report measures the build against. Follow `cursor` until it stops coming back; a 409 `BRIEF_CHANGED` means the brief was re-derived while you paged, so start again. The complete brief also carries `forms` \u2014 every form of this project with its id, status, fields and submitUrl \u2014 which is what `npx @bettercms-ai/convert --forms --brief brief.json --root . --receipt forms-receipt.json` wires into the repository's own <form> elements; run it after the binding pass, read its `forms.pending`, and publish every form its `forms.notes` names in the Forms tab (a draft form rejects every submission with a 403).",
3109
3109
  z.object({
3110
3110
  complete: z.boolean().optional().describe("true = the COMPLETE brief for a codemod: nothing truncated, no page omitted, paged 50 pages at a time. Page 1 pins the path list the coverage meter measures against."),
3111
3111
  cursor: z.string().optional().describe("The `cursor` from the previous page. Implies complete. A 409 BRIEF_CHANGED means the brief was re-derived mid-pagination \u2014 start again with no cursor.")
@@ -4254,7 +4254,12 @@ component placement, and the page keeps its fields, its values and its bindings.
4254
4254
  1. set_authoring_preference { preference: "components" }
4255
4255
  2. get_componentize_plan one component per section, computed live; creates nothing. It
4256
4256
  reads this project's PUBLISHED pages, so no deploy is needed
4257
- to reach it \u2014 the deploy is the last step, not the first
4257
+ to reach it \u2014 the deploy is the last step, not the first.
4258
+ On a site DERIVED at import the release hook has already run
4259
+ this plan in bind mode and PUBLISHED what it created, so
4260
+ expect ALREADY_COMPONENTIZED and skip to step 6 (publish the
4261
+ pages) \u2014 the lane publishes the COMPONENTS, not the placements,
4262
+ which are still draft blocks on the pages
4258
4263
  3. show the user the plan and CONFIRM \u2014 it says how many components and which pages
4259
4264
  4. componentize_sections \`dryRun: true\` first, then for real; components land as DRAFTS
4260
4265
  and each placement carries \`props.bind\` to the page's field
@@ -4437,7 +4442,10 @@ still gets its own component: its own family, plus \`allowedOn: ["slug:<page>"]\
4437
4442
  with NO \`sectionType\` never appears in the editor's "Add a section" picker. Start from the
4438
4443
  builtin blueprints \`list_components\` returns (\`builtin:*\`) instead of hand-writing block JSON.
4439
4444
  On a DERIVED site run \`get_componentize_plan\` \u2192 \`componentize_sections\` FIRST \u2014 it does most
4440
- of this in one call.
4445
+ of this in one call, and on a site derived at IMPORT the release hook has already run it in bind
4446
+ mode and published the components, so expect ALREADY_COMPONENTIZED \u2014 the placements it wrote are
4447
+ still DRAFT blocks on the pages, so publish the pages, then \`npx @bettercms-ai/convert
4448
+ --componentize\`.
4441
4449
 
4442
4450
  **3. The hierarchy editors see is the GROUP.** \`create_component\` and \`update_component\` take
4443
4451
  \`group\`: a NAME, resolved against the project's component groups and created when missing. That
@@ -4552,6 +4560,19 @@ hand. THE ORDER, and every step of it matters:
4552
4560
  \`npx @bettercms-ai/convert --brief brief.json --root . --receipt receipt.json\`, then read
4553
4561
  \`git diff\`. It rewrites the templates to read from BetterCMS, keeps the in-code copy as the
4554
4562
  fallback, and declares each binding.
4563
+ 2b. IF THE BRIEF CARRIES \`forms\`, wire them too:
4564
+ \`npx @bettercms-ai/convert --forms --brief brief.json --root . --receipt forms-receipt.json\`
4565
+ \u2014 ITS OWN receipt file, because the forms receipt claims no path and submitting it would
4566
+ overwrite the coverage the binding run just earned with zeros.
4567
+ A site imported by phase 1 has a DRAFT form row per \`<form>\` in its build, so the Forms tab
4568
+ is full while the repository's markup still posts wherever it always did \u2014 to nothing, or to
4569
+ somebody else's endpoint. This pass writes the endpoint, the form id, a marker per field and
4570
+ the submit script onto the \`<form>\` the repository already has. Then PUBLISH each form the
4571
+ receipt's \`forms.notes\` names, in the Forms tab: the public submit route answers 403 to a
4572
+ draft, so a wired draft form is a real, inviting form that rejects every visitor. Forms it
4573
+ could not match are in \`forms.pending\` with a reason (\`FORM_NOT_IN_SOURCE\`,
4574
+ \`FIELD_UNMATCHED\`, \`FORM_AMBIGUOUS\`, \u2026) \u2014 it refuses rather than guessing, because a form
4575
+ wired to the wrong id delivers the customer's leads into another form's inbox.
4555
4576
  3. REVIEW THE PENDING LIST. Every path the codemod could not do is in \`paths.pending\` with a
4556
4577
  reason (\`IN_EXPRESSION\`, \`AMBIGUOUS_LITERAL\`, \`REPEATER_FIXED_LENGTH\`, \`PARSE_ERROR\`, \u2026).
4557
4578
  Do those by hand, or decide they are genuinely not convertible \u2014 do not skip past them.