@bettercms-ai/mcp 0.84.0 → 0.84.2
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
|
@@ -2801,7 +2801,7 @@ function allKeys(fields) {
|
|
|
2801
2801
|
})
|
|
2802
2802
|
]);
|
|
2803
2803
|
}
|
|
2804
|
-
var CLEARABLE = ["helpText", "showIf", "ui", "placement", "readOnly", "lockReason", "helpMore", "advanced", "recommendedMax", "openMode", "localized"];
|
|
2804
|
+
var CLEARABLE = ["helpText", "showIf", "requiredIf", "compare", "ui", "placement", "readOnly", "lockReason", "helpMore", "advanced", "recommendedMax", "openMode", "localized"];
|
|
2805
2805
|
var SETTABLE = ["label", "required", ...CLEARABLE];
|
|
2806
2806
|
function mergeConfig(current, patch) {
|
|
2807
2807
|
const out = { ...current ?? {} };
|
|
@@ -2839,7 +2839,7 @@ function planFieldEdit(model, edit, callerIfMatch) {
|
|
|
2839
2839
|
}
|
|
2840
2840
|
const changes = SETTABLE.filter((k) => edit[k] !== void 0);
|
|
2841
2841
|
if (!retype && rename === void 0 && edit.config === void 0 && changes.length === 0) {
|
|
2842
|
-
return { ok: false, error: "Nothing to change: pass label, helpText, required, config, showIf, ui, placement, readOnly, lockReason, helpMore, advanced, recommendedMax, openMode, localized, type or key." };
|
|
2842
|
+
return { ok: false, error: "Nothing to change: pass label, helpText, required, config, showIf, requiredIf, compare, ui, placement, readOnly, lockReason, helpMore, advanced, recommendedMax, openMode, localized, type or key." };
|
|
2843
2843
|
}
|
|
2844
2844
|
const echo = helpTextEcho(edit.helpText, { label: edit.label ?? current.label, defaultValue: current.defaultValue });
|
|
2845
2845
|
if (echo) return { ok: false, error: echo };
|
|
@@ -3009,7 +3009,7 @@ var toolMeta = (name) => ALWAYS_LOADED.has(name) ? { "anthropic/alwaysLoad": tru
|
|
|
3009
3009
|
var TOOL_LOADING_INSTRUCTION = `TOOL SCHEMAS: a client with tool search lists most BetterCMS tools by name only. Before the first call to a tool whose schema you have not been shown, load it with the client's tool search, and load every tool the task needs in ONE search (for a renaming pass: update_field, update_content_model, update_component, list_components). A call made without the schema is refused by the client before it reaches BetterCMS ("Invalid tool parameters"): that is this, never a BetterCMS error, and never a reason to change the arguments.`;
|
|
3010
3010
|
|
|
3011
3011
|
// src/tool-text.ts
|
|
3012
|
-
var ADD_FIELD_DESCRIPTION = "Append ONE field to a content model (`modelId`) or to a page's schema (`pageId`) \u2014 additive, never overwrites; a key already in use is refused. For a section/zone add ONE 'group' (fixed block) or 'repeater' (repeating list) carrying its child `fields`, not the zone's inner fields as separate top-level fields. Pass `after` to insert it after an existing top-level field instead of at the end; key 'a.b' adds b inside group/repeater a (after: a sibling); `ui`, `helpText`, `showIf`, `placement` and `fieldsetId` declare how it presents in the editor \u2014 read them back with get_content_model or get_page. On a page a 'group' is stored as type 'array' with `config.zones.nonRepeatable`: entry and delivery data carry `<key>.nonRepeatable.<sub>`, while data-bcms-field paths are `<key>.<sub>`. Schema only \u2014 never places a section; use componentize_sections to turn a group into a section. `multiselect` stores a string[] of `config.options`; `icon` is a BetterCMS icon name or an uploaded icon. To change a field that exists, use update_field. V2 keys (object, openMode, advanced, helpMore, recommendedMax, config.scale): \xA714 of bettercms://playbook/schema.";
|
|
3012
|
+
var ADD_FIELD_DESCRIPTION = "Append ONE field to a content model (`modelId`) or to a page's schema (`pageId`) \u2014 additive, never overwrites; a key already in use is refused. For a section/zone add ONE 'group' (fixed block) or 'repeater' (repeating list) carrying its child `fields`, not the zone's inner fields as separate top-level fields. Pass `after` to insert it after an existing top-level field instead of at the end; key 'a.b' adds b inside group/repeater a (after: a sibling); `ui`, `helpText`, `showIf`, `placement` and `fieldsetId` declare how it presents in the editor \u2014 read them back with get_content_model or get_page. On a page a 'group' is stored as type 'array' with `config.zones.nonRepeatable`: entry and delivery data carry `<key>.nonRepeatable.<sub>`, while data-bcms-field paths are `<key>.<sub>`. Schema only \u2014 never places a section; use componentize_sections to turn a group into a section. `multiselect` stores a string[] of `config.options`; `icon` is a BetterCMS icon name or an uploaded icon. To change a field that exists, use update_field. V2 keys (object, openMode, advanced, helpMore, recommendedMax, config.scale): \xA714 of bettercms://playbook/schema. Cross-field: `requiredIf` (showIf's shape) and `compare` [{op:gt|gte|lt|lte|eq|neq, field, message?}].";
|
|
3013
3013
|
var V2_LEAF_TYPES_NOTE = "`tags`: string[] taxonomy (config.options suggestions, max, allowCustom). `rating`: 0..config.max (5), step 1|0.5. `code`: {language?, code} or a string (config.languages).";
|
|
3014
3014
|
var MOVE_STAGE_DESCRIPTION = "Move a content entry (`entryId`) or a page (`pageId`) to another editorial stage \u2014 this is how you take it OUT of review so it can be published. `workflowStage` is a stage key from get_workflow_board; pass `fromStage` to 409 if someone moved it first. Moving into the publish-gate stage is an approval and needs a publish-enabled connection. Publish afterwards with update_content_entry or update_page status:'published' \u2014 approving and publishing are deliberately two separate calls.";
|
|
3015
3015
|
var WINDOW_NOTE = "{from?, until?}, ISO 8601 with offset: shown only between the two instants; null clears (skill publishing).";
|
|
@@ -3135,7 +3135,7 @@ var INTEGRATION_PARAM_TEXT = {
|
|
|
3135
3135
|
var INPUT_CONFIRMED_HEADER = "x-bcms-confirmed-input";
|
|
3136
3136
|
var BUTTON_FIELD_NOTE = "'button' is ONE call to action, value {label, href, variant? (a Button family look), size?, arrow?, icon?, newTab?, rel?, fullWidth?} (arrow:false, icon:null off): never a text field beside a link field.";
|
|
3137
3137
|
var LINK_VALUE_NOTE = "A link or button href: a URL string or {type: url|page|entry|email|phone|anchor|file, href, title?, newTab?, rel?, section?, ref: page/entry id}.";
|
|
3138
|
-
var UPDATE_FIELD_DESCRIPTION = "Change ONE existing field of a content model (`modelId`) or of a page's schema (`pageId`), addressed by `path`: its key, or dot-separated keys through groups and repeaters ('hero.title'). Set its label, helpText, required, validation `config` (merged by key; null deletes one), showIf, ui, placement, readOnly, lockReason, or the V2 helpMore, advanced, recommendedMax and openMode (null clears those). The rest of the schema is written back unchanged at the version read; a 409 means it changed since, so read again. `type` changes how every stored value is read and needs allowRetype: true. `key` renames it: stored values stay under the old key, so the route answers 409 with the entry count unless allowFieldRemoval: true discards them \u2014 migrate the values first. Ask the user before a retype or a rename. A page's label + link pair (primaryCtaText + primaryCtaHref) becomes one button with `mergeHref`.";
|
|
3138
|
+
var UPDATE_FIELD_DESCRIPTION = "Change ONE existing field of a content model (`modelId`) or of a page's schema (`pageId`), addressed by `path`: its key, or dot-separated keys through groups and repeaters ('hero.title'). Set its label, helpText, required, validation `config` (merged by key; null deletes one), showIf, requiredIf, compare, ui, placement, readOnly, lockReason, or the V2 helpMore, advanced, recommendedMax and openMode (null clears those). The rest of the schema is written back unchanged at the version read; a 409 means it changed since, so read again. `type` changes how every stored value is read and needs allowRetype: true. `key` renames it: stored values stay under the old key, so the route answers 409 with the entry count unless allowFieldRemoval: true discards them \u2014 migrate the values first. Ask the user before a retype or a rename. A page's label + link pair (primaryCtaText + primaryCtaHref) becomes one button with `mergeHref`.";
|
|
3139
3139
|
var GET_SEO_DESCRIPTION = "Get the connected project's site-wide SEO settings \u2014 every key update_seo writes: seoDefaults (metaTitle, metaDescription, ogImage, twitterHandle, og, twitter, collectionSchemaTypes), siteSchema (the site's JSON-LD), robotsConfig, sitemapConfig, rssConfig, indexnowConfig and searchConfig.";
|
|
3140
3140
|
var UPDATE_SEO_DESCRIPTION = "Set the connected project's site-wide SEO defaults and config. Each key you send is REPLACED whole (not deep-merged), so read get_seo and send the complete object. `seoDefaults` applies to every page that does not override it, and its `collectionSchemaTypes` maps a collection's model id to the schema.org type of its entries. `siteSchema` is the site's own JSON-LD (Organization/WebSite, emitted on the home page). `robotsConfig`, `sitemapConfig` and `rssConfig` shape robots.txt, sitemap.xml and the feed; `indexnowConfig` pings search engines on publish; `searchConfig` is site search. A key the plan does not include answers 403 FEATURE_LOCKED. Rebuilds the site.";
|
|
3141
3141
|
var SEO_KEY_TEXT = {
|
|
@@ -3401,6 +3401,16 @@ var OPEN_MODE_INVALID = "openMode_invalid: openMode must be one of 'inline', 'dr
|
|
|
3401
3401
|
var slug = z.string().regex(/^[a-z0-9-]+$/, "lowercase letters, numbers, and hyphens only");
|
|
3402
3402
|
var fieldKey = z.string().regex(/^[a-zA-Z0-9_-]+$/, "letters, numbers, underscores, and hyphens only");
|
|
3403
3403
|
var dockIconArg = z.string().min(1).max(40).refine((v) => DOCK_ICON_SET.has(v), `not a dock icon, see ${DOCK_ICONS_URI}`);
|
|
3404
|
+
var fieldCondition = z.object({
|
|
3405
|
+
match: z.enum(["all", "any"]),
|
|
3406
|
+
rules: z.array(
|
|
3407
|
+
z.object({
|
|
3408
|
+
field: z.string().describe("the BARE KEY of another field on this same model"),
|
|
3409
|
+
op: z.enum(["eq", "neq", "in", "notIn", "gt", "lt", "isSet", "notEmpty", "empty"]),
|
|
3410
|
+
value: z.union([z.string(), z.array(z.string())]).optional().describe(`omit for 'isSet'/'notEmpty' (the source holds any value) and 'empty' (it holds none); 'gt'/'lt' take one number as a string ("10"); required for every other op`)
|
|
3411
|
+
})
|
|
3412
|
+
)
|
|
3413
|
+
});
|
|
3404
3414
|
var uiObject = z.strictObject({
|
|
3405
3415
|
collapsed: z.boolean().optional().describe("start this panel collapsed. Use it for long optional sections."),
|
|
3406
3416
|
preview: z.strictObject({
|
|
@@ -3489,18 +3499,17 @@ var fieldShape = {
|
|
|
3489
3499
|
// below did not model them, so they were stripped after the model had gone to the trouble of
|
|
3490
3500
|
// sending them. Declaring them here is what makes the existing panel agent-writable.
|
|
3491
3501
|
helpText: z.string().max(500).optional().describe(PARAM_TEXT.helpText),
|
|
3492
|
-
showIf:
|
|
3493
|
-
match: z.enum(["all", "any"]),
|
|
3494
|
-
rules: z.array(
|
|
3495
|
-
z.object({
|
|
3496
|
-
field: z.string().describe("the BARE KEY of another field on this same model"),
|
|
3497
|
-
op: z.enum(["eq", "neq", "in", "notIn", "gt", "lt", "isSet", "notEmpty", "empty"]),
|
|
3498
|
-
value: z.union([z.string(), z.array(z.string())]).optional().describe(`omit for 'isSet'/'notEmpty' (the source holds any value) and 'empty' (it holds none); 'gt'/'lt' take one number as a string ("10"); required for every other op`)
|
|
3499
|
-
})
|
|
3500
|
-
)
|
|
3501
|
-
}).optional().describe(
|
|
3502
|
+
showIf: fieldCondition.optional().describe(
|
|
3502
3503
|
"conditional visibility \u2014 hide this field until another field has a given value (e.g. show `external_url` only when `link_type` is 'external'). Admin-only: it changes what an author SEES, never what is stored or delivered. Rules reference fields by BARE KEY, and the key namespace is flat, so the key must exist on this model."
|
|
3503
3504
|
),
|
|
3505
|
+
requiredIf: fieldCondition.optional().describe("required only while this condition holds (showIf's shape), e.g. `address` when `delivery` eq 'ship'. Enforced on every entry write."),
|
|
3506
|
+
compare: z.array(
|
|
3507
|
+
z.object({
|
|
3508
|
+
op: z.enum(["gt", "gte", "lt", "lte", "eq", "neq"]),
|
|
3509
|
+
field: z.string().describe("the BARE KEY of the field to compare against"),
|
|
3510
|
+
message: z.string().max(200).optional().describe("the error an author reads; a default names both fields")
|
|
3511
|
+
})
|
|
3512
|
+
).max(10).optional().describe("this value against another field's, as numbers, dates or text, e.g. `end_date` [{op:'gte', field:'start_date'}]. Not judged while either is empty. Enforced on every entry write."),
|
|
3504
3513
|
ui: uiObject.optional().describe(
|
|
3505
3514
|
"AUTHORING CHROME \u2014 how this field presents in the editor; never a delivery effect. `preview` slots name a CHILD FIELD KEY and must name real children, or the write is refused with the valid keys listed. `preview`/`layout` need a nesting field, `reorderable` needs a list, and an unknown key inside `ui` is a 400, not a silent strip. No `order`: field order is the array index \u2014 use `after`. Section 14 of bettercms://playbook/schema has each key and where it is legal."
|
|
3506
3515
|
),
|
|
@@ -3661,6 +3670,8 @@ function toField(f) {
|
|
|
3661
3670
|
...f.required !== void 0 ? { required: f.required } : {},
|
|
3662
3671
|
...f.helpText !== void 0 ? { helpText: f.helpText } : {},
|
|
3663
3672
|
...f.showIf !== void 0 ? { showIf: f.showIf } : {},
|
|
3673
|
+
...f.requiredIf !== void 0 ? { requiredIf: f.requiredIf } : {},
|
|
3674
|
+
...f.compare !== void 0 ? { compare: f.compare } : {},
|
|
3664
3675
|
...f.ui !== void 0 ? { ui: f.ui } : {},
|
|
3665
3676
|
// G5: these four persist on the backend and were stripped here, like helpText once was.
|
|
3666
3677
|
...f.fieldsetId !== void 0 ? { fieldsetId: f.fieldsetId } : {},
|
|
@@ -5176,6 +5187,8 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
5176
5187
|
required: z.boolean().optional(),
|
|
5177
5188
|
config: z.record(z.string(), z.unknown()).optional().describe("per-type validation/config keys, merged into the stored config; null deletes a key"),
|
|
5178
5189
|
showIf: z.record(z.string(), z.unknown()).nullable().optional().describe("same shape as on add_field; null clears it"),
|
|
5190
|
+
requiredIf: z.record(z.string(), z.unknown()).nullable().optional().describe("same shape as on add_field; null clears it"),
|
|
5191
|
+
compare: z.array(z.record(z.string(), z.unknown())).nullable().optional().describe("same shape as on add_field; null clears it"),
|
|
5179
5192
|
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"),
|
|
5180
5193
|
placement: z.enum(["cover", "title", "excerpt", "body", "inline", "panel"]).nullable().optional(),
|
|
5181
5194
|
readOnly: z.union([z.literal(true), z.literal("developer")]).nullable().optional().describe(PARAM_TEXT.lockClears),
|