@bettercms-ai/mcp 0.86.0 → 0.87.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
|
@@ -3116,7 +3116,9 @@ var WEBHOOK_EVENTS = [
|
|
|
3116
3116
|
"content.created",
|
|
3117
3117
|
"content.updated",
|
|
3118
3118
|
"content.deleted",
|
|
3119
|
-
"deployment.triggered"
|
|
3119
|
+
"deployment.triggered",
|
|
3120
|
+
"branch.created",
|
|
3121
|
+
"branch.applied"
|
|
3120
3122
|
];
|
|
3121
3123
|
var NEW_TOOL_TEXT = {
|
|
3122
3124
|
save_reusable_block: "Copy a page section (its layout, values and design) into Saved blocks in the section library, under `name`. The page is not changed; a block placed from Saved blocks is an independent section.",
|
|
@@ -3130,12 +3132,12 @@ var NEW_TOOL_TEXT = {
|
|
|
3130
3132
|
create_webhook: "Create an outgoing webhook: BetterCMS POSTs each subscribed event to your https `url`, signed with HMAC-SHA256 in X-BetterCMS-Signature. The response carries the signing `secret` ONCE: store it now. `test: true` also sends a sample delivery. Payloads carry ids and metadata, never the content: fetch it from the API. A receiver that writes back on content.updated loops unless it skips its own writes.",
|
|
3131
3133
|
list_branches: "List the project's content branches (id, name, slug, parent, status, whether main) and the `currentBranchId` this connection is on. To work inside a branch, pass its id as `branchId` on any tool call; apply_branch merges it into its parent.",
|
|
3132
3134
|
create_branch: "Create a content branch: a copy of the project's content to edit without touching the live site. Returns the branch; pass its id as `branchId` on later calls to work in it, then apply_branch. 409 means the name or slug is taken.",
|
|
3133
|
-
apply_branch: "Merge a branch into its parent. dryRun: true returns the diff (changes, summary, conflicts) and writes nothing: ALWAYS read it and show the user first. `include` limits the merge to those change keys; `fields` resolves a conflicting field per change key ('keep_branch' or 'keep_parent'). 409 names unresolved conflicts, missing dependencies, or a merge already running.",
|
|
3135
|
+
apply_branch: "Merge a branch into its parent. dryRun: true returns the diff (changes, summary, conflicts) and writes nothing: ALWAYS read it and show the user first. `include` limits the merge to those change keys; `fields` resolves a conflicting field per change key ('keep_branch' or 'keep_parent'). `publish: true` takes the merged changes live in the same call; `scheduleAt` merges everything and publishes at that time instead (null cancels). Both need a branch made from main and a connection allowed to publish. 409 names unresolved conflicts, missing dependencies, or a merge already running.",
|
|
3134
3136
|
search_docs: "Search the BetterCMS documentation. Returns the best pages (title, url, breadcrumbs, snippet). Use it before guessing how a feature works; `meta.unavailable` means docs search is down right now.",
|
|
3135
3137
|
generate_image: "Generate an image with AI and add it to the Media Library (5 AI credits; free with the workspace's own Together key). `width`/`height` are 256-1440 in multiples of 16 (default 1024x768). Returns the new asset (id, url, altText): use the url as an 'image' field value. Always set `altText`.",
|
|
3136
3138
|
refresh_search_index: "Tell search engines and site search about published changes; costs nothing. action 'indexnow' submits `urls` (this site's own, up to 1000) to IndexNow, or every change since the last submission when omitted. action 'reindex' rebuilds the project's site-search index. 503 means the index is unreachable: try again later.",
|
|
3137
3139
|
import_redirects: "Bulk-create redirects for a migration, from `rows` or from `text` in `format` (our CSV export, a Netlify `_redirects` file, or a vercel.json). Call it with `dryRun: true` FIRST: nothing is written and each row comes back `would-create`, `existing` or `skipped` with a reason. Rows get create_redirect's rules. Max 5000.",
|
|
3138
|
-
editor_setup: "Make the live build editable: derives pages, collections, forms, bindings and components from the live release (skill bindings). Run it after an import or a rebuild, before the conversion brief. Idempotent: `ready`
|
|
3140
|
+
editor_setup: "Make the live build editable: derives pages, collections, forms, bindings and components from the live release (skill bindings). Run it after an import or a rebuild, before the conversion brief. Idempotent: `ready` if already run for the live sha, else starts (`running`; poll with `check: true`). `state`: never or stale (run it), running, ready, failed. 409: deploy first. Then get_next_steps. `setup.naming`: skill editor-chrome.",
|
|
3139
3141
|
get_editable_plan: "Choices the platform can't make alone: `rows`, `options`, `recommended`. Explore the site per row: if confident, answer via confirm_editable_plan and tell the owner; if unsure, ask the owner in chat, recommended first. Never finish with an unsure one unasked.",
|
|
3140
3142
|
confirm_editable_plan: "Record answers: each `decisions` item is an option's `decision`, unchanged. `check: true` = dry run.",
|
|
3141
3143
|
transform_image: "Edit an existing Media Library image with an instruction (e.g. 'remove the background', 'make it dusk'); the result is saved as a NEW asset and the original is kept (5 AI credits). Returns the new asset (id, url, altText).",
|
|
@@ -3153,11 +3155,11 @@ var NEW_TOOL_TEXT = {
|
|
|
3153
3155
|
install_integration_template: "Install a workspace template on this project: missing collections are created and the integration waits for approval (`approval.approveUrl`); `secretsNeeded` lists the env vars to set.",
|
|
3154
3156
|
test_integration_fetch: "Call the vendor once through the server, as the integration: an approved host only, with the integration's `inject` secrets added server-side and every secret redacted from the answer. The request itself takes no {{...}} templates, and the token endpoint cannot be called. Use it to read the response shape before writing a sync: `items`, `externalKey` and `map` are JSON Pointers into it. Bodies over 1 MB come back truncated. 409 integration_not_approved: an admin must approve it first.",
|
|
3155
3157
|
// CMS-stored custom dock UI: write → approve (the user's yes) → validate → publish. Recipe: skill dock-input.
|
|
3156
|
-
write_dock_ui: "Save a custom dock input or panel (one .tsx `source`) as a new DRAFT version of `name` (a letter, then [a-z0-9-], \u226448), what `cms:<name>` imports resolve. Imports: react, react-dom, @bettercms-ai/kit/*, @bettercms-ai/dock-input, cms:<name>.
|
|
3158
|
+
write_dock_ui: "Save a custom dock input or panel (one .tsx `source`) as a new DRAFT version of `name` (a letter, then [a-z0-9-], \u226448), what `cms:<name>` imports resolve. Imports: react, react-dom, @bettercms-ai/kit/*, @bettercms-ai/dock-input, cms:<name>. Skill dock-input",
|
|
3157
3159
|
approve_dock_ui: "Approve the newest `version` for publishing. Show the user the source first; userApproved: true only after their yes. A later write drops it",
|
|
3158
|
-
validate_dock_ui: "Check one version (default newest) without publishing:
|
|
3159
|
-
publish_dock_ui: "Publish an APPROVED version (default newest)
|
|
3160
|
-
list_dock_ui: "The project's dock UI sources
|
|
3160
|
+
validate_dock_ui: "Check one version (default newest) without publishing: imports, size caps, a name the repo also has. Answers the build receipt",
|
|
3161
|
+
publish_dock_ui: "Publish an APPROVED version (default newest); rebuilds the dock UI release. `notShown`: published, not drawn, and the fix to tell the user",
|
|
3162
|
+
list_dock_ui: "The project's dock UI sources (`notShown` when not drawn), usage, limits",
|
|
3161
3163
|
// A V2 TypeSchema into a model (lane fields, through a change set) or a component's props (lane props).
|
|
3162
3164
|
write_schema: "Write a kit V2 TypeSchema into a model (lane fields, as a change set; model: null creates) or a component's props (lane props). Run dryRun first: a write whose `loss` is not all in acceptLoss is refused schema.loss_not_accepted"
|
|
3163
3165
|
};
|
|
@@ -3184,6 +3186,7 @@ var PARAM_TEXT = {
|
|
|
3184
3186
|
componentIcon: "the block icon, a dock icon name; null clears. \xA73 of bettercms://playbook/schema",
|
|
3185
3187
|
componentTabs: "/kit tabs no top-level prop sits in: [{id,label,icon?,order?}]. \xA73 of bettercms://playbook/schema",
|
|
3186
3188
|
componentKitEntry: "the bettercms://kit entry id its V2 dock UI follows, confirmed by you: import only SUGGESTS one, so check its htmlSignals and pitfalls first (kit_entry_unknown otherwise); null clears. The setup gate's dock row needs one",
|
|
3189
|
+
componentDock: "propOrder: each top-level prop key once; tabs 'none': no tab strip; design 'fold': Design under the content, 'tab': own tab; null resets",
|
|
3187
3190
|
describes: "for editors: what it is and holds; omitted: written for you",
|
|
3188
3191
|
runtimeBundle: "instead of pageId: the server-app bundle cleanup",
|
|
3189
3192
|
pageRef: "page id or path ('/de/about'); a bare slug only when one page has it",
|
|
@@ -3211,9 +3214,10 @@ var PARAM_TEXT = {
|
|
|
3211
3214
|
focalX: "focal point, 0-1 across from the left edge; null resets to the centre",
|
|
3212
3215
|
focalY: "focal point, 0-1 down from the top edge; null resets to the centre",
|
|
3213
3216
|
mergeHref: "pageId only: the link field paired with `path` (the label). Both become ONE `button` field keyed `key` (default: their stem, primaryCtaHref \u2192 primaryCta). Each entry's DRAFT gets {label, href} and keeps the old values; the live copy changes on publish. ifMatch is the page's version. 409 CODE_RENDERED_ROUTE: do its `next` recipe in code",
|
|
3214
|
-
confirmedInput: "true only after the user explicitly approved adding this custom input (`ui.input`)
|
|
3217
|
+
confirmedInput: "true only after the user explicitly approved adding this custom input (`ui.input`), or a hide/fold/required\u2192optional (else a named 409). Removing one needs no approval",
|
|
3215
3218
|
dockUiUserApproved: "true only after the user said yes to this version",
|
|
3216
3219
|
dockUiTarget: "per scope: field {modelId|pageId|componentId, path}, section {componentId}, page {pageId}, layout {}",
|
|
3220
|
+
dockUiAction: "unpublish: off the dock; delete: an unpublished source",
|
|
3217
3221
|
writeSchemaModel: "model or component id/slug; null creates a model",
|
|
3218
3222
|
writeSchemaAcceptLoss: "loss keys or paths you accept",
|
|
3219
3223
|
writeSchemaIfMatch: "the dry run's `version`; needed to write over a stored row"
|
|
@@ -3852,7 +3856,7 @@ var UPDATE_MODEL_DESCRIPTION = "Edit a content model: rename it, change descript
|
|
|
3852
3856
|
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.";
|
|
3853
3857
|
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.";
|
|
3854
3858
|
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.";
|
|
3855
|
-
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).";
|
|
3859
|
+
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*, dock, override or a prop ui icon/itemLabel/group/tab (428 without).";
|
|
3856
3860
|
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";
|
|
3857
3861
|
var OVERRIDE_NOTE = "replace chrome a person set (otherwise 409 ui_human_owned names those paths). Send it only on the user's word.";
|
|
3858
3862
|
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";
|
|
@@ -4480,7 +4484,8 @@ function buildToolDefs(deps) {
|
|
|
4480
4484
|
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)"),
|
|
4481
4485
|
override: z.boolean().optional().describe(OVERRIDE_NOTE),
|
|
4482
4486
|
ifMatch: z.number().int().min(0).optional().describe(COMPONENT_IF_MATCH_NOTE),
|
|
4483
|
-
confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput)
|
|
4487
|
+
confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),
|
|
4488
|
+
dock: z.object({ propOrder: z.array(z.string().min(1)).optional(), tabs: z.enum(["none"]).nullable().optional(), design: z.enum(["tab", "fold"]).nullable().optional() }).strict().optional().describe(PARAM_TEXT.componentDock)
|
|
4484
4489
|
});
|
|
4485
4490
|
const setComponentSourceInput = z.object({
|
|
4486
4491
|
componentId: z.string().min(1).describe("component id (from list_components)"),
|
|
@@ -4856,8 +4861,13 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
4856
4861
|
"publish_dock_ui",
|
|
4857
4862
|
"Publish custom dock UI",
|
|
4858
4863
|
NEW_TOOL_TEXT.publish_dock_ui,
|
|
4859
|
-
z.object({ name: dockUiName, version: z.number().int().min(1).optional() }).shape,
|
|
4860
|
-
async (c, a) =>
|
|
4864
|
+
z.object({ name: dockUiName, version: z.number().int().min(1).optional(), action: z.enum(["unpublish", "delete"]).optional().describe(PARAM_TEXT.dockUiAction) }).shape,
|
|
4865
|
+
async (c, a) => {
|
|
4866
|
+
const at = `/management/dock-ui/${encodeURIComponent(s(a.name))}`;
|
|
4867
|
+
if (a.action === "unpublish") return ok("Unpublished the dock UI source.", await data(c, "POST", `${at}/unpublish`, {}));
|
|
4868
|
+
if (a.action === "delete") return ok("Deleted the dock UI source.", await data(c, "DELETE", at));
|
|
4869
|
+
return ok("Published the dock UI version.", await data(c, "POST", `${at}/publish`, { version: a.version }));
|
|
4870
|
+
}
|
|
4861
4871
|
),
|
|
4862
4872
|
def(
|
|
4863
4873
|
"list_dock_ui",
|
|
@@ -5694,9 +5704,11 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
5694
5704
|
branchId: z.string().min(1).describe("the branch to merge (from list_branches)"),
|
|
5695
5705
|
dryRun: z.boolean().optional().describe("true = return the diff and write nothing"),
|
|
5696
5706
|
include: z.array(z.string().min(1)).max(500).optional().describe("change keys to merge (from the diff); all when omitted"),
|
|
5697
|
-
fields: z.record(z.string(), z.record(z.string(), z.enum(["keep_branch", "keep_parent"]))).optional().describe("change key \u2192 field \u2192 'keep_branch' | 'keep_parent', for each conflict")
|
|
5707
|
+
fields: z.record(z.string(), z.record(z.string(), z.enum(["keep_branch", "keep_parent"]))).optional().describe("change key \u2192 field \u2192 'keep_branch' | 'keep_parent', for each conflict"),
|
|
5708
|
+
publish: z.boolean().optional().describe("true = also take the merged changes live, in the same call (a branch made from main)"),
|
|
5709
|
+
scheduleAt: z.string().datetime({ offset: true }).nullable().optional().describe("ISO time to merge everything and publish then, instead of now; null cancels a schedule")
|
|
5698
5710
|
}).shape,
|
|
5699
|
-
async (c, a) => a.dryRun === true ? ok("Branch diff (nothing was written).", await data(c, "GET", `/management/branches/${s(a.branchId)}/diff`)) : ok("Branch applied.", await c.fetchJSON(c.url(`/management/branches/${s(a.branchId)}/apply`), { method: "POST", body: JSON.stringify({ include: a.include, fields: a.fields }) }))
|
|
5711
|
+
async (c, a) => a.dryRun === true ? ok("Branch diff (nothing was written).", await data(c, "GET", `/management/branches/${s(a.branchId)}/diff`)) : a.scheduleAt !== void 0 ? ok(a.scheduleAt ? "Branch scheduled." : "Branch unscheduled.", await data(c, "PUT", `/management/branches/${s(a.branchId)}/schedule`, { at: a.scheduleAt })) : ok(a.publish ? "Branch applied and published." : "Branch applied.", await c.fetchJSON(c.url(`/management/branches/${s(a.branchId)}/apply`), { method: "POST", body: JSON.stringify({ include: a.include, fields: a.fields, publish: a.publish }) }))
|
|
5700
5712
|
),
|
|
5701
5713
|
def(
|
|
5702
5714
|
"search_docs",
|
|
@@ -6872,8 +6884,14 @@ ${lines.join("\n")}`, found);
|
|
|
6872
6884
|
},
|
|
6873
6885
|
handler: guard(
|
|
6874
6886
|
async (args) => withClient(async (client) => {
|
|
6875
|
-
const { componentId, ifMatch, confirmed, ...
|
|
6876
|
-
const
|
|
6887
|
+
const { componentId, ifMatch, confirmed, dock, ...rest } = args;
|
|
6888
|
+
const input = {
|
|
6889
|
+
...rest,
|
|
6890
|
+
...dock?.propOrder !== void 0 ? { propOrder: dock.propOrder } : {},
|
|
6891
|
+
...dock?.tabs !== void 0 ? { dockTabs: dock.tabs } : {},
|
|
6892
|
+
...dock?.design !== void 0 ? { dockDesign: dock.design } : {}
|
|
6893
|
+
};
|
|
6894
|
+
const res = confirmed === true || typeof input.kitEntry === "string" || dock !== void 0 ? await client.fetchJSON(client.url(`/management/components/${componentId}`), {
|
|
6877
6895
|
method: "PATCH",
|
|
6878
6896
|
body: JSON.stringify(input),
|
|
6879
6897
|
headers: { ...ifMatch !== void 0 ? { "If-Match": `W/"${ifMatch}"` } : {}, ...confirmedHeaders(confirmed) }
|