@bettercms-ai/mcp 0.76.6 → 0.78.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
@@ -2697,6 +2697,7 @@ ${JSON.stringify(STRUCTURE_EXAMPLE_PAYLOAD, null, 2)}
2697
2697
  `;
2698
2698
 
2699
2699
  // src/entry-merge.ts
2700
+ var mergesEntry = (args) => args.merge !== false && args.data !== void 0;
2700
2701
  function planEntryMerge(stored, patch, callerIfMatch) {
2701
2702
  const data = { ...stored.data ?? {}, ...patch };
2702
2703
  const ifMatch = callerIfMatch ?? (typeof stored.optimisticVersion === "number" ? stored.optimisticVersion : void 0);
@@ -2831,6 +2832,11 @@ function planFieldEdit(model, edit, callerIfMatch) {
2831
2832
  if (edit[k] === null && CLEARABLE.includes(k)) delete out[k];
2832
2833
  else out[k] = edit[k];
2833
2834
  }
2835
+ if (edit.ui && typeof edit.ui === "object") {
2836
+ const ui = mergeConfig(f.ui, edit.ui);
2837
+ if (Object.keys(ui).length > 0) out.ui = ui;
2838
+ else delete out.ui;
2839
+ }
2834
2840
  if (edit.config && typeof edit.config === "object") out = { ...out, config: mergeConfig(f.config, edit.config) };
2835
2841
  if (retype) out.type = edit.type;
2836
2842
  if (rename !== void 0) out.key = rename;
@@ -3532,7 +3538,7 @@ var MODEL_UPDATE_KEYS = [
3532
3538
  "override"
3533
3539
  ];
3534
3540
  var ENTRY_META_NOTE = "SEO is native: set this entry's metaTitle, metaDescription, noindex, canonical, og, twitter, schemaType or schema in `meta` (never as model fields). `meta` MERGES into what is stored: a key you leave out is kept, null or an empty string clears it.";
3535
- var ENTRY_MERGE_NOTE = "true = keep the fields you leave out: the entry is read, `data` is laid over its stored data by top-level key (a group or repeater value replaces that whole key) and written at the version read. Default false: `data` REPLACES the whole object.";
3541
+ var ENTRY_MERGE_NOTE = "Default true: keep the fields you leave out. The entry is read, `data` is laid over its stored data by top-level key (a group or repeater value replaces that whole key) and written at the version read. false = `data` REPLACES the whole object, deleting every field you leave out.";
3536
3542
  var ENTRY_IF_MATCH_NOTE = "optimisticVersion from get_content_entry: the write applies only at that version, and a 409 means it changed since: read it again and re-apply. With merge it defaults to the version merge read.";
3537
3543
  var ENTRY_SCHEDULED_AT_NOTE = "ISO datetime to publish this draft at (needs publish permission); null cancels. An edit that omits scheduledAt CANCELS a pending publish schedule, so send it again with every edit made before it fires.";
3538
3544
  var ENTRY_UNPUBLISH_AT_NOTE = "ISO datetime at which the published entry returns to draft; null cancels. Omitting it never cancels it.";
@@ -4632,8 +4638,8 @@ ${d.outline}` : "Proposed Content structure.", d);
4632
4638
  def(
4633
4639
  "update_project",
4634
4640
  "Update the connected project",
4635
- "Update the connected project's settings \u2014 rename it, change its slug/description, SEO defaults, visibility, or `presentation`. Only the provided fields change. `presentation` themes the platform's OWN renderer (the one serving a site built in the CMS with no deployed build, and previewing structural drafts everywhere) with the same closed knobs as bcms-presentation.json \u2014 DTCG { $type, $value } tokens keyed like 'page.maxWidth', 'nav.background'. Without it that renderer is a generic 768px document theme. An invalid manifest is 422 PRESENTATION_INVALID.",
4636
- z.object({ name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), visibility: z.string().optional(), seoDefaults: z.record(z.string(), z.unknown()).optional(), presentation: z.record(z.string(), z.unknown()).optional().describe("theme knobs for the platform renderer, keyed like bcms-presentation.json") }).shape,
4641
+ "Update the connected project's settings \u2014 rename it, change its slug/description, SEO defaults, visibility, or `presentation`. Only the provided fields change. `subdomainAlias` renames the staging URL: 'astronapp' serves the site at astronapp.bettercms.site (3\u201355 lowercase letters, numbers, hyphens; 409 when taken; null goes back to the original). The original <handle>.bettercms.site keeps working; a replaced name is released. `presentation` themes the platform's OWN renderer (the one serving a site built in the CMS with no deployed build, and previewing structural drafts everywhere) with the same closed knobs as bcms-presentation.json \u2014 DTCG { $type, $value } tokens keyed like 'page.maxWidth', 'nav.background'. Without it that renderer is a generic 768px document theme. An invalid manifest is 422 PRESENTATION_INVALID.",
4642
+ z.object({ name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), visibility: z.string().optional(), seoDefaults: z.record(z.string(), z.unknown()).optional(), presentation: z.record(z.string(), z.unknown()).optional().describe("theme knobs for the platform renderer, keyed like bcms-presentation.json"), subdomainAlias: z.string().nullable().optional().describe("the staging name: 'astronapp' \u2192 astronapp.bettercms.site; null = back to the original") }).shape,
4637
4643
  async (c, a) => ok("Updated project.", await data(c, "PATCH", `/management/projects/current`, a))
