@bettercms-ai/mcp 0.73.0 → 0.73.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
@@ -2989,6 +2989,7 @@ var PARAM_TEXT = {
2989
2989
  recommendedMax: "a SOFT limit (characters, items or value): the editor warns past it, never refuses",
2990
2990
  openMode: "object/array/group/repeater: how the value (or each row) opens: 'inline', 'drill', 'popover' or 'dialog'",
2991
2991
  fromBuiltin: "a builtin:* id from list_components: copies it into the project; fields you send win",
2992
+ componentPreview: "how ONE instance reads as a ROW in a parent's slot list (a /kit schema's document-level `preview`): {title?, subtitle?, media?} each a TOP-LEVEL prop key (422 preview_key_unknown otherwise), fallback? a literal row label (\u2264120), icon? a dock icon name. null clears it",
2992
2993
  describes: "for editors: what it is and holds; omitted: written for you",
2993
2994
  runtimeBundle: "instead of pageId: the server-app bundle cleanup",
2994
2995
  pageRef: "page id or path ('/de/about'); a bare slug only when one page has it",
@@ -3034,7 +3035,7 @@ var DETACHED_COPY_NOTE = "{overrides?}: a rich-text embed's separate-copy `field
3034
3035
  var UNPROPPED_COPY_NOTE = "A `warnings` entry UNPROPPED_COPY names copy no prop targets, which nobody can edit: add a prop with a `target` for each leaf it lists.";
3035
3036
  var UPDATE_PAGE_IF_MATCH_NOTE = "get_page's `optimisticVersion`: the write applies only at that version, and a 409 means the page changed since, so read it again. Send it whenever you pass blockJson, which REPLACES the whole composition.";
3036
3037
  var SLOT_MULTIPLE_NOTE = "'slot' with config.multiple holds a list [{componentId, overrides?}] (config.maxItems, default 12, at most 50): target.path 'props.children' on a section. V2 slots, 'table' mode 'types': playbook \xA75.";
3037
- var PROP_V2_NOTE = "Props take the fields' V2 keys (\xA714): 'object' = ONE {child: value} from config.fields, \u226410 levels (field_depth_exceeded); datetime|slug|email|phone|json|location|tags|rating|code|reference|multi-reference as that field (a reference names contentModelId, or polymorphic + allowedModelSlugs; page reads hydrate its entries); helpMore, advanced, recommendedMax, openMode, config.scale, ui.layout rows|chips|gallery, ui.preview.fallback, showIf notEmpty|empty.";
3038
+ var PROP_V2_NOTE = "Props take the fields' V2 keys (\xA714): 'object' = ONE {child: value} from config.fields, \u226410 levels (field_depth_exceeded); datetime|slug|email|phone|json|location|tags|rating|code|reference|multi-reference as that field (a reference names contentModelId, or polymorphic + allowedModelSlugs; page reads hydrate its entries); helpMore, advanced, recommendedMax, openMode, config.scale, ui.layout rows|chips|gallery, ui.preview.fallback, showIf notEmpty|empty. Send helpText: null for a prop whose /kit schema has no description (omitted, the platform writes one).";
3038
3039
  var LAYOUT_LOCK_NOTE = "A Global field with `overridable:false` + `lockReason` (add-field `field`, update-field `patch`) refuses page overrides (LAYOUT_FIELD_NOT_OVERRIDABLE); get_layout scope page lists stored ones as `shadowed`.";
3039
3040
 
3040
3041
  // src/entry-query.ts
@@ -3268,10 +3269,10 @@ var propUiObject = uiObject.extend({
3268
3269
  }).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
3270
  tab: z.strictObject({
3270
3271
  id: z.string().min(1).max(40),
3271
- label: z.string().min(1).max(20).optional(),
3272
+ label: z.string().min(1).max(40).optional(),
3272
3273
  icon: uiObject.shape.icon,
3273
3274
  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.")
3275
+ }).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 \u226440 chars and unique; a group's members share one tab.")
3275
3276
  });
