@bettercms-ai/mcp 0.66.0 → 0.66.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 +23 -24
- package/dist/index.js.map +1 -1
- package/dist/skills/bettercms/references/publishing.md +12 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2277,10 +2277,10 @@ var STRUCTURE_EXAMPLE_PAYLOAD = {
|
|
|
2277
2277
|
doc: {
|
|
2278
2278
|
schema: 1,
|
|
2279
2279
|
folders: [
|
|
2280
|
-
{ id: "home:pages", parentId: null, name: "Other pages", icon: "
|
|
2280
|
+
{ id: "home:pages", parentId: null, name: "Other pages", icon: "documents", sort: 1e3 },
|
|
2281
2281
|
{ id: "home:collections", parentId: null, name: "Shared", icon: null, sort: 1001 },
|
|
2282
|
-
{ id: "fld_std_blog", parentId: null, name: "Blog posts", icon: "
|
|
2283
|
-
{ id: "fld_std_products", parentId: null, name: "Products", icon: "
|
|
2282
|
+
{ id: "fld_std_blog", parentId: null, name: "Blog posts", icon: "document-text", sort: 0 },
|
|
2283
|
+
{ id: "fld_std_products", parentId: null, name: "Products", icon: "basket", sort: 1 }
|
|
2284
2284
|
],
|
|
2285
2285
|
items: [
|
|
2286
2286
|
{ kind: "page", id: "pg_home", folderId: "home:root", sort: 0, icon: null },
|
|
@@ -2293,7 +2293,7 @@ var STRUCTURE_EXAMPLE_PAYLOAD = {
|
|
|
2293
2293
|
{ kind: "collection", id: "cm_tags", folderId: "home:collections", sort: 0, icon: null },
|
|
2294
2294
|
{ kind: "page", id: "pg_about", folderId: "home:pages", sort: 0, icon: null },
|
|
2295
2295
|
{ kind: "page", id: "pg_contact", folderId: "home:pages", sort: 1, icon: null },
|
|
2296
|
-
{ kind: "page", id: "pg_404", folderId: "home:pages", sort: 2, icon: "
|
|
2296
|
+
{ kind: "page", id: "pg_404", folderId: "home:pages", sort: 2, icon: "code" }
|
|
2297
2297
|
]
|
|
2298
2298
|
}
|
|
2299
2299
|
};
|
|
@@ -2337,8 +2337,9 @@ ever changes.
|
|
|
2337
2337
|
7. **Settings closes the sidebar.** \`home:globals\` ("Settings") holds NO pages or collections \u2014
|
|
2338
2338
|
navigation, header, footer, site settings and SEO defaults open from it in the dashboard. The
|
|
2339
2339
|
three system folders always sort BELOW the folders you make: \u2026 Other pages, Shared, Settings.
|
|
2340
|
-
8. **Icons** (
|
|
2341
|
-
for docs, \`
|
|
2340
|
+
8. **Icons** (kit names, bettercms://icons/dock): \`document-text\` for posts, \`basket\` for products,
|
|
2341
|
+
\`book\` for docs, \`documents\` for Other pages, \`folder\` by default. Lucide names already stored
|
|
2342
|
+
still draw.
|
|
2342
2343
|
9. **Depth:** nest at most 2 levels by default. The hard limit is 4; do not use it without a
|
|
2343
2344
|
reason the user gave you.
|
|
2344
2345
|
10. **Organisation only.** Never rename a page, change a slug, touch a schema or move content to
|
|
@@ -2367,8 +2368,8 @@ What the structure writes refuse, and the code each refusal carries:
|
|
|
2367
2368
|
refuses a kind mismatch: it returns \`warnings\` and \`kindMismatches\` instead.
|
|
2368
2369
|
- **Page-bound models** are refused with 400 \`NAV_PAGE_BOUND_MODEL\` naming their page; organise
|
|
2369
2370
|
the page, by its page id.
|
|
2370
|
-
- **Shape:** folders nest at most 4 levels deep; names are 1-80 characters; icons are
|
|
2371
|
-
names (a-z, 0-9, dashes) and null clears one.
|
|
2371
|
+
- **Shape:** folders nest at most 4 levels deep; names are 1-80 characters; icons are kit
|
|
2372
|
+
names (bettercms://icons/dock; a-z, 0-9, dashes) and null clears one.
|
|
2372
2373
|
- **Access:** 403 \`SCHEMA_ACCESS_REQUIRED\` (rule 12).
|
|
2373
2374
|
- **Version:** 412 \`VERSION_CONFLICT\` (workflow step 4).
|
|
2374
2375
|
|
|
@@ -2736,6 +2737,7 @@ function entryListSearch(args) {
|
|
|
2736
2737
|
for (const key of ["modelId", "pageId", "status"]) if (args[key]) q.set(key, String(args[key]));
|
|
2737
2738
|
for (const [k, v] of whereToQuery(args.where)) q.append(k, v);
|
|
2738
2739
|
for (const key of ["sort", "page", "limit"]) if (args[key] !== void 0 && args[key] !== null) q.set(key, String(args[key]));
|
|
2740
|
+
if (args.detail !== true) q.set("select", "summary");
|
|
2739
2741
|
const s = q.toString();
|
|
2740
2742
|
return s ? `?${s}` : "";
|
|
2741
2743
|
}
|
|
@@ -3127,6 +3129,7 @@ var ENTRY_MERGE_NOTE = "true = keep the fields you leave out: the entry is read,
|
|
|
3127
3129
|
var ENTRY_IF_MATCH_NOTE = "optimisticVersion from get_content_entry: the write applies only at that version, and a 409 means it changed since: read it again and re-apply. With merge it defaults to the version merge read.";
|
|
3128
3130
|
var ENTRY_SCHEDULED_AT_NOTE = "ISO datetime to publish this draft at (needs publish permission); null cancels. An edit that omits scheduledAt CANCELS a pending publish schedule, so send it again with every edit made before it fires.";
|
|
3129
3131
|
var ENTRY_UNPUBLISH_AT_NOTE = "ISO datetime at which the published entry returns to draft; null cancels. Omitting it never cancels it.";
|
|
3132
|
+
var ENTRY_LIST_DETAIL_NOTE = "true = full rows with every field value and the published copy. Large: read one entry with get_content_entry instead.";
|
|
3130
3133
|
var ENTRY_LIST_LIMIT_NOTE = "entries per page, 1-200; 50 when omitted. Read `meta.totalPages` and ask for the next `page`.";
|
|
3131
3134
|
var PAGE_HEAD_NOTE = "noindex, canonical, og and twitter set the page's head extras; each MERGES into what is stored (a key you leave out is kept, null or an empty string clears it).";
|
|
3132
3135
|
var STRUCTURE_FENCE = "ORGANISATION ONLY: Content sidebar folders never change a URL, slug, content or publish state, and nothing is rebuilt or delivered; URL folders (page folders) are set in the dashboard. Read the resource bettercms://playbook/structure before you organise anything: it holds the rules this refuses on \u2014 system folders, type purity, the Admin/Developer access check, root pins and page-bound models.";
|
|
@@ -3411,7 +3414,8 @@ function buildToolDefs(deps) {
|
|
|
3411
3414
|
where: z.record(z.string(), z.unknown()).optional().describe(PARAM_TEXT.where),
|
|
3412
3415
|
sort: z.string().max(100).optional().describe(PARAM_TEXT.sort),
|
|
3413
3416
|
page: z.number().int().min(1).optional().describe(PARAM_TEXT.page),
|
|
3414
|
-
limit: z.number().int().min(1).max(200).optional().describe(ENTRY_LIST_LIMIT_NOTE)
|
|
3417
|
+
limit: z.number().int().min(1).max(200).optional().describe(ENTRY_LIST_LIMIT_NOTE),
|
|
3418
|
+
detail: z.boolean().optional().describe(ENTRY_LIST_DETAIL_NOTE)
|
|
3415
3419
|
});
|
|
3416
3420
|
const clearableText = (max) => z.string().max(max).nullable().optional();
|
|
3417
3421
|
const headPatchShape = {
|
|
@@ -3568,7 +3572,7 @@ function buildToolDefs(deps) {
|
|
|
3568
3572
|
projectId: z.string().min(1).optional().describe("required only for a workspace-scoped grant")
|
|
3569
3573
|
});
|
|
3570
3574
|
const layoutBinding = z.object({ inputId: z.string().min(1), fieldId: z.string().min(1) });
|
|
3571
|
-
const layoutIcon = z.string().min(1).max(80).regex(/^(?:[a-z0-9]+(?:-[a-z0-9]+)*|[A-Z][A-Za-z0-9]+)$/).refine((value) => LAYOUT_SECTION_ICON_SET.has(value), "Select a
|
|
3575
|
+
const layoutIcon = z.string().min(1).max(80).regex(/^(?:[a-z0-9]+(?:-[a-z0-9]+)*|[A-Z][A-Za-z0-9]+)$/).refine((value) => DOCK_ICON_NAME_SET.has(value) || LAYOUT_SECTION_ICON_SET.has(value), "Select a kit icon (bettercms://icons/dock) or a legacy Lucide icon").describe("kit icon name from bettercms://icons/dock (e.g. 'document-text'); legacy Lucide names (kebab-case or CamelCase) remain accepted");
|
|
3572
3576
|
const sectionTarget = { sectionId: z.string().min(1) };
|
|
3573
3577
|
const layoutCommand = z.discriminatedUnion("type", [
|
|
3574
3578
|
z.object({ type: z.literal("set-section-values"), ...sectionTarget, values: z.record(z.string(), z.unknown()) }),
|
|
@@ -3842,7 +3846,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3842
3846
|
def(
|
|
3843
3847
|
"set_content_structure",
|
|
3844
3848
|
"Replace the Content sidebar structure",
|
|
3845
|
-
`Replace the whole Content sidebar document in one write. Follow the structure standard (read ${STRUCTURE_PLAYBOOK_URI} first; suggest_content_structure returns a ready doc). Send the complete \`doc\` and the \`version\` get_content_structure returned (0 when the project has none yet). Validated exactly like the dashboard: unique folder ids, every parentId/folderId a folder in the doc, no cycles, depth \u22644, names 1-80 chars, lucide
|
|
3849
|
+
`Replace the whole Content sidebar document in one write. Follow the structure standard (read ${STRUCTURE_PLAYBOOK_URI} first; suggest_content_structure returns a ready doc). Send the complete \`doc\` and the \`version\` get_content_structure returned (0 when the project has none yet). Validated exactly like the dashboard: unique folder ids, every parentId/folderId a folder in the doc, no cycles, depth \u22644, names 1-80 chars, icons are kit names (bettercms://icons/dock; legacy lucide names still draw). A 412 VERSION_CONFLICT means someone changed it since you read it: read again and re-apply. Returns the new version and a diff. ${STRUCTURE_FENCE}`,
|
|
3846
3850
|
z.object({
|
|
3847
3851
|
doc: z.object({
|
|
3848
3852
|
schema: z.literal(1),
|
|
@@ -3850,7 +3854,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3850
3854
|
id: z.string().min(1).describe("your own stable id, up to 64 chars"),
|
|
3851
3855
|
parentId: z.string().nullable().describe("parent folder id; null = top level"),
|
|
3852
3856
|
name: z.string(),
|
|
3853
|
-
icon: z.string().nullable().describe("
|
|
3857
|
+
icon: z.string().nullable().describe("kit icon name (bettercms://icons/dock) or null"),
|
|
3854
3858
|
sort: z.number()
|
|
3855
3859
|
})),
|
|
3856
3860
|
items: z.array(z.object({
|
|
@@ -3872,7 +3876,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3872
3876
|
z.object({
|
|
3873
3877
|
name: z.string().min(1).describe("the folder's label, 1-80 chars"),
|
|
3874
3878
|
parentId: z.string().min(1).optional().describe("optional parent folder id (from get_content_structure); omit it, or send 'root', for the top level"),
|
|
3875
|
-
icon: z.string().min(1).optional().describe("optional
|
|
3879
|
+
icon: z.string().min(1).optional().describe("optional kit icon name (bettercms://icons/dock), e.g. 'folder'")
|
|
3876
3880
|
}).shape,
|
|
3877
3881
|
async (c, a) => structureResult(await data(c, "POST", `/management/content-structure/folders`, { name: a.name, parentId: a.parentId, icon: a.icon }))
|
|
3878
3882
|
),
|
|
@@ -3938,7 +3942,7 @@ ${d.outline}` : "Proposed Content structure.", d);
|
|
|
3938
3942
|
"what the id IS on this branch \u2014 VERIFIED, not assumed: an id is either a page or a collection, never both, and a mismatch is refused with 400 NAV_KIND_MISMATCH naming the kind to use. Call it again with that kind, which also clears the wrong-kind entry."
|
|
3939
3943
|
),
|
|
3940
3944
|
id: z.string().min(1).describe("the page id, collection (content model) id, or folder id"),
|
|
3941
|
-
icon: z.string().min(1).nullable().describe("
|
|
3945
|
+
icon: z.string().min(1).nullable().describe("kit icon name (bettercms://icons/dock), e.g. 'document-text'; null clears it")
|
|
3942
3946
|
}).shape,
|
|
3943
3947
|
async (c, a) => structureResult(await data(c, "POST", `/management/content-structure/icon`, { kind: a.kind, id: a.id, icon: a.icon }))
|
|
3944
3948
|
),
|
|
@@ -5216,20 +5220,11 @@ ${notes.join("\n")}` : summary, created);
|
|
|
5216
5220
|
name: "list_content_entries",
|
|
5217
5221
|
config: {
|
|
5218
5222
|
title: "List content entries (incl. drafts)",
|
|
5219
|
-
description: "List content entries \u2014 including drafts \u2014 filtered by model and/or page, by field values (`where`), sorted and paged. Use it to SEE existing content before editing. For a singleton page, pass its pageId to get its single entry. A project-scoped connection sees its own project's entries plus workspace-level ones, which it can read but not change. Returns `limit` entries per `page` (50 by default); the summary says which page of how many.",
|
|
5223
|
+
description: "List content entries \u2014 including drafts \u2014 filtered by model and/or page, by field values (`where`), sorted and paged. Use it to SEE existing content before editing. For a singleton page, pass its pageId to get its single entry. A project-scoped connection sees its own project's entries plus workspace-level ones, which it can read but not change. Returns `limit` entries per `page` (50 by default); the summary says which page of how many. Each entry is a SUMMARY (id, slug, title, status, model, page, dates, optimisticVersion) \u2014 read values with get_content_entry, or pass `detail: true` for full rows.",
|
|
5220
5224
|
inputSchema: listEntriesInput.shape
|
|
5221
5225
|
},
|
|
5222
5226
|
handler: guard(
|
|
5223
5227
|
async (args) => withClient(async (client) => {
|
|
5224
|
-
const filter = {
|
|
5225
|
-
...args.modelId ? { modelId: args.modelId } : {},
|
|
5226
|
-
...args.pageId ? { pageId: args.pageId } : {},
|
|
5227
|
-
...args.status ? { status: args.status } : {}
|
|
5228
|
-
};
|
|
5229
|
-
if ([args.limit, args.where, args.sort, args.page].every((v) => v === void 0)) {
|
|
5230
|
-
const entries = await client.listEntries(filter);
|
|
5231
|
-
return ok(`${entries.length} entr(y/ies).`, entries);
|
|
5232
|
-
}
|
|
5233
5228
|
const res = await client.fetchJSON(
|
|
5234
5229
|
client.url(`/management/content/entries${entryListSearch(args)}`),
|
|
5235
5230
|
{ method: "GET" }
|
|
@@ -6131,6 +6126,10 @@ components \u2014 is \`editor_setup\`, run on demand against the live build. The
|
|
|
6131
6126
|
\`get_deploy_status\` \`editorSetup\` (and get_next_steps) say when it has not run for the live
|
|
6132
6127
|
build: \`never\` or \`stale\` \u2192 run it before anything below.
|
|
6133
6128
|
|
|
6129
|
+
**Builds run \`build:bcms\` instead of \`build\`** when package.json declares one: the build alone,
|
|
6130
|
+
without CI checks (\`"build:bcms": "astro build"\` beside \`"build": "astro check && astro build"\`),
|
|
6131
|
+
keeping any step the build needs. The convert codemod adds it; never edit \`build\` for BetterCMS.
|
|
6132
|
+
|
|
6134
6133
|
\`deploy_project\` and \`promote_project\` both answer **409
|
|
6135
6134
|
AUTHORING_DECISION_REQUIRED** until a human has chosen this project's architecture. This is
|
|
6136
6135
|
asked ONCE per project, ever. It is not an error to retry or route around: read the message
|