4638
4644
  ),
4639
4645
  def(
@@ -4975,7 +4981,7 @@ ${d.outline}` : "Proposed Content structure.", d);
4975
4981
  required: z.boolean().optional(),
4976
4982
  config: z.record(z.string(), z.unknown()).optional().describe("per-type validation/config keys, merged into the stored config; null deletes a key"),
4977
4983
  showIf: z.record(z.string(), z.unknown()).nullable().optional().describe("same shape as on add_field; null clears it"),
4978
- ui: z.record(z.string(), z.unknown()).nullable().optional().describe("same vocabulary as on add_field; null clears it"),
4984
+ ui: z.record(z.string(), z.unknown()).nullable().optional().describe("same vocabulary as on add_field; merged per key, a null key or ui:null clears"),
4979
4985
  placement: z.enum(["cover", "title", "excerpt", "body", "inline", "panel"]).nullable().optional(),
4980
4986
  readOnly: z.union([z.literal(true), z.literal("developer")]).nullable().optional().describe(PARAM_TEXT.lockClears),
4981
4987
  lockReason: z.string().max(200).nullable().optional().describe(PARAM_TEXT.lockClears),
@@ -5822,12 +5828,12 @@ ${notes.join("\n")}` : summary, created);
5822
5828
  name: "update_content_entry",
5823
5829
  config: {
5824
5830
  title: "Update a content entry's values",
5825
- description: "Update a content entry's `data` (field values) and/or status by id. `data` is keyed by field key; a nested 'array' (zone) value is an object { nonRepeatable: {\u2026}, repeatable: [{\u2026}] }, a primitive 'array' is a plain list; an image value may carry this placement's focal {x,y} and crop {top,right,bottom,left} (0\u20131). Use this to edit an existing entry; for a singleton page prefer set_page_content. \u{1F534} `data` REPLACES the entry's whole value object: an optional field you leave out is DELETED, and a required one you leave out fails the whole write. To change one field, pass merge:true, or read the entry (get_content_entry), change that key and send the whole object back. " + FIELD_LOCKED_NOTE + " " + ENTRY_META_NOTE,
5831
+ description: "Update a content entry's `data` (field values) and/or status by id. `data` is keyed by field key; a nested 'array' (zone) value is an object { nonRepeatable: {\u2026}, repeatable: [{\u2026}] }, a primitive 'array' is a plain list; an image value may carry this placement's focal {x,y} and crop {top,right,bottom,left} (0\u20131). Use this to edit an existing entry; for a singleton page prefer set_page_content. `data` MERGES into the stored values by top-level key: a field you leave out is kept, null clears one, and a group or repeater value replaces that whole key. \u{1F534} merge:false REPLACES the whole value object instead: an optional field you leave out is DELETED, and a required one you leave out fails the whole write. " + FIELD_LOCKED_NOTE + " " + ENTRY_META_NOTE,
5826
5832
  inputSchema: updateEntryInput.shape
5827
5833
  },
5828
5834
  handler: guard(
5829
5835
  async (args) => withClient(async (client) => {
5830
- const write = args.merge === true && args.data !== void 0 ? planEntryMerge(await client.getEntry(args.entryId), args.data, args.ifMatch) : { data: args.data, ifMatch: args.ifMatch };
5836
+ const write = mergesEntry(args) ? planEntryMerge(await client.getEntry(args.entryId), args.data, args.ifMatch) : { data: args.data, ifMatch: args.ifMatch };
5831
5837
  const input = {
5832
5838
  ...write.data !== void 0 ? { data: write.data } : {},
5833
5839
  ...args.status !== void 0 ? { status: args.status } : {},
@@ -7861,8 +7867,8 @@ Read \`bettercms://playbook/schema\` \xA712 first \u2014 this is the short form
7861
7867
  Use Global, Navigation, Actions, Content, Forms, Media, Sections, Page-specific. \`category\`
7862
7868
  is the separate picker TAB.
7863
7869
  4. **Fields** = \`props\`: text, richtext, image, url, boolean, number, select, group, table, slot.
7864
- Always a \`defaultValue\`; \`required\` / \`helpText\` / \`placeholder\` are editor hints, not write
7865
- -time enforcement. \`select\` for styling-only variants, a separate component when the markup
7870
+ Always a \`defaultValue\`; \`helpText\` / \`placeholder\` are editor hints. A placement you SET empty on a
7871
+ \`required\` prop is refused (\`required_value\`). \`select\` for styling-only variants, a separate component when the markup
7866
7872
  differs. Nesting goes up to 10 levels; a \`table\` row may hold a data table or a polymorphic list.
7867
7873
  5. **Quality.** The componentize lane and \`npx @bettercms-ai/convert --componentize\` move markup
7868
7874
  VERBATIM \u2014 classes, responsive utilities, aria attributes, alt text all survive. Never