3276
3277
  var choiceOption = z.union([z.string(), z.object({ label: z.string(), value: z.string(), icon: z.string().optional(), description: z.string().optional() })]);
3277
3278
  var fieldShape = {
@@ -3664,7 +3665,7 @@ var withProjectId = (def) => ({
3664
3665
  return currentProject.run(arg("projectId"), () => currentBranch.run(arg("branchId"), () => def.handler(args)));
3665
3666
  }
3666
3667
  });
3667
- 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.";
3668
+ var autoHelpNote = (args) => args.helpText === null || 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.";
3668
3669
  function buildToolDefs(deps) {
3669
3670
  async function withClient(fn) {
3670
3671
  const token = await deps.auth.getAccessToken();
@@ -3971,6 +3972,7 @@ function buildToolDefs(deps) {
3971
3972
  // 'select' — required, choices
3972
3973
  // 'group'/'table'/'object' sub-shape. Typed loosely here (the server validates the full
3973
3974
  // recursive shape, 10 levels at most) so a deep tree needs no Zod mirror in the client.
3975
+ // A sub-field may be a 'slot' (its value at its key in the object or row), with the slot keys above.
3974
3976
  fields: z.array(z.record(z.string(), z.unknown())).optional(),
3975
3977
  min: z.number().optional(),
3976
3978
  // 'number'
@@ -3982,7 +3984,7 @@ function buildToolDefs(deps) {
3982
3984
  // override that omits it still saves — so it is a marker the dashboard renders and
3983
3985
  // get_site_composition counts, never a refusal. Parity: componentPropDefSchema on the server.
3984
3986
  required: z.boolean().optional().describe("mark the field required in the editor. An editor HINT: the API still accepts a placement that leaves it empty, and get_site_composition is what reports one."),
3985
- helpText: z.string().max(200).optional().describe("hint shown under the control, muted (\u2264 200 chars)"),
3987
+ helpText: z.string().max(200).nullable().optional().describe("hint shown under the control, muted (\u2264 200 chars). null = no help on purpose (a /kit schema with no description); omitted = the platform writes it"),
3986
3988
  placeholder: z.string().max(120).optional().describe("ghost text inside a text-ish control (\u2264 120 chars)"),
3987
3989
  // Stored markers on a prop: nothing refuses a prop value for them. Declared so an echo keeps them.
3988
3990
  readOnly: z.union([z.literal(true), z.literal("developer")]).optional(),
@@ -4071,6 +4073,13 @@ function buildToolDefs(deps) {
4071
4073
  "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."
4072
4074
  );
4073
4075
  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");
4076
+ const componentPreviewArg = z.strictObject({
4077
+ title: z.string().min(1).max(64).optional(),
4078
+ subtitle: z.string().min(1).max(64).optional(),
4079
+ media: z.string().min(1).max(64).optional(),
4080
+ fallback: z.string().min(1).max(120).optional(),
4081
+ icon: dockIconArg.optional()
4082
+ }).nullable().describe(PARAM_TEXT.componentPreview);
4074
4083
  const createComponentInput = z.object({
4075
4084
  name: z.string().min(1),
4076
4085
  slug: slug.describe("url-safe unique slug (lowercase letters/numbers/hyphens)"),
@@ -4082,6 +4091,7 @@ function buildToolDefs(deps) {
4082
4091
  projectId: z.string().nullable().optional().describe("owning project id; null creates a workspace-wide global component"),
4083
4092
  allowedOn: allowedOn.optional(),
4084
4093
  description: z.string().optional().describe(PARAM_TEXT.describes),
4094
+ preview: componentPreviewArg.optional(),
4085
4095
  blockJson: z.array(blockObject).default([]).describe("the component's block tree"),
4086
4096
  props: z.array(componentPropObject).default([]).describe(
4087
4097
  "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. 'button' is ONE unit {label, href, variant?, size?, arrow?, icon?, newTab?} on a button block's 'props', never a text prop plus a url prop. 'link' an href, 'date' YYYY-MM-DD, 'color' a hex, 'file' {url, name?}, 'icon' an icon name or an image, 'multiselect' a string[] from config.options (required). " + SLOT_MULTIPLE_NOTE + " " + PROP_V2_NOTE
@@ -4098,6 +4108,7 @@ function buildToolDefs(deps) {
4098
4108
  variantOf: z.string().min(1).max(255).optional().describe("see create_component"),
4099
4109
  allowedOn: allowedOn.optional().describe("REPLACES the placement allowlist"),
4100
4110
  description: z.string().optional(),
4111
+ preview: componentPreviewArg.optional(),
4101
4112
  blockJson: z.array(blockObject).optional().describe("REPLACES the block tree"),
4102
4113
  props: z.array(componentPropObject).optional().describe(
4103
4114
  "REPLACES the prop array \u2014 include every prop you want to keep, WITH its stored `ui`, or that prop's authoring chrome is dropped along with the prop. Read get_component first."
@@ -4106,7 +4117,7 @@ function buildToolDefs(deps) {
4106
4117
  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
4118
  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"),
4108
4119
  propLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe("prop key \u2192 label"),
4109
- propHelpText: z.record(z.string(), z.string().max(200).nullable()).optional().describe("prop key \u2192 help text, null clears it"),
4120
+ propHelpText: z.record(z.string(), z.string().max(200).nullable()).optional().describe("prop key \u2192 help text; null = no help on purpose (stays empty, never refilled)"),
4110
4121
  override: z.boolean().optional().describe(OVERRIDE_NOTE),
4111
4122
  ifMatch: z.number().int().min(0).optional().describe(COMPONENT_IF_MATCH_NOTE),
4112
4123
  confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput)
@@ -6529,8 +6540,11 @@ Then declare what an editor may change, via \`props\`:
6529
6540
  ]
6530
6541
 
6531
6542
  Each prop also takes \`required\`, \`helpText\` (\u2264 200 chars) and \`placeholder\` (\u2264 120), which the
6532
- dashboard's prop editor renders. They are HINTS: nothing on the write path refuses a placement
6543
+ dashboard's prop editor renders. \`helpText\` is three-state: a string is yours, \`null\` is no help on
6544
+ purpose (send it for a prop whose /kit schema has no description; nothing refills it), and omitted
6545
+ lets the platform write one. They are HINTS: nothing on the write path refuses a placement
6533
6546
  that leaves a required prop empty, so \`get_site_composition\` is what reports one.
6547
+ A /kit schema's document-level \`preview\` \u2192 the component's \`preview\` ({title?, subtitle?, media?} are top-level prop keys, plus \`fallback?\`, \`icon?\`); slot rows read it.
6534
6548
 
6535
6549
  \u{1F534} **On a components-first page, \`props\` is the ONLY editing surface.** Click-to-edit binds
6536
6550
  \`heading\`/\`text\`/\`button\`/\`image\` blocks; it does **not** bind a \`component\` block, because
@@ -6582,7 +6596,12 @@ A \`slot\` field (V2 blocks inside a block) takes the same \`config.blockSlugs\`
6582
6596
  but stores each child INLINE: \`[{ _key, _type: '<block slug>', _variant?, _settings?, ...values }]\`,
6583
6597
  its values judged by its block's fields. A component's \`slot\` prop with \`config.multiple\`
6584
6598
  takes the same child shape with \`_type\` the COMPONENT id (no \`_variant\`: a variant is its own
6585
- component). A list of several item shapes on a component is a \`table\` prop with
6599
+ component). A \`slot\` may also be a SUB-FIELD: inside a \`group\` / \`object\` prop's
6600
+ \`config.fields\` or a \`table\` row (an item type's \`fields\` too), with the slot prop's
6601
+ config keys (\`componentIds\`, \`multiple\`, \`minItems\`/\`maxItems\`, \`slotSettings\`). Its value
6602
+ sits at its key in the object or row, \`{ componentId, overrides? }\` or a list with
6603
+ \`config.multiple\`, judged like a slot prop's: the same allowlist, depth cap and cycle refusal.
6604
+ A list of several item shapes on a component is a \`table\` prop with
6586
6605
  \`config.mode: 'types'\` and \`config.itemTypes: [{ name, label?, fields }]\`, rows
6587
6606
  \`[{ _key?, _type: '<name>', ...values }]\`.
6588
6607
 
@@ -7038,8 +7057,10 @@ hints the dashboard renders \u2014 they are NOT enforced at write time, so an ov
7038
7057
  required prop still saves; \`get_site_composition\` is what reports those. Use \`select\` with
7039
7058
  \`config.options\` for layout / theme / alignment / spacing variants that change only styling,
7040
7059
  and a SEPARATE variant component when the markup differs. Repeatable list \u2192 \`table\`; fixed
7041
- cluster \u2192 \`group\`. Nesting is capped at TWO levels from the prop (a \`table\` row may hold a
7042
- \`table\`, and that inner row is scalars only). Flatten anything deeper.
7060
+ cluster \u2192 \`group\`. Nesting goes up to 10 levels counting the prop itself. A \`table\` row may hold a
7061
+ \`table\` (rows), a data table (\`config.mode: "data"\`) or a polymorphic list
7062
+ (\`config.mode: "types"\`), so a size guide's rows can each carry a chart and a multi-step
7063
+ form's steps can each carry their fields. Deeper is refused (\`field_depth_exceeded\`).
7043
7064
 
7044
7065
  **5. Design, responsiveness and accessibility.** \`componentize_sections\` and \`npx
7045
7066
  @bettercms-ai/convert --componentize\` move the section's markup VERBATIM \u2014 classes, responsive
@@ -7406,7 +7427,7 @@ back each prop's stored \`ui\` or you delete it along with the prop. Props have
7406
7427
  prop joins a group with \`ui.group\`: the FIRST prop of a group defines \`{ id, label, kind?, icon?,
7407
7428
  collapsed? }\` (kind \`group\` or \`row\`; a tab is \`ui.tab\`, never a group kind), and every later prop
7408
7429
  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
7430
+ defines \`{ id, label, icon?, order? }\`, later props send \`{ id }\`; at most 8 tabs, labels \u226440 characters
7410
7431
  and unique; top-level props only (never a sub-field); all members of one \`ui.group\` share one tab. A V2
7411
7432
  kit entry's schema \`groups\` and each field's \`group\` map 1:1 to \`ui.tab\`, so its \`design\` group is a
7412
7433
  tab named Design holding the theme, sticky and similar props. A FIELD never takes \`ui.group\` or
@@ -7484,7 +7505,7 @@ Importance orders a screen: required fields first, then array order.
7484
7505
  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.
7485
7506
 
7486
7507
  **Tabs.** A \`kind: 'tab'\` fieldset is a tab:
7487
- - at most **3** tabs, names at most 20 characters and unique;
7508
+ - at most **3** tabs, names at most 40 characters and unique;
7488
7509
  - top-level fields only: tabs never nest (a component's props take tabs through \`ui.tab\`, its own rules);
7489
7510
  - untabbed fields stay PINNED above the strip;
7490
7511
  - a group or row fieldset joins a tab with \`tab: '<tab id>'\`; groups in a non-first tab default open;
@@ -7766,7 +7787,7 @@ Read \`bettercms://playbook/schema\` \xA712 first \u2014 this is the short form
7766
7787
  4. **Fields** = \`props\`: text, richtext, image, url, boolean, number, select, group, table, slot.
7767
7788
  Always a \`defaultValue\`; \`required\` / \`helpText\` / \`placeholder\` are editor hints, not write
7768
7789
  -time enforcement. \`select\` for styling-only variants, a separate component when the markup
7769
- differs. Nesting is capped at two levels \u2014 flatten anything deeper.
7790
+ differs. Nesting goes up to 10 levels; a \`table\` row may hold a data table or a polymorphic list.
7770
7791
  5. **Quality.** The componentize lane and \`npx @bettercms-ai/convert --componentize\` move markup
7771
7792
  VERBATIM \u2014 classes, responsive utilities, aria attributes, alt text all survive. Never
7772
7793
  restyle. Dry-run first.