@bettercms-ai/mcp 0.67.1 → 0.68.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 CHANGED
@@ -2694,6 +2694,8 @@ var NEW_TOOL_TEXT = {
2694
2694
  };
2695
2695
  var DELETE_PAGE_RUNTIME_BUNDLE = " Or, with no pageId, `runtimeBundle`: 'report' lists the duplicate pages derived from a server app's own bundle (`app/` folders); 'apply' retires them and their empty folders.";
2696
2696
  var PARAM_TEXT = {
2697
+ helpText: "shown under the field: its purpose, where it shows, any constraint; never its label or value. Omitted: written for you.",
2698
+ describes: "for editors: what it is and holds; omitted: written for you",
2697
2699
  runtimeBundle: "instead of pageId: the server-app bundle cleanup",
2698
2700
  pageRef: "page id or path ('/de/about'); a bare slug only when one page has it",
2699
2701
  editorSetupForce: "re-run a setup already ready for the live build",
@@ -2962,9 +2964,7 @@ var fieldShape = {
2962
2964
  // builder. They were unreachable from MCP for ONE reason: the OutField/toField whitelist
2963
2965
  // below did not model them, so they were stripped after the model had gone to the trouble of
2964
2966
  // sending them. Declaring them here is what makes the existing panel agent-writable.
2965
- helpText: z.string().max(500).optional().describe(
2966
- "one line of guidance shown UNDER this field in the editor \u2014 what to write here, not what the field is. Write it for the person typing ('Roughly 60 characters; it becomes the browser tab title'), not for a developer."
2967
- ),
2967
+ helpText: z.string().max(500).optional().describe(PARAM_TEXT.helpText),
2968
2968
  showIf: z.object({
2969
2969
  match: z.enum(["all", "any"]),
2970
2970
  rules: z.array(
@@ -3281,6 +3281,7 @@ var withProjectId = (def) => ({
3281
3281
  return currentProject.run(arg("projectId"), () => currentBranch.run(arg("branchId"), () => def.handler(args)));
3282
3282
  }
3283
3283
  });
3284
+ var autoHelpNote = (args) => typeof args.helpText === "string" && args.helpText.trim() ? "" : " No helpText was sent, so the platform wrote it (helpSource: auto); send helpText with update_field to write your own.";
3284
3285
  function buildToolDefs(deps) {
3285
3286
  async function withClient(fn) {
3286
3287
  const token = await deps.auth.getAccessToken();
@@ -3382,7 +3383,7 @@ function buildToolDefs(deps) {
3382
3383
  const createModelInput = z.object({
3383
3384
  name: z.string().min(1).describe("human model name, e.g. 'Blog Post'"),
3384
3385
  slug: slug.describe("url-safe unique slug, e.g. 'blog-post'"),
3385
- description: z.string().optional(),
3386
+ description: z.string().optional().describe(PARAM_TEXT.describes),
3386
3387
  urlPattern: urlPatternArg,
3387
3388
  kind: z.enum(["model", "block"]).optional().describe(
3388
3389
  "'model' (default) = a collection with its own entries. 'block' = a type that exists only to be stacked inside another model's 'modular' field \u2014 it holds no entries, and create_content_entry against it is refused. Create blocks FIRST, then the model whose modular field lists their slugs. Cannot be changed later."
@@ -3614,7 +3615,7 @@ function buildToolDefs(deps) {
3614
3615
  z.object({ type: z.literal("set-section-state"), ...sectionTarget, state: z.enum(["inherit", "override-content", "customize-structure", "disable", "reset"]) }),
3615
3616
  z.object({ type: z.literal("add-section"), name: z.string().min(1), icon: layoutIcon, zone: z.enum(["before_page", "after_page"]) }),
3616
3617
  z.object({ type: z.literal("restore-section"), section: z.object({ id: z.string().min(1) }).passthrough(), data: z.object({ fields: z.record(z.string(), z.unknown()) }), placement: z.object({ zone: z.enum(["above-page-content", "below-page-content"]), localOrderKey: z.string().min(1), afterSectionId: z.string().optional(), beforeSectionId: z.string().optional() }).optional() }),
3617
- z.object({ type: z.literal("update-section"), ...sectionTarget, name: z.string().min(1).optional(), icon: layoutIcon.optional(), slug: z.string().min(1).optional(), zone: z.enum(["above-page-content", "below-page-content"]).optional(), orderKey: z.string().min(1).optional() }),
3618
+ z.object({ type: z.literal("update-section"), ...sectionTarget, name: z.string().min(1).optional(), icon: layoutIcon.optional(), slug: z.string().min(1).optional(), zone: z.enum(["above-page-content", "below-page-content"]).optional(), orderKey: z.string().min(1).optional(), description: z.string().optional() }),
3618
3619
  z.object({ type: z.literal("remove-section"), ...sectionTarget }),
3619
3620
  z.object({ type: z.literal("move-section"), ...sectionTarget, afterId: z.string().nullable().optional(), beforeId: z.string().nullable().optional() }),
3620
3621
  z.object({ type: z.literal("add-field"), ...sectionTarget, parentFieldId: z.string().optional(), fieldType: z.enum(["text", "longtext", "richtext", "number", "toggle", "date", "image", "file", "link", "email", "phone", "select", "color", "json", "reference", "multi-reference", "group", "repeater"]).optional(), field: z.object({ id: z.string(), slug: z.string(), label: z.string(), type: z.string() }).passthrough().optional() }),
@@ -3653,19 +3654,19 @@ function buildToolDefs(deps) {
3653
3654
  "conversion"
3654
3655
  ]);
3655
3656
  const sectionType = z.string().min(1).max(64).describe(
3656
- "section family, e.g. 'Hero' \u2014 set this with a library category to make the component selectable in the page editor's 'Add a section' picker. Components sharing a sectionType are layout variants of one section."
3657
+ "section family, e.g. 'Hero' \u2014 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."
3657
3658
  );
3658
3659
  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");
3659
3660
  const createComponentInput = z.object({
3660
3661
  name: z.string().min(1),
3661
3662
  slug: slug.describe("url-safe unique slug (lowercase letters/numbers/hyphens)"),
3662
3663
  category: componentCategory.optional().describe("defaults to 'custom'"),
3663
- group: z.string().min(1).max(100).optional().describe("the folder editors see in the dashboard's Components tab, addressed by NAME (e.g. 'Sections', 'Navigation', 'Forms'). Resolved against this project's Groups and CREATED when missing, so a whole-site run can file everything without looking any id up first. Separate from `category`, which is the picker tab."),
3664
+ group: z.string().min(1).max(100).optional().describe("the folder editors see in the dashboard's Components tab, by NAME (e.g. 'Sections', 'Forms'); CREATED when missing. Separate from `category`, the picker tab."),
3664
3665
  sectionType: sectionType.optional(),
3665
3666
  variantOf: z.string().min(1).max(255).optional().describe("id/slug of the component this is a VARIANT of: joins or starts its family (422 if its shared inputs are missing)"),
3666
3667
  projectId: z.string().nullable().optional().describe("owning project id; null creates a workspace-wide global component"),
3667
3668
  allowedOn: allowedOn.optional(),
3668
- description: z.string().optional(),
3669
+ description: z.string().optional().describe(PARAM_TEXT.describes),
3669
3670
  blockJson: z.array(blockObject).default([]).describe("the component's block tree"),
3670
3671
  props: z.array(componentPropObject).default([]).describe(
3671
3672
  "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."
@@ -5179,7 +5180,7 @@ ${notes.join("\n")}` : summary, created);
5179
5180
  body: JSON.stringify(input2),
5180
5181
  headers: confirmedHeaders(true)
5181
5182
  })).data : await client.addPageFields(args.pageId, input2);
5182
- return ok(`Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).`, page);
5183
+ return ok(`Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).${autoHelpNote(args)}`, page);
5183
5184
  }
5184
5185
  const modelId = args.modelId;
5185
5186
  const model = await client.getModel(modelId);
@@ -5208,7 +5209,7 @@ ${notes.join("\n")}` : summary, created);
5208
5209
  headers: { ...opts ? { "If-Match": `W/"${opts.ifMatch}"` } : {}, ...confirmedHeaders(true) }
5209
5210
  })).data : opts ? await client.updateModel(modelId, input, opts) : await client.updateModel(modelId, input);
5210
5211
  return ok(
5211
- `Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : ""}. Model now has ${updated.fields.length} field(s).`,
5212
+ `Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : ""}. Model now has ${updated.fields.length} field(s).${autoHelpNote(args)}`,
5212
5213
  updated
5213
5214
  );
5214
5215
  })
@@ -7031,7 +7032,13 @@ Do not stop at the plan or at a partial receipt \u2014 finish the whole site, ne
7031
7032
  8. \`get_binding_report\`: \`unmatched\` 0, \`unaddressable\` under 2% per route; fix the SOURCE, deploy, re-read (playbook \xA711).
7032
7033
  9. \`set_binding_mode { declaredBindings: true }\`, deploy AGAIN and poll, then confirm \`get_binding_report\`
7033
7034
  reads mode "declared", unmatched 0, bound above 0, \`coverage.pending\` empty. Send me that report.
7034
- 10. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the
7035
+ 10. \`get_next_steps\`: if it lists \`upgrade-section-roots\` (section spacing and style handles), in the repo run
7036
+ \`npx @bettercms-ai/convert@latest --upgrade-sections --root . --dry-run\`, read the plan, then run it for real. For every
7037
+ root its receipt lists as \`skipped\`, pass the block down by hand: \`{...sectionRootAttrs(block)}\` on the section root, or
7038
+ \`data-bcms-style=""\` plus \`style={...}\` from \`block.style\`. Run \`--verify-styles\` again and restore what it lists (the
7039
+ marker and the inline style from \`block.style\` are allowed; changing a class or an existing style is not). Deploy,
7040
+ poll, call \`get_next_steps\` again and tell me what it still lists. Not listed: say so and move on; invent no work.
7041
+ 11. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the
7035
7042
  next rebuild from my repo drops it). Touch git only as I answer.`;
7036
7043
  var FIELD_UI_PROMPT = {
7037
7044
  title: "Declare how fields LOOK in the editor (guided)",