@bettercms-ai/mcp 0.72.2 → 0.73.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
@@ -3265,7 +3265,13 @@ var propUiObject = uiObject.extend({
3265
3265
  collapsible: z.boolean().optional(),
3266
3266
  layout: z.enum(["stack", "breakpoints"]).optional(),
3267
3267
  order: z.number().int().min(0).max(99).optional()
3268
- }).optional().describe("the group this prop (or sub-field) sits in. The FIRST member defines {id, label, kind?, icon?, collapsed?, description?, columns?, collapsible?, layout?, order?}; later ones send only {id}.")
3268
+ }).optional().describe("the group this prop (or sub-field) sits in. The FIRST member defines {id, label, kind?, icon?, collapsed?, description?, columns?, collapsible?, layout?, order?}; later ones send only {id}."),
3269
+ tab: z.strictObject({
3270
+ id: z.string().min(1).max(40),
3271
+ label: z.string().min(1).max(20).optional(),
3272
+ icon: uiObject.shape.icon,
3273
+ order: z.number().int().min(0).max(99).optional()
3274
+ }).optional().describe("TOP-LEVEL props only: the dock tab this prop sits in (a V2 kit schema `groups` entry: Content, Design, \u2026). The FIRST prop in a tab defines {id, label, icon?, order?}; later ones send only {id}. \u22648 tabs, labels unique; a group's members share one tab.")
3269
3275
  });
3270
3276
  var choiceOption = z.union([z.string(), z.object({ label: z.string(), value: z.string(), icon: z.string().optional(), description: z.string().optional() })]);
