@bettercms-ai/mcp 0.67.3 → 0.68.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 +17 -11
- package/dist/index.js.map +1 -1
- package/dist/skills/bettercms/references/bindings.md +3 -0
- package/dist/skills/bettercms/references/componentize.md +4 -3
- package/dist/skills/bettercms/references/components.md +17 -0
- package/dist/skills/bettercms/references/content-modeling.md +30 -3
- package/dist/skills/bettercms/references/finish-site.md +1 -1
- package/dist/skills/bettercms/references/frameworks.md +7 -0
- package/dist/skills/bettercms/references/next.md +3 -0
- package/dist/skills/bettercms/references/site-review.md +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2694,6 +2694,8 @@ var NEW_TOOL_TEXT = {
|
|
|
2694
2694
|
};
|
|
2695
2695
|
var DELETE_PAGE_RUNTIME_BUNDLE = " Or, with no pageId, `runtimeBundle`: 'report' lists the duplicate pages derived from a server app's own bundle (`app/` folders); 'apply' retires them and their empty folders.";
|
|
2696
2696
|
var PARAM_TEXT = {
|
|
2697
|
+
helpText: "shown under the field: its purpose, where it shows, any constraint; never its label or value. Omitted: written for you.",
|
|
2698
|
+
describes: "for editors: what it is and holds; omitted: written for you",
|
|
2697
2699
|
runtimeBundle: "instead of pageId: the server-app bundle cleanup",
|
|
2698
2700
|
pageRef: "page id or path ('/de/about'); a bare slug only when one page has it",
|
|
2699
2701
|
editorSetupForce: "re-run a setup already ready for the live build",
|
|
@@ -2962,9 +2964,7 @@ var fieldShape = {
|
|
|
2962
2964
|
// builder. They were unreachable from MCP for ONE reason: the OutField/toField whitelist
|
|
2963
2965
|
// below did not model them, so they were stripped after the model had gone to the trouble of
|
|
2964
2966
|
// sending them. Declaring them here is what makes the existing panel agent-writable.
|
|
2965
|
-
helpText: z.string().max(500).optional().describe(
|
|
2966
|
-
"one line of guidance shown UNDER this field in the editor \u2014 what to write here, not what the field is. Write it for the person typing ('Roughly 60 characters; it becomes the browser tab title'), not for a developer."
|
|
2967
|
-
),
|
|
2967
|
+
helpText: z.string().max(500).optional().describe(PARAM_TEXT.helpText),
|
|
2968
2968
|
showIf: z.object({
|
|
2969
2969
|
match: z.enum(["all", "any"]),
|
|
2970
2970
|
rules: z.array(
|
|
@@ -3281,6 +3281,7 @@ var withProjectId = (def) => ({
|
|
|
3281
3281
|
return currentProject.run(arg("projectId"), () => currentBranch.run(arg("branchId"), () => def.handler(args)));
|
|
3282
3282
|
}
|
|
3283
3283
|
});
|
|
3284
|
+
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.";
|
|
3284
3285
|
function buildToolDefs(deps) {
|
|
3285
3286
|
async function withClient(fn) {
|
|
3286
3287
|
const token = await deps.auth.getAccessToken();
|
|
@@ -3382,7 +3383,7 @@ function buildToolDefs(deps) {
|
|
|
3382
3383
|
const createModelInput = z.object({
|
|
3383
3384
|
name: z.string().min(1).describe("human model name, e.g. 'Blog Post'"),
|
|
3384
3385
|
slug: slug.describe("url-safe unique slug, e.g. 'blog-post'"),
|
|
3385
|
-
description: z.string().optional(),
|
|
3386
|
+
description: z.string().optional().describe(PARAM_TEXT.describes),
|
|
3386
3387
|
urlPattern: urlPatternArg,
|
|
3387
3388
|
kind: z.enum(["model", "block"]).optional().describe(
|
|
3388
3389
|
"'model' (default) = a collection with its own entries. 'block' = a type that exists only to be stacked inside another model's 'modular' field \u2014 it holds no entries, and create_content_entry against it is refused. Create blocks FIRST, then the model whose modular field lists their slugs. Cannot be changed later."
|
|
@@ -3614,7 +3615,7 @@ function buildToolDefs(deps) {
|
|
|
3614
3615
|
z.object({ type: z.literal("set-section-state"), ...sectionTarget, state: z.enum(["inherit", "override-content", "customize-structure", "disable", "reset"]) }),
|
|
3615
3616
|
z.object({ type: z.literal("add-section"), name: z.string().min(1), icon: layoutIcon, zone: z.enum(["before_page", "after_page"]) }),
|
|
3616
3617
|
z.object({ type: z.literal("restore-section"), section: z.object({ id: z.string().min(1) }).passthrough(), data: z.object({ fields: z.record(z.string(), z.unknown()) }), placement: z.object({ zone: z.enum(["above-page-content", "below-page-content"]), localOrderKey: z.string().min(1), afterSectionId: z.string().optional(), beforeSectionId: z.string().optional() }).optional() }),
|
|
3617
|
-
z.object({ type: z.literal("update-section"), ...sectionTarget, name: z.string().min(1).optional(), icon: layoutIcon.optional(), slug: z.string().min(1).optional(), zone: z.enum(["above-page-content", "below-page-content"]).optional(), orderKey: z.string().min(1).optional() }),
|
|
3618
|
+
z.object({ type: z.literal("update-section"), ...sectionTarget, name: z.string().min(1).optional(), icon: layoutIcon.optional(), slug: z.string().min(1).optional(), zone: z.enum(["above-page-content", "below-page-content"]).optional(), orderKey: z.string().min(1).optional(), description: z.string().optional() }),
|
|
3618
3619
|
z.object({ type: z.literal("remove-section"), ...sectionTarget }),
|
|
3619
3620
|
z.object({ type: z.literal("move-section"), ...sectionTarget, afterId: z.string().nullable().optional(), beforeId: z.string().nullable().optional() }),
|
|
3620
3621
|
z.object({ type: z.literal("add-field"), ...sectionTarget, parentFieldId: z.string().optional(), fieldType: z.enum(["text", "longtext", "richtext", "number", "toggle", "date", "image", "file", "link", "email", "phone", "select", "color", "json", "reference", "multi-reference", "group", "repeater"]).optional(), field: z.object({ id: z.string(), slug: z.string(), label: z.string(), type: z.string() }).passthrough().optional() }),
|
|
@@ -3653,19 +3654,19 @@ function buildToolDefs(deps) {
|
|
|
3653
3654
|
"conversion"
|
|
3654
3655
|
]);
|
|
3655
3656
|
const sectionType = z.string().min(1).max(64).describe(
|
|
3656
|
-
"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
|
|
3657
|
+
"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."
|
|
3657
3658
|
);
|
|
3658
3659
|
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");
|
|
3659
3660
|
const createComponentInput = z.object({
|
|
3660
3661
|
name: z.string().min(1),
|
|
3661
3662
|
slug: slug.describe("url-safe unique slug (lowercase letters/numbers/hyphens)"),
|
|
3662
3663
|
category: componentCategory.optional().describe("defaults to 'custom'"),
|
|
3663
|
-
group: z.string().min(1).max(100).optional().describe("the folder editors see in the dashboard's Components tab,
|
|
3664
|
+
group: z.string().min(1).max(100).optional().describe("the folder editors see in the dashboard's Components tab, by NAME (e.g. 'Sections', 'Forms'); CREATED when missing. Separate from `category`, the picker tab."),
|
|
3664
3665
|
sectionType: sectionType.optional(),
|
|
3665
3666
|
variantOf: z.string().min(1).max(255).optional().describe("id/slug of the component this is a VARIANT of: joins or starts its family (422 if its shared inputs are missing)"),
|
|
3666
3667
|
projectId: z.string().nullable().optional().describe("owning project id; null creates a workspace-wide global component"),
|
|
3667
3668
|
allowedOn: allowedOn.optional(),
|
|
3668
|
-
description: z.string().optional(),
|
|
3669
|
+
description: z.string().optional().describe(PARAM_TEXT.describes),
|
|
3669
3670
|
blockJson: z.array(blockObject).default([]).describe("the component's block tree"),
|
|
3670
3671
|
props: z.array(componentPropObject).default([]).describe(
|
|
3671
3672
|
"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."
|
|
@@ -5179,7 +5180,7 @@ ${notes.join("\n")}` : summary, created);
|
|
|
5179
5180
|
body: JSON.stringify(input2),
|
|
5180
5181
|
headers: confirmedHeaders(true)
|
|
5181
5182
|
})).data : await client.addPageFields(args.pageId, input2);
|
|
5182
|
-
return ok(`Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s)
|
|
5183
|
+
return ok(`Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).${autoHelpNote(args)}`, page);
|
|
5183
5184
|
}
|
|
5184
5185
|
const modelId = args.modelId;
|
|
5185
5186
|
const model = await client.getModel(modelId);
|
|
@@ -5208,7 +5209,7 @@ ${notes.join("\n")}` : summary, created);
|
|
|
5208
5209
|
headers: { ...opts ? { "If-Match": `W/"${opts.ifMatch}"` } : {}, ...confirmedHeaders(true) }
|
|
5209
5210
|
})).data : opts ? await client.updateModel(modelId, input, opts) : await client.updateModel(modelId, input);
|
|
5210
5211
|
return ok(
|
|
5211
|
-
`Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : ""}. Model now has ${updated.fields.length} field(s)
|
|
5212
|
+
`Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : ""}. Model now has ${updated.fields.length} field(s).${autoHelpNote(args)}`,
|
|
5212
5213
|
updated
|
|
5213
5214
|
);
|
|
5214
5215
|
})
|
|
@@ -6711,6 +6712,11 @@ conversion is yours to write.
|
|
|
6711
6712
|
5. Codemod the templates. Read each value from the CMS (\`@bettercms-ai/astro\` /
|
|
6712
6713
|
\`@bettercms-ai/next\` client, or the \`bcms-content.json\` build snapshot), KEEP the in-code
|
|
6713
6714
|
copy as the fallback, and declare the binding on the element that already renders it.
|
|
6715
|
+
Read the snapshot ONLY through a supported reader: the helper \`npx @bettercms-ai/convert\`
|
|
6716
|
+
writes (\`bcms\`, \`bcmsRows\`, \`bcmsImage\`) or \`publishedEntry(slug)\` from
|
|
6717
|
+
\`@bettercms-ai/sdk\`. Never hand-write a parser of the file: a row holds its values under
|
|
6718
|
+
\`data\`, so \`row.title\` is undefined and the page renders its fallback on every publish. An
|
|
6719
|
+
editable image is \`bcmsImage(page, path, importedImage)\`, never the bare import with a stamp.
|
|
6714
6720
|
Prefer schema-derived bindings \u2014 the TypeGen analogue:
|
|
6715
6721
|
\`npx @bettercms-ai/codegen --bindings-out src/bettercms.bindings.generated.ts\`, then spread
|
|
6716
6722
|
\`{...bcms.home.hero.title}\` / \`{...bcms.blog.features.$(i)}\`. The hand form is
|
|
@@ -6745,7 +6751,7 @@ conversion is yours to write.
|
|
|
6745
6751
|
\`bcms-content.json\` into the repo root before \`build\`, with a key it mints per build: no
|
|
6746
6752
|
repo secret feeds it. (The secret a connect sets, \`BCMS_API_KEY_<RUNG>\` such as
|
|
6747
6753
|
\`BCMS_API_KEY_PROD\`, is the validation workflows' key; they fall back to the shared
|
|
6748
|
-
\`BCMS_API_KEY\` only for a repo whose last connect predates it.) Read that file, with in-code
|
|
6754
|
+
\`BCMS_API_KEY\` only for a repo whose last connect predates it.) Read that file (step 5's readers), with in-code
|
|
6749
6755
|
fallbacks so a local or CI build without it still renders.
|
|
6750
6756
|
- ARCHIVE (\`deploy_project\`, inline or by \`uploadKey\`): the sandbox build runs with no env
|
|
6751
6757
|
and no network content step, by design. So the archive MUST SHIP its own
|