3271
3277
  var fieldShape = {
@@ -3284,7 +3290,7 @@ var fieldShape = {
3284
3290
  "choices when type is 'select'. A plain string, or {label, value, icon?, description?} when the stored value differs from what the editor shows (e.g. {label:'Sold out', value:'soldOut'}); icon a dock name, description one line \u2264140."
3285
3291
  ),
3286
3292
  config: z.record(z.string(), z.unknown()).optional().describe(
3287
- "per-type config: reference {contentModelId}, multi-reference {contentModelId,min,max}, array {itemType: text|number|date|image|link|richtext}, date {includeTime, timezone}, modular|slot {blockSlugs: ['quote','gallery'], minItems?, maxItems?} (slot: playbook \xA75) \u2014 blockSlugs is REQUIRED, non-empty, and each slug must name an existing kind:'block' model; richtext {inline:true, hostTag:'h2', accept:['h2','p','b','i','u','link'], features:['bold','italic','underline','link','headings'], allowMultipleParagraphs:false} \u2014 for a field bound to ONE element on the page: `hostTag` is that element's tag and `accept` must name it, so the editor's block-style control opens already showing 'Heading 2' instead of 'Paragraph'. Name exactly ONE heading level: publish refuses an <h3> value bound to an <h2> rather than nesting one heading inside the other. Keep 'p' in `accept` or the sanitiser strips a block demoted to Paragraph; limits: text/longtext {minLength,maxLength,pattern,patternMessage}, richtext {minLength,maxLength}, number {validation:{min,max}}, array {minItems,maxItems}, tags {min,max}, rating {min,max,step}"
3293
+ "per-type config: reference {contentModelId}, multi-reference {contentModelId,min,max}, repeater {minItems, maxItems} (the list's item limits; the editor shows 'max N' and stops Add there), array {itemType: text|number|date|image|link|richtext}, date {includeTime, timezone}, modular|slot {blockSlugs: ['quote','gallery'], minItems?, maxItems?} (slot: playbook \xA75) \u2014 blockSlugs is REQUIRED, non-empty, and each slug must name an existing kind:'block' model; richtext {inline:true, hostTag:'h2', accept:['h2','p','b','i','u','link'], features:['bold','italic','underline','link','headings'], allowMultipleParagraphs:false} \u2014 for a field bound to ONE element on the page: `hostTag` is that element's tag and `accept` must name it, so the editor's block-style control opens already showing 'Heading 2' instead of 'Paragraph'. Name exactly ONE heading level: publish refuses an <h3> value bound to an <h2> rather than nesting one heading inside the other. Keep 'p' in `accept` or the sanitiser strips a block demoted to Paragraph; limits: text/longtext {minLength,maxLength,pattern,patternMessage}, richtext {minLength,maxLength}, number {validation:{min,max}}, array {minItems,maxItems}, tags {min,max}, rating {min,max,step}"
3288
3294
  ),
3289
3295
  fields: z.array(z.lazy(() => fieldObject)).optional().describe(
3290
3296
  "NESTED child fields \u2014 REQUIRED for type 'group' (one nested object, a Non-Repeatable Zone like blog_hero \u2192 heading, description, hero_image) and type 'repeater' (a repeatable array of such objects, a Repeatable Zone / section-list like testimonials \u2192 quote, author). A section with repeating items is a 'repeater'; a fixed grouped block is a 'group'. Recurse to any depth \u2014 do NOT flatten zones into separate top-level fields."
@@ -3455,7 +3461,8 @@ function toField(f) {
3455
3461
  return { ...base, type: "array", config: { zones: { nonRepeatable: toFields(f.fields) } } };
3456
3462
  }
3457
3463
  if (f.type === "repeater") {
3458
- return { ...base, type: "array", config: { zones: { repeatable: { fields: toFields(f.fields) } } } };
3464
+ const { minItems, maxItems } = f.config ?? {};
3465
+ return { ...base, type: "array", config: { zones: { repeatable: { fields: toFields(f.fields), ...minItems !== void 0 ? { minItems } : {}, ...maxItems !== void 0 ? { maxItems } : {} } } } };
3459
3466
  }
3460
3467
  if (f.type === "array" && f.config && typeof f.config === "object" && "zones" in f.config) {
3461
3468
  const zones = f.config.zones ?? {};
@@ -3488,8 +3495,8 @@ var UPDATE_MODEL_DESCRIPTION = "Edit a content model: rename it, change descript
3488
3495
  var FIELD_REMOVAL_NOTE = "top-level field keys (from get_content_model) to DELETE from this model with every entry's value for them; needs allowFieldRemoval: true. An unknown key refuses the whole call. Never for a rename: rename the label instead.";
3489
3496
  var ALLOW_FIELD_REMOVAL_NOTE = "true = the user accepts that removeFields discards those fields' data in every entry. There is no dry run on this route: confirm first.";
3490
3497
  var MODEL_IF_MATCH_NOTE = "optimisticVersion from get_content_model (with pageId: get_page backingModel). The write applies only at that version; a 409 version-conflict means it changed since: read it again and re-apply, never retry blindly. REQUIRED with field*, override or a fieldset kind/tab/icon/collapsed (428 without); otherwise, omitted, the last write wins.";
3491
- var COMPONENT_IF_MATCH_NOTE = "optimisticVersion from get_component. The write applies only at that version; a 409 version-conflict means it changed since: read it again and re-apply. REQUIRED with prop*, override or a prop ui icon/itemLabel/group (428 without).";
3492
- var PROP_UI_ARG_NOTE = "top-level prop key \u2192 ui patch, the same vocabulary as a prop's `ui`: each key merges, a null key clears it, null clears the whole ui";
3498
+ var COMPONENT_IF_MATCH_NOTE = "optimisticVersion from get_component. The write applies only at that version; a 409 version-conflict means it changed since: read it again and re-apply. REQUIRED with prop*, override or a prop ui icon/itemLabel/group/tab (428 without).";
3499
+ var PROP_UI_ARG_NOTE = "top-level prop key \u2192 ui patch, the same vocabulary as a prop's `ui` (group and tab included): each key merges, a null key clears it, null clears the whole ui. Patches keep every other prop as stored; sending `props` instead REPLACES the whole array, so echo each prop's stored `ui` (its `ui.group` AND `ui.tab`) or the prop leaves its tab";
3493
3500
  var OVERRIDE_NOTE = "replace chrome a person set (otherwise 409 ui_human_owned names those paths). Send it only on the user's word.";
3494
3501
  var FIELD_UI_ARG_NOTE = "path \u2192 ui patch, a field's `ui` vocabulary: each key merges, a null key clears it, null clears the whole ui";
3495
3502
  var MODEL_UPDATE_KEYS = [
@@ -4097,6 +4104,7 @@ function buildToolDefs(deps) {
4097
4104
  ),
4098
4105
  propUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(PROP_UI_ARG_NOTE),
4099
4106
  propGroup: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe("prop key \u2192 its ui.group ({id, label?, kind?, icon?, collapsed?}), null takes it out"),
4107
+ propTab: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe("prop key \u2192 its ui.tab ({id, label?, icon?, order?}), the V2 schema group it sits in. The FIRST top-level prop in a tab defines {id, label, icon?, order?}, later ones send {id}; \u22648 tabs; one group's members share one tab. null takes it out"),
4100
4108
  propLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe("prop key \u2192 label"),
4101
4109
  propHelpText: z.record(z.string(), z.string().max(200).nullable()).optional().describe("prop key \u2192 help text, null clears it"),
4102
4110
  override: z.boolean().optional().describe(OVERRIDE_NOTE),
@@ -7396,8 +7404,13 @@ them \u2014 except on a \`slot\`, whose children belong to whichever component f
7396
7404
  cannot be resolved at save time. \`update_component\` REPLACES the whole \`props\` array, so echo
7397
7405
  back each prop's stored \`ui\` or you delete it along with the prop. Props have no fieldsets, so a
7398
7406
  prop joins a group with \`ui.group\`: the FIRST prop of a group defines \`{ id, label, kind?, icon?,
7399
- collapsed? }\` (kind \`group\` or \`row\`, never \`tab\`), and every later prop sends \`{ id }\` only. A
7400
- FIELD never takes \`ui.group\`; it joins a fieldset with \`fieldsetId\`.
7407
+ collapsed? }\` (kind \`group\` or \`row\`; a tab is \`ui.tab\`, never a group kind), and every later prop
7408
+ sends \`{ id }\` only. A prop joins a TAB with \`ui.tab\` the same way: the FIRST top-level prop in a tab
7409
+ defines \`{ id, label, icon?, order? }\`, later props send \`{ id }\`; at most 8 tabs, labels \u226420 characters
7410
+ and unique; top-level props only (never a sub-field); all members of one \`ui.group\` share one tab. A V2
7411
+ kit entry's schema \`groups\` and each field's \`group\` map 1:1 to \`ui.tab\`, so its \`design\` group is a
7412
+ tab named Design holding the theme, sticky and similar props. A FIELD never takes \`ui.group\` or
7413
+ \`ui.tab\`; it joins a fieldset with \`fieldsetId\`.
7401
7414
 
7402
7415
  \`\`\`jsonc
7403
7416
  { "key": "slides", "label": "Slides", "type": "table",
@@ -7466,13 +7479,13 @@ Importance orders a screen: required fields first, then array order.
7466
7479
  | A star rating | \`type: 'rating'\`: a number from 0 to \`config.max\` (5), \`config.step\` 1 or 0.5 (\`rating_value_invalid\`) |
7467
7480
  | A code snippet | \`type: 'code'\`: \`{ language?, code }\` or a string; \`config.language\` default, \`config.languages\` allowlist (\`code_value_invalid\`) |
7468
7481
  | "Add question" instead of "Add item" | \`ui.itemLabel: 'Question'\` (V2 \`itemNoun\`; there is no itemNoun key) |
7469
- | The same section as a component (the dock edits a page section through its props) | the same keys on its \`props\`: \`type: 'object'\` with \`config.fields\` (\`group\` and \`table\` too, 10 levels), \`datetime\`, \`slug\`, \`email\`, \`phone\`, \`json\`, \`location\`, \`tags\`, \`rating\`, \`code\`, plus the two CMS-item types (\`reference\`, \`multi-reference\`: \`config.contentModelId\` or \`polymorphic\` + \`allowedModelSlugs\`; page reads hydrate them, a text slot shows the title), and every key above except fieldsets (props group with \`ui.group\`) |
7482
+ | The same section as a component (the dock edits a page section through its props) | the same keys on its \`props\`: \`type: 'object'\` with \`config.fields\` (\`group\` and \`table\` too, 10 levels), \`datetime\`, \`slug\`, \`email\`, \`phone\`, \`json\`, \`location\`, \`tags\`, \`rating\`, \`code\`, plus the two CMS-item types (\`reference\`, \`multi-reference\`: \`config.contentModelId\` or \`polymorphic\` + \`allowedModelSlugs\`; page reads hydrate them, a text slot shows the title), and every key above except fieldsets (props group with \`ui.group\` and tab with \`ui.tab\`) |
7470
7483
 
7471
7484
  An unknown \`openMode\` is refused with \`openMode_invalid\`, one on a leaf \`openMode_leaf\`; a bad \`config.scale\` with \`scale_invalid\`; more than 10 nested field levels with \`field_depth_exceeded\`. update_field sets and clears (null) helpMore, advanced, recommendedMax and openMode on an existing field.
7472
7485
 
7473
7486
  **Tabs.** A \`kind: 'tab'\` fieldset is a tab:
7474
7487
  - at most **3** tabs, names at most 20 characters and unique;
7475
- - top-level fields only: tabs never nest and props never take them;
7488
+ - top-level fields only: tabs never nest (a component's props take tabs through \`ui.tab\`, its own rules);
7476
7489
  - untabbed fields stay PINNED above the strip;
7477
7490
  - a group or row fieldset joins a tab with \`tab: '<tab id>'\`; groups in a non-first tab default open;
7478
7491
  - with fewer than 2 non-empty tabs no strip renders, so a tab for one fieldset is noise.
@@ -7491,7 +7504,7 @@ An unknown \`openMode\` is refused with \`openMode_invalid\`, one on a leaf \`op
7491
7504
  \`fieldLabel\`, \`fieldHelpText\` (keyed by dotted key path, \`'hero.title'\`) and \`fieldsets\`. A page's
7492
7505
  schema: the same call with \`pageId\` instead of \`modelId\`, and the version from \`get_page\`'s
7493
7506
  \`backingModel\`.
7494
- - A component's props: \`update_component\` with \`propUi\`, \`propGroup\`, \`propLabel\`, \`propHelpText\` (keyed by prop key).
7507
+ - A component's props: \`update_component\` with \`propUi\`, \`propGroup\`, \`propTab\`, \`propLabel\`, \`propHelpText\` (keyed by prop key).
7495
7508
  Name props from the code (\`plan.cents\` \u2192 Cents); help text guides ("Whole number, no currency symbol."), never repeats
7496
7509
  the value; repeated cards are one \`table\` prop. An icon (\`config.media: "icon"\`) is content: group it, never prune it.
7497
7510
  They write the DRAFT props; no publish is needed for the editor to show them.
@@ -7504,6 +7517,8 @@ An unknown \`openMode\` is refused with \`openMode_invalid\`, one on a leaf \`op
7504
7517
  - **409** \`ui_human_owned\` \u2014 a person shaped those paths. Leave them, or send \`override: true\`, and
7505
7518
  only when the user said so.
7506
7519
  - \`tab_unknown\`, \`tab_nested\`, \`tab_props\`, \`tab_max\`, \`tab_name\`, \`tab_depth\` \u2014 the tab rules above.
7520
+ - \`prop_tab_unknown\`, \`prop_tab_redefined\`, \`prop_group_split_tabs\` \u2014 a prop's \`ui.tab\` rules (\`tab_max\`,
7521
+ \`tab_name\` and \`tab_nested\` too); \`tab_props\` is a \`ui.group\` with \`kind: 'tab'\` \u2014 use \`ui.tab\`.
7507
7522
  - \`fieldset_unknown\` / \`fieldset_orphan\` \u2014 a \`fieldsetId\` naming no fieldset, or a list that drops a
7508
7523
  fieldset its fields still name.
7509
7524
  - \`row_member_type\`, \`row_member_count\`, \`row_member_control\` \u2014 the row rule.
@@ -7629,7 +7644,7 @@ shape, then ask me, once and batched). Icon names are in bettercms://icons/dock.
7629
7644
  - fields that exist: \`update_content_model\` fieldUi / fieldFieldset / fieldOrder / fieldLabel /
7630
7645
  fieldHelpText by field path, plus \`fieldsets\`. A singleton page: send \`pageId\` instead of
7631
7646
  modelId, with its backingModel's version;
7632
- - component props: \`update_component\` propUi / propGroup / propLabel / propHelpText;
7647
+ - component props: \`update_component\` propUi / propGroup / propTab / propLabel / propHelpText;
7633
7648
  - a NEW field: ui / helpText / showIf in the same \`add_field\` call, with \`after\`.
7634
7649
  A 409 \`ui_human_owned\` names chrome a person set: leave it, or ask me and send \`override: true\`
7635
7650
  only on my word.