@bettercms-ai/mcp 0.78.0 → 0.78.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 +5 -3
- package/dist/index.js.map +1 -1
- package/dist/skills/bettercms/SKILL.md +2 -2
- package/dist/skills/bettercms/references/animation.md +3 -3
- package/dist/skills/bettercms/references/finish-site.md +6 -4
- package/dist/skills/bettercms/references/getting-started.md +11 -6
- package/dist/skills/bettercms/references/publishing.md +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/tools.ts","../../types/src/component.ts","../../types/src/layout-lucide-icons.ts","../../types/src/dock-icon-names.ts","../src/dock-icons.ts","../src/structure-playbook.ts","../src/entry-merge.ts","../src/whoami.ts","../src/model-field-edit.ts","../src/toolsets.ts","../src/tool-text.ts","../src/entry-query.ts","../src/prompts.ts","../src/playbook.ts","../src/skill-docs.ts","../src/kit.ts"],"sourcesContent":["import { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { loadConfig, FileTokenStore, DeviceAuthClient } from \"@bettercms-ai/device-auth\";\nimport { buildServer } from \"./server.js\";\n\nexport { buildServer } from \"./server.js\";\n// Re-exported so importers of @bettercms-ai/mcp keep working after the move to\n// @bettercms-ai/device-auth.\nexport { DeviceAuthClient, loadConfig } from \"@bettercms-ai/device-auth\";\n\n/** Entrypoint for the `bettercms-mcp` stdio server. */\nasync function main(): Promise<void> {\n const config = loadConfig();\n const store = new FileTokenStore(config.credentialsPath, config.apiUrl);\n const auth = new DeviceAuthClient(config, store);\n const server = buildServer({ auth, managementBaseUrl: config.managementBaseUrl });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n process.stderr.write(`[bettercms-mcp] ready on stdio (api: ${config.apiUrl})\\n`);\n}\n\n// Only run when executed as the entry (not when imported, e.g. in tests).\n// Compare realpaths so symlinked launch paths still detect the entrypoint:\n// `import.meta.url` is realpath-resolved by Node, but `process.argv[1]` is not,\n// so the old `file://${argv[1]}` check silently failed under npx `.bin`\n// symlinks, global installs, and macOS /var→/private/var — the server would\n// exit 0 without starting.\nfunction isMainModule(): boolean {\n const argv1 = process.argv[1];\n if (!argv1) return false;\n try {\n return realpathSync(argv1) === fileURLToPath(import.meta.url);\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n main().catch((err) => {\n process.stderr.write(`[bettercms-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n","import { McpServer, ResourceTemplate } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { BetterCMS } from \"@bettercms-ai/sdk\";\nimport { registerTools } from \"./tools.js\";\nimport { registerPrompts } from \"./prompts.js\";\nimport { PLAYBOOK_URI, SCHEMA_PLAYBOOK } from \"./playbook.js\";\nimport { DOCK_ICONS_RESOURCE, DOCK_ICONS_TEXT } from \"./dock-icons.js\";\nimport { loadSkillDocs } from \"./skill-docs.js\";\nimport { KIT_ENTRY_URI_TEMPLATE, kitDocs, kitEntryTexts } from \"./kit.js\";\nimport { CTA_BUTTON_INSTRUCTION, DOCK_UI_ROUTING_INSTRUCTION, LAYOUT_CHROME_INSTRUCTION, PUBLISH_HOLD_INSTRUCTION, RECEIPT_FIRST_INSTRUCTION, SKILLS_ROUTING_INSTRUCTION, STRUCTURE_DEFAULT_INSTRUCTION, STRUCTURE_PLAYBOOK, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.js\";\nimport { TOOL_LOADING_INSTRUCTION } from \"./toolsets.js\";\nimport type { DeviceAuthClient } from \"@bettercms-ai/device-auth\";\n\nexport const SERVER_NAME = \"bettercms\";\n// Tracks the shared MCP tool-catalog version (kept in sync with the remote /mcp\n// SERVER_INFO in src/routes/mcp/index.ts) so both surfaces report the same version.\nexport const SERVER_VERSION = \"1.5.0\";\n\n/**\n * Display identity, mirroring the remote host's SERVER_INFO (src/lib/brand.ts). Not\n * imported from it: this package is published to npm and must not depend on backend\n * internals — same deliberate duplication as SERVER_VERSION above, so keep both in sync.\n *\n * The URLs are absolute and hardcoded because a published stdio server has no env to\n * derive an origin from. `title`/`websiteUrl`/`icons` are additive 2025-11-25\n * Implementation fields; older clients ignore them.\n */\nconst SERVER_DISPLAY = {\n title: \"BetterCMS\",\n websiteUrl: \"https://bettercms.ai\",\n icons: [\n { src: \"https://api.bettercms.ai/brand/mark-512.png\", mimeType: \"image/png\", sizes: [\"512x512\"] },\n { src: \"https://api.bettercms.ai/brand/mark.svg\", mimeType: \"image/svg+xml\", sizes: [\"any\"] },\n ],\n};\n\n/**\n * Send `X-Branch-Id` on every request this client makes. The SDK has no branch option, and every\n * request goes through its `headers()`, so the header is laid over that one method.\n */\nexport function withBranch<C extends { headers(): Record<string, string> }>(client: C, branch?: string): C {\n if (!branch) return client;\n const base = client.headers.bind(client);\n client.headers = () => ({ ...base(), \"X-Branch-Id\": branch });\n return client;\n}\n\nexport interface BuildServerDeps {\n auth: DeviceAuthClient;\n managementBaseUrl: string;\n}\n\n/**\n * Build the BetterCMS MCP server with its tools registered. Auth is lazy — the\n * device flow runs on the first tool call, not at connect time, so the MCP\n * handshake/tool-listing never blocks on user approval.\n */\nexport function buildServer(deps: BuildServerDeps): McpServer {\n const server = new McpServer(\n { name: SERVER_NAME, version: SERVER_VERSION, ...SERVER_DISPLAY },\n {\n capabilities: { tools: {}, prompts: {}, resources: {} },\n // 🔴 The plain-language ask, routed — the stdio twin of the hosted connector's line\n // (src/routes/mcp/index.ts MCP_INSTRUCTIONS). \"Make my site editable\" has one recipe and\n // one definition of done; without this an agent converts the page it landed on and stops.\n instructions:\n TOOL_LOADING_INSTRUCTION + \" \" + RECEIPT_FIRST_INSTRUCTION + \" \" +\n \"When the user asks to make a site or all of its pages editable and they were DERIVED at import: editor_setup, then get_next_steps until `receipt.gate.complete`. To convert its source or bind its fields: this is playbook §13. Read `bettercms://playbook/schema` §13, call get_binding_report and get_conversion_brief { complete: true }, convert EVERY route the brief lists, and finish only when get_binding_report shows coverage.pending empty on every route — not when the first page works. On a workspace-wide connection pass projectId on every call; never ask the user to re-scope the connection. \" +\n LAYOUT_CHROME_INSTRUCTION + \" \" + CTA_BUTTON_INSTRUCTION + \" \" +\n // 🔴 A DIFFERENT ASK WITH A DIFFERENT RECIPE. \"Componentize the whole site\" used to route\n // to §13 (bindings) — the wrong job entirely: it makes a site editable in place rather\n // than turning its sections into a component library. §12 is the map, and the batch tools\n // are why it is a handful of calls instead of one per component.\n \"When the user asks to componentize the whole site, to turn every section into a component, or to build a component library from the site: this is playbook §12. Read `bettercms://playbook/schema` §12, start with get_site_composition, and use the batch tools — componentize_sections, compose_pages, update_layout with `commands`, publish_components — rather than one call per component. Finish with get_site_composition and tell the user what the platform does not model (cookie banners, modals, breadcrumbs, pagination) and which components still need the owner's approval in the dashboard before they can be published. \" +\n // The default after authoring (the structure standard): organise what you made. Same\n // sentence as the hosted connector's MCP_INSTRUCTIONS.\n STRUCTURE_DEFAULT_INSTRUCTION + \" \" + SKILLS_ROUTING_INSTRUCTION + \" \" + DOCK_UI_ROUTING_INSTRUCTION + \" \" + PUBLISH_HOLD_INSTRUCTION,\n },\n );\n\n // The structure standard, beside the schema playbook: how to organise the Content sidebar.\n server.registerResource(\n \"structure-playbook\",\n STRUCTURE_PLAYBOOK_URI,\n {\n title: \"BetterCMS Content structure playbook\",\n description:\n \"How to organise a project's Content sidebar: one place per document, the home page and list pages pinned, one folder per content family named for the detail type its route holds and ordered by entry count, shared taxonomies in Shared, Pages for the rest, Settings last, at most 2 levels. With a worked set_content_structure payload.\",\n mimeType: \"text/markdown\",\n },\n () => ({\n contents: [{ uri: STRUCTURE_PLAYBOOK_URI, mimeType: \"text/markdown\", text: STRUCTURE_PLAYBOOK }],\n }),\n );\n\n // The playbook is a RESOURCE, not a tool description: it is fetched once by a client\n // that wants it, rather than riding in the prompt on every turn. Mirrors the hosted\n // /mcp PLAYBOOK_RESOURCE (src/routes/mcp/index.ts) — same URI, name and mime, so the\n // `bettercms://playbook/schema` that prompts and tool descriptions point at resolves\n // on stdio too. Without this, `import-site`'s \"read section 11 first\" is a dead link.\n server.registerResource(\n \"schema-playbook\",\n PLAYBOOK_URI,\n {\n title: \"BetterCMS schema & components playbook\",\n description:\n \"How to design a components-first BetterCMS project: components vs collections, section anatomy, sectionType variants, kind:'block' + modular fields, the 'document' article body, the draft->publish order, and what makes an imported site editable.\",\n mimeType: \"text/markdown\",\n },\n () => ({\n contents: [{ uri: PLAYBOOK_URI, mimeType: \"text/markdown\", text: SCHEMA_PLAYBOOK }],\n }),\n );\n\n // The dock's icon names: a resource, so the ~3 KB list never rides in a tool schema.\n const { uri: dockIconsUri, name: dockIconsName, ...dockIconsMeta } = DOCK_ICONS_RESOURCE;\n server.registerResource(dockIconsName, dockIconsUri, dockIconsMeta, () => ({\n contents: [{ uri: dockIconsUri, mimeType: dockIconsMeta.mimeType, text: DOCK_ICONS_TEXT }],\n }));\n\n // The bettercms skill, one resource per file, for a client that does not have it installed\n // (bettercms://skill/bettercms and bettercms://skill/<reference>). Same loader and URIs as the\n // hosted RESOURCES, so an instruction or a skill that names one resolves on both surfaces.\n for (const { uri, name, text, ...meta } of loadSkillDocs()) {\n server.registerResource(name, uri, meta, () => ({ contents: [{ uri, mimeType: meta.mimeType, text }] }));\n }\n\n // The kit catalogue (bettercms://kit, one resource per category, and each entry through a template):\n // which schema and blocks a section needs, generated from the dashboard kit. Same URIs as the hosted RESOURCES.\n for (const { uri, name, text, ...meta } of kitDocs()) {\n server.registerResource(name, uri, meta, () => ({ contents: [{ uri, mimeType: meta.mimeType, text }] }));\n }\n const kitEntries = kitEntryTexts();\n if (Object.keys(kitEntries).length) {\n server.registerResource(\n \"kit-entry\",\n new ResourceTemplate(KIT_ENTRY_URI_TEMPLATE, { list: undefined }),\n { title: \"Kit entry\", description: \"One kit entry: its model notes and the create_component props. Ids are in bettercms://kit.\", mimeType: \"text/markdown\" },\n (uri) => {\n const text = kitEntries[uri.href];\n if (text === undefined) throw new Error(`Unknown kit entry: ${uri.href}`);\n return { contents: [{ uri: uri.href, mimeType: \"text/markdown\", text }] };\n },\n );\n }\n\n registerTools(server, {\n auth: deps.auth,\n // `project` is the per-call target of a workspace-wide grant; the SDK sends it as\n // X-BCMS-Project. Omitted entirely when absent so a project-scoped key's request is\n // byte-identical to before.\n createClient: (apiKey, project, branch) =>\n withBranch(BetterCMS.management({ apiKey, baseUrl: deps.managementBaseUrl, ...(project ? { project } : {}) }), branch),\n });\n\n // Guided slash-command prompts ship with the server (auto-available as\n // /mcp__bettercms__studio and /mcp__bettercms__new_page when the MCP is added).\n registerPrompts(server);\n\n return server;\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { z } from \"zod\";\nimport { SECTION_DOCTRINE as DOCTRINE } from \"@bettercms-ai/types\";\nimport { BetterCMSError } from \"@bettercms-ai/sdk\";\nimport { DOCK_ICON_NAME_SET, LAYOUT_SECTION_ICON_SET, type ContentModelFieldUi, type DockIconName } from \"@bettercms-ai/types\";\nimport { DOCK_ICON_SET, DOCK_ICONS_URI } from \"./dock-icons.js\";\nimport { DeviceAuthPendingError } from \"@bettercms-ai/device-auth\";\nimport { NEXT_STEPS_DESCRIPTION, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.js\";\nimport { mergesEntry, planEntryMerge } from \"./entry-merge.js\";\nimport { WHOAMI_DESCRIPTION } from \"./whoami.js\";\nimport { fieldRemovalRequest, planFieldEdit, planFieldRemoval, type StoredModel } from \"./model-field-edit.js\";\nimport { LISTING_TAIL, listsTool, toolMeta, toolsetsOf } from \"./toolsets.js\";\nimport { ADD_FIELD_DESCRIPTION, FIELD_LOCKED_NOTE, GET_SEO_DESCRIPTION, MOVE_STAGE_DESCRIPTION, NEW_TOOL_TEXT, PARAM_TEXT, SEO_KEY_TEXT, UPDATE_FIELD_DESCRIPTION, UPDATE_SEO_DESCRIPTION, V2_LEAF_TYPES_NOTE, WEBHOOK_EVENTS } from \"./tool-text.js\";\nimport { BUTTON_FIELD_NOTE, KIT_ENTRY_REBUILD_NOTE, LINK_VALUE_NOTE, DELETE_PAGE_RUNTIME_BUNDLE, INPUT_CONFIRMED_HEADER, LAYOUT_LOCK_NOTE, PROP_V2_NOTE, SLOT_MULTIPLE_NOTE, UNPROPPED_COPY_NOTE, UPDATE_PAGE_IF_MATCH_NOTE, VARIANT_GROUP_NOTE, WINDOW_NOTE, DETACHED_COPY_NOTE } from \"./tool-text.js\";\nimport { entryListSearch } from \"./entry-query.js\";\nimport type {\n ManagedContentModel,\n ManagedContentEntry,\n ManagedPage,\n ManagedForm,\n ManagedFormInput,\n ManagedComponent,\n ManagedComponentSummary,\n ManagedComponentInput,\n ExtractionCandidate,\n CreateModelInput,\n UpdateModelInput,\n CreateEntryInput,\n UpdateEntryInput,\n CreateManagedPageInput,\n AddPageFieldsInput,\n UploadAssetInput,\n UploadedAsset,\n WriteContentInput,\n SeoMetaInput,\n SeoMeta,\n} from \"@bettercms-ai/sdk\";\nimport { COMPONENT_PROP_TYPES } from \"@bettercms-ai/types\";\nimport type {\n LayoutDataDocument,\n LayoutStructureDocument,\n ManagementLayoutCommand,\n PageLayoutOverrideDocument,\n} from \"@bettercms-ai/types\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\n/** Subset of the management SDK client the tools use (kept narrow for testability). */\nexport interface ManagementApi {\n listPages(): Promise<ManagedPage[]>;\n getPage(id: string): Promise<ManagedPage>;\n getModel(id: string): Promise<ManagedContentModel>;\n createModel(input: CreateModelInput): Promise<ManagedContentModel>;\n updateModel(id: string, input: UpdateModelInput, opts?: { ifMatch?: number }): Promise<ManagedContentModel>;\n /** `warnings` / `seedErrors`: the page exists, but the `data` seed was not stored. */\n createPage(input: CreateManagedPageInput): Promise<ManagedPage & { warnings?: string[]; seedErrors?: Record<string, string> }>;\n addPageFields(id: string, input: AddPageFieldsInput): Promise<ManagedPage>;\n setPageContent(\n id: string,\n input: { data: Record<string, unknown>; status?: \"draft\" | \"published\" },\n ): Promise<ManagedContentEntry>;\n /** `warnings`: advisory notes the server attached to the write (the write succeeded). */\n createEntry(input: CreateEntryInput): Promise<ManagedContentEntry & { warnings?: string[] }>;\n updateEntry(\n id: string,\n input: UpdateEntryInput,\n opts?: { ifMatch?: number },\n ): Promise<ManagedContentEntry & { warnings?: string[] }>;\n listEntries(filter?: {\n modelId?: string;\n pageId?: string;\n status?: \"draft\" | \"published\";\n }): Promise<ManagedContentEntry[]>;\n getEntry(id: string): Promise<ManagedContentEntry>;\n uploadAsset(input: UploadAssetInput): Promise<UploadedAsset>;\n deletePage(id: string): Promise<{ id: string }>;\n deleteEntry(id: string): Promise<{ id: string }>;\n deleteModel(id: string): Promise<{ id: string }>;\n listForms(): Promise<ManagedForm[]>;\n getForm(id: string): Promise<ManagedForm>;\n createForm(input: ManagedFormInput): Promise<ManagedForm>;\n updateForm(id: string, input: ManagedFormInput): Promise<ManagedForm>;\n listComponents(): Promise<ManagedComponent[]>;\n listComponents(options: { select: \"summary\" }): Promise<ManagedComponentSummary[]>;\n getComponent(id: string): Promise<ManagedComponent>;\n createComponent(input: ManagedComponentInput): Promise<ManagedComponent>;\n updateComponent(id: string, input: ManagedComponentInput, opts?: { ifMatch?: number }): Promise<ManagedComponent>;\n listExtractionCandidates(projectId?: string): Promise<ExtractionCandidate[]>;\n extractComponent(input: {\n hash: string;\n name: string;\n slug: string;\n projectId?: string;\n }): Promise<{ component: ManagedComponent; replaced: number }>;\n getManagedLayout(opts?: { scope?: \"global\" | \"page\"; pageId?: string; copy?: \"draft\" | \"published\"; projectId?: string }): Promise<ManagedLayoutDocument>;\n commandManagedLayout(input: { scope?: \"global\" | \"page\"; pageId?: string; projectId?: string; command: ManagementLayoutCommand; ifMatch: number }): Promise<ManagedLayoutDocument>;\n publishManagedLayout(input: { ifMatch: number; projectId?: string }): Promise<ManagedLayoutDocument>;\n writeContent(input: WriteContentInput): Promise<string>;\n generateSeoMeta(input: SeoMetaInput): Promise<SeoMeta>;\n // Generic escape hatch for the lifecycle tools (media mgmt, submissions, redirects,\n // SEO, site-files, promote, versions). These management endpoints have no bespoke SDK\n // method; the MCP tools call them straight through the client's public request plumbing,\n // so parity with the remote /mcp surface needs no per-endpoint SDK code (DRY).\n url(path: string): string;\n fetchJSON<T>(url: string, init?: RequestInit): Promise<T>;\n}\n\ntype ManagedLayoutDocument =\n | { scope: \"global\"; revision: number; etag: string; status: string; structure: LayoutStructureDocument; data: LayoutDataDocument }\n | { scope: \"page\"; pageId: string; pageSlug: string; revision: number; etag: string; status: string; globalStructure: LayoutStructureDocument; globalData: LayoutDataDocument; override: PageLayoutOverrideDocument };\n\nexport interface ToolDeps {\n auth: {\n getAccessToken(): Promise<string>;\n refresh(): Promise<string | null>;\n /** Forget cached creds + re-run device flow (used when the bound project was deleted). */\n resetAndReauthorize(): Promise<string>;\n };\n /**\n * Build a management client bound to the given access token, targeting `project`.\n *\n * `project` is the per-call target a WORKSPACE-WIDE grant must name — the SDK sends it as\n * `X-BCMS-Project`, which is what the Management middleware resolves the request's project\n * from. Undefined for a project-scoped grant, which carries its target on the key (and whose\n * middleware refuses a header naming anything else).\n *\n * `branch` is the call's content branch (`branchId`), sent as `X-Branch-Id`.\n */\n createClient: (apiKey: string, project?: string, branch?: string) => ManagementApi;\n /**\n * Ask the HUMAN a question mid-tool-call (MCP elicitation). Optional because plenty of\n * clients don't implement it — every caller must degrade to telling the model to ask in\n * chat instead. Wired from the McpServer in registerTools.\n */\n elicit?: (params: {\n message: string;\n requestedSchema: { type: \"object\"; properties: Record<string, unknown>; required?: string[] };\n }) => Promise<{ action: string; content?: Record<string, unknown> }>;\n}\n\n// ── Asking the human ──────────────────────────────────────────────────────────\n\n/**\n * Ask the HUMAN one question through the client (MCP elicitation), or hand the question back\n * as text for the model to ask in chat.\n *\n * The one outcome that never happens is a silent answer. A client that cannot elicit, a person\n * who dismisses the prompt, and a client that answers with the wrong type all land on the same\n * `{ prompt }`, which the caller returns as an error so the model has to go and ask.\n *\n * `accept` is a type predicate rather than a truthiness check on purpose: a boolean question's\n * legitimate answer is `false`, and every `if (picked)` shape would quietly discard it and fall\n * through to \"ask again\" forever.\n */\nasync function askHuman<T>(\n deps: ToolDeps,\n q: {\n /** Property name in the requested schema, and the key the answer comes back under. */\n key: string;\n message: string;\n /** The JSON-schema primitive describing the answer (string+enum, boolean+default, …). */\n property: Record<string, unknown>;\n accept: (value: unknown) => value is T;\n /** What the model reads out when the client cannot ask. */\n prompt: string;\n },\n): Promise<{ value: T } | { prompt: string }> {\n if (!deps.elicit) return { prompt: q.prompt };\n try {\n const res = await deps.elicit({\n message: q.message,\n requestedSchema: { type: \"object\", properties: { [q.key]: q.property }, required: [q.key] },\n });\n const picked = res.action === \"accept\" ? res.content?.[q.key] : undefined;\n if (q.accept(picked)) return { value: picked };\n } catch {\n // Client advertised elicitation but couldn't serve it. Fall through to asking in chat.\n }\n return { prompt: q.prompt };\n}\n\n// ── The framework question ────────────────────────────────────────────────────\n// Mirrors src/lib/projects/framework-choice.ts in the backend. Deliberately duplicated\n// rather than imported: this package is published to npm and must not depend on backend\n// internals (same reasoning as SERVER_VERSION in server.ts). Keep the two in sync.\n\n/** The one sentence every page-building surface states. Shared so the surfaces cannot drift apart. */\nexport { SECTION_DOCTRINE } from \"@bettercms-ai/types\";\n\nexport const FRAMEWORK_CHOICES = [\"astro\", \"next\", \"react-ts\", \"other\"] as const;\n\nconst FRAMEWORK_LABELS: Record<(typeof FRAMEWORK_CHOICES)[number], string> = {\n astro: \"Astro — recommended default, static by default and fastest to publish\",\n next: \"Next.js\",\n \"react-ts\": \"React + TypeScript (Vite, prerendered)\",\n other: \"Other — headless project: content and API only, bring your own frontend\",\n};\n\n/** What the model must read out when it cannot ask the user through the client UI. */\nexport const FRAMEWORK_PROMPT = [\n \"Ask the user which technology this site should be built with, then call create_project again with their answer as `framework`:\",\n ...FRAMEWORK_CHOICES.map((c, i) => ` ${i + 1}. ${c} — ${FRAMEWORK_LABELS[c]}`),\n \"\",\n \"Do not choose on their behalf. Sites cannot be built as plain HTML/CSS — every project is backed by one of these starters, which is what keeps its content editable in the CMS.\",\n].join(\"\\n\");\n\n/**\n * Resolve `framework` by ASKING, never by defaulting.\n *\n * Prefers a real client-side prompt (elicitation) so the human picks from a list instead of\n * the model inventing an answer. When the client can't elicit — or the person dismisses the\n * prompt — we return the question as text for the model to put in chat. Either way the one\n * outcome that never happens is a silent default, which is the whole point: a guessed\n * framework means a forked starter and seeded content pointing at the wrong stack, and\n * nobody notices until the site is half-built.\n */\nfunction askFramework(deps: ToolDeps) {\n return askHuman<string>(deps, {\n key: \"framework\",\n message: \"Which technology should this site be built with?\",\n property: {\n type: \"string\",\n title: \"Technology\",\n description: \"The frontend stack this project's starter is based on.\",\n enum: [...FRAMEWORK_CHOICES],\n enumNames: FRAMEWORK_CHOICES.map((c) => FRAMEWORK_LABELS[c]),\n },\n accept: (v): v is string =>\n typeof v === \"string\" && (FRAMEWORK_CHOICES as readonly string[]).includes(v),\n prompt: FRAMEWORK_PROMPT,\n });\n}\n\n// ── The authoring-architecture question ───────────────────────────────────────\n// Mirrors src/lib/projects/authoring-choice.ts in the backend, duplicated for the same\n// reason as the framework question above: this package ships to npm and must not import\n// backend internals. Keep the two in sync.\n//\n// The backend is where the ENFORCEMENT lives — deploy/promote answer 409\n// AUTHORING_DECISION_REQUIRED until this is set — and its refusal quotes the project's real\n// page counts, which this surface has no way to know at ask time. So the prompt here is the\n// generic question; the grounded one arrives in the 409.\n\nexport const AUTHORING_CHOICES = [\"components\", \"fields\"] as const;\n\nconst AUTHORING_LABELS: Record<(typeof AUTHORING_CHOICES)[number], string> = {\n components:\n \"Components (recommended) — reusable section components placed as blocks; editors add, reorder and swap sections without touching a schema. Recommend it for every marketing, landing, agency or product site\",\n fields:\n \"Fields — a typed field schema per page. Only for a blog, catalogue or directory where many rows share one shape; editors can change a page's copy but cannot add, reorder or swap its sections\",\n};\n\n/** What the model must read out when it cannot ask the user through the client UI. */\nexport const AUTHORING_PROMPT = [\n \"Ask the user which authoring architecture this site should use, then call set_authoring_preference again with their answer as `preference`:\",\n ...AUTHORING_CHOICES.map((c, i) => ` ${i + 1}. ${c} — ${AUTHORING_LABELS[c]}`),\n \"\",\n \"On a site whose pages were DERIVED at import, answering 'components' redoes nothing: after set_authoring_preference, get_componentize_plan proposes one component per section (it reads the PUBLISHED pages — no deploy needed to reach it), you confirm it with the user, then componentize_sections places them with `props.bind` (dry run first — they land as drafts and the page keeps its fields, values and bindings, so click-to-edit and the coverage meter are unchanged), then publish_component each one, publish the pages, run `npx @bettercms-ai/convert --componentize` in the repo, and deploy. For a section group the plan lists as NO_GROUP_ROOT or NOT_A_SECTION there is nothing to componentize, so author that section with create_component and set_page_content.\",\n \"\",\n \"Recommend components unless the user says the site is schema-first.\",\n \"Do not choose on their behalf. This is asked once per project.\",\n].join(\"\\n\");\n\n/** Resolve `preference` by ASKING, never by defaulting. Same shape as askFramework. */\nfunction askAuthoring(deps: ToolDeps) {\n return askHuman<string>(deps, {\n key: \"preference\",\n message:\n \"Which authoring architecture should this site use? Components is recommended for a marketing site.\",\n property: {\n type: \"string\",\n title: \"Authoring architecture\",\n description:\n \"How this site's pages are composed. Components is recommended unless this is a schema-first site (a blog, catalogue or directory). Asked once per project.\",\n enum: [...AUTHORING_CHOICES],\n enumNames: AUTHORING_CHOICES.map((c) => AUTHORING_LABELS[c]),\n },\n accept: (v): v is string =>\n typeof v === \"string\" && (AUTHORING_CHOICES as readonly string[]).includes(v),\n prompt: AUTHORING_PROMPT,\n });\n}\n\n// ── The media-delivery question ───────────────────────────────────────────────\n// Unlike the two above, this one HAS a safe default (the column is `NOT NULL DEFAULT true`)\n// and gates nothing. It is still asked rather than assumed, because it decides which host\n// goes into the customer's published content — but a project that is never asked simply keeps\n// the CDN, which is what every project does today.\n\n/** What the model must read out when it cannot ask the user through the client UI. */\nexport const USE_CDN_PROMPT = [\n \"Ask the user where this site's media should be served from, then call set_media_delivery again with their answer as `useCdn`:\",\n \" 1. true — the BetterCMS CDN (recommended, and the default). Media URLs are minted on the CDN host, or on the project's own CDN base if it stores media in its own bucket.\",\n \" 2. false — the API origin. Media URLs are minted on the API host instead. Same bytes, same service; only the hostname differs.\",\n \"\",\n \"This applies to URLs minted FROM NOW ON. Already-published content keeps the URLs it has, and they keep working.\",\n].join(\"\\n\");\n\n/** Resolve `useCdn` by ASKING. Same shape as askFramework/askAuthoring, with a boolean answer. */\nfunction askMediaDelivery(deps: ToolDeps) {\n return askHuman<boolean>(deps, {\n key: \"useCdn\",\n message: \"Serve this site's media from the BetterCMS CDN (recommended), or from the API origin?\",\n property: {\n type: \"boolean\",\n title: \"Use the CDN\",\n description:\n \"On (default): media URLs are minted on the CDN — or on this project's own CDN base if it uses its own bucket. Off: they are minted on the API origin instead. Same bytes either way; only the host changes, and only for URLs minted from now on.\",\n default: true,\n },\n accept: (v): v is boolean => typeof v === \"boolean\",\n prompt: USE_CDN_PROMPT,\n });\n}\n\n/** MCP tool result shape (text content + optional error flag). */\nexport interface ToolResult {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n}\n\nexport interface ToolDef {\n name: string;\n config: { title: string; description: string; inputSchema: z.ZodRawShape };\n handler: (args: Record<string, unknown>) => Promise<ToolResult>;\n}\n\n// ── Shared schema pieces ──────────────────────────────────────────────────────\n\nconst fieldType = z.enum([\n \"text\",\n \"richtext\",\n \"image\",\n \"boolean\",\n \"number\",\n \"select\",\n \"reference\",\n \"multi-reference\",\n \"array\",\n \"date\",\n \"datetime\",\n \"group\", // Non-Repeatable Zone: one nested object of fields\n \"repeater\", // Repeatable Zone: an array of nested field-objects\n // A slot holding one component instance. This enum is a SECOND, narrower copy of the\n // field-type union, and `toField`/`OutField` below strip anything not modelled here —\n // which is why showIf/helpText/searchable/placement are all unreachable from MCP today.\n // Adding the type here without also carrying its `config` through `toField` would let an\n // agent create the field and silently lose its component allowlist.\n \"component-ref\",\n // Migration 0188. Both are LEAF types, so `toField`'s pass-through branch carries their\n // `config` verbatim — which is what the warning above demands before adding a type here.\n // `modular` needs config.blockSlugs; `location` takes no config.\n \"modular\",\n \"location\",\n // One button as one value: { label, href, variant?, size?, arrow?, icon?, newTab? }. A leaf.\n \"button\",\n // All LEAF types, so the pass-through branch above covers them. `document` is THE article\n // body — the rich document canvas, pages or collections, at most one per schema, top level\n // only. It was the conspicuous omission: the dashboard shipped an editor for it while no\n // agent could create the field. `sections` is a page-section zone composed in the Visual\n // Editor, so it has no inline control.\n \"document\",\n \"longtext\",\n \"slug\",\n \"email\",\n \"phone\",\n \"link\",\n \"color\",\n \"json\",\n \"file\",\n \"sections\",\n \"multiselect\",\n \"icon\",\n // V2: ONE nested object of `fields`, kept as `object` (not normalized to zones). `toField` recurses into it.\n \"object\",\n // V2 leaves: a taxonomy string[], a rating number, a code value. The pass-through branch carries their config.\n \"tags\",\n \"rating\",\n \"code\",\n \"video\",\n \"table\",\n \"slot\",\n]);\n\n/** The backend's own 400 text (openModeSchema), so stdio's client-side refusal names the same code. */\nconst OPEN_MODE_INVALID = \"openMode_invalid: openMode must be one of 'inline', 'drill', 'popover', 'dialog'\";\n\nconst slug = z\n .string()\n .regex(/^[a-z0-9-]+$/, \"lowercase letters, numbers, and hyphens only\");\n\nconst fieldKey = z\n .string()\n .regex(/^[a-zA-Z0-9_-]+$/, \"letters, numbers, underscores, and hyphens only\");\n\n// Recursive field schema. The MCP SDK serialises this Zod shape to the JSON\n// Schema the LLM sees — on SDK >= 1.29 (the floor pinned in package.json) the\n// `z.lazy()` below emits a proper `$ref`/`$defs` recursion so nested\n// group/repeater fields are VISIBLE. A stale older SDK collapsed it to an\n// opaque {} (the historic \"nested fields not created\" bug). The same recursive\n// shape is hand-written as JSON Schema in the remote proxy — keep the two in\n// sync: see bettercms-backend/src/routes/mcp/index.ts (FIELD_DEF).\n/** A field definition. Recursive: `group`/`repeater` nest more fields. */\nexport type FieldInput = {\n key: string;\n label: string;\n type: z.infer<typeof fieldType>;\n required?: boolean;\n /** Opt OUT of the rich-text default for a non-prose string (href, slug, id). */\n richText?: boolean;\n /** A plain string, or `{label, value}` when the stored value differs from the shown label. */\n options?: Array<string | { label: string; value: string; icon?: string; description?: string }>;\n config?: Record<string, unknown>;\n fields?: FieldInput[];\n /** Id of one of the model's `fieldsets` — the editor card this field sits in. Editor-only. */\n fieldsetId?: string;\n /** Where the control sits in the entry editor. Editor-only. @see backend baseField.placement */\n placement?: \"cover\" | \"title\" | \"excerpt\" | \"body\" | \"inline\" | \"panel\";\n /** The value a new entry starts with. */\n defaultValue?: unknown;\n /** Absent ≡ true. `false` keeps the field out of site search. */\n searchable?: boolean;\n /** BE-6: no two entries (or repeater rows) may hold the same value. Scalar types only. */\n unique?: boolean;\n /** \"developer\": only schema authority may write the value or change the lock. `true`: an editor marker. */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2: a translation owns this value; unmarked values are its source's once any field is marked. */\n localized?: boolean;\n /** Shown under the field in the editor. Persisted end-to-end since FLO-119's sibling pass. */\n helpText?: string;\n /** Admin-only conditional visibility. No delivery or storage effect. */\n showIf?: {\n match: \"all\" | \"any\";\n rules: Array<{ field: string; op: \"eq\" | \"neq\" | \"in\" | \"notIn\" | \"gt\" | \"lt\" | \"isSet\" | \"notEmpty\" | \"empty\"; value?: string | string[] }>;\n };\n /** Authoring chrome — how the field presents in the editor. @see backend baseField.ui */\n ui?: FieldUi;\n /** V2 editor-only keys. @see backend baseField.helpMore */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** object / array / group / repeater: how the value (or each row) opens. */\n openMode?: \"inline\" | \"drill\" | \"popover\" | \"dialog\";\n};\n\n/** Shared by FIELDS and by component PROPS. The types package's shape, so the two cannot drift. */\nexport type FieldUi = ContentModelFieldUi;\n\n// A refine, not an enum: ~470 names inlined into every schema that carries `ui` would be paid on\n// every tools/list. The layoutIcon precedent; the server's z.enum is the guard.\nconst dockIconArg = z\n .string()\n .min(1)\n .max(40)\n .refine((v) => DOCK_ICON_SET.has(v), `not a dock icon, see ${DOCK_ICONS_URI}`) as unknown as z.ZodType<DockIconName, string>;\n\nconst uiObject = z.strictObject({\n collapsed: z\n .boolean()\n .optional()\n .describe(\"start this panel collapsed. Use it for long optional sections.\"),\n preview: z\n .strictObject({\n title: z.string().min(1).optional().describe(\"CHILD KEY whose value titles a collapsed row\"),\n subtitle: z.string().min(1).optional().describe(\"CHILD KEY whose value is the row's second line (e.g. 'level' → 'Heading · h2')\"),\n media: z.string().min(1).optional().describe(\"CHILD KEY whose value is the row's thumbnail (image/file/url all work)\"),\n fallback: z.string().min(1).max(60).optional().describe(\"a literal row label while the title child is empty ('Untitled question'), not a key\"),\n icon: dockIconArg.optional().describe(\"the row's icon while it has no media, a dock icon name\"),\n })\n .optional()\n .describe(\n \"how ONE ITEM summarises itself when collapsed. Every slot names a CHILD KEY of THIS field/prop (a dotted path reads into it: 'author.name'). Without it a repeater of testimonials reads 'Item 1, Item 2, Item 3'; with {title:'author', media:'avatar'} it reads the names with their faces.\",\n ),\n layout: z\n .enum([\"list\", \"grid\", \"table\", \"rows\", \"chips\", \"gallery\"])\n .optional()\n .describe(\n \"how the ITEMS are arranged. Omit (≡ 'list') for rows of text; 'grid' for items whose thumbnail is the thing you scan — a gallery, a logo wall, a team; 'table' for up to 3 scalar columns. Same placement rule as `preview`. V2 'rows' | 'chips' | 'gallery' are also valid on a primitive array.\",\n ),\n reorderable: z\n .boolean()\n .optional()\n .describe(\n \"omit (≡ true) unless the order is PART OF THE MEANING. `false` LOCKS the list — a 'three steps' band that must stay three steps in that order, a nav whose order is semantic, a timeline. Valid only where there is a list to lock.\",\n ),\n control: z\n .enum([\"segmented\", \"slider\", \"rating\", \"dropdown\", \"radio\", \"cards\", \"grid\", \"switch\", \"checkbox\"])\n .optional()\n .describe(\n \"editor control for a LEAF. Omit for the default. 'segmented' on a select with a few short options (alignment, theme, size); 'slider' on a number that has config.min < config.max (opacity, columns); 'rating' on a number with config.min, max and step; 'dropdown'/'radio'/'grid'/'cards' on a select ('cards' also a multiselect); 'switch'/'checkbox' on a boolean ('checkbox' also a multiselect). Anything else is refused with the rule named.\",\n ),\n icon: dockIconArg.optional().describe(`the branch row's icon, a name from ${DOCK_ICONS_URI}. Nesting fields only.`),\n itemLabel: z.string().min(1).max(24).optional().describe(\"what ONE item is called ('Slide'): the add button, crumbs and empty state. Nesting fields and lists. V2 itemNoun goes here.\"),\n // V2 chrome keys (the server's fieldUiSchema): editor-only, each refused with a named code where it means nothing.\n itemName: z.string().max(64).optional().describe(\"a list's item type name (an identifier). Lists only.\"),\n itemTitle: z.string().min(1).max(60).optional().describe(\"a list's item type title. Lists only.\"),\n rows: z.number().int().min(1).max(40).optional().describe(\"the lines a text box opens with. text / longtext only.\"),\n placeholder: z.string().min(1).max(120).optional().describe(\"ghost text, a field of any type. A prop uses its own `placeholder`.\"),\n synced: z.strictObject({ from: z.string().min(1).max(64) }).optional().describe(\"the value comes from this global; edits apply everywhere.\"),\n valueShape: z.enum([\"string\", \"object\"]).optional().describe(\"a link / image / button writes a plain string or the object.\"),\n access: z\n .strictObject({ view: z.literal(\"schema.view\").optional(), edit: z.literal(\"schema.manage\").optional() })\n .optional()\n .describe(\"who sees (view: developer-only) and who changes (edit) it, gated in the editor. The enforced lock is readOnly:'developer'.\"),\n hidden: z.boolean().optional().describe(\"true: never shown in the form (a system value). A conditional hide is showIf.\"),\n blocks: z\n .record(z.string(), z.strictObject({ icon: dockIconArg.optional(), preview: z.record(z.string(), z.string()).optional() }))\n .optional()\n .describe(\"modular only: per block slug, {icon?, preview?} for its rows.\"),\n input: z\n .object({\n name: z.string().regex(/^[a-z][a-z0-9-]{0,47}$/),\n writes: z.array(z.string().min(1).max(64)).max(16).optional(),\n })\n .optional()\n .describe(\n \"a custom dock input by NAME (the project's bettercms/inputs/<name>.tsx), a last resort after `control`, `preview` and groups. `writes`: sibling field keys it may also write, nothing else. Setting or changing it needs `confirmed: true`, sent only after the user approved it.\",\n ),\n});\n\n/** A prop's `ui`: the field vocabulary plus an inline `group` and `tab` (props have no fieldsets). A FIELD's `ui.group` stays a refusal. */\nconst propUiObject = uiObject.extend({\n group: z\n .strictObject({\n id: z.string().min(1).max(40),\n label: z.string().min(1).max(32).optional(),\n kind: z.enum([\"group\", \"row\"]).optional(),\n icon: uiObject.shape.icon,\n collapsed: z.boolean().optional(),\n description: z.string().min(1).max(200).optional(),\n columns: z.union([z.literal(1), z.literal(2)]).optional(),\n collapsible: z.boolean().optional(),\n layout: z.enum([\"stack\", \"breakpoints\"]).optional(),\n order: z.number().int().min(0).max(99).optional(),\n })\n .optional()\n .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}.\"),\n tab: z\n .strictObject({\n id: z.string().min(1).max(40),\n label: z.string().min(1).max(40).optional(),\n icon: uiObject.shape.icon,\n order: z.number().int().min(0).max(99).optional(),\n })\n .optional()\n .describe(\"TOP-LEVEL props only: the dock tab this prop sits in (a V2 kit schema `groups` entry: Content, Design, …). The FIRST prop in a tab defines {id, label, icon?, order?}; later ones send only {id}. ≤8 tabs, labels ≤40 chars and unique; a group's members share one tab.\"),\n});\n\n// One select choice, shared by model fields and component props; the server judges icon/description.\nconst choiceOption = z.union([z.string(), z.object({ label: z.string(), value: z.string(), icon: z.string().optional(), description: z.string().optional() })]);\n\nconst fieldShape = {\n key: fieldKey.describe(\n \"machine field key. 🔴 UNIQUE ACROSS THE WHOLE MODEL — API IDs share ONE FLAT NAMESPACE, so a field nested inside a group must NOT reuse a key used by another field or group. Every section's heading cannot be 'title'. Prefix with the section: 'hero_title', 'pricing_title', 'faq_title'. Reusing a key is refused, and if it slips through it leaves permanent errors in the editor and breaks conditional-visibility rules, which reference fields by bare key. Keys derived from an imported site may contain hyphens ('hero-h1-welcome'): address them exactly as returned.\",\n ),\n label: z.string().min(1).describe(\"human label shown in the editor\"),\n type: fieldType.describe(`field type. ${BUTTON_FIELD_NOTE} ${LINK_VALUE_NOTE}`),\n required: z.boolean().optional().describe(\n \"an entry cannot be saved without a value — set it only where the site genuinely cannot render without one\",\n ),\n richText: z\n .boolean()\n .optional()\n .describe(\n \"prose formatting. DEFAULTS TO TRUE for 'text': the field is created as rich text so editors can bold, link and format it on the canvas, and the API returns rich text (render with rich() from @bettercms-ai/sdk; plain() for titles and meta). Pass false for a value that is NOT prose and must stay a bare string — a URL/href, a slug, an id, an email, a phone number, a CSS class, an icon name. A link stored as rich text will not work as an href.\",\n ),\n options: z\n .array(choiceOption)\n .optional()\n .describe(\n \"choices when type is 'select'. A plain string, or {label, value, icon?, description?} when the stored value differs from what the editor shows (e.g. {label:'Sold out', value:'soldOut'}); icon a dock name, description one line ≤140.\",\n ),\n config: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"per-type config: reference {contentModelId}, multi-reference {contentModelId,min,max}, repeater {minItems, maxItems} (the list's item limits; the editor shows 'max N' and stops Add there), array {itemType: text|number|date|image|link|richtext}, date {includeTime, timezone}, modular|slot {blockSlugs: ['quote','gallery'], minItems?, maxItems?} (slot: playbook §5) — blockSlugs is REQUIRED, non-empty, and each slug must name an existing kind:'block' model; richtext {inline:true, hostTag:'h2', accept:['h2','p','b','i','u','link'], features:['bold','italic','underline','link','headings'], allowMultipleParagraphs:false} — for a field bound to ONE element on the page: `hostTag` is that element's tag and `accept` must name it, so the editor's block-style control opens already showing 'Heading 2' instead of 'Paragraph'. Name exactly ONE heading level: publish refuses an <h3> value bound to an <h2> rather than nesting one heading inside the other. Keep 'p' in `accept` or the sanitiser strips a block demoted to Paragraph; limits: text/longtext {minLength,maxLength,pattern,patternMessage}, richtext {minLength,maxLength}, number {validation:{min,max}}, array {minItems,maxItems}, tags {min,max}, rating {min,max,step}\",\n ),\n fields: z\n .array(z.lazy(() => fieldObject))\n .optional()\n .describe(\n \"NESTED child fields — REQUIRED for type 'group' (one nested object, a Non-Repeatable Zone like blog_hero → heading, description, hero_image) and type 'repeater' (a repeatable array of such objects, a Repeatable Zone / section-list like testimonials → quote, author). A section with repeating items is a 'repeater'; a fixed grouped block is a 'group'. Recurse to any depth — do NOT flatten zones into separate top-level fields.\",\n ),\n // ── Authoring chrome + editor behaviour ────────────────────────────────────\n // These three already persist end-to-end and already have a panel in the dashboard's schema\n // builder. They were unreachable from MCP for ONE reason: the OutField/toField whitelist\n // below did not model them, so they were stripped after the model had gone to the trouble of\n // sending them. Declaring them here is what makes the existing panel agent-writable.\n helpText: z\n .string()\n .max(500)\n .optional()\n .describe(PARAM_TEXT.helpText),\n showIf: z\n .object({\n match: z.enum([\"all\", \"any\"]),\n rules: z.array(\n z.object({\n field: z.string().describe(\"the BARE KEY of another field on this same model\"),\n op: z.enum([\"eq\", \"neq\", \"in\", \"notIn\", \"gt\", \"lt\", \"isSet\", \"notEmpty\", \"empty\"]),\n 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\"),\n }),\n ),\n })\n .optional()\n .describe(\n \"conditional visibility — 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.\",\n ),\n ui: uiObject\n .optional()\n .describe(\n \"AUTHORING CHROME — 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 — use `after`. Section 14 of bettercms://playbook/schema has each key and where it is legal.\",\n ),\n // ── G5: the four keys the backend field schema accepts that this whitelist stripped. ──\n fieldsetId: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"id of one of this model's `fieldsets` (create_content_model / update_content_model). The field is shown inside that card in the editor. Editor-only: never changes what is stored or delivered.\",\n ),\n placement: z\n .enum([\"cover\", \"title\", \"excerpt\", \"body\", \"inline\", \"panel\"])\n .optional()\n .describe(\n \"where the control sits in the entry editor: 'title' the entry's heading, 'cover' its lead image, 'excerpt' the summary, 'body' the document body, 'inline' or 'panel'. Omit to let the editor decide. Editor-only.\",\n ),\n defaultValue: z.unknown().optional().describe(\"the value a new entry starts with\"),\n searchable: z\n .boolean()\n .optional()\n .describe(\"omit (≡ true) to index this field for site search; false excludes it\"),\n unique: z\n .boolean()\n .optional()\n .describe(\n \"true: no two entries of this model may hold the same value (compared trimmed and case-insensitively). On a repeater child such as a variant SKU it also covers every row of every entry. Only on text, longtext, slug, email, phone, link, number, select, reference and date; on a list it means no item repeats. A clash is refused with 409 `unique_conflict`.\",\n ),\n readOnly: z.union([z.literal(true), z.literal(\"developer\")]).optional().describe(PARAM_TEXT.readOnly),\n lockReason: z.string().max(200).optional().describe(PARAM_TEXT.lockReason),\n // V2 schema language. Editor-only; the playbook's §14 table maps each to what the editor draws.\n helpMore: z.string().max(2000).optional().describe(PARAM_TEXT.helpMore),\n advanced: z.boolean().optional().describe(PARAM_TEXT.advanced),\n recommendedMax: z.number().int().positive().optional().describe(PARAM_TEXT.recommendedMax),\n openMode: z.enum([\"inline\", \"drill\", \"popover\", \"dialog\"], { error: OPEN_MODE_INVALID }).optional().describe(PARAM_TEXT.openMode),\n localized: z.boolean().optional(),\n};\nconst fieldObject: z.ZodType<FieldInput> = z.object(fieldShape);\n\n/**\n * A collection's entry URL (CPO-046). Loose here on purpose: the API's `urlPatternSchema` is the\n * one validator, and its field-level message is what the agent should read back.\n */\nconst urlPatternArg = z\n .string()\n .nullable()\n .optional()\n .describe(\n \"the public URL of one entry, e.g. '/blog/:slug'. Must start with '/' and contain ':slug' exactly once ('{slug}' is refused). Drives RSS item links and the automatic 301 when an entry's slug changes. null clears it.\",\n );\n\n/** A content model's fieldset list. Same shape as the backend `fieldsetsSchema` and the dashboard's `Fieldset`. */\nconst fieldsetsArg = z\n .array(\n z.strictObject({\n id: z.string().min(1),\n name: z.string().min(1).max(60),\n description: z.string().max(500).optional(),\n kind: z.enum([\"group\", \"row\", \"tab\"]).optional(),\n tab: z.string().min(1).optional(),\n icon: uiObject.shape.icon,\n collapsed: z.boolean().optional(),\n collapsible: z.boolean().optional(),\n columns: z.union([z.literal(1), z.literal(2)]).optional(),\n layout: z.enum([\"stack\", \"breakpoints\"]).optional(),\n // Server-owned provenance, as get_content_model returns it: an echo parses and is dropped\n // before the write (dropProvenance), never refused.\n uiOrigin: z.unknown().optional(),\n uiBefore: z.unknown().optional(),\n }),\n )\n .max(30)\n .optional()\n .describe(\n \"the model's editor cards: [{id, name, description?, kind?, tab?, icon?, collapsed?, collapsible?, columns?:1|2, layout?:'breakpoints'}], at most 30, ids unique, order = array index. kind 'group' is a disclosure, 'row' puts up to 3 short scalars on one line, 'tab' is a tab (at most 3, top-level fields only; untabbed fields stay pinned above the tabs; a group's `tab` names its tab). A field joins one with `fieldsetId`. Editor-only: never changes what is stored or delivered.\",\n );\n\n/** Drop the server-owned provenance an agent echoed from a read. */\nconst dropProvenance = (sets: Array<Record<string, unknown>> | null | undefined) =>\n sets?.map(({ uiOrigin: _origin, uiBefore: _before, ...set }) => set) ?? sets;\n\n/** The richText default, stated in the tool descriptions too (G5), not only on the arg. */\nconst RICH_TEXT_NOTE =\n \"🔴 A field of type 'text' is created as RICH TEXT unless you send `richText: false` on it. Send `richText: false` for every value that is not prose: a name used as a title, a URL, slug, id, SKU, email, phone, CSS class or icon name.\";\n\n/**\n * update_seo's keys: a hand copy of the zod the route validates with\n * (src/lib/validation/schemas/projects.ts), which this published package cannot import.\n * mcp-tool-routes.test.ts pins every key, at every depth, against those schemas.\n */\nconst SCHEMA_ORG_TYPES = [\"WebPage\", \"AboutPage\", \"ContactPage\", \"CollectionPage\", \"Blog\", \"BlogPosting\", \"Article\", \"Product\", \"FAQPage\", \"Event\", \"Organization\", \"LocalBusiness\", \"JobPosting\", \"Course\", \"Recipe\", \"HowTo\", \"Service\", \"Person\", \"VideoObject\"] as const;\nconst changefreq = z.enum([\"auto\", \"always\", \"hourly\", \"daily\", \"weekly\", \"monthly\", \"yearly\", \"never\"]);\nconst jsonObject = z.record(z.string(), z.unknown());\nexport const seoPatchShape = {\n seoDefaults: z.object({\n metaTitle: z.string().max(255).optional(),\n metaDescription: z.string().max(500).optional(),\n ogImage: z.string().url().max(2000).nullable().optional(),\n twitterHandle: z.string().max(255).nullable().optional(),\n og: z.object({ image: z.string().max(2048).optional(), type: z.string().max(50).optional(), siteName: z.string().max(255).optional(), locale: z.string().max(20).optional() }).optional(),\n twitter: z.object({ card: z.string().max(50).optional() }).optional(),\n feeds: z.array(z.object({ type: z.string().max(100), href: z.string().max(2048), title: z.string().max(255).optional() })).max(10).optional(),\n collectionSchemaTypes: z.record(z.string().min(1).max(64), z.enum(SCHEMA_ORG_TYPES)).optional(),\n }).optional().describe(SEO_KEY_TEXT.seoDefaults),\n siteSchema: z.union([jsonObject, z.array(jsonObject)]).optional().describe(SEO_KEY_TEXT.siteSchema),\n robotsConfig: z.object({ mode: z.enum([\"auto\", \"custom\"]), custom: z.string().max(10000).optional(), disallow: z.array(z.enum([\"GPTBot\", \"OAI-SearchBot\", \"ChatGPT-User\", \"ClaudeBot\", \"Claude-Web\", \"anthropic-ai\", \"PerplexityBot\", \"Google-Extended\", \"CCBot\", \"Bytespider\", \"Applebot-Extended\", \"Amazonbot\", \"Meta-ExternalAgent\"])).max(32).optional() }).optional().describe(SEO_KEY_TEXT.robotsConfig),\n sitemapConfig: z.object({\n enabled: z.boolean(),\n mode: z.enum([\"auto\", \"custom\"]).optional(),\n custom: z.string().max(500000).optional(),\n defaultChangefreq: changefreq.optional(),\n defaultPriority: z.number().min(0).max(1).optional(),\n extraUrls: z.array(z.object({ loc: z.string().min(1).max(2000), changefreq: changefreq.optional(), priority: z.number().min(0).max(1).optional() })).max(1000).optional(),\n }).optional().describe(SEO_KEY_TEXT.sitemapConfig),\n rssConfig: z.object({ enabled: z.boolean() }).optional().describe(SEO_KEY_TEXT.rssConfig),\n indexnowConfig: z.object({ enabled: z.boolean(), excludePatterns: z.array(z.string().max(2000)).max(200).optional() }).optional().describe(SEO_KEY_TEXT.indexnowConfig),\n searchConfig: z.object({ enabled: z.boolean(), placeholder: z.string().max(120), aiEnabled: z.boolean().optional() }).optional().describe(SEO_KEY_TEXT.searchConfig),\n};\n\n/** Pages are not collections — the rule every import lane follows (lib/content/collection-evidence.ts). */\nconst PAGES_NOT_COLLECTIONS_NOTE =\n \"A collection is only for items one template route repeats (/blog/:slug: set urlPattern). A single page's copy (home, about, contact, pricing, legal) is page fields in sections (add_field with pageId / set_page_content), never a one-entry collection.\";\n\n/**\n * Output field shape persisted by the API. Canonical: nesting lives on `array` via\n * `config.zones`. The LLM may still speak `group`/`repeater` (kept in the input schema\n * because it's intuitive) — toField() maps those into the canonical array.zones shape\n * here, so the backend, dashboard, codegen, and delivery all see one model.\n */\ntype OutField = {\n key: string;\n label: string;\n type: Exclude<FieldInput[\"type\"], \"group\" | \"repeater\">;\n required?: boolean;\n options?: FieldInput[\"options\"];\n config?: Record<string, unknown>;\n fieldsetId?: string;\n placement?: FieldInput[\"placement\"];\n defaultValue?: unknown;\n searchable?: boolean;\n unique?: boolean;\n readOnly?: FieldInput[\"readOnly\"];\n lockReason?: string;\n localized?: boolean;\n // ⚠ THIS TYPE IS THE WHITELIST. `toField` builds its result from exactly these keys, so a\n // prop absent here is stripped AFTER the agent sent it and AFTER the input schema accepted\n // it — a 200 with the declaration gone. helpText/showIf/ui all persist end-to-end on the\n // backend and all three were unreachable purely because of this omission.\n helpText?: string;\n showIf?: FieldInput[\"showIf\"];\n ui?: FieldInput[\"ui\"];\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n openMode?: FieldInput[\"openMode\"];\n /** `object` only: its children, recursed like a zone's. */\n fields?: OutField[];\n};\n\n\n/**\n * API IDs share ONE FLAT NAMESPACE across a model — a field inside a group must not reuse a key\n * used by any other field or group. Checked here, before the write, because the failure it\n * prevents is silent: the schema saves, and the author is left with permanent red error rows in\n * the builder plus `showIf` rules that reference a bare key and therefore cannot resolve.\n *\n * This is the shape `create_page` produces by default — its own description tells the agent to\n * build a nested tree where every visual section becomes a group, and the natural key for each\n * section's heading is `title`. The marketing page came out with `title` and `subtitle` in three\n * groups. The rule was never written down anywhere the model could read it, so this is both a\n * guard and the place it gets taught.\n *\n * Depth is ONE LEVEL, matching the dashboard's own `walk` — checking deeper here would refuse\n * schemas the builder renders as clean.\n *\n * Reads BOTH dialects: `fields` (what an agent sends) and `config.zones` (what the API returns).\n */\nfunction flatFieldKeys(fields: unknown): string[] {\n const out: string[] = [];\n const childrenOf = (f: Record<string, unknown>): unknown[] => {\n const zones = (f.config as { zones?: { nonRepeatable?: unknown[]; repeatable?: { fields?: unknown[] } } } | undefined)?.zones;\n if (zones?.nonRepeatable) return zones.nonRepeatable;\n if (zones?.repeatable?.fields) return zones.repeatable.fields;\n return (f.fields as unknown[]) ?? [];\n };\n for (const raw of (Array.isArray(fields) ? fields : [])) {\n const f = raw as Record<string, unknown>;\n if (typeof f?.key === \"string\" && f.key.trim()) out.push(f.key.trim());\n for (const raw2 of childrenOf(f)) {\n const c = raw2 as Record<string, unknown>;\n if (typeof c?.key === \"string\" && c.key.trim()) out.push(c.key.trim());\n }\n }\n return out;\n}\n\n/** Keys used more than once, first-seen order. */\nfunction duplicateKeys(keys: string[]): string[] {\n const seen = new Map<string, number>();\n for (const k of keys) seen.set(k, (seen.get(k) ?? 0) + 1);\n return [...new Set(keys)].filter((k) => (seen.get(k) ?? 0) > 1);\n}\n\n/** The refusal an AGENT has to be able to act on — names the keys, the rule, the remediation. */\nfunction duplicateKeyFailure(dupes: string[]): string {\n return (\n `Duplicate API ID${dupes.length === 1 ? \"\" : \"s\"}: ${dupes.map((k) => `'${k}'`).join(\", \")}. ` +\n `API IDs share ONE flat namespace across the whole model — a field inside a group must not ` +\n `reuse a key used by another field or group. Prefix each key with its section and retry ` +\n `(e.g. 'hero_title' and 'pricing_title', never 'title' in both).`\n );\n}\n\nfunction toFields(fs: FieldInput[] | undefined): OutField[] {\n return (fs ?? []).map(toField);\n}\n\n/**\n * Prose fields are RICH TEXT unless the caller opts out.\n *\n * The default is inverted from what the type name suggests, deliberately: an agent asked for a\n * headline says `type: 'text'` because that is the word for it, and the author then finds a\n * heading they cannot bold or link on the canvas — the toolbar's marks render disabled with\n * \"enable rich text formatting to use this\", and the only route out is a schema edit.\n *\n * 🔴 The opt-out is NOT cosmetic. A richtext field's API value is an ENVELOPE, not a string, so\n * an href, slug, id, email or class name created as rich text is broken the moment a template\n * interpolates it — that is the shape that renders \"[object Object]\". `richText: false` is the\n * required answer for every non-prose string, and the input schema says so.\n */\nfunction proseType(f: FieldInput): FieldInput[\"type\"] {\n // `text` is the only prose leaf this enum carries — `longtext` is not in it, so there is\n // nothing else to widen to. Stated because \"why only text?\" is the obvious next question.\n if (f.type !== \"text\") return f.type;\n return f.richText === false ? \"text\" : \"richtext\";\n}\n\n/** `confirmed: true` (the user approved a custom input) → the header the server gate reads. @see INPUT_CONFIRMED_HEADER */\nconst confirmedHeaders = (confirmed: unknown): Record<string, string> => (confirmed === true ? { [INPUT_CONFIRMED_HEADER]: \"true\" } : {});\n/** `{ headers }` only when there is one, so a call without any sends none. */\nconst withHeaders = (headers: Record<string, string>) => (Object.keys(headers).length > 0 ? { headers } : {});\nconst DRY_RUN_SUMMARY = \"Dry run: nothing was written.\";\n/** A write's own route with `dryRun: true`: the API validates and answers what it would store. */\nconst dryRunOf = async (client: ManagementApi, method: string, path: string, body: object, headers: Record<string, string> = {}) =>\n ok(DRY_RUN_SUMMARY, await client.fetchJSON(client.url(path), { method, body: JSON.stringify({ ...body, dryRun: true }), ...withHeaders(headers) }));\n\nfunction toField(f: FieldInput): OutField {\n // 🔴 `base` is the ONLY thing every branch below shares. The group/repeater branches REBUILD\n // `config` from scratch — `{ zones: … }`, with the incoming config never spread — so anything\n // carried inside `config` is destroyed on exactly the nesting fields it would be for. That is\n // why `ui` is a SIBLING here and on the backend's baseField, and why it goes in `base`: `base`\n // is spread FIRST in all four returns, and nothing below reassigns these keys.\n const base = {\n key: f.key,\n label: f.label,\n ...(f.required !== undefined ? { required: f.required } : {}),\n ...(f.helpText !== undefined ? { helpText: f.helpText } : {}),\n ...(f.showIf !== undefined ? { showIf: f.showIf } : {}),\n ...(f.ui !== undefined ? { ui: f.ui } : {}),\n // G5: these four persist on the backend and were stripped here, like helpText once was.\n ...(f.fieldsetId !== undefined ? { fieldsetId: f.fieldsetId } : {}),\n ...(f.placement !== undefined ? { placement: f.placement } : {}),\n ...(f.defaultValue !== undefined ? { defaultValue: f.defaultValue } : {}),\n ...(f.searchable !== undefined ? { searchable: f.searchable } : {}),\n // BE-6: a leaf key like the four above, so it rides on `base` and survives every branch.\n ...(f.unique !== undefined ? { unique: f.unique } : {}),\n // The developer lock: stripped here, an agent writing a model back would unlock every field.\n ...(f.readOnly !== undefined ? { readOnly: f.readOnly } : {}),\n ...(f.lockReason !== undefined ? { lockReason: f.lockReason } : {}),\n ...(f.localized !== undefined ? { localized: f.localized } : {}),\n // V2 editor keys: on `base` so the group/repeater rebuild cannot drop them.\n ...(f.helpMore !== undefined ? { helpMore: f.helpMore } : {}),\n ...(f.advanced !== undefined ? { advanced: f.advanced } : {}),\n ...(f.recommendedMax !== undefined ? { recommendedMax: f.recommendedMax } : {}),\n ...(f.openMode !== undefined ? { openMode: f.openMode } : {}),\n };\n\n // V2 object → stays an object; only its children are mapped.\n if (f.type === \"object\") {\n return { ...base, type: \"object\", fields: toFields(f.fields) };\n }\n // group → array with a non-repeatable zone (a fixed block).\n if (f.type === \"group\") {\n return { ...base, type: \"array\", config: { zones: { nonRepeatable: toFields(f.fields) } } };\n }\n // repeater → array with a repeatable zone (a list of blocks).\n if (f.type === \"repeater\") {\n // Its item limits ride along: the editor's \"2 items · max 4\" reads them from the zone.\n const { minItems, maxItems } = (f.config ?? {}) as { minItems?: number; maxItems?: number };\n return { ...base, type: \"array\", config: { zones: { repeatable: { fields: toFields(f.fields), ...(minItems !== undefined ? { minItems } : {}), ...(maxItems !== undefined ? { maxItems } : {}) } } } };\n }\n // Already-canonical zoned array (the LLM emitted config.zones directly) → recurse.\n if (f.type === \"array\" && f.config && typeof f.config === \"object\" && \"zones\" in f.config) {\n const zones = (f.config as { zones?: { nonRepeatable?: FieldInput[]; repeatable?: { fields?: FieldInput[]; minItems?: number; maxItems?: number } } }).zones ?? {};\n return {\n ...base,\n type: \"array\",\n config: {\n zones: {\n ...(zones.nonRepeatable ? { nonRepeatable: toFields(zones.nonRepeatable) } : {}),\n ...(zones.repeatable\n ? {\n repeatable: {\n fields: toFields(zones.repeatable.fields),\n ...(zones.repeatable.minItems !== undefined ? { minItems: zones.repeatable.minItems } : {}),\n ...(zones.repeatable.maxItems !== undefined ? { maxItems: zones.repeatable.maxItems } : {}),\n },\n }\n : {}),\n },\n },\n };\n }\n\n // Leaf field or primitive array (config.itemType) — pass through, with the prose default\n // applied here so EVERY field-creating tool (create_page, create_content_model, add_field)\n // inherits it from one place rather than several that can drift.\n return {\n ...base,\n type: proseType(f) as OutField[\"type\"],\n ...(f.options ? { options: f.options } : {}),\n ...(f.config ? { config: f.config } : {}),\n };\n}\n\n// ── Result helpers ────────────────────────────────────────────────────────────\n\n/** get_project's brand kit. Mirrors the remote catalog's note word for word. */\nconst BRAND_KIT_NOTE =\n \"`brandKit` (colors, typography, radius and any typeScale/spacing/elevation/motion/graphics) is edited in the BetterCMS dashboard AND by set_brand_assets and set_brand_graphics; every write is a version a person can restore. ASSETS: a media asset OF THIS PROJECT by id; null clears one; a slot a person chose needs `replace: true`. GRAPHICS: `kind`, optional `angle`, 2-8 stops naming `colors.*` or `extras` keys — never a CSS string and never a hex. CONSUME, DO NOT COPY: a hosted page exposes `--brand-color-<key>`, `--brand-shadow-<key>` and `--brand-gradient-<key>`; style sections with their `style` tokens (`nav.backgroundGradient` and `footer.backgroundGradient` take a gradient key), never copied values. Never invent brand facts: read them from get_project.\";\n\n\n/** update_content_model's text and optimistic lock. Mirror the remote catalog's word for word. */\nconst UPDATE_MODEL_DESCRIPTION =\n \"Edit a content model: rename it, change description/slug/urlPattern, set its `fieldsets`, or reshape how its EXISTING fields look in the editor. Never adds or retypes a field (use add_field). It removes one only with `removeFields` plus `allowFieldRemoval: true`, which DISCARDS its data in every entry and has no dry run; a page's fields go through remove_page_fields. Send modelId, or pageId for the model a page's schema lives in. `fieldsets` REPLACES the list (null drops all); a field joins one with fieldFieldset or add_field's `fieldsetId`. The field* args address fields by dotted key path ('hero.title'). Read with get_content_model, then pass `ifMatch` = the version from that read. A taken slug is 409 `slug_taken`. Section 14 of bettercms://playbook/schema.\";\nconst FIELD_REMOVAL_NOTE =\n \"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.\";\nconst ALLOW_FIELD_REMOVAL_NOTE =\n \"true = the user accepts that removeFields discards those fields' data in every entry. There is no dry run on this route: confirm first.\";\nconst MODEL_IF_MATCH_NOTE =\n \"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.\";\nconst COMPONENT_IF_MATCH_NOTE =\n \"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).\";\nconst PROP_UI_ARG_NOTE = \"top-level prop key → 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\";\nconst OVERRIDE_NOTE = \"replace chrome a person set (otherwise 409 ui_human_owned names those paths). Send it only on the user's word.\";\nconst FIELD_UI_ARG_NOTE = \"path → ui patch, a field's `ui` vocabulary: each key merges, a null key clears it, null clears the whole ui\";\n/** What update_content_model forwards. `fields` is not one of them: the PATCH replaces `fields` wholesale. */\nconst MODEL_UPDATE_KEYS = [\n \"name\", \"slug\", \"description\", \"urlPattern\", \"fieldsets\",\n \"fieldUi\", \"fieldFieldset\", \"fieldOrder\", \"fieldLabel\", \"fieldHelpText\", \"override\",\n] as const;\n\n/** Native SEO on the two write tools. Mirrors the remote catalog's notes word for word. */\nconst ENTRY_META_NOTE =\n \"SEO is native: set this entry's metaTitle, metaDescription, noindex, canonical, og, twitter, schemaType or schema in `meta` (never as model fields). `meta` MERGES into what is stored: a key you leave out is kept, null or an empty string clears it.\";\n/** update_content_entry / list_content_entries arguments. Mirror the remote catalog's word for word. */\nconst ENTRY_MERGE_NOTE =\n \"Default true: keep the fields you leave out. The entry is read, `data` is laid over its stored data by top-level key (a group or repeater value replaces that whole key) and written at the version read. false = `data` REPLACES the whole object, deleting every field you leave out.\";\nconst ENTRY_IF_MATCH_NOTE =\n \"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.\";\nconst ENTRY_SCHEDULED_AT_NOTE =\n \"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.\";\nconst ENTRY_UNPUBLISH_AT_NOTE =\n \"ISO datetime at which the published entry returns to draft; null cancels. Omitting it never cancels it.\";\nconst ENTRY_LIST_DETAIL_NOTE =\n \"true = full rows with every field value and the published copy. Large: read one entry with get_content_entry instead.\";\nconst ENTRY_LIST_LIMIT_NOTE =\n \"entries per page, 1-200; 50 when omitted. Read `meta.totalPages` and ask for the next `page`.\";\nconst PAGE_HEAD_NOTE =\n \"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).\";\n\n\n/**\n * The structure fence, for the three tools where an agent starts organising\n * (get_content_structure, set_content_structure, create_folder); the other four carry the\n * one-line STRUCTURE_POINTER below.\n *\n * The rules this refuses on (system folders, type purity, pins, access, page-bound models and\n * their 400/403 codes) used to be a 2.6k-character note pasted on all seven structure tools —\n * 16k of one paragraph in a catalogue an agent reads whole before it can speak. They live in the\n * resource bettercms://playbook/structure (\"Refusals\"), which is never truncated. Byte-identical\n * in both catalogs: `mcp-text-parity` pins create_folder and move_to_folder equal across the two.\n */\nconst STRUCTURE_FENCE =\n \"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 — system folders, type purity, the Admin/Developer access check, root pins and page-bound models.\";\n\n/**\n * The four single-item structure writes (rename_folder, move_to_folder, set_icon, delete_folder)\n * point at the rules instead of restating them: the full fence rides on set_content_structure,\n * create_folder and get_content_structure, and the rules themselves live in the resource.\n */\nconst STRUCTURE_POINTER = \"Sidebar only, never a URL; rules: bettercms://playbook/structure.\";\n\n/** set_brand_assets / set_brand_graphics: the brand kit paragraph is stated once, on get_project. */\nconst BRAND_KIT_POINTER = \"The brand kit's rules (consume its tokens, never copy values or invent brand facts) are on get_project.\";\n\n/** A structure write: lead with the server's diff text, then the full payload. */\nfunction structureResult(d: unknown): ToolResult {\n const message = (d as { message?: unknown } | undefined)?.message;\n return ok(typeof message === \"string\" ? message : \"Updated the Content structure.\", d);\n}\n\n/**\n * The git lane's tool descriptions, repeated word for word by the hosted catalog (backend `src/routes/mcp/index.ts`). A tool that says\n * two different things on the two surfaces is a prompt that works from one client and misleads\n * from the other, and the two catalogs cannot share a module — a value import across the package\n * boundary resolves to a gitignored dist in the deployed container. So these are two copies,\n * pinned byte-equal by `src/__tests__/mcp/mcp-text-parity.test.ts`.\n */\nconst GIT_TEXT = {\n list_github_repos:\n \"Every GitHub repository this workspace's connected GitHub App installations can reach, grouped by account. Use it to find the repository to import: each ACCOUNT carries the `installationId` that import_github_repo and fork_github_repo take, and each repository under it carries `owner`, `repo` and `defaultBranch`. An empty `accounts` list means nobody has connected GitHub to this workspace yet \\u2014 tell the user to connect it from the dashboard (Project \\u2192 Hosting \\u2192 Connect GitHub) and call this again.\",\n import_github_repo:\n \"Connect an existing GitHub repository to the connected project (the dashboard's Import from GitHub) \\u2014 do it BEFORE writing any code for a user who already has a repo. It wires the project API key and variables into the repository, records the connection, assigns the site handle, imports the repo's bcms-content.json as content models when it has one, and queues the first build. Pass `installationId`, `owner` and `repo` from list_github_repos; `branch` defaults to the repository's own default branch and becomes the branch every deploy builds from. It only works on a repository this workspace's installations can already reach \\u2014 for anyone else's (a public starter, a template, another account's site) use fork_github_repo. Read `warning` / `contentWarning` / `envWarning` back to the user verbatim when they come back (`envWarning` names the environment variables the repo documents in .env.example and the project lacks — the site renders empty or crashes until they are set) \\u2014 the repository connected but cannot build, or will leave the Pages tab empty. Re-importing replaces the project's existing connection.\",\n fork_github_repo:\n \"Fork ANY GitHub repository into the user's own account and import it in one step \\u2014 how a user starts from a repository that is not theirs (a public starter, a template, another account's site). BetterCMS cannot wire a repository it has no installation on, so the copy has to live on their account first; this makes that copy, keeps the upstream link, and then connects it exactly as import_github_repo does. `installationId` names the DESTINATION account (from list_github_repos); `owner` and `repo` name the SOURCE, anywhere on GitHub. `name` renames the fork; `connect: false` forks without connecting. Forking is asynchronous: a 202 means the fork exists but GitHub is still copying it, and the answer tells you to call import_github_repo with the fork's owner and repo a moment later \\u2014 never fork a second time.\",\n list_github_branches:\n \"The connected repository's branches, plus `buildBranch` \\u2014 the one the provisioned Action builds from. A commit on any other branch never reaches the live site, so check this before you push.\",\n list_github_commits:\n \"The connected repository's commit history, newest first: sha, message, author, date and url. Defaults to the build branch; pass `branch` for another, `path` to narrow it to one file or directory, and `limit` (1-100, default 20). Read the head sha here before a push you want to be safe, and hand it back as push_to_github's `expectedHeadSha`.\",\n push_to_github:\n \"Commit files to the connected repository \\u2014 a real git commit written server-side by the GitHub App: no clone, remote or token of your own. Send `files` ([{path, content, encoding}]) and/or `deletePaths`, plus a `message`; both go into ONE commit, so a rename is atomic. It targets the BUILD branch by default, where the push starts the rebuild that goes live \\u2014 poll get_deploy_status after it, and read the response's `note`, which says whether this push deploys. Pass `branch` to push somewhere else (a branch that does not exist yet is created from the build branch, or from `baseBranch`) and then open a pull request with create_github_pull_request. Pass `expectedHeadSha` from list_github_commits \\u2014 a full sha or a prefix of one \\u2014 to be refused with a 409 rather than silently overwrite a branch someone else moved while you worked. Limits, enforced BEFORE anything is written: 200 paths and 10 MB per commit, and `.git`, `.github/workflows`, `.env` and `.npmrc` are never writable \\u2014 a refused patch writes nothing at all and names every offending path.\",\n create_github_pull_request:\n \"Open a pull request on the connected repository. `head` is the branch you pushed; `base` defaults to the build branch, so merging it is what ships the change. Use this instead of pushing straight to the build branch whenever a human should review first, or when that branch is protected. Returns the number and the url to hand the user.\",\n list_github_pull_requests:\n \"Pull requests on the connected repository: number, title, state, whether it merged, draft, head, base and url. `state` is 'open' (the default), 'closed' or 'all'. Poll it to find out whether the pull request you opened has landed.\",\n} as const;\n\n/**\n * The host-deploy lane's descriptions, repeated word for word by the hosted catalog, for the reason\n * GIT_TEXT is: pinned byte-equal by `src/__tests__/mcp/mcp-text-parity.test.ts`.\n */\nconst HOSTING_TEXT = {\n list_env_vars:\n \"The project's environment variables by NAME and scope (never a value), and `missing`: the ones the repository's .env.example declares that the project does not set. A site missing them builds and serves, then renders empty or crashes in the browser. Resolve `missing` by running `npx @bettercms-ai/cli@latest env push` in the repository: it uploads those values from the user's own .env files straight to BetterCMS, so they never pass through this conversation. Never read, print or ask the user to paste a value. When the values do not exist locally because the site reads its content from another CMS, move that content into BetterCMS instead (the bettercms skill's external-content reference). BetterCMS's own BCMS_* identifiers are supplied to every build and never need setting.\",\n list_hosting_connections:\n \"The Vercel, Netlify and Cloudflare accounts connected to this workspace (id, provider, accountLabel, status; never a token), plus `connectUrl`, the dashboard page where a person connects one. Call it before deploy_to_host. If the provider the user wants has no connection with status `ok`, give the user `connectUrl` to connect it in their browser and stop until they have: you never handle OAuth or a host token yourself.\",\n deploy_to_host:\n \"Deploy this project to the user's own Vercel or Netlify account through their connection. BetterCMS builds the site and the host serves that build (skill publishing). The first call creates the site on the host and makes it the project's host; a later call for the same provider redeploys that site (`redeployed: true`). `connectionId` (from list_hosting_connections) defaults to the newest working one, `siteName` to the project's handle. A refusal carries a `code` and a `fixUrl` (not_connected, reconnect, pick_existing_site, grant_required, ADMIN_REQUIRED): each is fixed by the user at `fixUrl`, so relay it and stop. `deploymentQueued: false` means the project has no live build yet: deploy_project first, and that release reaches the host on its own. Never run the Vercel or Netlify CLI while a connection exists. Then poll get_host_deploy_status. Needs artifact:write, like deploy_project.\",\n get_host_deploy_status:\n \"The connected project's recent deployments to Vercel, Netlify or Cloudflare, newest first: state (queued|deploying|live|failed), providerUrl, error, sha and targetName. Poll it after deploy_to_host until the newest one is `live`, whose `providerUrl` is the live URL to hand the user, or `failed`, whose `error` you read back to them.\",\n} as const;\n\n/** update_page's `blockJson` when it is an object: one section edit, each half named as the page route takes it. */\ninterface SectionEdit {\n insertSection?: { componentId: string; at?: number; before?: string; after?: string; style?: Record<string, unknown>; overrides?: Record<string, unknown> };\n sectionStyle?: { blockId: string; style: Record<string, unknown> };\n}\n\n/**\n * The id of this project's copy of a built-in section, made when it has none. A built-in is a locked\n * blueprint no page may place by its own id; `sourceKey` names the blueprint a component was copied\n * from, so a second \"add testimonials\" reuses the first copy instead of minting a twin.\n */\nasync function builtinCopyId(client: ManagementApi, builtinId: string): Promise<string> {\n const listed = await client.fetchJSON<{ data?: { id: string; sourceKey?: string | null; builtin?: boolean }[] }>(client.url(`/management/components?select=summary`));\n const copy = (listed.data ?? []).find((row) => row.sourceKey === builtinId && !row.builtin);\n if (copy) return copy.id;\n const made = await client.fetchJSON<{ data: { id: string } }>(client.url(`/management/components`), { method: \"POST\", body: JSON.stringify({ from: builtinId }) });\n return made.data.id;\n}\n\n/** A publish's ledger summary, as the publish routes return it (`outcome`). */\ninterface PublishOutcome {\n status: string;\n summary: string | null;\n live: number;\n notLive: { route: string; address: string; reason: string | null; action: { label: string } | null }[];\n next?: string;\n}\n\n/**\n * The summary lines of a call that published. A value the served page does not show LEADS, by name\n * and with its action: \"published\" used to be the whole answer, and the ledger that said otherwise\n * was a second call nobody made. `summary` is the call's own line, said after.\n */\nfunction publishedLines(outcome: PublishOutcome | undefined, summary: string): string[] {\n if (!outcome) return [summary];\n if (outcome.notLive.length > 0) {\n const values = outcome.notLive.map((v) => `${v.route} ${v.address}: ${v.reason ?? \"not live\"} (${v.action?.label ?? \"no action\"})`).join(\"; \");\n // Every value named is still being applied: nothing to act on, and nothing to call live yet.\n if (outcome.next && outcome.notLive.every((v) => v.reason === \"NOT_CHECKED\")) {\n return [`PENDING: ${values}. Read ${outcome.next} \\`publishes\\` until each reads live or held; do not report it as live before.`, summary];\n }\n return [`NOT LIVE: ${outcome.summary ?? outcome.status}. ${values}. Take each action, then read get_deploy_status \\`publishes\\`.`, summary];\n }\n if (outcome.next) return [`${summary} Published, and not judged yet: nothing has looked at the served page. Read ${outcome.next} \\`publishes\\` before saying it is live.`];\n if (outcome.status !== \"live\") return [`${summary} Publish status: ${outcome.status}.`];\n return [`${summary} Published: ${outcome.live > 0 ? `${outcome.live} ${outcome.live === 1 ? \"value\" : \"values\"} live on the served page` : \"live\"}.`];\n}\n\n/** What follows a write that made components: their props carry derived ui an agent can better (the server's componentize answer carries the same). */\nconst DOCK_UI_NEXT =\n \"Give every prop of this component its V2 ui (control, tab, group, collapsed, layout, preview, itemLabel, icon) by playbook §14 and the closest bettercms://kit entry: get_component, then ONE update_component with propUi, propTab and propHelpText (the field-ui prompt). Its props already carry the ui the server derived, so this improves the dock and holds nothing open.\";\n\nfunction ok(summary: string, data: unknown): ToolResult {\n return {\n content: [\n { type: \"text\", text: summary },\n { type: \"text\", text: JSON.stringify(data, null, 2) },\n ],\n };\n}\n\nfunction fail(message: string): ToolResult {\n return { content: [{ type: \"text\", text: message }], isError: true };\n}\n\n/**\n * Every `componentId` a block tree places, at any depth.\n *\n * Mirrors the nesting the backend's own dependency projection walks (section children, columns,\n * slider slides, tabs). `compose_pages` checks these against the project's catalogue BEFORE it\n * writes, because a page that places a component the project does not have renders those bands\n * as empty strings — no error, no placeholder, on a page that returns 200.\n */\nfunction componentIdsIn(blocks: unknown): string[] {\n const out: string[] = [];\n const walk = (value: unknown): void => {\n if (!Array.isArray(value)) return;\n for (const candidate of value) {\n if (!candidate || typeof candidate !== \"object\") continue;\n const block = candidate as { type?: string; props?: Record<string, unknown> };\n const props = (block.props ?? {}) as Record<string, unknown>;\n if (block.type === \"component\" && typeof props.componentId === \"string\" && props.componentId) {\n out.push(props.componentId);\n }\n if (block.type === \"section\") walk(props.children);\n else if (block.type === \"columns\" && Array.isArray(props.columns)) for (const column of props.columns) walk(column);\n else if (block.type === \"slider\" && Array.isArray(props.slides)) {\n for (const slide of props.slides) walk((slide as { children?: unknown })?.children);\n } else if (block.type === \"tabs\" && Array.isArray(props.tabs)) {\n for (const tab of props.tabs) walk((tab as { children?: unknown })?.children);\n }\n }\n };\n walk(blocks);\n return out;\n}\n\n/**\n * 🔴 DUCK-TYPED, not `instanceof BetterCMSError`. This package is PUBLISHED and resolves the SDK\n * the consumer installed, so the error a call throws can be an instance of a DIFFERENT copy of\n * that class than the one bundled here — `instanceof` is false across two module copies and the\n * receipt silently degrades to `[object Object]`. The shape is the contract.\n */\nfunction apiError(err: unknown): { status: number; message: string; bodyCode?: string; fieldErrors?: Record<string, string>; body?: unknown } | null {\n if (!err || typeof err !== \"object\") return null;\n const e = err as { status?: unknown; message?: unknown; bodyCode?: unknown; fieldErrors?: unknown; body?: unknown };\n if (typeof e.status !== \"number\") return null;\n return {\n status: e.status,\n message: typeof e.message === \"string\" ? e.message : \"\",\n bodyCode: typeof e.bodyCode === \"string\" ? e.bodyCode : undefined,\n fieldErrors: e.fieldErrors && typeof e.fieldErrors === \"object\" ? (e.fieldErrors as Record<string, string>) : undefined,\n body: e.body,\n };\n}\n\n/**\n * One failure, rendered for a RECEIPT rather than for a thrown result.\n *\n * The batch tools do not stop on a failed item — a whole-site run that dies on component 31 of\n * 40 has done 30 writes nobody has a record of. So each item's error becomes a line the agent can\n * read and act on, which means it has to carry the status and the machine code, not just a\n * sentence: `COMPONENT_IMPLEMENTATION_NOT_READY` is a governance state to relay to the user, and\n * a 409 slug conflict is a name to change and retry.\n */\nfunction errorText(err: unknown): string {\n const api = apiError(err);\n if (api) {\n const fields = api.fieldErrors\n ? Object.entries(api.fieldErrors).map(([k, v]) => `${k}: ${v}`).join(\"; \")\n : \"\";\n return `${api.status}${api.bodyCode ? ` ${api.bodyCode}` : \"\"} — ${fields || api.message}`;\n }\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * The machine-readable half of a refusal, appended to a thrown tool error.\n *\n * Without it a 409 reached the agent as \"409 CONFLICT + a sentence\": it could not tell\n * COMPONENT_IMPLEMENTATION_NOT_READY (relay the missing approvals to the user, never retry) from a\n * slug conflict (rename and retry), and the `readiness` tuple naming what is missing was dropped.\n * `issues` carries a FORM_DEFINITION_INVALID refusal's per-path problems the same way.\n *\n * The component publish refusal puts its code in `error` (with the sentence in `message`), so the\n * SDK's `bodyCode` is empty for it; an all-caps `error` is read as the code.\n */\nfunction refusalDetail(err: unknown): string {\n const api = apiError(err);\n if (!api) return \"\";\n const body = (api.body && typeof api.body === \"object\" ? api.body : {}) as { error?: unknown; readiness?: unknown; issues?: unknown; fixUrl?: unknown };\n const code = api.bodyCode ?? (typeof body.error === \"string\" && /^[A-Z][A-Z0-9_]+$/.test(body.error) ? body.error : undefined);\n const lines = [\n code ? `code: ${code}` : \"\",\n body.readiness !== undefined ? `readiness: ${JSON.stringify(body.readiness)}` : \"\",\n body.issues !== undefined ? `issues: ${JSON.stringify(body.issues)}` : \"\",\n // The link a person follows to fix it (connect a host, create a Vercel project): an agent\n // that only sees the sentence has nothing to hand the user.\n typeof body.fixUrl === \"string\" ? `fixUrl: ${body.fixUrl}` : \"\",\n ].filter(Boolean);\n return lines.length ? `\\n${lines.join(\"\\n\")}` : \"\";\n}\n\n/**\n * Authorization isn't done yet. Surface the clickable activation link *in the\n * tool result* (the one channel every MCP client renders — unlike the server's\n * stderr, which VS Code hides). The device flow is persisted, so simply\n * re-running this tool after approval resumes it and completes the request.\n */\nfunction authPrompt(err: DeviceAuthPendingError): ToolResult {\n const text = [\n \"🔐 BetterCMS authorization required — you're not signed in yet.\",\n \"\",\n `1. Open this link and approve: ${err.verificationUriComplete}`,\n ` (or visit ${err.verificationUri} and enter code ${err.userCode})`,\n \"2. Once approved, run this tool again — it resumes automatically and completes your request.\",\n ].join(\"\\n\");\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// ── Tool definitions ──────────────────────────────────────────────────────────\n\n/**\n * The `projectId` of the tool call currently running, read by `withClient` several frames down.\n *\n * 🔴 ASYNC-LOCAL, NOT A MODULE VARIABLE. The MCP transport dispatches requests without awaiting\n * the previous one, so two tool calls naming different projects are genuinely in flight together\n * and a shared mutable would write one call's target into the other's request. The alternative —\n * threading the argument through ~50 handler bodies — is a larger diff that only has to be\n * forgotten once to send a write to the wrong site.\n */\nconst currentProject = new AsyncLocalStorage<string | undefined>();\n\n/** The `branchId` of the tool call currently running — async-local for the same reason. */\nconst currentBranch = new AsyncLocalStorage<string | undefined>();\n\n/**\n * The per-call project argument, added to every tool that does not already declare one.\n *\n * Mirrors `withProjectId` on the hosted connector (backend `src/routes/mcp/index.ts`), which\n * lifts the same property onto its whole catalog for the same reason: a workspace-wide grant has\n * no project on the key, so every project-scoped route answers 400 PROJECT_SCOPE_REQUIRED and the\n * agent connects, sees every tool and can call none of them. The header only ever narrows WITHIN\n * the key's own workspace, so this grants nothing the key does not already hold.\n */\nconst projectIdArg = z\n .string()\n .min(1)\n .optional()\n .describe(\n \"list_projects id; workspace-wide grants only\",\n );\n\n/**\n * The per-call content branch, added to every tool that does not already declare one: the client\n * sends it as X-Branch-Id, so the call reads and writes inside that branch (list_branches).\n */\nconst branchIdArg = z\n .string()\n .min(1)\n .optional()\n .describe(\"content branch id (from list_branches); omit to work on main\");\n\n/** What whoami reads from GET /management/projects/current. */\ntype ProjectSummary = { id: string; name: string; slug: string; workspaceSlug?: string | null };\n\n/** Lift `projectId` and `branchId` onto a tool and bind them for the duration of the call. */\nconst withProjectId = (def: ToolDef): ToolDef => ({\n ...def,\n config: {\n ...def.config,\n inputSchema: {\n ...def.config.inputSchema,\n ...(def.config.inputSchema.projectId ? {} : { projectId: projectIdArg }),\n ...(def.config.inputSchema.branchId ? {} : { branchId: branchIdArg }),\n },\n },\n handler: (args) => {\n const arg = (key: string) => (typeof args?.[key] === \"string\" && args[key] ? (args[key] as string) : undefined);\n return currentProject.run(arg(\"projectId\"), () => currentBranch.run(arg(\"branchId\"), () => def.handler(args)));\n },\n});\n\n/**\n * The listing tail and the ABM lane, shared with the hosted catalogue (packages/mcp/src/toolsets.ts):\n * Claude Desktop keeps a server's first ~100 tools, and THIS is the surface Desktop loads.\n */\nexport { LISTING_TAIL };\n\n/**\n * What a field-creating tool says when the agent sent no help: the server wrote it (the stored\n * field reads `helpSource: \"auto\"`), so nothing is created without help and the agent knows whose\n * words they are. The hosted surface returns the route's own `helpText: {source: \"auto\"}` receipt.\n */\nconst autoHelpNote = (args: { helpText?: unknown }): string =>\n 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.\";\n\nexport function buildToolDefs(deps: ToolDeps): ToolDef[] {\n /** Run with a token, retrying once on 401 after a refresh / re-auth. */\n async function withClient<T>(fn: (client: ManagementApi) => Promise<T>): Promise<T> {\n const token = await deps.auth.getAccessToken();\n const project = currentProject.getStore();\n const branch = currentBranch.getStore();\n try {\n return await fn(deps.createClient(token, project, branch));\n } catch (err) {\n if (err instanceof BetterCMSError && err.status === 401) {\n const next = (await deps.auth.refresh()) ?? (await deps.auth.getAccessToken());\n return await fn(deps.createClient(next, project, branch));\n }\n // The key is bound to a project that was deleted server-side (L1: 409\n // PROJECT_DELETED). It can never succeed again — clear creds and re-authorize\n // so the user picks a LIVE project, then retry the original call into it.\n // (resetAndReauthorize throws DeviceAuthPendingError if approval isn't instant,\n // which guard() turns into the clickable activation prompt.)\n if (err instanceof BetterCMSError && err.status === 409 && err.bodyCode === \"PROJECT_DELETED\") {\n const next = await deps.auth.resetAndReauthorize();\n return await fn(deps.createClient(next, project, branch));\n }\n throw err;\n }\n }\n\n /** The id of the page an id, path or unique slug names; a slug two pages share throws the 409 listing each. */\n const pageIdOf = async (client: ManagementApi, ref: string): Promise<string> =>\n UUID.test(ref) ? ref : (await client.fetchJSON<{ data: { id: string } }>(client.url(`/management/pages/resolve?ref=${encodeURIComponent(ref)}`))).data.id;\n\n /** Wrap a handler with uniform error → ToolResult conversion. */\n function guard<A>(fn: (args: A) => Promise<ToolResult>) {\n return async (args: A): Promise<ToolResult> => {\n try {\n return await fn(args);\n } catch (err) {\n if (err instanceof DeviceAuthPendingError) {\n return authPrompt(err);\n }\n if (err instanceof BetterCMSError) {\n return fail(`BetterCMS error (${err.status} ${err.code}): ${err.message}${refusalDetail(err)}`);\n }\n return fail(`Unexpected error: ${err instanceof Error ? err.message : String(err)}`);\n }\n };\n }\n\n // ── Component authoring schemas ──\n // blockJson is a recursive ContentBlock tree; props is the override allowlist. The\n // backend validates the exact block union, so blocks are typed loosely here.\n // Declared BEFORE createPageInput/createComponentInput — both reference it.\n interface BlockInput { type: string; id: string; props: Record<string, unknown>; style?: Record<string, unknown>; window?: { from?: string; until?: string } | null }\n /** A block's or Layout Section's visibility window; the API validates and normalizes the instants. */\n const windowArg = z.object({ from: z.string().optional(), until: z.string().optional() });\n const blockObject: z.ZodType<BlockInput> = z.object({\n type: z\n .enum([\n \"heading\", \"text\", \"richtext\", \"image\", \"button\", \"spacer\", \"video\",\n \"columns\", \"section\", \"slider\", \"tabs\", \"navbar\", \"footer\", \"form\", \"component\",\n \"collection\",\n ])\n .describe(\"block type; section/slider/tabs/columns nest child blocks\"),\n id: z.string().min(1).describe(\"stable unique block id\"),\n props: z\n .record(z.string(), z.unknown())\n .describe(\n \"per-type props by block type: §5 of bettercms://playbook/schema (text/richtext {html}, NOT {text}; button {text, href, variant?, size? sm|md|lg, fullWidth?}; component {componentId, overrides?}). Containers nest blocks to any depth.\",\n ),\n style: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"design tokens: theme, bg (none|surface|muted|accent|dark|custom), bgCustom hex, paddingTop/paddingBottom/paddingSides px, contentWidth (narrow|default|wide|full), align, corner, shadow, borderTop/borderBottom, border (all four sides, in the text colour), hideOn [mobile|tablet|desktop] (all three hides it on the page: kept in the draft, never published). A real marketing band is a `section` block carrying bg + padding + contentWidth.\",\n ),\n window: windowArg.nullable().optional().describe(WINDOW_NOTE),\n });\n\n const createPageInput = z.object({\n title: z.string().min(1).describe(\"display title of the page, e.g. 'Home'\"),\n slug: slug.describe(\"URL-safe path segment, unique per project, e.g. 'home'\"),\n pageType: z\n .enum([\"singleton\", \"dynamic\"])\n .default(\"singleton\")\n .describe(\n \"'singleton' = exactly one entry (Home, About, Contact); 'dynamic' = many entries sharing this schema (Blog posts, Products). Defaults to singleton.\",\n ),\n blockJson: z\n .array(blockObject)\n .optional()\n .describe(\n \"the page's VISUAL composition — how a components-first page is built. Place one `component` block per section: {type:'component', id:'<stable>', props:{componentId:'<id from create_component>'}}. The component must be PUBLISHED (publish_component) or it renders as nothing on the live site. Independent of `fields`, which is a typed schema for a site's own code to read.\",\n ),\n fields: z.array(fieldObject).optional().describe(\"the page's typed schema fields\"),\n // Undeclared, this was stripped by the SDK before the request, so a singleton created with its\n // values arrived without them. The remote adapter and POST /management/pages always took it.\n data: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"a SINGLETON's field VALUES keyed by field key — seeds its entry in the same call. If any value is refused the page is still created, none of `data` is saved, and the result names ENTRY_SEED_FAILED with the per-field reasons: fix them and write with set_page_content.\",\n ),\n metaTitle: z.string().optional().describe(\"SEO meta title\"),\n metaDescription: z.string().optional().describe(\"SEO meta description\"),\n locale: z.string().nullable().optional().describe(PARAM_TEXT.locale),\n translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf),\n });\n\n const writeContentInput = z.object({\n action: z\n .enum([\"write\", \"rewrite\", \"translate\"])\n .describe(\"'write' = draft from a brief, 'rewrite' = improve existing copy, 'translate' = needs targetLang\"),\n text: z.string().min(1).describe(\"the source text (a brief for 'write', the copy to change otherwise)\"),\n instructions: z.string().optional().describe(\"optional extra guidance, e.g. 'make it punchier'\"),\n targetLang: z.string().optional().describe(\"required for 'translate', e.g. 'Spanish'\"),\n context: z.string().optional().describe(\"optional surrounding context, e.g. the page title\"),\n });\n\n const generateSeoMetaInput = z.object({\n text: z.string().min(1).describe(\"the content to derive SEO metadata from\"),\n context: z.string().optional().describe(\"optional surrounding context, e.g. the page slug\"),\n });\n\n // `projectId` is deliberately absent: withProjectId lifts it onto every tool below.\n const connectNativeAiInput = z.object({\n capabilities: z\n .array(z.string().min(1))\n .min(1)\n .optional()\n .describe(\n \"optional — any of inspect, propose, implement, cancel, question. Defaults to inspect+propose+cancel.\",\n ),\n });\n\n\n const createModelInput = z.object({\n name: z.string().min(1).describe(\"human model name, e.g. 'Blog Post'\"),\n slug: slug.describe(\"url-safe unique slug, e.g. 'blog-post'\"),\n description: z.string().optional().describe(PARAM_TEXT.describes),\n urlPattern: urlPatternArg,\n kind: z\n .enum([\"model\", \"block\"])\n .optional()\n .describe(\n \"'model' (default) = a collection with its own entries. 'block' = a type that exists only to be stacked inside another model's 'modular' field — 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.\",\n ),\n fields: z\n .array(fieldObject)\n .optional()\n .describe(\n \"the model's typed schema fields. 'group'/'repeater' NEST their child fields (any depth) — don't flatten zones into top-level fields.\",\n ),\n fieldsets: fieldsetsArg,\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n });\n\n // Insertion point. An ARGUMENT, never stored state — which is the whole point: field order\n // IS the array index, so a stored `order`/`position` prop would be a second source of truth\n // that can disagree with the array the schema builder persists with arrayMove. Omit it and\n // the field appends, exactly as before.\n const afterArg = z\n .string()\n .min(1)\n .optional()\n .describe(\n \"OPTIONAL insertion point: the key of an existing TOP-LEVEL field to insert this one directly after. Omit to append at the end (the default, and the behaviour before this existed). Use it to put a field where an author expects it instead of at the bottom — e.g. after:'hero_title' for a subtitle. An unknown key is refused rather than silently appended.\",\n );\n\n const addFieldInput = z.object({\n modelId: z.string().min(1).optional().describe(\"the content model to extend (from list_content_models); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of modelId: the page whose schema to extend (from list_pages / create_page)\"),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n ...fieldShape,\n after: afterArg,\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n });\n\n // Exactly one of localPath/url (enforced by the SDK + backend route, documented here).\n const uploadAssetInput = z.object({\n localPath: z\n .string()\n .min(1)\n .optional()\n .describe(\"absolute path to a local file (e.g. a repo image); provide this OR url\"),\n url: z\n .string()\n .url()\n .optional()\n .describe(\"remote image URL this client downloads and uploads; provide this OR localPath OR sourceUrl\"),\n sourceUrl: z.string().url().optional().describe(PARAM_TEXT.sourceUrl),\n filename: z.string().optional().describe(\"override the stored filename\"),\n altText: z.string().optional().describe(\"accessibility alt text\"),\n caption: z.string().optional(),\n transcript: z\n .string()\n .max(100_000)\n .optional()\n .describe(\"video/audio only: the spoken words (≤ 100,000 chars), published wherever the file is used\"),\n folderId: z.string().optional().describe(\"target Media Library folder (defaults to project root)\"),\n });\n\n // Upsert by external key, on create_content_entry and each row of create_content_entries.\n const upsertShape = {\n externalKey: z.string().min(1).max(255).optional().describe(PARAM_TEXT.externalKey),\n source: z.string().max(2048).optional().describe(PARAM_TEXT.upsertSource),\n runId: z.string().max(100).optional().describe(PARAM_TEXT.upsertRunId),\n };\n const createEntryInput = z.object({\n contentModelId: z.string().min(1).describe(\"id of the model this entry belongs to\"),\n slug: slug.optional(),\n status: z.enum([\"draft\", \"published\"]).optional().describe(\"defaults to draft\"),\n data: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\"field values keyed by field key\"),\n locale: z.string().nullable().optional().describe(PARAM_TEXT.locale),\n translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n ...upsertShape,\n });\n\n const getPageInput = z.object({\n pageId: z.string().min(1).describe(PARAM_TEXT.pageRef),\n });\n\n const setPageContentInput = z.object({\n pageId: z.string().min(1).describe(PARAM_TEXT.pageRef),\n data: z\n .record(z.string(), z.unknown())\n .describe(\n \"field values keyed by field key. A nested 'array' (zone) value is an OBJECT { nonRepeatable: { childKey: value, … }, repeatable: [ { childKey: value }, … ] } — nonRepeatable holds the fixed-block values, repeatable is the list of item objects (omit a zone you didn't define). A primitive 'array' (itemType) is a plain list. An 'image' value is an asset URL or asset id (from upload_asset) — the server resolves it to { id, url, name, altText }. Read get_page first to see each field's zones.\",\n ),\n status: z.enum([\"draft\", \"published\"]).optional().describe(\"omit to leave status unchanged\"),\n replace: z\n .boolean()\n .optional()\n .describe(\"true replaces the whole entry data, removing omitted fields; default false merges by top-level key\"),\n });\n\n const getEntryInput = z.object({\n entryId: z.string().min(1).describe(\"content entry id\"),\n });\n\n const listEntriesInput = z.object({\n modelId: z.string().optional().describe(\"filter by content model id\"),\n pageId: z.string().optional().describe(\"filter by page id (a singleton page has one entry)\"),\n status: z.enum([\"draft\", \"published\"]).optional(),\n externalKey: z.string().optional().describe(PARAM_TEXT.externalKeyFilter),\n where: z.record(z.string(), z.unknown()).optional().describe(PARAM_TEXT.where),\n sort: z.string().max(100).optional().describe(PARAM_TEXT.sort),\n page: z.number().int().min(1).optional().describe(PARAM_TEXT.page),\n limit: z.number().int().min(1).max(200).optional().describe(ENTRY_LIST_LIMIT_NOTE),\n detail: z.boolean().optional().describe(ENTRY_LIST_DETAIL_NOTE),\n });\n\n // Native SEO patches (mirrors src/lib/seo/meta-patch.ts). Absent keeps a key; null or \"\" clears it.\n const clearableText = (max: number) => z.string().max(max).nullable().optional();\n const headPatchShape = {\n canonical: clearableText(2048).describe(\"canonical URL; null clears\"),\n og: z\n .object({ title: clearableText(255), description: clearableText(500), image: clearableText(2048), type: clearableText(50) })\n .nullable()\n .optional()\n .describe(\"Open Graph; each key merges, null clears that key\"),\n twitter: z\n .object({ card: clearableText(50), title: clearableText(255), description: clearableText(500), image: clearableText(2048) })\n .nullable()\n .optional()\n .describe(\"Twitter card; each key merges, null clears that key\"),\n };\n const entryMetaInput = z.object({\n metaTitle: clearableText(255),\n metaDescription: clearableText(500),\n noindex: z.boolean().optional().describe(\"hide this entry from search engines and site search\"),\n ...headPatchShape,\n schemaType: z.enum(SCHEMA_ORG_TYPES).nullable().optional(),\n schema: z.union([z.record(z.string(), z.unknown()), z.array(z.record(z.string(), z.unknown()))]).nullable().optional(),\n });\n const updateEntryInput = z.object({\n entryId: z.string().min(1).describe(\"content entry id\"),\n data: z.record(z.string(), z.unknown()).optional().describe(\"field values keyed by field key\"),\n status: z.enum([\"draft\", \"published\"]).optional(),\n slug: slug.optional(),\n meta: entryMetaInput.optional().describe(\"the entry's native SEO; merges into what is stored\"),\n merge: z.boolean().optional().describe(ENTRY_MERGE_NOTE),\n ifMatch: z.number().int().min(0).optional().describe(ENTRY_IF_MATCH_NOTE),\n scheduledAt: z.string().datetime().nullable().optional().describe(ENTRY_SCHEDULED_AT_NOTE),\n unpublishAt: z.string().datetime().nullable().optional().describe(ENTRY_UNPUBLISH_AT_NOTE),\n locale: z.string().nullable().optional().describe(PARAM_TEXT.locale),\n translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf),\n });\n\n const deletePageInput = z.object({\n pageId: z.string().min(1).optional().describe(\"id of the page to delete (from list_pages)\"),\n runtimeBundle: z.enum([\"report\", \"apply\"]).optional().describe(PARAM_TEXT.runtimeBundle),\n });\n const deleteEntryInput = z.object({\n entryId: z.string().min(1).describe(\"id of the content entry to delete (from list_content_entries)\"),\n });\n const deleteModelInput = z.object({\n modelId: z.string().min(1).describe(\"id of the content model to delete (from list_content_models)\"),\n });\n\n const getFormInput = z.object({\n formId: z.string().min(1).describe(\"form id (from list_forms)\"),\n });\n\n // ── Form authoring schemas ──\n // MUST stay at parity with the server's field vocabulary (packages/db FormField + the\n // route's Zod). `update_form` REPLACES the whole `fields` array, so a type this schema\n // omits cannot be echoed back: an agent that reads a form and writes it back DESTROYS\n // every human-authored field of that type. `radio`/`checkboxes` were exactly that gap.\n // Guarded by src/__tests__/mcp/mcp-parity.test.ts.\n const formFieldObject = z.object({\n key: z.string().min(1).describe(\"machine key for the submitted value, e.g. 'email'\"),\n label: z.string().min(1).describe(\"field label shown to the visitor\"),\n type: z.enum([\n \"text\", \"email\", \"textarea\", \"select\",\n \"checkbox\", // single boolean; predates `checkboxes`\n \"checkboxes\", // pick-many, value is a string[] of chosen option labels\n \"radio\", // pick-one, rendered inline rather than in a dropdown\n \"number\", \"phone\", \"date\", \"url\", \"consent\", \"hidden\", \"step\", // `step` is a divider: the fields after it are one page\n ]),\n placeholder: z.string().optional(),\n helpText: z.string().optional().describe(\"hint shown under the control, muted\"),\n required: z.boolean().optional().describe(\n \"an entry cannot be saved without a value — set it only where the site genuinely cannot render without one\",\n ),\n options: z.array(z.string()).optional().describe(\"choices when type is 'select', 'radio' or 'checkboxes'\"),\n optionValues: z.array(z.string()).optional().describe(\"what each choice SUBMITS, positionally paired with `options` — only where it differs from the label\"),\n hidden: z.boolean().optional().describe(\"not rendered; pairs with defaultValue to capture context\"),\n defaultValue: z.string().optional(),\n showIf: z\n .object({ field: z.string(), equals: z.string() })\n .optional()\n .describe(\"show this field only when another field equals a value\"),\n validation: z\n .object({\n emailPolicy: z.enum([\"any\", \"business\"]).optional().describe(\"'email' fields only\"),\n min: z.number().optional().describe(\"'number' fields only — inclusive floor\"),\n max: z.number().optional().describe(\"'number' fields only — inclusive ceiling\"),\n phoneFormat: z.enum([\"any\", \"e164\"]).optional().describe(\"'phone' fields only\"),\n pattern: z.string().optional().describe(\"'text' / 'textarea' / 'url' fields only — a regex\"),\n })\n .optional()\n .describe(\"per-field rules the API enforces on submit; each key is only valid on the field types listed\"),\n ui: z\n // strict, like the server's: a typo inside `ui` must refuse here rather than be stripped\n // before the request is built — the agent would otherwise get a 200 and lose the key.\n .strictObject({\n countryPicker: z.boolean().optional().describe(\"'phone' fields only — render a country picker; the value is stored as E.164\"),\n defaultCountry: z.string().optional().describe(\"'phone' fields only — uppercase ISO 3166-1 alpha-2 the picker starts on; requires countryPicker\"),\n showFlags: z.boolean().optional().describe(\"'phone' fields only — show the country flag beside the dial code; requires countryPicker\"),\n })\n .optional()\n .describe(\"per-field presentation options; each key is only valid on the field types listed\"),\n });\n const formSettingsShape = {\n description: z.string().optional(),\n submitLabel: z.string().optional().describe(\"submit button label (default 'Submit')\"),\n successMessage: z.string().optional(),\n redirectUrl: z.string().url().optional().describe(\"URL to redirect to on success\"),\n // Spam + delivery settings. Each MUST parse exactly like its key in the route's\n // createFormSchema (this package cannot import it); src/__tests__/mcp/mcp-parity.test.ts\n // checks the two agree. Never add turnstileSecretKey: a secret does not belong in an\n // agent's context.\n turnstileEnabled: z.boolean().optional().describe(\"require a Cloudflare Turnstile check on submit\"),\n honeypotField: z.string().max(100).nullable().optional().describe(\"name of a hidden honeypot input; a submission that fills it is marked spam. null clears\"),\n notifyEmails: z.array(z.string().email()).optional().describe(\"addresses emailed on each submission (REPLACES the list)\"),\n };\n const createFormInput = z.object({\n name: z.string().min(1).describe(\"human form name (used by getForm('Name'))\"),\n fields: z.array(formFieldObject).default([]).describe(\"the form's fields\"),\n ...formSettingsShape,\n });\n const updateFormInput = z.object({\n formId: z.string().min(1).describe(\"form id (from list_forms)\"),\n name: z.string().optional(),\n fields: z.array(formFieldObject).optional().describe(\"REPLACES the field array — include all fields to keep\"),\n ...formSettingsShape,\n ignored: z.boolean().optional().describe(PARAM_TEXT.formIgnored),\n });\n\n const componentPropObject = z.object({\n key: z.string().min(1),\n label: z.string().min(1),\n target: z.object({ blockId: z.string().min(1), path: z.string().min(1) }),\n // Parity with componentPropDefSchema is no longer a promise to keep by hand — both now read\n // the SAME list from @bettercms-ai/types. It used to be a copy, and the failure that made\n // was quiet and total: `update_component` REPLACES the whole `props` array, so a type this\n // enum omitted could not be echoed back, and an agent reading a component and writing it\n // straight back DESTROYED every prop of that type on a 200.\n type: z.enum(COMPONENT_PROP_TYPES),\n // 'slot' holds ONE nested component instance, or a list with config.multiple (the keys\n // pass through to the server); config.componentIds restricts what may fill it. Absent here until now, so a slot allowlist was unreachable from stdio even\n // once the enum allowed the type.\n config: z\n .object({\n componentIds: z.array(z.string()).optional(), // 'slot' allowlist\n options: z.array(choiceOption).optional(), // 'select' — required, choices\n // 'group'/'table'/'object' sub-shape. Typed loosely here (the server validates the full\n // recursive shape, 10 levels at most) so a deep tree needs no Zod mirror in the client.\n // A sub-field may be a 'slot' (its value at its key in the object or row), with the slot keys above.\n fields: z.array(z.record(z.string(), z.unknown())).optional(),\n min: z.number().optional(), // 'number'\n max: z.number().optional(),\n step: z.number().optional(),\n })\n .passthrough()\n .optional(),\n defaultValue: z.unknown().optional(),\n // Editor hints, stored in the props JSON. `required` is NOT enforced at write time — an\n // override that omits it still saves — so it is a marker the dashboard renders and\n // get_site_composition counts, never a refusal. Parity: componentPropDefSchema on the server.\n required: z\n .boolean()\n .optional()\n .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.\"),\n helpText: z.string().max(200).nullable().optional().describe(\"hint shown under the control, muted (≤ 200 chars). null = no help on purpose (a /kit schema with no description); omitted = the platform writes it\"),\n placeholder: z.string().max(120).optional().describe(\"ghost text inside a text-ish control (≤ 120 chars)\"),\n // Stored markers on a prop: nothing refuses a prop value for them. Declared so an echo keeps them.\n readOnly: z.union([z.literal(true), z.literal(\"developer\")]).optional(),\n lockReason: z.string().max(200).optional(),\n localized: z.boolean().optional(),\n showIf: z\n .object({\n match: z.enum([\"all\", \"any\"]),\n rules: z.array(z.object({\n field: z.string().min(1),\n op: z.enum([\"eq\", \"neq\", \"in\", \"notIn\", \"gt\", \"lt\", \"isSet\", \"notEmpty\", \"empty\"]),\n value: z.union([z.string(), z.array(z.string())]).optional(),\n })).min(1).max(20),\n })\n .optional()\n .describe(\"show this prop only while SIBLING props (by key) match: {match:'all'|'any', rules:[{field, op:'eq'|'neq'|'in'|'notIn'|'gt'|'lt'|'isSet'|'notEmpty'|'empty', value?}]}. 'isSet', 'notEmpty' and 'empty' take no value; 'gt'/'lt' one number as a string. Editor-only.\"),\n // V2 editor-only keys, the model field's (playbook §14). Declared: this is a strip site.\n helpMore: z.string().max(2000).optional().describe(PARAM_TEXT.helpMore),\n advanced: z.boolean().optional().describe(PARAM_TEXT.advanced),\n recommendedMax: z.number().int().positive().optional().describe(PARAM_TEXT.recommendedMax),\n // F1.x `unique` (a list's items / a table's rows distinct) and the server's `stale` marker:\n // undeclared here, an agent's `unique` and an echoed `stale` were dropped with a 200.\n unique: z.boolean().optional(),\n stale: z.boolean().optional(),\n openMode: z.enum([\"inline\", \"drill\", \"popover\", \"dialog\"], { error: OPEN_MODE_INVALID }).optional().describe(\"object/group/table props: how the value (or each row) opens\"),\n // ⚠ A STRIP SITE, exactly like OutField above: this is a `z.object`, so a key the model\n // sends and this shape does not declare is dropped BEFORE the request leaves — a 200 with\n // the declaration gone. `ui` rode through the backend's looseObject `config` and died here.\n ui: propUiObject\n .optional()\n .describe(\n \"AUTHORING CHROME for this prop's control in the inspector — never a delivery effect, and the same object a FIELD's `ui` takes. `preview` and `layout` are valid on 'group', 'table', 'object' and 'slot' (`layout` 'rows'|'chips'|'gallery' also on 'multiselect', 'tags'); `reorderable` on 'table' ALONE, the one prop type whose value is a LIST (a 'group' is one object, a 'slot' one component instance). preview keys name a SUB-FIELD of this prop's config.fields and are checked against them (on a 'slot' the shape is checked but the keys cannot be — they belong to whichever component fills it). An unknown key inside `ui` is a 400, not a silent strip. Read it back with get_component: a prop whose `ui` is absent there was not stored.\",\n ),\n });\n const getLayoutInput = z.object({\n scope: z.enum([\"global\", \"page\"]).default(\"global\"),\n pageId: z.string().min(1).optional().describe(\"page id or slug; required for page scope\"),\n copy: z.enum([\"draft\", \"published\"]).optional().describe(\"which copy to read; default draft. Verifying a publish MUST read copy:'published' and check the response's copy echo — the draft is never a publish receipt (FLO-1188).\"),\n projectId: z.string().min(1).optional().describe(\"required only for a workspace-scoped grant\"),\n });\n const layoutBinding = z.object({ inputId: z.string().min(1), fieldId: z.string().min(1) });\n const layoutIcon = z.string().min(1).max(80)\n .regex(/^(?:[a-z0-9]+(?:-[a-z0-9]+)*|[A-Z][A-Za-z0-9]+)$/)\n .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\")\n .describe(\"kit icon name from bettercms://icons/dock (e.g. 'document-text'); legacy Lucide names (kebab-case or CamelCase) remain accepted\");\n const sectionTarget = { sectionId: z.string().min(1) };\n const layoutCommand = z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"set-section-values\"), ...sectionTarget, values: z.record(z.string(), z.unknown()) }),\n z.object({ type: z.literal(\"set-field-value\"), ...sectionTarget, fieldId: z.string().min(1), value: z.unknown() }),\n z.object({ type: z.literal(\"add-component\"), ...sectionTarget, componentId: z.string().min(1), variantGroupId: z.string().min(1).optional(), bindings: z.array(layoutBinding).optional(), literalValues: z.record(z.string(), z.unknown()).optional() }),\n z.object({ type: z.literal(\"remove-item\"), ...sectionTarget, itemId: z.string().min(1) }),\n z.object({ type: z.literal(\"move-component\"), ...sectionTarget, itemId: z.string().min(1), index: z.number().int().nonnegative() }),\n z.object({ type: z.literal(\"move-item\"), ...sectionTarget, itemId: z.string().min(1), index: z.number().int().nonnegative() }),\n z.object({ type: z.literal(\"swap-component-variant\"), ...sectionTarget, itemId: z.string().min(1), componentId: z.string().min(1) }),\n z.object({ type: z.literal(\"set-page-state\"), ...sectionTarget, state: z.enum([\"inherit\", \"override-content\", \"customize-structure\", \"disable\", \"reset\"]) }),\n z.object({ type: z.literal(\"set-section-state\"), ...sectionTarget, state: z.enum([\"inherit\", \"override-content\", \"customize-structure\", \"disable\", \"reset\"]) }),\n z.object({ type: z.literal(\"add-section\"), name: z.string().min(1), icon: layoutIcon, zone: z.enum([\"before_page\", \"after_page\"]), window: windowArg.optional() }),\n 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() }),\n 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(), window: windowArg.nullable().optional().describe(\"as a block's `window`\") }),\n z.object({ type: z.literal(\"remove-section\"), ...sectionTarget }),\n z.object({ type: z.literal(\"move-section\"), ...sectionTarget, afterId: z.string().nullable().optional(), beforeId: z.string().nullable().optional() }),\n 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() }),\n z.object({ type: z.literal(\"update-field\"), ...sectionTarget, fieldId: z.string().min(1), patch: z.object({}).passthrough() }),\n z.object({ type: z.literal(\"remove-field\"), ...sectionTarget, fieldId: z.string().min(1) }),\n z.object({ type: z.literal(\"move-field\"), ...sectionTarget, itemId: z.string().min(1), index: z.number().int().nonnegative() }),\n z.object({ type: z.literal(\"set-bindings\"), ...sectionTarget, itemId: z.string().min(1), bindings: z.array(layoutBinding), literalValues: z.record(z.string(), z.unknown()).optional() }),\n ]);\n const commandLayoutInput = z.object({\n scope: z.enum([\"global\", \"page\"]).default(\"global\"),\n pageId: z.string().min(1).optional(),\n projectId: z.string().min(1).optional().describe(\"required only for a workspace-scoped grant\"),\n command: layoutCommand.optional().describe(\"one canonical discriminated Layout command; authority is derived from type\"),\n // Chrome is many commands — add a section, add a component to it, bind its fields — and each\n // one needs the revision the PREVIOUS one returned. An agent doing that by hand runs\n // get_layout between every write, and a single missed re-read is a 409 mid-sequence.\n commands: z\n .array(layoutCommand)\n .min(1)\n .max(50)\n .optional()\n .describe(\"apply these commands IN ORDER, each against the revision the previous one returned. Mutually exclusive with `command`. Stops at the first failure and reports what was applied.\"),\n ifMatch: z.number().int().nonnegative().describe(\"revision returned by get_layout. With `commands`, this is the revision for the FIRST command only — the rest are chained.\"),\n });\n const publishLayoutInput = z.object({\n projectId: z.string().min(1).optional().describe(\"required only for a workspace-scoped grant\"),\n ifMatch: z.number().int().nonnegative().describe(\"revision returned by get_layout (scope global)\"),\n });\n // Eight structural categories (what the component IS) + the four \"Add a section\" library\n // tabs (where it appears). Keep in step with componentCategorySchema in\n // src/lib/validation/schemas/components.ts — the library four were missing here, so an\n // agent could not file a component under a library tab.\n const componentCategory = z.enum([\n \"navbar\", \"footer\", \"button\", \"section\", \"slider\", \"tabs\", \"form\", \"custom\",\n \"hero\", \"content\", \"social-proof\", \"conversion\",\n ]);\n const sectionType = z\n .string()\n .min(1)\n .max(64)\n .describe(\n \"section family: what KIND of section this is, e.g. 'Hero', 'Logo cloud', 'Pricing', 'FAQ' (never its heading's words: a section's title is its own heading, shown as written). 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.\",\n );\n const allowedOn = z\n .array(z.string().regex(/^(\\*|slug:[a-z0-9-]+|type:(singleton|dynamic|template))$/))\n .max(100)\n .describe(\"placement allowlist: *, slug:<page-slug>, and/or type:singleton|dynamic|template\");\n const componentPreviewArg = z\n .strictObject({\n title: z.string().min(1).max(64).optional(),\n subtitle: z.string().min(1).max(64).optional(),\n media: z.string().min(1).max(64).optional(),\n fallback: z.string().min(1).max(120).optional(),\n icon: dockIconArg.optional(),\n })\n .nullable()\n .describe(PARAM_TEXT.componentPreview);\n const createComponentInput = z.object({\n name: z.string().min(1),\n slug: slug.describe(\"url-safe unique slug (lowercase letters/numbers/hyphens)\"),\n category: componentCategory.optional().describe(\"defaults to 'custom'\"),\n 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.\"),\n sectionType: sectionType.optional(),\n 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)\"),\n from: z.string().min(1).max(255).optional().describe(PARAM_TEXT.fromBuiltin),\n projectId: z.string().nullable().optional().describe(\"owning project id; null creates a workspace-wide global component\"),\n allowedOn: allowedOn.optional(),\n description: z.string().optional().describe(PARAM_TEXT.describes),\n preview: componentPreviewArg.optional(),\n icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),\n tabs: z.array(z.object({ id: z.string(), label: z.string(), icon: z.string().optional(), order: z.number().int().optional() })).nullable().optional().describe(PARAM_TEXT.componentTabs),\n kitEntry: z.string().min(1).max(100).nullable().optional().describe(PARAM_TEXT.componentKitEntry),\n blockJson: z.array(blockObject).default([]).describe(\"the component's block tree\"),\n props: z\n .array(componentPropObject)\n .default([])\n .describe(\n \"overridable fields. DECLARE A PROP — WITH A `target` — 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 — 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,\n ),\n });\n const updateComponentInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n name: z.string().optional(),\n category: componentCategory.optional(),\n group: z.string().min(1).max(100).optional().describe(\"move it into this Group (by NAME; created when missing) — the folder editors see in the dashboard's Components tab\"),\n sectionType: sectionType\n .nullable()\n .optional()\n .describe(\n \"null demotes it to an ordinary component — it disappears from the 'Add a section' picker, and instances already placed keep rendering but lose their section chrome and variant switcher\",\n ),\n variantOf: z.string().min(1).max(255).optional().describe(\"see create_component\"),\n allowedOn: allowedOn.optional().describe(\"REPLACES the placement allowlist\"),\n description: z.string().optional(),\n preview: componentPreviewArg.optional(),\n icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),\n kitEntry: z.string().min(1).max(100).nullable().optional().describe(PARAM_TEXT.componentKitEntry),\n blockJson: z.array(blockObject).optional().describe(\"REPLACES the block tree\"),\n props: z\n .array(componentPropObject)\n .optional()\n .describe(\n \"REPLACES the prop array — 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.\",\n ),\n propUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(PROP_UI_ARG_NOTE),\n propGroup: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(\"prop key → its ui.group ({id, label?, kind?, icon?, collapsed?}), null takes it out\"),\n propTab: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(\"prop key → 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}; ≤8 tabs; one group's members share one tab. null takes it out\"),\n propLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe(\"prop key → label\"),\n propHelpText: z.record(z.string(), z.string().max(200).nullable()).optional().describe(\"prop key → help text; null = no help on purpose (stays empty, never refilled)\"),\n override: z.boolean().optional().describe(OVERRIDE_NOTE),\n ifMatch: z.number().int().min(0).optional().describe(COMPONENT_IF_MATCH_NOTE),\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n });\n const setComponentSourceInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n path: z.string().min(1).max(512).describe(\"file path relative to the app root, e.g. src/components/sections/Hero.astro\"),\n export: z.string().min(1).max(128).optional().describe(\"named export that renders it; omit for a default export\"),\n kind: z.enum([\"file\", \"section\"]).optional().describe(\"'file' (props are this component's fields; default) or 'section' (a codemod-extracted section: props { blockId, bind, overrides, page })\"),\n });\n const submitComponentizeReceiptInput = z.object({\n receipt: z.record(z.string(), z.unknown()).describe(\"The receipt `npx @bettercms-ai/convert --componentize --receipt <file>` wrote, verbatim.\"),\n });\n const componentValidationRouteInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n path: z.string().min(1).max(500).optional().describe(\"route in the app that serves the preview; omit for the default\"),\n nativeViewports: z.array(z.object({\n name: z.string().min(1).max(64),\n width: z.number().int().positive().max(10000),\n height: z.number().int().positive().max(10000),\n })).min(1).max(8).optional().describe(\"viewports to check; omit for the defaults\"),\n });\n const clearComponentSourceInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n });\n const getComponentInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n detachedCopy: z.object({ overrides: z.record(z.string(), z.unknown()).optional() }).optional().describe(DETACHED_COPY_NOTE),\n });\n const publishComponentsInput = z.object({\n componentIds: z.array(z.string().min(1)).min(1).max(100).describe(\"component ids (from list_components)\"),\n });\n const composePagesInput = z.object({\n pages: z\n .array(\n z.object({\n pageId: z.string().min(1).optional().describe(PARAM_TEXT.pageRef),\n slug: z.string().min(1).optional().describe(\"a page slug, when one page has it; or pass `pageId`\"),\n blockJson: z.array(blockObject).describe(\"REPLACES this page's whole block composition\"),\n }),\n )\n .min(1)\n .max(50),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n });\n const listComponentsInput = z.object({\n detail: z\n .boolean()\n .optional()\n .describe(\"true = every component's full blockJson and props. Costly and rarely what you want — read one definition with get_component instead.\"),\n });\n const listExtractionCandidatesInput = z.object({\n projectId: z.string().min(1).optional().describe(\"only needed for a workspace-wide key\"),\n });\n const extractComponentInput = z.object({\n hash: z.string().min(1).describe(\"candidate hash from list_extraction_candidates\"),\n name: z.string().min(1).describe(\"name for the new component\"),\n slug: slug.describe(\"url-safe unique slug (lowercase letters/numbers/hyphens)\"),\n projectId: z.string().min(1).optional().describe(\"only needed for a workspace-wide key\"),\n });\n /**\n * The content-lifecycle tools, in parity with the remote /mcp catalog. Each is a thin\n * call to an authenticated API route through the client's public request plumbing — no\n * bespoke SDK method per endpoint (DRY). Most target Management; Section evidence targets\n * the project-scoped ingest lane. `def`/`data` collapse the shared boilerplate.\n */\n function lifecycleTools(): ToolDef[] {\n const def = (\n name: string,\n title: string,\n description: string,\n shape: z.ZodRawShape,\n run: (client: ManagementApi, args: Record<string, unknown>) => Promise<ToolResult>,\n ): ToolDef => ({\n name,\n config: { title, description, inputSchema: shape },\n handler: guard(async (args: Record<string, unknown>) => withClient((client) => run(client, args))) as ToolDef[\"handler\"],\n });\n const q = (obj: Record<string, unknown>): string => {\n const p = new URLSearchParams();\n for (const [k, v] of Object.entries(obj)) if (v !== undefined && v !== null) p.set(k, String(v));\n const s = p.toString();\n return s ? `?${s}` : \"\";\n };\n /**\n * Call a management endpoint and return its `data` payload.\n *\n * 🔴 Do NOT set a content-type here. `ManagementApi.headers()` already sends\n * `Content-Type: application/json`, and `fetchJSON` merges headers as a PLAIN OBJECT —\n * so a lowercase `content-type` is a DIFFERENT key, both survive the spread, and the\n * Headers constructor then APPENDS them into `application/json, application/json`.\n * Hono's zValidator does not recognise that as JSON, reads the body as absent, and every\n * write here failed with a validation error naming a field the caller did send. It cost\n * all 16 body-carrying tools on this surface, silently, because the request looked\n * perfect from the client side and the server's complaint pointed at the body's contents.\n */\n const data = async (client: ManagementApi, method: string, path: string, body?: unknown): Promise<unknown> =>\n (await client.fetchJSON<{ data?: unknown }>(client.url(path), {\n method,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n })).data;\n const s = (v: unknown) => v as string;\n /** POST raw bytes (base64 → binary) for the binary deploy tool; returns `data`. */\n const raw = async (client: ManagementApi, path: string, base64: string, mimeType?: string): Promise<unknown> =>\n (await client.fetchJSON<{ data?: unknown }>(client.url(path), {\n method: \"POST\",\n body: Buffer.from(base64, \"base64\"),\n headers: { \"content-type\": mimeType ?? \"application/octet-stream\" },\n })).data;\n\n return [\n def(\"create_media_upload\", \"Get a presigned media-upload URL\",\n \"PREFERRED way to add an image — get a presigned URL and upload the file DIRECTLY to storage, so the bytes never pass through the conversation. Flow: (1) call this with filename, mimeType and sizeBytes (the file's exact byte length); (2) PUT the file to `uploadUrl`, e.g. `curl -X PUT -H 'Content-Type: image/jpeg' --data-binary @photo.jpg \\\"<uploadUrl>\\\"` — the url pins both headers, so they must match exactly; (3) call attach_media_upload with the `assetId` + `uploadKey`. URL expires in 10 minutes.\",\n z.object({\n filename: z.string().min(1).describe(\"file name incl. extension, e.g. 'hero.png'\"),\n mimeType: z.string().min(1).describe(\"MIME type, e.g. 'image/png'\"),\n sizeBytes: z.number().describe(\"the file's exact size in bytes (e.g. from `stat`/`wc -c`) — the presigned url pins it\"),\n }).shape,\n async (c, a) => ok(\"Upload URL.\", await data(c, \"POST\", `/management/media/upload-url`, { filename: a.filename, mimeType: a.mimeType, sizeBytes: a.sizeBytes }))),\n def(\"attach_media_upload\", \"Attach a presigned media upload\",\n \"Register a file you already uploaded via create_media_upload (step 3) into the Media Library and get back its CDN url. Pass the `assetId` + `uploadKey` from step 1, plus the filename and any alt text/caption.\",\n z.object({\n assetId: z.string().min(1).describe(\"the assetId from create_media_upload\"),\n uploadKey: z.string().min(1).describe(\"the uploadKey from create_media_upload, after the PUT succeeded\"),\n filename: z.string().min(1).describe(\"file name incl. extension\"),\n altText: z.string().optional(),\n caption: z.string().optional(),\n transcript: z.string().max(100_000).optional().describe(\"video/audio only: the spoken words (≤ 100,000 chars)\"),\n folderId: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Media asset.\", await data(c, \"POST\", `/management/media/from-upload`, { assetId: a.assetId, uploadKey: a.uploadKey, filename: a.filename, altText: a.altText, caption: a.caption, transcript: a.transcript, folderId: a.folderId }))),\n def(\"update_media\", \"Update a media asset\",\n \"Describe an existing media asset: set its alt text, caption, transcript, `decorative` (no alt text needed) or focal point (focalX/focalY, the spot crops keep in frame; delivered images carry it with width, height and thumbHash). A transcript (video/audio only, ≤ 100,000 chars) is stored ON the asset, so every page and entry using the file publishes it — hosted pages, the .md twin, llms-full.txt and the delivery API. Pass null to clear a field. Use this after your own speech-to-text; BetterCMS does not generate transcripts.\",\n z.object({\n assetId: z.string().min(1).describe(\"media asset id (from list_media / upload_asset)\"),\n altText: z.string().max(500).nullable().optional().describe(\"alt text; null clears\"),\n caption: z.string().max(1000).nullable().optional().describe(\"caption; null clears\"),\n transcript: z.string().max(100_000).nullable().optional().describe(\"the spoken words; null clears. Video/audio only.\"),\n decorative: z.boolean().optional().describe(\"needs no alt text\"),\n focalX: z.number().min(0).max(1).nullable().optional().describe(PARAM_TEXT.focalX),\n focalY: z.number().min(0).max(1).nullable().optional().describe(PARAM_TEXT.focalY),\n }).shape,\n async (c, a) => ok(\"Updated media asset.\", await data(c, \"PATCH\", `/management/media/${encodeURIComponent(s(a.assetId))}`, { altText: a.altText, caption: a.caption, transcript: a.transcript, decorative: a.decorative, focalX: a.focalX, focalY: a.focalY }))),\n def(\"list_media\", \"List media assets\",\n \"List the images/assets already in the connected project's Media Library (id, url, filename, mimeType, size, alt/caption). Reuse an existing asset instead of re-uploading. Filter with `search` or `type` ('image'|'video'|…).\",\n z.object({ search: z.string().optional(), type: z.string().optional(), limit: z.number().optional(), page: z.number().optional() }).shape,\n async (c, a) => ok(\"Media assets.\", await data(c, \"GET\", `/management/media${q({ search: a.search, type: a.type, limit: a.limit, page: a.page })}`))),\n def(\"get_media\", \"Get a media asset\",\n \"Get one media asset by id — its CDN url, filename, MIME type, size, and alt/caption. Use the url as the value of an 'image' field.\",\n z.object({ assetId: z.string().min(1).describe(\"media asset id (from list_media / upload_asset)\") }).shape,\n async (c, a) => ok(\"Media asset.\", await data(c, \"GET\", `/management/media/${s(a.assetId)}`))),\n def(\"delete_media\", \"Delete a media asset\",\n \"Delete a media asset from the Media Library (soft delete — reversible from the dashboard trash). Provide assetId.\",\n z.object({ assetId: z.string().min(1).describe(\"media asset id (from list_media)\") }).shape,\n async (c, a) => ok(\"Deleted media asset.\", await data(c, \"DELETE\", `/management/media/${s(a.assetId)}`))),\n\n def(\"delete_form\", \"Delete a form\",\n \"Delete a form by id. Soft delete — the form stops rendering and accepting submissions, but leads already collected against it are preserved. Use it to clean up forms created by mistake.\",\n z.object({ formId: z.string().min(1).describe(\"form id (from list_forms)\") }).shape,\n async (c, a) => ok(\"Deleted form.\", await data(c, \"DELETE\", `/management/forms/${s(a.formId)}`))),\n\n def(\"list_form_submissions\", \"List a form's submissions (leads)\",\n \"List the SUBMISSIONS (leads) a form has received — each with its submitted field values. Filter with status ('inbox'|'spam') and paginate with limit/page.\",\n z.object({ formId: z.string().min(1), status: z.enum([\"inbox\", \"spam\"]).optional(), limit: z.number().optional(), page: z.number().optional() }).shape,\n async (c, a) => ok(\"Form submissions.\", await data(c, \"GET\", `/management/forms/${s(a.formId)}/submissions${q({ status: a.status, limit: a.limit, page: a.page })}`))),\n def(\"delete_form_submission\", \"Delete a form submission\",\n \"Delete one form submission (lead) — e.g. to clear spam. Provide formId and submissionId (from list_form_submissions).\",\n z.object({ formId: z.string().min(1), submissionId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Deleted submission.\", await data(c, \"DELETE\", `/management/forms/${s(a.formId)}/submissions/${s(a.submissionId)}`))),\n\n // ── Content structure: the Content sidebar's folders and icons ──\n def(\"get_content_structure\", \"Get the Content sidebar structure\",\n `Returns { doc, version, summary }: \\`doc\\` is the raw document ({ schema: 1, folders: [{ id, parentId, name, icon, sort }], items: [{ kind: 'page'|'collection', id, folderId, sort, icon }] }), \\`version\\` is what set_content_structure needs, and \\`summary\\` is the resolved tree with page and collection TITLES (\\`outline\\` is a readable version), ids that no longer resolve (\\`missing\\`), and the pages and collections not in any folder yet. Call it before changing the structure; a 403 SCHEMA_ACCESS_REQUIRED on a change means this connection lacks Admin or Developer: stop and tell the user. ${STRUCTURE_FENCE}`,\n z.object({}).shape,\n async (c) => {\n const d = (await data(c, \"GET\", `/management/content-structure`)) as { summary?: { outline?: string } } | undefined;\n return ok(d?.summary?.outline ? `Content structure:\\n${d.summary.outline}` : \"Content structure.\", d);\n }),\n def(\"suggest_content_structure\", \"Propose the standard Content structure\",\n `READ-ONLY: propose the standard Content sidebar structure for the connected project (${STRUCTURE_PLAYBOOK_URI}) and write NOTHING. Runs the standard over the project's pages, collections, references and built routes: the home page and each collection's list page pinned, one folder per content family named for its detail type (Blog posts, Case studies, Products with its taxonomies and an Attributes subfolder), ordered by entry count (or the caller's nav order), shared taxonomies in Shared, every remaining page in Pages, at most 2 levels deep. Page-bound models are never filed. Returns { doc, version, hasDocument, outline, rationale }. To apply it: show the user the outline, then call set_content_structure with this doc and this version (the If-Match; a 412 means someone changed the sidebar, so suggest again). When hasDocument is true the project already has a structure somebody made: never replace it without the user's yes; file only what is new with move_to_folder instead.`,\n z.object({\n maxDepth: z.number().int().min(1).max(4).optional().describe(\"folder nesting to propose; default 2 (the standard), 4 is the hard limit\"),\n }).shape,\n async (c, a) => {\n const d = (await data(c, \"GET\", `/management/content-structure/suggest${q({ maxDepth: a.maxDepth })}`)) as { outline?: string } | undefined;\n return ok(d?.outline ? `Proposed Content structure (nothing was written):\\n${d.outline}` : \"Proposed Content structure.\", d);\n }),\n def(\"set_content_structure\", \"Replace the Content sidebar structure\",\n `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 ≤4, names 1-80 chars, kit icons (bettercms://icons/dock). 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}`,\n z.object({\n doc: z.object({\n schema: z.literal(1),\n folders: z.array(z.object({\n id: z.string().min(1).describe(\"your own stable id, up to 64 chars\"),\n parentId: z.string().nullable().describe(\"parent folder id; null = top level\"),\n name: z.string(),\n icon: z.string().nullable().describe(\"kit icon name (bettercms://icons/dock) or null\"),\n sort: z.number(),\n })),\n items: z.array(z.object({\n kind: z.enum([\"page\", \"collection\"]),\n id: z.string().min(1).describe(\"page id or collection (content model) id\"),\n folderId: z.string().nullable().describe(\"folder id; \\\"home:root\\\" = pinned at the top level; null = its home (Pages for a page, the Shared list for a collection)\"),\n sort: z.number(),\n icon: z.string().nullable(),\n })),\n }).describe(\"the complete document\"),\n version: z.number().int().min(0).describe(\"the version get_content_structure returned\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"PUT\", `/management/content-structure`, { doc: a.doc, version: a.version }))),\n def(\"create_folder\", \"Create a Content sidebar folder\",\n `Create a folder in the Content sidebar, at the top level or inside \\`parentId\\`, placed after what is already there. Returns the new \\`folderId\\`. Reads, applies and writes with the version check, retrying once on a conflict. ${STRUCTURE_FENCE}`,\n z.object({\n name: z.string().min(1).describe(\"the folder's label, 1-80 chars\"),\n parentId: z.string().min(1).optional().describe(\"optional parent folder id (from get_content_structure); omit it, or send 'root', for the top level\"),\n icon: z.string().min(1).optional().describe(\"optional kit icon name (bettercms://icons/dock), e.g. 'folder'\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"POST\", `/management/content-structure/folders`, { name: a.name, parentId: a.parentId, icon: a.icon }))),\n def(\"rename_folder\", \"Rename a Content sidebar folder\",\n `Rename a Content sidebar folder. ${STRUCTURE_POINTER}`,\n z.object({\n folderId: z.string().min(1).describe(\"folder id (from get_content_structure)\"),\n name: z.string().min(1).describe(\"the new label, 1-80 chars\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"PATCH\", `/management/content-structure/folders/${encodeURIComponent(s(a.folderId))}`, { name: a.name }))),\n def(\"move_to_folder\", \"Move into a Content sidebar folder\",\n `Move a page, a collection or a folder into a folder. folderId null moves it back to its home: Pages for a page, the Shared list for a collection, the top level for a folder. It lands after what is already there. Moving a folder takes its contents with it and is refused if the result would nest deeper than 4 levels or put a folder inside itself. ${STRUCTURE_POINTER}`,\n z.object({\n kind: z.enum([\"page\", \"collection\", \"folder\"]).describe(\n \"what the id IS on this branch — 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.\",\n ),\n id: z.string().min(1).describe(\"the page id, collection (content model) id, or folder id\"),\n folderId: z.string().min(1).nullable().describe(\"target folder id; 'root' pins a page or collection at the top level (for a folder, 'root' is the top level); null moves it back to its home (Pages, the Shared list, or the top level for a folder)\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"POST\", `/management/content-structure/move`, { kind: a.kind, id: a.id, folderId: a.folderId }))),\n def(\"set_brand_assets\", \"Point the brand's logo or favicon at a media asset\",\n `Point the brand's logo (mark) or favicon at a media asset of this project — upload it to this project's media library first if it is not there. A slot a PERSON chose is refused without replace: true, and the refusal says so. ${BRAND_KIT_POINTER}`,\n z.object({\n mark: z.string().min(1).nullable().optional().describe(\"media asset id for the logo; null clears it\"),\n favicon: z.string().min(1).nullable().optional().describe(\"media asset id for the favicon; null clears it\"),\n replace: z.boolean().optional().describe(\"override a slot a person chose (default false)\"),\n }).shape,\n async (c, a) => ok(\"Brand assets.\", await data(c, \"POST\", `/management/projects/current/brand-kit/assets`, { mark: a.mark, favicon: a.favicon, replace: a.replace }))),\n def(\"set_brand_graphics\", \"Add, replace or remove the brand's gradients\",\n `Add, replace or remove the brand's gradients — the blobs and washes a site uses as backgrounds. They are TOKENS, not media. A stop naming a colour the kit does not have is refused; add it to \\`extras\\` first. Upsert matches BY KEY. ${BRAND_KIT_POINTER}`,\n z.object({\n upsert: z.array(z.object({\n key: z.string().min(1).describe(\"token key: lowercase letters, digits and hyphens. Emitted as --brand-gradient-<key>\"),\n label: z.string().optional(),\n kind: z.enum([\"linear\", \"radial\", \"conic\"]),\n angle: z.number().optional().describe(\"degrees 0-360; ignored for radial\"),\n stops: z.array(z.object({\n color: z.string().min(1).describe(\"a kit colour KEY — a colors.* role name or an extras key. Never a hex.\"),\n at: z.number().describe(\"position 0-100\"),\n })).min(2).max(8),\n })).max(12).optional().describe(\"gradients to add or replace, matched BY KEY\"),\n remove: z.array(z.string().min(1)).max(12).optional().describe(\"gradient keys to remove\"),\n }).shape,\n async (c, a) => ok(\"Brand graphics.\", await data(c, \"POST\", `/management/projects/current/brand-kit/graphics`, { upsert: a.upsert, remove: a.remove }))),\n def(\"set_icon\", \"Set a Content sidebar icon\",\n `Set or clear the sidebar icon of a page, a collection or a folder. ${STRUCTURE_POINTER}`,\n z.object({\n kind: z.enum([\"page\", \"collection\", \"folder\"]).describe(\n \"what the id IS on this branch — 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.\",\n ),\n id: z.string().min(1).describe(\"the page id, collection (content model) id, or folder id\"),\n icon: z.string().min(1).nullable().describe(\"kit icon name (bettercms://icons/dock), e.g. 'document-text'; null clears it\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"POST\", `/management/content-structure/icon`, { kind: a.kind, id: a.id, icon: a.icon }))),\n def(\"delete_folder\", \"Delete a folder (its contents move up; nothing is deleted)\",\n `Delete a folder (its contents move up; nothing is deleted). NOTHING ELSE IS DELETED: its pages, collections and sub-folders move up to the folder's parent, in the same order. ${STRUCTURE_POINTER}`,\n z.object({ folderId: z.string().min(1).describe(\"folder id (from get_content_structure)\") }).shape,\n async (c, a) => structureResult(await data(c, \"DELETE\", `/management/content-structure/folders/${encodeURIComponent(s(a.folderId))}`))),\n\n def(\"list_redirects\", \"List redirects\",\n \"List the URL redirects configured for the connected project (source path → destination, type).\",\n z.object({}).shape,\n async (c) => ok(\"Redirects.\", await data(c, \"GET\", `/management/redirects`))),\n def(\"update_redirect\", \"Update a redirect\",\n \"Update an existing redirect in place — change where it points, its HTTP status, or disable it without deleting. Prefer this over delete+create: it keeps the redirect's id and preserves the chain-collapse rewrites of other rules pointing at it. Only provided fields change. Loops 422, duplicate sources 409.\",\n z.object({ redirectId: z.string().min(1).describe(\"redirect id (from list_redirects)\"), sourcePath: z.string().min(1).optional(), destination: z.string().min(1).optional(), redirectType: z.enum([\"301\", \"302\", \"307\", \"308\", \"410\"]).optional().describe(\"HTTP status; 410 = Gone\"), isActive: z.boolean().optional().describe(\"set false to disable without deleting\") }).shape,\n async (c, a) => ok(\"Updated redirect.\", await data(c, \"PATCH\", `/management/redirects/${s(a.redirectId)}`, { sourcePath: a.sourcePath, destination: a.destination, redirectType: a.redirectType, isActive: a.isActive }))),\n def(\"create_redirect\", \"Create a redirect\",\n \"Create a URL redirect — e.g. a 301 after renaming a page's slug. `sourcePath` is the path to redirect FROM ('/old-page'), `destination` the path/url TO ('/new-page'). Chains collapse; loops/dupes rejected. Defaults to 301.\",\n z.object({ sourcePath: z.string().min(1), destination: z.string().min(1).optional(), redirectType: z.enum([\"301\", \"302\", \"307\", \"308\", \"410\"]).optional().describe(\"default '301'; 410 = Gone, omit destination\"), dryRun: z.boolean().optional().describe(\"true = return the verdict, write nothing\") }).shape,\n async (c, a) => ok(a.dryRun === true ? \"Dry run: nothing written.\" : \"Created redirect.\", await data(c, \"POST\", `/management/redirects`, { sourcePath: a.sourcePath, destination: a.destination, redirectType: a.redirectType, dryRun: a.dryRun }))),\n def(\"import_redirects\", \"Import redirects\",\n NEW_TOOL_TEXT.import_redirects,\n z.object({\n rows: z.array(z.record(z.string(), z.unknown())).optional().describe(\"[{ sourcePath, destination?, redirectType? }]\"),\n text: z.string().optional().describe(\"the file's contents, instead of rows\"),\n format: z.enum([\"csv\", \"_redirects\", \"vercel\"]).optional().describe(\"of `text` (default 'csv')\"),\n dryRun: z.boolean().optional().describe(\"default false\"),\n }).shape,\n async (c, a) => ok(a.dryRun === true ? \"Dry run: nothing written.\" : \"Imported redirects.\", await data(c, \"POST\", `/management/redirects/import`, { rows: a.rows, text: a.text, format: a.format, dryRun: a.dryRun }))),\n def(\"delete_redirect\", \"Delete a redirect\",\n \"Delete a URL redirect by id (from list_redirects). Provide redirectId.\",\n z.object({ redirectId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Deleted redirect.\", await data(c, \"DELETE\", `/management/redirects/${s(a.redirectId)}`))),\n\n def(\"save_reusable_block\", \"Save a section as a reusable block\",\n NEW_TOOL_TEXT.save_reusable_block,\n z.object({ pageId: z.string().min(1), blockId: z.string().min(1).describe(\"a top-level section id (get_page)\"), name: z.string().min(1).describe(\"80 characters at most; a longer one is refused as SAVED_BLOCK_NAME_TOO_LONG\") }).shape,\n async (c, a) => ok(\"Saved the section as a reusable block.\", await data(c, \"POST\", `/management/saved-blocks`, { pageId: a.pageId, blockId: a.blockId, name: a.name }))),\n\n def(\"get_seo\", \"Get site SEO\",\n GET_SEO_DESCRIPTION,\n z.object({}).shape,\n async (c) => ok(\"SEO settings.\", await data(c, \"GET\", `/management/seo`))),\n def(\"update_seo\", \"Update site SEO\",\n UPDATE_SEO_DESCRIPTION,\n seoPatchShape,\n async (c, a) => ok(\"Updated SEO.\", await data(c, \"PATCH\", `/management/seo`, Object.fromEntries(Object.keys(seoPatchShape).filter((k) => a[k] !== undefined).map((k) => [k, a[k]]))))),\n\n def(\"get_site_files\", \"List site files\",\n \"List the AI-crawler files installed on the connected project (llms.txt / llms-full.txt) — metadata only.\",\n z.object({}).shape,\n async (c) => ok(\"Site files.\", await data(c, \"GET\", `/management/site-files`))),\n def(\"set_site_file\", \"Set a site file\",\n \"Create or replace an AI-crawler file served at the site root — `kind` 'llms.txt' or 'llms-full.txt' — with `content` (plain text, max 5 MB). Rebuilds the site.\",\n z.object({ kind: z.enum([\"llms.txt\", \"llms-full.txt\"]), content: z.string() }).shape,\n async (c, a) => ok(\"Saved site file.\", await data(c, \"PUT\", `/management/site-files/${s(a.kind)}`, { content: a.content }))),\n def(\"delete_site_file\", \"Delete a site file\",\n \"Remove an AI-crawler file (llms.txt / llms-full.txt) from the connected project. Provide kind.\",\n z.object({ kind: z.enum([\"llms.txt\", \"llms-full.txt\"]) }).shape,\n async (c, a) => ok(\"Deleted site file.\", await data(c, \"DELETE\", `/management/site-files/${s(a.kind)}`))),\n\n // ── Editorial board ──\n // Publishing is two decisions: may the KEY publish (content:publish, granted at\n // consent) and may the ITEM publish (it must sit in the board's gate stage). These\n // tools are the second one. Without them a publish-enabled connection still dead-ends\n // on a 409 the moment a project uses review columns.\n def(\"get_workflow_board\", \"List editorial workflow stages\",\n \"List the connected project's editorial board columns in order — each stage's `key`, name, and whether it is the `publishGate` (the one stage content may go live from). Read this BEFORE move_stage: stage keys are per-project and not guessable, because a project can rename or replace every column.\",\n z.object({}).shape,\n async (c) => ok(\"Workflow stages.\", await data(c, \"GET\", `/management/workflow/stages`))),\n def(\"move_stage\", \"Move an entry or a page across the board\",\n MOVE_STAGE_DESCRIPTION,\n z.object({\n entryId: z.string().min(1).optional().describe(\"the entry to move; or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of entryId: the page to move\"),\n workflowStage: z.string().max(64).describe(\"stage key from get_workflow_board\"),\n fromStage: z.string().max(64).optional().describe(\"the stage you believe it is in — 409s if it has moved\"),\n }).shape,\n async (c, a) => {\n if (!a.entryId === !a.pageId) return fail(\"Pass exactly one of entryId (a content entry) or pageId (a page).\");\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/workflow` : `/management/content/entries/${s(a.entryId)}/workflow`;\n return ok(a.pageId ? \"Moved page.\" : \"Moved entry.\", await data(c, \"PATCH\", path, { workflowStage: a.workflowStage, fromStage: a.fromStage }));\n }),\n\n def(\"promote_project\", \"Promote staging → production\",\n \"Promote the connected project's STAGED build to PRODUCTION — the one-click publish. Flips prod to the newest staged release (no rebuild) after the QA scan passes. Managed hosting only; needs a publish-enabled connection.\",\n z.object({}).shape,\n async (c) => ok(\"Promoted to production.\", await data(c, \"POST\", `/management/projects/promote`))),\n\n def(\"list_entry_versions\", \"List a content entry's versions\",\n \"List a content entry's version history (newest first) — each version's number, data snapshot, and when it was saved. Use it to find a past state to restore.\",\n z.object({ entryId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Entry versions.\", await data(c, \"GET\", `/management/content/entries/${s(a.entryId)}/versions`))),\n def(\"restore_entry_version\", \"Restore a content entry to a past version\",\n \"Restore a content entry to a past version (undo). Copies that version's data back as the current DRAFT (non-destructive). Publish afterwards to take it live. Provide entryId and the version number (from list_entry_versions).\",\n z.object({ entryId: z.string().min(1), version: z.number().int().positive() }).shape,\n async (c, a) => ok(\"Restored entry version.\", await data(c, \"POST\", `/management/content/entries/${s(a.entryId)}/versions/${a.version}/restore`))),\n\n // ── Project / workspace (parity with remote /mcp) ──\n def(\"get_project\", \"Get the connected project\",\n \"Get the connected project's info — id, name, slug, subdomain, and its live URL (https://<handle>.bettercms.site). Use it to tell the user where their site is published / link the result. It also returns `useCdn` and `mediaBaseUrl` — the origin this project's media is minted and resized on. A deployed site's `PUBLIC_BCMS_MEDIA_URL` / `mediaUrl` must equal `mediaBaseUrl`, or resized images 404 on any rung but production. \" + BRAND_KIT_NOTE,\n z.object({}).shape,\n async (c) => ok(\"Project.\", await data(c, \"GET\", `/management/projects/current`))),\n def(\"list_projects\", \"List projects\",\n \"List the projects this key can see — id, name, slug, and live URL each. A project-scoped key sees only its own project; a workspace-level key sees every project in the workspace. Use it to find a project you created earlier, or to confirm which sites exist before acting.\",\n z.object({}).shape,\n async (c) => ok(\"Projects.\", await data(c, \"GET\", `/management/projects`))),\n {\n name: \"whoami\",\n config: { title: \"Who this connection acts as\", description: WHOAMI_DESCRIPTION, inputSchema: {} },\n /**\n * The stdio server holds a device-grant token and nothing that lists its grants, so it\n * reports only what it can observe: whether GET /projects/current resolves a project with\n * none named (a project-bound grant) or refuses with 400 (a workspace-wide one). The\n * lifted `projectId`, when sent, is checked separately — it must not decide the scope.\n */\n handler: guard(async () => {\n const requested = currentProject.getStore();\n const current = (c: ManagementApi) => data(c, \"GET\", `/management/projects/current`) as Promise<ProjectSummary>;\n const bound = await currentProject.run(undefined, () =>\n withClient(async (c) => {\n try {\n return { apiBaseUrl: c.url(\"\"), project: await current(c) };\n } catch (err) {\n if (err instanceof BetterCMSError && err.status === 400) return { apiBaseUrl: c.url(\"\"), project: null };\n throw err;\n }\n }),\n );\n const target = requested ? await withClient(current) : null;\n const pick = (p: ProjectSummary | null) => (p ? { id: p.id, name: p.name, slug: p.slug } : null);\n const scope = bound.project ? \"project\" : \"workspace\";\n return ok(\n bound.project\n ? `Bound to project '${bound.project.slug}' through a device grant.`\n : \"A workspace-wide device grant: pass projectId on every project tool.\",\n {\n surface: \"stdio\",\n principal: { kind: \"device_grant\" },\n apiBaseUrl: bound.apiBaseUrl,\n scope,\n workspaceSlug: (bound.project ?? target)?.workspaceSlug ?? null,\n project: pick(bound.project),\n ...(requested ? { requestedProject: pick(target) } : {}),\n grants: null,\n note: \"This server cannot see the connection's grants; a missing one is a 403 naming it on the call that needs it. The hosted connector's whoami lists them.\",\n },\n );\n }) as ToolDef[\"handler\"],\n },\n def(\"update_project\", \"Update the connected project\",\n \"Update the connected project's settings — rename it, change its slug/description, SEO defaults, visibility, or `presentation`. Only the provided fields change. `subdomainAlias` renames the staging URL: 'astronapp' serves the site at astronapp.bettercms.site (3–55 lowercase letters, numbers, hyphens; 409 when taken; null goes back to the original). The original <handle>.bettercms.site keeps working; a replaced name is released. `presentation` themes the platform's OWN renderer (the one serving a site built in the CMS with no deployed build, and previewing structural drafts everywhere) with the same closed knobs as bcms-presentation.json — DTCG { $type, $value } tokens keyed like 'page.maxWidth', 'nav.background'. Without it that renderer is a generic 768px document theme. An invalid manifest is 422 PRESENTATION_INVALID.\",\n z.object({ name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), visibility: z.string().optional(), seoDefaults: z.record(z.string(), z.unknown()).optional(), presentation: z.record(z.string(), z.unknown()).optional().describe(\"theme knobs for the platform renderer, keyed like bcms-presentation.json\"), subdomainAlias: z.string().nullable().optional().describe(\"the staging name: 'astronapp' → astronapp.bettercms.site; null = back to the original\") }).shape,\n async (c, a) => ok(\"Updated project.\", await data(c, \"PATCH\", `/management/projects/current`, a))),\n def(\"create_project\", \"Create a new project\",\n \"Create a NEW project (site) in the connected workspace. ASK THE USER WHICH TECHNOLOGY TO BUILD WITH FIRST and pass it as `framework` — 'astro' (recommended default), 'next', 'react-ts' (React + TypeScript), or 'other' for a headless project with no generated frontend. Do not pick for them: called without it, this tool asks them directly (or hands you the question to ask). Sites cannot be created as plain HTML/CSS — every project is backed by one of these starters, which is what makes its content editable in the CMS. Optionally pass templateId to seed curated content. Returns the new project's id and slug. (Use clone_project instead to duplicate an existing project.)\",\n // `framework` is OPTIONAL in the schema on purpose, even though it is required in\n // effect: a required arg is rejected by the SDK before the handler runs, which would\n // kill the elicitation below and leave the model guessing on its own. Optional here,\n // answered by a human there. The backend rejects a create with no framework regardless.\n z.object({ name: z.string().min(1), slug: z.string().optional(), description: z.string().optional(), templateId: z.string().optional(), framework: z.enum(FRAMEWORK_CHOICES).optional().describe(\"REQUIRED in effect — the technology the USER chose. Ask them; never default it.\") }).shape,\n async (c, a) => {\n let framework = a.framework;\n if (framework === undefined) {\n const asked = await askFramework(deps);\n if (\"prompt\" in asked) return fail(asked.prompt);\n framework = asked.value;\n }\n return ok(\"Created project.\", await data(c, \"POST\", `/management/projects`, { ...a, framework }));\n }),\n def(\"set_authoring_preference\", \"Set the site's authoring architecture\",\n \"Record which authoring architecture this site uses — 'components' (RECOMMENDED: reusable section components placed as blocks; editors add, reorder and swap sections without touching a schema — recommend it for every marketing, landing, agency or product site) or 'fields' (a typed field schema per page — only for a blog, catalogue or directory where many rows share one shape). ASK THE USER; do not pick for them. Called without `preference`, this tool asks them directly (or hands you the question to ask). deploy_project and promote_project both refuse with 409 AUTHORING_DECISION_REQUIRED until it is set, carrying this project's real page counts to show the user. Unset, editor_setup componentizes nothing; only `components` lets it place sections. On a site whose pages were DERIVED at import, answering 'components' redoes nothing: after set_authoring_preference, get_componentize_plan proposes one component per section (it reads the PUBLISHED pages — no deploy needed to reach it), you confirm it with the user, then componentize_sections places them with `props.bind` (dry run first — they land as drafts and the page keeps its fields, values and bindings, so click-to-edit and the coverage meter are unchanged), then publish_component each one, publish the pages, run `npx @bettercms-ai/convert --componentize` in the repo, and deploy. Asked once per project; re-callable if the user changes their mind.\",\n // Optional in the schema for exactly the reason `framework` is above: a required arg is\n // rejected by the SDK before the handler runs, which would kill the elicitation below\n // and leave the model guessing. Optional here, answered by a human there. The backend\n // gate refuses the deploy regardless, so nothing ships on a guess.\n z.object({ preference: z.enum(AUTHORING_CHOICES).optional().describe(\"REQUIRED in effect — the architecture the USER chose. Ask them; never default it.\") }).shape,\n async (c, a) => {\n let preference = a.preference;\n if (preference === undefined) {\n const asked = await askAuthoring(deps);\n if (\"prompt\" in asked) return fail(asked.prompt);\n preference = asked.value;\n }\n return ok(\"Recorded the authoring architecture.\", await data(c, \"PATCH\", `/management/projects/current/authoring-preference`, { preference }));\n }),\n def(\"set_binding_mode\", \"Set how the site's bindings are resolved\",\n \"Switch this project between the two binding resolvers, from the NEXT release on. `declaredBindings: true` makes the annotator trust the template's own data-bcms-field / data-bcms-props and never guess from rendered text — the durable state; `false` returns to text-matching, which holds only while the CMS values equal the built copy. Call it ONLY after every page's copy is declared in the template: undeclared fields stop being editable. The order around the flip (push, release, clean get_binding_report, flip, release, confirm): skill bindings. Flipping back is the same call. REQUIRES artifact:write (the authority that deploys the site): this decides what every future release does to every page. On a workspace-wide connection pass `projectId`: the scope is there, but the human who authorized the connection must be able to publish THAT project or it is refused with 403 PROJECT_PUBLISH_DENIED. Playbook section 13.\",\n z.object({ declaredBindings: z.boolean().describe(\"true = trust the template's declared bindings; false = text-match (the default)\") }).shape,\n async (c, a) => ok(\"Recorded the binding mode.\", await data(c, \"PATCH\", `/management/projects/current/binding-mode`, { declaredBindings: a.declaredBindings }))),\n def(\"set_media_delivery\", \"Choose where this site's media is served from\",\n \"Record whether this project's media (images, video, files) is served from the BetterCMS CDN or from the API origin. `useCdn: true` is the DEFAULT and the recommendation: URLs are minted on the CDN host, or on the project's own CDN base when it stores media in its own bucket (BYOK). `useCdn: false` mints them on the API origin instead — the same service serving the same bytes, only under a different hostname. ASK THE USER; do not pick for them. Called without `useCdn`, this tool asks them directly (or hands you the question to ask). 🔴 IT APPLIES TO URLs MINTED FROM NOW ON — new uploads, entry saves, get_media. It does NOT rewrite URLs already stored in published content, and it does not need to: the old URLs keep resolving. To move an existing image, re-save the field that holds it. 🔴 IT IS THE BACKEND HALF ONLY. A deployed frontend builds its own transform URLs with @bettercms-ai/image-url, which has its own media host — set `PUBLIC_BCMS_MEDIA_URL` (or the integration's `mediaUrl` option) to match, or that site's resized images stay on the CDN while everything else moves. Read the current answer from get_project: `useCdn` is the choice, `mediaBaseUrl` is the origin it produces — the value the frontend's `PUBLIC_BCMS_MEDIA_URL` must match. Re-callable; the last answer wins.\",\n // Optional in the schema for the same reason `framework` and `preference` are: a\n // required arg is rejected by the SDK before the handler runs, which would kill the\n // elicitation below and leave the model guessing.\n z.object({ useCdn: z.boolean().optional().describe(\"REQUIRED in effect — the USER's answer. true = CDN (the default), false = API origin. Ask them; never default it.\") }).shape,\n async (c, a) => {\n let useCdn = a.useCdn;\n if (useCdn === undefined) {\n const asked = await askMediaDelivery(deps);\n if (\"prompt\" in asked) return fail(asked.prompt);\n useCdn = asked.value;\n }\n return ok(\"Recorded the media delivery origin.\", await data(c, \"PATCH\", `/management/projects/current/media-delivery`, { useCdn }));\n }),\n def(\"submit_conversion_receipt\", \"Record what the conversion codemod could and could not do\",\n \"Hand BetterCMS the codemod's own account of a run, so the meter can say WHY a path is undeclared. Submit the receipt `npx @bettercms-ai/convert --receipt out.json` wrote as `{ briefDigest, receipt }`, for the SAME `briefDigest` get_conversion_brief { complete: true } returned (its shape: see `receipt`). 🔴 A RECEIPT WITH PENDING PATHS IS A PROGRESS REPORT, NOT A FINISH LINE: the response answers `complete` and `pendingTotal`, and echoes the first 40 pending rows with their `fix` (`action` one of `wrap-span`, `declare-attr`, `bind-expression`, `declare-richtext`, `bind-data`, `manual`; the row shape: skill bindings; a 404 `unknown-brief` means that digest was never issued here). Apply every fix, rerun, resubmit: only `complete: true` ends a conversion — never report a site converted on less. It is a RECORD, not a release: nothing on the site changes; the meter reads it on the get_binding_report after the next deploy. 🔴 The same run owes two more things (playbook §13 steps 2b and 3b): the `--forms` receipt (a SECOND call, same `briefDigest`) and the `styleEdits` of `convert --verify-styles` inside this receipt; any changed class or style is refused with 409 `style-edits`. Requires artifact:write.\",\n z.object({\n briefDigest: z.string().min(1).describe(\"The `briefDigest` get_conversion_brief { complete: true } returned. Must match the receipt's own.\"),\n receipt: z.record(z.string(), z.unknown()).describe(\"The receipt `npx @bettercms-ai/convert --receipt out.json` wrote, verbatim: `paths: { declared, rewritten, alreadyDeclared, pending[{ route, scope, path, kind, file, reason, message, fix }] }` plus `styleEdits`. `paths.declared` must equal rewritten + alreadyDeclared + pending.length; each pending `reason` is the converter's own (IN_EXPRESSION, AMBIGUOUS_LITERAL, REPEATER_FIXED_LENGTH, PARSE_ERROR, …); a path with no row reads `not-declared`.\"),\n }).shape,\n async (c, a) => ok(\"Recorded the conversion receipt.\", await data(c, \"POST\", `/management/projects/current/conversion-receipt`, { briefDigest: a.briefDigest, receipt: a.receipt }))),\n def(\"clone_project\", \"Clone a project\",\n \"Clone (duplicate) a project as a reusable template into the connected workspace. Copies pages, content models + entries, components, media, forms, and SEO/custom-code settings; excludes submissions, analytics, domains, and secrets. Returns the new project's id and slug. Omit sourceProjectId to clone the connected project.\",\n z.object({ sourceProjectId: z.string().optional(), name: z.string().optional(), slug: z.string().optional() }).shape,\n async (c, a) => ok(\"Cloned project.\", await data(c, \"POST\", `/management/projects/clone`, a))),\n\n // ── Content models (read/metadata; parity with remote /mcp) ──\n def(\"list_content_models\", \"List content models\",\n \"List the content models (reusable schemas for dynamic collections like Blog/Products) in the connected project. A project-scoped connection sees its own project's models plus workspace-level ones, which it can read but not change.\",\n z.object({}).shape,\n async (c) => ok(\"Content models.\", await data(c, \"GET\", `/management/content/models`))),\n def(\"get_content_model\", \"Get a content model\",\n \"Get one content model by id INCLUDING its full field schema (keys, types, nested group/repeater children) AND each field's stored authoring props — `helpText`, `showIf`, `ui`. Read it before add_field so you know the existing keys, and AFTER declaring `ui`/`showIf`/`helpText` as the receipt that the declaration actually landed: a prop that is missing from this response was not stored, whatever the write returned. Its `optimisticVersion` is the ifMatch for update_content_model.\",\n z.object({ modelId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Content model.\", await data(c, \"GET\", `/management/content/models/${s(a.modelId)}`))),\n def(\"update_content_model\", \"Update a content model's metadata\",\n UPDATE_MODEL_DESCRIPTION,\n z.object({\n modelId: z.string().min(1).optional().describe(\"content model id (from list_content_models); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of modelId: the page whose schema model to edit; ifMatch is get_page backingModel.optimisticVersion\"),\n name: z.string().optional(),\n slug: z.string().optional(),\n description: z.string().optional(),\n urlPattern: urlPatternArg,\n fieldsets: fieldsetsArg.nullable(),\n fieldUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(FIELD_UI_ARG_NOTE),\n fieldFieldset: z.record(z.string(), z.string().min(1).nullable()).optional().describe(\"path → fieldset id, null takes it out\"),\n fieldOrder: z.strictObject({ parentPath: z.string().min(1).optional(), order: z.array(z.string().min(1)).min(1).max(200) }).optional().describe(\"the full new order of one parent's child keys (top level without parentPath). An array with both zones needs 'KEY.zones.nonRepeatable' or 'KEY.zones.repeatable'; its bare key is a 400\"),\n fieldLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe(\"path → label\"),\n fieldHelpText: z.record(z.string(), z.string().max(500).nullable()).optional().describe(\"path → help text, null clears it\"),\n override: z.boolean().optional().describe(OVERRIDE_NOTE),\n ifMatch: z.number().int().min(0).optional().describe(MODEL_IF_MATCH_NOTE),\n removeFields: z.array(z.string().min(1)).min(1).max(100).optional().describe(FIELD_REMOVAL_NOTE),\n allowFieldRemoval: z.boolean().optional().describe(ALLOW_FIELD_REMOVAL_NOTE),\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n }).shape,\n // `fields` is sent only by removeFields, rebuilt from the model just read: the PATCH\n // replaces `fields` wholesale when present.\n async (c, a) => {\n if (Boolean(a.modelId) === Boolean(a.pageId)) return fail(\"Send exactly one of modelId or pageId.\");\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/model` : `/management/content/models/${s(a.modelId)}`;\n const body: Record<string, unknown> = Object.fromEntries(\n MODEL_UPDATE_KEYS.filter((k) => a[k] !== undefined).map((k) => [k, k === \"fieldsets\" ? dropProvenance(a[k] as never) : a[k]]),\n );\n let ifMatch = a.ifMatch;\n const removal = fieldRemovalRequest(a);\n if (removal.kind === \"refuse\") return fail(removal.error);\n if (removal.kind === \"remove\") {\n const plan = planFieldRemoval((await data(c, \"GET\", path)) as StoredModel, removal.keys, a.ifMatch as number | undefined);\n if (!plan.ok) return fail(plan.error);\n body.fields = plan.fields;\n body.allowFieldRemoval = true;\n ifMatch = plan.ifMatch;\n }\n return ok(\n \"Updated content model.\",\n (\n await c.fetchJSON<{ data?: unknown }>(c.url(path), {\n method: \"PATCH\",\n body: JSON.stringify(body),\n ...withHeaders({ ...(ifMatch !== undefined ? { \"if-match\": `W/\"${ifMatch}\"` } : {}), ...confirmedHeaders(a.confirmed) }),\n })\n ).data,\n );\n }),\n def(\"get_content_types\", \"Get generated TypeScript types\",\n \"Get the auto-generated TypeScript types for the connected project's content models/pages. Pull these to write correctly-typed code against the BetterCMS delivery SDK in the user's site.\",\n z.object({}).shape,\n async (c) => ok(\"Content types.\", await data(c, \"GET\", `/management/content/types`))),\n\n // ── Pages (metadata edit; parity with remote /mcp) ──\n def(\"remove_page_fields\", \"Remove fields from a page\",\n \"Delete page fields and their stored values (draft, published, every repeater row) in one transaction. Dry run by default: returns removedKeys, entriesWithContent, keysWithContent, liveCopyChanges and writes nothing. A field holding content needs discardContent:true (409 FIELDS_HOLD_CONTENT otherwise). keys: exact get_page keys, dotted for a group/repeater child (`features.icon`). Changing the live copy needs publish permission. Never use it to rename a field.\",\n z.object({\n pageId: z.string().min(1).describe(\"page id (from list_pages)\"),\n keys: z.array(z.string().min(1)).min(1).describe(\"field keys to remove\"),\n dryRun: z.boolean().optional().describe(\"default true\"),\n discardContent: z.boolean().optional().describe(\"delete fields that hold content, and the content\"),\n }).shape,\n // The whole body: a dry run answers with the report and no `data`.\n async (c, a) => {\n const res = await c.fetchJSON<Record<string, unknown>>(c.url(`/management/pages/${s(a.pageId)}/fields/remove`), {\n method: \"POST\",\n body: JSON.stringify({ keys: a.keys, dryRun: a.dryRun, discardContent: a.discardContent }),\n });\n return ok(res.dryRun ? \"Dry run — nothing removed.\" : \"Removed fields.\", res);\n }),\n def(\"update_page\", \"Edit a page\",\n \"Edit a page: title, slug, SEO metaTitle/metaDescription, structured data (`schemaType`, `schema`), publish status (draft|published), and `blockJson` (its block composition — passing an array REPLACES the whole array, so read get_page first and send its `optimisticVersion` as `ifMatch`; an object adds or styles ONE section). An answer that starts with `held` is a draft the live page will NOT show until each of `holds` has its `action` taken, and a publish answers with `outcome`: `partial` lists the values not live. Never report either as done (skill publishing). `warnings`: COMPONENT_SWAP_DROPS_OVERRIDES (skill components), ENTRY_STILL_DRAFT and COMPONENT_DRAFT (skill publishing). It does NOT change the field SCHEMA — use add_field (pageId) / set_page_content for that. Renaming the slug keeps content intact. Publishing copies the draft blocks live in the same call, and a singleton's content entry with them. STRUCTURED DATA is native SEO, never a field: Automatic JSON-LD from the content, unless `schemaType` picks a schema.org type or pasted `schema` (wins over both, null clears it) is set (skill seo). \" + PAGE_HEAD_NOTE + \" \" +\n DOCTRINE,\n z.object({ ...headPatchShape, noindex: z.boolean().optional().describe(\"hide this page from search engines and site search\"), pageId: z.string().min(1).describe(PARAM_TEXT.pageRef), title: z.string().optional(), slug: z.string().optional(), blockJson: z.union([z.array(blockObject), z.object({ insertSection: z.object({ componentId: z.string().min(1), at: z.number().int().min(0).optional(), before: z.string().optional(), after: z.string().optional(), style: z.record(z.string(), z.unknown()).optional(), overrides: z.record(z.string(), z.unknown()).optional() }).strict().optional(), sectionStyle: z.object({ blockId: z.string().min(1), style: z.record(z.string(), z.unknown()) }).strict().optional() }).strict()]).optional().describe(PARAM_TEXT.pageBlockJson), metaTitle: z.string().optional(), metaDescription: z.string().optional(), schemaType: z.enum([\"auto\", ...SCHEMA_ORG_TYPES]).optional().describe(\"structured data type; 'auto' (the default) derives it from the content\"), schema: z.union([z.record(z.string(), z.unknown()), z.array(z.record(z.string(), z.unknown()))]).nullable().optional().describe(\"custom JSON-LD; wins over schemaType; null clears it\"), status: z.enum([\"draft\", \"published\"]).optional(), scheduledAt: z.string().datetime().nullable().optional().describe(PARAM_TEXT.pageScheduledAt), unpublishAt: z.string().datetime().nullable().optional().describe(PARAM_TEXT.pageUnpublishAt), locale: z.string().nullable().optional().describe(PARAM_TEXT.locale), translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf), ifMatch: z.number().int().min(0).optional().describe(UPDATE_PAGE_IF_MATCH_NOTE), dynamic: z.object({ previewPath: z.string().nullable().optional().describe(PARAM_TEXT.previewPath), modelId: z.string().min(1).optional().describe(PARAM_TEXT.pageModelId) }).optional().describe(PARAM_TEXT.pageDynamic) }).shape,\n async (c, a) => {\n // Read the WHOLE body, not just `data`: a rename can come back with `redirectNote` when\n // an existing redirect on the old address was kept pointing elsewhere (CPO-120, QA D-06).\n // The agent is told in the summary line; the page JSON is unchanged.\n // A built-in is a locked blueprint: the page places the project's copy of it.\n // `blockJson` as an OBJECT is one section edit: the tool is at the 20 top-level properties a\n // client keeps, so the two edits ride the argument they stand in for. The page route takes\n // each under its own name.\n const edit = Array.isArray(a.blockJson) ? undefined : (a.blockJson as SectionEdit | undefined);\n const insert = edit?.insertSection;\n const insertSection = insert?.componentId.startsWith(\"builtin:\") ? { ...insert, componentId: await builtinCopyId(c, insert.componentId) } : insert;\n const res = await c.fetchJSON<{ data?: unknown; redirectNote?: { source: string; existingDestination: string }; warnings?: string[]; held?: string; holds?: unknown[]; outcome?: PublishOutcome; section?: { id: string; index: number } }>(\n c.url(`/management/pages/${s(a.pageId)}/meta`),\n {\n method: \"PATCH\",\n ...(a.ifMatch !== undefined ? { headers: { \"If-Match\": `W/\"${a.ifMatch}\"` } } : {}),\n body: JSON.stringify({ title: a.title, slug: a.slug, blockJson: Array.isArray(a.blockJson) ? a.blockJson : undefined, insertSection, sectionStyle: edit?.sectionStyle, metaTitle: a.metaTitle, metaDescription: a.metaDescription, schemaType: a.schemaType, schema: a.schema, status: a.status, noindex: a.noindex, canonical: a.canonical, og: a.og, twitter: a.twitter, scheduledAt: a.scheduledAt, unpublishAt: a.unpublishAt, locale: a.locale, translationOf: a.translationOf, ...(a.dynamic as { previewPath?: string | null; modelId?: string } | undefined) }),\n },\n );\n const note = res.redirectNote;\n // A hold is never \"done\": the draft is saved, and the live page will not show the section\n // change until the action is taken. So it LEADS, and \"Updated page.\" is never said over it.\n const edited = res.section\n ? insertSection ? `Added section ${res.section.id} at position ${res.section.index + 1} of the draft.` : `Set the style of section ${res.section.id} in the draft.`\n : null;\n const saved = res.held ? `${edited ? `${edited} ` : \"\"}The draft is saved; the live page is unchanged.` : edited ?? \"Updated page.\";\n const summary = note\n ? `${saved} An existing redirect from ${note.source} already points to ${note.existingDestination}; it wasn't changed, so the old address does not redirect to the new one.`\n : saved;\n const lines = [...(res.held ? [res.held] : []), ...publishedLines(res.outcome, summary), ...(res.warnings ?? [])].join(\"\\n\");\n const extra = { ...(res.holds?.length ? { holds: res.holds } : {}), ...(res.outcome ? { outcome: res.outcome } : {}), ...(res.section ? { section: res.section } : {}) };\n return ok(lines, Object.keys(extra).length ? { ...(res.data as Record<string, unknown>), ...extra } : res.data);\n }),\n\n // ── Code + deploy (parity with remote /mcp; needs artifact:write) ──\n // Both grant shapes carry that scope now; a workspace-wide one names its target per\n // call via `projectId` and is re-checked against it. @see management/projects.ts\n def(\"pull_project_source\", \"Pull the project's live source\",\n \"Get the connected project's CURRENT live source/build so you can edit it locally. Returns a presigned tarball download url (1h) + the live commit sha — download it, extract, edit the files, then call deploy_project. If the project is connected to a GitHub repo, `github` carries owner, repo, branch and cloneUrl — clone it and work on THAT branch, because it is the one the provisioned Action builds from; a commit on any other branch never reaches the live site. On a workspace-wide connection pass `projectId` (from list_projects) to say which site's source to pull.\",\n z.object({}).shape,\n async (c) => ok(\"Project source.\", await data(c, \"GET\", `/management/projects/source`))),\n def(\"deploy_project\", \"Deploy new source/build\",\n \"Deploy new source/build for the connected project and make it live at its <handle>.bettercms.site. Pass a .tgz or .zip of the project as a base64 string in `data`, or the `uploadKey` of an archive you PUT through create_deploy_upload (no size ceiling: use it for anything large, or after a 413/502). SOURCE (has package.json) is built server-side in an isolated sandbox; a prebuilt static site is served as-is. Returns the release id + sha — then poll get_deploy_status until it is live. IMPORTANT — you MUST exclude node_modules, .git and build output/caches (dist, build, .next, .astro, .cache) from the archive: the source is reinstalled and built server-side, and the ~100 MB upload ceiling is enforced in transit (a 413/502 with no server-side detail) — server-side stripping runs AFTER the upload and cannot rescue an over-limit body. Returns `canvas.lane` (skill bindings) and `editorUrl`, the visual editor to hand the user. On a workspace-wide connection pass `projectId` (from list_projects) to say which site this ships to.\",\n z.object({\n data: z.string().min(1).optional().describe(\"base64 .tgz/.zip of the project; or send uploadKey\"),\n uploadKey: z.string().min(1).optional().describe(\"instead of data: the uploadKey from create_deploy_upload, after PUTting the archive to its uploadUrl\"),\n mimeType: z.string().optional(),\n }).shape,\n async (c, a) => {\n if (!a.data === !a.uploadKey) return fail(\"Pass exactly one of data (the archive, base64) or uploadKey (from create_deploy_upload).\");\n return ok(\"Deploy queued.\", a.uploadKey\n ? await data(c, \"POST\", `/management/projects/deploy/from-upload`, { uploadKey: a.uploadKey })\n : await raw(c, `/management/projects/deploy`, s(a.data), a.mimeType as string | undefined));\n }),\n def(\"create_deploy_upload\", \"Get a presigned deploy-upload URL\",\n \"Get a presigned URL to upload a LARGE deploy archive directly to storage, bypassing the ~100 MB body limit deploy_project's inline `data` hits. Flow: (1) call this for `uploadUrl` + `uploadKey`; (2) PUT your .tgz/.zip to `uploadUrl` (e.g. `curl -X PUT --data-binary @archive.tgz \\\"<uploadUrl>\\\"`) — straight to storage, no size ceiling; (3) call deploy_project with `uploadKey`. Still exclude node_modules/.git/build caches. URL expires in 10 minutes.\",\n z.object({}).shape,\n async (c) => ok(\"Upload URL.\", await data(c, \"POST\", `/management/projects/deploy/upload-url`))),\n\n // ── Git (import a repository, read it, push commits back) ──\n // Same artifact:write authority as the deploy tools: on the build branch a push IS a\n // deploy. Every call runs server-side as the GitHub App installation, so the agent\n // needs no git remote, no clone and no token. @see management/git.ts\n def(\"list_github_repos\", \"List importable GitHub repositories\",\n GIT_TEXT.list_github_repos,\n z.object({}).shape,\n async (c) => ok(\"GitHub repositories.\", await data(c, \"GET\", `/management/git/repos`))),\n def(\"import_github_repo\", \"Import a GitHub repository\",\n GIT_TEXT.import_github_repo,\n z.object({\n installationId: z.number().int().positive().describe(\"from list_github_repos\"),\n owner: z.string().min(1).describe(\"the repository's account, e.g. 'acme'\"),\n repo: z.string().min(1).describe(\"the repository name, e.g. 'website'\"),\n branch: z.string().min(1).optional().describe(\"branch to build from; defaults to the repository's own default branch\"),\n }).shape,\n async (c, a) => ok(\"Repository imported.\", await data(c, \"POST\", `/management/git/connect`, { installationId: a.installationId, owner: a.owner, repo: a.repo, branch: a.branch }))),\n def(\"fork_github_repo\", \"Fork a repository and import it\",\n GIT_TEXT.fork_github_repo,\n z.object({\n installationId: z.number().int().positive().describe(\"the DESTINATION account's installation, from list_github_repos\"),\n owner: z.string().min(1).describe(\"the SOURCE repository's account, anywhere on GitHub\"),\n repo: z.string().min(1).describe(\"the SOURCE repository name\"),\n name: z.string().min(1).optional().describe(\"name for the fork; defaults to the source repository's name\"),\n connect: z.boolean().optional().describe(\"connect the fork to this project (the default); false forks only\"),\n }).shape,\n async (c, a) => ok(\"Repository forked.\", await data(c, \"POST\", `/management/git/fork`, { installationId: a.installationId, owner: a.owner, repo: a.repo, name: a.name, connect: a.connect }))),\n def(\"list_github_branches\", \"List the repository's branches\",\n GIT_TEXT.list_github_branches,\n z.object({}).shape,\n async (c) => ok(\"Branches.\", await data(c, \"GET\", `/management/git/branches`))),\n def(\"list_github_commits\", \"List the repository's commits\",\n GIT_TEXT.list_github_commits,\n z.object({\n branch: z.string().min(1).optional().describe(\"defaults to the build branch\"),\n path: z.string().min(1).optional().describe(\"only commits touching this file or directory\"),\n limit: z.number().int().min(1).max(100).optional(),\n }).shape,\n async (c, a) => ok(\"Commits.\", await data(c, \"GET\", `/management/git/commits${q({ branch: a.branch, path: a.path, limit: a.limit })}`))),\n def(\"push_to_github\", \"Push a commit to the repository\",\n GIT_TEXT.push_to_github,\n z.object({\n message: z.string().min(1).describe(\"the commit message\"),\n files: z.array(z.object({\n path: z.string().min(1).describe(\"repository-relative path, e.g. 'src/pages/index.astro'\"),\n content: z.string().describe(\"the file's contents\"),\n encoding: z.enum([\"utf8\", \"base64\"]).optional().describe(\"'base64' for binary files; defaults to utf8\"),\n })).optional().describe(\"files to write or overwrite\"),\n deletePaths: z.array(z.string().min(1)).optional().describe(\"paths to remove in the same commit\"),\n branch: z.string().min(1).optional().describe(\"defaults to the build branch; a branch that does not exist is created\"),\n baseBranch: z.string().min(1).optional().describe(\"what a newly created `branch` starts from; defaults to the build branch\"),\n expectedHeadSha: z.string().min(7).optional().describe(\"the head you built this change on; the push is refused if the branch moved since\"),\n }).shape,\n async (c, a) => ok(\"Pushed.\", await data(c, \"POST\", `/management/git/commit`, { message: a.message, files: a.files, deletePaths: a.deletePaths, branch: a.branch, baseBranch: a.baseBranch, expectedHeadSha: a.expectedHeadSha }))),\n def(\"create_github_pull_request\", \"Open a pull request\",\n GIT_TEXT.create_github_pull_request,\n z.object({\n head: z.string().min(1).describe(\"the branch you pushed\"),\n base: z.string().min(1).optional().describe(\"defaults to the build branch\"),\n title: z.string().min(1),\n body: z.string().optional(),\n draft: z.boolean().optional(),\n }).shape,\n async (c, a) => ok(\"Pull request opened.\", await data(c, \"POST\", `/management/git/pulls`, { head: a.head, base: a.base, title: a.title, body: a.body, draft: a.draft }))),\n def(\"list_github_pull_requests\", \"List pull requests\",\n GIT_TEXT.list_github_pull_requests,\n z.object({\n state: z.enum([\"open\", \"closed\", \"all\"]).optional(),\n limit: z.number().int().min(1).max(100).optional(),\n }).shape,\n async (c, a) => ok(\"Pull requests.\", await data(c, \"GET\", `/management/git/pulls${q({ state: a.state, limit: a.limit })}`))),\n // ── Insight: what happened, what's working, what's broken ─────────────────\n def(\"update_field\", \"Change one field of a model or a page\",\n UPDATE_FIELD_DESCRIPTION,\n z.object({\n modelId: z.string().min(1).optional().describe(\"the content model (from list_content_models); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of modelId: the page whose schema to edit\"),\n path: z.string().min(1).describe(\"the field's key, or dot-separated keys through its parents, e.g. 'hero.title'\"),\n label: z.string().min(1).optional(),\n helpText: z.string().nullable().optional().describe(\"null clears it\"),\n required: z.boolean().optional(),\n config: z.record(z.string(), z.unknown()).optional().describe(\"per-type validation/config keys, merged into the stored config; null deletes a key\"),\n showIf: z.record(z.string(), z.unknown()).nullable().optional().describe(\"same shape as on add_field; null clears it\"),\n 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\"),\n placement: z.enum([\"cover\", \"title\", \"excerpt\", \"body\", \"inline\", \"panel\"]).nullable().optional(),\n readOnly: z.union([z.literal(true), z.literal(\"developer\")]).nullable().optional().describe(PARAM_TEXT.lockClears),\n lockReason: z.string().max(200).nullable().optional().describe(PARAM_TEXT.lockClears),\n helpMore: z.string().max(2000).nullable().optional().describe(PARAM_TEXT.helpMore),\n advanced: z.boolean().nullable().optional().describe(PARAM_TEXT.advanced),\n recommendedMax: z.number().int().positive().nullable().optional().describe(PARAM_TEXT.recommendedMax),\n openMode: z.enum([\"inline\", \"drill\", \"popover\", \"dialog\"], { error: OPEN_MODE_INVALID }).nullable().optional().describe(PARAM_TEXT.openMode),\n localized: z.boolean().nullable().optional(),\n type: fieldType.optional().describe(\"a new type; needs allowRetype\"),\n key: fieldKey.optional().describe(\"a new key (flat namespace, unique in the schema)\"),\n allowRetype: z.boolean().optional().describe(\"confirm a type change, once the user has agreed\"),\n allowFieldRemoval: z.boolean().optional().describe(\"with a rename: discard the old key's stored values\"),\n mergeHref: z.string().min(1).optional().describe(PARAM_TEXT.mergeHref),\n ifMatch: z.number().int().min(0).optional().describe(\"the model's optimisticVersion; the version read when omitted\"),\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n }).shape,\n // Read the model (a page's through its backingModel), patch ONE field with the helper the\n // hosted catalogue uses, and PATCH the whole list at the version read. `mergeHref` is the\n // page route's \"Make it a full button\" instead, at the PAGE's version.\n async (c, a) => {\n if (a.mergeHref !== undefined) {\n if (!a.pageId) return fail(\"mergeHref merges two fields of a PAGE: pass pageId.\");\n const ifMatch = (a.ifMatch as number | undefined)\n ?? ((await data(c, \"GET\", `/management/pages/${s(a.pageId)}`)) as { optimisticVersion?: number } | undefined)?.optimisticVersion\n ?? 0;\n const merged = (await c.fetchJSON<{ data?: unknown; key?: string; entries?: number }>(c.url(`/management/pages/${s(a.pageId)}/fields/merge-button`), {\n method: \"POST\",\n body: JSON.stringify({ labelKey: a.path, hrefKey: a.mergeHref, ...(a.key !== undefined ? { key: a.key } : {}), ifMatch }),\n }));\n return ok(`Made '${s(a.path)}' + '${s(a.mergeHref)}' one button field '${merged.key ?? \"\"}' (${merged.entries ?? 0} draft entries).`, merged);\n }\n let modelId = a.modelId as string | undefined;\n if (a.pageId) {\n const page = (await data(c, \"GET\", `/management/pages/${s(a.pageId)}`)) as { backingModel?: { id?: string } | null } | undefined;\n modelId = page?.backingModel?.id;\n if (!modelId) return fail(\"This page has no backing content model; address its schema by modelId.\");\n }\n if (!modelId) return fail(\"Pass modelId (a content model) or pageId (a page).\");\n const plan = planFieldEdit((await data(c, \"GET\", `/management/content/models/${s(modelId)}`)) as StoredModel, a, a.ifMatch as number | undefined);\n if (!plan.ok) return fail(plan.error);\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/model` : `/management/content/models/${s(modelId)}`;\n const updated = (await c.fetchJSON<{ data?: unknown }>(c.url(path), {\n method: \"PATCH\",\n body: JSON.stringify({ fields: plan.fields, ...(a.allowFieldRemoval === true ? { allowFieldRemoval: true } : {}) }),\n ...withHeaders({ ...(plan.ifMatch !== undefined ? { \"If-Match\": `W/\"${plan.ifMatch}\"` } : {}), ...confirmedHeaders(a.confirmed) }),\n })).data;\n return ok(plan.renamed ? `Renamed '${plan.renamed.from}' to '${plan.renamed.to}'.` : `Updated field '${s(a.path)}'.`, updated);\n }),\n\n // ── Search, batch, localisation, automation, branches and AI images (2026-09-30) ──\n // Descriptions from ./tool-text.ts, shared word for word with the hosted catalogue.\n def(\"search_content\", \"Search published content\",\n NEW_TOOL_TEXT.search_content,\n z.object({\n q: z.string().min(1).max(200).describe(\"the words to find, 1-200 chars\"),\n type: z.enum([\"page\", \"entry\"]).optional().describe(\"only pages, or only entries\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"hits to return; 10 when omitted\"),\n }).shape,\n async (c, a) => ok(\"Search results.\", await c.fetchJSON(c.url(`/management/search${q({ q: a.q, type: a.type, limit: a.limit })}`), { method: \"GET\" }))),\n def(\"discard_draft\", \"Discard unpublished edits\",\n NEW_TOOL_TEXT.discard_draft,\n z.object({\n entryId: z.string().min(1).optional().describe(\"the entry (from list_content_entries); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of entryId: the page (from list_pages)\"),\n ifMatch: z.number().int().min(0).optional().describe(\"optimisticVersion from get_content_entry or get_page\"),\n }).shape,\n async (c, a) => {\n if (!a.entryId === !a.pageId) return fail(\"Pass exactly one of entryId (an entry) or pageId (a page).\");\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/discard-draft` : `/management/content/entries/${s(a.entryId)}/discard-draft`;\n return ok(\"Draft discarded.\", (await c.fetchJSON<{ data?: unknown }>(c.url(path), {\n method: \"POST\",\n body: JSON.stringify({}),\n ...(a.ifMatch !== undefined ? { headers: { \"If-Match\": `W/\"${a.ifMatch}\"` } } : {}),\n })).data);\n }),\n def(\"refresh_search_index\", \"Refresh IndexNow or site search\",\n NEW_TOOL_TEXT.refresh_search_index,\n z.object({\n action: z.enum([\"indexnow\", \"reindex\"]).describe(\"'indexnow' pings search engines; 'reindex' rebuilds site search\"),\n urls: z.array(z.string().min(1)).min(1).max(1000).optional().describe(\"indexnow only: this site's URLs; every change since the last submission when omitted\"),\n }).shape,\n async (c, a) => ok(a.action === \"reindex\" ? \"Site search rebuilt.\" : \"IndexNow submission.\", a.action === \"reindex\"\n ? await data(c, \"POST\", `/management/search/reindex`, {})\n : await data(c, \"POST\", `/management/seo/indexnow/submit`, { urls: a.urls }))),\n def(\"give_feedback\", \"Send feedback to the BetterCMS team\",\n NEW_TOOL_TEXT.give_feedback,\n z.object({\n kind: z.enum([\"bug\", \"missing_capability\", \"unclear_docs\", \"other\"]).describe(\"what went wrong\"),\n message: z.string().min(1).max(10_000).describe(\"what you tried, what happened and what you expected (1-10000 chars)\"),\n tool: z.string().max(100).optional().describe(\"the tool it is about, if any\"),\n context: z.string().max(4000).optional().describe(\"the request and response, or other detail (up to 4000 chars)\"),\n }).shape,\n async (c, a) => ok(\"Feedback sent.\", await data(c, \"POST\", `/management/feedback`, { kind: a.kind, message: a.message, tool: a.tool, context: a.context }))),\n def(\"publish_entries\", \"Publish or unpublish many entries and pages\",\n NEW_TOOL_TEXT.publish_entries,\n z.object({\n action: z.enum([\"publish\", \"unpublish\", \"hold\", \"release\"]).describe(\"live, back to draft, or hold/release from site publishes\"),\n entryIds: z.array(z.string().min(1)).max(100).optional().describe(\"entry ids (from list_content_entries)\"),\n pageIds: z.array(z.string().min(1)).max(100).optional().describe(\"page ids (from list_pages); not for unpublish\"),\n }).shape,\n async (c, a) => {\n const receipt = await data(c, \"POST\", `/management/publish`, { action: a.action, entryIds: a.entryIds, pageIds: a.pageIds });\n const outcome = (receipt as { outcome?: PublishOutcome } | null | undefined)?.outcome;\n return ok(a.action === \"publish\" ? publishedLines(outcome, \"Publish receipt.\").join(\"\\n\") : a.action === \"unpublish\" ? \"Unpublish receipt.\" : \"Hold receipt.\", receipt);\n }),\n def(\"create_content_entries\", \"Create many draft entries\",\n NEW_TOOL_TEXT.create_content_entries,\n z.object({\n contentModelId: z.string().min(1).describe(\"the collection every entry belongs to (from list_content_models)\"),\n entries: z.array(z.object({ slug: z.string().optional(), data: z.record(z.string(), z.unknown()), ...upsertShape })).min(1).max(200).describe(\"1-200 entries, each {slug?, data}\"),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n }).shape,\n // The whole body: the per-row receipt is `data`, the counts ride in `meta`.\n async (c, a) => ok(a.dryRun ? DRY_RUN_SUMMARY : \"Batch receipt.\", await c.fetchJSON(c.url(`/management/content/entries/batch`), { method: \"POST\", body: JSON.stringify({ contentModelId: a.contentModelId, entries: a.entries, dryRun: a.dryRun }) }))),\n def(\"translate_entry\", \"Translate an entry into another locale\",\n NEW_TOOL_TEXT.translate_entry,\n z.object({\n entryId: z.string().min(1).describe(\"the SOURCE entry, never another translation\"),\n targetLocale: z.string().min(1).describe(\"BCP-47 locale from the project's locales, e.g. 'fr'\"),\n slug: z.string().optional().describe(\"the translation's slug; <source slug>-<locale> when omitted\"),\n fields: z.array(z.string().min(1)).optional().describe(\"translate only these field keys\"),\n }).shape,\n async (c, a) => ok(\"Translation created.\", await c.fetchJSON(c.url(`/management/content/entries/${s(a.entryId)}/translate`), { method: \"POST\", body: JSON.stringify({ targetLocale: a.targetLocale, slug: a.slug, fields: a.fields }) }))),\n def(\"list_webhooks\", \"List webhooks\",\n NEW_TOOL_TEXT.list_webhooks,\n z.object({}).shape,\n async (c) => ok(\"Webhooks.\", await data(c, \"GET\", `/management/webhooks`))),\n def(\"create_webhook\", \"Create a webhook\",\n NEW_TOOL_TEXT.create_webhook,\n z.object({\n name: z.string().min(1).max(255).describe(\"a label, 1-255 chars\"),\n url: z.string().url().describe(\"the https endpoint that receives the events\"),\n events: z.array(z.enum(WEBHOOK_EVENTS)).min(1).optional().describe(\"events to send; ['content.publish'] when omitted\"),\n isActive: z.boolean().optional().describe(\"default true\"),\n test: z.boolean().optional().describe(\"send a sample delivery now\"),\n }).shape,\n // The whole body: a `test` delivery's outcome rides beside `data`.\n async (c, a) => ok(\"Webhook created. Store the `secret` now: it is never shown again.\", await c.fetchJSON(c.url(`/management/webhooks`), { method: \"POST\", body: JSON.stringify({ name: a.name, url: a.url, events: a.events, isActive: a.isActive, test: a.test }) }))),\n def(\"list_branches\", \"List content branches\",\n NEW_TOOL_TEXT.list_branches,\n z.object({}).shape,\n async (c) => ok(\"Branches.\", await c.fetchJSON(c.url(`/management/branches`), { method: \"GET\" }))),\n def(\"create_branch\", \"Create a content branch\",\n NEW_TOOL_TEXT.create_branch,\n z.object({\n name: z.string().min(1).max(80).describe(\"1-80 chars\"),\n slug: z.string().max(80).optional().describe(\"derived from the name when omitted\"),\n }).shape,\n async (c, a) => ok(\"Branch created.\", await data(c, \"POST\", `/management/branches`, { name: a.name, slug: a.slug }))),\n def(\"apply_branch\", \"Merge a branch into its parent\",\n NEW_TOOL_TEXT.apply_branch,\n z.object({\n branchId: z.string().min(1).describe(\"the branch to merge (from list_branches)\"),\n dryRun: z.boolean().optional().describe(\"true = return the diff and write nothing\"),\n include: z.array(z.string().min(1)).max(500).optional().describe(\"change keys to merge (from the diff); all when omitted\"),\n fields: z.record(z.string(), z.record(z.string(), z.enum([\"keep_branch\", \"keep_parent\"]))).optional().describe(\"change key → field → 'keep_branch' | 'keep_parent', for each conflict\"),\n }).shape,\n async (c, a) => a.dryRun === true\n ? ok(\"Branch diff (nothing was written).\", await data(c, \"GET\", `/management/branches/${s(a.branchId)}/diff`))\n : 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 }) }))),\n def(\"search_docs\", \"Search the BetterCMS docs\",\n NEW_TOOL_TEXT.search_docs,\n z.object({\n q: z.string().min(1).describe(\"the question or words to find\"),\n limit: z.number().int().min(1).max(20).optional().describe(\"pages to return; 5 when omitted\"),\n }).shape,\n async (c, a) => ok(\"Docs.\", await c.fetchJSON(c.url(`/management/docs/search${q({ q: a.q, limit: a.limit })}`), { method: \"GET\" }))),\n def(\"generate_image\", \"Generate an image with AI\",\n NEW_TOOL_TEXT.generate_image,\n z.object({\n prompt: z.string().min(1).max(2000).describe(\"what the image shows, 1-2000 chars\"),\n altText: z.string().optional().describe(\"alt text for the new asset\"),\n width: z.number().int().min(256).max(1440).multipleOf(16).optional(),\n height: z.number().int().min(256).max(1440).multipleOf(16).optional(),\n folderId: z.string().optional().describe(\"Media Library folder id\"),\n }).shape,\n async (c, a) => ok(\"Generated image.\", await data(c, \"POST\", `/management/ai/image`, { prompt: a.prompt, altText: a.altText, width: a.width, height: a.height, folderId: a.folderId }))),\n def(\"transform_image\", \"Edit an image with AI\",\n NEW_TOOL_TEXT.transform_image,\n z.object({\n mediaId: z.string().min(1).describe(\"the image to edit (from list_media)\"),\n prompt: z.string().min(1).max(2000).describe(\"the change to make, 1-2000 chars\"),\n altText: z.string().optional().describe(\"alt text for the new asset\"),\n folderId: z.string().optional().describe(\"Media Library folder id\"),\n }).shape,\n async (c, a) => ok(\"Edited image (a new asset).\", await data(c, \"POST\", `/management/ai/image/transform`, { mediaId: a.mediaId, prompt: a.prompt, altText: a.altText, folderId: a.folderId }))),\n def(\"write_alt_text\", \"Write alt text with AI\",\n NEW_TOOL_TEXT.write_alt_text,\n z.object({ mediaId: z.string().min(1).optional().describe(\"the image (from list_media)\"), url: z.string().optional().describe(\"or an https image URL\") }).shape,\n async (c, a) => ok(\"Alt text suggestion.\", await data(c, \"POST\", `/management/ai/alt-text`, a.url ? { url: a.url } : { mediaId: a.mediaId }))),\n\n def(\"list_activity\", \"List project activity\",\n \"Recent activity in the connected project — who changed what, and when. Filter by `category` (comma-separated: content, pages, media, forms, deployment, settings, members), `actorId`, or a `since`/`until` ISO window. At the start of a turn, pass `since` (your last look) to notice dashboard or agent edits made since.\",\n z.object({ category: z.string().optional(), actorId: z.string().optional(), since: z.string().optional(), until: z.string().optional(), limit: z.number().optional() }).shape,\n async (c, a) => ok(\"Project activity.\", await data(c, \"GET\", `/management/insights/activity${q({ category: a.category, actorId: a.actorId, since: a.since, until: a.until, limit: a.limit })}`))),\n def(\"get_next_steps\", \"Get what to do next\",\n NEXT_STEPS_DESCRIPTION,\n z.object({\n importJunk: z.boolean().optional().describe(\"true = add rule import-junk: what an old import left, with removal calls\"),\n }).shape,\n // The whole body: `receipt` rides beside `data`, and `data()` would drop it.\n async (c, a) =>\n ok(\"Next steps.\", await c.fetchJSON(c.url(`/management/insights/next-steps${a.importJunk === true ? \"?importJunk=true\" : \"\"}`), { method: \"GET\" }))),\n def(\"get_binding_report\", \"Check what on the live site is editable\",\n \"The receipt for 'is this site actually EDITABLE?'. Each release scans the built HTML for the element rendering each CMS field value; per slot this returns `mode` ('text-match' = guessed from rendered text, 'declared' = template-declared), what was bound, and `unmatched`: each path with its reason (reasons: skill bindings). DEPLOY FIRST: before any release there is no report (pages 0, mode null, refreshRequired true). `refreshReason`: a HEADLESS site never gets one (`never-generated`); `layoutRoutes` and `coverage.error`: skill bindings. `unaddressable` is the visible live text no field owns, by route (null = unmeasured: diff visible text against entry values); over `count / visible > 0.02`, fix it in the SOURCE and re-read (playbook §11). `entryRowUnbound`: a bound card's words no field of its entry claims, by route, with `reason` (reference, boolean, locale-format, counter, no-field); never also in `unaddressable`. `canvas.lane`: `none` → get_next_steps.\",\n z.object({ slot: z.enum([\"current\", \"staging\"]).optional().describe(\"which release tree to read — everything here, `unaddressable` included, is measured PER SLOT, so on a promote-gated project pass 'current' to read the tree the editor frames. Defaults to the slot this project's releases land in. The response's `sha` is the build the report describes; `refreshRequired` is true when that is not the build this slot serves. Other per-slot fields: skill bindings.\") }).shape,\n async (c, a) => ok(\"Binding report.\", await data(c, \"GET\", `/management/projects/current/binding-report${q({ slot: a.slot })}`))),\n def(\"get_conversion_brief\", \"Get the brief for making this site's bindings durable\",\n \"The per-project brief for making this site's bindings DURABLE — read it before you touch the templates. Returns what already exists in the CMS: every live page with its route, every bindable field path with its `label`, `kind`, the CMS value (`current`) and the copy the repo renders today (`original`), the exact attributes to declare, and the ordered steps. Call it for any site whose pages were DERIVED at import, and whenever get_next_steps reports `bindings-not-declared`. It REPLACES re-registering a schema: these pages, fields and values exist already, so create_page / add_field / create_content_model would build a second schema over the first — edit values with set_page_content instead. `lane`: 'git-connected' = pull_project_source returns a repo; 'archive' = a tarball. Recipe: playbook §13; get_binding_report is the finish line. Pass `complete: true` before running the CODEMOD (`npx @bettercms-ai/convert`): the brief UNCAPPED and paged, its full path list pinned under a `briefDigest` — what the coverage meter measures the build against. The complete brief also carries `forms`: wiring them and publishing the forms it names, skill bindings.\",\n z.object({\n complete: z.boolean().optional().describe(\"true = the COMPLETE brief for a codemod: nothing truncated, no page omitted, paged 50 pages at a time. Page 1 pins the path list the coverage meter measures against.\"),\n cursor: z.string().optional().describe(\"The `cursor` from the previous page. Implies complete. A 409 BRIEF_CHANGED means the brief was re-derived mid-pagination — start again with no cursor.\"),\n }).shape,\n async (c, a) => ok(\"Conversion brief.\", await data(c, \"GET\", `/management/projects/current/conversion-brief${q({ complete: a.complete, cursor: a.cursor })}`))),\n def(\"get_conversion_plan\", \"Get the approved conversion to apply\",\n \"The APPROVED conversion a human reviewed in the BetterCMS dashboard: the exact new contents of each template file, already checked against this project's real field paths. Apply it instead of writing the bindings by hand. Check out `baseHeadOid` (the exact commit it was written against), branch from there, write each file's `content` verbatim (whole file, no merge, no reformatting), then push or deploy however this project ships. `stale.head` / `stale.brief` say the repository or the CMS moved since it was approved: stop and ask for a fresh proposal. `receipt.paths.pending` lists every field the codemod could NOT bind, each with a reason (`DIALECT_UNSUPPORTED`, `PROP_TARGET_NOT_FOUND`, `REPEATER_FIXED_LENGTH`, …) — apply the plan first, then bind those by hand. Then finish as a hand conversion does: get_binding_report until `unmatched` is empty, then set_binding_mode { declaredBindings: true } and release once more. 404 with `code: \\\"no-approved-plan\\\"` means nobody has approved one: use get_conversion_brief and do the conversion yourself. Requires artifact:write; on a workspace-wide connection pass `projectId`.\",\n z.object({}).shape,\n async (c) => ok(\"Approved conversion plan.\", await data(c, \"GET\", `/management/projects/current/conversion-plan`))),\n def(\"get_site_composition\", \"Check every page is assembled from registered components\",\n \"The receipt for 'is every page assembled from registered components?' — read-only, computed live. Call it before a whole-site componentize run (playbook §12) and after it, as the proof. Per page: `kind`, a block census, `nonComponentBlocks` and every `component` placement with its `status` (a draft renders as an EMPTY STRING on the live site), `inPicker` and `emptyRequiredProps`. Site-wide: counts, `awaitingApproval` (a HUMAN approves in the dashboard; no tool here can), `notInPicker`, `unused` and `layout.placements`. Each field: skill components. `verdict.everyPageComposed` with `verdict.reasons` is the answer to give the user. Pages are read DRAFT-inclusive: check each page's own `status` before claiming the site is live.\",\n z.object({}).shape,\n async (c) => ok(\"Site composition.\", await data(c, \"GET\", `/management/projects/current/composition`))),\n def(\"get_componentize_plan\", \"Get the plan for turning this site's sections into components\",\n \"What this site's SECTIONS would become as components — a proposal that creates nothing and is computed live. For a site whose pages were DERIVED at import, each top-level field GROUP is one section: `hero-*` and `faq-*` keys, and the repeaters the import folded (`group-*`). Per page: each section's `groupKey`, `sectionType` family, leaf `fields` with their CMS values, `shapeHash`, and either the component already rendering it (`reuse.componentId`) or the proposed one (`reuse.proposedSlug`). Under `components`, a NEW one carries the exact `props` and `blockJson` create_component would take; an EXISTING one only `componentId`, `slug` and `name` (nothing is written for it). `pending` says why a group is not offered (its codes: see `summary`). Per-page components, collection templates and chrome (never a section): skill componentize. READ `summary: true` FIRST — the full plan runs to hundreds of KB; `paged` pages it (409 PLAN_CHANGED = start again); the unpaged full read is what `--plan plan.json` takes. Keep the `digest` — componentize_sections refuses any other.\",\n z.object({\n summary: z.boolean().optional().describe(\"true = no values: each section's groupKey, family, pending and component slug. Read this first. `pending` codes (each explained in skill componentize): `NO_GROUP_ROOT`, `NOT_A_SECTION` (`detail`: `ENTRY_METADATA`, `DECLINED`), `IMAGE_AS_TEXT`, `ALREADY_COMPONENTIZED`, `EMPTY_GROUP`, `NESTED_REPEATER`, `PAGE_NOT_EMPTY`.\"),\n paged: z.boolean().optional().describe(\"true = 10 pages at a time; the response carries `page`, `pageCount` and a `cursor` for the next.\"),\n cursor: z.string().optional().describe(\"The `cursor` from the previous page. Implies paged. A 409 `PLAN_CHANGED` means start again with no cursor.\"),\n }).shape,\n async (c, a) => ok(\"Componentize plan.\", await data(c, \"GET\", `/management/projects/current/componentize-plan${q({ summary: a.summary, paged: a.paged, cursor: a.cursor })}`))),\n def(\"componentize_sections\", \"Turn this site's derived sections into components\",\n \"Turn this site's derived sections into components. CONFIRM WITH THE USER FIRST: show them get_componentize_plan's sections, how many components it will create and which pages it will rewrite; `dryRun` first. It creates each proposed component as a DRAFT and replaces each page's DRAFT blocks with ordered `component` instances, one per group. The page keeps its `fields`, values and bindings (see `copy`). Pass the plan's `digest`; a 409 `stale-plan` means the site changed: read the plan again, show the user what changed and confirm again. Read `components.wouldDuplicate` first (skill components). Re-running is safe: a placed group returns as ALREADY_COMPONENTIZED. DRAFTS ONLY — an unpublished component renders as an EMPTY STRING on the live site, so publish_component each one and publish the pages, then call it again with `codemod: true` for the repository half (skill componentize). A group the user says is NOT a section: `decline: true` with those `sections` (skill componentize).\",\n z.object({\n digest: z.string().min(1).describe(\"The `digest` get_componentize_plan returned. A different one is refused with 409 stale-plan.\"),\n pageIds: z.array(z.string().min(1)).optional().describe(\"Componentize only these pages (ids from the plan). Omit for every page the plan lists.\"),\n pages: z.array(z.string().min(1)).optional().describe(\"The same page filter under the name the dashboard uses. Unioned with pageIds; an EMPTY list is refused rather than treated as every page.\"),\n sections: z.array(z.string().min(1)).optional().describe(\"Act only on these section groupKeys (from the plan); every other section keeps its placement.\"),\n copy: z.enum([\"bind\", \"instance\"]).optional().describe(\"Who owns each section's copy. 'bind' (default) leaves it in the page fields. 'instance' moves it onto each placement; the page's fields are KEPT and marked `origin: \\\"componentized\\\"` (skill componentize).\"),\n dryRun: z.boolean().optional().describe(\"true = return the receipt without writing anything. Do this first.\"),\n group: z.string().min(1).max(100).optional().describe(\"File the components this run creates into this Component Group (by NAME, created when missing), else its section family (skill componentize). A reused component keeps its Group; the receipt's `components.groups` lists the Groups filed into.\"),\n decline: z.boolean().optional().describe(\"true = record `sections` as NOT sections (nothing is componentized; the plan stops proposing them). false = offer them again. Needs `sections`.\"),\n joinTwins: z.boolean().optional().describe(\"true = move each locale copy (`/fr`) still on its own component onto its twin's (`bindPaths` keeps its fields). A dry run lists each in `joins`. Whole plan only.\"),\n codemod: z.boolean().optional().describe(PARAM_TEXT.componentizeCodemod),\n }).shape,\n async (c, a) => ok(a.codemod === true ? \"Section-order codemod.\" : \"Componentized the sections.\", await data(c, \"POST\", a.codemod === true ? `/management/projects/current/section-order` : `/management/projects/current/componentize`, { digest: a.digest, pageIds: a.pageIds, pages: a.pages, sections: a.sections, copy: a.copy, dryRun: a.dryRun, group: a.group, decline: a.decline, joinTwins: a.joinTwins, codemod: a.codemod }))),\n def(\"get_analytics_overview\", \"Get traffic overview\",\n \"Traffic totals and the daily series for the connected project — views, unique visitors, bytes, sessions and bounces. Defaults to the last 30 days; pass `from`/`to` as YYYY-MM-DD.\",\n z.object({ from: z.string().optional(), to: z.string().optional() }).shape,\n async (c, a) => ok(\"Analytics overview.\", await data(c, \"GET\", `/management/insights/analytics/overview${q({ from: a.from, to: a.to })}`))),\n def(\"get_analytics_top_pages\", \"Get top pages\",\n \"The most-viewed paths on the live site, with views and bytes. Defaults to the last 30 days; pass `from`/`to` (YYYY-MM-DD) and `limit`.\",\n z.object({ from: z.string().optional(), to: z.string().optional(), limit: z.number().optional() }).shape,\n async (c, a) => ok(\"Top pages.\", await data(c, \"GET\", `/management/insights/analytics/top-pages${q({ from: a.from, to: a.to, limit: a.limit })}`))),\n def(\"list_seo_issues\", \"List SEO issues\",\n \"Scan every published page for SEO problems (missing or over-long titles and descriptions, missing OG image, noindex, invalid pasted schema) and return them with severities. Also reports accessibility issues as `a11y.*` codes with block ids. Computed live — nothing is stored.\",\n z.object({}).shape,\n async (c) => ok(\"SEO issues.\", await data(c, \"GET\", `/management/insights/seo-issues`))),\n def(\"list_ai_reports\", \"List AI report runs\",\n \"Past AI report runs for the connected project — `kind` is 'links' (internal linking) or 'aeo' (AI-answer readiness). Read-only history; starting a run stays a dashboard action.\",\n z.object({ kind: z.enum([\"links\", \"aeo\"]), limit: z.number().optional() }).shape,\n async (c, a) => ok(\"AI reports.\", await data(c, \"GET\", `/management/insights/ai-reports${q({ kind: a.kind, limit: a.limit })}`))),\n\n // ── Bulk: one dataset → many pages ────────────────────────────────────────\n def(\"generate_pages_from_dataset\", \"Generate many pages from a dataset\",\n \"Turn a dataset into many pages at once (programmatic SEO from a keyword list, or ABM pages from an account list). Give a template `pageId`, a `mapping` (contentModelId, a slugTemplate like 'for-{{company}}', and per-field values that are either a column name or {ai:{prompt}}), and `rows`. For an ABM campaign set `mapping.campaign.id` and the run fans out across every page that campaign owns, returning one job id per page in `jobIds`. ALWAYS call with dryRun:true first and show the sample — a real run parks for approval and must be released with approve_ai_job.\",\n z.object({\n pageId: z.string().min(1),\n mapping: z.record(z.string(), z.unknown()),\n rows: z.array(z.record(z.string(), z.string())).min(1),\n dryRun: z.boolean().optional(),\n }).shape,\n async (c, a) => ok(\"Generation queued.\", await data(c, \"POST\", `/management/bulk/generate`, { pageId: a.pageId, mapping: a.mapping, rows: a.rows, dryRun: a.dryRun }))),\n def(\"research_account\", \"Research one account\",\n \"Read one company's public site into a cited brief the page generator can use: what they do, who they sell to, what they say is hard, with a source URL on every fact. `lite` is one fetch and costs nothing extra; `deep` searches the web, costs 3 credits and is capped per day. A brief less than 30 days old is returned from cache for free. Company-scoped by design: it never stores a person, an email or a job title.\",\n z.object({\n campaignId: z.string().min(1),\n domain: z.string().min(1),\n name: z.string().optional(),\n mode: z.enum([\"lite\", \"deep\"]).optional(),\n force: z.boolean().optional(),\n }).shape,\n async (c, a) => ok(\"Account brief.\", await data(c, \"POST\", `/management/campaigns/research`, { campaignId: a.campaignId, domain: a.domain, name: a.name, mode: a.mode, force: a.force }))),\n def(\"build_abm_page\", \"Build one ABM page for one account\",\n \"Build ONE personalized page for ONE account, guided: give the sales motion and a paragraph of context about the target ('Lumina — 300-rep sales team moving off spreadsheets…') and this mints the campaign, the page, the collection and the run. `brandUrl` learns the seller's brand first, once per project, and needs Settings access because it rewrites the project's brand. Research defaults to `lite` and is forced off when no domain is known. It PARKS for the user's approval like every agent generation here — release it with approve_ai_job — and `requestId` makes a retry return the first answer instead of a second page.\",\n z.object({\n motion: z.enum([\"new_account\", \"expand_customer\", \"accelerate_opportunity\", \"reengage_closed_lost\"]),\n context: z.string().min(20),\n website: z.string().optional(),\n name: z.string().optional(),\n research: z.enum([\"lite\", \"deep\", \"off\"]).optional(),\n ctaHref: z.string().optional(),\n formId: z.string().optional(),\n brandUrl: z.string().optional(),\n requestId: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Page queued for approval.\", await data(c, \"POST\", `/management/campaigns/build`, {\n motion: a.motion, context: a.context, website: a.website, name: a.name,\n research: a.research, ctaHref: a.ctaHref, formId: a.formId,\n brandUrl: a.brandUrl, requestId: a.requestId,\n }))),\n def(\"claim_abm_task\", \"Claim an account to research\",\n \"Claim the next account of a campaign that is waiting for YOU to research it. Returns the account, a `taskId` and a `leaseToken` good for ten minutes; `null` means there is nothing left and your loop is done. Research the company however you like, then call complete_abm_task with the brief — or fail_abm_task if you cannot. Never store a person, an email or a job title: the brief is refused if you do.\",\n z.object({ campaignId: z.string().min(1), agentId: z.string().optional() }).shape,\n async (c, a) => ok(\"Claimed task.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/tasks/claim`, { agentId: a.agentId }))),\n def(\"complete_abm_task\", \"Hand back an account brief\",\n \"Hand back the brief for a task you claimed. `brief` is {name, domain, industry?, size?, painPoint?, summary?, facts:[{text, sourceUrl}], logo?, brandColors?} and NOTHING else — an unknown key is refused with brief_invalid and the path. Every fact needs the URL it came from. When the campaign's last task is done the page generation starts on its own.\",\n z.object({\n campaignId: z.string().min(1),\n taskId: z.string().min(1),\n leaseToken: z.string().min(1),\n brief: z.record(z.string(), z.unknown()),\n }).shape,\n async (c, a) => ok(\"Brief accepted.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/tasks/${s(a.taskId)}/complete`, { leaseToken: a.leaseToken, brief: a.brief }))),\n def(\"fail_abm_task\", \"Give an account task back\",\n \"Give a claimed task back when you cannot research the account — the site is down, there is nothing public to read, the domain is wrong. The page is still written, from the dataset alone, and says so.\",\n z.object({\n campaignId: z.string().min(1),\n taskId: z.string().min(1),\n leaseToken: z.string().min(1),\n reason: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Task returned.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/tasks/${s(a.taskId)}/fail`, { leaseToken: a.leaseToken, reason: a.reason }))),\n def(\"get_campaign_review\", \"Review a campaign's pages\",\n \"The campaign's generated pages, SORTED BY DOUBT — flagged first, then least confident. Each row carries its flags (`unsupported_claim:headline` and the like), the claims the model said it made, which fields it wrote, and a preview link for drafts. `filter:'flagged'` is the review queue; `sample:5` is the first look at a big run; `filter:'failed'` lists the rows that produced no page at all and why.\",\n z.object({\n campaignId: z.string().min(1),\n filter: z.enum([\"all\", \"flagged\", \"pending\", \"approved\", \"rejected\", \"low_confidence\", \"failed\"]).optional(),\n sample: z.number().optional(),\n pageId: z.string().optional(),\n runId: z.string().optional(),\n cursor: z.string().optional(),\n limit: z.number().optional(),\n }).shape,\n async (c, a) => ok(\"Campaign review.\", await data(c, \"GET\", `/management/campaigns/${s(a.campaignId)}/review${q({ filter: a.filter, sample: a.sample, pageId: a.pageId, runId: a.runId, cursor: a.cursor, limit: a.limit })}`))),\n def(\"regenerate_entry\", \"Rewrite one account's page\",\n \"Rewrite ONE account's page, optionally with an instruction ('lead with the integration story') and optionally only certain fields. Costs one credit and writes a DRAFT — a published page shows unpublished changes until someone publishes it again. Re-runs from the original spreadsheet row, not from the last answer, so repeated regenerates do not drift.\",\n z.object({\n campaignId: z.string().min(1),\n entryId: z.string().min(1),\n instruction: z.string().optional(),\n fields: z.array(z.string()).optional(),\n }).shape,\n async (c, a) => ok(\"Regeneration queued.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/entries/${s(a.entryId)}/regenerate`, { instruction: a.instruction, fields: a.fields }))),\n def(\"approve_campaign_entries\", \"Mark campaign pages reviewed\",\n \"Mark campaign pages reviewed. `entryIds:'all_unflagged'` clears every page with nothing wrong with it, which is most of them; a FLAGGED page must be named explicitly, because approving one is a person saying they checked the claim. Approving does not publish — publish_campaign does, and it refuses pages that are still flagged.\",\n z.object({\n campaignId: z.string().min(1),\n entryIds: z.union([z.array(z.string()), z.literal(\"all_unflagged\")]),\n status: z.enum([\"approved\", \"rejected\"]),\n note: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Entries reviewed.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/entries/review`, { entryIds: a.entryIds, status: a.status, note: a.note }))),\n def(\"publish_campaign\", \"Publish a campaign\",\n \"Put a campaign's pages on the internet, or schedule them. `confirm: true` is REQUIRED — this is the one action in the ABM lane that a human, not you, decides. It REFUSES with `entry_flagged` if any page still carries an unchecked claim (call get_campaign_review and approve them first) and with `blueprint_missing_disclaimer` if a campaign page has lost its 'not affiliated with' band. Pages somebody rejected are skipped and counted.\",\n z.object({\n campaignId: z.string().min(1),\n scheduledAt: z.string().optional(),\n unpublishAt: z.string().optional(),\n confirm: z.boolean(),\n }).shape,\n async (c, a) => ok(\"Campaign publish queued.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/publish`, { scheduledAt: a.scheduledAt, unpublishAt: a.unpublishAt, confirm: a.confirm }))),\n def(\"get_campaign_share_link\", \"Make a share link\",\n \"Make a link a rep can send before the pages are published. `scope:'campaign'` opens the whole account index; `scope:'account'` with an `externalKey` (the account's domain) opens exactly that account's pages and 404s on anyone else's. At most 14 days, revocable, rate-limited and noindex. The link's `uses` is how a rep sees Not sent / Sent / Visited.\",\n z.object({\n campaignId: z.string().min(1),\n scope: z.enum([\"campaign\", \"account\"]).optional(),\n externalKey: z.string().optional(),\n expiresIn: z.string().optional(),\n label: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Share link.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/share-links`, { scope: a.scope, externalKey: a.externalKey, expiresIn: a.expiresIn, label: a.label }))),\n def(\"revoke_campaign_share_link\", \"Withdraw a share link\",\n \"Withdraw ONE share link by its `jti`, leaving every other link to the same campaign working. The link then answers 404. Safe to call twice.\",\n z.object({ campaignId: z.string().min(1), jti: z.string().min(1) }).shape,\n async (c, a) => ok(\"Share link revoked.\", await data(c, \"DELETE\", `/management/campaigns/${s(a.campaignId)}/share-links/${s(a.jti)}`))),\n def(\"list_ai_jobs\", \"List bulk jobs\",\n \"Recent bulk jobs for the connected project with status and progress. Use it to report how a generation is going.\",\n z.object({}).shape,\n async (c) => ok(\"Bulk jobs.\", await data(c, \"GET\", `/management/bulk/jobs`))),\n def(\"get_ai_job\", \"Get a bulk job\",\n \"One bulk job — its `type` (generate, seo, rename, migrate, publish, unpublish, research), status, rows processed, rows created, conflicts, and the approval plan if it is still parked. `rowResults` is the per-row ledger: every row that FAILED or was skipped, with a reason code, which is the only place “20 rows in, 18 pages out” is explained. `summary` splits a rerun into added / updated / unchanged, and `campaignId` / `collectionSlug` say which campaign and collection the pages landed in.\",\n z.object({ jobId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Bulk job.\", await data(c, \"GET\", `/management/bulk/jobs/${s(a.jobId)}`))),\n def(\"approve_ai_job\", \"Approve a bulk job\",\n \"Release a job that is awaiting approval so the queue can run it. Only call this when the USER has said yes — never approve your own plan unprompted.\",\n z.object({ jobId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Job approved.\", await data(c, \"POST\", `/management/bulk/jobs/${s(a.jobId)}/approve`))),\n def(\"reject_ai_job\", \"Reject a bulk job\",\n \"Discard a job awaiting approval. Nothing was charged and nothing was written.\",\n z.object({ jobId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Job rejected.\", await data(c, \"POST\", `/management/bulk/jobs/${s(a.jobId)}/reject`))),\n\n\n\n def(\"get_deploy_status\", \"Get deploy/build status\",\n \"Get the connected project's deploy/build status: state (idle|queued|building|failed), whether it's publishing, the live commit sha, when it went live, and any build error. `editorSetup`: whether editing is set up for the live build (never or stale = call editor_setup). Poll this after deploy_project until state is idle with your sha live. `release`, `held` and `publishes` (each `live` or `partial`): skill publishing. `runtime` ({state: ok|crash-loop, restarts, oomKilled}) appears for a server app only: crash-loop means its container keeps restarting (often out of memory) though the build went live fine. Also returns `canvas.lane` (skill bindings) and `editorUrl`, the visual editor to hand the user.\",\n z.object({}).shape,\n // Flat body, no `data` envelope: `data()` read it as undefined.\n async (c) => ok(\"Deploy status.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/deploy-status`), { method: \"GET\" }))),\n def(\"editor_setup\", \"Set up editing for the live build\",\n NEW_TOOL_TEXT.editor_setup,\n z.object({\n force: z.boolean().optional().describe(PARAM_TEXT.editorSetupForce),\n check: z.boolean().optional().describe(PARAM_TEXT.editorSetupCheck),\n exempt: z.array(z.record(z.string(), z.unknown())).optional().describe(PARAM_TEXT.editorSetupExempt),\n declare: z.array(z.record(z.string(), z.unknown())).optional().describe(PARAM_TEXT.editorSetupDeclare),\n }).shape,\n // The route answers `{ state, … }` with no `data` envelope, so the whole body is the result.\n // `exempt` records setup-gate exceptions instead of running anything (the gate's one write).\n // `declare` records binding decisions; with `check: true` it is a dry run (the body's `dryRun`).\n async (c, a) => a.exempt\n ? ok(\"Setup gate exceptions.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/setup-gate/exceptions`), { method: \"POST\", body: JSON.stringify({ exempt: a.exempt }) }))\n : a.declare\n ? ok(\"Binding decisions.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/binding-decisions`), { method: \"POST\", body: JSON.stringify({ declare: a.declare, ...(a.check === true ? { dryRun: true } : {}) }) }))\n : ok(\"Editor setup.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/editor-setup`), a.check === true\n ? { method: \"GET\" }\n : { method: \"POST\", body: JSON.stringify({ force: a.force }) }))),\n\n // ── Deploy to the user's own host (parity with remote /mcp) ──\n // A person connects Vercel or Netlify in the dashboard; nothing here touches OAuth or a host\n // token. deploy_to_host takes artifact:write like deploy_project. @see management/deploy-targets.ts\n def(\"list_env_vars\", \"List environment variables\",\n HOSTING_TEXT.list_env_vars,\n z.object({}).shape,\n async (c) => ok(\"Environment variables (names only).\", await data(c, \"GET\", `/management/hosting/env`))),\n def(\"list_hosting_connections\", \"List hosting connections\",\n HOSTING_TEXT.list_hosting_connections,\n z.object({}).shape,\n async (c) => ok(\"Hosting connections.\", await data(c, \"GET\", `/management/hosting/connections`))),\n def(\"deploy_to_host\", \"Deploy to Vercel or Netlify\",\n HOSTING_TEXT.deploy_to_host,\n z.object({\n provider: z.enum([\"vercel\", \"netlify\"]),\n connectionId: z.string().min(1).optional().describe(\"a connection id from list_hosting_connections; defaults to the newest working one\"),\n siteName: z.string().min(1).max(63).optional().describe(\"lowercase letters, numbers and hyphens; defaults to the project's handle\"),\n }).shape,\n async (c, a) => ok(\"Host deploy.\", await data(c, \"POST\", `/management/deploy-targets/provision`, { provider: a.provider, connectionId: a.connectionId, siteName: a.siteName }))),\n def(\"get_host_deploy_status\", \"Get host deploy status\",\n HOSTING_TEXT.get_host_deploy_status,\n z.object({}).shape,\n async (c) => ok(\"Host deployments.\", await data(c, \"GET\", `/management/hosting/external-deployments`))),\n ];\n }\n\n const defs: ToolDef[] = [\n {\n name: \"list_pages\",\n config: {\n title: \"List pages in the current project\",\n description:\n \"List the pages in the project this MCP key is bound to, each with its id, `path`, `language`, full field SCHEMA, pageType (singleton|dynamic), and status. Use it to verify WHERE content lands and to read field keys/types before set_page_content / add_field.\",\n inputSchema: {},\n },\n handler: guard(async () =>\n withClient(async (client) => {\n const pages = await client.listPages();\n return ok(\n `${pages.length} page(s) in the bound project.`,\n pages.map((p) => ({\n id: p.id,\n title: p.title,\n slug: p.slug,\n // Its URL and language: slugs are unique per folder, so `about` can be seven pages.\n path: (p as { path?: string }).path,\n language: (p as { language?: string | null }).language,\n pageType: p.pageType,\n status: p.status,\n // Held back from whole-site publishes: only when set, so an unheld list stays the same size.\n ...((p as { publishHeldAt?: string | null }).publishHeldAt ? { publishHeldAt: (p as { publishHeldAt?: string }).publishHeldAt } : {}),\n fields: p.fields,\n })),\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_page\",\n config: {\n title: \"Get a page (with its field schema)\",\n description:\n \"Get one page INCLUDING its full field schema (keys, types, nested group/repeater children), pageType, `path` and `language`. A field with `stale: true` is one the build no longer renders: kept, hidden in the editor. Read this before set_page_content so you write correctly-keyed values, or before add_field so you know the existing keys.\",\n inputSchema: getPageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getPageInput>) =>\n withClient(async (client) => {\n const page = await client.getPage(args.pageId);\n return ok(\n `Page '${page.title}' (${page.pageType ?? \"page\"}, ${page.fields.length} field(s)).`,\n page,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_page\",\n config: {\n title: \"Create a page\",\n description:\n \"Create a page with its own typed schema. Supports pageType 'singleton' (exactly one entry — Home, About, Contact) and 'dynamic' (many entries sharing the schema — Blog posts, Products). Project-scoped from the key. Additive — does not delete or overwrite existing pages. FIRST read the page's real markup and DECOMPOSE it into a destructured tree: each visual section becomes a nested field — a fixed grouped block → type 'group', a repeating list of items (cards, testimonials, features, FAQs) → type 'repeater' — each carrying its own child `fields`. Do NOT flatten sections into many flat top-level fields. Build the full nested tree, then call this once. 🔴 Every field key must be UNIQUE ACROSS THE WHOLE TREE — the namespace is flat, so 'title' cannot appear in two sections; prefix each with its section ('hero_title', 'faq_title'). Prose fields (headings, body copy, descriptions) are created as RICH TEXT by default; pass richText:false for values that must stay bare strings — hrefs, slugs, ids, emails. That tree is the page's SCHEMA — what it holds. \" +\n DOCTRINE,\n inputSchema: createPageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createPageInput>) =>\n withClient(async (client) => {\n // A create has no \"before\", so any collision is new. This is THE path that produced the\n // marketing page's six duplicate rows.\n const dupes = duplicateKeys(flatFieldKeys(args.fields));\n if (dupes.length > 0) return fail(duplicateKeyFailure(dupes));\n const page = await client.createPage({\n title: args.title,\n slug: args.slug,\n pageType: args.pageType ?? \"singleton\",\n ...(args.blockJson ? { blockJson: args.blockJson } : {}),\n // Cast: the SDK's ContentModelField types `options` as string[], narrower than the API,\n // which also takes {label, value} (backend selectFieldSchema).\n ...(args.fields ? { fields: args.fields.map(toField) as CreateManagedPageInput[\"fields\"] } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n ...(args.metaTitle !== undefined ? { metaTitle: args.metaTitle } : {}),\n ...(args.metaDescription !== undefined ? { metaDescription: args.metaDescription } : {}),\n ...(args.locale !== undefined ? { locale: args.locale } : {}),\n ...(args.translationOf !== undefined ? { translationOf: args.translationOf } : {}),\n } as CreateManagedPageInput);\n const { warnings, seedErrors, ...created } = page;\n const summary = `Created ${created.pageType ?? \"page\"} page '${created.title}' (id ${created.id}, slug ${created.slug}) with ${created.fields.length} field(s).`;\n // In the SUMMARY, where it is read, not buried in the page JSON: a create that dropped\n // its values reads as complete success otherwise.\n const notes = [\n ...(warnings ?? []),\n ...(seedErrors ? Object.entries(seedErrors).map(([key, why]) => ` ${key}: ${why}`) : []),\n ];\n return ok(notes.length ? `${summary}\\n${notes.join(\"\\n\")}` : summary, created);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_content_model\",\n config: {\n title: \"Create a content model (reusable schema)\",\n description:\n \"Create a content model — a reusable schema for a dynamic collection (Blog, Products, Testimonials). \" + PAGES_NOT_COLLECTIONS_NOTE + \" `fields` may NEST: type 'group' = one nested object of child fields; type 'repeater' = a repeatable array of child objects. Put child fields in each group/repeater's own `fields` (any depth). Pass kind:'block' to create a BLOCK type instead — see that argument. `fieldsets` ([{id, name}]) are the model's editor cards; a field joins one with `fieldsetId`. The slug must be unique in this project and branch: a taken one is refused with 409 `slug_taken` and free `suggestions`. \" +\n RICH_TEXT_NOTE,\n inputSchema: createModelInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createModelInput>) =>\n withClient(async (client) => {\n const modelDupes = duplicateKeys(flatFieldKeys(args.fields));\n if (modelDupes.length > 0) return fail(duplicateKeyFailure(modelDupes));\n const input = {\n name: args.name,\n slug: args.slug,\n ...(args.description !== undefined ? { description: args.description } : {}),\n ...(args.urlPattern !== undefined ? { urlPattern: args.urlPattern } : {}),\n ...(args.kind !== undefined ? { kind: args.kind } : {}),\n ...(args.fieldsets !== undefined ? { fieldsets: dropProvenance(args.fieldsets) as CreateModelInput[\"fieldsets\"] } : {}),\n fields: toFields(args.fields) as CreateModelInput[\"fields\"],\n };\n if (args.dryRun) return dryRunOf(client, \"POST\", `/management/content/models`, input);\n const model = await client.createModel(input);\n return ok(\n `Created content model '${model.name}' (${model.fields.length} field(s)).`,\n model,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"add_field\",\n config: {\n title: \"Add a field to a content model or a page\",\n description: ADD_FIELD_DESCRIPTION + \" \" + V2_LEAF_TYPES_NOTE + \" \" + RICH_TEXT_NOTE,\n inputSchema: addFieldInput.shape,\n },\n handler: guard(async (args: z.infer<typeof addFieldInput>) =>\n withClient(async (client) => {\n if (!args.modelId === !args.pageId) return fail(\"Pass exactly one of modelId (a content model) or pageId (a page).\");\n // The append routes validate where the field would be written, and store nothing.\n if (args.dryRun) {\n return dryRunOf(\n client,\n args.pageId ? \"PATCH\" : \"POST\",\n args.pageId ? `/management/pages/${args.pageId}` : `/management/content/models/${args.modelId}/fields`,\n { addFields: [toField(args)], ...(args.after !== undefined ? { after: args.after } : {}) },\n confirmedHeaders(args.confirmed),\n );\n }\n if (args.pageId) {\n // No client-side preflight for a page: `addPageFields` is an additive PATCH onto the\n // page-fields route, which refuses a flat-namespace collision itself and splices\n // `after` under the lock it already takes — a check here would be a second authority.\n const input = {\n // Cast: the SDK types `options` as string[], narrower than the API, which also takes\n // {label, value} (backend selectFieldSchema).\n addFields: [toField(args)] as AddPageFieldsInput[\"addFields\"],\n ...(args.after !== undefined ? { after: args.after } : {}),\n };\n // An approved custom input: client.addPageFields's own request plus the header it cannot send.\n const page = args.confirmed === true\n ? (await client.fetchJSON<{ data: Awaited<ReturnType<typeof client.addPageFields>> }>(client.url(`/management/pages/${args.pageId}`), {\n method: \"PATCH\",\n body: JSON.stringify(input),\n headers: confirmedHeaders(true),\n })).data\n : await client.addPageFields(args.pageId, input);\n return ok(`Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).${autoHelpNote(args)}`, page);\n }\n const modelId = args.modelId!;\n const model = await client.getModel(modelId);\n // 🔴 Was `model.fields.some(...)` — TOP LEVEL ONLY, so a key colliding with a group's\n // child sailed through. The namespace is flat; the check has to be too.\n const dupes = duplicateKeys([...flatFieldKeys(model.fields), args.key]);\n if (dupes.length > 0) return fail(duplicateKeyFailure(dupes));\n // `after` splices client-side here because this tool already holds the whole array\n // (it is a read-modify-write via updateModel, not the additive append route). An\n // unknown key FAILS instead of falling back to append: a silent append is how an\n // agent \"succeeds\" at putting a field somewhere it is not.\n const existingFields = model.fields as unknown[];\n let at = existingFields.length;\n if (args.after !== undefined) {\n const idx = existingFields.findIndex(\n (f) => (f as { key?: string }).key === args.after,\n );\n if (idx === -1) {\n return fail(\n `after: '${args.after}' is not a top-level field on this model. Valid keys: ` +\n `${existingFields.map((f) => `'${(f as { key?: string }).key}'`).join(\", \")}. ` +\n `Omit \\`after\\` to append at the end.`,\n );\n }\n at = idx + 1;\n }\n const nextFields = [...existingFields];\n nextFields.splice(at, 0, toField(args) as unknown);\n // The whole array goes back, so it carries every field's `ui`: a model where any field has a\n // dock icon / item label / group needs If-Match (428 without it). Send the version this\n // read-modify-write is based on, which also turns a concurrent edit into a 409, not a lost write.\n const input = { fields: nextFields as Parameters<typeof client.updateModel>[1][\"fields\"] };\n const opts = model.optimisticVersion !== undefined ? { ifMatch: model.optimisticVersion } : undefined;\n // An approved custom input: client.updateModel's own request plus the header it cannot send.\n const updated = args.confirmed === true\n ? (await client.fetchJSON<{ data: Awaited<ReturnType<typeof client.updateModel>> }>(client.url(`/management/content/models/${modelId}`), {\n method: \"PATCH\",\n body: JSON.stringify(input),\n headers: { ...(opts ? { \"If-Match\": `W/\"${opts.ifMatch}\"` } : {}), ...confirmedHeaders(true) },\n })).data\n : opts ? await client.updateModel(modelId, input, opts) : await client.updateModel(modelId, input);\n return ok(\n `Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : \"\"}. Model now has ${updated.fields.length} field(s).${autoHelpNote(args)}`,\n updated,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_content_entry\",\n config: {\n title: \"Create a content entry\",\n description:\n \"Create a content entry under a model. \" + PAGES_NOT_COLLECTIONS_NOTE + \" Pass its field VALUES in `data`, keyed by field key — INCLUDE ALL REQUIRED FIELDS (create validates them). New entries are drafts; pass status:'published' to take it live. Read get_content_model first for the field keys and which are required. One entry per call: for volume, run code against the Management API.\",\n inputSchema: createEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createEntryInput>) =>\n withClient(async (client) => {\n // One-shot create WITH data — the create route validates required fields, so\n // splitting into create-empty-then-update 400s for any model with a required\n // field. Status is draft-only on create server-side, so publishing needs a\n // follow-up update.\n const input = {\n contentModelId: args.contentModelId,\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n // The SDK's input type predates localization; its body is the input as given.\n ...(args.locale !== undefined ? { locale: args.locale } : {}),\n ...(args.translationOf !== undefined ? { translationOf: args.translationOf } : {}),\n ...(args.externalKey !== undefined ? { externalKey: args.externalKey, source: args.source, runId: args.runId } : {}),\n } as CreateEntryInput;\n if (args.dryRun) return dryRunOf(client, \"POST\", `/management/content/entries`, input);\n const created = await client.createEntry(input);\n const published =\n args.status !== undefined && args.status !== \"draft\"\n ? await client.updateEntry(created.id, { status: args.status })\n : created;\n // Advisory notes from either write (a reference to a deleted entry) go in the summary,\n // not the entry JSON.\n const { warnings, ...entry } = published;\n const notes = [...new Set([...(created.warnings ?? []), ...(warnings ?? [])])];\n return ok(\n // With an external key the write may have updated the entry, or left it unchanged.\n [`${args.externalKey ? \"Stored\" : \"Created\"} entry '${entry.slug}' (id ${entry.id}, status ${entry.status}).`, ...notes].join(\"\\n\"),\n entry,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"set_page_content\",\n config: {\n title: \"Set a page's field values (content)\",\n description:\n \"Set a page's field VALUES — the actual content. For a SINGLETON page (Home, About, Site Settings) this creates or updates its one entry, so call it again to edit. `data` is keyed by field key: a nested 'array' (zone) value is an OBJECT { nonRepeatable: { childKey: value }, repeatable: [ { childKey: value } ] }; a primitive 'array' is a plain list; an 'image' value is an asset URL or { url, altText?, focal?, crop? } — focal {x,y} and crop {top,right,bottom,left} (0–1, cut from each edge) frame THIS placement only. Read the schema first with get_page. This is how you populate Home/About/Settings — create_content_entry is for dynamic collections only. Merges by top-level key (a zone value replaces that whole zone); pass replace:true to remove omitted fields.\",\n inputSchema: setPageContentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof setPageContentInput>) =>\n withClient(async (client) => {\n const entry = await client.setPageContent(args.pageId, {\n data: args.data,\n ...(args.status !== undefined ? { status: args.status } : {}),\n ...(args.replace !== undefined ? { replace: args.replace } : {}),\n });\n return ok(\n `Set content on page ${args.pageId} (entry ${entry.id}, status ${entry.status}).`,\n entry,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"list_content_entries\",\n config: {\n title: \"List content entries (incl. drafts)\",\n description:\n \"List content entries — including drafts — 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) — read values with get_content_entry, or pass `detail: true` for full rows.\",\n inputSchema: listEntriesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listEntriesInput>) =>\n withClient(async (client) => {\n // The SDK's filter has no summary, limit, where, sort or page; the route does, so the read\n // goes straight through the client's request plumbing, with the query built by the helper\n // the hosted catalogue uses too.\n const res = await client.fetchJSON<{ data: unknown[]; meta?: { page: number; totalPages: number; total: number } }>(\n client.url(`/management/content/entries${entryListSearch(args)}`),\n { method: \"GET\" },\n );\n const paged = res.meta ? ` Page ${res.meta.page} of ${res.meta.totalPages} (${res.meta.total} in all).` : \"\";\n return ok(`${res.data.length} entr(y/ies).${paged}`, res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_content_entry\",\n config: {\n title: \"Get a content entry (with its values)\",\n description: \"Get one content entry by id INCLUDING its `data` (field values), even when draft.\",\n inputSchema: getEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getEntryInput>) =>\n withClient(async (client) => {\n const entry = await client.getEntry(args.entryId);\n return ok(`Entry '${entry.slug}' (id ${entry.id}, status ${entry.status}).`, entry);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_content_entry\",\n config: {\n title: \"Update a content entry's values\",\n description:\n \"Update a content entry's `data` (field values) and/or status by id. `data` is keyed by field key; a nested 'array' (zone) value is an object { nonRepeatable: {…}, repeatable: [{…}] }, a primitive 'array' is a plain list; an image value may carry this placement's focal {x,y} and crop {top,right,bottom,left} (0–1). Use this to edit an existing entry; for a singleton page prefer set_page_content. `data` MERGES into the stored values by top-level key: a field you leave out is kept, null clears one, and a group or repeater value replaces that whole key. 🔴 merge:false REPLACES the whole value object instead: an optional field you leave out is DELETED, and a required one you leave out fails the whole write. \" + FIELD_LOCKED_NOTE + \" \" + ENTRY_META_NOTE,\n inputSchema: updateEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateEntryInput>) =>\n withClient(async (client) => {\n // merge (the default): read, lay `data` over the stored keys, write at the version read.\n const write =\n mergesEntry(args)\n ? planEntryMerge(await client.getEntry(args.entryId), args.data!, args.ifMatch)\n : { data: args.data, ifMatch: args.ifMatch };\n const input = {\n ...(write.data !== undefined ? { data: write.data } : {}),\n ...(args.status !== undefined ? { status: args.status } : {}),\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.meta !== undefined ? { meta: args.meta } : {}),\n // Not on the SDK's input type yet; the route accepts both (null cancels).\n ...(args.scheduledAt !== undefined ? { scheduledAt: args.scheduledAt } : {}),\n ...(args.unpublishAt !== undefined ? { unpublishAt: args.unpublishAt } : {}),\n ...(args.locale !== undefined ? { locale: args.locale } : {}),\n ...(args.translationOf !== undefined ? { translationOf: args.translationOf } : {}),\n } as UpdateEntryInput;\n const { warnings, ...entry } =\n write.ifMatch === undefined\n ? await client.updateEntry(args.entryId, input)\n : await client.updateEntry(args.entryId, input, { ifMatch: write.ifMatch });\n return ok([`Updated entry '${entry.slug}' (id ${entry.id}, status ${entry.status}).`, ...(warnings ?? [])].join(\"\\n\"), entry);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"upload_asset\",\n config: {\n title: \"Upload an asset to the Media Library\",\n description:\n \"Upload an image/asset from a local file path or a remote URL into the project's Media Library, or have the server fetch a public `sourceUrl` itself. Returns the asset's stable CDN URL — put that URL into a content entry's image field. Use this BEFORE creating entries that reference images.\",\n inputSchema: uploadAssetInput.shape,\n },\n handler: guard(async (args: z.infer<typeof uploadAssetInput>) =>\n withClient(async (client) => {\n const asset = args.sourceUrl && !args.localPath && !args.url\n ? ((await client.fetchJSON<{ data: UploadedAsset }>(client.url(`/management/media/import`), {\n method: \"POST\",\n body: JSON.stringify({ url: args.sourceUrl, altText: args.altText, caption: args.caption, folderId: args.folderId }),\n })).data)\n : await client.uploadAsset(args);\n return ok(\n `Uploaded '${asset.filename}' (id ${asset.id}). Put this URL (or the id ${asset.id}) into an image field to attach it: ${asset.url}`,\n asset,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"delete_page\",\n config: {\n title: \"Delete a page\",\n description:\n \"DELETE a page and its content. Destructive but REVERSIBLE — it soft-deletes (can be restored from the dashboard) and is audit-logged. Use it to remove a page you created by mistake. Confirm with the user before deleting content they may want.\" +\n DELETE_PAGE_RUNTIME_BUNDLE,\n inputSchema: deletePageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deletePageInput>) =>\n withClient(async (client) => {\n if (!args.pageId === !args.runtimeBundle) return fail(\"Pass exactly one of pageId or runtimeBundle.\");\n if (args.runtimeBundle) {\n const res = await client.fetchJSON<{ data?: unknown }>(client.url(\"/management/pages/retire-runtime-bundle\"), {\n method: \"POST\",\n body: JSON.stringify({ dryRun: args.runtimeBundle !== \"apply\" }),\n });\n return ok(args.runtimeBundle === \"apply\" ? \"Bundle pages retired.\" : \"Bundle pages (dry run, nothing written).\", res.data);\n }\n const res = await client.deletePage(args.pageId!);\n return ok(`Deleted page ${res.id} (soft-delete — restorable from the dashboard).`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"delete_content_entry\",\n config: {\n title: \"Delete a content entry\",\n description:\n \"DELETE a single content entry. Destructive but REVERSIBLE (soft-delete, restorable from the dashboard) and audit-logged. Use it to remove content created by mistake.\",\n inputSchema: deleteEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deleteEntryInput>) =>\n withClient(async (client) => {\n const res = await client.deleteEntry(args.entryId);\n return ok(`Deleted entry ${res.id} (soft-delete — restorable from the dashboard).`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"delete_content_model\",\n config: {\n title: \"Delete a content model\",\n description:\n \"DELETE a content model and its entries. Destructive but REVERSIBLE (soft-delete, restorable from the dashboard) and audit-logged. Confirm with the user first — this removes all content under the model.\",\n inputSchema: deleteModelInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deleteModelInput>) =>\n withClient(async (client) => {\n const res = await client.deleteModel(args.modelId);\n return ok(`Deleted content model ${res.id} and its entries (soft-delete — restorable from the dashboard).`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n // ── Forms (read-only — discover dashboard forms to embed into the site) ──\n {\n name: \"list_forms\",\n config: {\n title: \"List forms in the current project\",\n description:\n \"List the forms built in the dashboard for the bound project — each with its id, name, and field schema. Use it to find a form to add to the user's site: read it, then write `<BcmsForm form={getForm('Name')} />` (from @bettercms-ai/next) into the page/component where the user wants it.\",\n inputSchema: {},\n },\n handler: guard(async () =>\n withClient(async (client) => {\n const forms = await client.listForms();\n return ok(\n `${forms.length} form(s) in the bound project.`,\n forms.map((f) => ({ id: f.id, name: f.name, fields: f.fields })),\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_form\",\n config: {\n title: \"Get a form (with its field schema)\",\n description:\n \"Get one form by id INCLUDING its fields (keys, types, required, options, showIf) and settings (submitLabel, successMessage, redirectUrl, turnstileEnabled, honeypotField). Read this before wiring `<BcmsForm>` so you render the right fields.\",\n inputSchema: getFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getFormInput>) =>\n withClient(async (client) => {\n const form = await client.getForm(args.formId);\n return ok(`Form '${form.name}' (${form.fields.length} field(s)).`, form);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_form\",\n config: {\n title: \"Create a form\",\n description:\n \"Create a form in the connected project from a field schema. Confirm the fields with the user first. Field types: text, email, textarea, select (needs options), radio (needs options), checkboxes (needs options), checkbox, number, phone, date, url, consent, hidden, step (a divider: the fields after it are one page). Returns the new form's id. It lands as a DRAFT; call publish_form before embedding (a draft form returns 403 on submit). Embed it with `<BcmsForm form={getForm('Name')} />` from @bettercms-ai/next.\",\n inputSchema: createFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createFormInput>) =>\n withClient(async (client) => {\n const form = await client.createForm(args as ManagedFormInput);\n return ok(`Created form '${form.name}' (id ${form.id}). Embed with <BcmsForm form={getForm('${form.name}')} />.`, form);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_form\",\n config: {\n title: \"Update a form\",\n description:\n \"Update a form by id — name, fields, or settings. Read get_form first. Passing `fields` REPLACES the array (include all fields to keep).\",\n inputSchema: updateFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateFormInput>) =>\n withClient(async (client) => {\n const { formId, ...input } = args;\n const form = await client.updateForm(formId, input as ManagedFormInput);\n return ok(`Updated form '${form.name}' (id ${form.id}).`, form);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"publish_form\",\n config: {\n title: \"Publish a form\",\n description:\n \"Publish a form by id so it accepts submissions. create_form and update_form only ever write a DRAFT, and a draft form answers every submit with 403 — call this before embedding it with `<BcmsForm form={getForm('Name')} />`. It re-bakes the project's site; `meta.rebuildQueued` says whether a rebuild was actually queued (false for a project with no connected source). 403 PUBLISH_NOT_GRANTED means this connection may author but not publish: say so and let the user publish from the dashboard Forms tab. 404 means the form is not in this connection's project.\",\n inputSchema: getFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getFormInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data?: { name?: string }; meta?: unknown }>(\n client.url(`/management/forms/${args.formId}/publish`),\n { method: \"POST\" },\n );\n return ok(`Published form '${res.data?.name ?? args.formId}'.`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n // ── Project/page Layout (draft commands + Global Layout publish; page overrides publish with the page) ──\n {\n name: \"get_layout\",\n config: {\n title: \"Get the project or page Layout\",\n description: \"Read the Global Layout or one page's Layout override, including its optimistic revision. Always read this before update_layout. copy:'published' reads the published copy — the only honest receipt for a publish claim.\",\n inputSchema: getLayoutInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getLayoutInput>) => withClient(async (client) => {\n const layout = await client.getManagedLayout(args);\n return ok(`${layout.scope === \"global\" ? \"Global\" : `Page ${layout.pageSlug}`} Layout ${args.copy === \"published\" ? \"PUBLISHED copy\" : \"draft\"} at revision ${layout.revision}.`, layout);\n })) as ToolDef[\"handler\"],\n },\n {\n name: \"update_layout\",\n config: {\n title: \"Apply Layout draft commands\",\n description: \"Apply permission-shaped values/composition/schema commands to the Global Layout or a page override. Draft-only: this never publishes. Pass the revision from get_layout as ifMatch. ONE command in `command`, or an ordered batch in `commands` (prefer the batch for more than three of anything — placing site chrome is add-section, add-component and set-bindings in sequence): each command is applied against the revision the previous one RETURNED, so you do not re-read get_layout between them. A batch stops at the first failure and tells you how many were applied and the revision it stopped at — the earlier ones stand, because a Layout command is not a transaction. \" + LAYOUT_LOCK_NOTE,\n inputSchema: commandLayoutInput.shape,\n },\n handler: guard(async (args: z.infer<typeof commandLayoutInput>) => withClient(async (client) => {\n const queued = args.commands ?? (args.command ? [args.command] : []);\n if (queued.length === 0) return fail(\"Pass `command` (one) or `commands` (an ordered batch).\");\n if (args.commands && args.command) return fail(\"Pass `command` or `commands`, not both — the order of the two would be undefined.\");\n\n let revision = args.ifMatch;\n let layout: Awaited<ReturnType<ManagementApi[\"commandManagedLayout\"]>> | undefined;\n const applied: Array<{ type: string; revision: number }> = [];\n for (const command of queued) {\n try {\n layout = await client.commandManagedLayout({\n scope: args.scope,\n pageId: args.pageId,\n projectId: args.projectId,\n command: command as ManagementLayoutCommand,\n ifMatch: revision,\n });\n } catch (err) {\n // 🔴 Report what LANDED. The commands before this one are already in the draft, and an\n // agent told only \"it failed\" re-runs the whole batch and duplicates every one of them.\n return fail(\n `Layout command ${applied.length + 1} of ${queued.length} (${command.type}) failed: ${errorText(err)}. ` +\n `${applied.length} command(s) were applied and remain in the draft; the Layout is at revision ${revision}. ` +\n `Re-read get_layout and continue from command ${applied.length + 1}.`,\n );\n }\n revision = layout.revision;\n applied.push({ type: command.type, revision });\n }\n const where = layout!.scope === \"global\" ? \"Global\" : `Page ${layout!.pageSlug}`;\n return ok(\n `Applied ${applied.length} command(s) to the ${where} Layout draft; now at revision ${revision}.`,\n { applied, revision, layout },\n );\n })) as ToolDef[\"handler\"],\n },\n {\n name: \"publish_layout\",\n config: {\n title: \"Publish the Global Layout draft\",\n description: \"Publish the connected project's GLOBAL Layout draft (navigation, footer, every reserved section). On a site BetterCMS serves, a Layout publish never builds: it writes the VALUES into the live pages, and a STRUCTURE change (Sections added, removed, moved) waits for a Rebuild or a push (`layout-rebuild-required`); a custom host gets its deploy hook. Until published, get_layout copy:'published' answers PUBLISHED_LAYOUT_UNAVAILABLE. Pass get_layout's `revision` as ifMatch; a stale one returns 409 — re-read, never retry blindly. A 422 lists validation issues (global, or per page override: pageSlug, copy) to fix with update_layout. A new project's chrome is draft: publish_component navigation-default and footer-default first (the order and the optional logo: skill components). Verify with get_layout copy:'published' — this response is the write's echo, not a receipt. Page Layout overrides go live with the page (update_page status:'published'). 403 PUBLISH_NOT_GRANTED: this connection may author drafts, not publish — say so; the user allows it or publishes from the dashboard.\",\n inputSchema: publishLayoutInput.shape,\n },\n handler: guard(async (args: z.infer<typeof publishLayoutInput>) => withClient(async (client) => {\n const layout = await client.publishManagedLayout(args);\n return ok(`Published the Global Layout at revision ${layout.revision} (copy: published). Verify with get_layout copy:'published'.`, layout);\n })) as ToolDef[\"handler\"],\n },\n // ── Components (discover + author reusable symbols) ──\n {\n name: \"list_components\",\n config: {\n title: \"List reusable components\",\n description: \"List the reusable components in the bound project. By DEFAULT this is the catalogue: id, name, slug, category, `sectionType` (the section family — a component with none is not in the editor's 'Add a section' picker), `status` ('draft' renders as NOTHING on the live site), and the `group` an editor browses it under, plus the locked `builtin:*` blueprints. It deliberately does NOT carry block trees: the full list carries every component's draft AND live `blockJson`, which is the largest response this API produces, and one component's definition is what `get_component` is for. Pass `detail: true` for the old full shape when you genuinely need every definition at once (rendering with `<BcmsBlocks>` from @bettercms-ai/next).\",\n inputSchema: listComponentsInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listComponentsInput>) =>\n withClient(async (client) => {\n // 🔴 The SUMMARY shape is chosen HERE, in the MCP tool, not on the server's default.\n // The route keeps its full shape for the renderers already reading it; what changes is\n // what an AGENT gets, which is the caller that never wanted the block trees and the one\n // whose context the response floods.\n if (args.detail) {\n const list = await client.listComponents();\n return ok(`${list.length} component(s) in the bound project (full definitions).`, list);\n }\n const list = await client.listComponents({ select: \"summary\" });\n return ok(\n `${list.length} component(s) in the bound project.`,\n list.map((cmp) => ({\n id: cmp.id,\n name: cmp.name,\n slug: cmp.slug,\n category: cmp.category,\n sectionType: cmp.sectionType,\n status: cmp.status,\n group: cmp.groupName,\n ...(cmp.builtin ? { builtin: true } : {}),\n })),\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_component\",\n config: {\n title: \"Get a component (with its blockJson)\",\n description: (\"One component with its blockJson and props (stored `ui` on them; `stale: true` = no placement renders it). Read it before update_component to keep its blocks, and after declaring field UI: a prop absent here was not stored.\") + \" \" + VARIANT_GROUP_NOTE,\n inputSchema: getComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getComponentInput>) =>\n withClient(async (client) => {\n if (args.detachedCopy) {\n const res = await client.fetchJSON<{ data: { name: string; fields: unknown } }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/detached-copy`),\n { method: \"POST\", body: JSON.stringify(args.detachedCopy) },\n );\n return ok(`A separate copy of '${res.data.name}': store \\`fields\\` on the embed.`, res.data);\n }\n const cmp = await client.getComponent(args.componentId);\n return ok(`Component '${cmp.name}' (${cmp.blockJson.length} block(s)).`, cmp);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_component\",\n config: {\n title: \"Create a reusable component\",\n description: (\"Create a reusable component from a blockJson tree. THIS IS ALSO HOW A PAGE GETS ITS SECTIONS: set `sectionType` (e.g. 'Hero') and the component becomes a placeable section, selectable in the editor's 'Add a section' picker. Components sharing a `sectionType` are its layout VARIANTS — one Hero with a 'Centered' and a 'Two-column' variant, same prop keys, so a swap keeps the content. CONFIRM the structure with the user first. blockJson is an array of blocks — the same set create_page accepts (heading, text/richtext, image, button, spacer, video, columns, section, slider, tabs, navbar, footer, form, component, collection), NOT a narrower one; `section` nests child blocks in props.children and `columns` in props.columns. `props` declares overridable fields. Returns the new id — render with `<BcmsBlocks>`. Always lands as a DRAFT — call publish_component to put it on the live site; until then it renders as NOTHING there, with no error. Buttons auto-join the project's Button family; section buttons link to its looks.\" +\n DOCTRINE) + \" \" + UNPROPPED_COPY_NOTE,\n inputSchema: createComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createComponentInput>) =>\n withClient(async (client) => {\n const cmp = await client.createComponent(args as ManagedComponentInput);\n return ok(`Created component '${cmp.name}' (id ${cmp.id}, slug ${cmp.slug}).`, cmp);\n }),\n ) as ToolDef[\"handler\"],\n },\n /**\n * ── The batch three ──────────────────────────────────────────────────────\n *\n * Sequential SDK calls with PER-ITEM receipts, and no new server route: the throughput\n * problem is one round trip per component, not one query per component, and inventing a bulk\n * endpoint would duplicate every validation, warning and governance gate the single writes\n * already run. A whole-site componentize run is forty creates, a dozen page compositions and\n * forty publishes; as individual tool calls that is a hundred turns of an agent's context\n * spent on plumbing.\n *\n * 🔴 NOTHING STOPS THE RUN. A batch that aborts on item 31 has already written 30 rows that\n * no receipt mentions, and the agent's only safe move is to re-run it and duplicate them.\n * Every item reports its own outcome instead, and the summary line says how many failed.\n */\n {\n name: \"publish_components\",\n config: {\n title: \"Publish many components in one call\",\n description:\n \"Publish up to 100 components in ONE call — the same act as publish_component, once per item, copying each DRAFT definition to the live copy. Each item reports `{ ok, status, error, readiness }` and a failure never stops the run. 🔴 A 409 COMPONENT_IMPLEMENTATION_NOT_READY is NOT retried: only the owner, in the dashboard, clears it (publish_component says when); relay the item's `readiness` to the user as what only they can approve. 403 PUBLISH_NOT_GRANTED means this connection may author but not publish; 422 means the publish would break a Layout, and the item names which.\",\n inputSchema: publishComponentsInput.shape,\n },\n handler: guard(async (args: z.infer<typeof publishComponentsInput>) =>\n withClient(async (client) => {\n const results: Array<Record<string, unknown>> = [];\n for (const componentId of args.componentIds) {\n try {\n const res = await client.fetchJSON<{ data?: { status?: string; slug?: string } }>(\n client.url(`/management/components/${componentId}/publish`),\n { method: \"POST\" },\n );\n results.push({ ok: true, componentId, slug: res.data?.slug, status: res.data?.status ?? \"published\" });\n } catch (err) {\n // The 409 body carries the whole readiness tuple — which evidence is missing, and\n // whether it is now waiting on a person. That is the difference between \"publish\n // failed\" and a sentence the user can act on.\n const readiness = (apiError(err)?.body as { readiness?: unknown } | undefined)?.readiness;\n results.push({\n ok: false,\n componentId,\n error: errorText(err),\n ...(readiness ? { readiness } : {}),\n });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n return ok(\n `Published ${results.length - failed} of ${args.componentIds.length} component(s)${failed ? `; ${failed} could not be published — read each item's error and readiness, and tell the user which ones need THEIR approval in the dashboard` : \"\"}.`,\n results,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"compose_pages\",\n config: {\n title: \"Set many pages' block composition in one call\",\n description:\n \"Give up to 50 pages their block composition in ONE call — the same write as update_page's `blockJson`, once per item, and it REPLACES each page's whole block array. Address a page by `pageId` or by `slug`. Each item reports `{ ok, pageId, slug, error }` and a failure does not stop the run. BEFORE writing anything it reads this project's component catalogue once and REFUSES any item placing a componentId the project does not have — its missing sections would render as empty strings with no error anywhere. Writes DRAFTS: publish each page with update_page status:'published' afterwards. \" +\n \"A page is composed of SECTIONS: a recurring band is a component with a `sectionType`, a one-off band is a `section` block whose `props.children` hold its blocks — never loose top-level heading/text/image blocks, which no editor can move, name or swap as a unit. The full doctrine is in the bettercms://playbook/schema resource, §12.\",\n inputSchema: composePagesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof composePagesInput>) =>\n withClient(async (client) => {\n const known = await client.listComponents({ select: \"summary\" });\n const ids = new Set(known.map((c) => c.id));\n\n const results: Array<Record<string, unknown>> = [];\n for (const page of args.pages) {\n const ref = page.pageId ?? page.slug;\n if (!ref) {\n results.push({ ok: false, error: \"Pass a pageId or path from list_pages.\" });\n continue;\n }\n let pageId: string;\n try {\n pageId = await pageIdOf(client, ref);\n } catch (err) {\n results.push({ ok: false, slug: page.slug, error: errorText(err) });\n continue;\n }\n const unknown = [...new Set(componentIdsIn(page.blockJson))].filter((id) => !ids.has(id));\n if (unknown.length) {\n results.push({\n ok: false,\n pageId,\n slug: page.slug,\n error: `Refused: this page places component id(s) this project does not have — ${unknown.join(\", \")}. A missing component renders as an empty string with no error, so nothing was written for this page.`,\n });\n continue;\n }\n try {\n const written = await client.fetchJSON<{ data?: { id?: string; slug?: string; path?: string }; held?: string; holds?: unknown[] }>(\n client.url(`/management/pages/${pageId}/meta`),\n { method: \"PATCH\", body: JSON.stringify({ blockJson: page.blockJson, ...(args.dryRun ? { dryRun: true } : {}) }) },\n );\n results.push({ ok: true, ...(args.dryRun ? { status: \"would-update\" } : {}), pageId, slug: written.data?.slug ?? page.slug, path: written.data?.path, blocks: page.blockJson.length, ...(written.held ? { held: written.held } : {}), ...(written.holds?.length ? { holds: written.holds } : {}) });\n } catch (err) {\n results.push({ ok: false, pageId, slug: page.slug, error: errorText(err) });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n if (args.dryRun) {\n return ok(DRY_RUN_SUMMARY, { dryRun: true, results, wouldCompose: results.length - failed, failed });\n }\n // A held page leads, by name: its draft is saved and its live page will not show the change.\n const held = results.filter((r) => typeof r.held === \"string\");\n const lead = held.length ? `HELD on ${held.length} of ${args.pages.length} page(s). ${held.map((r) => `${String(r.slug ?? r.pageId)}: ${String(r.held)}`).join(\" \")}\\n` : \"\";\n return ok(\n `${lead}Composed ${results.length - failed} of ${args.pages.length} page(s)${failed ? `; ${failed} failed — see the per-item errors` : \"\"}. These are page DRAFTS: publish each with update_page status:'published'. Then call get_site_composition for the receipt.`,\n results,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"list_extraction_candidates\",\n config: {\n title: \"Find sections that repeat across pages\",\n description:\n \"Find sections that appear IDENTICALLY (same structure and styling, different wording) on 3+ places across this project's pages, each proposed as one reusable component. Read-only — nothing changes. Returns a `hash` per candidate to pass to extract_component, plus how many places it appears, which fields differ between copies, and the exact pages involved. Use this before hand-building a component with create_component: if a section already repeats, extracting it is better than adding a 4th copy.\",\n inputSchema: listExtractionCandidatesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listExtractionCandidatesInput>) =>\n withClient(async (client) => {\n const found = await client.listExtractionCandidates(args.projectId);\n if (found.length === 0) {\n return ok(\"No section repeats on 3 or more pages in this project.\", found);\n }\n const lines = found.map(\n (c) => `- ${c.suggestedName} (hash ${c.hash}) — ${c.uses} places, ${c.props.length} varying field(s)`,\n );\n return ok(`${found.length} repeated section(s):\\n${lines.join(\"\\n\")}`, found);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"extract_component\",\n config: {\n title: \"Extract a repeated section into one component\",\n description:\n \"Fold one candidate from list_extraction_candidates into a single reusable component and repoint EVERY occurrence at it. CONFIRM WITH THE USER FIRST — this rewrites blocks on several pages at once, and name the pages from the candidate's `sites` when you ask. Only page DRAFTS change: the live site is untouched until those pages are published, and the component itself lands as a DRAFT. Fields that differ between copies become component props, so each page keeps its own wording. 409 means the sections were edited since you listed them — re-run list_extraction_candidates and ask again.\",\n inputSchema: extractComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof extractComponentInput>) =>\n withClient(async (client) => {\n const res = await client.extractComponent(args);\n const { component, replaced } = res;\n // The kit entry the matcher SUGGESTS (never recorded; SDK minor, an older SDK build has none to pass on).\n const kit = (res as { kit?: { suggested: string | null; score: number | null; link: string; line: string } }).kit;\n return ok(\n `Created component '${component.name}' (id ${component.id}) and repointed ${replaced} sections to it. Page drafts changed; publish those pages to make it live.${kit?.line ? ` ${kit.line}: only a suggestion, so check its htmlSignals and pitfalls, then confirm or replace it with update_component { kitEntry }.` : \"\"}`,\n { ...component, ...(kit ? { kit } : {}), nextAction: DOCK_UI_NEXT },\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_component\",\n config: {\n title: \"Update a reusable component\",\n description: (\"Update a component by id — blockJson, props, name, or category. Read with get_component, then pass `ifMatch` = the version from that read. Passing `blockJson`/`props` REPLACES them. This writes the DRAFT: call publish_component to push the change live.\") + \" \" + KIT_ENTRY_REBUILD_NOTE + \" \" + UNPROPPED_COPY_NOTE,\n inputSchema: updateComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateComponentInput>) =>\n withClient(async (client) => {\n const { componentId, ifMatch, confirmed, ...input } = args;\n // An approved custom input (the header client.updateComponent cannot send), or a kitEntry\n // (its `kitUiApplied` receipt sits beside `data`): client.updateComponent's own request, read whole.\n const res = confirmed === true || typeof input.kitEntry === \"string\"\n ? await client.fetchJSON<{ data: Awaited<ReturnType<typeof client.updateComponent>>; kitUiApplied?: string[] }>(client.url(`/management/components/${componentId}`), {\n method: \"PATCH\",\n body: JSON.stringify(input),\n headers: { ...(ifMatch !== undefined ? { \"If-Match\": `W/\"${ifMatch}\"` } : {}), ...confirmedHeaders(confirmed) },\n })\n : { data: await client.updateComponent(componentId, input as ManagedComponentInput, { ifMatch }), kitUiApplied: undefined };\n const cmp = res.data;\n const rebuilt = res.kitUiApplied ? ` kitEntry set: rebuilt the derived ui of ${res.kitUiApplied.length} prop(s)${res.kitUiApplied.length ? ` (${res.kitUiApplied.join(\", \")})` : \"\"}.` : \"\";\n return ok(`Updated component '${cmp.name}' (id ${cmp.id}).${rebuilt}`, res.kitUiApplied ? { ...cmp, kitUiApplied: res.kitUiApplied } : cmp);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"set_component_source\",\n config: {\n title: \"Record which file implements a component\",\n description:\n \"Call this RIGHT AFTER you write or locate a component's code in the app's repository: it records which file renders it, so the dashboard's Output button can preview and validate it with no setup (without it nothing is validated). Record ONLY a file that renders exactly this component from its own fields: a component whose props are this component's field keys (`kind: 'file'`, the default), or a section the codemod extracted with `npx @bettercms-ai/convert --componentize` — a file starting `// @bettercms-ai/convert section` whose props are `{ blockId, bind, overrides, page }` (`kind: 'section'`). Never record a different component that merely contains this markup (e.g. a card that needs a `post` object): it cannot render from these fields and validation fails. If the markup is inline in a page, extract it into a section first. `path` is relative to the app root (e.g. 'src/components/sections/Hero.astro'); `export` is the export name, omitted for a default export. Call it again if the file moves; call clear_component_source if a recorded file is wrong.\",\n inputSchema: setComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof setComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: { componentId: string; path: string; export: string } }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/preview-source`),\n { method: \"PUT\", body: JSON.stringify({ path: args.path, ...(args.export ? { export: args.export } : {}), ...(args.kind ? { kind: args.kind } : {}) }) },\n );\n return ok(`Recorded ${res.data.path}${res.data.export === \"default\" ? \"\" : ` (export ${res.data.export})`} as the source of component ${res.data.componentId}.`, res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"submit_componentize_receipt\",\n config: {\n title: \"Record the sources a componentize run wrote\",\n description:\n \"Record every section the componentize codemod extracted as its component's source. Call it right after `npx @bettercms-ai/convert --componentize --receipt componentize.json` (and after pushing the files): pass that receipt verbatim. Each extracted section is recorded as kind 'section' for the component with the same slug, so Output can build and validate it with no set_component_source per component. Answers which components were recorded, and any slug this project has no component for.\",\n inputSchema: submitComponentizeReceiptInput.shape,\n },\n handler: guard(async (args: z.infer<typeof submitComponentizeReceiptInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: { recorded: Array<{ slug: string; componentId: string; path: string }>; unknown: string[]; invalid: string[] } }>(\n client.url(\"/management/components/preview-sources/componentize-receipt\"),\n { method: \"POST\", body: JSON.stringify({ receipt: args.receipt }) },\n );\n const { recorded, unknown, invalid } = res.data;\n return ok(\n `Recorded ${recorded.length} section source${recorded.length === 1 ? \"\" : \"s\"}${unknown.length ? `; no component for ${unknown.join(\", \")}` : \"\"}${invalid.length ? `; unimportable path for ${invalid.join(\", \")}` : \"\"}.`,\n res.data,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"clear_component_source\",\n config: {\n title: \"Remove a component's recorded source file\",\n description:\n \"Remove the file recorded as a component's source (by set_component_source or a conversion receipt). Use it when the recorded file is wrong — Output then shows no source until the right file is recorded. Safe to call when nothing is recorded.\",\n inputSchema: clearComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof clearComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: { componentId: string; cleared: boolean } }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/preview-source`),\n { method: \"DELETE\" },\n );\n return ok(res.data.cleared ? `Removed the recorded source of component ${res.data.componentId}.` : `Component ${res.data.componentId} had no recorded source.`, res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_component_readiness\",\n config: {\n title: \"Read a component's Output validation readiness\",\n description: \"Read what stands between a component and a validated Output: `validation.gap` and `validation.fix` say why a validation run cannot take it yet (COMPONENT_SOURCE_NOT_RECORDED: record its file with set_component_source, or place it and deploy a build whose markup carries its data-bcms-block / data-bcms-field attributes), and the readiness says where its request, evidence and approval stand. Call it after authoring a component and after every validation run. outputReady means the Output renders; publishReady also needs the owner's Visual Approval in the dashboard, which no tool can give.\",\n inputSchema: clearComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof clearComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: unknown }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/readiness`),\n );\n return ok(\"Component validation readiness.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"declare_component_route\",\n config: {\n title: \"Declare where a component's preview is served\",\n description: \"Declare where this component's preview is served in the app (the dashboard's \\\"Show preview\\\"). Omit `path` to use the server's default route; pass `nativeViewports` only to check sizes other than the defaults. The origin is the project's preview URL and is never taken from you. Answers the readiness.\",\n inputSchema: componentValidationRouteInput.shape,\n },\n handler: guard(async (args: z.infer<typeof componentValidationRouteInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: unknown }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/adapter`),\n { method: \"PUT\", body: JSON.stringify({ path: args.path, nativeViewports: args.nativeViewports }) },\n );\n return ok(\"Preview route declared.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"request_component_validation\",\n config: {\n title: \"Request Output validation for a component\",\n description: \"Ask for this component's Output to be validated by YOU, the connected agent (provider user-agent). Record its source first (set_component_source, or the componentize codemod plus a deploy): a component nothing renders is refused with 422 and the fix, and no request is opened. After a 202, run `npx @bettercms-ai/preview-runtime validate --local --request <requestId>` in the app's repository with BCMS_API_KEY set in the environment (never pass a key in a tool call), then read get_component_readiness. Your evidence is self-attested: publishing still needs the owner's Visual Approval in the dashboard \\u2014 never claim you approved it. CI validation (github-app) runs in the owner's repository at their cost, so it is refused here with VALIDATION_PROVIDER_DASHBOARD_ONLY: ask the owner to start it from the dashboard. 409 COMPONENT_ORCHESTRATION_V2_REQUIRED means continue in Agent Dock.\",\n inputSchema: clearComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof clearComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: unknown }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/implementation-requests`),\n { method: \"POST\", body: JSON.stringify({}) },\n );\n return ok(\"Validation requested. Run `npx @bettercms-ai/preview-runtime validate --local --request <requestId>` in the repository next.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"publish_component\",\n config: {\n title: \"Publish a component\",\n description:\n \"Publish one project-scoped component variant after its exact implementation evidence and human approval are ready: copy its DRAFT definition to the live copy and re-bake every published page that embeds it. This is the ONLY way a component reaches the live site. Built-in `builtin:*` rows are locked blueprints, not implementations; materialize one with create_component first. Workspace-global component publication is currently fail-closed. Drafts (create_component, update_component) render as NOTHING live, with no error: publish every component you place on a page. 403 PUBLISH_NOT_GRANTED means this connection may author but not publish: say so and let the user publish from the dashboard. 🔴 A 409 COMPONENT_IMPLEMENTATION_NOT_READY is NOT retried and must not be: no tool on this connection can clear it. It asks for exact validation evidence and a human's approval, never of a component you just made with create_component (which ones: skill components). Its `readiness` names what is missing — relay it to the user instead of retrying or routing around it. 422 means publishing would break a Layout that uses it — the response names which.\",\n inputSchema: getComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getComponentInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data?: unknown }>(\n client.url(`/management/components/${args.componentId}/publish`),\n { method: \"POST\" },\n );\n return ok(\"Published component.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n\n\n // ── AI content + SEO actions (Option B) ────────────────────────────────────\n {\n name: \"write_content\",\n config: {\n title: \"Write, rewrite, or translate content\",\n description:\n \"AI-write a piece of copy: action 'write' (draft from a brief), 'rewrite' (improve existing copy), or 'translate' (needs targetLang). Returns the suggested text — apply it with set_page_content or update_content_entry. Uses the workspace's own Anthropic key (BYOK, unmetered) or platform AI credits.\",\n inputSchema: writeContentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof writeContentInput>) =>\n withClient(async (client) => {\n const suggestion = await client.writeContent(args);\n return ok(`Generated ${args.action} suggestion (${suggestion.length} chars).`, { suggestion });\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"generate_seo_meta\",\n config: {\n title: \"Generate SEO metadata\",\n description:\n \"Generate SEO metadata (metaTitle, metaDescription, keywords, optional JSON-LD) for a piece of content. Pass the page/entry content as `text`. Returns a suggestion: apply a page's with update_page (metaTitle, metaDescription, schemaType, schema) and an entry's with update_content_entry `meta`.\",\n inputSchema: generateSeoMetaInput.shape,\n },\n handler: guard(async (args: z.infer<typeof generateSeoMetaInput>) =>\n withClient(async (client) => {\n const meta = await client.generateSeoMeta(args);\n return ok(`Generated SEO metadata: \"${meta.metaTitle}\".`, meta);\n }),\n ) as ToolDef[\"handler\"],\n },\n\n // ── Native bridge (executor presence) ──────────────────────────────────────\n {\n name: \"connect_native_ai\",\n config: {\n title: \"Connect this client to the project's Native AI Connection\",\n description:\n \"Connect this client to the project's Native AI Connection, so the dashboard shows it as an available executor. Call it ONCE when the user asks to connect — after that, ordinary tool calls on the same project keep it listed, and nothing needs to run on a timer. Idempotent. Returns the project it connected to and `presenceWindowMs`: the executor stays listed for that long after the last tool call, then drops off until the next one. THIS GRANTS NOTHING — it is presence only, and starting a run is still a human act in the dashboard. A 403 BRIDGE_GRANT_REQUIRED means this client is using a bare API key rather than an approved connection; a 400 means the connection covers the whole workspace and you must pass `projectId`.\",\n inputSchema: connectNativeAiInput.shape,\n },\n handler: guard(async (args: z.infer<typeof connectNativeAiInput>) =>\n withClient(async (client) => {\n const result = await client.fetchJSON<{\n state: string;\n projectId: string;\n installationId: string;\n presenceWindowMs: number | null;\n }>(client.url(\"/management/orchestration/bridge/connect\"), {\n method: \"POST\",\n body: JSON.stringify({\n protocolVersion: \"1\",\n ...(args.capabilities ? { capabilities: args.capabilities } : {}),\n }),\n });\n const mins = result.presenceWindowMs\n ? Math.round(result.presenceWindowMs / 60_000)\n : null;\n return ok(\n `Connected to project ${result.projectId}. The dashboard now lists this client as an available executor${mins ? `; it stays listed for ${mins} minutes after the last tool call` : \"\"}.`,\n result,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n\n // ── Lifecycle tools (parity with the remote /mcp surface) ──────────────────\n // Media management, form submissions (leads), redirects, SEO, AEO site-files,\n // promote, and entry version history. These call the management endpoints straight\n // through the client's request plumbing — no bespoke SDK method per endpoint.\n ...lifecycleTools(),\n ];\n\n /**\n * A page named by PATH or slug (`/de/about`, `about`) becomes its id before the tool runs, as\n * the hosted callTool does: a slug two pages share fails with each match's id, path and language.\n */\n const withPageRef = (def: ToolDef): ToolDef => ({\n ...def,\n handler: (args) => {\n const ref = args?.pageId;\n if (typeof ref !== \"string\" || !ref || UUID.test(ref)) return def.handler(args);\n return guard(async () => def.handler({ ...args, pageId: await withClient((c) => pageIdOf(c, ref)) }))(undefined);\n },\n });\n\n // Tail last, so a client that keeps only the first 100 keeps the authoring lane. A stable\n // partition: inside each half the order is still the one the literal above declares.\n return [\n ...defs.filter((d) => !LISTING_TAIL.has(d.name)),\n ...defs.filter((d) => LISTING_TAIL.has(d.name)),\n ].map(withPageRef).map(withProjectId);\n}\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Register the BetterCMS tools on an MCP server — those the toolsets list: BETTERCMS_MCP_TOOLS is a\n * comma list of `core`, `abm` and `all` (the hosted connector's `?tools=`); unset = every tool\n * except the ABM lane. A tool this connection does not list is not registered.\n */\nexport function registerTools(server: McpServer, deps: ToolDeps, tools = process.env.BETTERCMS_MCP_TOOLS): void {\n // Give the tools a way to ask the human directly. Threaded here rather than taken as a\n // dep by the caller so buildToolDefs stays server-free for the tests.\n const withElicit: ToolDeps = {\n ...deps,\n elicit: deps.elicit ?? ((params) => server.server.elicitInput(params as never)),\n };\n const sets = toolsetsOf(tools);\n for (const def of buildToolDefs(withElicit).filter((d) => listsTool(d.name, sets))) {\n const _meta = toolMeta(def.name);\n server.registerTool(def.name, _meta ? { ...def.config, _meta } : def.config, def.handler as never);\n }\n}\n","/**\n * Component — a reusable, Webflow-style block tree (a \"symbol\").\n *\n * A component is authored once and placed across pages via `component` blocks\n * (see `ComponentBlock` in `./block.ts`). Its definition lives in `blockJson`;\n * `props` declares a flat allowlist of values an instance may override.\n */\nimport type { BlockStyle, ContentBlock, VisibilityWindow } from \"./block.js\";\nimport type { ChoiceOption, ContentModelFieldUi, FieldsetKind, OpenMode, ShowIf, UiBefore, UiOrigin } from \"./content-model.js\";\nimport type { DockIconName } from \"./dock-icon-names.js\";\nimport type { VariantInputMapping } from \"./layout.js\";\n\n/**\n * The category a component belongs to (drives library grouping + icons). The first eight\n * are structural (what the component IS); the last four are the \"Add a section\" library\n * tabs (where it appears). One varchar column, not a PG enum — widening is code-only.\n */\n/**\n * 🔴 THE STRUCTURE DOCTRINE — one sentence, one home, spliced into every surface that builds a page.\n *\n * It lives HERE, beside the component contract it describes, because there are THREE places that teach\n * an agent how to build a page and they drifted apart:\n * • `packages/mcp/src/tools.ts` — the MCP tool descriptions (external agents)\n * • `src/lib/ai/agent.ts` — the in-product Studio Agent's system prompt\n * • `packages/mcp/src/prompts.ts` — the authoring playbook, which a tool call does not carry\n *\n * Only the playbook explained sections. `create_page` taught the SCHEMA axis in detail (\"each visual\n * section becomes a nested field\") and said nothing about STRUCTURE; the Studio Agent's prompt named\n * \"pages & reusable components (structure/layout)\" without ever mentioning `sectionType`.\n *\n * Measured consequence, production 2026-08-18: project `acme` has three components, ALL with\n * `section_type = (none)`, and its home page is 18 loose top-level blocks with ZERO sections. Every\n * generated page came out flat, so the visual editor's section lane — outline, name, move, duplicate,\n * delete, variant swap — had nothing to attach to. The editor was faithfully showing pages that were\n * never built out of sections.\n *\n * A constant rather than three paraphrases, because updating some of them is exactly how this happened.\n */\nexport const SECTION_DOCTRINE =\n \"STRUCTURE (separate from schema): a page is composed of SECTIONS. NEVER build a page out of loose top-level heading/text/image/button/spacer blocks — they cannot be moved, duplicated or swapped as a unit, the visual editor cannot outline or name them, and every one of them becomes its own section in the editor. A hero of a headline, a lede and two CTAs is ONE section, not four. TWO SHAPES, and the choice is about REUSE. (1) A band that appears on more than one page, or that needs layout variants, is a COMPONENT with a `sectionType` — see create_component. Components sharing a `sectionType` are that section's VARIANTS (one Hero: 'Centered' for the home page and 'Two-column' for about, same prop keys so a swap keeps the content). This is also the only shape the editor's 'Add a section' picker can insert, and the only one that gets a family name and a variant switcher. (2) A genuinely one-off band on a single page is a `section` BLOCK whose `props.children` hold its blocks. THE TRADEOFF, stated in the present tense because it is real today: inside a component, ONLY the leaves a declared prop TARGETS are click-to-edit on the canvas — each declared prop's `target` is re-keyed to that PLACEMENT's own override address, so editing it changes this page and not the shared definition. A prop with no `target` still SHOWS as a dock control, but its override reaches no rendered slot, so editing it changes nothing on the page. Copy that no prop points at is worse still: no binding and no control, unreachable from click-to-edit AND from the dock, changeable only by editing the component definition, which rewrites every page that places it. A `section` block's children stay click-to-edit unconditionally. So when you choose a component, DECLARE A PROP — WITH A `target` — for every string, link and image a marketer will ever touch; a component with un-propped editable copy is the defect, not the component. In the dock an unset prop shows EMPTY and inherits the definition's default, so set props explicitly when you want the current copy visible there. An IMPORTED site's components are its own (read the repo); its nav, footer and modals are the Layout. On a blank site, do not hand-write a band's JSON: start from a built-in section blueprint (list_components returns locked `builtin:*` blueprints with no projectId — hero-centered, hero-split, feature-grid-three, cta-banner and more), each already rooted in a `section` block with its editable leaves declared as props. INLINE its blockJson as a `section` block for a one-off band; for a recurring band, materialize it with create_component `from` so it becomes project-scoped before implementation validation, Output or publication. Direct `builtin:*` component references exist only for legacy delivery compatibility. Two consecutive call-to-action buttons are two sibling `button` blocks inside the same section — never a `columns` block, which is a `repeat(N,1fr)` grid and would stretch each CTA to half the container. Buttons are inline-level and flow side by side on their own.\";\n\nexport type ComponentCategory =\n | \"navbar\"\n | \"footer\"\n | \"button\"\n | \"section\"\n | \"slider\"\n | \"tabs\"\n | \"form\"\n | \"custom\"\n | \"hero\"\n | \"content\"\n | \"social-proof\"\n | \"conversion\";\n\n/**\n * A single overridable field on a component. `target` points at the block + JSON\n * path inside `blockJson` the override writes to (e.g. blockId \"cta\", path\n * \"props.text\"). Keeping overrides a declared allowlist (not arbitrary nested\n * rewrites) keeps instance data small and the contract explicit.\n */\n/**\n * THE prop vocabulary. One list, imported everywhere a prop type is enumerated.\n *\n * It exists as a value (not just a union) because four places used to spell it out by hand —\n * this file, the Drizzle schema, `COMPONENT_PROP_TYPES` in the backend's Zod schemas, and the\n * MCP tool shape — and the MCP copy is the dangerous one: `update_component` REPLACES the whole\n * `props` array, so a type its enum omits cannot be echoed back, and an agent that reads a\n * component and writes it straight back DESTROYS every prop of that type with a 200.\n *\n * Order is not semantic; append rather than re-sort, so a diff stays readable.\n */\nexport const COMPONENT_PROP_TYPES = [\n \"text\",\n \"richtext\",\n \"image\",\n \"url\",\n \"boolean\",\n \"number\",\n \"select\",\n \"group\",\n \"table\",\n \"slot\",\n \"form\",\n // The seven below each store what the same-named content-model FIELD stores (`icon` and\n // `multiselect` have no field twin; see the value notes on ComponentPropDef.type).\n \"link\",\n \"button\",\n \"date\",\n \"color\",\n \"file\",\n \"icon\",\n \"multiselect\",\n // V2 schema language (F1.x). `object` is ONE nested value of named `config.fields`, stored as\n // `{ [childKey]: value }` like the model field `object`; the six after it store what the\n // same-named content-model FIELD stores (`location` is the V2 geopoint) and are judged by\n // that field's validator.\n \"object\",\n \"datetime\",\n \"slug\",\n \"email\",\n \"phone\",\n \"json\",\n \"location\",\n // V2 leaves, each storing what the same-named content-model FIELD stores: a taxonomy string[],\n // a rating number, a code value (`{ language?, code }` or a string).\n \"tags\",\n \"rating\",\n \"code\",\n // CMS items, as the same-named content-model FIELDS store them: an entry id (or a polymorphic\n // `{ entryId, modelSlug }`), and a list of them. Delivery hydrates them like an entry's.\n \"reference\",\n \"multi-reference\",\n // V2 chrome types, each storing what the same-named content-model FIELD stores: a video value,\n // a primitive list (`config.itemType`), and multi-line text (the field lane's V2 `text`).\n \"video\",\n \"array\",\n \"longtext\",\n] as const;\n\nexport type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];\n\n/**\n * The value a `form` prop STORES: just the id. The form itself is a Form document and stays the\n * single source of truth for its fields — a component references one, it never re-declares it.\n *\n * `.strict()` at the write boundary, so a client that POSTs a hydrated form object alongside the\n * id gets a 400 rather than a silent strip.\n *\n * There is deliberately NO resolved twin of this shape. Every renderer already receives forms the\n * same way — a catalogue beside the blocks (`BcmsBlocks({blocks, forms})`, the site renderer's\n * forms map) — and looks the id up in it. A hydrated `{formId, form}` prop value would be a shape\n * that exists nowhere in delivery.\n */\nexport interface ComponentFormPropRef {\n formId: string;\n}\n\nexport interface ComponentPropDef {\n key: string;\n label: string;\n target: { blockId: string; path: string };\n /**\n * `slot` holds ONE nested component instance — the component-level twin of the\n * content-model field type `component-ref` (see content-model.ts), named differently for\n * the same reason that one is: `component` already means a BLOCK type. Its value is\n * `{ componentId, overrides }` and its `target.path` is `props`, so filling a slot writes\n * that object over an empty `component` block's props.\n *\n * With `config.multiple` it holds a LIST of them and targets a container's child list\n * (`props.children` on a `section`, `props.columns.<n>` on a `columns`): the resolver writes\n * one `component` block per item there, so every renderer draws them as ordinary children.\n * @see slotItems\n *\n * On a PAGE a slot fill is a LIVE reference; a published ENTRY freezes it (resolveDeep).\n */\n /**\n * The EDITOR contract, not a storage one: `applyOverrides` writes the value at\n * `target.path` whatever its shape, so `type` decides which control the inspector renders\n * and what shape that control produces (FLO-1020).\n *\n * number → a number (heading.level, columns.count)\n * select → one string from `config.options`\n * group → an object keyed by `config.fields`\n * table → an array of such objects (slider.slides); with `config.mode: \"data\"` instead ONE\n * V2 `TableValue` (typed, keyed columns × keyed rows, table-value.ts), the value a\n * `table` FIELD stores. Aimed at a text or richtext block's `props.html` it renders\n * as the semantic HTML table. With `config.mode: \"types\"` a V2 polymorphic list: rows of\n * several item types (`config.itemTypes`), each row naming its type in `_type`.\n * link → an href string (URL, internal path or #fragment)\n * button → ONE `ButtonValue` (button-look.ts): label, href and look as a unit, never a text prop plus\n * a url prop that drift apart. Targets the `props` of a `button` block.\n * date → `YYYY-MM-DD`\n * color → a hex colour (`#RGB`, `#RRGGBB`, `#RRGGBBAA`)\n * file → `{ url, name?, size? }`, or a bare URL string\n * icon → a BetterCMS icon name (`DOCK_ICON_NAMES`), or an uploaded icon as an image value\n * multiselect → a `string[]`, each one of `config.options`\n * object → ONE `{ [childKey]: value }` keyed by `config.fields` (the V2 model-field `object`)\n * datetime · slug · email · phone · json · location → what the same-named model FIELD stores\n * tags · rating · code → what the same-named model FIELD stores (a string[], a number,\n * `{ language?, code }` or a string)\n * reference · multi-reference → what the same-named model FIELD stores: an entry id, or a\n * list of them (`config.contentModelId`, or `polymorphic` + `allowedModelSlugs`;\n * `min`/`max` on the list). Delivery and preview hydrate the ids in a page's overrides\n * to entries at the read's `depth`; a plain-text slot renders the entry's title.\n * video → a URL string or `{ url, poster?, autoplay?, loop?, transcript? }` (the video\n * block's props; aimed at a video block it lands as them) @see VideoValue\n * array → a list of `config.itemType` values: text, number, date, image, link or richtext\n * (the model field's primitive `array`; a list of objects is a `table`)\n * longtext → a multi-line string (the model field `longtext`; `text` is one line)\n */\n type: ComponentPropType;\n defaultValue?: unknown;\n /**\n * EDITOR HINTS (playbook §12). Stored in the props JSON, so no migration.\n *\n * 🔴 `required` IS NOT ENFORCED AT WRITE TIME, deliberately. Nothing on the write path\n * refuses an override that omits a required prop — a placement saves either way — because\n * the alternative is a component definition that can retroactively make already-saved pages\n * unsaveable. It is a marker the dashboard renders and `get_site_composition` counts, which\n * is the honest shape: the receipt names what is missing instead of the write refusing it.\n */\n required?: boolean;\n /** Hint shown under the control, muted. */\n helpText?: string;\n /** Server-owned: who wrote `helpText`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /** Ghost text inside a text-ish control. */\n placeholder?: string;\n /**\n * Editor-only conditional visibility: show this prop's control only while sibling props (by\n * key) hold these values. The save schema refuses a key no prop of the component declares.\n */\n showIf?: ShowIf;\n /** V2 editor-only keys, as on a model field. @see ContentModelField.helpMore */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /**\n * F1.x: a list prop's items (a table's rows) distinct; on a table sub-field, no two rows share\n * the value. Refused (`unique_prop_scope`) on a top-level scalar: nothing to be unique across.\n */\n unique?: boolean;\n /** `object` / `group` / `table`: how the value (or each row) opens when edited. */\n openMode?: OpenMode;\n /**\n * The content-model field's `readOnly` / `lockReason` pair, as STORED MARKERS only: the\n * editor may render the prop read-only, and no write of a prop value is refused for them.\n */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization (the locale chip): a stored marker, as on a model field. */\n localized?: boolean;\n /** Per-type settings; the save schema enforces that each is present on the type needing it. */\n config?: {\n /** `slot` — a pick allowlist. */\n componentIds?: string[];\n /** `slot` — the V2 `of.allow` block names it takes (`textBlock`), kept as written; the dock resolves them to components. */\n allow?: string[];\n /**\n * `array` — the V2 item field's own settings (`of[0]`): help under each item, the locale chip,\n * required, and a text / rich text item's length (a text item's pattern). Stored markers.\n */\n item?: { helpText?: string; localized?: boolean; required?: boolean; minLength?: number; maxLength?: number; pattern?: string; patternMessage?: string };\n /** `slot` — the value is a list of instances, not one. @see slotItems */\n multiple?: boolean;\n /** `slot` with `multiple` — bounds on the list. `maxItems` defaults to {@link SLOT_MAX_ITEMS}. */\n minItems?: number;\n maxItems?: number;\n /**\n * `slot` — per-child layout settings (V2 `slotSettings`, e.g. a bento span): what a V2 child's\n * `_settings` holds (`{ _key, _type, _settings, ...props }`, slot-child.ts). Leaf sub-fields.\n */\n slotSettings?: ComponentSubField[];\n /**\n * `table` with `mode: \"types\"` — a V2 polymorphic list: each row is ONE of these item types,\n * named by the row's `_type` (`{ _key?, _type, ...values }`), its values keyed by that type's `fields`.\n */\n itemTypes?: Array<{\n name: string;\n label?: string;\n fields: ComponentSubField[];\n /** How a row of this type reads collapsed: title/subtitle/media name THIS type's fields (dotted ok, e.g. `table.caption`). */\n preview?: { title?: string; subtitle?: string; media?: string; fallback?: string; icon?: DockIconName };\n /** The row icon for this type, a dock icon name. */\n icon?: DockIconName;\n }>;\n /**\n * `select` / `multiselect` — the choices. Required, and a default must be one of them. `{ label, value }`\n * when the stored value is not what an author should read (a component id, for instance).\n */\n options?: Array<string | ChoiceOption>;\n /** `group` / `table` / `object` — the sub-shape; 10 levels at most, counting the prop (MAX_FIELD_DEPTH). */\n fields?: ComponentSubField[];\n /**\n * `table` — which value it holds: `\"rows\"` (the default, an array of `fields` rows) or\n * `\"data\"` (one V2 TableValue, with the table field's options beside it: columnTypes,\n * lockColumns, minRows, maxRows, maxColumns, requireCaption, …). A data table has no `fields`.\n */\n mode?: \"rows\" | \"data\" | \"types\";\n /** `number` — bounds for the control; `multiselect` / `tags` / `multi-reference` — how many items. */\n min?: number;\n max?: number;\n step?: number;\n /** `number` — V2 `validation.min / max`: the error bounds, which win over `min` / `max`. */\n validation?: { min?: number; max?: number };\n /** `text` / `url` / `richtext` — length in characters (richtext: its plain text). */\n minLength?: number;\n maxLength?: number;\n /** `text` / `url` — a regex (≤ 200 characters) and the message shown when it does not match. */\n pattern?: string;\n patternMessage?: string;\n /** `reference` / `multi-reference` — the target model, or `polymorphic` with an allowlist of model slugs. */\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n } & Record<string, unknown>;\n /**\n * AUTHORING CHROME — the same object a content-model FIELD carries ({@link ContentModelFieldUi}),\n * deliberately: an agent that has learned `ui` once has learned it on both lanes.\n *\n * A SIBLING of `config`, not a member of it. `config` is a loose bag, so a `config.ui` already\n * survived the write — and that is the problem this key fixes: surviving is not declared, and\n * an undeclared prop is a typo that saves cleanly and renders as nothing.\n *\n * WHERE EACH KEY IS LEGAL differs from the field lane, because the vocabulary does:\n * `preview`/`layout` on `group`, `table` and `slot`; `reorderable` on `table` ALONE, the only\n * prop type whose value is a list. The save schema refuses the rest with the valid set named.\n */\n ui?: ComponentPropUi;\n /** Server-owned provenance of this prop's chrome. @see UiOrigin */\n uiOrigin?: UiOrigin;\n /** Server-owned revert point. @see UiBefore */\n uiBefore?: UiBefore;\n /** `true`: no placement the last release inspected renders this prop — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n}\n\n/**\n * A top-level prop's dock group. Props have no fieldsets column, so the group rides inline: the\n * first prop to carry an `id` defines it (label, kind, icon, collapsed), later props name `{id}`.\n */\nexport interface PropGroup {\n id: string;\n /** 1–32 chars. Required on the defining prop. */\n label?: string;\n kind?: Exclude<FieldsetKind, \"tab\">;\n icon?: DockIconName;\n collapsed?: boolean;\n /** V2 fieldset keys (CPO D45), on the defining prop: a line under the header (≤200), members side by side, a static header, a breakpoint switcher, and its place among the groups (0–99; absent = where its first prop sits). */\n description?: string;\n columns?: 1 | 2;\n collapsible?: boolean;\n layout?: \"stack\" | \"breakpoints\";\n order?: number;\n}\n\n/**\n * A top-level prop's dock tab (V2 kit schema `groups`: Content | Design | Media | Settings | …).\n * Define-once like {@link PropGroup}: the first prop naming an `id` sets label/icon/order, later\n * props name `{ id }`. At most 8 tabs; never on a sub-field; one group's members share one tab.\n */\nexport interface PropTab {\n id: string;\n /** 1–40 chars, unique per component (case-insensitive). Required on the defining prop. */\n label?: string;\n icon?: DockIconName;\n /** 0–99; the tab's place among the tabs (absent = where its first prop sits). */\n order?: number;\n}\n\n/** A prop's `ui`: the field-lane chrome plus its inline {@link PropGroup} and {@link PropTab}. */\nexport type ComponentPropUi = ContentModelFieldUi & { group?: PropGroup; tab?: PropTab };\n\n/** One field inside a `group` / `object` prop or a `table` row. Recursive, 10 levels at most counting the prop (MAX_FIELD_DEPTH). */\nexport interface ComponentSubField {\n key: string;\n label: string;\n /**\n * No `form`: a form in a table row would mean N form documents per component with no way to\n * author them — the second field model this design exists to avoid. A `slot` sub-field IS\n * accepted by the API (V2 kit entries: an instance in an object or a row, `{ componentId,\n * overrides? }` at its key, the slot prop's config keys), and the `packages/db` schema mirror widened with it.\n */\n type: Exclude<ComponentPropDef[\"type\"], \"form\">;\n defaultValue?: unknown;\n /** The same editor hints as the prop above, one level down. @see ComponentPropDef */\n required?: boolean;\n helpText?: string;\n helpSource?: \"auto\" | \"human\" | \"agent\";\n placeholder?: string;\n options?: Array<string | ChoiceOption>;\n /** The V2 editor keys, one level down. `showIf` names SIBLING sub-fields. @see ComponentPropDef */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** On a table's sub-field: no two rows share the value; on a list: no item repeats. */\n unique?: boolean;\n openMode?: OpenMode;\n showIf?: ShowIf;\n /** The prop's `ui`, inline group included: V2 fieldsets nest, so sub-fields group too. */\n ui?: ComponentPropUi;\n /** V2 sub-field read-only / developer lock: stored markers, as on the prop. `\"developer\"` needs a lockReason. */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization: a stored marker, as on the prop. */\n localized?: boolean;\n /** CANONICAL. A nested `group`/`table`/`object`'s own sub-shape. */\n fields?: ComponentSubField[];\n /**\n * A READ-ONLY MIRROR of `options`/`fields`, in the shape `ComponentPropDef` puts them in.\n *\n * 🔴 WHY A SECOND COPY EXISTS AT ALL. A `group`/`table` PROP declares its sub-shape under\n * `config.fields`; a sub-field of one declares its own under a bare `fields`. So a consumer\n * walking a nested table has to switch shape after the first level, and the componentize lane's\n * repo half (`@bettercms-ai/convert --componentize`) walks exactly that — it reads one node\n * shape at every depth. Mirroring the sub-shape here lets it, without the CMS having to\n * describe a nested table differently from a top-level one.\n *\n * `fields` is the authority. The save schema REFUSES a node whose mirror disagrees with it\n * (`componentPropDefSchema`), because two copies that may drift are worse than one awkward\n * shape — an editor that rewrote `fields` alone would leave a stale row description behind.\n */\n config?: { fields?: ComponentSubField[]; options?: Array<string | ChoiceOption> } & Record<string, unknown>;\n}\n\n/** The value a `slot` prop holds — the draft half of a `component-ref`, deliberately. */\nexport interface SlotValue {\n componentId: string;\n overrides?: Record<string, unknown>;\n}\n\n/**\n * One child of a `multiple` slot: a {@link SlotValue} that may also carry the two placement keys a\n * `component` block has. The child block is built with them, so it hides per breakpoint and\n * shows inside its window exactly as a block placed by hand does.\n */\nexport interface SlotItem extends SlotValue {\n style?: BlockStyle;\n window?: VisibilityWindow;\n}\n\n/** How many children a `multiple` slot holds when its prop sets no `config.maxItems`. */\nexport const SLOT_MAX_ITEMS = 12;\n/** The most `config.maxItems` may ask for: one placement never expands into more blocks than this. */\nexport const SLOT_ITEMS_CAP = 50;\n/** The most a `table` prop's rows or an `array` prop's items may be bounded to (`config.maxItems`). */\nexport const LIST_ITEMS_CAP = 500;\n\n/**\n * A slot value as a list of its instances, whichever shape it was stored in: `[]` for nothing,\n * one item for a single `{ componentId, overrides }`, the array's own items for a `multiple`\n * slot. An item with no `componentId` names no component and is left out.\n *\n * THE one reading of a slot value. A walker that tests `value.componentId` alone sees a\n * `multiple` slot as empty, and for a \"where used\" answer or a delete guard that is a component\n * removed from under the pages that hold it.\n */\nexport function slotItems(value: unknown): SlotItem[] {\n const list = Array.isArray(value) ? value : [value];\n const out: SlotItem[] = [];\n for (const item of list) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const o = item as Record<string, unknown>;\n if (typeof o.componentId === \"string\" && o.componentId !== \"\") out.push(item as SlotItem);\n // A V2 slot child (`{ _key, _type, ...props }`, slot-child.ts): `_type` is the component id and\n // the child ITSELF is the overrides, so a walker that writes into them writes into the stored\n // value. applyOverrides reads declared prop keys only; the `_` keys are never a prop's.\n else if (typeof o.componentId !== \"string\" && typeof o._type === \"string\" && o._type !== \"\") out.push({ componentId: o._type, overrides: o });\n }\n return out;\n}\n\n/**\n * A component is a DRAFT until published; only the published copy reaches a visitor.\n * Mirrors pages and entries. See migration 0186_component_draft_live_split.sql.\n */\nexport type ComponentStatus = \"draft\" | \"published\";\n\n/**\n * Archive state (FLO-1012), deliberately SEPARATE from `ComponentStatus`.\n *\n * Archive takes a component out of the working set — hidden from the components list by\n * default, not offered in the visual editor's insert surfaces — while every existing usage\n * keeps serving. It is not unpublish (which pulls the live copy and re-bakes every page that\n * embeds it) and it is not delete.\n *\n * It is a timestamp rather than a third `status` value because a component can be published\n * AND archived; collapsing the two would lose the bit restore has to put back.\n */\n\n/**\n * How ONE instance of a component reads as a ROW in a parent's slot list (\"Open Rosa Delgado,\n * 2 of 5\"): the V2 /kit schema's document-level `preview`. `title`, `subtitle` and `media` each\n * name a TOP-LEVEL prop key, or a dotted path into one (`slides.0.heading`; the API refuses any\n * other with `preview_key_unknown`); `fallback` is\n * the literal row label while the title prop is empty; `icon` the row's icon while it has no media.\n * Draft-only authoring chrome: never part of the publish snapshot.\n */\nexport interface ComponentPreview {\n title?: string;\n subtitle?: string;\n media?: string;\n fallback?: string;\n icon?: DockIconName;\n}\n\n/**\n * A V2 /kit schema tab (a `groups` entry) NO top-level prop sits in, declared on the component so\n * the schema round-trips: V2 hides a tab with no visible top-level field, and so does the dock. A\n * tab a prop sits in is defined on that prop (`ui.tab`). `order` places it among all the tabs.\n */\nexport interface ComponentTab {\n id: string;\n label: string;\n icon?: DockIconName;\n order?: number;\n}\n\nexport interface Component {\n id: string;\n workspaceId: string;\n projectId?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n /**\n * Section library: the family this component is a LAYOUT of, e.g. \"Hero\". `name` is the\n * layout label (\"Centered\"), so components sharing a sectionType are selectable variants\n * of one section. Null/absent = an ordinary component, not shown in the section library.\n */\n sectionType?: string | null;\n /** First-class variant family membership; exact workspace/project scope is enforced in DB. */\n variantGroupId?: string | null;\n variantInputMappings?: VariantInputMapping[];\n /** Placement governance: `*`, `slug:<page-slug>`, and/or `type:<page-type>`. */\n allowedOn: string[];\n description?: string | null;\n /** The DRAFT definition. Every builder/autosave/import write path targets these two. */\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n /** How an instance reads as a row in a parent's slot list. Null/absent = unset. @see ComponentPreview */\n preview?: ComponentPreview | null;\n /** The block icon (a /kit schema's document-level `icon`): root crumb, slot rows, slot child frames. Null/absent = unset. */\n icon?: DockIconName | null;\n /** Declared tabs no top-level prop sits in. Null/absent = none. @see ComponentTab */\n tabs?: ComponentTab[] | null;\n /** The bettercms://kit entry its V2 dock UI was built from (a kit-catalog id). Null/absent = none named. */\n kitEntry?: string | null;\n status: ComponentStatus;\n /** When it left the working set, or null/absent while active. @see ComponentStatus */\n archivedAt?: string | Date | null;\n /** Derived from `archivedAt`, so a client never has to know the column. */\n archived?: boolean;\n /**\n * The LIVE snapshot get_components_by_handle() serves. Null until the first publish.\n * Returned by GET-one (the Compare view needs it), omitted from list rows for payload.\n */\n publishedBlockJson?: ContentBlock[] | null;\n publishedProps?: ComponentPropDef[] | null;\n publishedAt?: string | null; // ISO 8601\n /**\n * Computed in SQL on list/get, never stored:\n * status='published' AND (blockJson or props has diverged from its published copy).\n * An exact jsonb compare, so it self-clears when an edit is reverted.\n */\n pendingChanges?: boolean;\n thumbnail?: string | null;\n createdAt: string; // ISO 8601\n updatedAt: string; // ISO 8601\n}\n\n/**\n * Public/delivery projection — the fields a renderer needs to resolve instances.\n *\n * DELIBERATELY UNCHANGED by the 0186 draft/live split: delivery aliases\n * publishedBlockJson -> blockJson, so every already-deployed site and every\n * bcms-content.json on disk keeps a byte-identical wire shape. Do not add `status` here —\n * delivery only ever returns published rows, so it would always be the same constant.\n */\nexport interface DeliveryComponent {\n id: string;\n /** The project the component belongs to. */\n projectId?: string | null;\n /** The component's preview image in the editor's library, when it has one. */\n thumbnail?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n sectionType?: string | null;\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n}\n","/**\n * Generated from lucide-react@1.8.0 dynamic icon names.\n * Legacy CamelCase identifiers remain valid for existing Layout documents.\n */\nexport const LAYOUT_SECTION_ICONS: readonly string[] = Object.freeze([\n \"LayoutPanelTop\",\n \"PanelTop\",\n \"PanelBottom\",\n \"Menu\",\n \"Navigation\",\n \"Megaphone\",\n \"GalleryHorizontal\",\n \"Rows3\",\n \"Grid2X2\",\n \"FileText\",\n \"Link\",\n \"Contact\",\n \"BadgeInfo\",\n \"Sparkles\",\n \"a-arrow-down\",\n \"a-arrow-up\",\n \"a-large-small\",\n \"accessibility\",\n \"activity\",\n \"air-vent\",\n \"airplay\",\n \"alarm-clock-check\",\n \"alarm-check\",\n \"alarm-clock-minus\",\n \"alarm-minus\",\n \"alarm-clock-off\",\n \"alarm-clock-plus\",\n \"alarm-plus\",\n \"alarm-clock\",\n \"alarm-smoke\",\n \"album\",\n \"align-center-horizontal\",\n \"align-center-vertical\",\n \"align-end-horizontal\",\n \"align-end-vertical\",\n \"align-horizontal-distribute-center\",\n \"align-horizontal-distribute-end\",\n \"align-horizontal-distribute-start\",\n \"align-horizontal-justify-center\",\n \"align-horizontal-justify-end\",\n \"align-horizontal-justify-start\",\n \"align-horizontal-space-around\",\n \"align-horizontal-space-between\",\n \"align-start-horizontal\",\n \"align-start-vertical\",\n \"align-vertical-distribute-center\",\n \"align-vertical-distribute-end\",\n \"align-vertical-distribute-start\",\n \"align-vertical-justify-center\",\n \"align-vertical-justify-end\",\n \"align-vertical-justify-start\",\n \"align-vertical-space-around\",\n \"align-vertical-space-between\",\n \"ambulance\",\n \"ampersand\",\n \"ampersands\",\n \"amphora\",\n \"anchor\",\n \"angry\",\n \"annoyed\",\n \"antenna\",\n \"anvil\",\n \"aperture\",\n \"app-window-mac\",\n \"app-window\",\n \"apple\",\n \"archive-restore\",\n \"archive-x\",\n \"archive\",\n \"armchair\",\n \"arrow-big-down-dash\",\n \"arrow-big-down\",\n \"arrow-big-left-dash\",\n \"arrow-big-left\",\n \"arrow-big-right-dash\",\n \"arrow-big-right\",\n \"arrow-big-up-dash\",\n \"arrow-big-up\",\n \"arrow-down-0-1\",\n \"arrow-down-01\",\n \"arrow-down-1-0\",\n \"arrow-down-10\",\n \"arrow-down-a-z\",\n \"arrow-down-az\",\n \"arrow-down-from-line\",\n \"arrow-down-left\",\n \"arrow-down-narrow-wide\",\n \"arrow-down-right\",\n \"arrow-down-to-dot\",\n \"arrow-down-to-line\",\n \"arrow-down-up\",\n \"arrow-down-wide-narrow\",\n \"sort-desc\",\n \"arrow-down-z-a\",\n \"arrow-down-za\",\n \"arrow-down\",\n \"arrow-left-from-line\",\n \"arrow-left-right\",\n \"arrow-left-to-line\",\n \"arrow-left\",\n \"arrow-right-from-line\",\n \"arrow-right-left\",\n \"arrow-right-to-line\",\n \"arrow-right\",\n \"arrow-up-0-1\",\n \"arrow-up-01\",\n \"arrow-up-1-0\",\n \"arrow-up-10\",\n \"arrow-up-a-z\",\n \"arrow-up-az\",\n \"arrow-up-down\",\n \"arrow-up-from-dot\",\n \"arrow-up-from-line\",\n \"arrow-up-left\",\n \"arrow-up-narrow-wide\",\n \"sort-asc\",\n \"arrow-up-right\",\n \"arrow-up-to-line\",\n \"arrow-up-wide-narrow\",\n \"arrow-up-z-a\",\n \"arrow-up-za\",\n \"arrow-up\",\n \"arrows-up-from-line\",\n \"asterisk\",\n \"at-sign\",\n \"atom\",\n \"audio-lines\",\n \"audio-waveform\",\n \"award\",\n \"axe\",\n \"axis-3d\",\n \"axis-3-d\",\n \"baby\",\n \"backpack\",\n \"badge-alert\",\n \"badge-cent\",\n \"badge-check\",\n \"verified\",\n \"badge-dollar-sign\",\n \"badge-euro\",\n \"badge-indian-rupee\",\n \"badge-info\",\n \"badge-japanese-yen\",\n \"badge-minus\",\n \"badge-percent\",\n \"badge-plus\",\n \"badge-pound-sterling\",\n \"badge-question-mark\",\n \"badge-help\",\n \"badge-russian-ruble\",\n \"badge-swiss-franc\",\n \"badge-turkish-lira\",\n \"badge-x\",\n \"badge\",\n \"baggage-claim\",\n \"balloon\",\n \"ban\",\n \"banana\",\n \"bandage\",\n \"banknote-arrow-down\",\n \"banknote-arrow-up\",\n \"banknote-x\",\n \"banknote\",\n \"barcode\",\n \"barrel\",\n \"baseline\",\n \"bath\",\n \"battery-charging\",\n \"battery-full\",\n \"battery-low\",\n \"battery-medium\",\n \"battery-plus\",\n \"battery-warning\",\n \"battery\",\n \"beaker\",\n \"bean-off\",\n \"bean\",\n \"bed-double\",\n \"bed-single\",\n \"bed\",\n \"beef-off\",\n \"beef\",\n \"beer-off\",\n \"beer\",\n \"bell-dot\",\n \"bell-electric\",\n \"bell-minus\",\n \"bell-off\",\n \"bell-plus\",\n \"bell-ring\",\n \"bell\",\n \"between-horizontal-end\",\n \"between-horizonal-end\",\n \"between-horizontal-start\",\n \"between-horizonal-start\",\n \"between-vertical-end\",\n \"between-vertical-start\",\n \"biceps-flexed\",\n \"bike\",\n \"binary\",\n \"binoculars\",\n \"biohazard\",\n \"bird\",\n \"birdhouse\",\n \"bitcoin\",\n \"blend\",\n \"blinds\",\n \"blocks\",\n \"bluetooth-connected\",\n \"bluetooth-off\",\n \"bluetooth-searching\",\n \"bluetooth\",\n \"bold\",\n \"bolt\",\n \"bomb\",\n \"bone\",\n \"book-a\",\n \"book-alert\",\n \"book-audio\",\n \"book-check\",\n \"book-copy\",\n \"book-dashed\",\n \"book-template\",\n \"book-down\",\n \"book-headphones\",\n \"book-heart\",\n \"book-image\",\n \"book-key\",\n \"book-lock\",\n \"book-marked\",\n \"book-minus\",\n \"book-open-check\",\n \"book-open-text\",\n \"book-open\",\n \"book-plus\",\n \"book-search\",\n \"book-text\",\n \"book-type\",\n \"book-up-2\",\n \"book-up\",\n \"book-user\",\n \"book-x\",\n \"book\",\n \"bookmark-check\",\n \"bookmark-minus\",\n \"bookmark-off\",\n \"bookmark-plus\",\n \"bookmark-x\",\n \"bookmark\",\n \"boom-box\",\n \"bot-message-square\",\n \"bot-off\",\n \"bot\",\n \"bottle-wine\",\n \"bow-arrow\",\n \"box\",\n \"boxes\",\n \"braces\",\n \"curly-braces\",\n \"brackets\",\n \"brain-circuit\",\n \"brain-cog\",\n \"brain\",\n \"brick-wall-fire\",\n \"brick-wall-shield\",\n \"brick-wall\",\n \"briefcase-business\",\n \"briefcase-conveyor-belt\",\n \"briefcase-medical\",\n \"briefcase\",\n \"bring-to-front\",\n \"brush-cleaning\",\n \"brush\",\n \"bubbles\",\n \"bug-off\",\n \"bug-play\",\n \"bug\",\n \"building-2\",\n \"building\",\n \"bus-front\",\n \"bus\",\n \"cable-car\",\n \"cable\",\n \"cake-slice\",\n \"cake\",\n \"calculator\",\n \"calendar-1\",\n \"calendar-arrow-down\",\n \"calendar-arrow-up\",\n \"calendar-check-2\",\n \"calendar-check\",\n \"calendar-clock\",\n \"calendar-cog\",\n \"calendar-days\",\n \"calendar-fold\",\n \"calendar-heart\",\n \"calendar-minus-2\",\n \"calendar-minus\",\n \"calendar-off\",\n \"calendar-plus-2\",\n \"calendar-plus\",\n \"calendar-range\",\n \"calendar-search\",\n \"calendar-sync\",\n \"calendar-x-2\",\n \"calendar-x\",\n \"calendar\",\n \"calendars\",\n \"camera-off\",\n \"camera\",\n \"candy-cane\",\n \"candy-off\",\n \"candy\",\n \"cannabis-off\",\n \"cannabis\",\n \"captions-off\",\n \"captions\",\n \"subtitles\",\n \"car-front\",\n \"car-taxi-front\",\n \"car\",\n \"caravan\",\n \"card-sim\",\n \"carrot\",\n \"case-lower\",\n \"case-sensitive\",\n \"case-upper\",\n \"cassette-tape\",\n \"cast\",\n \"castle\",\n \"cat\",\n \"cctv-off\",\n \"cctv\",\n \"chart-area\",\n \"area-chart\",\n \"chart-bar-big\",\n \"bar-chart-horizontal-big\",\n \"chart-bar-decreasing\",\n \"chart-bar-increasing\",\n \"chart-bar-stacked\",\n \"chart-bar\",\n \"bar-chart-horizontal\",\n \"chart-candlestick\",\n \"candlestick-chart\",\n \"chart-column-big\",\n \"bar-chart-big\",\n \"chart-column-decreasing\",\n \"chart-column-increasing\",\n \"bar-chart-4\",\n \"chart-column-stacked\",\n \"chart-column\",\n \"bar-chart-3\",\n \"chart-gantt\",\n \"chart-line\",\n \"line-chart\",\n \"chart-network\",\n \"chart-no-axes-column-decreasing\",\n \"chart-no-axes-column-increasing\",\n \"bar-chart\",\n \"chart-no-axes-column\",\n \"bar-chart-2\",\n \"chart-no-axes-combined\",\n \"chart-no-axes-gantt\",\n \"gantt-chart\",\n \"chart-pie\",\n \"pie-chart\",\n \"chart-scatter\",\n \"scatter-chart\",\n \"chart-spline\",\n \"check-check\",\n \"check-line\",\n \"check\",\n \"chef-hat\",\n \"cherry\",\n \"chess-bishop\",\n \"chess-king\",\n \"chess-knight\",\n \"chess-pawn\",\n \"chess-queen\",\n \"chess-rook\",\n \"chevron-down\",\n \"chevron-first\",\n \"chevron-last\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-down-up\",\n \"chevrons-down\",\n \"chevrons-left-right-ellipsis\",\n \"chevrons-left-right\",\n \"chevrons-left\",\n \"chevrons-right-left\",\n \"chevrons-right\",\n \"chevrons-up-down\",\n \"chevrons-up\",\n \"church\",\n \"cigarette-off\",\n \"cigarette\",\n \"circle-alert\",\n \"alert-circle\",\n \"circle-arrow-down\",\n \"arrow-down-circle\",\n \"circle-arrow-left\",\n \"arrow-left-circle\",\n \"circle-arrow-out-down-left\",\n \"arrow-down-left-from-circle\",\n \"circle-arrow-out-down-right\",\n \"arrow-down-right-from-circle\",\n \"circle-arrow-out-up-left\",\n \"arrow-up-left-from-circle\",\n \"circle-arrow-out-up-right\",\n \"arrow-up-right-from-circle\",\n \"circle-arrow-right\",\n \"arrow-right-circle\",\n \"circle-arrow-up\",\n \"arrow-up-circle\",\n \"circle-check-big\",\n \"check-circle\",\n \"circle-check\",\n \"check-circle-2\",\n \"circle-chevron-down\",\n \"chevron-down-circle\",\n \"circle-chevron-left\",\n \"chevron-left-circle\",\n \"circle-chevron-right\",\n \"chevron-right-circle\",\n \"circle-chevron-up\",\n \"chevron-up-circle\",\n \"circle-dashed\",\n \"circle-divide\",\n \"divide-circle\",\n \"circle-dollar-sign\",\n \"circle-dot-dashed\",\n \"circle-dot\",\n \"circle-ellipsis\",\n \"circle-equal\",\n \"circle-fading-arrow-up\",\n \"circle-fading-plus\",\n \"circle-gauge\",\n \"gauge-circle\",\n \"circle-minus\",\n \"minus-circle\",\n \"circle-off\",\n \"circle-parking-off\",\n \"parking-circle-off\",\n \"circle-parking\",\n \"parking-circle\",\n \"circle-pause\",\n \"pause-circle\",\n \"circle-percent\",\n \"percent-circle\",\n \"circle-pile\",\n \"circle-play\",\n \"play-circle\",\n \"circle-plus\",\n \"plus-circle\",\n \"circle-pound-sterling\",\n \"circle-power\",\n \"power-circle\",\n \"circle-question-mark\",\n \"help-circle\",\n \"circle-help\",\n \"circle-slash-2\",\n \"circle-slashed\",\n \"circle-slash\",\n \"circle-small\",\n \"circle-star\",\n \"circle-stop\",\n \"stop-circle\",\n \"circle-user-round\",\n \"user-circle-2\",\n \"circle-user\",\n \"user-circle\",\n \"circle-x\",\n \"x-circle\",\n \"circle\",\n \"circuit-board\",\n \"citrus\",\n \"clapperboard\",\n \"clipboard-check\",\n \"clipboard-clock\",\n \"clipboard-copy\",\n \"clipboard-list\",\n \"clipboard-minus\",\n \"clipboard-paste\",\n \"clipboard-pen-line\",\n \"clipboard-signature\",\n \"clipboard-pen\",\n \"clipboard-edit\",\n \"clipboard-plus\",\n \"clipboard-type\",\n \"clipboard-x\",\n \"clipboard\",\n \"clock-1\",\n \"clock-10\",\n \"clock-11\",\n \"clock-12\",\n \"clock-2\",\n \"clock-3\",\n \"clock-4\",\n \"clock-5\",\n \"clock-6\",\n \"clock-7\",\n \"clock-8\",\n \"clock-9\",\n \"clock-alert\",\n \"clock-arrow-down\",\n \"clock-arrow-up\",\n \"clock-check\",\n \"clock-fading\",\n \"clock-plus\",\n \"clock\",\n \"closed-caption\",\n \"cloud-alert\",\n \"cloud-backup\",\n \"cloud-check\",\n \"cloud-cog\",\n \"cloud-download\",\n \"download-cloud\",\n \"cloud-drizzle\",\n \"cloud-fog\",\n \"cloud-hail\",\n \"cloud-lightning\",\n \"cloud-moon-rain\",\n \"cloud-moon\",\n \"cloud-off\",\n \"cloud-rain-wind\",\n \"cloud-rain\",\n \"cloud-snow\",\n \"cloud-sun-rain\",\n \"cloud-sun\",\n \"cloud-sync\",\n \"cloud-upload\",\n \"upload-cloud\",\n \"cloud\",\n \"cloudy\",\n \"clover\",\n \"club\",\n \"code-xml\",\n \"code-2\",\n \"code\",\n \"coffee\",\n \"cog\",\n \"coins\",\n \"columns-2\",\n \"columns\",\n \"columns-3-cog\",\n \"columns-settings\",\n \"table-config\",\n \"columns-3\",\n \"panels-left-right\",\n \"columns-4\",\n \"combine\",\n \"command\",\n \"compass\",\n \"component\",\n \"computer\",\n \"concierge-bell\",\n \"cone\",\n \"construction\",\n \"contact-round\",\n \"contact-2\",\n \"contact\",\n \"container\",\n \"contrast\",\n \"cookie\",\n \"cooking-pot\",\n \"copy-check\",\n \"copy-minus\",\n \"copy-plus\",\n \"copy-slash\",\n \"copy-x\",\n \"copy\",\n \"copyleft\",\n \"copyright\",\n \"corner-down-left\",\n \"corner-down-right\",\n \"corner-left-down\",\n \"corner-left-up\",\n \"corner-right-down\",\n \"corner-right-up\",\n \"corner-up-left\",\n \"corner-up-right\",\n \"cpu\",\n \"creative-commons\",\n \"credit-card\",\n \"croissant\",\n \"crop\",\n \"cross\",\n \"crosshair\",\n \"crown\",\n \"cuboid\",\n \"cup-soda\",\n \"currency\",\n \"cylinder\",\n \"dam\",\n \"database-backup\",\n \"database-search\",\n \"database-zap\",\n \"database\",\n \"decimals-arrow-left\",\n \"decimals-arrow-right\",\n \"delete\",\n \"dessert\",\n \"diameter\",\n \"diamond-minus\",\n \"diamond-percent\",\n \"percent-diamond\",\n \"diamond-plus\",\n \"diamond\",\n \"dice-1\",\n \"dice-2\",\n \"dice-3\",\n \"dice-4\",\n \"dice-5\",\n \"dice-6\",\n \"dices\",\n \"diff\",\n \"disc-2\",\n \"disc-3\",\n \"disc-album\",\n \"disc\",\n \"divide\",\n \"dna-off\",\n \"dna\",\n \"dock\",\n \"dog\",\n \"dollar-sign\",\n \"donut\",\n \"door-closed-locked\",\n \"door-closed\",\n \"door-open\",\n \"dot\",\n \"download\",\n \"drafting-compass\",\n \"drama\",\n \"drill\",\n \"drone\",\n \"droplet-off\",\n \"droplet\",\n \"droplets\",\n \"drum\",\n \"drumstick\",\n \"dumbbell\",\n \"ear-off\",\n \"ear\",\n \"earth-lock\",\n \"earth\",\n \"globe-2\",\n \"eclipse\",\n \"egg-fried\",\n \"egg-off\",\n \"egg\",\n \"ellipse\",\n \"ellipsis-vertical\",\n \"more-vertical\",\n \"ellipsis\",\n \"more-horizontal\",\n \"equal-approximately\",\n \"equal-not\",\n \"equal\",\n \"eraser\",\n \"ethernet-port\",\n \"euro\",\n \"ev-charger\",\n \"expand\",\n \"external-link\",\n \"eye-closed\",\n \"eye-off\",\n \"eye\",\n \"factory\",\n \"fan\",\n \"fast-forward\",\n \"feather\",\n \"fence\",\n \"ferris-wheel\",\n \"file-archive\",\n \"file-axis-3d\",\n \"file-axis-3-d\",\n \"file-badge\",\n \"file-badge-2\",\n \"file-box\",\n \"file-braces-corner\",\n \"file-json-2\",\n \"file-braces\",\n \"file-json\",\n \"file-chart-column-increasing\",\n \"file-bar-chart\",\n \"file-chart-column\",\n \"file-bar-chart-2\",\n \"file-chart-line\",\n \"file-line-chart\",\n \"file-chart-pie\",\n \"file-pie-chart\",\n \"file-check-corner\",\n \"file-check-2\",\n \"file-check\",\n \"file-clock\",\n \"file-code-corner\",\n \"file-code-2\",\n \"file-code\",\n \"file-cog\",\n \"file-cog-2\",\n \"file-diff\",\n \"file-digit\",\n \"file-down\",\n \"file-exclamation-point\",\n \"file-warning\",\n \"file-headphone\",\n \"file-audio\",\n \"file-audio-2\",\n \"file-heart\",\n \"file-image\",\n \"file-input\",\n \"file-key\",\n \"file-key-2\",\n \"file-lock\",\n \"file-lock-2\",\n \"file-minus-corner\",\n \"file-minus-2\",\n \"file-minus\",\n \"file-music\",\n \"file-output\",\n \"file-pen-line\",\n \"file-signature\",\n \"file-pen\",\n \"file-edit\",\n \"file-play\",\n \"file-video\",\n \"file-plus-corner\",\n \"file-plus-2\",\n \"file-plus\",\n \"file-question-mark\",\n \"file-question\",\n \"file-scan\",\n \"file-search-corner\",\n \"file-search-2\",\n \"file-search\",\n \"file-signal\",\n \"file-volume-2\",\n \"file-sliders\",\n \"file-spreadsheet\",\n \"file-stack\",\n \"file-symlink\",\n \"file-terminal\",\n \"file-text\",\n \"file-type-corner\",\n \"file-type-2\",\n \"file-type\",\n \"file-up\",\n \"file-user\",\n \"file-video-camera\",\n \"file-video-2\",\n \"file-volume\",\n \"file-x-corner\",\n \"file-x-2\",\n \"file-x\",\n \"file\",\n \"files\",\n \"film\",\n \"fingerprint-pattern\",\n \"fingerprint\",\n \"fire-extinguisher\",\n \"fish-off\",\n \"fish-symbol\",\n \"fish\",\n \"fishing-hook\",\n \"fishing-rod\",\n \"flag-off\",\n \"flag-triangle-left\",\n \"flag-triangle-right\",\n \"flag\",\n \"flame-kindling\",\n \"flame\",\n \"flashlight-off\",\n \"flashlight\",\n \"flask-conical-off\",\n \"flask-conical\",\n \"flask-round\",\n \"flip-horizontal-2\",\n \"flip-vertical-2\",\n \"flower-2\",\n \"flower\",\n \"focus\",\n \"fold-horizontal\",\n \"fold-vertical\",\n \"folder-archive\",\n \"folder-check\",\n \"folder-clock\",\n \"folder-closed\",\n \"folder-code\",\n \"folder-cog\",\n \"folder-cog-2\",\n \"folder-dot\",\n \"folder-down\",\n \"folder-git-2\",\n \"folder-git\",\n \"folder-heart\",\n \"folder-input\",\n \"folder-kanban\",\n \"folder-key\",\n \"folder-lock\",\n \"folder-minus\",\n \"folder-open-dot\",\n \"folder-open\",\n \"folder-output\",\n \"folder-pen\",\n \"folder-edit\",\n \"folder-plus\",\n \"folder-root\",\n \"folder-search-2\",\n \"folder-search\",\n \"folder-symlink\",\n \"folder-sync\",\n \"folder-tree\",\n \"folder-up\",\n \"folder-x\",\n \"folder\",\n \"folders\",\n \"footprints\",\n \"forklift\",\n \"form\",\n \"forward\",\n \"frame\",\n \"frown\",\n \"fuel\",\n \"fullscreen\",\n \"funnel-plus\",\n \"funnel-x\",\n \"filter-x\",\n \"funnel\",\n \"filter\",\n \"gallery-horizontal-end\",\n \"gallery-horizontal\",\n \"gallery-thumbnails\",\n \"gallery-vertical-end\",\n \"gallery-vertical\",\n \"gamepad-2\",\n \"gamepad-directional\",\n \"gamepad\",\n \"gauge\",\n \"gavel\",\n \"gem\",\n \"georgian-lari\",\n \"ghost\",\n \"gift\",\n \"git-branch-minus\",\n \"git-branch-plus\",\n \"git-branch\",\n \"git-commit-horizontal\",\n \"git-commit\",\n \"git-commit-vertical\",\n \"git-compare-arrows\",\n \"git-compare\",\n \"git-fork\",\n \"git-graph\",\n \"git-merge-conflict\",\n \"git-merge\",\n \"git-pull-request-arrow\",\n \"git-pull-request-closed\",\n \"git-pull-request-create-arrow\",\n \"git-pull-request-create\",\n \"git-pull-request-draft\",\n \"git-pull-request\",\n \"glass-water\",\n \"glasses\",\n \"globe-lock\",\n \"globe-off\",\n \"globe-x\",\n \"globe\",\n \"goal\",\n \"gpu\",\n \"graduation-cap\",\n \"grape\",\n \"grid-2x2-check\",\n \"grid-2-x-2-check\",\n \"grid-2x2-plus\",\n \"grid-2-x-2-plus\",\n \"grid-2x2-x\",\n \"grid-2-x-2-x\",\n \"grid-2x2\",\n \"grid-2-x-2\",\n \"grid-3x2\",\n \"grid-3x3\",\n \"grid\",\n \"grid-3-x-3\",\n \"grip-horizontal\",\n \"grip-vertical\",\n \"grip\",\n \"group\",\n \"guitar\",\n \"ham\",\n \"hamburger\",\n \"hammer\",\n \"hand-coins\",\n \"hand-fist\",\n \"hand-grab\",\n \"grab\",\n \"hand-heart\",\n \"hand-helping\",\n \"helping-hand\",\n \"hand-metal\",\n \"hand-platter\",\n \"hand\",\n \"handbag\",\n \"handshake\",\n \"hard-drive-download\",\n \"hard-drive-upload\",\n \"hard-drive\",\n \"hard-hat\",\n \"hash\",\n \"hat-glasses\",\n \"haze\",\n \"hd\",\n \"hdmi-port\",\n \"heading-1\",\n \"heading-2\",\n \"heading-3\",\n \"heading-4\",\n \"heading-5\",\n \"heading-6\",\n \"heading\",\n \"headphone-off\",\n \"headphones\",\n \"headset\",\n \"heart-crack\",\n \"heart-handshake\",\n \"heart-minus\",\n \"heart-off\",\n \"heart-plus\",\n \"heart-pulse\",\n \"heart\",\n \"heater\",\n \"helicopter\",\n \"hexagon\",\n \"highlighter\",\n \"history\",\n \"hop-off\",\n \"hop\",\n \"hospital\",\n \"hotel\",\n \"hourglass\",\n \"house-heart\",\n \"house-plug\",\n \"house-plus\",\n \"house-wifi\",\n \"house\",\n \"home\",\n \"ice-cream-bowl\",\n \"ice-cream-2\",\n \"ice-cream-cone\",\n \"ice-cream\",\n \"id-card-lanyard\",\n \"id-card\",\n \"image-down\",\n \"image-minus\",\n \"image-off\",\n \"image-play\",\n \"image-plus\",\n \"image-up\",\n \"image-upscale\",\n \"image\",\n \"images\",\n \"import\",\n \"inbox\",\n \"indian-rupee\",\n \"infinity\",\n \"info\",\n \"inspection-panel\",\n \"italic\",\n \"iteration-ccw\",\n \"iteration-cw\",\n \"japanese-yen\",\n \"joystick\",\n \"kanban\",\n \"kayak\",\n \"key-round\",\n \"key-square\",\n \"key\",\n \"keyboard-music\",\n \"keyboard-off\",\n \"keyboard\",\n \"lamp-ceiling\",\n \"lamp-desk\",\n \"lamp-floor\",\n \"lamp-wall-down\",\n \"lamp-wall-up\",\n \"lamp\",\n \"land-plot\",\n \"landmark\",\n \"languages\",\n \"laptop-minimal-check\",\n \"laptop-minimal\",\n \"laptop-2\",\n \"laptop\",\n \"lasso-select\",\n \"lasso\",\n \"laugh\",\n \"layers-2\",\n \"layers-plus\",\n \"layers\",\n \"layers-3\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-panel-left\",\n \"layout-panel-top\",\n \"layout-template\",\n \"leaf\",\n \"leafy-green\",\n \"lectern\",\n \"lens-concave\",\n \"lens-convex\",\n \"library-big\",\n \"library\",\n \"life-buoy\",\n \"ligature\",\n \"lightbulb-off\",\n \"lightbulb\",\n \"line-dot-right-horizontal\",\n \"line-squiggle\",\n \"line-style\",\n \"link-2-off\",\n \"link-2\",\n \"link\",\n \"list-check\",\n \"list-checks\",\n \"list-chevrons-down-up\",\n \"list-chevrons-up-down\",\n \"list-collapse\",\n \"list-end\",\n \"list-filter-plus\",\n \"list-filter\",\n \"list-indent-decrease\",\n \"outdent\",\n \"indent-decrease\",\n \"list-indent-increase\",\n \"indent\",\n \"indent-increase\",\n \"list-minus\",\n \"list-music\",\n \"list-ordered\",\n \"list-plus\",\n \"list-restart\",\n \"list-start\",\n \"list-todo\",\n \"list-tree\",\n \"list-video\",\n \"list-x\",\n \"list\",\n \"loader-circle\",\n \"loader-2\",\n \"loader-pinwheel\",\n \"loader\",\n \"locate-fixed\",\n \"locate-off\",\n \"locate\",\n \"lock-keyhole-open\",\n \"unlock-keyhole\",\n \"lock-keyhole\",\n \"lock-open\",\n \"unlock\",\n \"lock\",\n \"log-in\",\n \"log-out\",\n \"logs\",\n \"lollipop\",\n \"luggage\",\n \"magnet\",\n \"mail-check\",\n \"mail-minus\",\n \"mail-open\",\n \"mail-plus\",\n \"mail-question-mark\",\n \"mail-question\",\n \"mail-search\",\n \"mail-warning\",\n \"mail-x\",\n \"mail\",\n \"mailbox\",\n \"mails\",\n \"map-minus\",\n \"map-pin-check-inside\",\n \"map-pin-check\",\n \"map-pin-house\",\n \"map-pin-minus-inside\",\n \"map-pin-minus\",\n \"map-pin-off\",\n \"map-pin-pen\",\n \"location-edit\",\n \"map-pin-plus-inside\",\n \"map-pin-plus\",\n \"map-pin-search\",\n \"map-pin-x-inside\",\n \"map-pin-x\",\n \"map-pin\",\n \"map-pinned\",\n \"map-plus\",\n \"map\",\n \"mars-stroke\",\n \"mars\",\n \"martini\",\n \"maximize-2\",\n \"maximize\",\n \"medal\",\n \"megaphone-off\",\n \"megaphone\",\n \"meh\",\n \"memory-stick\",\n \"menu\",\n \"merge\",\n \"message-circle-check\",\n \"message-circle-code\",\n \"message-circle-dashed\",\n \"message-circle-heart\",\n \"message-circle-more\",\n \"message-circle-off\",\n \"message-circle-plus\",\n \"message-circle-question-mark\",\n \"message-circle-question\",\n \"message-circle-reply\",\n \"message-circle-warning\",\n \"message-circle-x\",\n \"message-circle\",\n \"message-square-check\",\n \"message-square-code\",\n \"message-square-dashed\",\n \"message-square-diff\",\n \"message-square-dot\",\n \"message-square-heart\",\n \"message-square-lock\",\n \"message-square-more\",\n \"message-square-off\",\n \"message-square-plus\",\n \"message-square-quote\",\n \"message-square-reply\",\n \"message-square-share\",\n \"message-square-text\",\n \"message-square-warning\",\n \"message-square-x\",\n \"message-square\",\n \"messages-square\",\n \"metronome\",\n \"mic-off\",\n \"mic-vocal\",\n \"mic-2\",\n \"mic\",\n \"microchip\",\n \"microscope\",\n \"microwave\",\n \"milestone\",\n \"milk-off\",\n \"milk\",\n \"minimize-2\",\n \"minimize\",\n \"minus\",\n \"mirror-rectangular\",\n \"mirror-round\",\n \"monitor-check\",\n \"monitor-cloud\",\n \"monitor-cog\",\n \"monitor-dot\",\n \"monitor-down\",\n \"monitor-off\",\n \"monitor-pause\",\n \"monitor-play\",\n \"monitor-smartphone\",\n \"monitor-speaker\",\n \"monitor-stop\",\n \"monitor-up\",\n \"monitor-x\",\n \"monitor\",\n \"moon-star\",\n \"moon\",\n \"motorbike\",\n \"mountain-snow\",\n \"mountain\",\n \"mouse-left\",\n \"mouse-off\",\n \"mouse-pointer-2-off\",\n \"mouse-pointer-2\",\n \"mouse-pointer-ban\",\n \"mouse-pointer-click\",\n \"mouse-pointer\",\n \"mouse-right\",\n \"mouse\",\n \"move-3d\",\n \"move-3-d\",\n \"move-diagonal-2\",\n \"move-diagonal\",\n \"move-down-left\",\n \"move-down-right\",\n \"move-down\",\n \"move-horizontal\",\n \"move-left\",\n \"move-right\",\n \"move-up-left\",\n \"move-up-right\",\n \"move-up\",\n \"move-vertical\",\n \"move\",\n \"music-2\",\n \"music-3\",\n \"music-4\",\n \"music\",\n \"navigation-2-off\",\n \"navigation-2\",\n \"navigation-off\",\n \"navigation\",\n \"network\",\n \"newspaper\",\n \"nfc\",\n \"non-binary\",\n \"notebook-pen\",\n \"notebook-tabs\",\n \"notebook-text\",\n \"notebook\",\n \"notepad-text-dashed\",\n \"notepad-text\",\n \"nut-off\",\n \"nut\",\n \"octagon-alert\",\n \"alert-octagon\",\n \"octagon-minus\",\n \"octagon-pause\",\n \"pause-octagon\",\n \"octagon-x\",\n \"x-octagon\",\n \"octagon\",\n \"omega\",\n \"option\",\n \"orbit\",\n \"origami\",\n \"package-2\",\n \"package-check\",\n \"package-minus\",\n \"package-open\",\n \"package-plus\",\n \"package-search\",\n \"package-x\",\n \"package\",\n \"paint-bucket\",\n \"paint-roller\",\n \"paintbrush-vertical\",\n \"paintbrush-2\",\n \"paintbrush\",\n \"palette\",\n \"panda\",\n \"panel-bottom-close\",\n \"panel-bottom-dashed\",\n \"panel-bottom-inactive\",\n \"panel-bottom-open\",\n \"panel-bottom\",\n \"panel-left-close\",\n \"sidebar-close\",\n \"panel-left-dashed\",\n \"panel-left-inactive\",\n \"panel-left-open\",\n \"sidebar-open\",\n \"panel-left-right-dashed\",\n \"panel-left\",\n \"sidebar\",\n \"panel-right-close\",\n \"panel-right-dashed\",\n \"panel-right-inactive\",\n \"panel-right-open\",\n \"panel-right\",\n \"panel-top-bottom-dashed\",\n \"panel-top-close\",\n \"panel-top-dashed\",\n \"panel-top-inactive\",\n \"panel-top-open\",\n \"panel-top\",\n \"panels-left-bottom\",\n \"panels-right-bottom\",\n \"panels-top-left\",\n \"layout\",\n \"paperclip\",\n \"parentheses\",\n \"parking-meter\",\n \"party-popper\",\n \"pause\",\n \"paw-print\",\n \"pc-case\",\n \"pen-line\",\n \"edit-3\",\n \"pen-off\",\n \"pen-tool\",\n \"pen\",\n \"edit-2\",\n \"pencil-line\",\n \"pencil-off\",\n \"pencil-ruler\",\n \"pencil\",\n \"pentagon\",\n \"percent\",\n \"person-standing\",\n \"philippine-peso\",\n \"phone-call\",\n \"phone-forwarded\",\n \"phone-incoming\",\n \"phone-missed\",\n \"phone-off\",\n \"phone-outgoing\",\n \"phone\",\n \"pi\",\n \"piano\",\n \"pickaxe\",\n \"picture-in-picture-2\",\n \"picture-in-picture\",\n \"piggy-bank\",\n \"pilcrow-left\",\n \"pilcrow-right\",\n \"pilcrow\",\n \"pill-bottle\",\n \"pill\",\n \"pin-off\",\n \"pin\",\n \"pipette\",\n \"pizza\",\n \"plane-landing\",\n \"plane-takeoff\",\n \"plane\",\n \"play\",\n \"plug-2\",\n \"plug-zap\",\n \"plug-zap-2\",\n \"plug\",\n \"plus\",\n \"pocket-knife\",\n \"podcast\",\n \"pointer-off\",\n \"pointer\",\n \"popcorn\",\n \"popsicle\",\n \"pound-sterling\",\n \"power-off\",\n \"power\",\n \"presentation\",\n \"printer-check\",\n \"printer-x\",\n \"printer\",\n \"projector\",\n \"proportions\",\n \"puzzle\",\n \"pyramid\",\n \"qr-code\",\n \"quote\",\n \"rabbit\",\n \"radar\",\n \"radiation\",\n \"radical\",\n \"radio-off\",\n \"radio-receiver\",\n \"radio-tower\",\n \"radio\",\n \"radius\",\n \"rainbow\",\n \"rat\",\n \"ratio\",\n \"receipt-cent\",\n \"receipt-euro\",\n \"receipt-indian-rupee\",\n \"receipt-japanese-yen\",\n \"receipt-pound-sterling\",\n \"receipt-russian-ruble\",\n \"receipt-swiss-franc\",\n \"receipt-text\",\n \"receipt-turkish-lira\",\n \"receipt\",\n \"rectangle-circle\",\n \"rectangle-ellipsis\",\n \"form-input\",\n \"rectangle-goggles\",\n \"rectangle-horizontal\",\n \"rectangle-vertical\",\n \"recycle\",\n \"redo-2\",\n \"redo-dot\",\n \"redo\",\n \"refresh-ccw-dot\",\n \"refresh-ccw\",\n \"refresh-cw-off\",\n \"refresh-cw\",\n \"refrigerator\",\n \"regex\",\n \"remove-formatting\",\n \"repeat-1\",\n \"repeat-2\",\n \"repeat\",\n \"replace-all\",\n \"replace\",\n \"reply-all\",\n \"reply\",\n \"rewind\",\n \"ribbon\",\n \"road\",\n \"rocket\",\n \"rocking-chair\",\n \"roller-coaster\",\n \"rose\",\n \"rotate-3d\",\n \"rotate-3-d\",\n \"rotate-ccw-key\",\n \"rotate-ccw-square\",\n \"rotate-ccw\",\n \"rotate-cw-square\",\n \"rotate-cw\",\n \"route-off\",\n \"route\",\n \"router\",\n \"rows-2\",\n \"rows\",\n \"rows-3\",\n \"panels-top-bottom\",\n \"rows-4\",\n \"rss\",\n \"ruler-dimension-line\",\n \"ruler\",\n \"russian-ruble\",\n \"sailboat\",\n \"salad\",\n \"sandwich\",\n \"satellite-dish\",\n \"satellite\",\n \"saudi-riyal\",\n \"save-all\",\n \"save-off\",\n \"save\",\n \"scale-3d\",\n \"scale-3-d\",\n \"scale\",\n \"scaling\",\n \"scan-barcode\",\n \"scan-eye\",\n \"scan-face\",\n \"scan-heart\",\n \"scan-line\",\n \"scan-qr-code\",\n \"scan-search\",\n \"scan-text\",\n \"scan\",\n \"school\",\n \"scissors-line-dashed\",\n \"scissors\",\n \"scooter\",\n \"screen-share-off\",\n \"screen-share\",\n \"scroll-text\",\n \"scroll\",\n \"search-alert\",\n \"search-check\",\n \"search-code\",\n \"search-slash\",\n \"search-x\",\n \"search\",\n \"section\",\n \"send-horizontal\",\n \"send-horizonal\",\n \"send-to-back\",\n \"send\",\n \"separator-horizontal\",\n \"separator-vertical\",\n \"server-cog\",\n \"server-crash\",\n \"server-off\",\n \"server\",\n \"settings-2\",\n \"settings\",\n \"shapes\",\n \"share-2\",\n \"share\",\n \"sheet\",\n \"shell\",\n \"shelving-unit\",\n \"shield-alert\",\n \"shield-ban\",\n \"shield-check\",\n \"shield-cog-corner\",\n \"shield-cog\",\n \"shield-ellipsis\",\n \"shield-half\",\n \"shield-minus\",\n \"shield-off\",\n \"shield-plus\",\n \"shield-question-mark\",\n \"shield-question\",\n \"shield-user\",\n \"shield-x\",\n \"shield-close\",\n \"shield\",\n \"ship-wheel\",\n \"ship\",\n \"shirt\",\n \"shopping-bag\",\n \"shopping-basket\",\n \"shopping-cart\",\n \"shovel\",\n \"shower-head\",\n \"shredder\",\n \"shrimp\",\n \"shrink\",\n \"shrub\",\n \"shuffle\",\n \"sigma\",\n \"signal-high\",\n \"signal-low\",\n \"signal-medium\",\n \"signal-zero\",\n \"signal\",\n \"signature\",\n \"signpost-big\",\n \"signpost\",\n \"siren\",\n \"skip-back\",\n \"skip-forward\",\n \"skull\",\n \"slash\",\n \"slice\",\n \"sliders-horizontal\",\n \"sliders-vertical\",\n \"sliders\",\n \"smartphone-charging\",\n \"smartphone-nfc\",\n \"smartphone\",\n \"smile-plus\",\n \"smile\",\n \"snail\",\n \"snowflake\",\n \"soap-dispenser-droplet\",\n \"sofa\",\n \"solar-panel\",\n \"soup\",\n \"space\",\n \"spade\",\n \"sparkle\",\n \"sparkles\",\n \"stars\",\n \"speaker\",\n \"speech\",\n \"spell-check-2\",\n \"spell-check\",\n \"spline-pointer\",\n \"spline\",\n \"split\",\n \"spool\",\n \"sport-shoe\",\n \"spotlight\",\n \"spray-can\",\n \"sprout\",\n \"square-activity\",\n \"activity-square\",\n \"square-arrow-down-left\",\n \"arrow-down-left-square\",\n \"square-arrow-down-right\",\n \"arrow-down-right-square\",\n \"square-arrow-down\",\n \"arrow-down-square\",\n \"square-arrow-left\",\n \"arrow-left-square\",\n \"square-arrow-out-down-left\",\n \"arrow-down-left-from-square\",\n \"square-arrow-out-down-right\",\n \"arrow-down-right-from-square\",\n \"square-arrow-out-up-left\",\n \"arrow-up-left-from-square\",\n \"square-arrow-out-up-right\",\n \"arrow-up-right-from-square\",\n \"square-arrow-right-enter\",\n \"square-arrow-right-exit\",\n \"square-arrow-right\",\n \"arrow-right-square\",\n \"square-arrow-up-left\",\n \"arrow-up-left-square\",\n \"square-arrow-up-right\",\n \"arrow-up-right-square\",\n \"square-arrow-up\",\n \"arrow-up-square\",\n \"square-asterisk\",\n \"asterisk-square\",\n \"square-bottom-dashed-scissors\",\n \"scissors-square-dashed-bottom\",\n \"square-centerline-dashed-horizontal\",\n \"flip-horizontal\",\n \"square-centerline-dashed-vertical\",\n \"flip-vertical\",\n \"square-chart-gantt\",\n \"gantt-chart-square\",\n \"square-gantt-chart\",\n \"square-check-big\",\n \"check-square\",\n \"square-check\",\n \"check-square-2\",\n \"square-chevron-down\",\n \"chevron-down-square\",\n \"square-chevron-left\",\n \"chevron-left-square\",\n \"square-chevron-right\",\n \"chevron-right-square\",\n \"square-chevron-up\",\n \"chevron-up-square\",\n \"square-code\",\n \"code-square\",\n \"square-dashed-bottom-code\",\n \"square-dashed-bottom\",\n \"square-dashed-kanban\",\n \"kanban-square-dashed\",\n \"square-dashed-mouse-pointer\",\n \"mouse-pointer-square-dashed\",\n \"square-dashed-text\",\n \"text-selection\",\n \"text-select\",\n \"square-dashed-top-solid\",\n \"square-dashed\",\n \"box-select\",\n \"square-divide\",\n \"divide-square\",\n \"square-dot\",\n \"dot-square\",\n \"square-equal\",\n \"equal-square\",\n \"square-function\",\n \"function-square\",\n \"square-kanban\",\n \"kanban-square\",\n \"square-library\",\n \"library-square\",\n \"square-m\",\n \"m-square\",\n \"square-menu\",\n \"menu-square\",\n \"square-minus\",\n \"minus-square\",\n \"square-mouse-pointer\",\n \"inspect\",\n \"square-parking-off\",\n \"parking-square-off\",\n \"square-parking\",\n \"parking-square\",\n \"square-pause\",\n \"square-pen\",\n \"pen-box\",\n \"edit\",\n \"pen-square\",\n \"square-percent\",\n \"percent-square\",\n \"square-pi\",\n \"pi-square\",\n \"square-pilcrow\",\n \"pilcrow-square\",\n \"square-play\",\n \"play-square\",\n \"square-plus\",\n \"plus-square\",\n \"square-power\",\n \"power-square\",\n \"square-radical\",\n \"square-round-corner\",\n \"square-scissors\",\n \"scissors-square\",\n \"square-sigma\",\n \"sigma-square\",\n \"square-slash\",\n \"slash-square\",\n \"square-split-horizontal\",\n \"split-square-horizontal\",\n \"square-split-vertical\",\n \"split-square-vertical\",\n \"square-square\",\n \"square-stack\",\n \"square-star\",\n \"square-stop\",\n \"square-terminal\",\n \"terminal-square\",\n \"square-user-round\",\n \"user-square-2\",\n \"square-user\",\n \"user-square\",\n \"square-x\",\n \"x-square\",\n \"square\",\n \"squares-exclude\",\n \"squares-intersect\",\n \"squares-subtract\",\n \"squares-unite\",\n \"squircle-dashed\",\n \"squircle\",\n \"squirrel\",\n \"stamp\",\n \"star-half\",\n \"star-off\",\n \"star\",\n \"step-back\",\n \"step-forward\",\n \"stethoscope\",\n \"sticker\",\n \"sticky-note\",\n \"stone\",\n \"store\",\n \"stretch-horizontal\",\n \"stretch-vertical\",\n \"strikethrough\",\n \"subscript\",\n \"sun-dim\",\n \"sun-medium\",\n \"sun-moon\",\n \"sun-snow\",\n \"sun\",\n \"sunrise\",\n \"sunset\",\n \"superscript\",\n \"swatch-book\",\n \"swiss-franc\",\n \"switch-camera\",\n \"sword\",\n \"swords\",\n \"syringe\",\n \"table-2\",\n \"table-cells-merge\",\n \"table-cells-split\",\n \"table-columns-split\",\n \"table-of-contents\",\n \"table-properties\",\n \"table-rows-split\",\n \"table\",\n \"tablet-smartphone\",\n \"tablet\",\n \"tablets\",\n \"tag\",\n \"tags\",\n \"tally-1\",\n \"tally-2\",\n \"tally-3\",\n \"tally-4\",\n \"tally-5\",\n \"tangent\",\n \"target\",\n \"telescope\",\n \"tent-tree\",\n \"tent\",\n \"terminal\",\n \"test-tube-diagonal\",\n \"test-tube-2\",\n \"test-tube\",\n \"test-tubes\",\n \"text-align-center\",\n \"align-center\",\n \"text-align-end\",\n \"align-right\",\n \"text-align-justify\",\n \"align-justify\",\n \"text-align-start\",\n \"text\",\n \"align-left\",\n \"text-cursor-input\",\n \"text-cursor\",\n \"text-initial\",\n \"letter-text\",\n \"text-quote\",\n \"text-search\",\n \"text-wrap\",\n \"wrap-text\",\n \"theater\",\n \"thermometer-snowflake\",\n \"thermometer-sun\",\n \"thermometer\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket-check\",\n \"ticket-minus\",\n \"ticket-percent\",\n \"ticket-plus\",\n \"ticket-slash\",\n \"ticket-x\",\n \"ticket\",\n \"tickets-plane\",\n \"tickets\",\n \"timer-off\",\n \"timer-reset\",\n \"timer\",\n \"toggle-left\",\n \"toggle-right\",\n \"toilet\",\n \"tool-case\",\n \"toolbox\",\n \"tornado\",\n \"torus\",\n \"touchpad-off\",\n \"touchpad\",\n \"towel-rack\",\n \"tower-control\",\n \"toy-brick\",\n \"tractor\",\n \"traffic-cone\",\n \"train-front-tunnel\",\n \"train-front\",\n \"train-track\",\n \"tram-front\",\n \"train\",\n \"transgender\",\n \"trash-2\",\n \"trash\",\n \"tree-deciduous\",\n \"tree-palm\",\n \"palmtree\",\n \"tree-pine\",\n \"trees\",\n \"trending-down\",\n \"trending-up-down\",\n \"trending-up\",\n \"triangle-alert\",\n \"alert-triangle\",\n \"triangle-dashed\",\n \"triangle-right\",\n \"triangle\",\n \"trophy\",\n \"truck-electric\",\n \"truck\",\n \"turkish-lira\",\n \"turntable\",\n \"turtle\",\n \"tv-minimal-play\",\n \"tv-minimal\",\n \"tv-2\",\n \"tv\",\n \"type-outline\",\n \"type\",\n \"umbrella-off\",\n \"umbrella\",\n \"underline\",\n \"undo-2\",\n \"undo-dot\",\n \"undo\",\n \"unfold-horizontal\",\n \"unfold-vertical\",\n \"ungroup\",\n \"university\",\n \"school-2\",\n \"unlink-2\",\n \"unlink\",\n \"unplug\",\n \"upload\",\n \"usb\",\n \"user-check\",\n \"user-cog\",\n \"user-key\",\n \"user-lock\",\n \"user-minus\",\n \"user-pen\",\n \"user-plus\",\n \"user-round-check\",\n \"user-check-2\",\n \"user-round-cog\",\n \"user-cog-2\",\n \"user-round-key\",\n \"user-round-minus\",\n \"user-minus-2\",\n \"user-round-pen\",\n \"user-round-plus\",\n \"user-plus-2\",\n \"user-round-search\",\n \"user-round-x\",\n \"user-x-2\",\n \"user-round\",\n \"user-2\",\n \"user-search\",\n \"user-star\",\n \"user-x\",\n \"user\",\n \"users-round\",\n \"users-2\",\n \"users\",\n \"utensils-crossed\",\n \"fork-knife-crossed\",\n \"utensils\",\n \"fork-knife\",\n \"utility-pole\",\n \"van\",\n \"variable\",\n \"vault\",\n \"vector-square\",\n \"vegan\",\n \"venetian-mask\",\n \"venus-and-mars\",\n \"venus\",\n \"vibrate-off\",\n \"vibrate\",\n \"video-off\",\n \"video\",\n \"videotape\",\n \"view\",\n \"voicemail\",\n \"volleyball\",\n \"volume-1\",\n \"volume-2\",\n \"volume-off\",\n \"volume-x\",\n \"volume\",\n \"vote\",\n \"wallet-cards\",\n \"wallet-minimal\",\n \"wallet-2\",\n \"wallet\",\n \"wallpaper\",\n \"wand-sparkles\",\n \"wand-2\",\n \"wand\",\n \"warehouse\",\n \"washing-machine\",\n \"watch\",\n \"waves-arrow-down\",\n \"waves-arrow-up\",\n \"waves-ladder\",\n \"waves\",\n \"waypoints\",\n \"webcam\",\n \"webhook-off\",\n \"webhook\",\n \"weight-tilde\",\n \"weight\",\n \"wheat-off\",\n \"wheat\",\n \"whole-word\",\n \"wifi-cog\",\n \"wifi-high\",\n \"wifi-low\",\n \"wifi-off\",\n \"wifi-pen\",\n \"wifi-sync\",\n \"wifi-zero\",\n \"wifi\",\n \"wind-arrow-down\",\n \"wind\",\n \"wine-off\",\n \"wine\",\n \"workflow\",\n \"worm\",\n \"wrench\",\n \"x-line-top\",\n \"x\",\n \"zap-off\",\n \"zap\",\n \"zodiac-aquarius\",\n \"zodiac-aries\",\n \"zodiac-cancer\",\n \"zodiac-capricorn\",\n \"zodiac-gemini\",\n \"zodiac-leo\",\n \"zodiac-libra\",\n \"zodiac-ophiuchus\",\n \"zodiac-pisces\",\n \"zodiac-sagittarius\",\n \"zodiac-scorpio\",\n \"zodiac-taurus\",\n \"zodiac-virgo\",\n \"zoom-in\",\n \"zoom-out\",\n]);\n\nexport const LAYOUT_SECTION_ICON_SET: ReadonlySet<string> = new Set(LAYOUT_SECTION_ICONS);\nexport type LayoutSectionIcon = string;\n","/**\n * Generated by scripts/gen-dock-icon-names.mjs from the vendored icon tarball\n * (sha256 0691620e50bdf453c2fed06224d9dc52d521574ab254a149eba47664b92fb889)\n * and the vendored line-icon subset (sha256 06cd85d602d1104d962ed8ace64f6c4d64846ee50bd62bd328252c9d8f697b75).\n * Do not edit by hand: rerun the script (`--check` fails CI on drift).\n *\n * The closed vocabulary for `ui.icon` (field ui, fieldsets, prop ui.group). `as const` because a\n * z.enum needs the literal tuple; a `readonly string[]` would type every string as valid.\n */\nexport const DOCK_ICON_NAMES = [\n \"abc\",\n \"access-denied\",\n \"activity\",\n \"add\",\n \"add-circle\",\n \"add-comment\",\n \"add-document\",\n \"add-user\",\n \"address-book\",\n \"adjustments\",\n \"adjustments-horizontal\",\n \"alarm\",\n \"alert-triangle\",\n \"align-left\",\n \"api\",\n \"app-window\",\n \"apple\",\n \"apps\",\n \"archive\",\n \"arrow-back-up\",\n \"arrow-down\",\n \"arrow-guide\",\n \"arrow-left\",\n \"arrow-right\",\n \"arrow-top-right\",\n \"arrow-up\",\n \"arrows-diagonal\",\n \"arrows-down\",\n \"arrows-exchange\",\n \"arrows-horizontal\",\n \"arrows-left-right\",\n \"arrows-shuffle\",\n \"arrows-sort\",\n \"article\",\n \"aspect-ratio\",\n \"asterisk\",\n \"award\",\n \"axis-x\",\n \"backpack\",\n \"badge\",\n \"badge-cc\",\n \"badges\",\n \"bar-chart\",\n \"basket\",\n \"bell\",\n \"bill\",\n \"binary-document\",\n \"block-content\",\n \"block-element\",\n \"blockquote\",\n \"bold\",\n \"bolt\",\n \"book\",\n \"book-2\",\n \"bookmark\",\n \"bookmark-filled\",\n \"books\",\n \"bottle\",\n \"box\",\n \"brand-dribbble\",\n \"brand-facebook\",\n \"brand-instagram\",\n \"brand-linkedin\",\n \"brand-pinterest\",\n \"brand-tiktok\",\n \"brand-x\",\n \"brand-youtube\",\n \"briefcase\",\n \"broadcast\",\n \"browser\",\n \"bug\",\n \"building\",\n \"building-skyscraper\",\n \"building-store\",\n \"bulb-filled\",\n \"bulb-outline\",\n \"calculator\",\n \"calendar\",\n \"calendar-dollar\",\n \"calendar-event\",\n \"calendar-exclamation\",\n \"calendar-off\",\n \"calendar-plus\",\n \"calendar-star\",\n \"calendar-time\",\n \"camera\",\n \"campfire\",\n \"carousel-horizontal\",\n \"case\",\n \"cash\",\n \"category\",\n \"category-2\",\n \"chart-area\",\n \"chart-arrows\",\n \"chart-bar\",\n \"chart-bar-popular\",\n \"chart-donut\",\n \"chart-dots\",\n \"chart-line\",\n \"chart-upward\",\n \"check\",\n \"checkbox\",\n \"checklist\",\n \"checkmark\",\n \"checkmark-circle\",\n \"chef-hat\",\n \"chevron-down\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-right\",\n \"circle\",\n \"circle-check\",\n \"circle-dot\",\n \"circle-number-1\",\n \"circle-plus\",\n \"click\",\n \"clipboard\",\n \"clipboard-image\",\n \"clipboard-text\",\n \"clock\",\n \"clock-check\",\n \"clock-hour-4\",\n \"close\",\n \"close-circle\",\n \"code\",\n \"code-block\",\n \"cog\",\n \"collapse\",\n \"color-wheel\",\n \"columns\",\n \"columns-2\",\n \"columns-3\",\n \"comment\",\n \"component\",\n \"compose\",\n \"compose-sparkles\",\n \"confetti\",\n \"controls\",\n \"cookie\",\n \"copy\",\n \"credit-card\",\n \"crop\",\n \"cube\",\n \"currency-dollar\",\n \"dashboard\",\n \"database\",\n \"database-search\",\n \"desktop\",\n \"device-desktop\",\n \"device-mobile\",\n \"device-tablet\",\n \"devices\",\n \"diamond\",\n \"discount\",\n \"document\",\n \"document-pdf\",\n \"document-remove\",\n \"document-sheet\",\n \"document-text\",\n \"document-video\",\n \"document-word\",\n \"document-zip\",\n \"documents\",\n \"door-exit\",\n \"dot\",\n \"double-chevron-down\",\n \"double-chevron-left\",\n \"double-chevron-right\",\n \"double-chevron-up\",\n \"double-quote\",\n \"download\",\n \"drag-handle\",\n \"drop\",\n \"droplet\",\n \"droplet-half\",\n \"earth-americas\",\n \"earth-globe\",\n \"edit\",\n \"egg\",\n \"ellipsis-horizontal\",\n \"ellipsis-vertical\",\n \"empty\",\n \"enter\",\n \"enter-right\",\n \"envelope\",\n \"equal\",\n \"error-filled\",\n \"error-outline\",\n \"error-screen\",\n \"expand\",\n \"eye-closed\",\n \"eye-off\",\n \"eye-open\",\n \"face-happy\",\n \"face-indifferent\",\n \"face-sad\",\n \"feather\",\n \"feedback\",\n \"file\",\n \"file-certificate\",\n \"file-code\",\n \"file-download\",\n \"file-text\",\n \"filter\",\n \"flag\",\n \"flame\",\n \"flask\",\n \"focus-2\",\n \"folder\",\n \"folders\",\n \"forms\",\n \"frame\",\n \"generate\",\n \"gift\",\n \"git-branch\",\n \"github\",\n \"grid-dots\",\n \"groq\",\n \"hammer\",\n \"hand-finger\",\n \"hanger\",\n \"hash\",\n \"headphones\",\n \"headset\",\n \"heart\",\n \"heart-filled\",\n \"heart-handshake\",\n \"help-circle\",\n \"highlight\",\n \"history\",\n \"home\",\n \"hourglass\",\n \"ice-cream\",\n \"id-badge\",\n \"id-badge-2\",\n \"image\",\n \"image-remove\",\n \"images\",\n \"inbox\",\n \"infinity\",\n \"info-circle\",\n \"info-filled\",\n \"info-outline\",\n \"info-square-rounded\",\n \"inline\",\n \"inline-element\",\n \"input-search\",\n \"insert-above\",\n \"insert-below\",\n \"italic\",\n \"joystick\",\n \"json\",\n \"language\",\n \"launch\",\n \"layout\",\n \"layout-align-center\",\n \"layout-board\",\n \"layout-board-split\",\n \"layout-bottombar\",\n \"layout-bottombar-expand\",\n \"layout-cards\",\n \"layout-columns\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-navbar\",\n \"layout-rows\",\n \"layout-sidebar\",\n \"layout-sidebar-right\",\n \"leaf\",\n \"leave\",\n \"lemon\",\n \"library-photo\",\n \"lifebuoy\",\n \"link\",\n \"link-removed\",\n \"linkedin\",\n \"list\",\n \"list-check\",\n \"list-details\",\n \"list-numbers\",\n \"list-tree\",\n \"lock\",\n \"logo-js\",\n \"logo-ts\",\n \"mail\",\n \"map-2\",\n \"map-pin\",\n \"map-pins\",\n \"marker\",\n \"marker-removed\",\n \"master-detail\",\n \"math-function\",\n \"meat\",\n \"menu\",\n \"message\",\n \"message-2\",\n \"message-check\",\n \"message-circle\",\n \"message-circle-2\",\n \"message-plus\",\n \"message-star\",\n \"microphone\",\n \"microphone-slash\",\n \"mobile-device\",\n \"mood-empty\",\n \"moon\",\n \"movie\",\n \"news\",\n \"notes\",\n \"number\",\n \"ok-hand\",\n \"olist\",\n \"overage\",\n \"package\",\n \"packages\",\n \"palette\",\n \"panel-left\",\n \"panel-right\",\n \"paperclip\",\n \"pause\",\n \"pencil\",\n \"phone\",\n \"photo\",\n \"photo-scan\",\n \"photo-search\",\n \"pig-money\",\n \"pin\",\n \"pin-filled\",\n \"pin-removed\",\n \"play\",\n \"player-play\",\n \"player-track-next\",\n \"playlist-add\",\n \"plug\",\n \"plug-connected\",\n \"plus-minus\",\n \"point\",\n \"presentation\",\n \"printer\",\n \"progress-50\",\n \"progress-75\",\n \"projects\",\n \"publish\",\n \"qrcode\",\n \"quote\",\n \"read-only\",\n \"receipt\",\n \"recycle\",\n \"redo\",\n \"refresh\",\n \"remove\",\n \"remove-circle\",\n \"repeat\",\n \"reset\",\n \"restore\",\n \"retrieve\",\n \"retry\",\n \"revert\",\n \"robot\",\n \"rocket\",\n \"rosette\",\n \"route\",\n \"ruler\",\n \"ruler-measure\",\n \"salad\",\n \"scale\",\n \"schema\",\n \"school\",\n \"search\",\n \"section\",\n \"select\",\n \"send\",\n \"server\",\n \"settings\",\n \"share\",\n \"shield-check\",\n \"shield-lock\",\n \"shopping-bag\",\n \"shopping-cart\",\n \"shopping-cart-plus\",\n \"signature\",\n \"sitemap\",\n \"slideshow\",\n \"sort\",\n \"sort-descending\",\n \"spacing-vertical\",\n \"sparkle\",\n \"sparkles\",\n \"speakerphone\",\n \"spinner\",\n \"split-horizontal\",\n \"split-vertical\",\n \"square\",\n \"stack\",\n \"stack-2\",\n \"stack-compact\",\n \"stairs\",\n \"stairs-up\",\n \"star\",\n \"star-filled\",\n \"stars\",\n \"stop\",\n \"strikethrough\",\n \"string\",\n \"subtask\",\n \"sun\",\n \"superscript\",\n \"sync\",\n \"table\",\n \"table-options\",\n \"tablet-device\",\n \"tag\",\n \"tags\",\n \"target\",\n \"task\",\n \"template\",\n \"tent\",\n \"terminal\",\n \"terminal-2\",\n \"text\",\n \"th-large\",\n \"th-list\",\n \"thumb-up\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket\",\n \"tiers\",\n \"timeline\",\n \"toggle-arrow-right\",\n \"toggle-right\",\n \"token\",\n \"tool\",\n \"tools-kitchen-2\",\n \"transfer\",\n \"translate\",\n \"trash\",\n \"trend-upward\",\n \"triangle-outline\",\n \"trolley\",\n \"truck\",\n \"truck-delivery\",\n \"truncate\",\n \"twitter\",\n \"typography\",\n \"ulist\",\n \"unarchive\",\n \"underline\",\n \"undo\",\n \"unknown\",\n \"unlink\",\n \"unlock\",\n \"unpublish\",\n \"upload\",\n \"user\",\n \"user-circle\",\n \"user-plus\",\n \"user-search\",\n \"user-star\",\n \"users\",\n \"users-group\",\n \"versions\",\n \"video\",\n \"vocabulary\",\n \"vs\",\n \"warning-filled\",\n \"warning-outline\",\n \"weight\",\n \"world\",\n \"wrench\",\n \"zoom-question\",\n] as const;\n\nexport type DockIconName = (typeof DOCK_ICON_NAMES)[number];\n\nexport const DOCK_ICON_NAME_SET: ReadonlySet<string> = new Set<string>(DOCK_ICON_NAMES);\n","/**\n * The dock's icon vocabulary as an MCP resource (`bettercms://icons/dock`), served by both surfaces.\n *\n * A resource and not an enum in a tool schema: the list is ~6 KB, and every tool that inlines a\n * field or prop definition would pay for it on every tools/list. The schemas carry a string (stdio\n * refines it against DOCK_ICON_SET) and point here; the server's z.enum is the guard.\n */\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET } from \"@bettercms-ai/types\";\n\nexport const DOCK_ICONS_URI = \"bettercms://icons/dock\";\nexport const DOCK_ICON_SET: ReadonlySet<string> = DOCK_ICON_NAME_SET;\n\nexport const DOCK_ICONS_RESOURCE = {\n uri: DOCK_ICONS_URI,\n name: \"dock-icons\",\n title: \"BetterCMS dock icon names\",\n description:\n \"Every name `ui.icon`, a fieldset's `icon` and a prop's `ui.group.icon` accept. Layout section icons are a different list (Lucide names).\",\n mimeType: \"text/markdown\",\n};\n\nexport const DOCK_ICONS_TEXT = `# Dock icon names\n\n\\`ui.icon\\` on a nesting field, \\`icon\\` on a fieldset and \\`ui.group.icon\\` on a component prop take ONE\nname from this list. Any other string is refused with a 400 that names this resource. A leaf field\nnever carries an icon.\n\nTwo vocabularies, on purpose: Layout section icons (update_layout \\`add-section\\`) stay Lucide names.\nA name from one list is not valid in the other.\n\nThe list includes the V2 kit's line-icon names (\\`building\\`, \\`settings\\`, \\`layout-grid\\`, …) as themselves.\n\n${DOCK_ICON_NAMES.length} names:\n\n${DOCK_ICON_NAMES.join(\", \")}\n`;\n","/**\n * How to ORGANISE a BetterCMS project's Content sidebar — the structure standard, as a resource.\n *\n * Same rules as playbook.ts: dependency-free strings, one copy read by both MCP surfaces (the\n * hosted /mcp resource list and the stdio server). The algorithm these rules describe lives in\n * the backend (src/lib/content-navigation/standard.ts) and runs in two places — the import lane\n * that derives a structure for a site imported from GitHub, and the read-only\n * `suggest_content_structure` tool. The worked example below is that algorithm's actual output\n * for the input it describes; a backend test derives it and compares, so the two cannot drift.\n */\n\nexport const STRUCTURE_PLAYBOOK_URI = \"bettercms://playbook/structure\";\n\n/**\n * The server-instructions sentence both MCP surfaces carry: organising is the DEFAULT after an\n * agent creates collections or pages, not something it does only when asked.\n */\nexport const STRUCTURE_DEFAULT_INSTRUCTION =\n `After you create collections or pages, organise them per the structure playbook: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure (read-only), show the user its outline, then apply it with set_content_structure and the version it returned (the If-Match). A project that already has a structure keeps it: file only what you created, with move_to_folder, unless the user asks for a full re-organisation.`;\n\n/**\n * The other sentence both MCP surfaces carry: code-side skills are loaded by their description, so\n * the server points at the one that routes to the rest. Harmless where no skill is installed.\n * The catalog is one core skill whose table names a reference per task (progressive disclosure),\n * so the sentence asks for ONE reference: reading every reference is the context cost it avoids.\n */\nexport const SKILLS_ROUTING_INSTRUCTION =\n \"Before writing code in a repo that uses BetterCMS, explore the repo, then read the installed `bettercms` skill (`npx @bettercms-ai/install --project -y` adds it if missing): its table turns what you found into the one reference the task needs — read only that. Without the skill installed, read the same files as resources: bettercms://skill/bettercms, then bettercms://skill/<reference>.\";\n\n/** Both surfaces: editor chrome (the dock) has one doctrine, one write path and one receipt. */\nexport const DOCK_UI_ROUTING_INSTRUCTION =\n \"How fields and props look in the editor (groups, tabs, rows, icons, item names) is playbook §14 or the `field-ui` prompt: write it with update_content_model field* or update_component prop* plus ifMatch, read it back, and finish when get_next_steps reports no dock-* step.\";\n\n/** Both surfaces: an author's \"Hold edits back\" (V2 D53) is a decision a whole-site publish respects. */\nexport const PUBLISH_HOLD_INSTRUCTION =\n \"An item an author held back from site publishes (`publishHeldAt` set) stays out of whole-site publishes: do not publish it unless the user names it; publish_entries `release` includes it again.\";\n\n/**\n * Receipt first: both MCP surfaces open a project on get_next_steps, whose `receipt` says what\n * the platform already sees as done, what is missing and the one next action. Starting from it is\n * what stops an agent redoing finished work or converting the one page it happened to land on.\n */\nexport const RECEIPT_FIRST_INSTRUCTION =\n \"Start every project with get_next_steps: its `receipt` lists what is already done (`done`), what is still missing (`missing`, each item citing the count it reacted to) and the one `nextAction`. Work from that receipt instead of re-reading the site, call get_next_steps again after each batch of edits, and before you tell the user you are finished. On an imported site the gate is the definition of done: run `receipt.gate.nextAction`, read again, and repeat until `receipt.complete` is true. Record a gap you cannot close with editor_setup `exempt` only for an allowed reason that is true, with a note, never in prose.\";\n\n/** The get_next_steps tool description, shared by both surfaces so they cannot drift. */\nexport const NEXT_STEPS_DESCRIPTION =\n `Call this FIRST on a project. Returns \\`receipt\\` — \\`done\\` (live release, bound elements, conversion coverage, composed pages, published components and Layout), \\`missing\\`, \\`nextAction\\` and \\`notes\\` (unjudged: unknown, not done) — plus \\`data\\`, the unfinished items by \\`ruleId\\` (skill finish-site lists them). Each item cites its count and may carry \\`payload\\` {rows, total}, at most 20 rows. \\`receipt.complete\\` is the setup gate's verdict and \\`receipt.gate\\` its numbers per built route. Run \\`receipt.gate.nextAction\\`, call it again after each batch; you are finished only when \\`complete\\` is true. \\`organise-content\\`: pages and collections are in no folder — read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure and, once the user agrees, set_content_structure.`;\n\n/**\n * Site chrome, routed — the sentence both MCP surfaces carry: nav and footer are the project\n * Layout, never page fields, and the get_next_steps Layout rules point back here.\n */\nexport const LAYOUT_CHROME_INSTRUCTION =\n \"When the user asks to make the navigation, footer or other site chrome editable, or get_next_steps lists a `layout-*` or `chrome-duplicated` item: this is playbook §11 item 3. Chrome is the project Layout, never page fields: in the source, wrap each Section in `data-bcms-layout-section` (the slot, its base slug) and mark each value `data-bcms-layout-field=\\\"layout:<sections[slug].id>:<fieldId>\\\"`, never `data-bcms-field` inside it, then push; the strip removes the page copies, never delete them by hand. On a site BetterCMS serves, publish_layout writes Layout VALUES into the live pages; a structure change waits for a Rebuild. Never place nav, footer or modal blocks or fields on a page: the Layout (or the site's own layout) draws chrome, so a page copy either duplicates it or renders nowhere (get_componentize_plan reports one as LAYOUT_CHROME).\";\n\n/**\n * A call to action, said once for both surfaces: one `button` field, never a label field beside a\n * link field. The management lane refuses the importer's spelling of a pair (`cta_pair`), and\n * update_field `mergeHref` upgrades a pair a page already holds. @see BUTTON_FIELD_NOTE\n */\nexport const CTA_BUTTON_INSTRUCTION =\n \"A call to action is ONE `button` field (value {label, href, variant?, size?, arrow?, icon?, newTab?}), rendered with BcmsButton from @bettercms-ai/astro or @bettercms-ai/next: never a text field beside a link field. A page that already holds such a pair (primaryCtaText + primaryCtaHref) becomes one button with update_field `mergeHref`. Inside a component a CTA is a `button` block whose text and href two props target.\";\n\n/** The worked example's `set_content_structure` payload, exported so the backend test can compare. */\nexport const STRUCTURE_EXAMPLE_PAYLOAD = {\n version: 0,\n doc: {\n schema: 1,\n folders: [\n { id: \"home:pages\", parentId: null, name: \"Pages\", icon: \"documents\", sort: 1000 },\n { id: \"home:collections\", parentId: null, name: \"Shared\", icon: null, sort: 1001 },\n { id: \"fld_std_blog\", parentId: null, name: \"Blog posts\", icon: \"document-text\", sort: 0 },\n { id: \"fld_std_products\", parentId: null, name: \"Products\", icon: \"basket\", sort: 1 },\n ],\n items: [\n { kind: \"page\", id: \"pg_home\", folderId: \"home:root\", sort: 0, icon: null },\n { kind: \"page\", id: \"pg_blog\", folderId: \"home:root\", sort: 1, icon: null },\n { kind: \"page\", id: \"pg_shop\", folderId: \"home:root\", sort: 2, icon: null },\n { kind: \"collection\", id: \"cm_posts\", folderId: \"fld_std_blog\", sort: 0, icon: null },\n { kind: \"collection\", id: \"cm_products\", folderId: \"fld_std_products\", sort: 0, icon: null },\n { kind: \"collection\", id: \"cm_categories\", folderId: \"fld_std_products\", sort: 1, icon: null },\n { kind: \"collection\", id: \"cm_colours\", folderId: \"fld_std_products\", sort: 2, icon: null },\n { kind: \"collection\", id: \"cm_tags\", folderId: \"home:collections\", sort: 0, icon: null },\n { kind: \"page\", id: \"pg_about\", folderId: \"home:pages\", sort: 0, icon: null },\n { kind: \"page\", id: \"pg_contact\", folderId: \"home:pages\", sort: 1, icon: null },\n { kind: \"page\", id: \"pg_404\", folderId: \"home:pages\", sort: 2, icon: \"code\" },\n ],\n },\n} as const;\n\nexport const STRUCTURE_PLAYBOOK = `# Organising a BetterCMS project: the Content structure standard\n\nRead this BEFORE you organise the Content sidebar, and AFTER you create collections or pages:\nthe default is to organise what you made by these rules. The sidebar is one document per\nproject, \\`{ schema: 1, folders: [{ id, parentId, name, icon, sort }], items: [{ kind: 'page' |\n'collection', id, folderId, sort, icon }] }\\`, read with \\`get_content_structure\\` and written with\n\\`set_content_structure\\`. It is ORGANISATION ONLY: no URL, slug, schema, content or publish state\never changes.\n\n## The rules\n\n1. **One place per document.** Every page and every collection sits in exactly ONE place: pinned\n at the top level (\\`folderId: \"home:root\"\\`) or in one folder. A folder lists only its direct\n contents. Never list an id twice.\n2. **Pinned at the top:** the home page, then each collection's LIST page (the dynamic page that\n lists it, e.g. /blog). A single document opens straight into the editor, so it is a pin, not a\n folder with one page in it.\n3. **One folder per content family, named for the DETAIL type its route holds.** /blog gives\n \"Blog posts\", /case-studies \"Case studies\", /careers \"Jobs\".\n - Blog: a \"Blog posts\" folder holding the blog collection. A folder with exactly one\n collection opens that collection's table directly.\n - Commerce: a \"Products\" folder holding the product collection AND its taxonomies (product\n categories, product tags, merch collections, ...). Once there are more than four taxonomies,\n the VARIANT OPTIONS (colours, sizes, materials) move into an \"Attributes\" subfolder; the\n categories and tags stay beside the catalogue.\n - Decide the rest by the REFERENCE GRAPH: a collection that is referenced only by one family,\n or that references only one family (reviews → products), belongs in that family's folder.\n The family's main collection comes first, then the others in the order its fields reference\n them.\n4. **Family order:** the site's navigation order; failing that, entry count, then name.\n5. **Pages.** EVERY remaining standalone page goes in the system folder \\`home:pages\\`\n (\"Pages\") — no standalone page ever gets a top-level folder. Code-only routes (a 404, a\n page built by code with nothing to edit) stay there too, marked with the \\`file-code\\` icon.\n Pages that share a route (/legal/terms, /legal/privacy, /docs/...) get a subfolder of it.\n A site in more than one language files every page, home included, under Pages › <language>\n (named in itself: English, Français, Deutsch), default language first.\n6. **Shared taxonomies.** A vocabulary several families reference (Tags used by posts AND\n products) goes in the system folder \\`home:collections\\`, named \"Shared\". So does supporting\n content no family owns (testimonials, FAQs with no list page).\n7. **Settings closes the sidebar.** \\`home:globals\\` (\"Settings\") holds NO pages or collections —\n navigation, header, footer, site settings and SEO defaults open from it in the dashboard. The\n three system folders always sort BELOW the folders you make: … Pages, Shared, Settings.\n8. **Icons** (kit names, bettercms://icons/dock): \\`document-text\\` for posts, \\`basket\\` for products,\n \\`book\\` for docs, \\`documents\\` for Pages, \\`folder\\` by default. Lucide names already stored\n still draw.\n9. **Depth:** nest at most 2 levels by default. The hard limit is 4; do not use it without a\n reason the user gave you.\n10. **Organisation only.** Never rename a page, change a slug, touch a schema or move content to\n make a structure fit. The structure fits the site, not the other way round.\n11. **Page-bound models are not collections.** A page with fields has a content model bound to\n it; it is never filed (400 \\`NAV_PAGE_BOUND_MODEL\\`). Organise the PAGE.\n12. **Access:** changing the structure needs Admin or Developer, the same as editing the schema;\n reading needs only content access. A 403 \\`SCHEMA_ACCESS_REQUIRED\\` means this connection is\n neither: stop and tell the user, do not retry.\n\n## Refusals\n\nWhat the structure writes refuse, and the code each refusal carries:\n\n- **System folders.** \\`home:pages\\` (Pages), \\`home:collections\\` (Shared) and\n \\`home:globals\\` (Settings) always exist and can never be moved or deleted (400\n \\`NAV_SYSTEM_FOLDER\\`); \\`rename_folder\\` and \\`set_icon\\` work on them.\n- **Type purity** (400 \\`NAV_TYPE_MISMATCH\\`): Pages holds only pages at any depth, Shared\n only collections, Settings neither — globals are not sidebar items.\n- **Pins** sit above the folders in their own order, pages or collections. In a document a pin is\n \\`folderId: \"home:root\"\\`, a virtual id with no folder record; a folder record with that id is\n 400 \\`NAV_SYSTEM_FOLDER\\`. In \\`move_to_folder\\`, \\`folderId: 'root'\\` pins and \\`null\\` returns\n the item to its home (Pages / Shared).\n- **Kind.** \\`move_to_folder\\` and \\`set_icon\\` VERIFY what an id is: a page id sent as a\n collection is 400 \\`NAV_KIND_MISMATCH\\` naming the kind to use. \\`set_content_structure\\` never\n refuses a kind mismatch: it returns \\`warnings\\` and \\`kindMismatches\\` instead.\n- **Page-bound models** are refused with 400 \\`NAV_PAGE_BOUND_MODEL\\` naming their page; organise\n the page, by its page id.\n- **Shape:** folders nest at most 4 levels deep; names are 1-80 characters; icons are kit\n names (bettercms://icons/dock; a-z, 0-9, dashes) and null clears one.\n- **Access:** 403 \\`SCHEMA_ACCESS_REQUIRED\\` (rule 12).\n- **Version:** 412 \\`VERSION_CONFLICT\\` (workflow step 4).\n\n## The workflow\n\n1. \\`get_content_structure\\` — note \\`version\\` and whether a structure exists.\n2. \\`suggest_content_structure\\` — READ-ONLY. It runs the platform's own implementation of these\n rules over the project's pages, collections, references and routes and returns\n \\`{ doc, outline, rationale, version, hasDocument }\\`. It writes nothing.\n3. Show the user the \\`outline\\`. If \\`hasDocument\\` is true the project ALREADY has a structure\n someone made: never replace it without the user's explicit yes. Offer to file only what is\n new (\\`move_to_folder\\` per item) instead.\n4. Apply with \\`set_content_structure { doc, version }\\`, where \\`version\\` is the one you read —\n it is the If-Match. A 412 \\`VERSION_CONFLICT\\` means someone changed the sidebar since: read it\n again and re-apply; never overwrite blind.\n5. For one or two new documents, prefer \\`move_to_folder\\` into the matching family folder.\n\nProjects imported from GitHub get this structure automatically (the \"Organising your content\"\nstep of the import), but only when they have none yet; a later import files NEW documents into\nthe matching folder and changes nothing else.\n\n## Worked example: a blog plus a shop\n\nThe site: a home page (\\`pg_home\\`), a /blog list page (\\`pg_blog\\`, dynamic) for the Blog\ncollection (\\`cm_posts\\`), a /shop list page (\\`pg_shop\\`, dynamic) for Products\n(\\`cm_products\\`), About (\\`pg_about\\`), Contact (\\`pg_contact\\`) and a code-only 404\n(\\`pg_404\\`). Products references Product categories (\\`cm_categories\\`) and Colours\n(\\`cm_colours\\`); both Blog and Products reference Tags (\\`cm_tags\\`).\n\n\\`\\`\\`text\n[pinned page] Home\n[pinned page] Blog (/blog lists Blog)\n[pinned page] Shop (/shop lists Products)\n[folder] Blog posts icon=newspaper\n Blog\n[folder] Products icon=shopping-bag\n Products, Product categories, Colours (referenced only by Products)\n[system folder] Pages icon=files\n About, Contact, Not found (icon=file-code)\n[system folder] Shared\n Tags (referenced by Blog AND Products: shared)\n[system folder] Settings (navigation, header, footer, site settings, SEO defaults)\n\\`\\`\\`\n\nThe exact \\`set_content_structure\\` payload (\\`version: 0\\` because the project had no structure):\n\n\\`\\`\\`json\n${JSON.stringify(STRUCTURE_EXAMPLE_PAYLOAD, null, 2)}\n\\`\\`\\`\n`;\n","/**\n * update_content_entry's merge, planned once for every agent surface (stdio, hosted, Studio).\n *\n * The entry PATCH REPLACES `data` wholesale, so changing one field meant reading the entry and\n * sending every other field back by hand — and an agent that forgot one deleted it. So merge is\n * the default: the host reads the entry, lays the caller's keys over the stored ones, and writes\n * at the version it read: a concurrent edit between the read and the write is a 409, never a\n * silent overwrite. Only an explicit `merge: false` replaces the whole object.\n *\n * Dependency-free on purpose: the hosted catalog (src/routes/mcp/index.ts) imports it across the\n * package boundary, like playbook.ts.\n */\n\nexport interface StoredEntry {\n data?: Record<string, unknown> | null;\n optimisticVersion?: number | null;\n}\n\nexport interface MergedEntryWrite {\n /** The stored data with the caller's keys laid over it, by top-level key. */\n data: Record<string, unknown>;\n /** The If-Match to write at: the caller's own when given, else the version that was read. */\n ifMatch?: number;\n}\n\n/** True unless the caller asked for a full replace (`merge: false`) or sent no `data`. */\nexport const mergesEntry = (args: { merge?: unknown; data?: unknown }): boolean =>\n args.merge !== false && args.data !== undefined;\n\n/**\n * Shallow merge by top-level key. A key the caller sends replaces the stored value whole (a group\n * or repeater value is one key); a key it omits is kept; `null` is a value like any other.\n */\nexport function planEntryMerge(\n stored: StoredEntry,\n patch: Record<string, unknown>,\n callerIfMatch?: number,\n): MergedEntryWrite {\n const data = { ...(stored.data ?? {}), ...patch };\n const ifMatch = callerIfMatch ?? (typeof stored.optimisticVersion === \"number\" ? stored.optimisticVersion : undefined);\n return ifMatch === undefined ? { data } : { data, ifMatch };\n}\n","/**\n * `whoami`: who a connection acts as, for access troubleshooting. One description for both MCP\n * surfaces (the hosted catalog imports it across the package boundary, like playbook.ts).\n *\n * The two surfaces answer from what each can actually know. The hosted connector resolves the\n * caller's credential on every call, so it reports the principal, the scope and the grants. The\n * stdio server holds only an access token and has no route that reports a key's grants, so it\n * reports the scope it can observe (whether the Management API resolves a project without one\n * being named) and says that grants are not visible from there — never a guess.\n */\n\nexport const WHOAMI_DESCRIPTION =\n \"Who this connection acts as. Call it first when a call is refused for access. Returns the principal (`device_grant` from the connect flow, or `api_key`), the workspace, `scope` ('project' = bound to one project; 'workspace' = pass projectId on every project tool) and, where the server can see them, `grants`: content:publish takes content live, artifact:write runs the code and deploy tools, schema:manage changes the Content sidebar. `grants: null` means this server cannot see them, not that there are none. Reads nothing else and changes nothing.\";\n\n/** The grants whoami names, keyed to what each one unlocks. */\nexport const WHOAMI_GRANT_FLAGS = {\n canPublish: \"content:publish\",\n canWriteArtifacts: \"artifact:write\",\n canChangeStructure: \"schema:manage\",\n} as const;\n\n/** `{ canPublish, canWriteArtifacts, canChangeStructure }` from a key's permission list. */\nexport function grantFlags(permissions: readonly string[]): Record<keyof typeof WHOAMI_GRANT_FLAGS, boolean> {\n return {\n canPublish: permissions.includes(WHOAMI_GRANT_FLAGS.canPublish),\n canWriteArtifacts: permissions.includes(WHOAMI_GRANT_FLAGS.canWriteArtifacts),\n canChangeStructure: permissions.includes(WHOAMI_GRANT_FLAGS.canChangeStructure),\n };\n}\n","/**\n * Model-schema edits planned once for both MCP surfaces: `update_content_model` `removeFields`\n * and `update_field`. Both end in the one write the model PATCH offers — a whole `fields` array,\n * sent at the version read — because that PATCH REPLACES the list wholesale, and an agent retyping\n * the whole schema to change one field is how the rest of it gets lost. So the host reads the\n * model, changes exactly what was named, and writes the rest back untouched.\n *\n * Removal: `removeFields` + `allowFieldRemoval` drop named TOP-LEVEL keys (otherwise a key that\n * still has content is a 409). Nothing is removed by accident: both arguments are required\n * together, an unknown key refuses the whole call, and a page's fields go through\n * remove_page_fields, which has a dry run.\n *\n * Edit: `update_field` patches ONE field anywhere in the tree, addressed by a dot path through its\n * group/repeater children. A retype needs `allowRetype`; a key rename leaves the old key's content\n * to the route's orphan guard (409 with the entry count unless allowFieldRemoval).\n *\n * Dependency-free on purpose: the hosted catalog imports it across the package boundary.\n */\n\nexport type FieldRemovalRequest =\n | { kind: \"none\" }\n | { kind: \"refuse\"; error: string }\n | { kind: \"remove\"; keys: string[] };\n\n/** What the caller asked for, judged before anything is read. */\nexport function fieldRemovalRequest(args: {\n removeFields?: unknown;\n allowFieldRemoval?: unknown;\n pageId?: unknown;\n}): FieldRemovalRequest {\n const { removeFields, allowFieldRemoval, pageId } = args;\n if (removeFields === undefined && allowFieldRemoval === undefined) return { kind: \"none\" };\n if (removeFields === undefined) {\n return { kind: \"refuse\", error: \"allowFieldRemoval names no field: pass removeFields with the top-level keys to delete.\" };\n }\n if (!Array.isArray(removeFields) || removeFields.length === 0 || !removeFields.every((k) => typeof k === \"string\" && k)) {\n return { kind: \"refuse\", error: \"removeFields must be a non-empty list of top-level field keys (from get_content_model).\" };\n }\n if (pageId !== undefined) {\n return { kind: \"refuse\", error: \"A page's fields are removed with remove_page_fields, which has a dry run; removeFields takes modelId.\" };\n }\n if (allowFieldRemoval !== true) {\n return {\n kind: \"refuse\",\n error: \"removeFields deletes those fields and DISCARDS their values in every entry: send allowFieldRemoval: true with it, once the user has agreed.\",\n };\n }\n return { kind: \"remove\", keys: [...new Set(removeFields as string[])] };\n}\n\nexport interface StoredModel {\n fields?: Array<{ key?: unknown; [prop: string]: unknown }> | null;\n optimisticVersion?: number | null;\n}\n\nexport type FieldRemovalPlan =\n | { ok: true; fields: Array<{ key?: unknown }>; ifMatch?: number }\n | { ok: false; error: string };\n\n/** The model's `fields` without the named top-level keys, and the If-Match to write at. */\nexport function planFieldRemoval(model: StoredModel, keys: string[], callerIfMatch?: number): FieldRemovalPlan {\n const fields = model.fields ?? [];\n const present = new Set(fields.map((f) => f.key));\n const unknown = keys.filter((k) => !present.has(k));\n if (unknown.length > 0) {\n return {\n ok: false,\n error: `Not top-level fields of this model: ${unknown.join(\", \")}. Nothing was removed; read get_content_model for its keys (a group's child goes with its group, or is edited in the dashboard).`,\n };\n }\n const drop = new Set(keys);\n const ifMatch = callerIfMatch ?? (typeof model.optimisticVersion === \"number\" ? model.optimisticVersion : undefined);\n const kept = fields.filter((f) => !drop.has(f.key as string));\n return ifMatch === undefined ? { ok: true, fields: kept } : { ok: true, fields: kept, ifMatch };\n}\n\n// ── update_field ─────────────────────────────────────────────────────────────\n\ntype Field = Record<string, unknown>;\n\n/** What update_field may change on one field. `null` clears helpText, showIf, ui, placement, the lock pair and the V2 keys. */\nexport interface FieldEdit {\n path?: unknown;\n label?: unknown;\n helpText?: unknown;\n required?: unknown;\n config?: unknown;\n showIf?: unknown;\n ui?: unknown;\n placement?: unknown;\n readOnly?: unknown;\n lockReason?: unknown;\n helpMore?: unknown;\n advanced?: unknown;\n recommendedMax?: unknown;\n openMode?: unknown;\n localized?: unknown;\n type?: unknown;\n key?: unknown;\n allowRetype?: unknown;\n}\n\nexport type FieldEditPlan =\n | { ok: true; fields: Field[]; ifMatch?: number; renamed?: { from: string; to: string } }\n | { ok: false; error: string };\n\n/**\n * Where a field keeps its children, in the shapes a stored schema uses: the off-config `fields`,\n * a group's `config.zones.nonRepeatable` (the list itself), a repeater's\n * `config.zones.repeatable.fields`, and an object array's `config.fields` / `config.itemFields`.\n * Mirrors childListsOf in src/lib/content/field-paths.ts.\n */\nconst CHILD_LISTS: string[][] = [\n [\"fields\"],\n [\"config\", \"zones\", \"nonRepeatable\"],\n [\"config\", \"zones\", \"repeatable\", \"fields\"],\n [\"config\", \"fields\"],\n [\"config\", \"itemFields\"],\n];\n\nconst getIn = (node: unknown, at: string[]): unknown =>\n at.reduce<unknown>((n, k) => (n && typeof n === \"object\" ? (n as Field)[k] : undefined), node);\n\nconst setIn = (node: Field, [head, ...rest]: string[], value: unknown): Field =>\n ({ ...node, [head]: rest.length === 0 ? value : setIn((node[head] ?? {}) as Field, rest, value) });\n\n/** The fields list with the field at `keys` replaced by `edit(field)`, or null when no such field. */\nfunction patchAt(fields: Field[], [key, ...rest]: string[], edit: (f: Field) => Field): Field[] | null {\n const at = fields.findIndex((f) => f.key === key);\n if (at === -1) return null;\n const field = fields[at];\n let next: Field | null = null;\n if (rest.length === 0) next = edit(field);\n else {\n for (const list of CHILD_LISTS) {\n const kids = getIn(field, list);\n const patched = Array.isArray(kids) ? patchAt(kids as Field[], rest, edit) : null;\n if (patched) {\n next = setIn(field, list, patched);\n break;\n }\n }\n }\n return next && fields.map((f, i) => (i === at ? next : f));\n}\n\n/** The field at a dot path, or undefined. */\nfunction fieldAt(fields: Field[], keys: string[]): Field | undefined {\n let found: Field | undefined;\n patchAt(fields, keys, (f) => ((found = f), f));\n return found;\n}\n\n/** Every key in the tree — the namespace is flat, nested fields included. */\nfunction allKeys(fields: Field[]): string[] {\n return fields.flatMap((f) => [\n String(f.key),\n ...CHILD_LISTS.flatMap((list) => {\n const kids = getIn(f, list);\n return Array.isArray(kids) ? allKeys(kids as Field[]) : [];\n }),\n ]);\n}\n\nconst CLEARABLE = [\"helpText\", \"showIf\", \"ui\", \"placement\", \"readOnly\", \"lockReason\", \"helpMore\", \"advanced\", \"recommendedMax\", \"openMode\", \"localized\"] as const;\nconst SETTABLE = [\"label\", \"required\", ...CLEARABLE] as const;\n\n/** Shallow-merge a config patch; a null key deletes it, so a group's zones are never lost. */\nfunction mergeConfig(current: unknown, patch: Record<string, unknown>): Field {\n const out: Field = { ...((current ?? {}) as Field) };\n for (const [k, v] of Object.entries(patch)) {\n if (v === null) delete out[k];\n else out[k] = v;\n }\n return out;\n}\n\nconst wordsOf = (v: unknown): string =>\n (typeof v === \"string\" ? v : typeof (v as { label?: unknown })?.label === \"string\" ? (v as { label: string }).label : \"\")\n .replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim().toLowerCase();\n\n/**\n * Why `helpText` is no help for this field, or null. Help that repeats the field — its label, the\n * value it holds, or `e.g. \"<that value>\"` — tells an editor nothing the input does not already\n * show (`e.g. \"Starter Kit\"` under an input holding \"Starter Kit\"). One check for update_field\n * and the server's fieldHelpText / propHelpText writes, so the two cannot disagree.\n */\nexport function helpTextEcho(helpText: unknown, field: { label?: unknown; defaultValue?: unknown }): string | null {\n if (typeof helpText !== \"string\" || !helpText.trim()) return null;\n const said = wordsOf(helpText.replace(/^\\s*e\\.?g\\.?[:,]?\\s*/i, \"\")).replace(/^[\"'“”‘’]+|[\"'“”‘’.…]+$/g, \"\");\n const value = wordsOf(field.defaultValue);\n const echoes = said === wordsOf(field.label) || (value !== \"\" && (said === value || (/…[\"”]?$/.test(helpText.trim()) && value.startsWith(said))));\n return echoes\n ? \"helpText repeats the field's label or value, which the editor already shows. Say what belongs here or its format in under 60 characters (\\\"Whole number, no currency symbol.\\\"), or send null for none.\"\n : null;\n}\n\n/** The model's `fields` with ONE field changed, and the If-Match to write at. */\nexport function planFieldEdit(model: StoredModel, edit: FieldEdit, callerIfMatch?: number): FieldEditPlan {\n const fields = (model.fields ?? []) as Field[];\n const keys = typeof edit.path === \"string\" && edit.path ? edit.path.split(\".\") : [];\n const current = keys.length ? fieldAt(fields, keys) : undefined;\n if (!current) {\n return { ok: false, error: `No field at path '${String(edit.path ?? \"\")}'. Paths are dot-separated keys from get_content_model or get_page, e.g. 'hero.title'.` };\n }\n const retype = edit.type !== undefined && edit.type !== current.type;\n if (retype && edit.allowRetype !== true) {\n return {\n ok: false,\n error: `Changing '${keys.join(\".\")}' from ${String(current.type)} to ${String(edit.type)} changes how every stored value is read, and values that do not fit are lost. Send allowRetype: true with it, once the user has agreed.`,\n };\n }\n const rename = typeof edit.key === \"string\" && edit.key !== current.key ? edit.key : undefined;\n if (rename !== undefined && allKeys(fields).includes(rename)) {\n return { ok: false, error: `The key '${rename}' is already used in this schema; keys share one flat namespace, nested fields included.` };\n }\n const changes = SETTABLE.filter((k) => edit[k] !== undefined);\n if (!retype && rename === undefined && edit.config === undefined && changes.length === 0) {\n 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.\" };\n }\n const echo = helpTextEcho(edit.helpText, { label: edit.label ?? current.label, defaultValue: current.defaultValue });\n if (echo) return { ok: false, error: echo };\n const next = patchAt(fields, keys, (f) => {\n let out: Field = { ...f };\n for (const k of changes) {\n if (edit[k] === null && (CLEARABLE as readonly string[]).includes(k)) delete out[k];\n else out[k] = edit[k];\n }\n // `ui` merges per key like `fieldUi` (field-ui-write.ts): sending { reorderable: false } must\n // not drop a stored collapsed/preview. A null member clears that key; `ui: null` clears it all.\n if (edit.ui && typeof edit.ui === \"object\") {\n const ui = mergeConfig(f.ui, edit.ui as Record<string, unknown>);\n if (Object.keys(ui).length > 0) out.ui = ui;\n else delete out.ui;\n }\n if (edit.config && typeof edit.config === \"object\") out = { ...out, config: mergeConfig(f.config, edit.config as Record<string, unknown>) };\n if (retype) out.type = edit.type;\n if (rename !== undefined) out.key = rename;\n return out;\n })!;\n const ifMatch = callerIfMatch ?? (typeof model.optimisticVersion === \"number\" ? model.optimisticVersion : undefined);\n return {\n ok: true,\n fields: next,\n ...(ifMatch === undefined ? {} : { ifMatch }),\n ...(rename === undefined ? {} : { renamed: { from: String(current.key), to: rename } }),\n };\n}\n","/**\n * Which tools a connection LISTS, decided once for both MCP surfaces.\n *\n * The hosted connector reads `?tools=` off its URL; the stdio server reads the\n * BETTERCMS_MCP_TOOLS environment variable. Both hand the raw string to `toolsetsOf` and ask\n * `listsTool` per name, so `core`, `abm` and `all` mean the same thing wherever an agent connects.\n *\n * Dependency-free on purpose: the hosted catalog (src/routes/mcp/index.ts) imports it across the\n * package boundary, like entry-merge.ts.\n */\n\n/**\n * 🔴 WHICH 100 SURVIVE A CLIENT THAT KEEPS 100 IS OUR DECISION, NOT ITS.\n *\n * Claude Desktop shows a server's first ~100 tools and silently drops the rest (MCP discussion\n * #537). The tail is what a connector can lose first: the agent-job lane, component evidence,\n * analytics, entry history and the one-off project operations. Both surfaces list it LAST, and\n * every tool in it stays callable.\n * @see MCP-TRUNCATION-FACTS.md\n */\nexport const LISTING_TAIL: ReadonlySet<string> = new Set([\n // The agent-job lane: a dashboard surface an agent rarely drives.\n \"list_ai_jobs\", \"get_ai_job\", \"approve_ai_job\", \"reject_ai_job\", \"list_ai_reports\",\n \"connect_native_ai\",\n // Component validation: a CI lane, not an authoring one.\n \"request_component_validation\", \"declare_component_route\", \"clear_component_source\",\n \"submit_componentize_receipt\",\n // Reporting, history and workflow chrome.\n \"get_analytics_overview\", \"get_analytics_top_pages\", \"list_activity\", \"get_workflow_board\",\n \"move_stage\", \"list_entry_versions\", \"restore_entry_version\",\n // One-off project operations and the extraction lane.\n \"clone_project\", \"promote_project\", \"generate_pages_from_dataset\", \"extract_component\",\n \"list_extraction_candidates\", \"create_deploy_upload\", \"import_redirects\",\n \"set_authoring_preference\", \"set_media_delivery\", \"delete_form_submission\", \"remove_page_fields\",\n // Access troubleshooting and platform feedback: called when something is refused or missing.\n \"whoami\", \"give_feedback\", \"search_docs\",\n // Search, batch and localisation: reached for once the site exists.\n \"search_content\", \"discard_draft\", \"publish_entries\", \"create_content_entries\", \"translate_entry\",\n \"update_field\", \"refresh_search_index\",\n // Automation, branches and AI images.\n \"list_webhooks\", \"create_webhook\", \"list_branches\", \"create_branch\", \"apply_branch\",\n \"generate_image\", \"transform_image\", \"write_alt_text\",\n // The ABM campaign lane — also hidden from the default listing (ABM_TOOLS below).\n \"research_account\", \"build_abm_page\", \"claim_abm_task\", \"complete_abm_task\", \"fail_abm_task\",\n \"get_campaign_review\", \"regenerate_entry\", \"approve_campaign_entries\", \"publish_campaign\",\n \"get_campaign_share_link\", \"revoke_campaign_share_link\",\n]);\n\n/**\n * The ABM campaign lane: a marketer's surface plus the worker tools a task runner claims with.\n * Listed only when asked for (`?tools=abm`, BETTERCMS_MCP_TOOLS=abm), because eleven tools every\n * other connection reads and never calls are a tax on each of them.\n */\nexport const ABM_TOOLS: ReadonlySet<string> = new Set([\n \"research_account\", \"build_abm_page\", \"claim_abm_task\", \"complete_abm_task\", \"fail_abm_task\",\n \"get_campaign_review\", \"regenerate_entry\", \"approve_campaign_entries\", \"publish_campaign\",\n \"get_campaign_share_link\", \"revoke_campaign_share_link\",\n]);\n\nexport const TOOLSETS = [\"core\", \"abm\", \"all\"] as const;\nexport type Toolset = (typeof TOOLSETS)[number];\n\n/** A comma list (`core,abm`) → the named toolsets; unknown names are ignored, empty = default. */\nexport function toolsetsOf(raw: string | null | undefined): Set<Toolset> {\n const names = (raw ?? \"\").toLowerCase().split(\",\").map((s) => s.trim());\n return new Set(names.filter((n): n is Toolset => (TOOLSETS as readonly string[]).includes(n)));\n}\n\n/**\n * Whether a tool is LISTED under these toolsets. The base is the default listing (every tool but\n * the ABM lane), or only the head of the catalogue under `core`; `abm` adds the ABM lane to that\n * base and `all` lists everything. So `abm` alone is the default plus the lane, and `core,abm` is\n * the core plus the lane.\n */\nexport function listsTool(name: string, sets: ReadonlySet<Toolset>): boolean {\n if (sets.has(\"all\")) return true;\n if (ABM_TOOLS.has(name)) return sets.has(\"abm\");\n return !sets.has(\"core\") || !LISTING_TAIL.has(name);\n}\n\n/**\n * 🔴 WHAT AN AGENT CALLS FIRST MUST BE CALLABLE FIRST.\n *\n * A client with tool search (Claude Code) does not put 150 schemas in the prompt: it lists the\n * tools by NAME and loads a schema when the agent searches for it. A call to a tool whose schema\n * it has not loaded never reaches us: the client refuses it (\"Invalid tool parameters\" in Claude\n * Code). After an import that is the agent's second or third call every time, because every\n * instruction, receipt and tool result names the next tool to call (editor_setup, then the brief,\n * then the receipt) and the agent calls it by that name.\n *\n * `_meta[\"anthropic/alwaysLoad\"]` keeps a tool's schema in the prompt. These are the ones a setup\n * starts with and returns to. Few on purpose (about 9,000 characters of a 236,000-character\n * catalogue): each is read on every turn of every connection.\n */\nexport const ALWAYS_LOADED: ReadonlySet<string> = new Set([\n \"get_next_steps\", \"editor_setup\", \"get_deploy_status\", \"get_conversion_brief\", \"get_binding_report\",\n \"list_projects\", \"list_pages\", \"get_page\", \"list_content_models\",\n]);\n\n/** A tool's `_meta` in tools/list, or nothing for a tool a client may defer. */\nexport const toolMeta = (name: string): { \"anthropic/alwaysLoad\": true } | undefined =>\n ALWAYS_LOADED.has(name) ? { \"anthropic/alwaysLoad\": true } : undefined;\n\n/** The other half, for every tool that is deferred: said once, to every client, on connect. */\nexport const TOOL_LOADING_INSTRUCTION =\n \"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.\";\n\n","/**\n * Tool descriptions written ONCE for both MCP surfaces.\n *\n * The hosted catalog (src/routes/mcp/index.ts) and the stdio package (./tools.ts) each declare\n * their own schemas, but a description that says two different things on the two surfaces is a\n * prompt that works from one client and misleads from the other. Text here is imported by both,\n * so it cannot drift; mcp-text-parity pins the tools that use it byte-equal.\n *\n * Dependency-free on purpose: the hosted catalog imports it across the package boundary.\n */\n\nexport const ADD_FIELD_DESCRIPTION =\n \"Append ONE field to a content model (`modelId`) or to a page's schema (`pageId`) — 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; `ui`, `helpText`, `showIf`, `placement` and `fieldsetId` declare how it presents in the editor — 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 — 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): §14 of bettercms://playbook/schema.\";\n\n/** The V2 leaf types, one short line each; appended to add_field after ADD_FIELD_DESCRIPTION. */\nexport const V2_LEAF_TYPES_NOTE =\n \"`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).\";\n\nexport const MOVE_STAGE_DESCRIPTION =\n \"Move a content entry (`entryId`) or a page (`pageId`) to another editorial stage — 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' — approving and publishing are deliberately two separate calls.\";\n\n/** A block's (and a Layout Section's) visibility window, on both surfaces. */\nexport const WINDOW_NOTE =\n \"{from?, until?}, ISO 8601 with offset: shown only between the two instants; null clears (skill publishing).\";\n\n/** The events a webhook can subscribe to — pinned to the route's schema by mcp-tool-routes.test.ts. */\nexport const WEBHOOK_EVENTS = [\n \"content.publish\", \"content.unpublish\", \"content.stage_changed\", \"content.created\",\n \"content.updated\", \"content.deleted\", \"deployment.triggered\",\n] as const;\n\n/** The fourteen tools the Sanity-parity pass added, one description each for both surfaces. */\nexport const NEW_TOOL_TEXT = {\n 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.\",\n search_content:\n \"Full-text search over the project's PUBLISHED pages and entries (the site-search index). Returns id, type ('page'|'entry'), title, slug and a snippet per hit; `type` narrows to one kind. Drafts are not indexed: find those with list_content_entries `where`. `meta.unavailable` means site search is off for this project.\",\n discard_draft:\n \"Throw away unpublished edits to an entry (`entryId`) or a page (`pageId`) — exactly one: the draft returns to exactly what is live and `pendingChanges` becomes false. A page resets its blockJson and its published Layout overrides. 409 no_published_version means it was never published (delete it instead). Pass ifMatch (optimisticVersion) to refuse if it changed since you read it.\",\n give_feedback:\n \"Tell the BetterCMS team about a tool that failed, a capability you needed and did not have, or docs that misled you. Opens a ticket for the team; nothing in the project changes. Name the `tool`, and paste the request and response into `context`. Never include secrets or personal data.\",\n publish_entries:\n \"Publish or unpublish many entries and pages in ONE call (up to 100 ids of each; no page unpublish). Needs a publish-enabled connection, and each item still passes its own gates (editorial stage, required fields). Nothing stops the run: the result lists what changed (`published` or `unpublished`) and every refusal in `failed` with its reason. A publish answers 202 with the routes being rebuilt. `hold` keeps a live item's edits out of whole-site publishes, `release` includes them again; publishing a held item here ends its hold.\",\n create_content_entries:\n \"Create up to 200 DRAFT entries of one collection in ONE call, each {slug?, data} as create_content_entry takes it. Every row reports `created` (with id and slug) or `failed` (with the error), a failure does not stop the others, and `meta` counts them. A row with `externalKey` is safe to send again: its entry is `updated` (draft only), or `unchanged` when the row is the same. A row setting a developer-locked field fails (FIELD_LOCKED). Publish afterwards with publish_entries.\",\n translate_entry:\n \"Create an entry's `targetLocale` translation with AI (uses AI credits: 402/403 when out or not on the plan). Text and longtext fields are translated; rich text and documents are copied for you to translate; the rest is copied. The new entry is a DRAFT with `locale` set and `translationOf` = the source; `meta` lists translated and copied keys. `targetLocale` must be one of the project's locales; 409 locale_conflict means that translation exists, so edit it instead.\",\n list_webhooks:\n \"List the project's outgoing webhooks: name, url, events, whether active, and delivery health (total, failed, last attempt). Signing secrets are never returned.\",\n create_webhook:\n \"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.\",\n list_branches:\n \"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.\",\n create_branch:\n \"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.\",\n apply_branch:\n \"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.\",\n search_docs:\n \"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.\",\n generate_image:\n \"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`.\",\n refresh_search_index:\n \"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.\",\n import_redirects:\n \"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.\",\n editor_setup:\n \"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` when it already ran for the live sha, else it starts (`running`; poll with `check: true`). `state`: never or stale (run it), running, ready, failed. 409 = nothing is live yet: deploy first. Then get_next_steps.\",\n transform_image:\n \"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).\",\n write_alt_text:\n \"Alt text for a Media Library image (mediaId) or an https image URL (url), written from its pixels (1 AI credit). A suggestion: save it with update_media.\",\n} as const;\n\n/**\n * delete_page's second job, on both surfaces: the server-app bundle cleanup. A parameter on an\n * existing delete rather than a tool of its own, because a tool's fixed cost alone would break the\n * tools/list ceiling (mcp-payload-weight.test.ts).\n */\nexport const DELETE_PAGE_RUNTIME_BUNDLE =\n \" 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.\";\n\n/** Parameter descriptions the extended arguments share across both surfaces. */\n/** update_content_entry: what a developer lock does to a value write. One sentence, both catalogs. */\nexport const FIELD_LOCKED_NOTE =\n \"A readOnly 'developer' field keeps its stored value: changing or omitting it without schema access is 403 FIELD_LOCKED.\";\n\nexport const PARAM_TEXT = {\n dryRun: \"validates and reports what would be written; writes nothing\",\n externalKey: \"id in the source system; sent again, it updates that entry's draft or leaves it unchanged\",\n upsertSource: \"source URL, kept with the entry\",\n upsertRunId: \"your run's id, kept with the entry\",\n externalKeyFilter: \"exact externalKey an entry was created with\",\n readOnly: \"'developer' = the value and this lock change only with schema access (needs lockReason); true = an editor marker\",\n lockReason: \"which system owns the value (≤ 200 chars)\",\n lockClears: \"as on add_field; null clears it\",\n helpText: \"shown under the field. Most fields get none: write it only for a format or unit, a place the canvas cannot show, a real constraint or a fallback, as one plain sentence under 90 characters with no semicolons, no dashes and no values from the page, never its label or value. Omitted: the platform writes it where one of those reasons holds.\",\n helpMore: \"longer help behind the ⓘ next to the label, when one helpText line cannot carry it\",\n advanced: \"true = a rare or developer setting: it collects in a closed 'Advanced' section\",\n recommendedMax: \"a SOFT limit (characters, items or value): the editor warns past it, never refuses\",\n openMode: \"object/array/group/repeater: how the value (or each row) opens: 'inline', 'drill', 'popover' or 'dialog'\",\n fromBuiltin: \"a builtin:* id from list_components: copies it into the project; fields you send win\",\n componentPreview: \"a slot row's look: {title?, subtitle?, media?} TOP-LEVEL prop keys, fallback?, icon?; null clears. §3 of bettercms://playbook/schema\",\n componentIcon: \"the block icon, a dock icon name; null clears. §3 of bettercms://playbook/schema\",\n componentTabs: \"/kit tabs no top-level prop sits in: [{id,label,icon?,order?}]. §3 of bettercms://playbook/schema\",\n 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\",\n describes: \"for editors: what it is and holds; omitted: written for you\",\n runtimeBundle: \"instead of pageId: the server-app bundle cleanup\",\n pageRef: \"page id or path ('/de/about'); a bare slug only when one page has it\",\n editorSetupForce: \"re-run a setup already ready for the live build\",\n editorSetupCheck: \"true = only report the state; starts nothing\",\n editorSetupExempt: \"instead of running: record setup-gate exceptions [{ route, check, reason, note }]; reason null removes one. Reasons: get_next_steps `receipt.gate`\",\n editorSetupDeclare: \"instead of running: record binding decisions [{op, id, ...}], max 100, a result each; with `check: true` a dry run. Ops: skill bindings\",\n pageBlockJson:\n \"an ARRAY REPLACES the page's block composition (a `component` block per section). An OBJECT edits ONE section of the stored page instead: `insertSection` adds a component (its id, or a builtin:* id: copied into the project once) at index `at`, or `before` / `after` a section's block id (none = last), with its `style` and `overrides`; `sectionStyle` sets a section's block style (a key replaces the stored one, null unsets it). `section` in the answer names the block (skill publishing)\",\n pageDynamic: \"a dynamic (collection template) page only\",\n previewPath: \"its route pattern, e.g. /blog/{slug}; null clears\",\n pageModelId: \"an existing collection this page lists (when it has no model yet)\",\n formIgnored: \"true = not one of the site's forms (a search box, a widget); false restores it\",\n componentizeCodemod: \"true = componentize nothing; run the section-order codemod in the connected repo on its own Actions, which commits for the next build. After the components and pages are published. `skipped` = no repo to commit to: run `convert --sections` in a checkout (skill componentize)\",\n where:\n \"field filters: {field: value} is equality, {field: {op: value}} with op eq|ne|gt|gte|lt|lte|contains|in, and an array means `in`. System fields slug, status, publishedAt, locale work anywhere; a data field needs modelId. Compares the served copy (live for published, working for draft)\",\n sort: \"comma list, a leading - sorts descending, e.g. '-publishedAt,title'\",\n page: \"1-based page of `limit` rows; the response's meta says totalPages\",\n locale: \"language, a BCP-47 tag (zh-CN → zh-cn), one of the project's locales; null = the default\",\n translationOf:\n \"the SOURCE id this translates (never a translation); null unlinks. One per locale: the translation sets locale and translationOf\",\n pageScheduledAt:\n \"ISO datetime to publish this page's draft at (needs publish permission); null cancels. An edit that omits scheduledAt CANCELS a pending schedule\",\n pageUnpublishAt: \"ISO datetime at which the published page returns to draft; null cancels; omitting it never cancels it\",\n sourceUrl:\n \"instead of data: a public http(s) URL the server fetches and stores (private or internal addresses are refused)\",\n focalX: \"focal point, 0-1 across from the left edge; null resets to the centre\",\n focalY: \"focal point, 0-1 down from the top edge; null resets to the centre\",\n mergeHref:\n \"pageId only: the link field paired with `path` (the label). Both become ONE `button` field keyed `key` (default: their stem, primaryCtaHref → 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\",\n confirmedInput:\n \"true only after the user explicitly approved adding this custom input (`ui.input`); else setting or changing one is refused input_needs_confirmation. Removing one needs no approval\",\n} as const;\n\n/**\n * The header `confirmed: true` travels as, on both surfaces. The server's custom-input gate reads\n * it on every Management write of fields or props. @see src/lib/content/field-ui-write.ts\n */\nexport const INPUT_CONFIRMED_HEADER = \"x-bcms-confirmed-input\";\n\n/**\n * What a `button` field is, said where a field TYPE is chosen. Without it an agent meets the type\n * only through the `cta_pair` refusal. @see packages/types/src/button-look.ts ButtonValue\n */\nexport const BUTTON_FIELD_NOTE =\n \"'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.\";\n\n/**\n * What a `link` value may be, said beside the field types. @see packages/types/src/link-value.ts\n */\nexport const LINK_VALUE_NOTE =\n \"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}.\";\n\nexport const UPDATE_FIELD_DESCRIPTION =\n \"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 — 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`.\";\n\nexport const GET_SEO_DESCRIPTION =\n \"Get the connected project's site-wide SEO settings — 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.\";\n\nexport const UPDATE_SEO_DESCRIPTION =\n \"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.\";\n\n/** One line per update_seo key, shared by both surfaces' schemas. */\nexport const SEO_KEY_TEXT = {\n seoDefaults: \"site-wide meta defaults every page inherits\",\n siteSchema: \"the site's JSON-LD: an object or an array of objects\",\n robotsConfig: \"robots.txt: 'auto' (`disallow` names AI crawlers to block), or 'custom' with its text\",\n sitemapConfig: \"sitemap.xml: generated ('auto') or 'custom', defaults and extra URLs\",\n rssConfig: \"the RSS feed on or off\",\n indexnowConfig: \"IndexNow on publish, minus URL patterns to leave out\",\n searchConfig: \"site search: on/off, the box's placeholder, AI answers\",\n} as const;\n\n/** Round-2 clauses shared by both surfaces. */\nexport const VARIANT_GROUP_NOTE =\n \"`variantGroup`: the family of looks it belongs to, if any, and its looks.\";\n/** get_component `detachedCopy`, on both surfaces. */\nexport const DETACHED_COPY_NOTE =\n \"{overrides?}: a rich-text embed's separate-copy `fields` (playbook §5)\";\n/** update_component `kitEntry`, on both surfaces. */\nexport const KIT_ENTRY_REBUILD_NOTE =\n \"Setting or changing `kitEntry` puts that entry's ui over every prop's server-derived ui: the entry wins where it specifies a tab, group, control or preview key, and derived ui it says nothing about stays (ui a person or an agent set is kept); `kitUiApplied` lists the props it changed.\";\nexport const UNPROPPED_COPY_NOTE =\n \"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.\";\nexport const UPDATE_PAGE_IF_MATCH_NOTE =\n \"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.\";\n/** The list form of a `slot` prop, on create_component `props` of both surfaces. */\nexport const SLOT_MULTIPLE_NOTE =\n \"'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 §5.\";\n/** Sections are props: the V2 field language on create_component of both surfaces. */\nexport const PROP_V2_NOTE =\n \"Props take the fields' V2 keys (§14): 'object' = ONE {child: value} from config.fields, ≤10 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).\";\n/** The Global Layout field lock, on update_layout of both surfaces. */\nexport const LAYOUT_LOCK_NOTE =\n \"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`.\";\n","/**\n * list_content_entries' query string, built once for both MCP surfaces.\n *\n * The management list route takes the Delivery API's filter grammar (`filter[field]=v`,\n * `filter[field][op]=v`, `in` as a comma list — src/lib/delivery/list-query.ts parseFilters)\n * plus `sort`, `page` and `limit`. An agent writes `where` as an object, which is what it gets\n * right; this turns it into that grammar.\n *\n * Dependency-free on purpose: the hosted catalog imports it across the package boundary.\n */\n\n/** The operators the route understands; `eq` is what a bare value means. */\nexport const WHERE_OPS = [\"eq\", \"ne\", \"gt\", \"gte\", \"lt\", \"lte\", \"contains\", \"in\"] as const;\n\nconst text = (v: unknown): string => (Array.isArray(v) ? v.map(String).join(\",\") : String(v));\n\n/**\n * `{ title: \"Hi\", price: { gte: 10 }, tags: [\"a\", \"b\"] }` →\n * `[[\"filter[title]\", \"Hi\"], [\"filter[price][gte]\", \"10\"], [\"filter[tags][in]\", \"a,b\"]]`.\n * An undefined or null condition is skipped.\n */\nexport function whereToQuery(where: Record<string, unknown> | undefined): Array<[string, string]> {\n const out: Array<[string, string]> = [];\n for (const [field, cond] of Object.entries(where ?? {})) {\n if (cond === undefined || cond === null) continue;\n if (Array.isArray(cond)) out.push([`filter[${field}][in]`, text(cond)]);\n else if (typeof cond === \"object\") {\n for (const [op, v] of Object.entries(cond as Record<string, unknown>)) {\n if (v !== undefined && v !== null) out.push([`filter[${field}][${op}]`, text(v)]);\n }\n } else out.push([`filter[${field}]`, text(cond)]);\n }\n return out;\n}\n\nexport interface EntryListArgs {\n modelId?: unknown;\n pageId?: unknown;\n status?: unknown;\n externalKey?: unknown;\n where?: unknown;\n sort?: unknown;\n page?: unknown;\n limit?: unknown;\n /** true = full rows (field data, published copy); otherwise a summary without them. */\n detail?: unknown;\n}\n\n/** The whole `?…` for GET /management/content/entries: a summary list unless `detail` is true. */\nexport function entryListSearch(args: EntryListArgs): string {\n const q = new URLSearchParams();\n for (const key of [\"modelId\", \"pageId\", \"status\", \"externalKey\"] as const) if (args[key]) q.set(key, String(args[key]));\n for (const [k, v] of whereToQuery(args.where as Record<string, unknown> | undefined)) q.append(k, v);\n for (const key of [\"sort\", \"page\", \"limit\"] as const) if (args[key] !== undefined && args[key] !== null) q.set(key, String(args[key]));\n if (args.detail !== true) q.set(\"select\", \"summary\");\n const s = q.toString();\n return s ? `?${s}` : \"\";\n}\n","import { z } from \"zod\";\nimport { SCHEMA_PLAYBOOK } from \"./playbook.js\";\nimport { SECTION_DOCTRINE } from \"@bettercms-ai/types\";\n\n/**\n * The one rule that decides whether a generated page is editable at all, injected into every\n * prompt that can end in a block tree.\n *\n * Only `studio` and `propose_schema` carried the playbook, and the playbook is where the\n * section rules lived — so `new_page`, `build_site` and `generate_landing_pages` could each\n * author a page with no idea that a page is a list of sections. A page authored as loose\n * top-level blocks gets one editor section per block: a hero of headline + lede + two CTAs\n * arrives as four sections, and the two CTAs stack instead of sitting side by side.\n */\nconst STRUCTURE_RULE = `### Page structure (non-negotiable)\n${SECTION_DOCTRINE}`;\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\n/**\n * Guided slash-command prompts that ship WITH the MCP. Claude Code (and other\n * hosts) surface server prompts automatically as `/mcp__bettercms__<name>`, so\n * adding the MCP is all it takes — no per-machine skill files.\n *\n * Design: one **generous parent** (`studio`) that reads the user's intent and\n * routes to the right sub-flow, plus thin direct entry points (`new_page`, ...)\n * for the individual flows. New BetterCMS tools get a new sub-flow section here.\n */\n\n/**\n * THE CONVERSION LOOP, in the fewest lines it fits in.\n *\n * 🔴 IT ENDS WHEN NOTHING IS PENDING, not when the codemod has run once. Measured on a real kit:\n * one pass declared 282 of 767 paths and every agent that read that receipt reported the site\n * converted. The loop below is the fix — apply each pending path's `fix`, rerun, resubmit — and\n * `submit_conversion_receipt` answers `complete` so there is one unambiguous finish line.\n *\n * SHARED WITH THE HOSTED SURFACE (src/routes/mcp/index.ts), which serves the same prompt over the\n * remote transport. Two copies of a loop drift, and the drifted one is the one the agent runs.\n */\n/**\n * The editor-chrome step every import, convert and componentize flow ends on. Without it an agent\n * finishes with every component prop bare and the dock shows none of the V2 vocabulary; the setup\n * gate's `dock` row holds `complete` until it is done. ONE copy, shared by the three prompts.\n */\nexport const DOCK_UI_STEP =\n \"EDITOR CHROME: for every component, run the field-ui lane (the `field-ui` prompt, playbook §14): `get_component`, then one `update_component` with `propUi`, `propTab` and `propHelpText` giving each prop its V2 ui (control, tab, group, collapsed, layout, preview, itemLabel, icon) after the closest `bettercms://kit` entry. The gate's `dock` row stays open until each has it, or a true `default-controls` exception.\";\n\nexport const CONVERT_SITE_TEXT = (projectId?: string): string =>\n `Convert my site so every visible element is editable in BetterCMS${projectId ? `, project ${projectId}` : \"\"}.\nDo not stop at the plan or at a partial receipt — finish the whole site, never editing a class or style.\n\n1. \\`list_projects\\`; pass \\`projectId\\`${projectId ? ` (${projectId})` : \"\"} on every project tool. Not listed = the grant is on\n another workspace: have the user re-authenticate there. Never convert a different project.\n2. \\`editor_setup\\` until it is \\`ready\\` (poll with \\`check: true\\`), then \\`get_conversion_plan\\`; on a 404 \\`no-approved-plan\\`,\n \\`get_conversion_brief { complete: true }\\` and follow \\`cursor\\` to the LAST page, keeping every\n page — a codemod fed the capped brief converts a truncated site. Write them to \\`brief.json\\`.\n3. \\`pull_project_source\\` (or clone the \\`github\\` remote it names) and work from the SOURCE, never\n from the deployed HTML.\n4. \\`npx @bettercms-ai/convert --brief brief.json --root . --receipt receipt.json\\`; read \\`git diff\\`.\n5. For EVERY entry of \\`paths.pending\\`, go to its \\`fix.file\\`:\\`fix.line\\` and do what \\`fix.action\\`\n says: \\`wrap-span\\` wrap the literal in \\`<span data-bcms-field=\"…\">\\`; \\`declare-attr\\` add\n \\`data-bcms-field=\"…\"\\` to that element; \\`bind-expression\\` replace the expression with the\n framework's bcmsField helper; \\`declare-richtext\\` bind the container with the richtext helper;\n \\`bind-data\\` bind the field in the data file it names; \\`manual\\` do what its \\`why\\` says. A row\n with no \\`fix\\` is still yours. Then rerun step 4 until \\`paths.pending\\` is EMPTY.\n6. \\`npx @bettercms-ai/convert --verify-styles --base <commit before step 4>\\`, restore what it lists, then\n \\`submit_conversion_receipt { briefDigest, receipt }\\` with its \\`styleEdits\\`: only \\`complete: true\\` ends it (else step 5).\n7. Deploy the working tree (\\`create_deploy_upload\\`, then \\`deploy_project\\` with its \\`uploadKey\\`); poll \\`get_deploy_status\\` until live. No git yet.\n8. \\`get_binding_report\\`: \\`unmatched\\` 0, \\`unaddressable\\` under 2% per route; fix the SOURCE, deploy, re-read (playbook §11).\n9. \\`set_binding_mode { declaredBindings: true }\\`, deploy AGAIN and poll, then confirm \\`get_binding_report\\`\n reads mode \"declared\", unmatched 0, bound above 0, \\`coverage.pending\\` empty. Send me that report.\n10. \\`get_next_steps\\`: if it lists \\`upgrade-section-roots\\` (section spacing and style handles), in the repo run\n \\`npx @bettercms-ai/convert@latest --upgrade-sections --root . --dry-run\\`, read the plan, then run it for real. For every\n root its receipt lists as \\`skipped\\`, pass the block down by hand: \\`{...sectionRootAttrs(block)}\\` on the section root, or\n \\`data-bcms-style=\"\"\\` plus \\`style={...}\\` from \\`block.style\\`. For \\`upgrade-element-styles\\` (field width, spacing, text handles)\n do the same with \\`npx @bettercms-ai/convert@latest --upgrade-element-styles --root . --dry-run\\`. Run \\`--verify-styles\\` again\n and restore what it lists (the marker, and the inline style from \\`block.style\\` or \\`fieldAttrs\\`, are allowed; changing a class\n or an existing style is not). Deploy, poll, call \\`get_next_steps\\` again and run \\`receipt.gate.nextAction\\` until \\`receipt.complete\\` is true; what else it lists, tell me by name. Not listed: say so; invent no work. Its \\`receipt.gate\\` fails a route on \\`sections\\` or \\`style\\` while I could not add a section to that page, reorder it or space it: run each such row's \\`fix\\` too. A write that answers \\`held\\`, or a publish whose \\`outcome\\` is \\`partial\\`, is not done until its action is taken.\n11. ${DOCK_UI_STEP}\n12. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the next rebuild from my repo drops it). Touch git only as I answer.`;\n\n/**\n * The editor-chrome lane: §14 is the doctrine, this is the order of work and the receipt. Shared with\n * the hosted surface (src/routes/mcp/index.ts), like CONVERT_SITE_TEXT.\n */\nexport const FIELD_UI_PROMPT = {\n title: \"Declare how fields LOOK in the editor (guided)\",\n description:\n \"Set the editor chrome of an existing schema and its component props: groups, tabs, rows, icons, item names, what titles and thumbnails a list's rows, help text, conditional visibility. Derives it from your source, then from the field shapes, and asks only what it cannot know.\",\n request: \"scope, e.g. 'the Team and Testimonials models' or 'the whole project'\",\n};\nexport const FIELD_UI_TEXT = (request?: string): string =>\n `Declare the editor UI for my BetterCMS fields and component props.${request ? ` Scope: \"${request}\".` : \"\"}\n\nRead bettercms://playbook/schema section 14 first: the vocabulary, patterns, budgets, recipes, the\ntabs rule, every refusal, and the three tiers that decide each value (my source, then the field\nshape, then ask me, once and batched). Icon names are in bettercms://icons/dock.\n\n**Order of work**\n1. \\`get_next_steps\\`: its dock-budget, dock-repeater-unnamed and dock-showif-order steps name the\n screens to fix. Read each target with \\`get_content_model\\`, \\`get_page\\` (its \\`backingModel\\`) or\n \\`get_component\\`; note its \\`optimisticVersion\\` and the chrome a person already set.\n2. Decide each field's chrome by the §14 tiers and write down which tier answered.\n3. Apply one write per model or component, always with \\`ifMatch\\` (428 without it; 409\n version-conflict when stale: read again and re-apply, never retry blindly):\n - fields that exist: \\`update_content_model\\` fieldUi / fieldFieldset / fieldOrder / fieldLabel /\n fieldHelpText by field path, plus \\`fieldsets\\`. A singleton page: send \\`pageId\\` instead of\n modelId, with its backingModel's version;\n - component props: \\`update_component\\` propUi / propGroup / propTab / propLabel / propHelpText;\n - a NEW field: ui / helpText / showIf in the same \\`add_field\\` call, with \\`after\\`.\n A 409 \\`ui_human_owned\\` names chrome a person set: leave it, or ask me and send \\`override: true\\`\n only on my word.\n4. **RECEIPT, non-negotiable.** Re-read every target and confirm the stored chrome matches what you\n sent: a key ABSENT from the read was not stored, whatever the write said. Call \\`get_next_steps\\`\n until no dock-* step is left. Report per field the tier that decided it, what you set, and that\n the read-back confirmed it; say plainly what you could not confirm.`;\n\n// ── Reusable sub-flows ──────────────────────────────────────────────────────\n\nconst SCHEMA_PROPOSAL_FLOW = `### Whole-project design (confirm-first) → \\`create_component\\` / \\`create_page\\` / \\`create_content_model\\`\nDesign the WHOLE project from its brief or its code, and **confirm the shape with the user\nBEFORE creating anything**. Never silently guess.\n\n1. **Read the source** — the connected repo, or the uploaded project in your working\n directory. For each page, identify the repeated visual regions and the list-shaped data.\n2. **Classify every part** using the decision tree in the playbook below. The two mistakes\n that matter: flattening a marketing page into loose page fields when its sections should\n be COMPONENTS, and giving a blog a \\`richtext\\` field when its body should be \\`document\\`.\n3. **Present the proposal (REQUIRED gate).** Show the component library (with each section's\n family and variants), the collections and their fields, and the pages that place them.\n Ask the user (AskUserQuestion) to confirm or adjust. Do not create anything before this.\n4. **Build it in the playbook's order** — blocks, collections, components, PUBLISH the\n components, pages, content, publish. Skipping the publish step ships a blank site.\n\n${SCHEMA_PLAYBOOK}\n`;\n\nconst PAGE_FLOW = `### Page authoring → \\`create_page\\` tool\nAuthor a page (the page-first schema). Ask, in order, via AskUserQuestion:\n1. **Page type** — singleton (exactly one entry: Home, About, Contact) vs dynamic\n (many entries sharing the schema: Blog posts, Products).\n2. **Identity** — title; derive a slug (lowercase, a–z 0–9 -) and confirm; optional\n metaTitle/metaDescription.\n3. **Fields (loop until done)** — for each: key (^[a-zA-Z0-9_]+$), label, type,\n required?. Types (14): text, richtext, image, boolean, number, select (needs\n \\`options: string[]\\`), reference / multi-reference (\\`config.contentModelId\\`,\n multi adds min/max), array (primitives — \\`config.itemType\\`: text|number|date),\n date (\\`config.includeTime\\`?), datetime, **button** (ONE call to action, value\n {label, href, variant?, size?, arrow?, icon?, newTab?} — never a text field plus a\n link field), **group** (Non-Repeatable Zone: ONE\n nested object — recurse to collect its \\`fields\\`, e.g. blog_hero → heading,\n description, hero_image), **repeater** (Repeatable Zone: an ARRAY of such objects\n — recurse to collect item \\`fields\\`, e.g. testimonials → quote, author). Nesting\n may go several levels deep.\n4. **Review** the assembled tree, then call \\`create_page\\` with\n { title, slug, pageType, fields, metaTitle?, metaDescription? }. Field object:\n { key, label, type, required?, options?, config?, fields? }.`;\n\nconst FIELD_FLOW = `### Add a field → \\`add_field\\` (a model or a page)\nAppend a field to an existing schema. First decide the target: a **content model**\nor a **page** (Home, About, a blog template). Ask: which target (id — use\n\\`list_pages\\` to find a page id), then the field (key, label, type — any of the 14\nabove, including nested group/repeater), required?. Confirm, then call:\n- a model → \\`add_field\\` { modelId, key, label, type, ... }\n- a page → \\`add_field\\` { pageId, key, label, type, ... }\nIt is additive: it rejects a key that already exists and never retypes/overwrites\nan existing field — change one of those with \\`update_field\\` { path, … }.`;\n\nconst ENTRY_FLOW = `### Create an entry → \\`create_content_entry\\` tool\nCreate a content entry under a model. Ask: which model (id), the field values (data),\nstatus (draft/published). Then call \\`create_content_entry\\` { contentModelId, data?, status?, slug? }.`;\n\nconst FORM_FLOW = `### Form authoring → \\`create_form\\` / \\`update_form\\` tools\nAuthor a form (then the user embeds it with \\`<BcmsForm form={getForm('Name')} />\\` from\n@bettercms-ai/next). Confirm the fields with the user BEFORE creating. Never guess fields.\n1. **Discover** — \\`list_forms\\` to see existing forms; \\`get_form\\` to read one before editing.\n2. **Collect fields (loop)** — for each: key (machine key for the value), label, type. Types:\n text, email, textarea, select (needs \\`options: string[]\\`), checkbox, checkboxes (needs\n \\`options\\`), radio (needs \\`options\\`), number, phone, date, url, consent, hidden, step (divider). Optional per\n field: required?, placeholder?, helpText? (shown under the input), defaultValue?,\n \\`validation\\` (\\`emailPolicy\\` on email, \\`min\\`/\\`max\\` on number, \\`phoneFormat\\` on phone,\n \\`pattern\\` on text/textarea/url — a rule on any other type is a 400),\n \\`ui\\` (\\`countryPicker\\` + \\`defaultCountry\\` on phone — renders a country picker and stores\n E.164; \\`defaultCountry\\` without \\`countryPicker\\` is a 400), and\n \\`showIf: { field, equals }\\` for conditional display.\n3. **Settings** — name (used by getForm('Name')), submitLabel?, successMessage?, redirectUrl?.\n4. **Confirm**, then \\`create_form\\` { name, fields, ... } (returns the new id), or\n \\`update_form\\` { formId, ... } to edit (passing \\`fields\\` REPLACES the array — include all).\n5. The form lands as a DRAFT, and a draft refuses every submission (403): call\n \\`publish_form\\` { formId } (on 403 PUBLISH_NOT_GRANTED, tell the user to publish it in the\n dashboard Forms tab), then offer to wire \\`<BcmsForm>\\` into the page/component where the\n user wants it.`;\n\nconst COMPONENT_FLOW = `### Component authoring → \\`create_component\\` / \\`publish_component\\`\nAuthor a reusable section. blockJson is the visual definition; authoring it blind is\nerror-prone, so go slow and confirm. Never guess the layout.\n1. **Discover** — \\`list_components\\` / \\`get_component\\` (read before update; keep existing blocks).\n2. **Design the tree** — wrap the section in a \\`section\\` block carrying \\`style\\`\n (bg + paddingTop/paddingBottom + contentWidth) and nest content in props.children. See\n \"Anatomy of a real section component\" in the playbook. Give every block a stable id.\n3. **sectionType + category** — set both, or the component never appears in the editor's\n \"Add a section\" picker. Components sharing a sectionType are swappable VARIANTS, so reuse\n the same prop keys across a family or a swap drops content.\n4. **Props** — declare only what should really be editable:\n { key, label, target: { blockId, path },\n type: text|richtext|image|url|boolean|number|select|group|table|slot|form|link|button|date|color|file|icon|multiselect|object|datetime|slug|email|phone|json|location|tags|rating|code|reference|multi-reference|video|array|longtext }.\n 'select'/'multiselect' need config.options; 'group'/'table'/'object' need config.fields; a 'button'\n is ONE prop on a button block's 'props', never a label prop plus a url prop; 'slot' holds ONE nested component (a list with config.multiple);\n 'form' holds ONE Form document — point target.path at 'props' on an empty form block and set\n defaultValue to {formId}. Never re-declare a form's FIELDS as props: the Form document owns\n them, and a second copy is a second source of truth that drifts on the first edit.\n5. **Confirm the structure** (AskUserQuestion: show the block tree), then \\`create_component\\`.\n6. **\\`publish_component\\`.** It lands as a DRAFT, and a draft component renders as NOTHING on\n the live site — no error, no placeholder. This step is not optional.\n`;\n\n/**\n * The WHOLE-SITE componentization ask, mapped onto the platform. Its six headings are the six\n * the request itself arrives with; each line is the platform's answer, and the parts with no\n * answer say so rather than inviting the agent to invent one. The deep version is playbook §12.\n */\nconst COMPONENTIZE_SITE_FLOW = `### Componentize the entire website → playbook §12 + the batch tools\nRead \\`bettercms://playbook/schema\\` §12 first — this is the short form of it.\n1. **Global elements.** Navbar / mobile nav / header / footer are the LAYOUT (\\`get_layout\\`,\n \\`update_layout\\`; a chrome component is placed with the \\`add-component\\` command). CTA buttons\n are \\`button\\` BLOCKS inside the section that uses them, exposed as \\`text\\` + \\`url\\` props —\n variant/size/icon are that block's own props and \\`style\\`; each look joins the project's Button\n family by itself, so never hand-build a Button component. Rich text\n is a \\`richtext\\` prop. Forms are \\`create_form\\` + a \\`form\\` block, and form FIELDS are the only\n place with real \\`required\\` / \\`placeholder\\` / \\`helpText\\` / \\`validation\\`. Cards, badges, tags,\n links, lists and media are blocks inside a section, repeatables as one \\`table\\` prop.\n Accordions/FAQ: \\`builtin:faq-list\\` or a \\`tabs\\` block. NOT MODELLED: cookie banners, modals,\n breadcrumbs, pagination — leave them in the site's code and say so at the end.\n2. **One component per distinct section**, one-offs included. \\`sectionType\\` is the family;\n components sharing one are VARIANTS and must share prop KEYS. A one-off gets its own family\n plus \\`allowedOn: [\"slug:<page>\"]\\`. Start from the \\`builtin:*\\` blueprints in\n \\`list_components\\`. On a DERIVED site (\\`editor_setup\\` derives it) run \\`get_componentize_plan\\` →\n \\`componentize_sections\\` first (dryRun first, and confirm the plan with the user).\n3. **Hierarchy** = \\`group\\` on create_component/update_component (a NAME; created when missing).\n Use Global, Navigation, Actions, Content, Forms, Media, Sections, Page-specific. \\`category\\`\n is the separate picker TAB.\n4. **Fields** = \\`props\\`: text, richtext, image, url, boolean, number, select, group, table, slot.\n Always a \\`defaultValue\\`; \\`helpText\\` / \\`placeholder\\` are editor hints. A placement you SET empty on a\n \\`required\\` prop is refused (\\`required_value\\`). \\`select\\` for styling-only variants, a separate component when the markup\n differs. Nesting goes up to 10 levels; a \\`table\\` row may hold a data table or a polymorphic list.\n5. **Quality.** The componentize lane and \\`npx @bettercms-ai/convert --componentize\\` move markup\n VERBATIM — classes, responsive utilities, aria attributes, alt text all survive. Never\n restyle. Dry-run first.\n6. **Validation** = \\`get_site_composition\\`: every page's placements, each component's status,\n and \\`verdict.everyPageComposed\\` with its reasons. Publishing needs the OWNER's approval in\n the dashboard (evidence via \\`request_component_validation\\` and a run in the repository), then\n \\`publish_components\\`. No tool here can grant that approval, and there is no bulk approve.\n\n**Order:** get_site_composition → (get_componentize_plan → componentize_sections) →\ncreate_component per uncovered section → compose_pages → update_layout { commands } → evidence + owner approval →\npublish_components → publish the pages / publish_layout → get_site_composition → get_next_steps.\nPrefer the batch tools whenever there is more than three of anything.`;\n\nconst LAYOUT_FLOW = `### Project/page Layout authoring → \\`get_layout\\` / \\`update_layout\\` / \\`publish_layout\\`\nEdit the project's draft Global Layout or one page's draft override. \\`update_layout\\` never\nchanges the live site; \\`publish_layout\\` takes the Global Layout draft live (page overrides go\nlive with their page). Until it is called, site chrome you authored is NOT on the live site.\n1. **Read first** — call \\`get_layout\\` with scope \\`global\\`, or scope \\`page\\` + pageId.\n Keep the returned \\`revision\\`; every write must pass it as \\`ifMatch\\`.\n2. **Choose one discriminated command type** — the server derives its authority family;\n callers cannot claim a weaker family for a schema or composition mutation.\n3. **Apply one canonical command** with \\`update_layout\\`, then use the returned revision for\n the next command. A 409 means somebody else edited it: re-read; never blindly retry.\n4. Direct fields are headless data. Only Component items render markup. Navigation/Footer\n are reserved Sections and cannot be deleted or moved; page overrides may inherit,\n override content, customize structure, or disable them.\n5. Read Component/Variant identities before attaching or swapping. Required values and\n bindings must be complete before a human publishes from the dashboard.`;\n\nconst BUILD_SITE_FLOW = `### Build a whole site (schema → pages → AI copy) → composes the flows below\nEnd-to-end authoring from a repo or a brief. Confirm-first at every stage.\n1. **Schema** — run the whole-project schema design above: propose the page/zone/field tree,\n get the user's approval, then \\`create_page\\` per page.\n2. **Copy** — for each page/entry, draft the real text with \\`write_content\\` (action 'write',\n pass the section as the brief + the page title as \\`context\\`). Review with the user, then\n apply via \\`set_page_content\\` / \\`create_content_entry\\` / \\`update_content_entry\\`.\n3. **SEO** — run the SEO flow to fill metaTitle/metaDescription for each page.\nNever invent brand facts — ask the user for anything the repo/brief doesn't state.`;\n\nconst LANDING_PAGES_FLOW = `### Generate landing pages (programmatic SEO / ABM) → \\`generate_pages_from_dataset\\`\nSpin up many pages sharing one template, each personalized per row (company, keyword, persona).\n\nFor an ABM campaign — a page per NAMED COMPANY — the whole flow is eight steps, in this order:\n1. **Research** — \\`research_account\\` per account, or set \\`mapping.campaign.research\\` and let the\n run do it ('lite' reads the company's own site, 'deep' searches the web, 'agent' hands the work\n to YOU through \\`claim_abm_task\\` / \\`complete_abm_task\\`).\n2. **Generate** — \\`generate_pages_from_dataset\\` with \\`mapping.campaign = { id, research,\n externalKeyColumn: 'domain' }\\`. It fans out across every page the campaign owns and parks for\n approval. Re-running the same export UPDATES each account's page rather than duplicating it.\n3. **Approve the job** — \\`approve_ai_job\\`, only once the user has said yes.\n4. **Review** — \\`get_campaign_review\\` with \\`sample: 5\\`, then \\`filter: 'flagged'\\`. A flag reads\n \\`unsupported_claim:headline\\`: a figure that is in none of the account's own facts, so the field\n fell back to the blueprint's copy. \\`filter: 'failed'\\` lists rows that produced no page at all.\n5. **Regenerate** — \\`regenerate_entry\\` with an instruction, one row at a time.\n6. **Approve entries** — \\`approve_campaign_entries\\`; \\`'all_unflagged'\\` clears the rest in one call.\n A FLAGGED page must be named explicitly: approving one says a person checked the claim.\n7. **Publish** — \\`publish_campaign\\` with \\`confirm: true\\`. It refuses \\`entry_flagged\\` while any\n page carries an unresolved flag, and \\`blueprint_missing_disclaimer\\` if a page has lost its\n \"not affiliated with\" band. The user decides this step, never you.\n8. **Share** — \\`get_campaign_share_link\\` for a link a rep can send before publishing.\n\nFor a plain programmatic-SEO run (a page per keyword, no named companies) the same tool works\nwith no \\`campaign\\`, and \\`write_content\\` + \\`create_content_entry\\` per row is still fine for a\nhandful. ALWAYS dry-run first and show the sample.`;\n\nconst SEO_FLOW = `### Optimize SEO → \\`generate_seo_meta\\` + the page/entry update tools\nFill or refresh SEO metadata across the site.\n1. **Target** — pick the pages/entries (\\`list_pages\\` / \\`list_content_entries\\`); confirm scope with the user.\n2. **Per target** — read its content (\\`get_page\\` / \\`get_content_entry\\`), call \\`generate_seo_meta\\` with that\n content as \\`text\\`, review the suggested metaTitle/metaDescription/keywords, then apply it via\n the page/entry update tools (or the dashboard SEO fields).\nKeep titles ~60 chars and descriptions ~155; don't overwrite good existing meta without asking.`;\n\n// ── Registration ─────────────────────────────────────────────────────────────\n\nexport function registerPrompts(server: McpServer): void {\n // Parent router — the generous entry point.\n server.registerPrompt(\n \"studio\",\n {\n title: \"BetterCMS Studio (guided)\",\n description:\n \"One command to author in BetterCMS. Detects what you want — create a page, add a field, create an entry — and runs the matching guided flow, then calls the right tool.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"what you want to do, e.g. 'a blog page with a hero zone'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `You are the BetterCMS authoring assistant (via the bettercms MCP).\n${request ? `The user's request: \"${request}\".\\n` : \"\"}\nFirst, **preflight**: confirm the bettercms tools are loaded (\\`create_page\\`, \\`add_field\\`,\n\\`create_content_entry\\`). If \\`create_page\\` is missing and only \\`create_model\\` shows, the host has a\nstale cached MCP — tell the user to run \\`rm -rf ~/.npm/_npx\\` and restart, then stop.\n\nThen **route** to the matching sub-flow below based on the request and conversation\ncontext. DEFAULT: when setting up a project or designing its schema from the repo (or\nwhen intent is unclear), run the **whole-repo schema design** flow — it proposes the\nstructure and confirms with the user before creating anything. Use the single-page or\nsingle-field flows only for targeted follow-ups. If still unsure, ask the user\n(AskUserQuestion: \"Design the schema from my project\" / \"Create one page\" / \"Add a field\" /\n\"Create an entry\" / \"Build a form\" / \"Build a component\"). Run flows by asking ONE step at\na time, pre-filling sensible defaults from the request but never inventing fields the user\ndidn't imply. Whatever the page/zone/form/component is scoped to follows the MCP key's project.\n\n${SCHEMA_PROPOSAL_FLOW}\n\n${PAGE_FLOW}\n\n${FIELD_FLOW}\n\n${ENTRY_FLOW}\n\n${FORM_FLOW}\n\n${COMPONENT_FLOW}\n\n${COMPONENTIZE_SITE_FLOW}\n\n${LAYOUT_FLOW}\n\n${BUILD_SITE_FLOW}\n\n${LANDING_PAGES_FLOW}\n\n${SEO_FLOW}\n\nThis assistant is extensible: when new BetterCMS tools are added, a new sub-flow appears\nhere — route to it the same way.`,\n },\n },\n ],\n }),\n );\n\n server.registerPrompt(\n \"edit_layout\",\n {\n title: \"Edit project or page Layout (guided)\",\n description:\n \"Safely edit a draft Global Layout or page override with optimistic locking. Publishing remains in the dashboard.\",\n argsSchema: {\n request: z.string().optional().describe(\"what to change, e.g. 'disable the footer on the pricing page'\"),\n },\n },\n ({ request }) => ({\n messages: [{\n role: \"user\",\n content: {\n type: \"text\",\n text: `Edit the BetterCMS Layout draft.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${LAYOUT_FLOW}\n\nReport which scope changed and the new revision. Remind the user that publishing is a separate dashboard action.`,\n },\n }],\n }),\n );\n\n // Direct entry point for whole-repo schema design (the confirm-first default).\n server.registerPrompt(\n \"propose_schema\",\n {\n title: \"Design schema from repo (confirm-first)\",\n description:\n \"Read the repository, propose a destructured content schema (pages → group/repeater zones → nested fields), confirm it with you, then create it via create_page. Use this to set up a project's schema.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"optional focus, e.g. 'just the marketing pages' or 'the whole site'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Design the BetterCMS content schema for this repository.${\n request ? ` Focus: \"${request}\".` : \"\"\n }\n\nPreflight: if \\`create_page\\` isn't available (only create_model/add_field/create_content_entry),\nthe host has a stale cached MCP — tell the user to \\`rm -rf ~/.npm/_npx\\` and restart, then stop.\n\n${SCHEMA_PROPOSAL_FLOW}\n\nAfter creating, report each page's id, path, type, and field count, and the project it\nlanded in. On 409 slug_taken, offer an alternative slug; on 401/403, the MCP key needs\n(re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for the page flow (parent can also dispatch here).\n server.registerPrompt(\n \"new_page\",\n {\n title: \"New page (guided)\",\n description:\n \"Guided creation of a BetterCMS page (singleton or dynamic) with fields, including nested group (Non-Repeatable Zone) and repeater (Repeatable Zone) fields. Calls create_page.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"what the page is, e.g. 'a blog page with a hero'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Create a BetterCMS page via the \\`create_page\\` tool.${\n request ? ` The user wants: \"${request}\".` : \"\"\n }\n\nPreflight: if \\`create_page\\` isn't available (only create_model/add_field/create_content_entry),\nthe host has a stale cached MCP — tell the user to \\`rm -rf ~/.npm/_npx\\` and restart, then stop.\n\n${PAGE_FLOW}\n\n${STRUCTURE_RULE}\n\nAfter creating, report the page id, path, type, field count, and the project it landed in.\nOn 409 slug_taken, offer an alternative slug; on 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for form authoring.\n server.registerPrompt(\n \"new_form\",\n {\n title: \"New form (guided)\",\n description:\n \"Guided creation of a BetterCMS form (fields + settings) you can embed with <BcmsForm>. Calls create_form.\",\n argsSchema: {\n request: z.string().optional().describe(\"what the form is, e.g. 'a contact form with name, email, message'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Author a BetterCMS form via the \\`create_form\\` tool.${\n request ? ` The user wants: \"${request}\".` : \"\"\n }\n\n${FORM_FLOW}\n\nAfter creating, report the form id and name, and how to embed it (\\`<BcmsForm form={getForm('Name')} />\\`).\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for component authoring.\n server.registerPrompt(\n \"new_component\",\n {\n title: \"New component (guided)\",\n description:\n \"Guided creation of a reusable BetterCMS component (a blockJson tree + overridable props) you render with <BcmsBlocks>. Calls create_component.\",\n argsSchema: {\n request: z.string().optional().describe(\"what the component is, e.g. 'a hero with heading, text and a button'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Author a reusable BetterCMS component via the \\`create_component\\` tool.${\n request ? ` The user wants: \"${request}\".` : \"\"\n }\n\n${COMPONENT_FLOW}\n\nAfter creating, report the component id, name, and slug, and how to render it (\\`<BcmsBlocks>\\`).\nOn 409 slug_taken, offer an alternative slug; on 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // The whole-site componentization ask. A direct entry point because the request arrives as one\n // sentence (\"componentize the whole site\") and used to route to §13 — bindings — which makes a\n // site editable in place and never builds the component library the user asked for.\n server.registerPrompt(\n \"componentize_site\",\n {\n title: \"Componentize the entire website (guided)\",\n description:\n \"Turn every section of a site into a reusable component, organised into groups editors can browse: audit with get_site_composition, create the components in one call, compose every page, then publish what the owner has approved.\",\n argsSchema: {\n request: z.string().optional().describe(\"scope or emphasis, e.g. 'marketing pages only'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Componentize this entire website in BetterCMS.${request ? ` Scope: \"${request}\".` : \"\"}\n\n${COMPONENTIZE_SITE_FLOW}\n\n${STRUCTURE_RULE}\n\nLast, before the summary: ${DOCK_UI_STEP}\n\nConfirm the component library with the user before creating it. End with the summary §12 asks\nfor: the group hierarchy, each family and its variants, what you left in the site's code because\nthe platform does not model it, and which components are still waiting for the owner's approval\nin the dashboard — those render as an empty string until they are published.`,\n },\n },\n ],\n }),\n );\n\n // The whole-site conversion ask, and the one prompt the dashboard launcher names. Its whole\n // job is that the agent does not stop early: the loop is written as a loop.\n server.registerPrompt(\n \"convert_site\",\n {\n title: \"Convert a site so nothing is left pending (guided)\",\n description:\n \"Run the conversion end to end: pull the source, run @bettercms-ai/convert, apply every fix it lists as pending, rerun until nothing is pending, and finish only when submit_conversion_receipt returns complete and get_binding_report reads unmatched 0, coverage.pending empty and every route's unaddressable under 2%.\",\n argsSchema: {\n projectId: z.string().optional().describe(\"the project to convert; omit if this connection is scoped to one\"),\n },\n },\n ({ projectId }) => ({\n messages: [{ role: \"user\", content: { type: \"text\", text: CONVERT_SITE_TEXT(projectId) } }],\n }),\n );\n\n // Direct entry point for end-to-end site authoring (schema → pages → AI copy → SEO).\n server.registerPrompt(\n \"build_site\",\n {\n title: \"Build a site (guided, end-to-end)\",\n description:\n \"Author a whole BetterCMS site from a repo or a brief: design the schema, create the pages, draft the copy with AI (write_content), and fill SEO (generate_seo_meta).\",\n argsSchema: {\n request: z.string().optional().describe(\"what to build, e.g. 'a SaaS marketing site from this repo'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Build a BetterCMS site end-to-end.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${SCHEMA_PROPOSAL_FLOW}\n\n${BUILD_SITE_FLOW}\n\n${STRUCTURE_RULE}\n\n${SEO_FLOW}\n\nConfirm each stage with the user before writing. On 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for programmatic-SEO / ABM landing-page generation.\n server.registerPrompt(\n \"generate_landing_pages\",\n {\n title: \"Generate landing pages (programmatic SEO / ABM)\",\n description:\n \"Spin up many personalized landing pages from one template + a dataset. For ABM (a page per named company) this is the research -> generate -> review -> approve -> publish -> share order.\",\n argsSchema: {\n request: z.string().optional().describe(\"the campaign, e.g. 'a page per target company for our ABM push'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Generate programmatic landing pages.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${LANDING_PAGES_FLOW}\n\n${STRUCTURE_RULE}\n\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for an SEO metadata pass.\n server.registerPrompt(\n \"seo_optimize\",\n {\n title: \"Optimize SEO (guided)\",\n description:\n \"Generate and apply SEO metadata (title, description, keywords, JSON-LD) across pages/entries with generate_seo_meta.\",\n argsSchema: {\n request: z.string().optional().describe(\"scope, e.g. 'all blog posts' or 'the home page'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Optimize SEO metadata.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${SEO_FLOW}\n\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // FLO-1178 agent-import: the sequence that turns a LIVE imported site into an EDITABLE one.\n // A deploy alone leaves every trap in place — content only in the build (nothing binds),\n // no presentation manifest (generic previews), unpublished components (render as nothing).\n // This prompt is the ordered walk out of all three, mirroring playbook §11.\n server.registerPrompt(\n \"import-site\",\n {\n title: \"Make an imported site editable (guided)\",\n description:\n \"After importing or deploying an existing site: run the editor setup, componentize or convert it, declare its presentation manifest, and publish everything that renders. A build makes a site LIVE, not EDITABLE — this flow closes that gap.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"scope, e.g. 'all routes' or 'just the home page'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Make my imported site editable in BetterCMS.${request ? ` Scope: \"${request}\".` : \"\"}\n\nRead bettercms://playbook/schema section 11 first, then work this order:\n\n1. EDITOR SETUP — the build imported only SEO/meta, media, brand and the models the repo\n declares. Call editor_setup and poll editor_setup { check: true } until \\`ready\\`: it derives\n the pages, collections, forms and bindings from the live build.\n2. AUTHORING GATE — if get_next_steps or a deploy (409 AUTHORING_DECISION_REQUIRED) asks,\n ask ME components-or-fields (do not choose), then set_authoring_preference.\n3. COMPONENTS: get_componentize_plan -> componentize_sections (dryRun first) -> publish the\n components and pages -> componentize_sections { codemod: true } (the section-order codemod in\n the repo). FIELDS: the convert_site loop (get_conversion_brief, the codemod, the receipt).\n Only where the setup derived nothing: create_page (slug = route) -> add_field {pageId} ->\n set_page_content with values EXACTLY equal to the rendered text (binding matches by value; a\n paraphrase binds nothing) -> update_page status 'published'.\n4. PRESENTATION MANIFEST — add bcms-presentation.json to public/ (container width, type\n scale, nav position/background, footer surface as DTCG {\"$type\",\"$value\"} entries) and\n redeploy, or structural draft previews render in a generic theme, not this site's design.\n5. ${DOCK_UI_STEP}\n6. VERIFY — call get_next_steps and fix what it lists (it knows about missing manifests,\n a setup that has not run, and placed-but-unpublished components). You are finished only\n when its receipt.complete is true: run receipt.gate.nextAction, read it again after each\n batch, and record an item you cannot close with editor_setup { exempt } only under an allowed\n reason that is true. Telling me why is not an exception.\n\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // The editor-chrome lane. `ui`/`helpText`/`showIf` are declarable on every field-creating\n // tool, but an agent that does not know they exist writes a schema whose repeaters read\n // \"Item 1 … Item 10\". This prompt is the 3-tier rule as a slash command.\n server.registerPrompt(\n \"field-ui\",\n {\n title: FIELD_UI_PROMPT.title,\n description: FIELD_UI_PROMPT.description,\n argsSchema: { request: z.string().optional().describe(FIELD_UI_PROMPT.request) },\n },\n ({ request }) => ({\n messages: [{ role: \"user\", content: { type: \"text\", text: FIELD_UI_TEXT(request) } }],\n }),\n );\n}\n","/**\n * How to design a BetterCMS project — ONE copy, read by both MCP surfaces.\n *\n * WHY IT LIVES HERE AND NOT IN THE BACKEND. `packages/mcp` is a published npm package:\n * tsup bundles `src/index.ts` and externalises only the sdk/mcp-sdk/zod, so an import\n * reaching into backend `src/` would drag Hono, Drizzle and Postgres into the tarball.\n * The backend has no such constraint and already imports from this package (see\n * `src/__tests__/mcp/mcp-parity.test.ts`), so the dependency points backend -> package.\n * This module is deliberately dependency-free strings for exactly that reason.\n *\n * WHY A RESOURCE AND NOT A TOOL DESCRIPTION. Every tool's schema rides in the prompt on\n * every step of every turn; a resource is fetched once, on demand, by a client that wants\n * it. Long-form guidance in a description is a tax on all 82 tools forever. So the\n * remote host serves this at `bettercms://playbook/schema` and MCP_INSTRUCTIONS points at\n * it, while the stdio package folds it into its guided prompts.\n *\n * WHAT IT HAD TO FIX. The previous guidance was page-first: it mapped a site to pages,\n * groups and repeaters and never mentioned components, `sectionType` variants,\n * `kind:'block'` + `modular`, or the `document` body — so an agent asked for \"a marketing\n * site with a blog\" built a pile of flat page fields and a richtext box.\n */\n\nexport const PLAYBOOK_URI = \"bettercms://playbook/schema\";\n\nexport const SCHEMA_PLAYBOOK = `# Designing a BetterCMS project\n\nRead this BEFORE creating anything. Confirm the shape with the user before you build it.\n\n## 1. Pick the architecture first\n\n**Components-first** — a marketing site. A library of reusable *components*, each a\nsection, and thin pages that place them. Editors add, reorder and swap sections without\ntouching a schema. This is what \\`create_component\\` + \\`create_page(blockJson)\\` are for.\n\n**Schema-first** — a blog, a product catalogue, a directory: many rows sharing one shape.\nA collection (\\`create_content_model\\`) plus entries.\n\nMost real sites are both: components for the marketing pages, a collection for the blog.\nDecide before your first call; converting later means rewriting content — unless the site was\nDERIVED by \\`editor_setup\\`, where the componentize lane in §10 reuses every field.\n\n## 2. The decision tree\n\n Designing ANY section? -> FIRST find its closest kit entry in bettercms://kit\n (by category, then edge tag); follow that entry's\n mcp notes and avoid its pitfalls (tag rules below).\n Its props carry NO target: give each one a target\n into YOUR blockJson (§3) before create_component\n Every component names its kitEntry\n (bettercms://kit/entry/{id}). The import's entry\n is only a SUGGESTION: check its htmlSignals and\n pitfalls, confirm or replace it (update_component\n kitEntry rebuilds the derived ui and carries its\n rules; a gate.kit drift row lists rules still missing); exempt with no-kit-match or kit-drift-accepted only with a note\n Repeated visual region on a page? -> a COMPONENT with sectionType (a Section)\n ...and it comes in more than one look? -> siblings sharing that sectionType = VARIANTS\n A stack of mixed, reorderable content? -> kind:'block' models + a \\`modular\\` field\n A row in a list (post, author, tier)? -> a collection (kind:'model'); rows one template\n route renders get urlPattern, e.g. '/blog/:slug'\n Copy for ONE page (home, about, legal)?-> page fields in sections (add_field {pageId} /\n set_page_content) — never a one-entry collection\n The one body of an article? -> type:'document' (exactly one, top level)\n A fixed cluster of fields? -> group (never a 1-item repeater)\n A repeating cluster? -> repeater\n A list of plain strings? -> array (never a repeater of one text)\n A call to action (words + link)? -> ONE \\`button\\` field {label, href, variant?, size?,\n arrow?, icon?, newTab?} — never text + link fields\n (in a component: a \\`button\\` block, §3)\n A link to a page or CMS item? -> a \\`link\\` value {type:'page'|'entry', href, ref:<id>}:\n the write checks ref, delivery resolves it;\n a plain href string stays valid\n Site-wide nav/footer/modal? -> the LAYOUT (get_layout/update_layout), never a\n page section and never one component per page\n\nKit edge tags, one rule each (long form with entry ids: the skill's kit-scenarios reference):\n\n deep-nesting levels = content kinds, not wrappers; past 6, split the deepest subtree out\n repeater one band holds the list; never store what order says (step no., totals)\n polymorphic-array each item names its _type; merge consecutive prose into one text item\n slots children differ in shape; span/surface/phone order go in slotSettings\n variants column count, side, carousel = a variant, never a free number or boolean\n conditional a select reveals one branch; fill only it (hidden values still publish)\n references reference the entry/product/page; store only what differs as overrides\n dynamic-query store collection + filters + sort + limit; import the items as entries first\n global-synced same on ~80% of pages = one global; an instance overrides only what differs\n localized match locales by position, never text; never translate on import; no hreflang\n rich-text one body; callouts, tables, media, instances are islands; no h1, no chrome\n media-heavy largest source, real alt, video poster + caption file, positions in %\n embed store provider + id or canonical URL, never the script; iframes need a title\n form a Form reference by id; never the inputs copied into the section\n commerce the store owns price, stock, SKU, options, cart: reference, never copy\n personalization only with evidence; complete default, audiences hold only the differences\n validation numbers as numbers, datetimes with offset; check cross-field rules on import\n a11y every visual-only element gets text: logo name, pin label, iframe title\n seo-structured JSON-LD is emitted from content; never model meta or JSON-LD fields (§5b)\n responsive-layout per-breakpoint values as settings that inherit desktop; spacing as tokens\n\n## 3. Anatomy of a real section component\n\nA component that is only headings and text renders as an unstyled stack — plain text on white\nin a 768px column, on the live site AND in the visual editor. Every section the product ships\nlooks like this — a \\`section\\` block carrying \\`style\\`, with content nested in\n\\`props.children\\`. \\`create_component\\` and \\`update_component\\` return a \\`warnings\\` entry when a\nSection's root section has no \\`style\\`; treat it as a defect, not a note:\n\n {\n type: \"section\", id: \"root\",\n style: { bg: \"surface\", paddingTop: 96, paddingBottom: 96, contentWidth: \"default\", align: \"center\" },\n props: { children: [\n { type: \"heading\", id: \"h\", props: { text: \"Headline\", level: 2 } },\n { type: \"text\", id: \"sub\", props: { html: \"<p>Supporting copy.</p>\" } },\n { type: \"button\", id: \"cta\", props: { text: \"Get started\", href: \"/signup\", variant: \"primary\" } }\n ] }\n }\n\n\\`style\\` takes the design tokens the editor's dock sliders and pickers write: \\`theme\\`, \\`bg\\` /\n\\`bgCustom\\` / \\`bgImage\\` (an image url), \\`spaceTop\\` / \\`spaceBottom\\` / \\`spaceSides\\` (token steps,\nwinning over the \\`padding*\\` pixels), \\`contentWidth\\`, \\`contentAlign\\`, \\`opacity\\` (0–100), \\`corner\\`,\n\\`shadow\\`, \\`border\\` / \\`borderTop\\` / \\`borderBottom\\`, and on a button \\`hover\\` { bg, bgCustom, textColor,\nborder }.\n\nThen declare what an editor may change, via \\`props\\`:\n\n props: [\n { key: \"headline\", label: \"Headline\", target: { blockId: \"h\", path: \"props.text\" }, type: \"text\" },\n { key: \"body\", label: \"Body\", target: { blockId: \"sub\", path: \"props.html\" }, type: \"richtext\" },\n { key: \"ctaHref\", label: \"CTA link\", target: { blockId: \"cta\", path: \"props.href\" }, type: \"url\" }\n ]\n\nEach prop also takes \\`required\\`, \\`helpText\\` (≤ 200 chars) and \\`placeholder\\` (≤ 120), which the\ndashboard's prop editor renders. \\`helpText\\` is three-state: a string is yours, \\`null\\` is no help on\npurpose (send it for a prop whose /kit schema has no description; nothing refills it), and omitted\nlets the platform write one. They are HINTS: nothing on the write path refuses a placement\nthat leaves a required prop empty, so \\`get_site_composition\\` is what reports one.\nA /kit schema's document-level \\`preview\\` → the component's \\`preview\\`: how ONE instance reads as a ROW in a parent's slot list. {title?, subtitle?, media?} each name a TOP-LEVEL prop key or a dotted path into one (\\`slides.0.heading\\`; 422 \\`preview_key_unknown\\` otherwise), \\`fallback?\\` is a literal row label (≤ 120) and \\`icon?\\` a dock icon name; null clears it.\nA /kit schema's document-level \\`icon\\` → the component's \\`icon\\` (a dock icon name from bettercms://icons/dock, null clears): the block icon on the root crumb, slot rows and slot child frames.\nA /kit schema's \\`groups\\` → each prop's \\`ui.tab\\` (defined on the first top-level prop in it; a nested field's \\`group\\` → its \\`ui.tab: {id}\\`); a group NO top-level prop sits in → the component's \\`tabs\\` ([{id, label, icon?, order?}], 422 \\`component_tab_invalid\\` for a prop's own tab). A slot's \\`of.allow\\` → \\`config.allow\\` (block names); a scalar list's item settings (\\`of[0]\\` validation, description, localized) → \\`config.item\\`.\n\n**Prop types, one rule each.** 'select' REQUIRES \\`config.options\\` (a default must be one of them). 'group'/'table'/'object' REQUIRE \\`config.fields\\` (\\`[{key,label,type,options?,fields?}]\\`); a group writes an object, a table an array of them (\\`config.mode: 'data'\\`: ONE V2 table value, no fields). 'number' takes optional \\`config.min/max/step\\`. 'slot' holds ONE nested component instance: \\`target.path: 'props'\\` on an EMPTY component block (\\`props.componentId: \"\"\\`), \\`config.componentIds\\` restricts fills, defaultValue \\`{componentId, overrides?}\\`. 'form' holds ONE Form document: \\`target.path: 'props'\\` on an EMPTY form block (\\`props.formId: \"\"\\`), defaultValue \\`{formId}\\`, never the hydrated \\`{formId, form}\\` (400); do NOT re-declare the form's FIELDS as props, the Form document owns them. '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).\n\n🔴 **On a components-first page, \\`props\\` is the ONLY editing surface.** Click-to-edit binds\n\\`heading\\`/\\`text\\`/\\`button\\`/\\`image\\` blocks; it does **not** bind a \\`component\\` block, because\na component's blocks belong to the shared definition, not to the instance. So a page built\nfrom \\`component\\` blocks renders correctly and emits ZERO fields on the canvas — editing goes\nthrough the declared props allowlist to per-instance overrides. **A component with no props\nis a section nobody can change.** Declare a prop for every string, link and image a marketer\nwould ever reasonably want to touch; leave out only structure and styling.\n\n## 4. Variants\n\nComponents sharing a \\`sectionType\\` are swappable layouts of one section family — \"Hero\ncentered\" and \"Hero split\" both with \\`sectionType: \"Hero\"\\`. Swapping is one write and\nkeeps content, because overrides are keyed by prop KEY.\n\nSo **use the same prop keys across a family**. A variant that calls it \\`title\\` where its\nsibling calls it \\`headline\\` silently drops that content on the swap.\n\nPair \\`sectionType\\` with a library \\`category\\` (hero, content, social-proof, conversion) or\nthe component never appears in the editor's \"Add a section\" picker.\n\n**An IMPORTED site gets there without you writing any of that.** Its pages are derived by\n\\`editor_setup\\` — flat field groups (\\`hero-title\\`, \\`faq-question\\`, the repeaters folded as \\`group-*\\`)\nand an empty \\`blockJson\\` — so there is nothing in the picker and no section to swap. Read\n\\`get_componentize_plan\\`: it groups those fields into sections, names each family, and proposes\none component per SHAPE (the same hero on two pages is one component with two placements),\nwith every string, link and image already declared as a prop. Show the user the plan and\n**confirm before writing**, then \\`componentize_sections { digest, dryRun: true }\\` and, once the\nreceipt reads right, without \\`dryRun\\`. Each page's blocks become ordered \\`component\\`\ninstances carrying \\`props.bind\\` — the field group keeps the copy, so nothing moves and\nclick-to-edit keeps working. Pass \\`copy: \"instance\"\\` instead when the INSTANCE should own its\nwords (the page-builder model): each placement takes that group's current values into\n\\`props.overrides\\`, records where each came from in \\`props.source\\`, and the page's fields are\nkept and marked \\`origin: \"componentized\"\\` so the editor stops offering a second place to type\nthem. Either way, running it again converts nothing and duplicates nothing. Then run \\`npx @bettercms-ai/convert --componentize\\` in the repo\nso its templates render those sections from \\`pages[].blocks\\`, and finish with the publishes:\n\\`publish_component\\` every new component, \\`publish_layout\\` if you touched site chrome (nav,\nfooter), and publish the pages, or the site renders the sections as empty strings.\n\n## 5. Blocks and modular fields\n\nA \\`kind:'block'\\` model holds no entries of its own; it exists to be stacked inside another\nmodel's \\`modular\\` field. Create the blocks FIRST, then name their slugs (not ids) in\n\\`config.blockSlugs\\`. This is the page-builder shape: one \\`sections\\` field holding an\nordered list of typed blocks.\n\nA \\`slot\\` field (V2 blocks inside a block) takes the same \\`config.blockSlugs\\` (plus\n\\`minItems\\`, \\`maxItems\\` and \\`slotSettings\\`, leaf fields each child's \\`_settings\\` holds),\nbut stores each child INLINE: \\`[{ _key, _type: '<block slug>', _variant?, _settings?, ...values }]\\`,\nits values judged by its block's fields. A component's \\`slot\\` prop with \\`config.multiple\\`\ntakes the same child shape with \\`_type\\` the COMPONENT id (no \\`_variant\\`: a variant is its own\ncomponent). A \\`slot\\` may also be a SUB-FIELD: inside a \\`group\\` / \\`object\\` prop's\n\\`config.fields\\` or a \\`table\\` row (an item type's \\`fields\\` too), with the slot prop's\nconfig keys (\\`componentIds\\`, \\`multiple\\`, \\`minItems\\`/\\`maxItems\\`, \\`slotSettings\\`). Its value\nsits at its key in the object or row, \\`{ componentId, overrides? }\\` or a list with\n\\`config.multiple\\`, judged like a slot prop's: the same allowlist, depth cap and cycle refusal.\nA list of several item shapes on a component is a \\`table\\` prop with\n\\`config.mode: 'types'\\` and \\`config.itemTypes: [{ name, label?, fields, preview?, icon? }]\\`, rows\n\\`[{ _key?, _type: '<name>', ...values }]\\`. An item type's \\`preview\\` names its OWN fields (dotted ok, \\`<table>.caption\\`).\n\n**Block props by type** (a block's \\`props\\` in any \\`blockJson\\`): heading {text, level 1-6}; text/richtext {html} (NOT {text}), both also take level 1-6, rendering the html AS that <hN> with inline marks kept (one line of inline copy only); image {src (asset url), alt, caption?}; button {text, href, variant (hosted pages; else a Button component), size sm|md|lg, fullWidth, arrow, icon (a ui.icon name), newTab, rel nofollow|sponsored|ugc}; spacer {height px}; video {url, poster?}; form {formId}; component {componentId, overrides?}; navbar {links:[{label,href}], logo?, cta?}; footer {columns:[{heading?,links}], copyright?}; section {children: block[], background?, paddingY?, maxWidth?}; columns {columns: block[][], gap} (a column may hold ANY block); slider {slides:[{id,children:block[]}]}; tabs {tabs:[{id,label,children:block[]}]}; collection {cardComponentId?, source? {modelId}, limit?, filters?, sort?, pinnedIds?, excludeCurrent?}: a collection's published entries as cards. Containers nest blocks to any depth.\n\nA component inside a \\`richtext\\` value is \\`{ _type: 'bcmsBlock', _key, schemaKey: 'component',\nschemaLabel?, fields: { componentId, overrides?, variant? } }\\` and FOLLOWS the component: publishing\nit changes this place. A SEPARATE COPY stops following it: \\`fields: { componentId, detached: true,\nprops, blocks, sourcePublishedAt, variant? }\\`, exactly as \\`get_component { componentId,\ndetachedCopy: { overrides } }\\` returns them. It renders its own \\`blocks\\`; \\`componentId\\` stays so\nit can be linked again (write the linked shape), and a \\`sourcePublishedAt\\` older than the\ncomponent's \\`lastPublishedAt\\` (every publish; \\`publishedAt\\` is the first) means the shared\nversion changed since. Refused by name:\n\\`component_copy_invalid\\`, \\`component_copy_not_frozen\\`.\n\n## 5b. NEVER MODEL SEO. It is native.\n\nDo not create \\`seoTitle\\`, \\`metaTitle\\`, \\`metaDescription\\`, \\`ogImage\\`, \\`canonicalUrl\\`,\n\\`noindex\\` or an \\`seo\\` group on ANY model, page or component. Every one of those already\nexists on the platform:\n\n per page metaTitle, metaDescription, schemaType, schema — set with update_page\n per entry metaTitle, metaDescription, noindex, canonical, og, twitter, schemaType,\n schema — set with update_content_entry \\`meta\\` (merges; null clears a key)\n page head extras noindex, canonical, og, twitter — set with update_page (merges; null clears)\n site-wide defaults get_seo / update_seo — { metaTitle, metaDescription, ogImage, twitterHandle }\n generated for you generate_seo_meta\n audited for you list_seo_issues\n\nA modelled copy does not add a capability, it adds a SECOND place the same fact lives — and the\ntwo immediately disagree. The native fields are what the renderer emits into \\`<head>\\`, what\nsitemap and llms.txt read, and what \\`list_seo_issues\\` scans; a field called \\`seoTitle\\` on a\nmodel is a string an author edits that changes nothing on the page. It is worse than useless:\nit looks like the control and is not.\n\nIf a page needs its own meta, set it on the page. If the whole site needs a default, set it with\nupdate_seo. If you want it written for you, call generate_seo_meta and apply the result.\n\nThe one legitimate exception is a field that is genuinely CONTENT and happens to be used in meta\ntoo — a blog post's \\`excerpt\\`, an article's \\`coverImage\\`. Model those as content, name them\nfor what they are, and let \\`generate_seo_meta\\` read them.\n\n## 6. Blogs\n\n author collection: name, avatar, bio\n blog-post collection: title, slug, excerpt, cover (image),\n body (document), author (reference -> author)\n\n\\`document\\` is THE article body: a rich document canvas on pages or collections, at most one\nper schema, top level only (never inside a group or repeater). It cannot coexist with a\nSection zone, which also owns the document canvas. Use \\`richtext\\` for a short formatted field,\n\\`longtext\\` for multi-line plain text.\n\nThen the pages:\n\n create_page slug:\"blog\" pageType:\"dynamic\" fields:[...the post schema...]\n blockJson: [ heading, { type:\"collection\", id:\"list\", props:{} } ]\n\nNever put a \\`navbar\\` or \\`footer\\` block on a page: site chrome is the Layout (get_layout /\nupdate_layout), drawn around every page already, so a page copy duplicates it.\n\n create_content_entry per post, with pageId set to that page\n\nThe \\`collection\\` block is lane-aware: on \\`/blog\\` it renders a card per entry, and on\n\\`/blog/<slug>\\` it renders THAT entry. One page, both jobs. Every OTHER block in the array\nis interpolated per entry with \\`{{fieldKey}}\\` placeholders — \\`{{title}}\\`, \\`{{cover.url}}\\`,\n\\`{{body.html}}\\`. Note that richtext and document bind to \\`.html\\` only, never the bare name.\n\n## 7. Order of operations\n\n 1. blocks create_content_model kind:'block' (before anything references them)\n 2. collections create_content_model\n 3. components create_component (they land as DRAFTS)\n 4. publish publish_component <- every component you intend to place\n (409 COMPONENT_IMPLEMENTATION_NOT_READY: this exact variant still needs passing\n implementation evidence and a HUMAN's approval in the dashboard, which no tool\n can grant; relay the response's readiness to the user, never retry)\n 5. pages create_page with blockJson placing those components\n 6. content create_content_entry / set_page_content\n 7. publish update_page status:'published'\n 7b. layout publish_layout <- if you authored the Global Layout (nav/footer); page overrides publish with the page\n 8. check get_next_steps, and fix what it lists; on an imported site, until receipt.complete is true\n\n## 8. Two ways to ship a blank site\n\n**An unpublished component renders as an empty string.** Not an error, not a placeholder —\nnothing, on a page that returns 200. If a section is missing from the live site, check\n\\`publish_component\\` before anything else.\n\n**A workspace-level component (\\`projectId: null\\`) never reaches a live site.** It resolves\nin preview and is blank in production. Always pass the project's id.\n\n## 9. Check which project you are bound to, BEFORE you build\n\n\\`create_project\\` succeeds on a project-scoped connection and hands back a real new project\n— but every write that follows still lands in the project your grant is bound to.\n\\`projectId\\` is forwarded as a header for a workspace-scoped grant; a **project-scoped grant\naccepts it and ignores it**, silently. No error, no warning, wrong project.\n\nSo call \\`get_project\\` (no arguments) first — it reports the project you are actually\nwriting to.\n\n**If the grant covers the WHOLE WORKSPACE, that is not a blocker and there is nothing to\nstop for.** Pass \\`projectId\\` on every project tool — \\`list_projects\\` gives you the id, and\n\\`get_project { projectId }\\` confirms you are addressing the right site. Every tool takes it,\nincluding the code and deploy ones. Do NOT send the user to re-scope the connection; the only\nthing that genuinely blocks you is a grant on a different WORKSPACE, which is what an empty or\nforeign \\`list_projects\\` tells you.\n\nIf the connected project is simply the WRONG one for the work — a project-scoped grant pointed\nelsewhere — that is the case the user has to fix, in the BetterCMS dashboard under\n**Settings → Connected AI clients**. No tool can switch it.\n\nIf you must probe, probe with a \\`create_content_model\\` — models are deletable\n(\\`delete_content_model\\`, soft-delete) and **there is no \\`delete_component\\`**. A component\nwritten to the wrong project can only be demoted (\\`sectionType: null\\`) and left unpublished.\n\n## 10. You imported a site, or you are about to deploy one\n\n**A build imports what the build itself ships, and nothing more:** SEO and meta, every media\nasset, the brand, and the models the repository declares in \\`bcms-content.json\\`. Everything\nthat makes the site EDITABLE — pages, inferred collections, forms, bindings, button and section\ncomponents — is \\`editor_setup\\`, run on demand against the live build. The import recipe:\n\n import (import_github_repo / deploy_project) -> editor_setup (poll { check: true } until ready)\n -> the authoring answer -> componentize_sections, or get_conversion_brief (§13)\n -> the codemods (componentize_sections { codemod: true } runs the section-order one in the repo)\n -> submit_conversion_receipt / submit_componentize_receipt -> deploy\n\n\\`get_deploy_status\\` \\`editorSetup\\` (and get_next_steps) say when it has not run for the live\nbuild: \\`never\\` or \\`stale\\` → run it before anything below. It also fills missing meta from the\npages' own copy, merges components that are identical, and switches to declared bindings when the\nbuild proves every binding declared; get_next_steps lists only what it could not do.\n\n**Builds run \\`build:bcms\\` instead of \\`build\\`** when package.json declares one: the build alone,\nwithout CI checks (\\`\"build:bcms\": \"astro build\"\\` beside \\`\"build\": \"astro check && astro build\"\\`),\nkeeping any step the build needs. The convert codemod adds it; never edit \\`build\\` for BetterCMS.\n\n\\`deploy_project\\` and \\`promote_project\\` both answer **409\nAUTHORING_DECISION_REQUIRED** until a human has chosen this project's architecture. This is\nasked ONCE per project, ever. It is not an error to retry or route around: read the message\nout, let the user pick, call \\`set_authoring_preference\\`, then deploy again.\n\nUntil someone answers, \\`editor_setup\\` derives the pages but componentizes nothing (the\npreference is null). Once \\`components\\` is recorded, each \\`editor_setup\\` componentizes the\nderived pages' NEW sections in bind mode; \\`fields\\` stops it for good. And a run over the WHOLE plan splits a section component an earlier run placed on\n2 pages into one per page (the first page keeps it, the others get a clone), so two pages' heroes\nstop editing each other; a run narrowed to one page or section never splits.\n\nIt exists because an imported site arrives **field-driven whether anyone chose that or not**\n— a crawl-based import (Webflow, a starter, a template) emits pages with a typed field schema\nand an empty block tree, because that is all a crawl can infer. Nobody decided it. On a\nmarketing site it is the wrong answer. So the platform stops once, at the last moment it is\nstill cheap — and on a derived site that moment costs nothing, because the componentize lane\nbelow reuses every field \\`editor_setup\\` already derived.\n\n**Recommend \\`components\\`.** On a site whose pages were DERIVED by \\`editor_setup\\` — the site §13\ndescribes — it redoes nothing: the componentize lane turns each top-level field GROUP into a\ncomponent placement, and the page keeps its fields, its values and its bindings. In this order:\n\n 1. set_authoring_preference { preference: \"components\" }\n 2. get_componentize_plan one component per section, computed live; creates nothing. It\n reads this project's PUBLISHED pages, so no deploy is needed\n to reach it — the deploy is the last step, not the first.\n On a DERIVED site, each editor_setup after this answer\n runs this plan in bind mode for NEW sections (it never splits\n or joins a placement, and runs nothing while the answer is\n unset) and PUBLISHES what it created, so after one expect\n ALREADY_COMPONENTIZED and skip to step 6 (publish the pages) —\n the lane publishes the COMPONENTS, not the placements, which\n are still draft blocks on the pages. A /fr still on its own\n components joins its twin's with \\`joinTwins: true\\` (step 4)\n 3. show the user the plan and CONFIRM — it says how many components and which pages\n 4. componentize_sections \\`dryRun: true\\` first, then for real; components land as DRAFTS\n and each placement carries \\`props.bind\\` to the page's field\n group, so click-to-edit and the coverage meter do not change\n 5. publish_component each one — unpublished renders as NOTHING, on a page that 200s\n 5b. publish_layout if you authored site chrome — the layout is a separate publish\n 6. publish the pages\n 7. componentize_sections { digest, codemod: true } the section-order codemod\n (\\`--componentize\\`) on the repo's own Actions, so its templates\n render these sections from \\`pages[].blocks\\`; \\`skipped\\` = no\n repo it may commit to: run \\`npx @bettercms-ai/convert\n --componentize\\` in your checkout\n 8. deploy the ONLY deploy this sequence needs\n\nStep 5 is not a formality: \\`componentize_sections\\` and \\`create_component\\` both land components\nas DRAFTS, so \\`publish_component\\` each one and publish the page — otherwise the canvas keeps\npainting the PUBLISHED copy and the editor reports N components unpublished.\n\n**A site with nothing to componentize you author by hand.** Where the plan offers nothing for\na group (\\`NO_GROUP_ROOT\\` — the page's field keys are still the derive lane's own;\n\\`NOT_A_SECTION\\` — a lone scalar with no family), and on a site with no derived pages at all,\nthe order is \\`create_component\\` per section → \\`publish_component\\` each → \\`set_page_content\\`\nplacing \\`component\\` blocks → \\`list_extraction_candidates\\` / \\`extract_component\\` to fold any\nsection repeated 3+ times. \\`extract_component\\` is not a converter and cannot stand in for the\ncomponentize lane: it scans \\`blockJson\\`, which is empty on exactly the pages that would need\nconverting.\n\n**Answering \\`fields\\` is a real answer, not a deferral** — for a SCHEMA-FIRST site. A blog, a\ncatalogue or a directory is schema-first by design (§1) and should stay that way. On anything\nelse it costs the editor the ability to add, reorder or swap sections. Say so and move on.\n\nEither way: ask, do not choose — recommending is not answering. The 409 carries this project's\nactual page counts — how many are field-driven, block-driven, and how many place a reusable\ncomponent — so quote those to the user rather than describing the choice in the abstract.\n\n## 11. The canvas: what makes an imported site EDITABLE\n\nA deploy makes a site LIVE. It does not make it editable — those are different states, and the\ngap between them is the single most common disappointment after an import.\n\n**The canvas is the real site.** A PUBLISHED page of a DEPLOYED site with DECLARED bindings\nframes the project's OWN build, with unpublished text painted over it, whether or not the draft\nhas drifted from the published copy. STRUCTURAL drafts (new\nsections, reordering, a changed component definition) are the one thing that build cannot show,\nand there are four ways to see them: publish and redeploy; the editor's **Draft render** toggle,\nwhich swaps in the platform renderer on demand (approximate theme, one click back); live, through\nthe draft bridge below (Next); or — for server-rendered sites — the node lane, coming.\n\nOnly FOUR states use the platform renderer by default: an UNPUBLISHED page, a page whose route\nthe last build does not carry (\\`get_binding_report.builtRoutes\\`), a project with NO build at\nall, and a \\`mode: \"text-match\"\\` site whose draft has drifted (its elements are found by matching\npage text to stored values, so drifted text may be unclickable — declare the bindings, §13).\nThose are exactly where \\`bcms-presentation.json\\` matters — the renderer previews in a\nGENERIC theme unless the deploy artifact declares one at its root. Put the file in \\`public/\\`\n(the build lands it at the artifact root) declaring the site's presentation — container width,\ntype scale, nav position and background, footer surface — as DTCG \\`{\"$type\": ..., \"$value\": ...}\\`\nentries. Redeclare it on every deploy; absent means \"declared nothing\" and previews fall back\nto platform defaults that will not look like this site.\n\n**Which live-preview lane THIS site has, and what it costs not to have one.**\n\\`get_binding_report.canvas.lane\\` names it: \\`bridge\\` (the build ships \\`BcmsDraftBridge\\` from\n\\`@bettercms-ai/next/draft-bridge\\`, so a structural draft re-renders inside the site's own\nbuild), \\`draft-route\\` (a node runtime whose app renders drafts server-side), or \\`none\\` — no\nlane, so every structural draft falls back to the platform renderer and its generic theme.\n\\`null\\` means the report predates the field; redeploy to learn. When it is \\`none\\`,\n\\`get_next_steps\\` names the recipe for this project's framework (\\`canvas-lane-missing\\`), and\n§13 step 5c has both. The same report carries \\`unaddressable\\`: how much VISIBLE text on the\nlive site no field owns — \\`unmatched\\` cannot see it, because it only ever speaks about fields\nthat already exist. EVERY release measures it server-side, per route, with a denominator and the\nplaces it is (\\`unaddressable.routes[]\\`: \\`path\\`, \\`count\\`, \\`visible\\`, \\`buckets[]\\`). An author\nturning the editor's **\"Unbound text\"** control on posts a bare count of text NODES for the route\nthey opened; it is reported only for a build the release never measured, and never added to\nthe release's characters. Ornaments, skip links and the platform badge are excluded from both sides.\n\n**THE LOOP, and it is not optional — a deploy is not a conversion.**\n\n 1. deploy, then \\`get_binding_report\\`;\n 2. for each \\`unaddressable.routes[]\\` where \\`count / visible > 0.02\\`:\n read its \\`buckets\\` — each one is a TAG in a LANDMARK with a sample of the copy;\n 3. fix it in the SOURCE: wrap that run of text in an element the codemod can bind (a\n \\`<span>\\`, a \\`<p>\\`, a \\`<div>\\` — never a bare text node between tags), or declare it\n yourself with \\`<BcmsField path=\"…\">\\`;\n 4. deploy again and re-read. Repeat until every route is under 2%.\n\n\\`get_next_steps\\` runs the same test and hands you the worst route with its buckets\n(\\`unaddressable-copy\\`). Its \\`receipt.gate\\` holds EVERY built route to that bar, beside its page,\nits images and its links, and \\`receipt.complete\\` stays false until each route passes. A \\`coverage\\` carrying \\`error: \"nothing-bound\"\\` means NOT ONE element\nof the build is bound — usually the singleton lane declined the project (\\`skipReasons\\`\n\\`authored-content\\`: its content models were authored by the repo), so the percentage beside it\ndescribes a site this build is not.\n\n**A site built in the CMS with NO deployed build has only that renderer** — live and in the\neditor — so the generic theme IS the site until you theme it. Theme it without a deploy:\n\\`update_project { presentation: { \"page.maxWidth\": { \"$type\": \"dimension\", \"$value\": 1200 },\n\"nav.background\": { \"$type\": \"color\", \"$value\": \"#0b0b0b\" }, ... } }\\` takes the same knobs as\nbcms-presentation.json, and set \\`style\\` on every Section's root (§3). A later deploy that\nships bcms-presentation.json replaces it wholesale.\n\n**Editing binds by VALUE.** The editor matches CMS field values against the text the site\nrenders. Three consequences, each load-bearing:\n\n 1. Content that exists ONLY in the build can never be click-to-edit. Bring it in, per\n route, in this order (get_next_steps reports the state until it is done):\n\n a. create_page one per route, slug matching the route\n b. add_field {pageId} the fields its content needs (or create_component +\n publish_component + component blocks, per your §10 answer)\n c. set_page_content values EXACTLY equal to the text the site renders —\n binding matches by value, so a paraphrase binds nothing\n d. update_page status 'published' — the canvas binds the PUBLISHED copy\n e. publish_layout if site chrome was authored — the canvas binds the PUBLISHED layout too\n 2. A value that renders in more than one place is still ONE field: bind every element that\n renders it, and the editor keeps them in sync — an edit patches every copy at once.\n Binding only one copy leaves the others showing the old text until the next rebuild.\n 3. Make the chrome ITSELF editable by speaking the layout grammar: the nav/footer\n elements declare \\`data-bcms-layout-section=\"navigation\"\\` / \\`\"footer\"\\`, and each\n CMS-backed text inside them a \\`data-bcms-layout-field=\"layout:<sections[slug].id>:<fieldId>\"\\`\n marker (fieldId is the field's REAL id, verbatim — production layout ids are\n section-prefixed and dotted, e.g. \\`footer.tagline\\`, so the marker reads\n \\`layout:footer:footer.tagline\\`) — the canvas then gives them hover chrome, the\n Layout side panel, and\n double-click editing, writing to the project Layout store (never the page).\n The address reaches INSIDE structured fields by walking the schema: a group's text\n sub appends its slug (\\`layout:navigation:navigation.cta.label\\`), a repeater row its\n STORED index then the slug (\\`layout:navigation:navigation.links.0.label\\`), nesting\n as deep as the schema goes (\\`layout:footer:footer.link-groups.0.links.1.label\\`).\n Five rules, each one a measured defect when broken:\n a. a field rendered by TWO elements gets a marker on BOTH — the editor keeps the copies\n in sync, and a marker on only one leaves the other stale;\n b. PROVENANCE — mark an element only when the LAYOUT supplied its value; a marker\n over a fallback/singleton-sourced string opens an editor for a row that does not\n exist;\n c. row markers use the value's STORED index (a row you filtered out of the render\n still occupies its slot), or the edit lands on the wrong row;\n d. the address names the DELIVERED entry's id, \\`sections[slug].id\\`, never the slug — a\n Section created in the dashboard has a UUID id. On a translated route address the\n entry that fills the slot, by ITS own id: a page's own \\`layout\\` already delivers it\n at \\`sections['navigation']\\`, the Global Layout carries it beside the base at\n \\`sections['navigation--fr']\\`; the \\`data-bcms-layout-section\\` wrapper still names\n the SLOT, the base slug (\\`navigation\\`);\n e. ONE OWNER PER ELEMENT: never a \\`data-bcms-field\\` inside a Layout-declared region.\n The report will not flag one you write: it binds, and the element gets two writers.\n \\`layout-owned\\` names only the page copies left with no element, which the strip removes.\n Text/longtext leaves edit inline; link/select/image leaves are side-panel-only by\n design (their formats need a real control). THE DOCTRINE: every string a marketer\n can see must be addressable — no marker means read-only on the canvas, so an\n unmarked CMS-backed string is a defect, not a style choice.\n On a site BetterCMS serves, a Layout publish never builds: it writes the new VALUES into\n the live pages, and a STRUCTURE change (a Section added, removed or moved) waits for a\n Rebuild or a push — get_next_steps says \\`layout-rebuild-required\\` until a build ships\n it. A custom host gets its deploy hook instead.\n 4. Keep chrome semantic — \\`<nav>\\`, \\`<footer>\\`, page content inside \\`<main>\\`, mastheads\n as a top-level \\`<header>\\`. Chrome is edited through the project Layout, not the page,\n and semantic landmarks are how the editor keeps a nav edit from being written into page\n content. Div-built chrome outside \\`<main>\\` is still excluded; div-built chrome with no\n \\`<main>\\` anywhere loses that protection.\n\n**Structural drafts can render on the real site too, LIVE — the draft bridge.** Wrap your page's\nblocks in \\`BcmsDraftBridge\\` (\\`@bettercms-ai/next/draft-bridge\\`) instead of calling\n\\`BcmsBlocks\\` directly: standalone it renders identically, and inside the visual editor it\nreceives the DRAFT block tree over a same-origin postMessage handshake and re-renders it with\nthe site's own components — so adding, removing or reordering sections previews in the site's\nreal design, with no publish and no Draft render detour. A bridge that answers wins over the\ntoggle. Sites without one keep Draft render's approximate fallback, and a route the build does\nnot carry falls back always (a static build has no file to frame).\n\n**Sections on a site whose CODE renders the page.** The editor's outline is the page's \\`blockJson\\`,\nbut a code-built site ships only what its own templates draw:\n- An added or moved section reaches the live site only when the site renders the page's block list\n itself, in order, each section root stamped \\`data-bcms-block=\"<blockId>\"\\`. \\`npx @bettercms-ai/convert\n --sections\\` wraps a page's sections in \\`<BcmsSections>\\`, which is that loop and the stamps\n (\\`--componentize\\` lifts them into components first, where a plan exists). Until it ships, the canvas\n only ARRANGES the static build to match the draft (a section the build never rendered is stood in for\n by a server render); the editor still saves added, moved and swapped sections but says the live site\n keeps its own order, and offers \"Let BetterCMS control section order\" (that same codemod, committed\n to the connected repository); and each such route leads \\`submit_conversion_receipt\\`'s \\`pending\\`\n with a \\`SECTIONS_UNSTAMPED\\` row, so \\`complete\\` stays false. Never hard-code a page's bands, or\n literal \\`data-bcms-block\\` ids, in a template whose order the CMS owns: a release measures whether\n the stamped roots come out in the CMS order (\\`ordered\\` on the binding report's structure row).\n- To add ONE section or set ONE section's spacing, send \\`update_page\\` an OBJECT \\`blockJson\\`:\n \\`{ insertSection: { componentId, at | before | after, style?, overrides? } }\\` or\n \\`{ sectionStyle: { blockId, style } }\\`. The server edits the stored page, so nothing else is\n resent. An answer that begins with \\`held\\` is a saved draft this site's code will not show:\n take the hold's action first. A publish answers with \\`outcome\\`; \\`partial\\` names each value\n that is not live and its action. Neither is ever \"done\". \\`get_next_steps\\` keeps them listed\n (\\`publish-held\\`), and its gate fails a route on \\`sections\\` or \\`style\\` until the build draws\n the page's sections from the CMS and marks every root for style, or the release writes them in\n place. Each failing row's \\`fixCode\\` says which: the project's switch, the wrap, or a rebuild.\n- A placement the site never renders (a leftover nav, footer or modal its layout draws) moves\n nothing: the editor counts section moves in RENDERED sections only and locks that row. Remove\n such placements; do not reorder around them.\n- Section spacing and style handles need every stamped root to also carry \\`data-bcms-style\\` and\n paint \\`block.style\\`: spread \\`sectionRootAttrs(block)\\` (\\`@bettercms-ai/astro\\`, \\`@bettercms-ai/next\\`)\n on the root. A site converted before that existed shows none (\\`get_next_steps\\`\n \\`upgrade-section-roots\\`): run \\`npx @bettercms-ai/convert@latest --upgrade-sections --root .\\` (with\n \\`--dry-run\\` first), fix the roots it lists as skipped by hand, check \\`--verify-styles\\`, push, release.\n\n**Hosting decides whether a canvas exists at all.** A site deployed here is framed through a\nsame-origin proxy — that is what the canvas requires. A site hosted elsewhere (your own Vercel,\nyour own server) has NO canvas today: the SDK's draft mode with \\`stega: true\\` embeds invisible\nper-field provenance in fetched strings, which prepares the content for editing surfaces, but do\nnot promise a canvas for an externally-hosted site.\n\n**RECEIPTS: a claim about published state needs a read of the PUBLISHED copy.** The\ndoctrine this encodes cost a real incident (FLO-1188): a publish was verified against the\ndraft for ~50 minutes because the reader silently returned the draft, and every check was\ngreen on the wrong document. Three rules, none optional:\n 1. NEVER verify a write by re-reading the store you wrote. Draft writes verify against\n the draft; a PUBLISH claim verifies ONLY via \\`get_layout copy:'published'\\` (or the\n entry/page's published copy) — and check the response's \\`copy\\` echo says\n 'published'. A reader that ignores your copy selector hands you the draft and a\n false green; the echo is how you catch it. \\`publish_layout\\`'s own response echoes\n copy:'published' too — that is the WRITE's echo, not a receipt; still re-read.\n 2. Publish and deploy are SEPARATE claims. \"Published\" means the published copy changed;\n the LIVE SITE changes only after its next deploy/rebuild. Never report \"it's live\"\n from a publish receipt — fetch the live URL (cache-busted) for that claim.\n 3. A tool param the schema does not declare is SILENTLY DROPPED, not rejected. If a\n call's behavior doesn't change when you change a param, treat the param as dead and\n verify through an independent channel before trusting any result built on it.\n\n## 12. Componentize the entire website\n\nThe whole-site ask — \"turn every section into a reusable component, organised for editors\" —\nmapped onto what this platform actually models. Work the order at the end; each numbered part\nbelow is one heading of that ask.\n\n**1. Global elements.** Navbar, mobile nav, header and footer are the LAYOUT, not page content:\n\\`get_layout\\` then \\`update_layout\\`, and a chrome COMPONENT is placed into a Layout section with\nthe \\`add-component\\` command. CTA buttons are \\`button\\` BLOCKS inside the section that uses them,\nexposed as \\`text\\` + \\`url\\` props that target that ONE block — never the words as a separate text\nblock beside it, or the Button panel edits nothing — variant, size and fullWidth are that block's own props and\n\\`style\\`. Do not hand-build a Button component. On a site built here every button look you write joins\nthe project's Button family (Globals/Buttons) on its own, and a new look is \\`create_component\\` with\n\\`variantOf\\` naming a Button. On an IMPORTED site the family is the looks measured in the site and\nnothing you write adds to it: read it with \\`list_components\\`, place a look as a \\`component\\` block,\nand never add CSS for a look the site does not have. On a page's FIELDS a CTA is one \\`button\\` field\n(§2), whose \\`variant\\` picks a look of that family. Rich text is a \\`richtext\\` prop over a\n\\`richtext\\`/\\`text\\` block. Forms are \\`create_form\\` plus a \\`form\\` block, and form FIELDS are the\none place the platform models \\`required\\`, \\`placeholder\\`, \\`helpText\\` and real \\`validation\\`\n(emailPolicy, min/max, phoneFormat, pattern) — put a site's validated inputs there. Cards,\nbadges, tags, links, lists and media are BLOCKS inside a section, exposed through props; a\nrepeatable row of them is ONE \\`table\\` prop whose \\`config.fields\\` describe the row. Accordions\nand FAQs: start from the \\`builtin:faq-list\\` blueprint, or use a \\`tabs\\` block. NOT MODELLED —\ncookie banners, modals, breadcrumbs and pagination have no primitive at all. Leave them in the\nsite's code and say so in your final summary. A modal is chrome, like the nav: never a page section\n(the plan reports it \\`LAYOUT_CHROME\\`).\n\n**2. One component per distinct section, one-offs included.** \\`create_component\\` with a\n\\`sectionType\\` IS the section. \\`sectionType\\` is the FAMILY (Hero, Features, Testimonials,\nPricing, FAQ, Contact, Newsletter, CTA, Stats, Logo cloud, Content…) and components sharing one\nare its VARIANTS — give a family the same prop KEYS or a swap drops content. A one-off band\nstill gets its own component: its own family, plus \\`allowedOn: [\"slug:<page>\"]\\`. A component\nwith NO \\`sectionType\\` never appears in the editor's \"Add a section\" picker. On a BLANK site, start\nfrom the builtin blueprints \\`list_components\\` returns (\\`builtin:*\\`) instead of hand-writing block\nJSON. On an IMPORTED site, never materialize a builtin: read the repo's own components first\n(\\`src/components\\`, its sections folder) and make ONE CMS component per source component, named\nas the source names it — the site's Pricing section is \"Pricing\", not \"Section 2\" or \"Simple\".\nOn a DERIVED site run \\`get_componentize_plan\\` → \\`componentize_sections\\` FIRST — it does most\nof this in one call, and once \\`components\\` is recorded each \\`editor_setup\\` of a derived site\nruns it in bind mode and publishes the components, so expect ALREADY_COMPONENTIZED — the placements it wrote are\nstill DRAFT blocks on the pages, so publish the pages, then \\`componentize_sections { codemod: true }\\`\n(or \\`npx @bettercms-ai/convert --componentize\\` in your checkout).\n\n**3. The hierarchy editors see is the GROUP.** \\`create_component\\` and \\`update_component\\` take\n\\`group\\`: a NAME, resolved against the project's component groups and created when missing. That\nis the folder the dashboard's Components tab shows. Use the names the request asks for — Global,\nNavigation, Actions, Content, Forms, Media, Sections, Page-specific. \\`category\\` is a different\naxis: it is the picker TAB (hero / content / social-proof / conversion for sections; navbar /\nfooter for chrome; form; custom for page-specific).\n\n**3b. Group the fields the way the source groups them.** A price, a stat's figure and a badge are\nprops of their own (\"Price\", \"Stat value\"), never folded into a sentence. Give every component of\nmore than ~8 props \\`ui.group\\`s that mirror its markup — Content, Call to action, Media — and\n\\`ui.collapsed\\` on the secondary ones (§14). A flat list of 20 props named by their copy is the\nform editors cannot read.\n\n**4. Editor fields are \\`props\\`.** Types: \\`text richtext image url boolean number select group\ntable slot form\\`. Always set \\`defaultValue\\`. \\`form\\` points at ONE Form document: target a\n\\`form\\` block's \\`props\\` and set \\`defaultValue\\` to \\`{formId}\\`. NEVER re-declare a form's fields\nas props — the Form document owns them, a second copy drifts on the first edit, and the Forms\ntab is where an author edits them. \\`required\\`, \\`helpText\\` and \\`placeholder\\` are editor\nhints the dashboard renders — they are NOT enforced at write time, so an override missing a\nrequired prop still saves; \\`get_site_composition\\` is what reports those. Use \\`select\\` with\n\\`config.options\\` for layout / theme / alignment / spacing variants that change only styling,\nand a SEPARATE variant component when the markup differs. Repeatable list → \\`table\\`; fixed\ncluster → \\`group\\`. Nesting goes up to 10 levels counting the prop itself. A \\`table\\` row may hold a\n\\`table\\` (rows), a data table (\\`config.mode: \"data\"\\`) or a polymorphic list\n(\\`config.mode: \"types\"\\`), so a size guide's rows can each carry a chart and a multi-step\nform's steps can each carry their fields. Deeper is refused (\\`field_depth_exceeded\\`).\n\n**5. Design, responsiveness and accessibility.** \\`componentize_sections\\` and \\`npx\n@bettercms-ai/convert --componentize\\` move the section's markup VERBATIM — classes, responsive\nutilities, aria attributes and alt text all survive. Never restyle while componentizing. Run\n\\`componentize_sections { dryRun: true }\\` and the codemod's \\`--dry-run\\` first.\n\n**5b. Every component's Output must render — record its SOURCE.** The dashboard's Output builds and\nvalidates a component from the file in the repository that renders it, and only a file whose props\nmatch renders it. A section the codemod extracted is such a file: after \\`npx @bettercms-ai/convert\n--componentize --receipt componentize.json\\`, push the files and call \\`submit_componentize_receipt\n{ receipt }\\` — every extracted section is recorded for the component with the same slug. A section\nyou write BY HAND follows the same contract: props exactly \\`{ blockId, bind, overrides, page }\\`, the\nroot element carries \\`data-bcms-block={blockId}\\`, and copy is read through \\`bcmsSection(page, bind,\noverrides)\\` (or \\`bcmsSectionPaths\\` for a flat field family like \\`wrap-h2-latest\\`); then call\n\\`set_component_source { kind: 'section' }\\`. A component module whose props ARE its fields is\n\\`set_component_source\\` with the default kind. NEVER record a different component that merely\ncontains the markup (a card needing a \\`post\\` object): it cannot render from these fields and its\nvalidation fails every time — \\`clear_component_source\\` removes a wrong one.\n\n**6. The final validation is \\`get_site_composition\\`.** It is the receipt for \"is every page\nassembled from registered components?\": per page its blocks and every component placement with\nthat component's status, plus site totals — unpublished, awaiting evidence, awaiting approval,\nmissing from the picker, placed nowhere — and \\`verdict.everyPageComposed\\` with the reasons it\nis false. A component reaches a visitor only once PUBLISHED, and publishing needs the project\nowner's approval in the DASHBOARD: evidence comes from \\`request_component_validation\\` and a\nvalidation run in the repository, the owner approves there, then \\`publish_components\\`. There is no\nbulk approve, and no tool here can grant that approval. Finish with \\`get_next_steps\\`.\n\n**Order of operations.**\n\n 1. get_site_composition the before picture\n 2. get_componentize_plan DERIVED site only — confirm it with the user\n 3. componentize_sections dryRun first, then for real\n 3b. npx @bettercms-ai/convert --componentize --receipt componentize.json, push,\n then submit_componentize_receipt { receipt } every section's Output source, ONE call\n 4. create_component each section the plan did not cover, each with a group\n 5. compose_pages every page's blockJson, ONE call\n 6. update_layout { commands } nav/footer chrome + add-component, ONE call\n 7. evidence request_component_validation -> the repo's validation run\n 8. owner approves in the dashboard, then publish_components ONE call, per-item receipts\n 9. update_page status:'published', publish_layout\n 10. get_site_composition, then get_next_steps\n\n**What to tell the user at the end.** The group hierarchy and what landed in each; every family\nand its variants; what you left in the site's code because the platform does not model it\n(cookie banners, modals, breadcrumbs, pagination) and why; and exactly which components are\nstill waiting for THEIR approval in the dashboard — until that happens those sections render as\nan empty string on the live site.\n\n## 13. Convert an imported repo into a CMS-backed, editable site\n\n§11 says a deploy does not make a site editable. This is the recipe that does.\n\n🔴 **A CONVERSION ENDS ONLY WHEN NOTHING IS PENDING.** The codemod's first pass never\ndeclares every path — measured on a real site, one pass declared 282 of 767 — and every path it\nleaves in \\`paths.pending\\` carries a \\`fix\\` naming the file, the line and the one edit. Apply\nthem, rerun, resubmit, and repeat until \\`submit_conversion_receipt\\` answers \\`complete: true\\`.\nThat boolean is the finish line; a receipt with pending paths is a progress report. The\n\\`convert_site\\` MCP prompt walks exactly this loop.\n\n**Scope, before you start.**\n\n(a) This is the FIELD-driven conversion — page fields and collections. If the human answered\n\\`components\\` at the §10 gate, go to §10's recipe instead: a component's editing surface is its\ndeclared \\`props\\`, and those bindings are NOT what \\`get_binding_report\\` walks.\n\n(b) It works for any framework that emits STATIC HTML, because the binding contract is plain\nHTML attributes — the annotator, the injector and the canvas stamper never see your source.\nThere are SDK helpers for Astro and Next. A Node-runtime site (\\`bcms-runtime.json\\`) edits on\nthe canvas but skips release annotation and publish-time injection, because there is no HTML on\ndisk to annotate. Copy rendered on the client must carry the attributes in the HYDRATED DOM,\nand only the canvas sees it — a release scan cannot.\n\n**On a workspace-wide connection, pass \\`projectId\\` on every call in this section** — that is\nall it takes; the code and deploy tools work from such a connection and nobody needs to re-scope\nanything. See §9.\n\n**Which recipe.** There are TWO below and they are not alternatives you pick by taste — call\n\\`get_binding_report\\` and \\`get_conversion_brief\\` first and let the answer choose. A brief that\ncomes back WITH PAGES means this project was imported and \\`editor_setup\\` derived its schema and\nvalues already → **Recipe A**. On an import whose \\`get_deploy_status\\` \\`editorSetup\\` is \\`never\\`\nor \\`stale\\`, run \\`editor_setup\\` FIRST and read the brief again. A 404 or an empty brief after\nthat means the site is not in the CMS yet → **Recipe B**. \\`get_next_steps\\` works on every plan and names the next unfinished step\neither way.\n\n**If you know Sanity, this is the same shape under different names:**\n\n defineType schema in code -> content models / page fields (create_content_model,\n add_field, or bcms-content.json \"schema\")\n TypeGen -> @bettercms-ai/codegen\n GROQ query in the page -> @bettercms-ai/sdk read client, or the bcms-content.json\n build snapshot\n <PortableText> body -> @bettercms-ai/richtext portableTextToHtml, field type\n 'document'\n data-sanity / stega -> data-bcms-field + data-bcms-kind (<BcmsField>), stega on\n draft reads\n Presentation tool overlays -> the visual editor canvas, framing your own build\n\n**Imported site whose pages were DERIVED.** If this project was imported and \\`editor_setup\\` ran\nover its build, the schema and the values already exist — a page per route, a field per element, and\nthe original copy carried on each field as its \\`defaultValue\\`. Call \\`get_conversion_brief\\`\nfirst: it lists those pages, their routes, every bindable path with its current and original\nvalue, and the attributes to declare. SKIP Recipe B's steps 3 and 4 below and bind the keys it\nnames — registering the schema again builds a second one over the first.\n\n**Recipe A — imported and deployed: the codemod order.** For a derived site the whole of Recipe\nB's step 5 is mechanical, and there is a tool that does it. Run the codemod rather than editing by\nhand. THE ORDER, and every step of it matters:\n\n1. \\`get_conversion_brief { complete: true }\\` — the COMPLETE brief, not the capped one. It comes\n back uncapped and paged (50 pages at a time): follow \\`cursor\\` until it stops coming back and\n keep every page. The capped read truncates values and omits pages, and a codemod fed a\n truncated \\`original\\` searches the source for a string that is not there. Page 1 PINS the\n path list under a \\`briefDigest\\`; that pinned list is what the coverage meter measures the\n build against, so nothing later can move the denominator. A 409 \\`BRIEF_CHANGED\\` mid-pagination\n means the brief was re-derived under you — start again with no cursor.\n2. Write the pages you collected to \\`brief.json\\` and run\n \\`npx @bettercms-ai/convert --brief brief.json --root . --receipt receipt.json\\`, then read\n \\`git diff\\`. It rewrites the templates to read from BetterCMS, keeps the in-code copy as the\n fallback, and declares each binding.\n2b. IF THE BRIEF CARRIES \\`forms\\`, wire them too:\n \\`npx @bettercms-ai/convert --forms --brief brief.json --root . --receipt forms-receipt.json\\`\n — ITS OWN receipt file, submitted with submit_conversion_receipt as a second call under the\n SAME \\`briefDigest\\` (its \\`paths\\` are all zero): the server stores its \\`forms\\` block\n beside the binding receipt (never counted in coverage), and\n the next release reads \\`wiredForms\\` to say which component renders each form.\n A site imported by phase 1 has a DRAFT form row per \\`<form>\\` in its build, so the Forms tab\n is full while the repository's markup still posts wherever it always did — to nothing, or to\n somebody else's endpoint. This pass writes the endpoint, the form id, a marker per field and\n the submit script onto the \\`<form>\\` the repository already has. Then PUBLISH each form the\n receipt's \\`forms.notes\\` names, in the Forms tab: the public submit route answers 403 to a\n draft, so a wired draft form is a real, inviting form that rejects every visitor. Forms it\n could not match are in \\`forms.pending\\` with a reason (\\`FORM_NOT_IN_SOURCE\\`,\n \\`FIELD_UNMATCHED\\`, \\`FORM_AMBIGUOUS\\`, …) — it refuses rather than guessing, because a form\n wired to the wrong id delivers the customer's leads into another form's inbox.\n3. APPLY EVERY PENDING FIX, THEN RERUN. Each entry of \\`paths.pending\\` carries its reason\n (\\`IN_EXPRESSION\\`, \\`AMBIGUOUS_LITERAL\\`, \\`REPEATER_FIXED_LENGTH\\`, \\`PARSE_ERROR\\`, …) and,\n where the codemod could work one out, a \\`fix\\`: \\`{ action, file, line, col?, snippet, why? }\\`.\n Go to \\`file\\`:\\`line\\` and do what \\`action\\` says — \\`wrap-span\\` (wrap the literal in\n \\`<span data-bcms-field=\"…\">\\`), \\`declare-attr\\` (add \\`data-bcms-field=\"…\"\\` to that element),\n \\`bind-expression\\` (replace the expression with the framework's bcmsField helper),\n \\`declare-richtext\\` (bind the container with the richtext helper), \\`bind-data\\` (bind the field\n in the data file or collection entry it names) or \\`manual\\` (do what its \\`why\\` says). A row\n with no \\`fix\\` is still yours. Then RERUN step 2 and repeat until \\`paths.pending\\` is empty —\n the codemod is idempotent, so a second run over converted source rewrites nothing.\n3b. THE SITE'S DESIGN IS NOT YOURS TO CHANGE. The \\`--verify-styles\\` pass of the same codemod\n (\\`--root .\\`, with \\`--base\\` set to the last commit before you started converting) lists every\n \\`class\\`, \\`className\\` and \\`style\\` the conversion altered as \\`styleEdits\\`; they travel\n inside the receipt, and a non-empty list is refused with 409 \\`style-edits\\` naming every\n token. Restore them in the source, rerun, resubmit.\n4. \\`submit_conversion_receipt { briefDigest, receipt }\\` with the receipt file, verbatim. It\n answers \\`complete\\`, \\`pendingTotal\\` and the first 40 pending rows with their \\`fix\\`. \\`complete: true\\` — nothing\n pending — is the ONLY receipt that ends a conversion; on anything less go back to step 3. It\n is also what lets the coverage meter say WHY a path is undeclared instead of only that it is.\n It records and releases nothing.\n5. Push, or \\`deploy_project\\`. A PLAIN HTML repo — no \\`package.json\\` — deploys by PUSH ONLY:\n \\`deploy_project\\` refuses such an archive by design, so pushing is the whole lane. Either way,\n poll \\`get_deploy_status\\` until \\`slot\\` is \\`current\\` (or \\`awaitingPromote\\` is false) before you\n read the report in step 6 — a report read against the previous release is the previous\n release's verdict.\n6. \\`get_binding_report\\`. Alongside \\`unmatched\\` it now carries \\`coverage\\` — \\`declared\\` (what the\n brief listed), \\`bound\\` (what the build declares) and \\`pending\\` with the reasons. It must read\n \\`unmatched\\` 0 and \\`unaddressable\\` under 2% of each route's visible text (§11). Fix what it\n names IN THE SOURCE and release again until \\`coverage.pending\\` is empty.\n7. \\`set_binding_mode { declaredBindings: true }\\` and release ONE MORE TIME — the mode applies to\n the next release, not to the one already out. (editor_setup sets it itself when the build\n already declares every binding; skip this step when get_binding_report reads \\`declared\\`.)\n\n**Or let BetterCMS propose the edit.** \\`get_conversion_plan\\` returns an APPROVED conversion — the\nexact new contents of each template file, reviewed by a human in the dashboard and already checked\nagainst this project's real field paths. When there is one, apply it instead of Recipe A's step 2\n(the codemod): check out its \\`baseHeadOid\\`, branch from there, write each file's \\`content\\`\nverbatim, and carry on from Recipe A's step 5. A 404 with \\`code: \"no-approved-plan\"\\` means nobody approved one, so the\nconversion is yours to write.\n\n**Recipe B — not in the CMS yet: the steps.**\n\n1. \\`pull_project_source\\` (or clone the \\`github\\` remote it returns — \\`cloneUrl\\` on the \\`branch\\`\n it names, which is the branch the provisioned Action builds). Read the SOURCE. Never\n reconstruct content from the deployed HTML — that is how a site ends up bound to a copy of\n its own stale build.\n2. Decide the architecture WITH the human (§10) and record it: \\`set_authoring_preference\\`.\n3. Register the schema. Per route: \\`create_page\\` + \\`add_field\\` { pageId } (text / longtext /\n richtext / image / array groups). Per repeated content type: \\`create_content_model\\`, with a\n \\`document\\` body for articles. Site chrome goes through \\`update_layout\\`; images through\n \\`create_media_upload\\` / \\`upload_asset\\`, then reference the CMS URL. The repo-owned\n alternative to calling these one by one is a committed \\`bcms-content.json\\` carrying a\n \\`schema\\` block, which seeds models, pages and entries at connect time — the \\`defineType\\`\n analogue.\n4. Seed the entries with the copy EXACTLY as the source renders it (\\`set_page_content\\`,\n \\`create_content_entry\\`). Prose goes in as Portable Text arrays (\\`_type: \"block\"\\`); never\n markup inside a \\`text\\` field.\n **Prose MIGRATED from another CMS needs one extra check.** Every block's \\`_type\\` must be one\n this platform stores — \\`block\\`, \\`table\\` (\\`{_type:\"table\", rows:[{_key, cells:[{_key,\n content:[...blocks], header?, group?, highlight?, sortable?, note?, column?: {type?: \"text\"|\"number\"|\"money\"|\"boolean\"|\"rating\"|\"link\", unit?, currency?, decimals?, align?, trueLabel?, falseLabel?, max?, description?} (first row only), type?, value?: number|boolean (content keeps its words)}], group?, footer?, highlight?, type?}], caption?, notes?, rowGroups?, columnGroups?, filterable?, jsonLd?: {type: \"ItemList\"|\"Dataset\"|\"Offers\", axis?, priceRow?}, design?: {responsive?: \"stack\"|\"cards\", sticky?}, footnotes?: [{_key, text}]}\\`,\n groups \\`[{_key, label}]\\`; Sanity's row of plain strings, \\`rows:[{cells:[\"a\",\"b\"]}]\\`,\n is admitted too), \\`bcmsCode\\`, \\`bcmsDivider\\`, \\`bcmsMention\\`, \\`pullQuote\\`\n (\\`{quote, name, role?, link?}\\`), \\`keyTakeaways\\` (\\`{title?, points:[...strings]}\\`,\n title at most 40 characters, at most 8 points), or \\`bcmsBlock\\` carrying a\n \\`schemaKey\\` — and a foreign node (a Sanity image, \\`{_type:\"image\", asset:{_ref}}\\`, for one)\n is not merely unrendered: it has no component here, so it\n vanishes from the HTML every delivery surface reads while the stored value still looks whole.\n Verify each \\`_type\\` against the schema before you write, not after.\n5. Codemod the templates. Read each value from the CMS (\\`@bettercms-ai/astro\\` /\n \\`@bettercms-ai/next\\` client, or the \\`bcms-content.json\\` build snapshot), KEEP the in-code\n copy as the fallback, and declare the binding on the element that already renders it.\n Read the snapshot ONLY through a supported reader: the helper \\`npx @bettercms-ai/convert\\`\n writes (\\`bcms\\`, \\`bcmsRows\\`, \\`bcmsImage\\`) or \\`publishedEntry(slug)\\` from\n \\`@bettercms-ai/sdk\\`. Never hand-write a parser of the file: a row holds its values under\n \\`data\\`, so \\`row.title\\` is undefined and the page renders its fallback on every publish. An\n editable image is \\`bcmsImage(page, path, importedImage)\\`, never the bare import with a stamp.\n Prefer schema-derived bindings — the TypeGen analogue:\n \\`npx @bettercms-ai/codegen --bindings-out src/bettercms.bindings.generated.ts\\`, then spread\n \\`{...bcms.home.hero.title}\\` / \\`{...bcms.blog.features.$(i)}\\`. The hand form is\n \\`data-bcms-field=\"<path>\"\\` (plus \\`data-bcms-kind=\"richtext\"|\"image\"\\`), the §11 layout markers\n for nav and footer, and \\`<div data-bcms-field=\"body\" data-bcms-kind=\"document\">\\` around a\n Portable Text render, whose per-block elements carry their own \\`data-bcms-kind=\"richtext\"\\`.\n **A value that lives in an ATTRIBUTE — an \\`href\\`, an \\`alt\\`, an \\`src\\` — rides\n \\`data-bcms-props\\`, and its grammar is PIPES, NOT JSON:**\n \\`data-bcms-props=\"<path>|<kind>|<domAttribute>\"\\`, semicolon-separated for several on one\n element, where \\`kind\\` is \\`text | richtext | image | url | number | array\\`. A link is\n \\`data-bcms-props=\"cta.url|url|href\"\\`; an image's alt text is\n \\`data-bcms-props=\"hero.image.alt|text|alt\"\\`; an \\`<a>\\` wrapping an \\`<img>\\` carries both as\n \\`data-bcms-props=\"cta.url|url|href;hero.image.alt|text|alt\"\\`. A JSON object there parses to\n NOTHING — the reader splits on \\`;\\` and \\`|\\` and drops what does not match — so the value stays\n uneditable and the binding report never mentions it. The SDK helpers\n (\\`@bettercms-ai/astro\\`, \\`@bettercms-ai/next\\`) and \\`@bettercms-ai/codegen\\` emit this form\n for you; write it by hand only when you are not using them.\n Bind CONDITIONALLY (\\`fromCms ? path : undefined\\`) so a fallback row is never bound. A value\n rendered in N places carries the binding on ALL N — the editor keeps the copies in sync.\n **Read the LIVE SCHEMA before you bind — \\`get_page\\` / \\`get_content_model\\`, never the\n delivery snapshot.** A field nobody has authored yet is simply ABSENT from the payload, so a\n snapshot cannot tell \"this field does not exist\" from \"this field is empty\": bind against it\n and you declare a path for a \\`cover\\` field that was never created, which the report then\n reports as broken forever. The schema is the list of what exists; the snapshot is only what\n currently has a value.\n **An index or listing route binds NOTHING.** The editor loads ONE entry per route, and an\n index renders many, so a binding there addresses whichever entry the editor happened to\n load. Bind each item's fields on that item's OWN route (\\`/blog/<slug>\\`); on the index,\n render from the CMS and declare nothing.\n5b. **Where the content comes from at build time.** Two lanes, and they differ:\n - GIT-CONNECTED (recommended for a converted site): the platform's build writes\n \\`bcms-content.json\\` into the repo root before \\`build\\`, with a key it mints per build: no\n repo secret feeds it. (The secret a connect sets, \\`BCMS_API_KEY_<RUNG>\\` such as\n \\`BCMS_API_KEY_PROD\\`, is the validation workflows' key; they fall back to the shared\n \\`BCMS_API_KEY\\` only for a repo whose last connect predates it.) Read that file (step 5's readers), with in-code\n fallbacks so a local or CI build without it still renders.\n - ARCHIVE (\\`deploy_project\\`, inline or by \\`uploadKey\\`): the sandbox build runs with no env\n and no network content step, by design. So the archive MUST SHIP its own\n \\`bcms-content.json\\` — generate it locally with a delivery key and commit it. Without\n one the site renders its fallbacks and the report says \\`no-element\\` for every path.\n5c. **Live preview lane.** Static HTML makes a page click-to-edit; it cannot show a STRUCTURAL\n draft — a new section, a reorder, a changed component — so those fall back to the platform\n renderer's generic theme unless the build can render drafts itself. Give it a lane:\n - NEXT: wrap the page's \\`BcmsBlocks\\` in \\`BcmsDraftBridge\\` from\n \\`@bettercms-ai/next/draft-bridge\\` and redeploy. The bridge marks its output\n \\`data-bcms-canvas=\"bridge\"\\`, which is what the release scan records.\n - ASTRO: switch the pages to \\`output: 'server'\\` with \\`@astrojs/node\\` in\n \\`mode: 'standalone'\\` — the \\`bettercms()\\` integration already injects the draft routes,\n do not write them by hand — render pages from \\`loadPage\\` + \\`loadComponents\\`, mount\n \\`<BcmsLive>\\`, set \\`BCMS_DRAFT_SECRET\\` (BetterCMS hosting sets it for you), redeploy,\n then switch the project to \"Run as a server app\" on the Hosting page. Never migrate a\n static site to SSR without asking the human first.\n Then \\`get_binding_report.canvas.lane\\` reads \\`bridge\\` or \\`draft-route\\` instead of \\`none\\`.\n6. Push, or \\`deploy_project\\`. A PLAIN HTML repo — no \\`package.json\\` — deploys by PUSH ONLY:\n \\`deploy_project\\` refuses such an archive by design. Poll \\`get_deploy_status\\` until \\`slot\\` is\n \\`current\\` (or \\`awaitingPromote\\` is false). Then\n \\`get_binding_report\\` — still \\`text-match\\`, and \\`unmatched\\` should be EMPTY because the\n values are byte-equal to what the build renders. On a converted site read \\`coverage\\` too: it\n counts the PINNED brief's paths, which \\`unmatched\\` cannot, because \\`unmatched\\` only ever\n speaks about fields that already hold a value. Now \\`set_binding_mode\n {declaredBindings: true}\\` and release again (an empty commit is enough). Do not flip before\n the report is clean: in declared mode an undeclared field simply stops being editable.\n7. **Receipts.** \\`get_binding_report\\` reads \\`mode: \"declared\"\\`, \\`unmatched: []\\`,\n \\`bound > 0\\`, and — for a site converted against a pinned brief — \\`coverage.pending: []\\`. That certifies one thing only — that every non-empty field has SOME element\n carrying its path. It CANNOT see copy that was never modelled, so diff each route's visible\n text against its entry values yourself before you call the page done. Then publish, and\n fetch the live URL cache-busted (RECEIPTS in §11: publish and deploy are separate claims).\n \\`get_next_steps\\` keeps reporting the gap until every one of these holds.\n\n**The finish line is \\`receipt.complete\\`.** \\`get_next_steps\\` answers it from the setup gate\n(\\`receipt.gate\\`): every route of the live build has a published page (or entry), one page only,\nat most 2% of its visible text unowned, every image a field's and 95% of its links. \\`blocking\\`\nlists what fails, worst route first, each with the \\`fix\\` call to run, and \\`nextAction\\` is the\none to run now (the fix that closes the most rows): run it, read again after each batch, repeat\nuntil \\`complete\\`. A null \\`fix\\` is the user's to decide. A gap left on purpose is RECORDED, \\`editor_setup { exempt: [{ route, check,\nreason, note }] }\\`, with a reason \\`allowedExceptions\\` lists for that check. Running out of time,\ncontext or patience is in \\`neverExceptions\\`: it is refused, and telling the user why instead\nleaves the gate incomplete. \\`bettercms init\\` reads the same gate when you exit and prints it.\n\n**Done means.** Whichever recipe you ran: \\`get_binding_report\\` reads \\`mode \"declared\"\\`,\n\\`unmatched\\` empty, \\`bound\\` above 0, \\`coverage.pending\\` empty, and \\`canvas.lane\\` is \\`bridge\\` or\n\\`draft-route\\` when the site should show structural drafts.\n\n## 14. Declare how a field LOOKS in the editor — \\`ui\\`, \\`helpText\\`, \\`showIf\\`\n\nYou can create the schema. You can also say how it PRESENTS to the person filling it in. These\nthree props ride on any field, on any field-creating tool (\\`create_content_model\\`,\n\\`create_page\\`, \\`add_field\\`), and none of them can move, reshape or hide a\ndelivered value — they change editor chrome only.\n\n\\`\\`\\`jsonc\n{ \"key\": \"testimonials\", \"label\": \"Testimonials\", \"type\": \"repeater\",\n \"ui\": { \"collapsed\": true, \"preview\": { \"title\": \"author\", \"media\": \"avatar\" },\n \"layout\": \"grid\", \"icon\": \"double-quote\", \"itemLabel\": \"Testimonial\" },\n \"helpText\": \"Three to five.\",\n \"fields\": [ { \"key\": \"author\", ... }, { \"key\": \"avatar\", \"type\": \"image\", ... }, ... ] }\n\\`\\`\\`\n\n- **\\`helpText\\`** — the exception: most fields get none. Write it only when the author needs it to\n type the right value: a format or unit (\"Price in cents.\"), a placement the canvas cannot show, a\n real constraint, a fallback. One plain sentence under 90 characters, no semicolons, no dashes, no values copied from the page. Never restate the label (\"The title field\"), never coach (\"Keep it short\").\n- **\\`showIf\\`** — hide a field until another has a value:\n \\`{match:'all',rules:[{field:'link_type',op:'eq',value:'external'}]}\\`. Rules name fields by\n BARE KEY, and the key namespace is FLAT across the model (§ the duplicate-key rule), so the\n key you reference must exist.\n- **\\`ui.collapsed\\`** — start a nesting field's panel closed. For long optional sections.\n- **\\`ui.preview\\`** — how ONE ITEM of a nesting field summarises itself when collapsed. Each\n slot (\\`title\\`, \\`subtitle\\`, \\`media\\`) names a **CHILD FIELD KEY of that field** — not a value, not a dotted path.\n Without it a repeater of ten testimonials reads \"Item 1 … Item 10\" and the author has to open\n each one to find the one they meant. \\`media\\` may point at an \\`image\\`, \\`file\\` or url-ish\n \\`text\\` child; the type is not constrained.\n- **\\`ui.layout\\`** — \\`'list'\\` (the default; omit it), \\`'grid'\\`, or \\`'table'\\`. Grid when the THUMBNAIL is\n what the author scans: a gallery, a logo wall, a team. Table when a repeatable row schema's\n fields are columns, such as pricing or comparison data. List when the words are.\n- **\\`ui.reorderable\\`** — omit it (≡ \\`true\\`) unless the ORDER IS PART OF THE MEANING. \\`false\\`\n LOCKS the list so its items cannot be dragged: a \"three steps\" band that must stay three steps\n in that order, a nav whose order is semantic, a timeline. Locking a list nobody should reorder\n is the declaration there was previously no way to make; locking one out of tidiness takes a\n capability away from the author, so do not set it \"just in case\".\n- **\\`ui.control\\`** — which control a LEAF edits with; omit it for the default. \\`'segmented'\\` on a\n \\`select\\` with a few short options (alignment, theme, size: one click instead of a dropdown);\n \\`'slider'\\` on a \\`number\\` with \\`config.min\\` < \\`config.max\\` (opacity, columns). Anywhere else it\n is refused with the rule named.\n- **\\`ui.icon\\`** — the branch row's icon: ONE name from \\`bettercms://icons/dock\\` (read that resource;\n any other string is a 400). Nesting fields, fieldsets and a prop's \\`ui.group\\` only. Layout\n section icons are a different vocabulary (Lucide names), so a name valid there may be refused here.\n- **\\`ui.itemLabel\\`** — what ONE item of a list is called (\"Slide\", \"Person\"), at most 24 characters:\n the add button, the crumbs and the empty state say it. Nesting fields only.\n\n**Six refusals, all deliberate, all 400 with the fix in the message.**\n1. An unknown key inside \\`ui\\` is REJECTED, not stripped. \\`ui\\` is a strict object precisely so\n that a typo is a refusal you can read instead of a 200 with your declaration gone.\n2. \\`ui.preview\\` on a LEAF field is refused — it summarises an item, and a leaf has no items.\n Valid on \\`group\\`, \\`repeater\\`, an \\`array\\` with \\`config.zones\\`, or \\`modular\\`.\n3. \\`preview.title\\` / \\`preview.subtitle\\` / \\`preview.media\\` naming a key that is not a child of that field is refused,\n and the error lists the valid child keys.\n4. \\`ui.layout\\` follows the same rule as \\`preview\\`: nesting fields only. A leaf has no items\n to arrange.\n5. \\`ui.reorderable\\` is STRICTER — it needs a LIST, not merely children. Valid on \\`repeater\\`,\n an \\`array\\` with \\`config.zones.repeatable\\`, or \\`modular\\`. A \\`group\\` (and a non-repeatable\n zone) holds exactly ONE item, so there is nothing there to drag and the write is refused.\n6. \\`ui.control\\` outside its fit is refused: \\`segmented\\` needs a \\`select\\`, \\`slider\\` a \\`number\\`\n whose \\`config.min\\` and \\`config.max\\` are both set with min < max.\n\n**The same \\`ui\\` rides on COMPONENT PROPS.** \\`create_component\\` / \\`update_component\\` take it on\neach entry of \\`props\\`, with the placement rules the prop vocabulary implies: \\`preview\\` and\n\\`layout\\` on \\`group\\`, \\`table\\` and \\`slot\\`; \\`reorderable\\` on \\`table\\` ALONE, because a table is the\nonly prop whose value is a list (a \\`group\\` is one object, a \\`slot\\` one component instance). A\nprop's \\`preview\\` keys name a SUB-FIELD from its own \\`config.fields\\` and are checked against\nthem — except on a \\`slot\\`, whose children belong to whichever component fills it and therefore\ncannot be resolved at save time. \\`update_component\\` REPLACES the whole \\`props\\` array, so echo\nback each prop's stored \\`ui\\` or you delete it along with the prop. Props have no fieldsets, so a\nprop joins a group with \\`ui.group\\`: the FIRST prop of a group defines \\`{ id, label, kind?, icon?,\ncollapsed? }\\` (kind \\`group\\` or \\`row\\`; a tab is \\`ui.tab\\`, never a group kind), and every later prop\nsends \\`{ id }\\` only. A prop joins a TAB with \\`ui.tab\\` the same way: the FIRST top-level prop in a tab\ndefines \\`{ id, label, icon?, order? }\\`, later props send \\`{ id }\\`; at most 8 tabs, labels ≤40 characters\nand unique; top-level props only (never a sub-field); all members of one \\`ui.group\\` share one tab. A V2\nkit entry's schema \\`groups\\` and each field's \\`group\\` map 1:1 to \\`ui.tab\\`, so its \\`design\\` group is a\ntab named Design holding the theme, sticky and similar props. A FIELD never takes \\`ui.group\\` or\n\\`ui.tab\\`; it joins a fieldset with \\`fieldsetId\\`.\n\n\\`\\`\\`jsonc\n{ \"key\": \"slides\", \"label\": \"Slides\", \"type\": \"table\",\n \"target\": { \"blockId\": \"slider\", \"path\": \"props.slides\" },\n \"ui\": { \"preview\": { \"title\": \"caption\", \"media\": \"image\" }, \"layout\": \"grid\" },\n \"config\": { \"fields\": [ { \"key\": \"image\", \"type\": \"image\", ... },\n { \"key\": \"caption\", \"type\": \"text\", ... } ] } }\n\\`\\`\\`\n\n**Patterns — what the dock draws, and the key that asks for it.**\n- **leaf** — one field, one control. Nothing to declare; \\`ui.control\\` only when the default is wrong.\n- **group** — a \\`kind: 'group'\\` fieldset (a prop: \\`ui.group\\`): a disclosure that shows two values\n when closed. \\`collapsed: true\\` starts it closed.\n- **row** — a \\`kind: 'row'\\` fieldset: at most 3 short scalars (number, rating, color, boolean, date,\n datetime, select) on one line. No \\`ui.control\\` on a row member.\n- **branch** — a nesting field drawn as a drill-in row with its \\`ui.icon\\` and a summary.\n- **list** — repeatable items named by \\`ui.itemLabel\\` and \\`ui.preview\\`.\n- **grid** — \\`layout: 'grid'\\`, media-led: the field needs an image or file child for \\`preview.media\\`.\n- **table** — \\`layout: 'table'\\`: at most 3 scalar columns (text, number, select, boolean, date,\n datetime, slug, email).\n- **section header** — a fieldset's \\`name\\` and \\`description\\` over its fields.\n- **conditional** — \\`showIf\\`, placed AFTER the field it reads.\n\n**Budgets, per dock screen.** \\`get_next_steps\\` measures them (\\`dock-budget\\`):\n- at most **8 ungrouped leaves** at rest (the pinned fields plus any one tab);\n- at most **12 leaves in a group**, and branches at most **3 levels** deep;\n- **any value within 2 activations** of its section screen. A collapsed group, a non-first tab and a\n branch each cost 1, so a group inside tab 2 already costs 2: leave groups in non-first tabs open.\nImportance orders a screen: required fields first, then array order.\n\n**Recipes — named key presets, never code.** Pick the one the section is; adapt the child keys.\n\n| Recipe | Keys |\n|---|---|\n| Gallery | \\`layout:'grid'\\`, \\`preview:{media:'image', title:'caption'}\\`, \\`itemLabel:'Image'\\`, \\`icon:'images'\\` |\n| Logo wall | \\`layout:'grid'\\`, \\`preview:{media:'logo', title:'name'}\\`, \\`itemLabel:'Logo'\\`, \\`icon:'image'\\` |\n| Team | \\`layout:'grid'\\`, \\`preview:{media:'photo', title:'name', subtitle:'role'}\\`, \\`itemLabel:'Person'\\`, \\`icon:'users'\\` |\n| Testimonials | \\`preview:{title:'author', subtitle:'role', media:'avatar'}\\`, \\`itemLabel:'Testimonial'\\`, \\`icon:'double-quote'\\` |\n| Steps | \\`preview:{title:'title'}\\`, \\`itemLabel:'Step'\\`, \\`icon:'olist'\\`; \\`reorderable:false\\` only on Tier-1 evidence |\n| Pricing tiers | \\`preview:{title:'name', subtitle:'price'}\\`, \\`itemLabel:'Tier'\\`, \\`icon:'tiers'\\` |\n| FAQ | \\`preview:{title:'question'}\\`, \\`itemLabel:'Question'\\`, \\`icon:'help-circle'\\` |\n| Nav links | \\`preview:{title:'label', subtitle:'href'}\\`, \\`itemLabel:'Link'\\`, \\`icon:'link'\\` (never a table: a label and its href are one link) |\n| Stats | \\`layout:'table'\\` over ≤3 scalar columns (value, label, suffix), \\`itemLabel:'Stat'\\`, \\`icon:'bar-chart'\\` |\n| CTA | one \\`kind:'group'\\` fieldset holding the heading, text and ONE \\`button\\` field, \\`icon:'launch'\\` |\n| Dimensions | one \\`kind:'row'\\` fieldset of up to 3 numbers (width, height, gap) |\n\n**The V2 schema language — to get X in the editor, write Y.** Every key below is editor-only and stored as sent, EXCEPT \\`type: 'object'\\`: it changes the stored and delivered value to \\`{ [childKey]: value }\\` (a \\`group\\` carries \\`<key>.nonRepeatable.<sub>\\` instead), and codegen types it as a nested object, so swapping group ↔ object moves values and templates.\n\n| To get this in the editor | Write this |\n|---|---|\n| A section that starts closed / a static heading | fieldset \\`collapsed: true\\` / \\`collapsible: false\\` |\n| Two short fields side by side | fieldset \\`columns: 2\\` |\n| One Desktop · Tablet · Phone switcher | three \\`type: 'object'\\` fields named \\`desktop\\`, \\`tablet\\`, \\`phone\\`, each with \\`fieldsetId\\` pointing at ONE fieldset with \\`layout: 'breakpoints'\\` |\n| A small inset of 2–3 fields, or a row that opens its own screen | \\`type: 'object'\\` with \\`fields\\`; \\`openMode: 'inline', 'drill', 'popover', 'dialog'\\` |\n| List rows that drill in instead of expanding | \\`openMode: 'drill'\\` on the array (or repeater) |\n| Tiles instead of rows | \\`ui.layout: 'grid'\\` on a list of objects (V2 \\`arrayLayout: 'grid'\\`); a primitive image array takes \\`'gallery'\\` |\n| BetterCMS-only list layouts | \\`ui.layout: 'rows'\\` (≡ 'list'), \\`'chips'\\`, \\`'gallery'\\`, also on a primitive array. Never chips for a feature list: chips cut long lines |\n| A size capsule with numeric steps | \\`type: 'number'\\`, \\`config.scale: { steps: {min, max, step} or [{value, label}], units?, presets? }\\`. Token (string) steps and an \\`allowCustom\\` object are refused (\\`scale_invalid\\`): use numeric steps and \\`allowCustom: true\\` |\n| Help under the label / longer help behind ⓘ | \\`helpText\\` / \\`helpMore\\` |\n| Calm defaults for rare settings | \\`advanced: true\\` |\n| A soft length warning (amber, never a refusal) | \\`recommendedMax: 60\\` |\n| A marketer cannot change it | \\`readOnly: 'developer'\\` plus \\`lockReason\\` |\n| A field that shows only sometimes | \\`showIf\\` (it SHOWS the field): ops \\`eq\\`, \\`neq\\`, \\`in\\`, \\`notIn\\`, \\`gt\\`, \\`lt\\` (one number as a string), \\`isSet\\`, \\`notEmpty\\`, \\`empty\\` |\n| A good row title and thumbnail | \\`ui.preview: { title, subtitle, media, fallback }\\` (\\`fallback\\` is a literal label) |\n| Labels that classify or filter (topics, keywords), never a feature list | \\`type: 'tags'\\`: a string[], trimmed, de-duplicated, each ≤64 characters; \\`config.options\\` are suggestions, \\`config.max\\`, \\`config.allowCustom: false\\` closes the list (\\`tags_value_invalid\\`) |\n| A star rating | \\`type: 'rating'\\`: a number from 0 to \\`config.max\\` (5), \\`config.step\\` 1 or 0.5 (\\`rating_value_invalid\\`) |\n| A code snippet | \\`type: 'code'\\`: \\`{ language?, code }\\` or a string; \\`config.language\\` default, \\`config.languages\\` allowlist (\\`code_value_invalid\\`) |\n| \"Add question\" instead of \"Add item\" | \\`ui.itemLabel: 'Question'\\` (V2 \\`itemNoun\\`; there is no itemNoun key) |\n| The same section as a component (the dock edits a page section through its props) | the same keys on its \\`props\\`: \\`type: 'object'\\` with \\`config.fields\\` (\\`group\\` and \\`table\\` too, 10 levels), \\`datetime\\`, \\`slug\\`, \\`email\\`, \\`phone\\`, \\`json\\`, \\`location\\`, \\`tags\\`, \\`rating\\`, \\`code\\`, plus the two CMS-item types (\\`reference\\`, \\`multi-reference\\`: \\`config.contentModelId\\` or \\`polymorphic\\` + \\`allowedModelSlugs\\`; page reads hydrate them, a text slot shows the title), and every key above except fieldsets (props group with \\`ui.group\\` and tab with \\`ui.tab\\`) |\n\nAn 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.\n\n**Tabs.** A \\`kind: 'tab'\\` fieldset is a tab:\n- at most **3** tabs, names at most 40 characters and unique;\n- top-level fields only: tabs never nest (a component's props take tabs through \\`ui.tab\\`, its own rules);\n- untabbed fields stay PINNED above the strip;\n- a group or row fieldset joins a tab with \\`tab: '<tab id>'\\`; groups in a non-first tab default open;\n- with fewer than 2 non-empty tabs no strip renders, so a tab for one fieldset is noise.\n\n\\`\\`\\`jsonc\n\"fieldsets\": [\n { \"id\": \"content\", \"name\": \"Content\", \"kind\": \"tab\" },\n { \"id\": \"style\", \"name\": \"Style\", \"kind\": \"tab\" },\n { \"id\": \"cta\", \"name\": \"Button\", \"kind\": \"group\", \"tab\": \"content\", \"icon\": \"launch\" },\n { \"id\": \"size\", \"name\": \"Size\", \"kind\": \"row\", \"tab\": \"style\" }\n]\n\\`\\`\\`\n\n**The write path — existing fields, by path, with If-Match.**\n- A model's fields: \\`update_content_model\\` with \\`fieldUi\\`, \\`fieldFieldset\\`, \\`fieldOrder\\`,\n \\`fieldLabel\\`, \\`fieldHelpText\\` (keyed by dotted key path, \\`'hero.title'\\`) and \\`fieldsets\\`. A page's\n schema: the same call with \\`pageId\\` instead of \\`modelId\\`, and the version from \\`get_page\\`'s\n \\`backingModel\\`.\n- A component's props: \\`update_component\\` with \\`propUi\\`, \\`propGroup\\`, \\`propTab\\`, \\`propLabel\\`, \\`propHelpText\\` (keyed by prop key).\n Name props from the code (\\`plan.cents\\` → Cents); help text only where a format, a hidden placement, a constraint or a fallback needs it (\"Whole number, no currency symbol.\"), one plain sentence under 90 characters with no semicolons or dashes, never repeating\n the value; repeated cards are one \\`table\\` prop. An icon (\\`config.media: \"icon\"\\`) is content: group it, never prune it.\n They write the DRAFT props; no publish is needed for the editor to show them.\n- Always send \\`ifMatch\\`, the \\`optimisticVersion\\` you read.\n- A NEW field carries its chrome in the same \\`add_field\\` call.\n\n**The dock's refusals, each named in the message.**\n- **428** \\`precondition-required\\` — a chrome key without \\`ifMatch\\`. Read, then send it.\n- **409** \\`version-conflict\\` — someone wrote since your read. Read again, re-apply; never retry blindly.\n- **409** \\`ui_human_owned\\` — a person shaped those paths. Leave them, or send \\`override: true\\`, and\n only when the user said so.\n- \\`tab_unknown\\`, \\`tab_nested\\`, \\`tab_props\\`, \\`tab_max\\`, \\`tab_name\\`, \\`tab_depth\\` — the tab rules above.\n- \\`prop_tab_unknown\\`, \\`prop_tab_redefined\\`, \\`prop_group_split_tabs\\` — a prop's \\`ui.tab\\` rules (\\`tab_max\\`,\n \\`tab_name\\` and \\`tab_nested\\` too); \\`tab_props\\` is a \\`ui.group\\` with \\`kind: 'tab'\\` — use \\`ui.tab\\`.\n- \\`fieldset_unknown\\` / \\`fieldset_orphan\\` — a \\`fieldsetId\\` naming no fieldset, or a list that drops a\n fieldset its fields still name.\n- \\`row_member_type\\`, \\`row_member_count\\`, \\`row_member_control\\` — the row rule.\n- \\`pair_split\\` — a legacy button's label and href in different fieldsets.\n- \\`cta_pair\\` — a NEW text field beside a link keyed like it plus \\`-href\\` (\\`hero-span-go\\` + \\`hero-a-go-href\\`): one\n call to action. Add ONE \\`type: \"button\"\\` field (value \\`{ label, href }\\`); on a component, point both props\n at one button block. A pair a page ALREADY holds (\\`primaryCtaText\\` + \\`primaryCtaHref\\`) is never refused:\n turn it into one button with \\`update_field { pageId, path: <label key>, mergeHref: <link key> }\\` —\n drafts only, the old values stay, the live copy changes on publish.\n- \\`ui.icon\\` or \\`ui.itemLabel\\` on a leaf; an icon name not in \\`bettercms://icons/dock\\`.\n- \\`layout_grid\\` — a grid with no image or file child. \\`layout_table\\` — more than 3 columns, or a\n column that is not a scalar.\n- \\`prop_group_unknown\\` / \\`prop_group_redefined\\` — the \\`ui.group\\` define-once rule.\n- \\`field_path_unknown\\` / \\`field_path_ambiguous\\` / \\`field_order_not_permutation\\` — a path that names\n no field or two, or an order that is not exactly the parent's keys.\n\n**THE RECEIPT — read it back.** There is no separate verification tool and no mode to flip.\n\\`get_content_model\\` (and \\`get_page\\` / \\`get_component\\`) return each field's — and each component\nprop's — stored \\`ui\\`, \\`helpText\\` and \\`showIf\\`. A prop that is ABSENT from that response was not\nstored, whatever the write returned — §11 RECEIPTS rule 3, applied to this feature. For a page, read\n\\`get_page\\` and its \\`backingModel\\`. Then call \\`get_next_steps\\`: \\`dock-budget\\`, \\`dock-repeater-unnamed\\`\nand \\`dock-showif-order\\` must all be gone. Declare, then read back, then say it works.\n\n**No \\`order\\` property. Ever.** A field's order IS its index in \\`fields\\`. To put a new field\nsomewhere other than the end, pass \\`after: '<existing top-level field key>'\\` to \\`add_field\\`;\nomit it and the field appends, exactly as before. \\`after\\` is an argument\napplied once at the write — a stored ordering prop would be a second source of truth that\ndisagrees with the array the moment anyone drags a row in the builder.\n\n**Where the values come from — three tiers, in order. Stop at the first that answers.**\n\n TIER 1 DERIVE FROM THE SITE'S SOURCE, when you have a checkout.\n <img src={item.image}> + <h3>{item.name}</h3> inside the map over \\`team\\`\n → ui.preview = { title: 'name', media: 'image' }\n A section rendered inside a <details> or behind a \"Show advanced\" toggle\n → ui.collapsed: true\n grid-cols-* / display:grid on the wrapper of the .map → ui.layout: 'grid'\n A FIXED-ARITY render — steps[0]/steps[1]/steps[2], or copy that names the\n positions (\"Step 1\", \"then\", \"finally\") → ui.reorderable: false\n A prop read only when another is set → showIf\n 🔴 THE SERVER NEVER READS YOUR SOURCE on the add_field path. \\`pull_project_source\\`\n and \\`get_conversion_brief\\` hand YOU the repo; this tier is work you do in your own\n checkout before you call the tool. On a greenfield, schema-first project there is\n no source at all — Tier 1 is vacuous and TIER 2 IS THE FLOOR.\n\n TIER 2 DERIVE FROM THE FIELD SHAPE, when the code is silent.\n A repeater whose children include exactly one image-ish child → that is \\`media\\`.\n Its first required short-text child (name/title/heading/label) → that is \\`title\\`.\n A nesting field with more than ~6 children, or one whose label reads as optional\n (\"Advanced\", \"Extras\", \"SEO overrides\") → \\`collapsed: true\\`.\n A repeatable whose item is MOSTLY its image (gallery, logos, team) → \\`layout:\n 'grid'\\`; anything whose words are the point stays 'list' — so OMIT \\`layout\\`.\n \\`reorderable\\` HAS NO TIER-2 GUESS. The default (true) is the safe one, and\n locking a list the user did not ask to lock takes a capability away from them.\n Leave it absent unless Tier 1 showed you a fixed arity or the user said so.\n Guessing here is CORRECT. A wrong preview costs one edit; asking about every\n repeater on a 40-field schema costs the user the session.\n\n TIER 3 ASK THE USER — only when 1 and 2 are both silent, and only for these three:\n a) MANY fields in one panel, where the grouping and the order depend on which\n content the user considers primary. You cannot know their priorities.\n b) CONDITIONAL VISIBILITY (\\`showIf\\`). It encodes business logic — when a field is\n irrelevant — and nothing in the code or the shape tells you that.\n c) VARIANTS SHARING A \\`sectionType\\`. Their prop keys MUST match (§4), so a preview\n or a rename that diverges between two variants makes a layout swap lose content.\n Confirm the shared key set before you declare per-variant chrome.\n Ask with AskUserQuestion, batched, once — never one field at a time.\n`;\n","/**\n * The `bettercms` skill, served as MCP resources: `bettercms://skill/bettercms` for SKILL.md and\n * `bettercms://skill/<stem>` for each `references/<stem>.md`.\n *\n * A skill is loaded only by a client that has it installed. The same references as resources\n * reach every client — fetched on demand, never in tools/list, never truncated — so an agent\n * without the skill can still read the one reference its task needs.\n *\n * One loader for both surfaces, reading markdown from disk:\n * - the hosted connector runs from source, where this file sits at packages/mcp/src and the\n * skill at packages/skills/bettercms (the runtime image copies the whole packages/ tree);\n * - the npm package ships a copy at dist/skills/bettercms, made by tsup's onSuccess, because\n * node_modules/@bettercms-ai/mcp has no sibling skills package.\n * The first of those that holds a SKILL.md wins. None found = no skill resources, never a crash:\n * a server that cannot serve a reference must still serve its tools.\n */\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const SKILL_URI_PREFIX = \"bettercms://skill/\";\n/** The core skill's own name: SKILL.md is served at bettercms://skill/bettercms. */\nexport const CORE_SKILL = \"bettercms\";\n\nexport interface SkillDoc {\n uri: string;\n name: string;\n title: string;\n description?: string;\n mimeType: \"text/markdown\";\n text: string;\n}\n\n/** Where the skill lives, in the order a build or a checkout would put it. */\nconst CANDIDATES = [\"./skills/bettercms/\", \"../../skills/bettercms/\"];\n\nexport function defaultSkillDir(): string | null {\n for (const rel of CANDIDATES) {\n const dir = fileURLToPath(new URL(rel, import.meta.url));\n if (existsSync(join(dir, \"SKILL.md\"))) return dir;\n }\n return null;\n}\n\n/** `title` / `description` from a leading YAML frontmatter block: plain, quoted or folded scalars. */\nexport function frontmatterOf(text: string): Record<string, string> {\n const m = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n/.exec(text);\n if (!m) return {};\n const out: Record<string, string> = {};\n const lines = m[1]!.split(/\\r?\\n/);\n for (let i = 0; i < lines.length; i++) {\n const kv = /^([A-Za-z_][\\w-]*):\\s*(.*)$/.exec(lines[i]!);\n if (!kv) continue;\n let value = kv[2]!.trim();\n if (value === \">\" || value === \"|\" || value === \">-\" || value === \"|-\") {\n const block: string[] = [];\n while (i + 1 < lines.length && /^\\s+\\S/.test(lines[i + 1]!)) block.push(lines[++i]!.trim());\n value = block.join(value.startsWith(\">\") ? \" \" : \"\\n\");\n } else if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1).replace(/\\\\\"/g, '\"');\n }\n if (value) out[kv[1]!] = value;\n }\n return out;\n}\n\n/** The resource for one markdown file: frontmatter `title`/`description`, else its first `# ` heading. */\nexport function skillDocOf(stem: string, text: string): SkillDoc {\n const fm = frontmatterOf(text);\n const heading = /^#\\s+(.+?)\\s*$/m.exec(text)?.[1];\n const title = fm.title ?? heading ?? stem;\n const description = fm.description ?? heading;\n return {\n uri: `${SKILL_URI_PREFIX}${stem}`,\n name: `skill-${stem}`,\n title,\n ...(description ? { description } : {}),\n mimeType: \"text/markdown\",\n text,\n };\n}\n\n/** SKILL.md first, then every reference by name. */\nexport function loadSkillDocs(dir: string | null = defaultSkillDir()): SkillDoc[] {\n if (!dir) return [];\n const docs = [skillDocOf(CORE_SKILL, readFileSync(join(dir, \"SKILL.md\"), \"utf8\"))];\n const refs = join(dir, \"references\");\n if (!existsSync(refs)) return docs;\n for (const file of readdirSync(refs).filter((f) => f.endsWith(\".md\")).sort()) {\n const stem = file.slice(0, -3);\n if (stem === CORE_SKILL) continue;\n docs.push(skillDocOf(stem, readFileSync(join(refs, file), \"utf8\")));\n }\n return docs;\n}\n","/**\n * The Kit Library catalogue as MCP resources: which schema and blocks a section needs, and when.\n *\n * bettercms://kit the index: categories, edge tags, one line per entry\n * bettercms://kit/<category> every entry's notes in that category (why, HTML signals, mcp, pitfalls)\n * bettercms://kit/entry/{id} one entry: its notes plus the create_component payload (props)\n *\n * Source: kit-catalog.json beside this file, GENERATED by the dashboard (scripts/kit-export.ts) from its\n * KIT_LIBRARY + EXAMPLES. Never edit it here; regenerate from the dashboard with\n * `bun run kit:export -- --backend <this checkout>`, which also rewrites references/kit-catalog.md\n * (scripts/kit-reference.ts). tsup copies the JSON to dist, so the stdio package and the hosted connector\n * (which runs from source) read the same file. A missing file means no kit resources, never a crash.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const KIT_URI = \"bettercms://kit\";\nexport const KIT_ENTRY_URI_PREFIX = \"bettercms://kit/entry/\";\nexport const KIT_ENTRY_URI_TEMPLATE = `${KIT_ENTRY_URI_PREFIX}{id}`;\n\nexport interface KitEntry {\n id: string;\n name: string;\n category: string;\n tags: string[];\n proves: string;\n why: string;\n htmlSignals: string[];\n mcp: string;\n pitfalls: string[];\n notCarried: string[];\n component: { props: unknown[] } & Record<string, unknown>;\n}\nexport interface KitCatalog {\n $comment: string;\n categories: { name: string; slug: string; entries: string[] }[];\n tags: { tag: string; label: string; hint: string; entries: string[] }[];\n entries: KitEntry[];\n}\nexport interface KitDoc {\n uri: string;\n name: string;\n title: string;\n description: string;\n mimeType: \"text/markdown\";\n text: string;\n}\n\nexport function loadKitCatalog(path = fileURLToPath(new URL(\"./kit-catalog.json\", import.meta.url))): KitCatalog | null {\n return existsSync(path) ? (JSON.parse(readFileSync(path, \"utf8\")) as KitCatalog) : null;\n}\n\nconst list = (xs: string[]) => xs.map((x) => `- ${x}`).join(\"\\n\");\n\n/** One entry's notes, as markdown (shared by the category resource, the entry resource and the skill reference). */\nexport function entryNotes(e: KitEntry, h = \"###\"): string {\n const out = [`${h} ${e.name} (\\`${e.id}\\`)`, \"\", `Tags: ${e.tags.join(\", \") || \"none\"}. Proves: ${e.proves}`];\n if (!e.why && !e.mcp) out.push(\"\", \"No model notes in the kit for this entry: read its props.\");\n if (e.why) out.push(\"\", `**Why this shape.** ${e.why}`);\n if (e.htmlSignals.length) out.push(\"\", \"**HTML signals.**\", list(e.htmlSignals));\n if (e.mcp) out.push(\"\", `**Do.** ${e.mcp}`);\n if (e.pitfalls.length) out.push(\"\", \"**Pitfalls.**\", list(e.pitfalls));\n if (e.notCarried.length) out.push(\"\", `Not carried by a stored component: ${e.notCarried.join(\", \")}.`);\n return out.join(\"\\n\");\n}\n\nexport function kitIndexText(k: KitCatalog): string {\n const byId = new Map(k.entries.map((e) => [e.id, e]));\n return [\n \"# BetterCMS kit catalogue\",\n \"\",\n `${k.entries.length} modelled website sections. Before designing a section, find the closest entry by its edge tag or category, read its notes and follow its mcp + pitfalls; its create_component props are at ${KIT_ENTRY_URI_TEMPLATE}.`,\n \"\",\n \"## Categories\",\n \"\",\n ...k.categories.map((c) => `- ${c.name} (${c.entries.length}): ${KIT_URI}/${c.slug}`),\n \"\",\n \"## Edge tags\",\n \"\",\n ...k.tags.map((t) => `- \\`${t.tag}\\` (${t.hint}): ${t.entries.join(\", \") || \"none\"}`),\n \"\",\n \"## Entries\",\n \"\",\n ...k.categories.flatMap((c) => [\n `### ${c.name}`,\n \"\",\n ...c.entries.map((id) => {\n const e = byId.get(id)!;\n return `- \\`${e.id}\\` ${e.name} [${e.tags.join(\", \")}]: ${e.proves}`;\n }),\n \"\",\n ]),\n ].join(\"\\n\");\n}\n\nexport function kitCategoryText(k: KitCatalog, slug: string): string {\n const c = k.categories.find((x) => x.slug === slug)!;\n const byId = new Map(k.entries.map((e) => [e.id, e]));\n return [\n `# Kit: ${c.name}`,\n \"\",\n `${c.entries.length} entries. Each one's create_component props: ${KIT_ENTRY_URI_TEMPLATE}. Index: ${KIT_URI}.`,\n \"\",\n ...c.entries.map((id) => entryNotes(byId.get(id)!, \"##\") + \"\\n\"),\n ].join(\"\\n\");\n}\n\nexport function kitEntryText(e: KitEntry): string {\n return [\n entryNotes(e, \"#\"),\n \"\",\n \"## create_component payload\",\n \"\",\n \"Props in the exact shape create_component accepts. Adapt keys and copy to the site; keep the types, `ui` and config.\",\n \"\",\n \"```json\",\n JSON.stringify(e.component, null, 1),\n \"```\",\n \"\",\n ].join(\"\\n\");\n}\n\nexport const KIT_REFERENCE_FILE = \"packages/skills/bettercms/references/kit-catalog.md\";\n\n/** references/kit-catalog.md: the same notes as the category resources, in one file. Generated, never hand-edited. */\nexport function kitReferenceText(k: KitCatalog): string {\n const byId = new Map(k.entries.map((e) => [e.id, e]));\n const anchor = (s: string) => s.toLowerCase().replace(/[^a-z0-9 -]/g, \"\").replace(/ /g, \"-\");\n return [\n \"---\",\n \"title: Kit catalogue\",\n `description: The ${k.entries.length} modelled website sections of the BetterCMS kit, by category and edge tag, with each one's model notes (why, HTML signals, mcp, pitfalls). Generated from the dashboard kit; do not edit.`,\n \"---\",\n \"\",\n \"# Kit catalogue\",\n \"\",\n `<!-- GENERATED by packages/mcp/scripts/kit-reference.ts from packages/mcp/src/kit-catalog.json. Regenerate from the dashboard: bun run kit:export -- --backend <backend checkout> -->`,\n \"\",\n `Find the closest entry by edge tag or category, then follow its **Do** and **Pitfalls**. Each entry's create_component props: ${KIT_ENTRY_URI_TEMPLATE} (MCP resource). Search this file for an id or a tag rather than reading it whole.`,\n \"\",\n \"## Contents\",\n \"\",\n \"- [Edge tags](#edge-tags)\",\n ...k.categories.map((c) => `- [${c.name}](#${anchor(c.name)})`),\n \"\",\n \"## Edge tags\",\n \"\",\n ...k.tags.map((t) => `- \\`${t.tag}\\` (${t.hint}): ${t.entries.join(\", \") || \"none\"}`),\n \"\",\n ...k.categories.flatMap((c) => [`## ${c.name}`, \"\", ...c.entries.map((id) => entryNotes(byId.get(id)!) + \"\\n\")]),\n ].join(\"\\n\");\n}\n\n/** The listed resources: the index, then one per category. Entries are read through the template. */\nexport function kitDocs(k: KitCatalog | null = loadKitCatalog()): KitDoc[] {\n if (!k) return [];\n const doc = (uri: string, name: string, title: string, description: string, text: string): KitDoc => ({ uri, name, title, description, mimeType: \"text/markdown\", text });\n return [\n doc(KIT_URI, \"kit\", \"BetterCMS kit catalogue\", \"Index of modelled website sections by category and edge tag: find the closest one before designing a section.\", kitIndexText(k)),\n ...k.categories.map((c) =>\n doc(`${KIT_URI}/${c.slug}`, `kit-${c.slug}`, `Kit: ${c.name}`, `Model notes for the ${c.entries.length} ${c.name} entries: why, HTML signals, mcp, pitfalls.`, kitCategoryText(k, c.slug)),\n ),\n ];\n}\n\n/** uri → text for every entry (bettercms://kit/entry/<id>). */\nexport function kitEntryTexts(k: KitCatalog | null = loadKitCatalog()): Record<string, string> {\n return k ? Object.fromEntries(k.entries.map((e) => [`${KIT_ENTRY_URI_PREFIX}${e.id}`, kitEntryText(e)])) : {};\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,iBAAAA,sBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,YAAY,gBAAgB,wBAAwB;;;ACH7D,SAAS,WAAW,wBAAwB;AAC5C,SAAS,iBAAiB;;;ACD1B,SAAS,yBAAyB;AAClC,SAAS,SAAS;;;ACqCX,IAAM,mBACX;AAiCK,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AACF;;;AClHO,IAAM,uBAA0C,OAAO,OAAO;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,0BAA+C,IAAI,IAAI,oBAAoB;;;ACn6DjF,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EA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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["fileURLToPath","list","text","s","input","res","list","z","z","text","existsSync","readFileSync","fileURLToPath","slug","text","text","DeviceAuthClient","loadConfig","fileURLToPath"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/tools.ts","../../types/src/component.ts","../../types/src/layout-lucide-icons.ts","../../types/src/dock-icon-names.ts","../src/dock-icons.ts","../src/structure-playbook.ts","../src/entry-merge.ts","../src/whoami.ts","../src/model-field-edit.ts","../src/toolsets.ts","../src/tool-text.ts","../src/entry-query.ts","../src/prompts.ts","../src/playbook.ts","../src/skill-docs.ts","../src/kit.ts"],"sourcesContent":["import { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { loadConfig, FileTokenStore, DeviceAuthClient } from \"@bettercms-ai/device-auth\";\nimport { buildServer } from \"./server.js\";\n\nexport { buildServer } from \"./server.js\";\n// Re-exported so importers of @bettercms-ai/mcp keep working after the move to\n// @bettercms-ai/device-auth.\nexport { DeviceAuthClient, loadConfig } from \"@bettercms-ai/device-auth\";\n\n/** Entrypoint for the `bettercms-mcp` stdio server. */\nasync function main(): Promise<void> {\n const config = loadConfig();\n const store = new FileTokenStore(config.credentialsPath, config.apiUrl);\n const auth = new DeviceAuthClient(config, store);\n const server = buildServer({ auth, managementBaseUrl: config.managementBaseUrl });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n process.stderr.write(`[bettercms-mcp] ready on stdio (api: ${config.apiUrl})\\n`);\n}\n\n// Only run when executed as the entry (not when imported, e.g. in tests).\n// Compare realpaths so symlinked launch paths still detect the entrypoint:\n// `import.meta.url` is realpath-resolved by Node, but `process.argv[1]` is not,\n// so the old `file://${argv[1]}` check silently failed under npx `.bin`\n// symlinks, global installs, and macOS /var→/private/var — the server would\n// exit 0 without starting.\nfunction isMainModule(): boolean {\n const argv1 = process.argv[1];\n if (!argv1) return false;\n try {\n return realpathSync(argv1) === fileURLToPath(import.meta.url);\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n main().catch((err) => {\n process.stderr.write(`[bettercms-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n });\n}\n","import { McpServer, ResourceTemplate } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { BetterCMS } from \"@bettercms-ai/sdk\";\nimport { registerTools } from \"./tools.js\";\nimport { registerPrompts } from \"./prompts.js\";\nimport { PLAYBOOK_URI, SCHEMA_PLAYBOOK } from \"./playbook.js\";\nimport { DOCK_ICONS_RESOURCE, DOCK_ICONS_TEXT } from \"./dock-icons.js\";\nimport { loadSkillDocs } from \"./skill-docs.js\";\nimport { KIT_ENTRY_URI_TEMPLATE, kitDocs, kitEntryTexts } from \"./kit.js\";\nimport { CTA_BUTTON_INSTRUCTION, DOCK_UI_ROUTING_INSTRUCTION, LAYOUT_CHROME_INSTRUCTION, PUBLISH_HOLD_INSTRUCTION, RECEIPT_FIRST_INSTRUCTION, SKILLS_ROUTING_INSTRUCTION, STRUCTURE_DEFAULT_INSTRUCTION, STRUCTURE_PLAYBOOK, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.js\";\nimport { TOOL_LOADING_INSTRUCTION } from \"./toolsets.js\";\nimport type { DeviceAuthClient } from \"@bettercms-ai/device-auth\";\n\nexport const SERVER_NAME = \"bettercms\";\n// Tracks the shared MCP tool-catalog version (kept in sync with the remote /mcp\n// SERVER_INFO in src/routes/mcp/index.ts) so both surfaces report the same version.\nexport const SERVER_VERSION = \"1.5.0\";\n\n/**\n * Display identity, mirroring the remote host's SERVER_INFO (src/lib/brand.ts). Not\n * imported from it: this package is published to npm and must not depend on backend\n * internals — same deliberate duplication as SERVER_VERSION above, so keep both in sync.\n *\n * The URLs are absolute and hardcoded because a published stdio server has no env to\n * derive an origin from. `title`/`websiteUrl`/`icons` are additive 2025-11-25\n * Implementation fields; older clients ignore them.\n */\nconst SERVER_DISPLAY = {\n title: \"BetterCMS\",\n websiteUrl: \"https://bettercms.ai\",\n icons: [\n { src: \"https://api.bettercms.ai/brand/mark-cube-512.png\", mimeType: \"image/png\", sizes: [\"512x512\"] },\n { src: \"https://api.bettercms.ai/brand/mark-cube.svg\", mimeType: \"image/svg+xml\", sizes: [\"any\"] },\n ],\n};\n\n/**\n * Send `X-Branch-Id` on every request this client makes. The SDK has no branch option, and every\n * request goes through its `headers()`, so the header is laid over that one method.\n */\nexport function withBranch<C extends { headers(): Record<string, string> }>(client: C, branch?: string): C {\n if (!branch) return client;\n const base = client.headers.bind(client);\n client.headers = () => ({ ...base(), \"X-Branch-Id\": branch });\n return client;\n}\n\nexport interface BuildServerDeps {\n auth: DeviceAuthClient;\n managementBaseUrl: string;\n}\n\n/**\n * Build the BetterCMS MCP server with its tools registered. Auth is lazy — the\n * device flow runs on the first tool call, not at connect time, so the MCP\n * handshake/tool-listing never blocks on user approval.\n */\nexport function buildServer(deps: BuildServerDeps): McpServer {\n const server = new McpServer(\n { name: SERVER_NAME, version: SERVER_VERSION, ...SERVER_DISPLAY },\n {\n capabilities: { tools: {}, prompts: {}, resources: {} },\n // 🔴 The plain-language ask, routed — the stdio twin of the hosted connector's line\n // (src/routes/mcp/index.ts MCP_INSTRUCTIONS). \"Make my site editable\" has one recipe and\n // one definition of done; without this an agent converts the page it landed on and stops.\n instructions:\n TOOL_LOADING_INSTRUCTION + \" \" + RECEIPT_FIRST_INSTRUCTION + \" \" +\n \"When the user asks to make a site or all of its pages editable and they were DERIVED at import: editor_setup, then get_next_steps until `receipt.gate.complete`. To convert its source or bind its fields: this is playbook §13. Read `bettercms://playbook/schema` §13, call get_binding_report and get_conversion_brief { complete: true }, convert EVERY route the brief lists, and finish only when get_binding_report shows coverage.pending empty on every route — not when the first page works. On a workspace-wide connection pass projectId on every call; never ask the user to re-scope the connection. \" +\n LAYOUT_CHROME_INSTRUCTION + \" \" + CTA_BUTTON_INSTRUCTION + \" \" +\n // 🔴 A DIFFERENT ASK WITH A DIFFERENT RECIPE. \"Componentize the whole site\" used to route\n // to §13 (bindings) — the wrong job entirely: it makes a site editable in place rather\n // than turning its sections into a component library. §12 is the map, and the batch tools\n // are why it is a handful of calls instead of one per component.\n \"When the user asks to componentize the whole site, to turn every section into a component, or to build a component library from the site: this is playbook §12. Read `bettercms://playbook/schema` §12, start with get_site_composition, and use the batch tools — componentize_sections, compose_pages, update_layout with `commands`, publish_components — rather than one call per component. Finish with get_site_composition and tell the user what the platform does not model (cookie banners, modals, breadcrumbs, pagination) and which components still need the owner's approval in the dashboard before they can be published. \" +\n // The default after authoring (the structure standard): organise what you made. Same\n // sentence as the hosted connector's MCP_INSTRUCTIONS.\n STRUCTURE_DEFAULT_INSTRUCTION + \" \" + SKILLS_ROUTING_INSTRUCTION + \" \" + DOCK_UI_ROUTING_INSTRUCTION + \" \" + PUBLISH_HOLD_INSTRUCTION,\n },\n );\n\n // The structure standard, beside the schema playbook: how to organise the Content sidebar.\n server.registerResource(\n \"structure-playbook\",\n STRUCTURE_PLAYBOOK_URI,\n {\n title: \"BetterCMS Content structure playbook\",\n description:\n \"How to organise a project's Content sidebar: one place per document, the home page and list pages pinned, one folder per content family named for the detail type its route holds and ordered by entry count, shared taxonomies in Shared, Pages for the rest, Settings last, at most 2 levels. With a worked set_content_structure payload.\",\n mimeType: \"text/markdown\",\n },\n () => ({\n contents: [{ uri: STRUCTURE_PLAYBOOK_URI, mimeType: \"text/markdown\", text: STRUCTURE_PLAYBOOK }],\n }),\n );\n\n // The playbook is a RESOURCE, not a tool description: it is fetched once by a client\n // that wants it, rather than riding in the prompt on every turn. Mirrors the hosted\n // /mcp PLAYBOOK_RESOURCE (src/routes/mcp/index.ts) — same URI, name and mime, so the\n // `bettercms://playbook/schema` that prompts and tool descriptions point at resolves\n // on stdio too. Without this, `import-site`'s \"read section 11 first\" is a dead link.\n server.registerResource(\n \"schema-playbook\",\n PLAYBOOK_URI,\n {\n title: \"BetterCMS schema & components playbook\",\n description:\n \"How to design a components-first BetterCMS project: components vs collections, section anatomy, sectionType variants, kind:'block' + modular fields, the 'document' article body, the draft->publish order, and what makes an imported site editable.\",\n mimeType: \"text/markdown\",\n },\n () => ({\n contents: [{ uri: PLAYBOOK_URI, mimeType: \"text/markdown\", text: SCHEMA_PLAYBOOK }],\n }),\n );\n\n // The dock's icon names: a resource, so the ~3 KB list never rides in a tool schema.\n const { uri: dockIconsUri, name: dockIconsName, ...dockIconsMeta } = DOCK_ICONS_RESOURCE;\n server.registerResource(dockIconsName, dockIconsUri, dockIconsMeta, () => ({\n contents: [{ uri: dockIconsUri, mimeType: dockIconsMeta.mimeType, text: DOCK_ICONS_TEXT }],\n }));\n\n // The bettercms skill, one resource per file, for a client that does not have it installed\n // (bettercms://skill/bettercms and bettercms://skill/<reference>). Same loader and URIs as the\n // hosted RESOURCES, so an instruction or a skill that names one resolves on both surfaces.\n for (const { uri, name, text, ...meta } of loadSkillDocs()) {\n server.registerResource(name, uri, meta, () => ({ contents: [{ uri, mimeType: meta.mimeType, text }] }));\n }\n\n // The kit catalogue (bettercms://kit, one resource per category, and each entry through a template):\n // which schema and blocks a section needs, generated from the dashboard kit. Same URIs as the hosted RESOURCES.\n for (const { uri, name, text, ...meta } of kitDocs()) {\n server.registerResource(name, uri, meta, () => ({ contents: [{ uri, mimeType: meta.mimeType, text }] }));\n }\n const kitEntries = kitEntryTexts();\n if (Object.keys(kitEntries).length) {\n server.registerResource(\n \"kit-entry\",\n new ResourceTemplate(KIT_ENTRY_URI_TEMPLATE, { list: undefined }),\n { title: \"Kit entry\", description: \"One kit entry: its model notes and the create_component props. Ids are in bettercms://kit.\", mimeType: \"text/markdown\" },\n (uri) => {\n const text = kitEntries[uri.href];\n if (text === undefined) throw new Error(`Unknown kit entry: ${uri.href}`);\n return { contents: [{ uri: uri.href, mimeType: \"text/markdown\", text }] };\n },\n );\n }\n\n registerTools(server, {\n auth: deps.auth,\n // `project` is the per-call target of a workspace-wide grant; the SDK sends it as\n // X-BCMS-Project. Omitted entirely when absent so a project-scoped key's request is\n // byte-identical to before.\n createClient: (apiKey, project, branch) =>\n withBranch(BetterCMS.management({ apiKey, baseUrl: deps.managementBaseUrl, ...(project ? { project } : {}) }), branch),\n });\n\n // Guided slash-command prompts ship with the server (auto-available as\n // /mcp__bettercms__studio and /mcp__bettercms__new_page when the MCP is added).\n registerPrompts(server);\n\n return server;\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { z } from \"zod\";\nimport { SECTION_DOCTRINE as DOCTRINE } from \"@bettercms-ai/types\";\nimport { BetterCMSError } from \"@bettercms-ai/sdk\";\nimport { DOCK_ICON_NAME_SET, LAYOUT_SECTION_ICON_SET, type ContentModelFieldUi, type DockIconName } from \"@bettercms-ai/types\";\nimport { DOCK_ICON_SET, DOCK_ICONS_URI } from \"./dock-icons.js\";\nimport { DeviceAuthPendingError } from \"@bettercms-ai/device-auth\";\nimport { NEXT_STEPS_DESCRIPTION, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.js\";\nimport { mergesEntry, planEntryMerge } from \"./entry-merge.js\";\nimport { WHOAMI_DESCRIPTION } from \"./whoami.js\";\nimport { fieldRemovalRequest, planFieldEdit, planFieldRemoval, type StoredModel } from \"./model-field-edit.js\";\nimport { LISTING_TAIL, listsTool, toolMeta, toolsetsOf } from \"./toolsets.js\";\nimport { ADD_FIELD_DESCRIPTION, FIELD_LOCKED_NOTE, GET_SEO_DESCRIPTION, MOVE_STAGE_DESCRIPTION, NEW_TOOL_TEXT, PARAM_TEXT, SEO_KEY_TEXT, UPDATE_FIELD_DESCRIPTION, UPDATE_SEO_DESCRIPTION, V2_LEAF_TYPES_NOTE, WEBHOOK_EVENTS } from \"./tool-text.js\";\nimport { BUTTON_FIELD_NOTE, KIT_ENTRY_REBUILD_NOTE, LINK_VALUE_NOTE, DELETE_PAGE_RUNTIME_BUNDLE, INPUT_CONFIRMED_HEADER, LAYOUT_LOCK_NOTE, PROP_V2_NOTE, SLOT_MULTIPLE_NOTE, UNPROPPED_COPY_NOTE, UPDATE_PAGE_IF_MATCH_NOTE, VARIANT_GROUP_NOTE, WINDOW_NOTE, DETACHED_COPY_NOTE } from \"./tool-text.js\";\nimport { entryListSearch } from \"./entry-query.js\";\nimport type {\n ManagedContentModel,\n ManagedContentEntry,\n ManagedPage,\n ManagedForm,\n ManagedFormInput,\n ManagedComponent,\n ManagedComponentSummary,\n ManagedComponentInput,\n ExtractionCandidate,\n CreateModelInput,\n UpdateModelInput,\n CreateEntryInput,\n UpdateEntryInput,\n CreateManagedPageInput,\n AddPageFieldsInput,\n UploadAssetInput,\n UploadedAsset,\n WriteContentInput,\n SeoMetaInput,\n SeoMeta,\n} from \"@bettercms-ai/sdk\";\nimport { COMPONENT_PROP_TYPES } from \"@bettercms-ai/types\";\nimport type {\n LayoutDataDocument,\n LayoutStructureDocument,\n ManagementLayoutCommand,\n PageLayoutOverrideDocument,\n} from \"@bettercms-ai/types\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\n/** Subset of the management SDK client the tools use (kept narrow for testability). */\nexport interface ManagementApi {\n listPages(): Promise<ManagedPage[]>;\n getPage(id: string): Promise<ManagedPage>;\n getModel(id: string): Promise<ManagedContentModel>;\n createModel(input: CreateModelInput): Promise<ManagedContentModel>;\n updateModel(id: string, input: UpdateModelInput, opts?: { ifMatch?: number }): Promise<ManagedContentModel>;\n /** `warnings` / `seedErrors`: the page exists, but the `data` seed was not stored. */\n createPage(input: CreateManagedPageInput): Promise<ManagedPage & { warnings?: string[]; seedErrors?: Record<string, string> }>;\n addPageFields(id: string, input: AddPageFieldsInput): Promise<ManagedPage>;\n setPageContent(\n id: string,\n input: { data: Record<string, unknown>; status?: \"draft\" | \"published\" },\n ): Promise<ManagedContentEntry>;\n /** `warnings`: advisory notes the server attached to the write (the write succeeded). */\n createEntry(input: CreateEntryInput): Promise<ManagedContentEntry & { warnings?: string[] }>;\n updateEntry(\n id: string,\n input: UpdateEntryInput,\n opts?: { ifMatch?: number },\n ): Promise<ManagedContentEntry & { warnings?: string[] }>;\n listEntries(filter?: {\n modelId?: string;\n pageId?: string;\n status?: \"draft\" | \"published\";\n }): Promise<ManagedContentEntry[]>;\n getEntry(id: string): Promise<ManagedContentEntry>;\n uploadAsset(input: UploadAssetInput): Promise<UploadedAsset>;\n deletePage(id: string): Promise<{ id: string }>;\n deleteEntry(id: string): Promise<{ id: string }>;\n deleteModel(id: string): Promise<{ id: string }>;\n listForms(): Promise<ManagedForm[]>;\n getForm(id: string): Promise<ManagedForm>;\n createForm(input: ManagedFormInput): Promise<ManagedForm>;\n updateForm(id: string, input: ManagedFormInput): Promise<ManagedForm>;\n listComponents(): Promise<ManagedComponent[]>;\n listComponents(options: { select: \"summary\" }): Promise<ManagedComponentSummary[]>;\n getComponent(id: string): Promise<ManagedComponent>;\n createComponent(input: ManagedComponentInput): Promise<ManagedComponent>;\n updateComponent(id: string, input: ManagedComponentInput, opts?: { ifMatch?: number }): Promise<ManagedComponent>;\n listExtractionCandidates(projectId?: string): Promise<ExtractionCandidate[]>;\n extractComponent(input: {\n hash: string;\n name: string;\n slug: string;\n projectId?: string;\n }): Promise<{ component: ManagedComponent; replaced: number }>;\n getManagedLayout(opts?: { scope?: \"global\" | \"page\"; pageId?: string; copy?: \"draft\" | \"published\"; projectId?: string }): Promise<ManagedLayoutDocument>;\n commandManagedLayout(input: { scope?: \"global\" | \"page\"; pageId?: string; projectId?: string; command: ManagementLayoutCommand; ifMatch: number }): Promise<ManagedLayoutDocument>;\n publishManagedLayout(input: { ifMatch: number; projectId?: string }): Promise<ManagedLayoutDocument>;\n writeContent(input: WriteContentInput): Promise<string>;\n generateSeoMeta(input: SeoMetaInput): Promise<SeoMeta>;\n // Generic escape hatch for the lifecycle tools (media mgmt, submissions, redirects,\n // SEO, site-files, promote, versions). These management endpoints have no bespoke SDK\n // method; the MCP tools call them straight through the client's public request plumbing,\n // so parity with the remote /mcp surface needs no per-endpoint SDK code (DRY).\n url(path: string): string;\n fetchJSON<T>(url: string, init?: RequestInit): Promise<T>;\n}\n\ntype ManagedLayoutDocument =\n | { scope: \"global\"; revision: number; etag: string; status: string; structure: LayoutStructureDocument; data: LayoutDataDocument }\n | { scope: \"page\"; pageId: string; pageSlug: string; revision: number; etag: string; status: string; globalStructure: LayoutStructureDocument; globalData: LayoutDataDocument; override: PageLayoutOverrideDocument };\n\nexport interface ToolDeps {\n auth: {\n getAccessToken(): Promise<string>;\n refresh(): Promise<string | null>;\n /** Forget cached creds + re-run device flow (used when the bound project was deleted). */\n resetAndReauthorize(): Promise<string>;\n };\n /**\n * Build a management client bound to the given access token, targeting `project`.\n *\n * `project` is the per-call target a WORKSPACE-WIDE grant must name — the SDK sends it as\n * `X-BCMS-Project`, which is what the Management middleware resolves the request's project\n * from. Undefined for a project-scoped grant, which carries its target on the key (and whose\n * middleware refuses a header naming anything else).\n *\n * `branch` is the call's content branch (`branchId`), sent as `X-Branch-Id`.\n */\n createClient: (apiKey: string, project?: string, branch?: string) => ManagementApi;\n /**\n * Ask the HUMAN a question mid-tool-call (MCP elicitation). Optional because plenty of\n * clients don't implement it — every caller must degrade to telling the model to ask in\n * chat instead. Wired from the McpServer in registerTools.\n */\n elicit?: (params: {\n message: string;\n requestedSchema: { type: \"object\"; properties: Record<string, unknown>; required?: string[] };\n }) => Promise<{ action: string; content?: Record<string, unknown> }>;\n}\n\n// ── Asking the human ──────────────────────────────────────────────────────────\n\n/**\n * Ask the HUMAN one question through the client (MCP elicitation), or hand the question back\n * as text for the model to ask in chat.\n *\n * The one outcome that never happens is a silent answer. A client that cannot elicit, a person\n * who dismisses the prompt, and a client that answers with the wrong type all land on the same\n * `{ prompt }`, which the caller returns as an error so the model has to go and ask.\n *\n * `accept` is a type predicate rather than a truthiness check on purpose: a boolean question's\n * legitimate answer is `false`, and every `if (picked)` shape would quietly discard it and fall\n * through to \"ask again\" forever.\n */\nasync function askHuman<T>(\n deps: ToolDeps,\n q: {\n /** Property name in the requested schema, and the key the answer comes back under. */\n key: string;\n message: string;\n /** The JSON-schema primitive describing the answer (string+enum, boolean+default, …). */\n property: Record<string, unknown>;\n accept: (value: unknown) => value is T;\n /** What the model reads out when the client cannot ask. */\n prompt: string;\n },\n): Promise<{ value: T } | { prompt: string }> {\n if (!deps.elicit) return { prompt: q.prompt };\n try {\n const res = await deps.elicit({\n message: q.message,\n requestedSchema: { type: \"object\", properties: { [q.key]: q.property }, required: [q.key] },\n });\n const picked = res.action === \"accept\" ? res.content?.[q.key] : undefined;\n if (q.accept(picked)) return { value: picked };\n } catch {\n // Client advertised elicitation but couldn't serve it. Fall through to asking in chat.\n }\n return { prompt: q.prompt };\n}\n\n// ── The framework question ────────────────────────────────────────────────────\n// Mirrors src/lib/projects/framework-choice.ts in the backend. Deliberately duplicated\n// rather than imported: this package is published to npm and must not depend on backend\n// internals (same reasoning as SERVER_VERSION in server.ts). Keep the two in sync.\n\n/** The one sentence every page-building surface states. Shared so the surfaces cannot drift apart. */\nexport { SECTION_DOCTRINE } from \"@bettercms-ai/types\";\n\nexport const FRAMEWORK_CHOICES = [\"astro\", \"next\", \"react-ts\", \"other\"] as const;\n\nconst FRAMEWORK_LABELS: Record<(typeof FRAMEWORK_CHOICES)[number], string> = {\n astro: \"Astro — recommended default, static by default and fastest to publish\",\n next: \"Next.js\",\n \"react-ts\": \"React + TypeScript (Vite, prerendered)\",\n other: \"Other — headless project: content and API only, bring your own frontend\",\n};\n\n/** What the model must read out when it cannot ask the user through the client UI. */\nexport const FRAMEWORK_PROMPT = [\n \"Ask the user which technology this site should be built with, then call create_project again with their answer as `framework`:\",\n ...FRAMEWORK_CHOICES.map((c, i) => ` ${i + 1}. ${c} — ${FRAMEWORK_LABELS[c]}`),\n \"\",\n \"Do not choose on their behalf. Sites cannot be built as plain HTML/CSS — every project is backed by one of these starters, which is what keeps its content editable in the CMS.\",\n].join(\"\\n\");\n\n/**\n * Resolve `framework` by ASKING, never by defaulting.\n *\n * Prefers a real client-side prompt (elicitation) so the human picks from a list instead of\n * the model inventing an answer. When the client can't elicit — or the person dismisses the\n * prompt — we return the question as text for the model to put in chat. Either way the one\n * outcome that never happens is a silent default, which is the whole point: a guessed\n * framework means a forked starter and seeded content pointing at the wrong stack, and\n * nobody notices until the site is half-built.\n */\nfunction askFramework(deps: ToolDeps) {\n return askHuman<string>(deps, {\n key: \"framework\",\n message: \"Which technology should this site be built with?\",\n property: {\n type: \"string\",\n title: \"Technology\",\n description: \"The frontend stack this project's starter is based on.\",\n enum: [...FRAMEWORK_CHOICES],\n enumNames: FRAMEWORK_CHOICES.map((c) => FRAMEWORK_LABELS[c]),\n },\n accept: (v): v is string =>\n typeof v === \"string\" && (FRAMEWORK_CHOICES as readonly string[]).includes(v),\n prompt: FRAMEWORK_PROMPT,\n });\n}\n\n// ── The authoring-architecture question ───────────────────────────────────────\n// Mirrors src/lib/projects/authoring-choice.ts in the backend, duplicated for the same\n// reason as the framework question above: this package ships to npm and must not import\n// backend internals. Keep the two in sync.\n//\n// The backend is where the ENFORCEMENT lives — deploy/promote answer 409\n// AUTHORING_DECISION_REQUIRED until this is set — and its refusal quotes the project's real\n// page counts, which this surface has no way to know at ask time. So the prompt here is the\n// generic question; the grounded one arrives in the 409.\n\nexport const AUTHORING_CHOICES = [\"components\", \"fields\"] as const;\n\nconst AUTHORING_LABELS: Record<(typeof AUTHORING_CHOICES)[number], string> = {\n components:\n \"Components (recommended) — reusable section components placed as blocks; editors add, reorder and swap sections without touching a schema. Recommend it for every marketing, landing, agency or product site\",\n fields:\n \"Fields — a typed field schema per page. Only for a blog, catalogue or directory where many rows share one shape; editors can change a page's copy but cannot add, reorder or swap its sections\",\n};\n\n/** What the model must read out when it cannot ask the user through the client UI. */\nexport const AUTHORING_PROMPT = [\n \"Ask the user which authoring architecture this site should use, then call set_authoring_preference again with their answer as `preference`:\",\n ...AUTHORING_CHOICES.map((c, i) => ` ${i + 1}. ${c} — ${AUTHORING_LABELS[c]}`),\n \"\",\n \"On a site whose pages were DERIVED at import, answering 'components' redoes nothing: after set_authoring_preference, get_componentize_plan proposes one component per section (it reads the PUBLISHED pages — no deploy needed to reach it), you confirm it with the user, then componentize_sections places them with `props.bind` (dry run first — they land as drafts and the page keeps its fields, values and bindings, so click-to-edit and the coverage meter are unchanged), then publish_component each one, publish the pages, run `npx @bettercms-ai/convert --componentize` in the repo, and deploy. For a section group the plan lists as NO_GROUP_ROOT or NOT_A_SECTION there is nothing to componentize, so author that section with create_component and set_page_content.\",\n \"\",\n \"Recommend components unless the user says the site is schema-first.\",\n \"Do not choose on their behalf. This is asked once per project.\",\n].join(\"\\n\");\n\n/** Resolve `preference` by ASKING, never by defaulting. Same shape as askFramework. */\nfunction askAuthoring(deps: ToolDeps) {\n return askHuman<string>(deps, {\n key: \"preference\",\n message:\n \"Which authoring architecture should this site use? Components is recommended for a marketing site.\",\n property: {\n type: \"string\",\n title: \"Authoring architecture\",\n description:\n \"How this site's pages are composed. Components is recommended unless this is a schema-first site (a blog, catalogue or directory). Asked once per project.\",\n enum: [...AUTHORING_CHOICES],\n enumNames: AUTHORING_CHOICES.map((c) => AUTHORING_LABELS[c]),\n },\n accept: (v): v is string =>\n typeof v === \"string\" && (AUTHORING_CHOICES as readonly string[]).includes(v),\n prompt: AUTHORING_PROMPT,\n });\n}\n\n// ── The media-delivery question ───────────────────────────────────────────────\n// Unlike the two above, this one HAS a safe default (the column is `NOT NULL DEFAULT true`)\n// and gates nothing. It is still asked rather than assumed, because it decides which host\n// goes into the customer's published content — but a project that is never asked simply keeps\n// the CDN, which is what every project does today.\n\n/** What the model must read out when it cannot ask the user through the client UI. */\nexport const USE_CDN_PROMPT = [\n \"Ask the user where this site's media should be served from, then call set_media_delivery again with their answer as `useCdn`:\",\n \" 1. true — the BetterCMS CDN (recommended, and the default). Media URLs are minted on the CDN host, or on the project's own CDN base if it stores media in its own bucket.\",\n \" 2. false — the API origin. Media URLs are minted on the API host instead. Same bytes, same service; only the hostname differs.\",\n \"\",\n \"This applies to URLs minted FROM NOW ON. Already-published content keeps the URLs it has, and they keep working.\",\n].join(\"\\n\");\n\n/** Resolve `useCdn` by ASKING. Same shape as askFramework/askAuthoring, with a boolean answer. */\nfunction askMediaDelivery(deps: ToolDeps) {\n return askHuman<boolean>(deps, {\n key: \"useCdn\",\n message: \"Serve this site's media from the BetterCMS CDN (recommended), or from the API origin?\",\n property: {\n type: \"boolean\",\n title: \"Use the CDN\",\n description:\n \"On (default): media URLs are minted on the CDN — or on this project's own CDN base if it uses its own bucket. Off: they are minted on the API origin instead. Same bytes either way; only the host changes, and only for URLs minted from now on.\",\n default: true,\n },\n accept: (v): v is boolean => typeof v === \"boolean\",\n prompt: USE_CDN_PROMPT,\n });\n}\n\n/** MCP tool result shape (text content + optional error flag). */\nexport interface ToolResult {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n}\n\nexport interface ToolDef {\n name: string;\n config: { title: string; description: string; inputSchema: z.ZodRawShape };\n handler: (args: Record<string, unknown>) => Promise<ToolResult>;\n}\n\n// ── Shared schema pieces ──────────────────────────────────────────────────────\n\nconst fieldType = z.enum([\n \"text\",\n \"richtext\",\n \"image\",\n \"boolean\",\n \"number\",\n \"select\",\n \"reference\",\n \"multi-reference\",\n \"array\",\n \"date\",\n \"datetime\",\n \"group\", // Non-Repeatable Zone: one nested object of fields\n \"repeater\", // Repeatable Zone: an array of nested field-objects\n // A slot holding one component instance. This enum is a SECOND, narrower copy of the\n // field-type union, and `toField`/`OutField` below strip anything not modelled here —\n // which is why showIf/helpText/searchable/placement are all unreachable from MCP today.\n // Adding the type here without also carrying its `config` through `toField` would let an\n // agent create the field and silently lose its component allowlist.\n \"component-ref\",\n // Migration 0188. Both are LEAF types, so `toField`'s pass-through branch carries their\n // `config` verbatim — which is what the warning above demands before adding a type here.\n // `modular` needs config.blockSlugs; `location` takes no config.\n \"modular\",\n \"location\",\n // One button as one value: { label, href, variant?, size?, arrow?, icon?, newTab? }. A leaf.\n \"button\",\n // All LEAF types, so the pass-through branch above covers them. `document` is THE article\n // body — the rich document canvas, pages or collections, at most one per schema, top level\n // only. It was the conspicuous omission: the dashboard shipped an editor for it while no\n // agent could create the field. `sections` is a page-section zone composed in the Visual\n // Editor, so it has no inline control.\n \"document\",\n \"longtext\",\n \"slug\",\n \"email\",\n \"phone\",\n \"link\",\n \"color\",\n \"json\",\n \"file\",\n \"sections\",\n \"multiselect\",\n \"icon\",\n // V2: ONE nested object of `fields`, kept as `object` (not normalized to zones). `toField` recurses into it.\n \"object\",\n // V2 leaves: a taxonomy string[], a rating number, a code value. The pass-through branch carries their config.\n \"tags\",\n \"rating\",\n \"code\",\n \"video\",\n \"table\",\n \"slot\",\n]);\n\n/** The backend's own 400 text (openModeSchema), so stdio's client-side refusal names the same code. */\nconst OPEN_MODE_INVALID = \"openMode_invalid: openMode must be one of 'inline', 'drill', 'popover', 'dialog'\";\n\nconst slug = z\n .string()\n .regex(/^[a-z0-9-]+$/, \"lowercase letters, numbers, and hyphens only\");\n\nconst fieldKey = z\n .string()\n .regex(/^[a-zA-Z0-9_-]+$/, \"letters, numbers, underscores, and hyphens only\");\n\n// Recursive field schema. The MCP SDK serialises this Zod shape to the JSON\n// Schema the LLM sees — on SDK >= 1.29 (the floor pinned in package.json) the\n// `z.lazy()` below emits a proper `$ref`/`$defs` recursion so nested\n// group/repeater fields are VISIBLE. A stale older SDK collapsed it to an\n// opaque {} (the historic \"nested fields not created\" bug). The same recursive\n// shape is hand-written as JSON Schema in the remote proxy — keep the two in\n// sync: see bettercms-backend/src/routes/mcp/index.ts (FIELD_DEF).\n/** A field definition. Recursive: `group`/`repeater` nest more fields. */\nexport type FieldInput = {\n key: string;\n label: string;\n type: z.infer<typeof fieldType>;\n required?: boolean;\n /** Opt OUT of the rich-text default for a non-prose string (href, slug, id). */\n richText?: boolean;\n /** A plain string, or `{label, value}` when the stored value differs from the shown label. */\n options?: Array<string | { label: string; value: string; icon?: string; description?: string }>;\n config?: Record<string, unknown>;\n fields?: FieldInput[];\n /** Id of one of the model's `fieldsets` — the editor card this field sits in. Editor-only. */\n fieldsetId?: string;\n /** Where the control sits in the entry editor. Editor-only. @see backend baseField.placement */\n placement?: \"cover\" | \"title\" | \"excerpt\" | \"body\" | \"inline\" | \"panel\";\n /** The value a new entry starts with. */\n defaultValue?: unknown;\n /** Absent ≡ true. `false` keeps the field out of site search. */\n searchable?: boolean;\n /** BE-6: no two entries (or repeater rows) may hold the same value. Scalar types only. */\n unique?: boolean;\n /** \"developer\": only schema authority may write the value or change the lock. `true`: an editor marker. */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2: a translation owns this value; unmarked values are its source's once any field is marked. */\n localized?: boolean;\n /** Shown under the field in the editor. Persisted end-to-end since FLO-119's sibling pass. */\n helpText?: string;\n /** Admin-only conditional visibility. No delivery or storage effect. */\n showIf?: {\n match: \"all\" | \"any\";\n rules: Array<{ field: string; op: \"eq\" | \"neq\" | \"in\" | \"notIn\" | \"gt\" | \"lt\" | \"isSet\" | \"notEmpty\" | \"empty\"; value?: string | string[] }>;\n };\n /** Authoring chrome — how the field presents in the editor. @see backend baseField.ui */\n ui?: FieldUi;\n /** V2 editor-only keys. @see backend baseField.helpMore */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** object / array / group / repeater: how the value (or each row) opens. */\n openMode?: \"inline\" | \"drill\" | \"popover\" | \"dialog\";\n};\n\n/** Shared by FIELDS and by component PROPS. The types package's shape, so the two cannot drift. */\nexport type FieldUi = ContentModelFieldUi;\n\n// A refine, not an enum: ~470 names inlined into every schema that carries `ui` would be paid on\n// every tools/list. The layoutIcon precedent; the server's z.enum is the guard.\nconst dockIconArg = z\n .string()\n .min(1)\n .max(40)\n .refine((v) => DOCK_ICON_SET.has(v), `not a dock icon, see ${DOCK_ICONS_URI}`) as unknown as z.ZodType<DockIconName, string>;\n\nconst uiObject = z.strictObject({\n collapsed: z\n .boolean()\n .optional()\n .describe(\"start this panel collapsed. Use it for long optional sections.\"),\n preview: z\n .strictObject({\n title: z.string().min(1).optional().describe(\"CHILD KEY whose value titles a collapsed row\"),\n subtitle: z.string().min(1).optional().describe(\"CHILD KEY whose value is the row's second line (e.g. 'level' → 'Heading · h2')\"),\n media: z.string().min(1).optional().describe(\"CHILD KEY whose value is the row's thumbnail (image/file/url all work)\"),\n fallback: z.string().min(1).max(60).optional().describe(\"a literal row label while the title child is empty ('Untitled question'), not a key\"),\n icon: dockIconArg.optional().describe(\"the row's icon while it has no media, a dock icon name\"),\n })\n .optional()\n .describe(\n \"how ONE ITEM summarises itself when collapsed. Every slot names a CHILD KEY of THIS field/prop (a dotted path reads into it: 'author.name'). Without it a repeater of testimonials reads 'Item 1, Item 2, Item 3'; with {title:'author', media:'avatar'} it reads the names with their faces.\",\n ),\n layout: z\n .enum([\"list\", \"grid\", \"table\", \"rows\", \"chips\", \"gallery\"])\n .optional()\n .describe(\n \"how the ITEMS are arranged. Omit (≡ 'list') for rows of text; 'grid' for items whose thumbnail is the thing you scan — a gallery, a logo wall, a team; 'table' for up to 3 scalar columns. Same placement rule as `preview`. V2 'rows' | 'chips' | 'gallery' are also valid on a primitive array.\",\n ),\n reorderable: z\n .boolean()\n .optional()\n .describe(\n \"omit (≡ true) unless the order is PART OF THE MEANING. `false` LOCKS the list — a 'three steps' band that must stay three steps in that order, a nav whose order is semantic, a timeline. Valid only where there is a list to lock.\",\n ),\n control: z\n .enum([\"segmented\", \"slider\", \"rating\", \"dropdown\", \"radio\", \"cards\", \"grid\", \"switch\", \"checkbox\"])\n .optional()\n .describe(\n \"editor control for a LEAF. Omit for the default. 'segmented' on a select with a few short options (alignment, theme, size); 'slider' on a number that has config.min < config.max (opacity, columns); 'rating' on a number with config.min, max and step; 'dropdown'/'radio'/'grid'/'cards' on a select ('cards' also a multiselect); 'switch'/'checkbox' on a boolean ('checkbox' also a multiselect). Anything else is refused with the rule named.\",\n ),\n icon: dockIconArg.optional().describe(`the branch row's icon, a name from ${DOCK_ICONS_URI}. Nesting fields only.`),\n itemLabel: z.string().min(1).max(24).optional().describe(\"what ONE item is called ('Slide'): the add button, crumbs and empty state. Nesting fields and lists. V2 itemNoun goes here.\"),\n // V2 chrome keys (the server's fieldUiSchema): editor-only, each refused with a named code where it means nothing.\n itemName: z.string().max(64).optional().describe(\"a list's item type name (an identifier). Lists only.\"),\n itemTitle: z.string().min(1).max(60).optional().describe(\"a list's item type title. Lists only.\"),\n rows: z.number().int().min(1).max(40).optional().describe(\"the lines a text box opens with. text / longtext only.\"),\n placeholder: z.string().min(1).max(120).optional().describe(\"ghost text, a field of any type. A prop uses its own `placeholder`.\"),\n synced: z.strictObject({ from: z.string().min(1).max(64) }).optional().describe(\"the value comes from this global; edits apply everywhere.\"),\n valueShape: z.enum([\"string\", \"object\"]).optional().describe(\"a link / image / button writes a plain string or the object.\"),\n access: z\n .strictObject({ view: z.literal(\"schema.view\").optional(), edit: z.literal(\"schema.manage\").optional() })\n .optional()\n .describe(\"who sees (view: developer-only) and who changes (edit) it, gated in the editor. The enforced lock is readOnly:'developer'.\"),\n hidden: z.boolean().optional().describe(\"true: never shown in the form (a system value). A conditional hide is showIf.\"),\n blocks: z\n .record(z.string(), z.strictObject({ icon: dockIconArg.optional(), preview: z.record(z.string(), z.string()).optional() }))\n .optional()\n .describe(\"modular only: per block slug, {icon?, preview?} for its rows.\"),\n input: z\n .object({\n name: z.string().regex(/^[a-z][a-z0-9-]{0,47}$/),\n writes: z.array(z.string().min(1).max(64)).max(16).optional(),\n })\n .optional()\n .describe(\n \"a custom dock input by NAME (the project's bettercms/inputs/<name>.tsx), a last resort after `control`, `preview` and groups. `writes`: sibling field keys it may also write, nothing else. Setting or changing it needs `confirmed: true`, sent only after the user approved it.\",\n ),\n});\n\n/** A prop's `ui`: the field vocabulary plus an inline `group` and `tab` (props have no fieldsets). A FIELD's `ui.group` stays a refusal. */\nconst propUiObject = uiObject.extend({\n group: z\n .strictObject({\n id: z.string().min(1).max(40),\n label: z.string().min(1).max(32).optional(),\n kind: z.enum([\"group\", \"row\"]).optional(),\n icon: uiObject.shape.icon,\n collapsed: z.boolean().optional(),\n description: z.string().min(1).max(200).optional(),\n columns: z.union([z.literal(1), z.literal(2)]).optional(),\n collapsible: z.boolean().optional(),\n layout: z.enum([\"stack\", \"breakpoints\"]).optional(),\n order: z.number().int().min(0).max(99).optional(),\n })\n .optional()\n .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}.\"),\n tab: z\n .strictObject({\n id: z.string().min(1).max(40),\n label: z.string().min(1).max(40).optional(),\n icon: uiObject.shape.icon,\n order: z.number().int().min(0).max(99).optional(),\n })\n .optional()\n .describe(\"TOP-LEVEL props only: the dock tab this prop sits in (a V2 kit schema `groups` entry: Content, Design, …). The FIRST prop in a tab defines {id, label, icon?, order?}; later ones send only {id}. ≤8 tabs, labels ≤40 chars and unique; a group's members share one tab.\"),\n});\n\n// One select choice, shared by model fields and component props; the server judges icon/description.\nconst choiceOption = z.union([z.string(), z.object({ label: z.string(), value: z.string(), icon: z.string().optional(), description: z.string().optional() })]);\n\nconst fieldShape = {\n key: fieldKey.describe(\n \"machine field key. 🔴 UNIQUE ACROSS THE WHOLE MODEL — API IDs share ONE FLAT NAMESPACE, so a field nested inside a group must NOT reuse a key used by another field or group. Every section's heading cannot be 'title'. Prefix with the section: 'hero_title', 'pricing_title', 'faq_title'. Reusing a key is refused, and if it slips through it leaves permanent errors in the editor and breaks conditional-visibility rules, which reference fields by bare key. Keys derived from an imported site may contain hyphens ('hero-h1-welcome'): address them exactly as returned.\",\n ),\n label: z.string().min(1).describe(\"human label shown in the editor\"),\n type: fieldType.describe(`field type. ${BUTTON_FIELD_NOTE} ${LINK_VALUE_NOTE}`),\n required: z.boolean().optional().describe(\n \"an entry cannot be saved without a value — set it only where the site genuinely cannot render without one\",\n ),\n richText: z\n .boolean()\n .optional()\n .describe(\n \"prose formatting. DEFAULTS TO TRUE for 'text': the field is created as rich text so editors can bold, link and format it on the canvas, and the API returns rich text (render with rich() from @bettercms-ai/sdk; plain() for titles and meta). Pass false for a value that is NOT prose and must stay a bare string — a URL/href, a slug, an id, an email, a phone number, a CSS class, an icon name. A link stored as rich text will not work as an href.\",\n ),\n options: z\n .array(choiceOption)\n .optional()\n .describe(\n \"choices when type is 'select'. A plain string, or {label, value, icon?, description?} when the stored value differs from what the editor shows (e.g. {label:'Sold out', value:'soldOut'}); icon a dock name, description one line ≤140.\",\n ),\n config: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"per-type config: reference {contentModelId}, multi-reference {contentModelId,min,max}, repeater {minItems, maxItems} (the list's item limits; the editor shows 'max N' and stops Add there), array {itemType: text|number|date|image|link|richtext}, date {includeTime, timezone}, modular|slot {blockSlugs: ['quote','gallery'], minItems?, maxItems?} (slot: playbook §5) — blockSlugs is REQUIRED, non-empty, and each slug must name an existing kind:'block' model; richtext {inline:true, hostTag:'h2', accept:['h2','p','b','i','u','link'], features:['bold','italic','underline','link','headings'], allowMultipleParagraphs:false} — for a field bound to ONE element on the page: `hostTag` is that element's tag and `accept` must name it, so the editor's block-style control opens already showing 'Heading 2' instead of 'Paragraph'. Name exactly ONE heading level: publish refuses an <h3> value bound to an <h2> rather than nesting one heading inside the other. Keep 'p' in `accept` or the sanitiser strips a block demoted to Paragraph; limits: text/longtext {minLength,maxLength,pattern,patternMessage}, richtext {minLength,maxLength}, number {validation:{min,max}}, array {minItems,maxItems}, tags {min,max}, rating {min,max,step}\",\n ),\n fields: z\n .array(z.lazy(() => fieldObject))\n .optional()\n .describe(\n \"NESTED child fields — REQUIRED for type 'group' (one nested object, a Non-Repeatable Zone like blog_hero → heading, description, hero_image) and type 'repeater' (a repeatable array of such objects, a Repeatable Zone / section-list like testimonials → quote, author). A section with repeating items is a 'repeater'; a fixed grouped block is a 'group'. Recurse to any depth — do NOT flatten zones into separate top-level fields.\",\n ),\n // ── Authoring chrome + editor behaviour ────────────────────────────────────\n // These three already persist end-to-end and already have a panel in the dashboard's schema\n // builder. They were unreachable from MCP for ONE reason: the OutField/toField whitelist\n // below did not model them, so they were stripped after the model had gone to the trouble of\n // sending them. Declaring them here is what makes the existing panel agent-writable.\n helpText: z\n .string()\n .max(500)\n .optional()\n .describe(PARAM_TEXT.helpText),\n showIf: z\n .object({\n match: z.enum([\"all\", \"any\"]),\n rules: z.array(\n z.object({\n field: z.string().describe(\"the BARE KEY of another field on this same model\"),\n op: z.enum([\"eq\", \"neq\", \"in\", \"notIn\", \"gt\", \"lt\", \"isSet\", \"notEmpty\", \"empty\"]),\n 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\"),\n }),\n ),\n })\n .optional()\n .describe(\n \"conditional visibility — 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.\",\n ),\n ui: uiObject\n .optional()\n .describe(\n \"AUTHORING CHROME — 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 — use `after`. Section 14 of bettercms://playbook/schema has each key and where it is legal.\",\n ),\n // ── G5: the four keys the backend field schema accepts that this whitelist stripped. ──\n fieldsetId: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"id of one of this model's `fieldsets` (create_content_model / update_content_model). The field is shown inside that card in the editor. Editor-only: never changes what is stored or delivered.\",\n ),\n placement: z\n .enum([\"cover\", \"title\", \"excerpt\", \"body\", \"inline\", \"panel\"])\n .optional()\n .describe(\n \"where the control sits in the entry editor: 'title' the entry's heading, 'cover' its lead image, 'excerpt' the summary, 'body' the document body, 'inline' or 'panel'. Omit to let the editor decide. Editor-only.\",\n ),\n defaultValue: z.unknown().optional().describe(\"the value a new entry starts with\"),\n searchable: z\n .boolean()\n .optional()\n .describe(\"omit (≡ true) to index this field for site search; false excludes it\"),\n unique: z\n .boolean()\n .optional()\n .describe(\n \"true: no two entries of this model may hold the same value (compared trimmed and case-insensitively). On a repeater child such as a variant SKU it also covers every row of every entry. Only on text, longtext, slug, email, phone, link, number, select, reference and date; on a list it means no item repeats. A clash is refused with 409 `unique_conflict`.\",\n ),\n readOnly: z.union([z.literal(true), z.literal(\"developer\")]).optional().describe(PARAM_TEXT.readOnly),\n lockReason: z.string().max(200).optional().describe(PARAM_TEXT.lockReason),\n // V2 schema language. Editor-only; the playbook's §14 table maps each to what the editor draws.\n helpMore: z.string().max(2000).optional().describe(PARAM_TEXT.helpMore),\n advanced: z.boolean().optional().describe(PARAM_TEXT.advanced),\n recommendedMax: z.number().int().positive().optional().describe(PARAM_TEXT.recommendedMax),\n openMode: z.enum([\"inline\", \"drill\", \"popover\", \"dialog\"], { error: OPEN_MODE_INVALID }).optional().describe(PARAM_TEXT.openMode),\n localized: z.boolean().optional(),\n};\nconst fieldObject: z.ZodType<FieldInput> = z.object(fieldShape);\n\n/**\n * A collection's entry URL (CPO-046). Loose here on purpose: the API's `urlPatternSchema` is the\n * one validator, and its field-level message is what the agent should read back.\n */\nconst urlPatternArg = z\n .string()\n .nullable()\n .optional()\n .describe(\n \"the public URL of one entry, e.g. '/blog/:slug'. Must start with '/' and contain ':slug' exactly once ('{slug}' is refused). Drives RSS item links and the automatic 301 when an entry's slug changes. null clears it.\",\n );\n\n/** A content model's fieldset list. Same shape as the backend `fieldsetsSchema` and the dashboard's `Fieldset`. */\nconst fieldsetsArg = z\n .array(\n z.strictObject({\n id: z.string().min(1),\n name: z.string().min(1).max(60),\n description: z.string().max(500).optional(),\n kind: z.enum([\"group\", \"row\", \"tab\"]).optional(),\n tab: z.string().min(1).optional(),\n icon: uiObject.shape.icon,\n collapsed: z.boolean().optional(),\n collapsible: z.boolean().optional(),\n columns: z.union([z.literal(1), z.literal(2)]).optional(),\n layout: z.enum([\"stack\", \"breakpoints\"]).optional(),\n // Server-owned provenance, as get_content_model returns it: an echo parses and is dropped\n // before the write (dropProvenance), never refused.\n uiOrigin: z.unknown().optional(),\n uiBefore: z.unknown().optional(),\n }),\n )\n .max(30)\n .optional()\n .describe(\n \"the model's editor cards: [{id, name, description?, kind?, tab?, icon?, collapsed?, collapsible?, columns?:1|2, layout?:'breakpoints'}], at most 30, ids unique, order = array index. kind 'group' is a disclosure, 'row' puts up to 3 short scalars on one line, 'tab' is a tab (at most 3, top-level fields only; untabbed fields stay pinned above the tabs; a group's `tab` names its tab). A field joins one with `fieldsetId`. Editor-only: never changes what is stored or delivered.\",\n );\n\n/** Drop the server-owned provenance an agent echoed from a read. */\nconst dropProvenance = (sets: Array<Record<string, unknown>> | null | undefined) =>\n sets?.map(({ uiOrigin: _origin, uiBefore: _before, ...set }) => set) ?? sets;\n\n/** The richText default, stated in the tool descriptions too (G5), not only on the arg. */\nconst RICH_TEXT_NOTE =\n \"🔴 A field of type 'text' is created as RICH TEXT unless you send `richText: false` on it. Send `richText: false` for every value that is not prose: a name used as a title, a URL, slug, id, SKU, email, phone, CSS class or icon name.\";\n\n/**\n * update_seo's keys: a hand copy of the zod the route validates with\n * (src/lib/validation/schemas/projects.ts), which this published package cannot import.\n * mcp-tool-routes.test.ts pins every key, at every depth, against those schemas.\n */\nconst SCHEMA_ORG_TYPES = [\"WebPage\", \"AboutPage\", \"ContactPage\", \"CollectionPage\", \"Blog\", \"BlogPosting\", \"Article\", \"Product\", \"FAQPage\", \"Event\", \"Organization\", \"LocalBusiness\", \"JobPosting\", \"Course\", \"Recipe\", \"HowTo\", \"Service\", \"Person\", \"VideoObject\"] as const;\nconst changefreq = z.enum([\"auto\", \"always\", \"hourly\", \"daily\", \"weekly\", \"monthly\", \"yearly\", \"never\"]);\nconst jsonObject = z.record(z.string(), z.unknown());\nexport const seoPatchShape = {\n seoDefaults: z.object({\n metaTitle: z.string().max(255).optional(),\n metaDescription: z.string().max(500).optional(),\n ogImage: z.string().url().max(2000).nullable().optional(),\n twitterHandle: z.string().max(255).nullable().optional(),\n og: z.object({ image: z.string().max(2048).optional(), type: z.string().max(50).optional(), siteName: z.string().max(255).optional(), locale: z.string().max(20).optional() }).optional(),\n twitter: z.object({ card: z.string().max(50).optional() }).optional(),\n feeds: z.array(z.object({ type: z.string().max(100), href: z.string().max(2048), title: z.string().max(255).optional() })).max(10).optional(),\n collectionSchemaTypes: z.record(z.string().min(1).max(64), z.enum(SCHEMA_ORG_TYPES)).optional(),\n }).optional().describe(SEO_KEY_TEXT.seoDefaults),\n siteSchema: z.union([jsonObject, z.array(jsonObject)]).optional().describe(SEO_KEY_TEXT.siteSchema),\n robotsConfig: z.object({ mode: z.enum([\"auto\", \"custom\"]), custom: z.string().max(10000).optional(), disallow: z.array(z.enum([\"GPTBot\", \"OAI-SearchBot\", \"ChatGPT-User\", \"ClaudeBot\", \"Claude-Web\", \"anthropic-ai\", \"PerplexityBot\", \"Google-Extended\", \"CCBot\", \"Bytespider\", \"Applebot-Extended\", \"Amazonbot\", \"Meta-ExternalAgent\"])).max(32).optional() }).optional().describe(SEO_KEY_TEXT.robotsConfig),\n sitemapConfig: z.object({\n enabled: z.boolean(),\n mode: z.enum([\"auto\", \"custom\"]).optional(),\n custom: z.string().max(500000).optional(),\n defaultChangefreq: changefreq.optional(),\n defaultPriority: z.number().min(0).max(1).optional(),\n extraUrls: z.array(z.object({ loc: z.string().min(1).max(2000), changefreq: changefreq.optional(), priority: z.number().min(0).max(1).optional() })).max(1000).optional(),\n }).optional().describe(SEO_KEY_TEXT.sitemapConfig),\n rssConfig: z.object({ enabled: z.boolean() }).optional().describe(SEO_KEY_TEXT.rssConfig),\n indexnowConfig: z.object({ enabled: z.boolean(), excludePatterns: z.array(z.string().max(2000)).max(200).optional() }).optional().describe(SEO_KEY_TEXT.indexnowConfig),\n searchConfig: z.object({ enabled: z.boolean(), placeholder: z.string().max(120), aiEnabled: z.boolean().optional() }).optional().describe(SEO_KEY_TEXT.searchConfig),\n};\n\n/** Pages are not collections — the rule every import lane follows (lib/content/collection-evidence.ts). */\nconst PAGES_NOT_COLLECTIONS_NOTE =\n \"A collection is only for items one template route repeats (/blog/:slug: set urlPattern). A single page's copy (home, about, contact, pricing, legal) is page fields in sections (add_field with pageId / set_page_content), never a one-entry collection.\";\n\n/**\n * Output field shape persisted by the API. Canonical: nesting lives on `array` via\n * `config.zones`. The LLM may still speak `group`/`repeater` (kept in the input schema\n * because it's intuitive) — toField() maps those into the canonical array.zones shape\n * here, so the backend, dashboard, codegen, and delivery all see one model.\n */\ntype OutField = {\n key: string;\n label: string;\n type: Exclude<FieldInput[\"type\"], \"group\" | \"repeater\">;\n required?: boolean;\n options?: FieldInput[\"options\"];\n config?: Record<string, unknown>;\n fieldsetId?: string;\n placement?: FieldInput[\"placement\"];\n defaultValue?: unknown;\n searchable?: boolean;\n unique?: boolean;\n readOnly?: FieldInput[\"readOnly\"];\n lockReason?: string;\n localized?: boolean;\n // ⚠ THIS TYPE IS THE WHITELIST. `toField` builds its result from exactly these keys, so a\n // prop absent here is stripped AFTER the agent sent it and AFTER the input schema accepted\n // it — a 200 with the declaration gone. helpText/showIf/ui all persist end-to-end on the\n // backend and all three were unreachable purely because of this omission.\n helpText?: string;\n showIf?: FieldInput[\"showIf\"];\n ui?: FieldInput[\"ui\"];\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n openMode?: FieldInput[\"openMode\"];\n /** `object` only: its children, recursed like a zone's. */\n fields?: OutField[];\n};\n\n\n/**\n * API IDs share ONE FLAT NAMESPACE across a model — a field inside a group must not reuse a key\n * used by any other field or group. Checked here, before the write, because the failure it\n * prevents is silent: the schema saves, and the author is left with permanent red error rows in\n * the builder plus `showIf` rules that reference a bare key and therefore cannot resolve.\n *\n * This is the shape `create_page` produces by default — its own description tells the agent to\n * build a nested tree where every visual section becomes a group, and the natural key for each\n * section's heading is `title`. The marketing page came out with `title` and `subtitle` in three\n * groups. The rule was never written down anywhere the model could read it, so this is both a\n * guard and the place it gets taught.\n *\n * Depth is ONE LEVEL, matching the dashboard's own `walk` — checking deeper here would refuse\n * schemas the builder renders as clean.\n *\n * Reads BOTH dialects: `fields` (what an agent sends) and `config.zones` (what the API returns).\n */\nfunction flatFieldKeys(fields: unknown): string[] {\n const out: string[] = [];\n const childrenOf = (f: Record<string, unknown>): unknown[] => {\n const zones = (f.config as { zones?: { nonRepeatable?: unknown[]; repeatable?: { fields?: unknown[] } } } | undefined)?.zones;\n if (zones?.nonRepeatable) return zones.nonRepeatable;\n if (zones?.repeatable?.fields) return zones.repeatable.fields;\n return (f.fields as unknown[]) ?? [];\n };\n for (const raw of (Array.isArray(fields) ? fields : [])) {\n const f = raw as Record<string, unknown>;\n if (typeof f?.key === \"string\" && f.key.trim()) out.push(f.key.trim());\n for (const raw2 of childrenOf(f)) {\n const c = raw2 as Record<string, unknown>;\n if (typeof c?.key === \"string\" && c.key.trim()) out.push(c.key.trim());\n }\n }\n return out;\n}\n\n/** Keys used more than once, first-seen order. */\nfunction duplicateKeys(keys: string[]): string[] {\n const seen = new Map<string, number>();\n for (const k of keys) seen.set(k, (seen.get(k) ?? 0) + 1);\n return [...new Set(keys)].filter((k) => (seen.get(k) ?? 0) > 1);\n}\n\n/** The refusal an AGENT has to be able to act on — names the keys, the rule, the remediation. */\nfunction duplicateKeyFailure(dupes: string[]): string {\n return (\n `Duplicate API ID${dupes.length === 1 ? \"\" : \"s\"}: ${dupes.map((k) => `'${k}'`).join(\", \")}. ` +\n `API IDs share ONE flat namespace across the whole model — a field inside a group must not ` +\n `reuse a key used by another field or group. Prefix each key with its section and retry ` +\n `(e.g. 'hero_title' and 'pricing_title', never 'title' in both).`\n );\n}\n\nfunction toFields(fs: FieldInput[] | undefined): OutField[] {\n return (fs ?? []).map(toField);\n}\n\n/**\n * Prose fields are RICH TEXT unless the caller opts out.\n *\n * The default is inverted from what the type name suggests, deliberately: an agent asked for a\n * headline says `type: 'text'` because that is the word for it, and the author then finds a\n * heading they cannot bold or link on the canvas — the toolbar's marks render disabled with\n * \"enable rich text formatting to use this\", and the only route out is a schema edit.\n *\n * 🔴 The opt-out is NOT cosmetic. A richtext field's API value is an ENVELOPE, not a string, so\n * an href, slug, id, email or class name created as rich text is broken the moment a template\n * interpolates it — that is the shape that renders \"[object Object]\". `richText: false` is the\n * required answer for every non-prose string, and the input schema says so.\n */\nfunction proseType(f: FieldInput): FieldInput[\"type\"] {\n // `text` is the only prose leaf this enum carries — `longtext` is not in it, so there is\n // nothing else to widen to. Stated because \"why only text?\" is the obvious next question.\n if (f.type !== \"text\") return f.type;\n return f.richText === false ? \"text\" : \"richtext\";\n}\n\n/** `confirmed: true` (the user approved a custom input) → the header the server gate reads. @see INPUT_CONFIRMED_HEADER */\nconst confirmedHeaders = (confirmed: unknown): Record<string, string> => (confirmed === true ? { [INPUT_CONFIRMED_HEADER]: \"true\" } : {});\n/** `{ headers }` only when there is one, so a call without any sends none. */\nconst withHeaders = (headers: Record<string, string>) => (Object.keys(headers).length > 0 ? { headers } : {});\nconst DRY_RUN_SUMMARY = \"Dry run: nothing was written.\";\n/** A write's own route with `dryRun: true`: the API validates and answers what it would store. */\nconst dryRunOf = async (client: ManagementApi, method: string, path: string, body: object, headers: Record<string, string> = {}) =>\n ok(DRY_RUN_SUMMARY, await client.fetchJSON(client.url(path), { method, body: JSON.stringify({ ...body, dryRun: true }), ...withHeaders(headers) }));\n\nfunction toField(f: FieldInput): OutField {\n // 🔴 `base` is the ONLY thing every branch below shares. The group/repeater branches REBUILD\n // `config` from scratch — `{ zones: … }`, with the incoming config never spread — so anything\n // carried inside `config` is destroyed on exactly the nesting fields it would be for. That is\n // why `ui` is a SIBLING here and on the backend's baseField, and why it goes in `base`: `base`\n // is spread FIRST in all four returns, and nothing below reassigns these keys.\n const base = {\n key: f.key,\n label: f.label,\n ...(f.required !== undefined ? { required: f.required } : {}),\n ...(f.helpText !== undefined ? { helpText: f.helpText } : {}),\n ...(f.showIf !== undefined ? { showIf: f.showIf } : {}),\n ...(f.ui !== undefined ? { ui: f.ui } : {}),\n // G5: these four persist on the backend and were stripped here, like helpText once was.\n ...(f.fieldsetId !== undefined ? { fieldsetId: f.fieldsetId } : {}),\n ...(f.placement !== undefined ? { placement: f.placement } : {}),\n ...(f.defaultValue !== undefined ? { defaultValue: f.defaultValue } : {}),\n ...(f.searchable !== undefined ? { searchable: f.searchable } : {}),\n // BE-6: a leaf key like the four above, so it rides on `base` and survives every branch.\n ...(f.unique !== undefined ? { unique: f.unique } : {}),\n // The developer lock: stripped here, an agent writing a model back would unlock every field.\n ...(f.readOnly !== undefined ? { readOnly: f.readOnly } : {}),\n ...(f.lockReason !== undefined ? { lockReason: f.lockReason } : {}),\n ...(f.localized !== undefined ? { localized: f.localized } : {}),\n // V2 editor keys: on `base` so the group/repeater rebuild cannot drop them.\n ...(f.helpMore !== undefined ? { helpMore: f.helpMore } : {}),\n ...(f.advanced !== undefined ? { advanced: f.advanced } : {}),\n ...(f.recommendedMax !== undefined ? { recommendedMax: f.recommendedMax } : {}),\n ...(f.openMode !== undefined ? { openMode: f.openMode } : {}),\n };\n\n // V2 object → stays an object; only its children are mapped.\n if (f.type === \"object\") {\n return { ...base, type: \"object\", fields: toFields(f.fields) };\n }\n // group → array with a non-repeatable zone (a fixed block).\n if (f.type === \"group\") {\n return { ...base, type: \"array\", config: { zones: { nonRepeatable: toFields(f.fields) } } };\n }\n // repeater → array with a repeatable zone (a list of blocks).\n if (f.type === \"repeater\") {\n // Its item limits ride along: the editor's \"2 items · max 4\" reads them from the zone.\n const { minItems, maxItems } = (f.config ?? {}) as { minItems?: number; maxItems?: number };\n return { ...base, type: \"array\", config: { zones: { repeatable: { fields: toFields(f.fields), ...(minItems !== undefined ? { minItems } : {}), ...(maxItems !== undefined ? { maxItems } : {}) } } } };\n }\n // Already-canonical zoned array (the LLM emitted config.zones directly) → recurse.\n if (f.type === \"array\" && f.config && typeof f.config === \"object\" && \"zones\" in f.config) {\n const zones = (f.config as { zones?: { nonRepeatable?: FieldInput[]; repeatable?: { fields?: FieldInput[]; minItems?: number; maxItems?: number } } }).zones ?? {};\n return {\n ...base,\n type: \"array\",\n config: {\n zones: {\n ...(zones.nonRepeatable ? { nonRepeatable: toFields(zones.nonRepeatable) } : {}),\n ...(zones.repeatable\n ? {\n repeatable: {\n fields: toFields(zones.repeatable.fields),\n ...(zones.repeatable.minItems !== undefined ? { minItems: zones.repeatable.minItems } : {}),\n ...(zones.repeatable.maxItems !== undefined ? { maxItems: zones.repeatable.maxItems } : {}),\n },\n }\n : {}),\n },\n },\n };\n }\n\n // Leaf field or primitive array (config.itemType) — pass through, with the prose default\n // applied here so EVERY field-creating tool (create_page, create_content_model, add_field)\n // inherits it from one place rather than several that can drift.\n return {\n ...base,\n type: proseType(f) as OutField[\"type\"],\n ...(f.options ? { options: f.options } : {}),\n ...(f.config ? { config: f.config } : {}),\n };\n}\n\n// ── Result helpers ────────────────────────────────────────────────────────────\n\n/** get_project's brand kit. Mirrors the remote catalog's note word for word. */\nconst BRAND_KIT_NOTE =\n \"`brandKit` (colors, typography, radius and any typeScale/spacing/elevation/motion/graphics) is edited in the BetterCMS dashboard AND by set_brand_assets and set_brand_graphics; every write is a version a person can restore. ASSETS: a media asset OF THIS PROJECT by id; null clears one; a slot a person chose needs `replace: true`. GRAPHICS: `kind`, optional `angle`, 2-8 stops naming `colors.*` or `extras` keys — never a CSS string and never a hex. CONSUME, DO NOT COPY: a hosted page exposes `--brand-color-<key>`, `--brand-shadow-<key>` and `--brand-gradient-<key>`; style sections with their `style` tokens (`nav.backgroundGradient` and `footer.backgroundGradient` take a gradient key), never copied values. Never invent brand facts: read them from get_project.\";\n\n\n/** update_content_model's text and optimistic lock. Mirror the remote catalog's word for word. */\nconst UPDATE_MODEL_DESCRIPTION =\n \"Edit a content model: rename it, change description/slug/urlPattern, set its `fieldsets`, or reshape how its EXISTING fields look in the editor. Never adds or retypes a field (use add_field). It removes one only with `removeFields` plus `allowFieldRemoval: true`, which DISCARDS its data in every entry and has no dry run; a page's fields go through remove_page_fields. Send modelId, or pageId for the model a page's schema lives in. `fieldsets` REPLACES the list (null drops all); a field joins one with fieldFieldset or add_field's `fieldsetId`. The field* args address fields by dotted key path ('hero.title'). Read with get_content_model, then pass `ifMatch` = the version from that read. A taken slug is 409 `slug_taken`. Section 14 of bettercms://playbook/schema.\";\nconst FIELD_REMOVAL_NOTE =\n \"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.\";\nconst ALLOW_FIELD_REMOVAL_NOTE =\n \"true = the user accepts that removeFields discards those fields' data in every entry. There is no dry run on this route: confirm first.\";\nconst MODEL_IF_MATCH_NOTE =\n \"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.\";\nconst COMPONENT_IF_MATCH_NOTE =\n \"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).\";\nconst PROP_UI_ARG_NOTE = \"top-level prop key → 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\";\nconst OVERRIDE_NOTE = \"replace chrome a person set (otherwise 409 ui_human_owned names those paths). Send it only on the user's word.\";\nconst FIELD_UI_ARG_NOTE = \"path → ui patch, a field's `ui` vocabulary: each key merges, a null key clears it, null clears the whole ui\";\n/** What update_content_model forwards. `fields` is not one of them: the PATCH replaces `fields` wholesale. */\nconst MODEL_UPDATE_KEYS = [\n \"name\", \"slug\", \"description\", \"urlPattern\", \"fieldsets\",\n \"fieldUi\", \"fieldFieldset\", \"fieldOrder\", \"fieldLabel\", \"fieldHelpText\", \"override\",\n] as const;\n\n/** Native SEO on the two write tools. Mirrors the remote catalog's notes word for word. */\nconst ENTRY_META_NOTE =\n \"SEO is native: set this entry's metaTitle, metaDescription, noindex, canonical, og, twitter, schemaType or schema in `meta` (never as model fields). `meta` MERGES into what is stored: a key you leave out is kept, null or an empty string clears it.\";\n/** update_content_entry / list_content_entries arguments. Mirror the remote catalog's word for word. */\nconst ENTRY_MERGE_NOTE =\n \"Default true: keep the fields you leave out. The entry is read, `data` is laid over its stored data by top-level key (a group or repeater value replaces that whole key) and written at the version read. false = `data` REPLACES the whole object, deleting every field you leave out.\";\nconst ENTRY_IF_MATCH_NOTE =\n \"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.\";\nconst ENTRY_SCHEDULED_AT_NOTE =\n \"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.\";\nconst ENTRY_UNPUBLISH_AT_NOTE =\n \"ISO datetime at which the published entry returns to draft; null cancels. Omitting it never cancels it.\";\nconst ENTRY_LIST_DETAIL_NOTE =\n \"true = full rows with every field value and the published copy. Large: read one entry with get_content_entry instead.\";\nconst ENTRY_LIST_LIMIT_NOTE =\n \"entries per page, 1-200; 50 when omitted. Read `meta.totalPages` and ask for the next `page`.\";\nconst PAGE_HEAD_NOTE =\n \"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).\";\n\n\n/**\n * The structure fence, for the three tools where an agent starts organising\n * (get_content_structure, set_content_structure, create_folder); the other four carry the\n * one-line STRUCTURE_POINTER below.\n *\n * The rules this refuses on (system folders, type purity, pins, access, page-bound models and\n * their 400/403 codes) used to be a 2.6k-character note pasted on all seven structure tools —\n * 16k of one paragraph in a catalogue an agent reads whole before it can speak. They live in the\n * resource bettercms://playbook/structure (\"Refusals\"), which is never truncated. Byte-identical\n * in both catalogs: `mcp-text-parity` pins create_folder and move_to_folder equal across the two.\n */\nconst STRUCTURE_FENCE =\n \"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 — system folders, type purity, the Admin/Developer access check, root pins and page-bound models.\";\n\n/**\n * The four single-item structure writes (rename_folder, move_to_folder, set_icon, delete_folder)\n * point at the rules instead of restating them: the full fence rides on set_content_structure,\n * create_folder and get_content_structure, and the rules themselves live in the resource.\n */\nconst STRUCTURE_POINTER = \"Sidebar only, never a URL; rules: bettercms://playbook/structure.\";\n\n/** set_brand_assets / set_brand_graphics: the brand kit paragraph is stated once, on get_project. */\nconst BRAND_KIT_POINTER = \"The brand kit's rules (consume its tokens, never copy values or invent brand facts) are on get_project.\";\n\n/** A structure write: lead with the server's diff text, then the full payload. */\nfunction structureResult(d: unknown): ToolResult {\n const message = (d as { message?: unknown } | undefined)?.message;\n return ok(typeof message === \"string\" ? message : \"Updated the Content structure.\", d);\n}\n\n/**\n * The git lane's tool descriptions, repeated word for word by the hosted catalog (backend `src/routes/mcp/index.ts`). A tool that says\n * two different things on the two surfaces is a prompt that works from one client and misleads\n * from the other, and the two catalogs cannot share a module — a value import across the package\n * boundary resolves to a gitignored dist in the deployed container. So these are two copies,\n * pinned byte-equal by `src/__tests__/mcp/mcp-text-parity.test.ts`.\n */\nconst GIT_TEXT = {\n list_github_repos:\n \"Every GitHub repository this workspace's connected GitHub App installations can reach, grouped by account. Use it to find the repository to import: each ACCOUNT carries the `installationId` that import_github_repo and fork_github_repo take, and each repository under it carries `owner`, `repo` and `defaultBranch`. An empty `accounts` list means nobody has connected GitHub to this workspace yet \\u2014 tell the user to connect it from the dashboard (Project \\u2192 Hosting \\u2192 Connect GitHub) and call this again.\",\n import_github_repo:\n \"Connect an existing GitHub repository to the connected project (the dashboard's Import from GitHub) \\u2014 do it BEFORE writing any code for a user who already has a repo. It wires the project API key and variables into the repository, records the connection, assigns the site handle, imports the repo's bcms-content.json as content models when it has one, and queues the first build. Pass `installationId`, `owner` and `repo` from list_github_repos; `branch` defaults to the repository's own default branch and becomes the branch every deploy builds from. It only works on a repository this workspace's installations can already reach \\u2014 for anyone else's (a public starter, a template, another account's site) use fork_github_repo. Read `warning` / `contentWarning` / `envWarning` back to the user verbatim when they come back (`envWarning` names the environment variables the repo documents in .env.example and the project lacks — the site renders empty or crashes until they are set) \\u2014 the repository connected but cannot build, or will leave the Pages tab empty. Re-importing replaces the project's existing connection.\",\n fork_github_repo:\n \"Fork ANY GitHub repository into the user's own account and import it in one step \\u2014 how a user starts from a repository that is not theirs (a public starter, a template, another account's site). BetterCMS cannot wire a repository it has no installation on, so the copy has to live on their account first; this makes that copy, keeps the upstream link, and then connects it exactly as import_github_repo does. `installationId` names the DESTINATION account (from list_github_repos); `owner` and `repo` name the SOURCE, anywhere on GitHub. `name` renames the fork; `connect: false` forks without connecting. Forking is asynchronous: a 202 means the fork exists but GitHub is still copying it, and the answer tells you to call import_github_repo with the fork's owner and repo a moment later \\u2014 never fork a second time.\",\n list_github_branches:\n \"The connected repository's branches, plus `buildBranch` \\u2014 the one the provisioned Action builds from. A commit on any other branch never reaches the live site, so check this before you push.\",\n list_github_commits:\n \"The connected repository's commit history, newest first: sha, message, author, date and url. Defaults to the build branch; pass `branch` for another, `path` to narrow it to one file or directory, and `limit` (1-100, default 20). Read the head sha here before a push you want to be safe, and hand it back as push_to_github's `expectedHeadSha`.\",\n push_to_github:\n \"Commit files to the connected repository \\u2014 a real git commit written server-side by the GitHub App: no clone, remote or token of your own. Send `files` ([{path, content, encoding}]) and/or `deletePaths`, plus a `message`; both go into ONE commit, so a rename is atomic. It targets the BUILD branch by default, where the push starts the rebuild that goes live \\u2014 poll get_deploy_status after it, and read the response's `note`, which says whether this push deploys. Pass `branch` to push somewhere else (a branch that does not exist yet is created from the build branch, or from `baseBranch`) and then open a pull request with create_github_pull_request. Pass `expectedHeadSha` from list_github_commits \\u2014 a full sha or a prefix of one \\u2014 to be refused with a 409 rather than silently overwrite a branch someone else moved while you worked. Limits, enforced BEFORE anything is written: 200 paths and 10 MB per commit, and `.git`, `.github/workflows`, `.env` and `.npmrc` are never writable \\u2014 a refused patch writes nothing at all and names every offending path.\",\n create_github_pull_request:\n \"Open a pull request on the connected repository. `head` is the branch you pushed; `base` defaults to the build branch, so merging it is what ships the change. Use this instead of pushing straight to the build branch whenever a human should review first, or when that branch is protected. Returns the number and the url to hand the user.\",\n list_github_pull_requests:\n \"Pull requests on the connected repository: number, title, state, whether it merged, draft, head, base and url. `state` is 'open' (the default), 'closed' or 'all'. Poll it to find out whether the pull request you opened has landed.\",\n} as const;\n\n/**\n * The host-deploy lane's descriptions, repeated word for word by the hosted catalog, for the reason\n * GIT_TEXT is: pinned byte-equal by `src/__tests__/mcp/mcp-text-parity.test.ts`.\n */\nconst HOSTING_TEXT = {\n list_env_vars:\n \"The project's environment variables by NAME and scope (never a value), and `missing`: the ones the repository's .env.example declares that the project does not set. A site missing them builds and serves, then renders empty or crashes in the browser. Resolve `missing` by running `npx @bettercms-ai/cli@latest env push` in the repository: it uploads those values from the user's own .env files straight to BetterCMS, so they never pass through this conversation. Never read, print or ask the user to paste a value. When the values do not exist locally because the site reads its content from another CMS, move that content into BetterCMS instead (the bettercms skill's external-content reference). BetterCMS's own BCMS_* identifiers are supplied to every build and never need setting.\",\n list_hosting_connections:\n \"The Vercel, Netlify and Cloudflare accounts connected to this workspace (id, provider, accountLabel, status; never a token), plus `connectUrl`, the dashboard page where a person connects one. Call it before deploy_to_host. If the provider the user wants has no connection with status `ok`, give the user `connectUrl` to connect it in their browser and stop until they have: you never handle OAuth or a host token yourself.\",\n deploy_to_host:\n \"Deploy this project to the user's own Vercel or Netlify account through their connection. BetterCMS builds the site and the host serves that build (skill publishing). The first call creates the site on the host and makes it the project's host; a later call for the same provider redeploys that site (`redeployed: true`). `connectionId` (from list_hosting_connections) defaults to the newest working one, `siteName` to the project's handle. A refusal carries a `code` and a `fixUrl` (not_connected, reconnect, pick_existing_site, grant_required, ADMIN_REQUIRED): each is fixed by the user at `fixUrl`, so relay it and stop. `deploymentQueued: false` means the project has no live build yet: deploy_project first, and that release reaches the host on its own. Never run the Vercel or Netlify CLI while a connection exists. Then poll get_host_deploy_status. Needs artifact:write, like deploy_project.\",\n get_host_deploy_status:\n \"The connected project's recent deployments to Vercel, Netlify or Cloudflare, newest first: state (queued|deploying|live|failed), providerUrl, error, sha and targetName. Poll it after deploy_to_host until the newest one is `live`, whose `providerUrl` is the live URL to hand the user, or `failed`, whose `error` you read back to them.\",\n} as const;\n\n/** update_page's `blockJson` when it is an object: one section edit, each half named as the page route takes it. */\ninterface SectionEdit {\n insertSection?: { componentId: string; at?: number; before?: string; after?: string; style?: Record<string, unknown>; overrides?: Record<string, unknown> };\n sectionStyle?: { blockId: string; style: Record<string, unknown> };\n}\n\n/**\n * The id of this project's copy of a built-in section, made when it has none. A built-in is a locked\n * blueprint no page may place by its own id; `sourceKey` names the blueprint a component was copied\n * from, so a second \"add testimonials\" reuses the first copy instead of minting a twin.\n */\nasync function builtinCopyId(client: ManagementApi, builtinId: string): Promise<string> {\n const listed = await client.fetchJSON<{ data?: { id: string; sourceKey?: string | null; builtin?: boolean }[] }>(client.url(`/management/components?select=summary`));\n const copy = (listed.data ?? []).find((row) => row.sourceKey === builtinId && !row.builtin);\n if (copy) return copy.id;\n const made = await client.fetchJSON<{ data: { id: string } }>(client.url(`/management/components`), { method: \"POST\", body: JSON.stringify({ from: builtinId }) });\n return made.data.id;\n}\n\n/** A publish's ledger summary, as the publish routes return it (`outcome`). */\ninterface PublishOutcome {\n status: string;\n summary: string | null;\n live: number;\n notLive: { route: string; address: string; reason: string | null; action: { label: string } | null }[];\n next?: string;\n}\n\n/**\n * The summary lines of a call that published. A value the served page does not show LEADS, by name\n * and with its action: \"published\" used to be the whole answer, and the ledger that said otherwise\n * was a second call nobody made. `summary` is the call's own line, said after.\n */\nfunction publishedLines(outcome: PublishOutcome | undefined, summary: string): string[] {\n if (!outcome) return [summary];\n if (outcome.notLive.length > 0) {\n const values = outcome.notLive.map((v) => `${v.route} ${v.address}: ${v.reason ?? \"not live\"} (${v.action?.label ?? \"no action\"})`).join(\"; \");\n // Every value named is still being applied: nothing to act on, and nothing to call live yet.\n if (outcome.next && outcome.notLive.every((v) => v.reason === \"NOT_CHECKED\")) {\n return [`PENDING: ${values}. Read ${outcome.next} \\`publishes\\` until each reads live or held; do not report it as live before.`, summary];\n }\n return [`NOT LIVE: ${outcome.summary ?? outcome.status}. ${values}. Take each action, then read get_deploy_status \\`publishes\\`.`, summary];\n }\n if (outcome.next) return [`${summary} Published, and not judged yet: nothing has looked at the served page. Read ${outcome.next} \\`publishes\\` before saying it is live.`];\n if (outcome.status !== \"live\") return [`${summary} Publish status: ${outcome.status}.`];\n return [`${summary} Published: ${outcome.live > 0 ? `${outcome.live} ${outcome.live === 1 ? \"value\" : \"values\"} live on the served page` : \"live\"}.`];\n}\n\n/** What follows a write that made components: their props carry derived ui an agent can better (the server's componentize answer carries the same). */\nconst DOCK_UI_NEXT =\n \"Give every prop of this component its V2 ui (control, tab, group, collapsed, layout, preview, itemLabel, icon) by playbook §14 and the closest bettercms://kit entry: get_component, then ONE update_component with propUi, propTab and propHelpText (the field-ui prompt). Its props already carry the ui the server derived, so this improves the dock and holds nothing open.\";\n\nfunction ok(summary: string, data: unknown): ToolResult {\n return {\n content: [\n { type: \"text\", text: summary },\n { type: \"text\", text: JSON.stringify(data, null, 2) },\n ],\n };\n}\n\nfunction fail(message: string): ToolResult {\n return { content: [{ type: \"text\", text: message }], isError: true };\n}\n\n/**\n * Every `componentId` a block tree places, at any depth.\n *\n * Mirrors the nesting the backend's own dependency projection walks (section children, columns,\n * slider slides, tabs). `compose_pages` checks these against the project's catalogue BEFORE it\n * writes, because a page that places a component the project does not have renders those bands\n * as empty strings — no error, no placeholder, on a page that returns 200.\n */\nfunction componentIdsIn(blocks: unknown): string[] {\n const out: string[] = [];\n const walk = (value: unknown): void => {\n if (!Array.isArray(value)) return;\n for (const candidate of value) {\n if (!candidate || typeof candidate !== \"object\") continue;\n const block = candidate as { type?: string; props?: Record<string, unknown> };\n const props = (block.props ?? {}) as Record<string, unknown>;\n if (block.type === \"component\" && typeof props.componentId === \"string\" && props.componentId) {\n out.push(props.componentId);\n }\n if (block.type === \"section\") walk(props.children);\n else if (block.type === \"columns\" && Array.isArray(props.columns)) for (const column of props.columns) walk(column);\n else if (block.type === \"slider\" && Array.isArray(props.slides)) {\n for (const slide of props.slides) walk((slide as { children?: unknown })?.children);\n } else if (block.type === \"tabs\" && Array.isArray(props.tabs)) {\n for (const tab of props.tabs) walk((tab as { children?: unknown })?.children);\n }\n }\n };\n walk(blocks);\n return out;\n}\n\n/**\n * 🔴 DUCK-TYPED, not `instanceof BetterCMSError`. This package is PUBLISHED and resolves the SDK\n * the consumer installed, so the error a call throws can be an instance of a DIFFERENT copy of\n * that class than the one bundled here — `instanceof` is false across two module copies and the\n * receipt silently degrades to `[object Object]`. The shape is the contract.\n */\nfunction apiError(err: unknown): { status: number; message: string; bodyCode?: string; fieldErrors?: Record<string, string>; body?: unknown } | null {\n if (!err || typeof err !== \"object\") return null;\n const e = err as { status?: unknown; message?: unknown; bodyCode?: unknown; fieldErrors?: unknown; body?: unknown };\n if (typeof e.status !== \"number\") return null;\n return {\n status: e.status,\n message: typeof e.message === \"string\" ? e.message : \"\",\n bodyCode: typeof e.bodyCode === \"string\" ? e.bodyCode : undefined,\n fieldErrors: e.fieldErrors && typeof e.fieldErrors === \"object\" ? (e.fieldErrors as Record<string, string>) : undefined,\n body: e.body,\n };\n}\n\n/**\n * One failure, rendered for a RECEIPT rather than for a thrown result.\n *\n * The batch tools do not stop on a failed item — a whole-site run that dies on component 31 of\n * 40 has done 30 writes nobody has a record of. So each item's error becomes a line the agent can\n * read and act on, which means it has to carry the status and the machine code, not just a\n * sentence: `COMPONENT_IMPLEMENTATION_NOT_READY` is a governance state to relay to the user, and\n * a 409 slug conflict is a name to change and retry.\n */\nfunction errorText(err: unknown): string {\n const api = apiError(err);\n if (api) {\n const fields = api.fieldErrors\n ? Object.entries(api.fieldErrors).map(([k, v]) => `${k}: ${v}`).join(\"; \")\n : \"\";\n return `${api.status}${api.bodyCode ? ` ${api.bodyCode}` : \"\"} — ${fields || api.message}`;\n }\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * The machine-readable half of a refusal, appended to a thrown tool error.\n *\n * Without it a 409 reached the agent as \"409 CONFLICT + a sentence\": it could not tell\n * COMPONENT_IMPLEMENTATION_NOT_READY (relay the missing approvals to the user, never retry) from a\n * slug conflict (rename and retry), and the `readiness` tuple naming what is missing was dropped.\n * `issues` carries a FORM_DEFINITION_INVALID refusal's per-path problems the same way.\n *\n * The component publish refusal puts its code in `error` (with the sentence in `message`), so the\n * SDK's `bodyCode` is empty for it; an all-caps `error` is read as the code.\n */\nfunction refusalDetail(err: unknown): string {\n const api = apiError(err);\n if (!api) return \"\";\n const body = (api.body && typeof api.body === \"object\" ? api.body : {}) as { error?: unknown; readiness?: unknown; issues?: unknown; fixUrl?: unknown };\n const code = api.bodyCode ?? (typeof body.error === \"string\" && /^[A-Z][A-Z0-9_]+$/.test(body.error) ? body.error : undefined);\n const lines = [\n code ? `code: ${code}` : \"\",\n body.readiness !== undefined ? `readiness: ${JSON.stringify(body.readiness)}` : \"\",\n body.issues !== undefined ? `issues: ${JSON.stringify(body.issues)}` : \"\",\n // The link a person follows to fix it (connect a host, create a Vercel project): an agent\n // that only sees the sentence has nothing to hand the user.\n typeof body.fixUrl === \"string\" ? `fixUrl: ${body.fixUrl}` : \"\",\n ].filter(Boolean);\n return lines.length ? `\\n${lines.join(\"\\n\")}` : \"\";\n}\n\n/**\n * Authorization isn't done yet. Surface the clickable activation link *in the\n * tool result* (the one channel every MCP client renders — unlike the server's\n * stderr, which VS Code hides). The device flow is persisted, so simply\n * re-running this tool after approval resumes it and completes the request.\n */\nfunction authPrompt(err: DeviceAuthPendingError): ToolResult {\n const text = [\n \"🔐 BetterCMS authorization required — you're not signed in yet.\",\n \"\",\n `1. Open this link and approve: ${err.verificationUriComplete}`,\n ` (or visit ${err.verificationUri} and enter code ${err.userCode})`,\n \"2. Once approved, run this tool again — it resumes automatically and completes your request.\",\n ].join(\"\\n\");\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// ── Tool definitions ──────────────────────────────────────────────────────────\n\n/**\n * The `projectId` of the tool call currently running, read by `withClient` several frames down.\n *\n * 🔴 ASYNC-LOCAL, NOT A MODULE VARIABLE. The MCP transport dispatches requests without awaiting\n * the previous one, so two tool calls naming different projects are genuinely in flight together\n * and a shared mutable would write one call's target into the other's request. The alternative —\n * threading the argument through ~50 handler bodies — is a larger diff that only has to be\n * forgotten once to send a write to the wrong site.\n */\nconst currentProject = new AsyncLocalStorage<string | undefined>();\n\n/** The `branchId` of the tool call currently running — async-local for the same reason. */\nconst currentBranch = new AsyncLocalStorage<string | undefined>();\n\n/**\n * The per-call project argument, added to every tool that does not already declare one.\n *\n * Mirrors `withProjectId` on the hosted connector (backend `src/routes/mcp/index.ts`), which\n * lifts the same property onto its whole catalog for the same reason: a workspace-wide grant has\n * no project on the key, so every project-scoped route answers 400 PROJECT_SCOPE_REQUIRED and the\n * agent connects, sees every tool and can call none of them. The header only ever narrows WITHIN\n * the key's own workspace, so this grants nothing the key does not already hold.\n */\nconst projectIdArg = z\n .string()\n .min(1)\n .optional()\n .describe(\n \"list_projects id; workspace-wide grants only\",\n );\n\n/**\n * The per-call content branch, added to every tool that does not already declare one: the client\n * sends it as X-Branch-Id, so the call reads and writes inside that branch (list_branches).\n */\nconst branchIdArg = z\n .string()\n .min(1)\n .optional()\n .describe(\"content branch id (from list_branches); omit to work on main\");\n\n/** What whoami reads from GET /management/projects/current. */\ntype ProjectSummary = { id: string; name: string; slug: string; workspaceSlug?: string | null };\n\n/** Lift `projectId` and `branchId` onto a tool and bind them for the duration of the call. */\nconst withProjectId = (def: ToolDef): ToolDef => ({\n ...def,\n config: {\n ...def.config,\n inputSchema: {\n ...def.config.inputSchema,\n ...(def.config.inputSchema.projectId ? {} : { projectId: projectIdArg }),\n ...(def.config.inputSchema.branchId ? {} : { branchId: branchIdArg }),\n },\n },\n handler: (args) => {\n const arg = (key: string) => (typeof args?.[key] === \"string\" && args[key] ? (args[key] as string) : undefined);\n return currentProject.run(arg(\"projectId\"), () => currentBranch.run(arg(\"branchId\"), () => def.handler(args)));\n },\n});\n\n/**\n * The listing tail and the ABM lane, shared with the hosted catalogue (packages/mcp/src/toolsets.ts):\n * Claude Desktop keeps a server's first ~100 tools, and THIS is the surface Desktop loads.\n */\nexport { LISTING_TAIL };\n\n/**\n * What a field-creating tool says when the agent sent no help: the server wrote it (the stored\n * field reads `helpSource: \"auto\"`), so nothing is created without help and the agent knows whose\n * words they are. The hosted surface returns the route's own `helpText: {source: \"auto\"}` receipt.\n */\nconst autoHelpNote = (args: { helpText?: unknown }): string =>\n 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.\";\n\nexport function buildToolDefs(deps: ToolDeps): ToolDef[] {\n /** Run with a token, retrying once on 401 after a refresh / re-auth. */\n async function withClient<T>(fn: (client: ManagementApi) => Promise<T>): Promise<T> {\n const token = await deps.auth.getAccessToken();\n const project = currentProject.getStore();\n const branch = currentBranch.getStore();\n try {\n return await fn(deps.createClient(token, project, branch));\n } catch (err) {\n if (err instanceof BetterCMSError && err.status === 401) {\n const next = (await deps.auth.refresh()) ?? (await deps.auth.getAccessToken());\n return await fn(deps.createClient(next, project, branch));\n }\n // The key is bound to a project that was deleted server-side (L1: 409\n // PROJECT_DELETED). It can never succeed again — clear creds and re-authorize\n // so the user picks a LIVE project, then retry the original call into it.\n // (resetAndReauthorize throws DeviceAuthPendingError if approval isn't instant,\n // which guard() turns into the clickable activation prompt.)\n if (err instanceof BetterCMSError && err.status === 409 && err.bodyCode === \"PROJECT_DELETED\") {\n const next = await deps.auth.resetAndReauthorize();\n return await fn(deps.createClient(next, project, branch));\n }\n throw err;\n }\n }\n\n /** The id of the page an id, path or unique slug names; a slug two pages share throws the 409 listing each. */\n const pageIdOf = async (client: ManagementApi, ref: string): Promise<string> =>\n UUID.test(ref) ? ref : (await client.fetchJSON<{ data: { id: string } }>(client.url(`/management/pages/resolve?ref=${encodeURIComponent(ref)}`))).data.id;\n\n /** Wrap a handler with uniform error → ToolResult conversion. */\n function guard<A>(fn: (args: A) => Promise<ToolResult>) {\n return async (args: A): Promise<ToolResult> => {\n try {\n return await fn(args);\n } catch (err) {\n if (err instanceof DeviceAuthPendingError) {\n return authPrompt(err);\n }\n if (err instanceof BetterCMSError) {\n return fail(`BetterCMS error (${err.status} ${err.code}): ${err.message}${refusalDetail(err)}`);\n }\n return fail(`Unexpected error: ${err instanceof Error ? err.message : String(err)}`);\n }\n };\n }\n\n // ── Component authoring schemas ──\n // blockJson is a recursive ContentBlock tree; props is the override allowlist. The\n // backend validates the exact block union, so blocks are typed loosely here.\n // Declared BEFORE createPageInput/createComponentInput — both reference it.\n interface BlockInput { type: string; id: string; props: Record<string, unknown>; style?: Record<string, unknown>; window?: { from?: string; until?: string } | null }\n /** A block's or Layout Section's visibility window; the API validates and normalizes the instants. */\n const windowArg = z.object({ from: z.string().optional(), until: z.string().optional() });\n const blockObject: z.ZodType<BlockInput> = z.object({\n type: z\n .enum([\n \"heading\", \"text\", \"richtext\", \"image\", \"button\", \"spacer\", \"video\",\n \"columns\", \"section\", \"slider\", \"tabs\", \"navbar\", \"footer\", \"form\", \"component\",\n \"collection\",\n ])\n .describe(\"block type; section/slider/tabs/columns nest child blocks\"),\n id: z.string().min(1).describe(\"stable unique block id\"),\n props: z\n .record(z.string(), z.unknown())\n .describe(\n \"per-type props by block type: §5 of bettercms://playbook/schema (text/richtext {html}, NOT {text}; button {text, href, variant?, size? sm|md|lg, fullWidth?}; component {componentId, overrides?}). Containers nest blocks to any depth.\",\n ),\n style: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"design tokens: theme, bg (none|surface|muted|accent|dark|custom), bgCustom hex, paddingTop/paddingBottom/paddingSides px, contentWidth (narrow|default|wide|full), align, corner, shadow, borderTop/borderBottom, border (all four sides, in the text colour), hideOn [mobile|tablet|desktop] (all three hides it on the page: kept in the draft, never published). A real marketing band is a `section` block carrying bg + padding + contentWidth.\",\n ),\n window: windowArg.nullable().optional().describe(WINDOW_NOTE),\n });\n\n const createPageInput = z.object({\n title: z.string().min(1).describe(\"display title of the page, e.g. 'Home'\"),\n slug: slug.describe(\"URL-safe path segment, unique per project, e.g. 'home'\"),\n pageType: z\n .enum([\"singleton\", \"dynamic\"])\n .default(\"singleton\")\n .describe(\n \"'singleton' = exactly one entry (Home, About, Contact); 'dynamic' = many entries sharing this schema (Blog posts, Products). Defaults to singleton.\",\n ),\n blockJson: z\n .array(blockObject)\n .optional()\n .describe(\n \"the page's VISUAL composition — how a components-first page is built. Place one `component` block per section: {type:'component', id:'<stable>', props:{componentId:'<id from create_component>'}}. The component must be PUBLISHED (publish_component) or it renders as nothing on the live site. Independent of `fields`, which is a typed schema for a site's own code to read.\",\n ),\n fields: z.array(fieldObject).optional().describe(\"the page's typed schema fields\"),\n // Undeclared, this was stripped by the SDK before the request, so a singleton created with its\n // values arrived without them. The remote adapter and POST /management/pages always took it.\n data: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"a SINGLETON's field VALUES keyed by field key — seeds its entry in the same call. If any value is refused the page is still created, none of `data` is saved, and the result names ENTRY_SEED_FAILED with the per-field reasons: fix them and write with set_page_content.\",\n ),\n metaTitle: z.string().optional().describe(\"SEO meta title\"),\n metaDescription: z.string().optional().describe(\"SEO meta description\"),\n locale: z.string().nullable().optional().describe(PARAM_TEXT.locale),\n translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf),\n });\n\n const writeContentInput = z.object({\n action: z\n .enum([\"write\", \"rewrite\", \"translate\"])\n .describe(\"'write' = draft from a brief, 'rewrite' = improve existing copy, 'translate' = needs targetLang\"),\n text: z.string().min(1).describe(\"the source text (a brief for 'write', the copy to change otherwise)\"),\n instructions: z.string().optional().describe(\"optional extra guidance, e.g. 'make it punchier'\"),\n targetLang: z.string().optional().describe(\"required for 'translate', e.g. 'Spanish'\"),\n context: z.string().optional().describe(\"optional surrounding context, e.g. the page title\"),\n });\n\n const generateSeoMetaInput = z.object({\n text: z.string().min(1).describe(\"the content to derive SEO metadata from\"),\n context: z.string().optional().describe(\"optional surrounding context, e.g. the page slug\"),\n });\n\n // `projectId` is deliberately absent: withProjectId lifts it onto every tool below.\n const connectNativeAiInput = z.object({\n capabilities: z\n .array(z.string().min(1))\n .min(1)\n .optional()\n .describe(\n \"optional — any of inspect, propose, implement, cancel, question. Defaults to inspect+propose+cancel.\",\n ),\n });\n\n\n const createModelInput = z.object({\n name: z.string().min(1).describe(\"human model name, e.g. 'Blog Post'\"),\n slug: slug.describe(\"url-safe unique slug, e.g. 'blog-post'\"),\n description: z.string().optional().describe(PARAM_TEXT.describes),\n urlPattern: urlPatternArg,\n kind: z\n .enum([\"model\", \"block\"])\n .optional()\n .describe(\n \"'model' (default) = a collection with its own entries. 'block' = a type that exists only to be stacked inside another model's 'modular' field — 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.\",\n ),\n fields: z\n .array(fieldObject)\n .optional()\n .describe(\n \"the model's typed schema fields. 'group'/'repeater' NEST their child fields (any depth) — don't flatten zones into top-level fields.\",\n ),\n fieldsets: fieldsetsArg,\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n });\n\n // Insertion point. An ARGUMENT, never stored state — which is the whole point: field order\n // IS the array index, so a stored `order`/`position` prop would be a second source of truth\n // that can disagree with the array the schema builder persists with arrayMove. Omit it and\n // the field appends, exactly as before.\n const afterArg = z\n .string()\n .min(1)\n .optional()\n .describe(\n \"OPTIONAL insertion point: the key of an existing TOP-LEVEL field to insert this one directly after. Omit to append at the end (the default, and the behaviour before this existed). Use it to put a field where an author expects it instead of at the bottom — e.g. after:'hero_title' for a subtitle. An unknown key is refused rather than silently appended.\",\n );\n\n const addFieldInput = z.object({\n modelId: z.string().min(1).optional().describe(\"the content model to extend (from list_content_models); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of modelId: the page whose schema to extend (from list_pages / create_page)\"),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n ...fieldShape,\n after: afterArg,\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n });\n\n // Exactly one of localPath/url (enforced by the SDK + backend route, documented here).\n const uploadAssetInput = z.object({\n localPath: z\n .string()\n .min(1)\n .optional()\n .describe(\"absolute path to a local file (e.g. a repo image); provide this OR url\"),\n url: z\n .string()\n .url()\n .optional()\n .describe(\"remote image URL this client downloads and uploads; provide this OR localPath OR sourceUrl\"),\n sourceUrl: z.string().url().optional().describe(PARAM_TEXT.sourceUrl),\n filename: z.string().optional().describe(\"override the stored filename\"),\n altText: z.string().optional().describe(\"accessibility alt text\"),\n caption: z.string().optional(),\n transcript: z\n .string()\n .max(100_000)\n .optional()\n .describe(\"video/audio only: the spoken words (≤ 100,000 chars), published wherever the file is used\"),\n folderId: z.string().optional().describe(\"target Media Library folder (defaults to project root)\"),\n });\n\n // Upsert by external key, on create_content_entry and each row of create_content_entries.\n const upsertShape = {\n externalKey: z.string().min(1).max(255).optional().describe(PARAM_TEXT.externalKey),\n source: z.string().max(2048).optional().describe(PARAM_TEXT.upsertSource),\n runId: z.string().max(100).optional().describe(PARAM_TEXT.upsertRunId),\n };\n const createEntryInput = z.object({\n contentModelId: z.string().min(1).describe(\"id of the model this entry belongs to\"),\n slug: slug.optional(),\n status: z.enum([\"draft\", \"published\"]).optional().describe(\"defaults to draft\"),\n data: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\"field values keyed by field key\"),\n locale: z.string().nullable().optional().describe(PARAM_TEXT.locale),\n translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n ...upsertShape,\n });\n\n const getPageInput = z.object({\n pageId: z.string().min(1).describe(PARAM_TEXT.pageRef),\n });\n\n const setPageContentInput = z.object({\n pageId: z.string().min(1).describe(PARAM_TEXT.pageRef),\n data: z\n .record(z.string(), z.unknown())\n .describe(\n \"field values keyed by field key. A nested 'array' (zone) value is an OBJECT { nonRepeatable: { childKey: value, … }, repeatable: [ { childKey: value }, … ] } — nonRepeatable holds the fixed-block values, repeatable is the list of item objects (omit a zone you didn't define). A primitive 'array' (itemType) is a plain list. An 'image' value is an asset URL or asset id (from upload_asset) — the server resolves it to { id, url, name, altText }. Read get_page first to see each field's zones.\",\n ),\n status: z.enum([\"draft\", \"published\"]).optional().describe(\"omit to leave status unchanged\"),\n replace: z\n .boolean()\n .optional()\n .describe(\"true replaces the whole entry data, removing omitted fields; default false merges by top-level key\"),\n });\n\n const getEntryInput = z.object({\n entryId: z.string().min(1).describe(\"content entry id\"),\n });\n\n const listEntriesInput = z.object({\n modelId: z.string().optional().describe(\"filter by content model id\"),\n pageId: z.string().optional().describe(\"filter by page id (a singleton page has one entry)\"),\n status: z.enum([\"draft\", \"published\"]).optional(),\n externalKey: z.string().optional().describe(PARAM_TEXT.externalKeyFilter),\n where: z.record(z.string(), z.unknown()).optional().describe(PARAM_TEXT.where),\n sort: z.string().max(100).optional().describe(PARAM_TEXT.sort),\n page: z.number().int().min(1).optional().describe(PARAM_TEXT.page),\n limit: z.number().int().min(1).max(200).optional().describe(ENTRY_LIST_LIMIT_NOTE),\n detail: z.boolean().optional().describe(ENTRY_LIST_DETAIL_NOTE),\n });\n\n // Native SEO patches (mirrors src/lib/seo/meta-patch.ts). Absent keeps a key; null or \"\" clears it.\n const clearableText = (max: number) => z.string().max(max).nullable().optional();\n const headPatchShape = {\n canonical: clearableText(2048).describe(\"canonical URL; null clears\"),\n og: z\n .object({ title: clearableText(255), description: clearableText(500), image: clearableText(2048), type: clearableText(50) })\n .nullable()\n .optional()\n .describe(\"Open Graph; each key merges, null clears that key\"),\n twitter: z\n .object({ card: clearableText(50), title: clearableText(255), description: clearableText(500), image: clearableText(2048) })\n .nullable()\n .optional()\n .describe(\"Twitter card; each key merges, null clears that key\"),\n };\n const entryMetaInput = z.object({\n metaTitle: clearableText(255),\n metaDescription: clearableText(500),\n noindex: z.boolean().optional().describe(\"hide this entry from search engines and site search\"),\n ...headPatchShape,\n schemaType: z.enum(SCHEMA_ORG_TYPES).nullable().optional(),\n schema: z.union([z.record(z.string(), z.unknown()), z.array(z.record(z.string(), z.unknown()))]).nullable().optional(),\n });\n const updateEntryInput = z.object({\n entryId: z.string().min(1).describe(\"content entry id\"),\n data: z.record(z.string(), z.unknown()).optional().describe(\"field values keyed by field key\"),\n status: z.enum([\"draft\", \"published\"]).optional(),\n slug: slug.optional(),\n meta: entryMetaInput.optional().describe(\"the entry's native SEO; merges into what is stored\"),\n merge: z.boolean().optional().describe(ENTRY_MERGE_NOTE),\n ifMatch: z.number().int().min(0).optional().describe(ENTRY_IF_MATCH_NOTE),\n scheduledAt: z.string().datetime().nullable().optional().describe(ENTRY_SCHEDULED_AT_NOTE),\n unpublishAt: z.string().datetime().nullable().optional().describe(ENTRY_UNPUBLISH_AT_NOTE),\n locale: z.string().nullable().optional().describe(PARAM_TEXT.locale),\n translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf),\n });\n\n const deletePageInput = z.object({\n pageId: z.string().min(1).optional().describe(\"id of the page to delete (from list_pages)\"),\n runtimeBundle: z.enum([\"report\", \"apply\"]).optional().describe(PARAM_TEXT.runtimeBundle),\n });\n const deleteEntryInput = z.object({\n entryId: z.string().min(1).describe(\"id of the content entry to delete (from list_content_entries)\"),\n });\n const deleteModelInput = z.object({\n modelId: z.string().min(1).describe(\"id of the content model to delete (from list_content_models)\"),\n });\n\n const getFormInput = z.object({\n formId: z.string().min(1).describe(\"form id (from list_forms)\"),\n });\n\n // ── Form authoring schemas ──\n // MUST stay at parity with the server's field vocabulary (packages/db FormField + the\n // route's Zod). `update_form` REPLACES the whole `fields` array, so a type this schema\n // omits cannot be echoed back: an agent that reads a form and writes it back DESTROYS\n // every human-authored field of that type. `radio`/`checkboxes` were exactly that gap.\n // Guarded by src/__tests__/mcp/mcp-parity.test.ts.\n const formFieldObject = z.object({\n key: z.string().min(1).describe(\"machine key for the submitted value, e.g. 'email'\"),\n label: z.string().min(1).describe(\"field label shown to the visitor\"),\n type: z.enum([\n \"text\", \"email\", \"textarea\", \"select\",\n \"checkbox\", // single boolean; predates `checkboxes`\n \"checkboxes\", // pick-many, value is a string[] of chosen option labels\n \"radio\", // pick-one, rendered inline rather than in a dropdown\n \"number\", \"phone\", \"date\", \"url\", \"consent\", \"hidden\", \"step\", // `step` is a divider: the fields after it are one page\n ]),\n placeholder: z.string().optional(),\n helpText: z.string().optional().describe(\"hint shown under the control, muted\"),\n required: z.boolean().optional().describe(\n \"an entry cannot be saved without a value — set it only where the site genuinely cannot render without one\",\n ),\n options: z.array(z.string()).optional().describe(\"choices when type is 'select', 'radio' or 'checkboxes'\"),\n optionValues: z.array(z.string()).optional().describe(\"what each choice SUBMITS, positionally paired with `options` — only where it differs from the label\"),\n hidden: z.boolean().optional().describe(\"not rendered; pairs with defaultValue to capture context\"),\n defaultValue: z.string().optional(),\n showIf: z\n .object({ field: z.string(), equals: z.string() })\n .optional()\n .describe(\"show this field only when another field equals a value\"),\n validation: z\n .object({\n emailPolicy: z.enum([\"any\", \"business\"]).optional().describe(\"'email' fields only\"),\n min: z.number().optional().describe(\"'number' fields only — inclusive floor\"),\n max: z.number().optional().describe(\"'number' fields only — inclusive ceiling\"),\n phoneFormat: z.enum([\"any\", \"e164\"]).optional().describe(\"'phone' fields only\"),\n pattern: z.string().optional().describe(\"'text' / 'textarea' / 'url' fields only — a regex\"),\n })\n .optional()\n .describe(\"per-field rules the API enforces on submit; each key is only valid on the field types listed\"),\n ui: z\n // strict, like the server's: a typo inside `ui` must refuse here rather than be stripped\n // before the request is built — the agent would otherwise get a 200 and lose the key.\n .strictObject({\n countryPicker: z.boolean().optional().describe(\"'phone' fields only — render a country picker; the value is stored as E.164\"),\n defaultCountry: z.string().optional().describe(\"'phone' fields only — uppercase ISO 3166-1 alpha-2 the picker starts on; requires countryPicker\"),\n showFlags: z.boolean().optional().describe(\"'phone' fields only — show the country flag beside the dial code; requires countryPicker\"),\n })\n .optional()\n .describe(\"per-field presentation options; each key is only valid on the field types listed\"),\n });\n const formSettingsShape = {\n description: z.string().optional(),\n submitLabel: z.string().optional().describe(\"submit button label (default 'Submit')\"),\n successMessage: z.string().optional(),\n redirectUrl: z.string().url().optional().describe(\"URL to redirect to on success\"),\n // Spam + delivery settings. Each MUST parse exactly like its key in the route's\n // createFormSchema (this package cannot import it); src/__tests__/mcp/mcp-parity.test.ts\n // checks the two agree. Never add turnstileSecretKey: a secret does not belong in an\n // agent's context.\n turnstileEnabled: z.boolean().optional().describe(\"require a Cloudflare Turnstile check on submit\"),\n honeypotField: z.string().max(100).nullable().optional().describe(\"name of a hidden honeypot input; a submission that fills it is marked spam. null clears\"),\n notifyEmails: z.array(z.string().email()).optional().describe(\"addresses emailed on each submission (REPLACES the list)\"),\n };\n const createFormInput = z.object({\n name: z.string().min(1).describe(\"human form name (used by getForm('Name'))\"),\n fields: z.array(formFieldObject).default([]).describe(\"the form's fields\"),\n ...formSettingsShape,\n });\n const updateFormInput = z.object({\n formId: z.string().min(1).describe(\"form id (from list_forms)\"),\n name: z.string().optional(),\n fields: z.array(formFieldObject).optional().describe(\"REPLACES the field array — include all fields to keep\"),\n ...formSettingsShape,\n ignored: z.boolean().optional().describe(PARAM_TEXT.formIgnored),\n });\n\n const componentPropObject = z.object({\n key: z.string().min(1),\n label: z.string().min(1),\n target: z.object({ blockId: z.string().min(1), path: z.string().min(1) }),\n // Parity with componentPropDefSchema is no longer a promise to keep by hand — both now read\n // the SAME list from @bettercms-ai/types. It used to be a copy, and the failure that made\n // was quiet and total: `update_component` REPLACES the whole `props` array, so a type this\n // enum omitted could not be echoed back, and an agent reading a component and writing it\n // straight back DESTROYED every prop of that type on a 200.\n type: z.enum(COMPONENT_PROP_TYPES),\n // 'slot' holds ONE nested component instance, or a list with config.multiple (the keys\n // pass through to the server); config.componentIds restricts what may fill it. Absent here until now, so a slot allowlist was unreachable from stdio even\n // once the enum allowed the type.\n config: z\n .object({\n componentIds: z.array(z.string()).optional(), // 'slot' allowlist\n options: z.array(choiceOption).optional(), // 'select' — required, choices\n // 'group'/'table'/'object' sub-shape. Typed loosely here (the server validates the full\n // recursive shape, 10 levels at most) so a deep tree needs no Zod mirror in the client.\n // A sub-field may be a 'slot' (its value at its key in the object or row), with the slot keys above.\n fields: z.array(z.record(z.string(), z.unknown())).optional(),\n min: z.number().optional(), // 'number'\n max: z.number().optional(),\n step: z.number().optional(),\n })\n .passthrough()\n .optional(),\n defaultValue: z.unknown().optional(),\n // Editor hints, stored in the props JSON. `required` is NOT enforced at write time — an\n // override that omits it still saves — so it is a marker the dashboard renders and\n // get_site_composition counts, never a refusal. Parity: componentPropDefSchema on the server.\n required: z\n .boolean()\n .optional()\n .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.\"),\n helpText: z.string().max(200).nullable().optional().describe(\"hint shown under the control, muted (≤ 200 chars). null = no help on purpose (a /kit schema with no description); omitted = the platform writes it\"),\n placeholder: z.string().max(120).optional().describe(\"ghost text inside a text-ish control (≤ 120 chars)\"),\n // Stored markers on a prop: nothing refuses a prop value for them. Declared so an echo keeps them.\n readOnly: z.union([z.literal(true), z.literal(\"developer\")]).optional(),\n lockReason: z.string().max(200).optional(),\n localized: z.boolean().optional(),\n showIf: z\n .object({\n match: z.enum([\"all\", \"any\"]),\n rules: z.array(z.object({\n field: z.string().min(1),\n op: z.enum([\"eq\", \"neq\", \"in\", \"notIn\", \"gt\", \"lt\", \"isSet\", \"notEmpty\", \"empty\"]),\n value: z.union([z.string(), z.array(z.string())]).optional(),\n })).min(1).max(20),\n })\n .optional()\n .describe(\"show this prop only while SIBLING props (by key) match: {match:'all'|'any', rules:[{field, op:'eq'|'neq'|'in'|'notIn'|'gt'|'lt'|'isSet'|'notEmpty'|'empty', value?}]}. 'isSet', 'notEmpty' and 'empty' take no value; 'gt'/'lt' one number as a string. Editor-only.\"),\n // V2 editor-only keys, the model field's (playbook §14). Declared: this is a strip site.\n helpMore: z.string().max(2000).optional().describe(PARAM_TEXT.helpMore),\n advanced: z.boolean().optional().describe(PARAM_TEXT.advanced),\n recommendedMax: z.number().int().positive().optional().describe(PARAM_TEXT.recommendedMax),\n // F1.x `unique` (a list's items / a table's rows distinct) and the server's `stale` marker:\n // undeclared here, an agent's `unique` and an echoed `stale` were dropped with a 200.\n unique: z.boolean().optional(),\n stale: z.boolean().optional(),\n openMode: z.enum([\"inline\", \"drill\", \"popover\", \"dialog\"], { error: OPEN_MODE_INVALID }).optional().describe(\"object/group/table props: how the value (or each row) opens\"),\n // ⚠ A STRIP SITE, exactly like OutField above: this is a `z.object`, so a key the model\n // sends and this shape does not declare is dropped BEFORE the request leaves — a 200 with\n // the declaration gone. `ui` rode through the backend's looseObject `config` and died here.\n ui: propUiObject\n .optional()\n .describe(\n \"AUTHORING CHROME for this prop's control in the inspector — never a delivery effect, and the same object a FIELD's `ui` takes. `preview` and `layout` are valid on 'group', 'table', 'object' and 'slot' (`layout` 'rows'|'chips'|'gallery' also on 'multiselect', 'tags'); `reorderable` on 'table' ALONE, the one prop type whose value is a LIST (a 'group' is one object, a 'slot' one component instance). preview keys name a SUB-FIELD of this prop's config.fields and are checked against them (on a 'slot' the shape is checked but the keys cannot be — they belong to whichever component fills it). An unknown key inside `ui` is a 400, not a silent strip. Read it back with get_component: a prop whose `ui` is absent there was not stored.\",\n ),\n });\n const getLayoutInput = z.object({\n scope: z.enum([\"global\", \"page\"]).default(\"global\"),\n pageId: z.string().min(1).optional().describe(\"page id or slug; required for page scope\"),\n copy: z.enum([\"draft\", \"published\"]).optional().describe(\"which copy to read; default draft. Verifying a publish MUST read copy:'published' and check the response's copy echo — the draft is never a publish receipt (FLO-1188).\"),\n projectId: z.string().min(1).optional().describe(\"required only for a workspace-scoped grant\"),\n });\n const layoutBinding = z.object({ inputId: z.string().min(1), fieldId: z.string().min(1) });\n const layoutIcon = z.string().min(1).max(80)\n .regex(/^(?:[a-z0-9]+(?:-[a-z0-9]+)*|[A-Z][A-Za-z0-9]+)$/)\n .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\")\n .describe(\"kit icon name from bettercms://icons/dock (e.g. 'document-text'); legacy Lucide names (kebab-case or CamelCase) remain accepted\");\n const sectionTarget = { sectionId: z.string().min(1) };\n const layoutCommand = z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"set-section-values\"), ...sectionTarget, values: z.record(z.string(), z.unknown()) }),\n z.object({ type: z.literal(\"set-field-value\"), ...sectionTarget, fieldId: z.string().min(1), value: z.unknown() }),\n z.object({ type: z.literal(\"add-component\"), ...sectionTarget, componentId: z.string().min(1), variantGroupId: z.string().min(1).optional(), bindings: z.array(layoutBinding).optional(), literalValues: z.record(z.string(), z.unknown()).optional() }),\n z.object({ type: z.literal(\"remove-item\"), ...sectionTarget, itemId: z.string().min(1) }),\n z.object({ type: z.literal(\"move-component\"), ...sectionTarget, itemId: z.string().min(1), index: z.number().int().nonnegative() }),\n z.object({ type: z.literal(\"move-item\"), ...sectionTarget, itemId: z.string().min(1), index: z.number().int().nonnegative() }),\n z.object({ type: z.literal(\"swap-component-variant\"), ...sectionTarget, itemId: z.string().min(1), componentId: z.string().min(1) }),\n z.object({ type: z.literal(\"set-page-state\"), ...sectionTarget, state: z.enum([\"inherit\", \"override-content\", \"customize-structure\", \"disable\", \"reset\"]) }),\n z.object({ type: z.literal(\"set-section-state\"), ...sectionTarget, state: z.enum([\"inherit\", \"override-content\", \"customize-structure\", \"disable\", \"reset\"]) }),\n z.object({ type: z.literal(\"add-section\"), name: z.string().min(1), icon: layoutIcon, zone: z.enum([\"before_page\", \"after_page\"]), window: windowArg.optional() }),\n 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() }),\n 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(), window: windowArg.nullable().optional().describe(\"as a block's `window`\") }),\n z.object({ type: z.literal(\"remove-section\"), ...sectionTarget }),\n z.object({ type: z.literal(\"move-section\"), ...sectionTarget, afterId: z.string().nullable().optional(), beforeId: z.string().nullable().optional() }),\n 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() }),\n z.object({ type: z.literal(\"update-field\"), ...sectionTarget, fieldId: z.string().min(1), patch: z.object({}).passthrough() }),\n z.object({ type: z.literal(\"remove-field\"), ...sectionTarget, fieldId: z.string().min(1) }),\n z.object({ type: z.literal(\"move-field\"), ...sectionTarget, itemId: z.string().min(1), index: z.number().int().nonnegative() }),\n z.object({ type: z.literal(\"set-bindings\"), ...sectionTarget, itemId: z.string().min(1), bindings: z.array(layoutBinding), literalValues: z.record(z.string(), z.unknown()).optional() }),\n ]);\n const commandLayoutInput = z.object({\n scope: z.enum([\"global\", \"page\"]).default(\"global\"),\n pageId: z.string().min(1).optional(),\n projectId: z.string().min(1).optional().describe(\"required only for a workspace-scoped grant\"),\n command: layoutCommand.optional().describe(\"one canonical discriminated Layout command; authority is derived from type\"),\n // Chrome is many commands — add a section, add a component to it, bind its fields — and each\n // one needs the revision the PREVIOUS one returned. An agent doing that by hand runs\n // get_layout between every write, and a single missed re-read is a 409 mid-sequence.\n commands: z\n .array(layoutCommand)\n .min(1)\n .max(50)\n .optional()\n .describe(\"apply these commands IN ORDER, each against the revision the previous one returned. Mutually exclusive with `command`. Stops at the first failure and reports what was applied.\"),\n ifMatch: z.number().int().nonnegative().describe(\"revision returned by get_layout. With `commands`, this is the revision for the FIRST command only — the rest are chained.\"),\n });\n const publishLayoutInput = z.object({\n projectId: z.string().min(1).optional().describe(\"required only for a workspace-scoped grant\"),\n ifMatch: z.number().int().nonnegative().describe(\"revision returned by get_layout (scope global)\"),\n });\n // Eight structural categories (what the component IS) + the four \"Add a section\" library\n // tabs (where it appears). Keep in step with componentCategorySchema in\n // src/lib/validation/schemas/components.ts — the library four were missing here, so an\n // agent could not file a component under a library tab.\n const componentCategory = z.enum([\n \"navbar\", \"footer\", \"button\", \"section\", \"slider\", \"tabs\", \"form\", \"custom\",\n \"hero\", \"content\", \"social-proof\", \"conversion\",\n ]);\n const sectionType = z\n .string()\n .min(1)\n .max(64)\n .describe(\n \"section family: what KIND of section this is, e.g. 'Hero', 'Logo cloud', 'Pricing', 'FAQ' (never its heading's words: a section's title is its own heading, shown as written). 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.\",\n );\n const allowedOn = z\n .array(z.string().regex(/^(\\*|slug:[a-z0-9-]+|type:(singleton|dynamic|template))$/))\n .max(100)\n .describe(\"placement allowlist: *, slug:<page-slug>, and/or type:singleton|dynamic|template\");\n const componentPreviewArg = z\n .strictObject({\n title: z.string().min(1).max(64).optional(),\n subtitle: z.string().min(1).max(64).optional(),\n media: z.string().min(1).max(64).optional(),\n fallback: z.string().min(1).max(120).optional(),\n icon: dockIconArg.optional(),\n })\n .nullable()\n .describe(PARAM_TEXT.componentPreview);\n const createComponentInput = z.object({\n name: z.string().min(1),\n slug: slug.describe(\"url-safe unique slug (lowercase letters/numbers/hyphens)\"),\n category: componentCategory.optional().describe(\"defaults to 'custom'\"),\n 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.\"),\n sectionType: sectionType.optional(),\n 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)\"),\n from: z.string().min(1).max(255).optional().describe(PARAM_TEXT.fromBuiltin),\n projectId: z.string().nullable().optional().describe(\"owning project id; null creates a workspace-wide global component\"),\n allowedOn: allowedOn.optional(),\n description: z.string().optional().describe(PARAM_TEXT.describes),\n preview: componentPreviewArg.optional(),\n icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),\n tabs: z.array(z.object({ id: z.string(), label: z.string(), icon: z.string().optional(), order: z.number().int().optional() })).nullable().optional().describe(PARAM_TEXT.componentTabs),\n kitEntry: z.string().min(1).max(100).nullable().optional().describe(PARAM_TEXT.componentKitEntry),\n blockJson: z.array(blockObject).default([]).describe(\"the component's block tree\"),\n props: z\n .array(componentPropObject)\n .default([])\n .describe(\n \"overridable fields. DECLARE A PROP — WITH A `target` — 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 — 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,\n ),\n });\n const updateComponentInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n name: z.string().optional(),\n category: componentCategory.optional(),\n group: z.string().min(1).max(100).optional().describe(\"move it into this Group (by NAME; created when missing) — the folder editors see in the dashboard's Components tab\"),\n sectionType: sectionType\n .nullable()\n .optional()\n .describe(\n \"null demotes it to an ordinary component — it disappears from the 'Add a section' picker, and instances already placed keep rendering but lose their section chrome and variant switcher\",\n ),\n variantOf: z.string().min(1).max(255).optional().describe(\"see create_component\"),\n allowedOn: allowedOn.optional().describe(\"REPLACES the placement allowlist\"),\n description: z.string().optional(),\n preview: componentPreviewArg.optional(),\n icon: dockIconArg.nullable().optional().describe(PARAM_TEXT.componentIcon),\n kitEntry: z.string().min(1).max(100).nullable().optional().describe(PARAM_TEXT.componentKitEntry),\n blockJson: z.array(blockObject).optional().describe(\"REPLACES the block tree\"),\n props: z\n .array(componentPropObject)\n .optional()\n .describe(\n \"REPLACES the prop array — 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.\",\n ),\n propUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(PROP_UI_ARG_NOTE),\n propGroup: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(\"prop key → its ui.group ({id, label?, kind?, icon?, collapsed?}), null takes it out\"),\n propTab: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(\"prop key → 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}; ≤8 tabs; one group's members share one tab. null takes it out\"),\n propLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe(\"prop key → label\"),\n propHelpText: z.record(z.string(), z.string().max(200).nullable()).optional().describe(\"prop key → help text; null = no help on purpose (stays empty, never refilled)\"),\n override: z.boolean().optional().describe(OVERRIDE_NOTE),\n ifMatch: z.number().int().min(0).optional().describe(COMPONENT_IF_MATCH_NOTE),\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n });\n const setComponentSourceInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n path: z.string().min(1).max(512).describe(\"file path relative to the app root, e.g. src/components/sections/Hero.astro\"),\n export: z.string().min(1).max(128).optional().describe(\"named export that renders it; omit for a default export\"),\n kind: z.enum([\"file\", \"section\"]).optional().describe(\"'file' (props are this component's fields; default) or 'section' (a codemod-extracted section: props { blockId, bind, overrides, page })\"),\n });\n const submitComponentizeReceiptInput = z.object({\n receipt: z.record(z.string(), z.unknown()).describe(\"The receipt `npx @bettercms-ai/convert --componentize --receipt <file>` wrote, verbatim.\"),\n });\n const componentValidationRouteInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n path: z.string().min(1).max(500).optional().describe(\"route in the app that serves the preview; omit for the default\"),\n nativeViewports: z.array(z.object({\n name: z.string().min(1).max(64),\n width: z.number().int().positive().max(10000),\n height: z.number().int().positive().max(10000),\n })).min(1).max(8).optional().describe(\"viewports to check; omit for the defaults\"),\n });\n const clearComponentSourceInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n });\n const getComponentInput = z.object({\n componentId: z.string().min(1).describe(\"component id (from list_components)\"),\n detachedCopy: z.object({ overrides: z.record(z.string(), z.unknown()).optional() }).optional().describe(DETACHED_COPY_NOTE),\n });\n const publishComponentsInput = z.object({\n componentIds: z.array(z.string().min(1)).min(1).max(100).describe(\"component ids (from list_components)\"),\n });\n const composePagesInput = z.object({\n pages: z\n .array(\n z.object({\n pageId: z.string().min(1).optional().describe(PARAM_TEXT.pageRef),\n slug: z.string().min(1).optional().describe(\"a page slug, when one page has it; or pass `pageId`\"),\n blockJson: z.array(blockObject).describe(\"REPLACES this page's whole block composition\"),\n }),\n )\n .min(1)\n .max(50),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n });\n const listComponentsInput = z.object({\n detail: z\n .boolean()\n .optional()\n .describe(\"true = every component's full blockJson and props. Costly and rarely what you want — read one definition with get_component instead.\"),\n });\n const listExtractionCandidatesInput = z.object({\n projectId: z.string().min(1).optional().describe(\"only needed for a workspace-wide key\"),\n });\n const extractComponentInput = z.object({\n hash: z.string().min(1).describe(\"candidate hash from list_extraction_candidates\"),\n name: z.string().min(1).describe(\"name for the new component\"),\n slug: slug.describe(\"url-safe unique slug (lowercase letters/numbers/hyphens)\"),\n projectId: z.string().min(1).optional().describe(\"only needed for a workspace-wide key\"),\n });\n /**\n * The content-lifecycle tools, in parity with the remote /mcp catalog. Each is a thin\n * call to an authenticated API route through the client's public request plumbing — no\n * bespoke SDK method per endpoint (DRY). Most target Management; Section evidence targets\n * the project-scoped ingest lane. `def`/`data` collapse the shared boilerplate.\n */\n function lifecycleTools(): ToolDef[] {\n const def = (\n name: string,\n title: string,\n description: string,\n shape: z.ZodRawShape,\n run: (client: ManagementApi, args: Record<string, unknown>) => Promise<ToolResult>,\n ): ToolDef => ({\n name,\n config: { title, description, inputSchema: shape },\n handler: guard(async (args: Record<string, unknown>) => withClient((client) => run(client, args))) as ToolDef[\"handler\"],\n });\n const q = (obj: Record<string, unknown>): string => {\n const p = new URLSearchParams();\n for (const [k, v] of Object.entries(obj)) if (v !== undefined && v !== null) p.set(k, String(v));\n const s = p.toString();\n return s ? `?${s}` : \"\";\n };\n /**\n * Call a management endpoint and return its `data` payload.\n *\n * 🔴 Do NOT set a content-type here. `ManagementApi.headers()` already sends\n * `Content-Type: application/json`, and `fetchJSON` merges headers as a PLAIN OBJECT —\n * so a lowercase `content-type` is a DIFFERENT key, both survive the spread, and the\n * Headers constructor then APPENDS them into `application/json, application/json`.\n * Hono's zValidator does not recognise that as JSON, reads the body as absent, and every\n * write here failed with a validation error naming a field the caller did send. It cost\n * all 16 body-carrying tools on this surface, silently, because the request looked\n * perfect from the client side and the server's complaint pointed at the body's contents.\n */\n const data = async (client: ManagementApi, method: string, path: string, body?: unknown): Promise<unknown> =>\n (await client.fetchJSON<{ data?: unknown }>(client.url(path), {\n method,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n })).data;\n const s = (v: unknown) => v as string;\n /** POST raw bytes (base64 → binary) for the binary deploy tool; returns `data`. */\n const raw = async (client: ManagementApi, path: string, base64: string, mimeType?: string): Promise<unknown> =>\n (await client.fetchJSON<{ data?: unknown }>(client.url(path), {\n method: \"POST\",\n body: Buffer.from(base64, \"base64\"),\n headers: { \"content-type\": mimeType ?? \"application/octet-stream\" },\n })).data;\n\n return [\n def(\"create_media_upload\", \"Get a presigned media-upload URL\",\n \"PREFERRED way to add an image — get a presigned URL and upload the file DIRECTLY to storage, so the bytes never pass through the conversation. Flow: (1) call this with filename, mimeType and sizeBytes (the file's exact byte length); (2) PUT the file to `uploadUrl`, e.g. `curl -X PUT -H 'Content-Type: image/jpeg' --data-binary @photo.jpg \\\"<uploadUrl>\\\"` — the url pins both headers, so they must match exactly; (3) call attach_media_upload with the `assetId` + `uploadKey`. URL expires in 10 minutes.\",\n z.object({\n filename: z.string().min(1).describe(\"file name incl. extension, e.g. 'hero.png'\"),\n mimeType: z.string().min(1).describe(\"MIME type, e.g. 'image/png'\"),\n sizeBytes: z.number().describe(\"the file's exact size in bytes (e.g. from `stat`/`wc -c`) — the presigned url pins it\"),\n }).shape,\n async (c, a) => ok(\"Upload URL.\", await data(c, \"POST\", `/management/media/upload-url`, { filename: a.filename, mimeType: a.mimeType, sizeBytes: a.sizeBytes }))),\n def(\"attach_media_upload\", \"Attach a presigned media upload\",\n \"Register a file you already uploaded via create_media_upload (step 3) into the Media Library and get back its CDN url. Pass the `assetId` + `uploadKey` from step 1, plus the filename and any alt text/caption.\",\n z.object({\n assetId: z.string().min(1).describe(\"the assetId from create_media_upload\"),\n uploadKey: z.string().min(1).describe(\"the uploadKey from create_media_upload, after the PUT succeeded\"),\n filename: z.string().min(1).describe(\"file name incl. extension\"),\n altText: z.string().optional(),\n caption: z.string().optional(),\n transcript: z.string().max(100_000).optional().describe(\"video/audio only: the spoken words (≤ 100,000 chars)\"),\n folderId: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Media asset.\", await data(c, \"POST\", `/management/media/from-upload`, { assetId: a.assetId, uploadKey: a.uploadKey, filename: a.filename, altText: a.altText, caption: a.caption, transcript: a.transcript, folderId: a.folderId }))),\n def(\"update_media\", \"Update a media asset\",\n \"Describe an existing media asset: set its alt text, caption, transcript, `decorative` (no alt text needed) or focal point (focalX/focalY, the spot crops keep in frame; delivered images carry it with width, height and thumbHash). A transcript (video/audio only, ≤ 100,000 chars) is stored ON the asset, so every page and entry using the file publishes it — hosted pages, the .md twin, llms-full.txt and the delivery API. Pass null to clear a field. Use this after your own speech-to-text; BetterCMS does not generate transcripts.\",\n z.object({\n assetId: z.string().min(1).describe(\"media asset id (from list_media / upload_asset)\"),\n altText: z.string().max(500).nullable().optional().describe(\"alt text; null clears\"),\n caption: z.string().max(1000).nullable().optional().describe(\"caption; null clears\"),\n transcript: z.string().max(100_000).nullable().optional().describe(\"the spoken words; null clears. Video/audio only.\"),\n decorative: z.boolean().optional().describe(\"needs no alt text\"),\n focalX: z.number().min(0).max(1).nullable().optional().describe(PARAM_TEXT.focalX),\n focalY: z.number().min(0).max(1).nullable().optional().describe(PARAM_TEXT.focalY),\n }).shape,\n async (c, a) => ok(\"Updated media asset.\", await data(c, \"PATCH\", `/management/media/${encodeURIComponent(s(a.assetId))}`, { altText: a.altText, caption: a.caption, transcript: a.transcript, decorative: a.decorative, focalX: a.focalX, focalY: a.focalY }))),\n def(\"list_media\", \"List media assets\",\n \"List the images/assets already in the connected project's Media Library (id, url, filename, mimeType, size, alt/caption). Reuse an existing asset instead of re-uploading. Filter with `search` or `type` ('image'|'video'|…).\",\n z.object({ search: z.string().optional(), type: z.string().optional(), limit: z.number().optional(), page: z.number().optional() }).shape,\n async (c, a) => ok(\"Media assets.\", await data(c, \"GET\", `/management/media${q({ search: a.search, type: a.type, limit: a.limit, page: a.page })}`))),\n def(\"get_media\", \"Get a media asset\",\n \"Get one media asset by id — its CDN url, filename, MIME type, size, and alt/caption. Use the url as the value of an 'image' field.\",\n z.object({ assetId: z.string().min(1).describe(\"media asset id (from list_media / upload_asset)\") }).shape,\n async (c, a) => ok(\"Media asset.\", await data(c, \"GET\", `/management/media/${s(a.assetId)}`))),\n def(\"delete_media\", \"Delete a media asset\",\n \"Delete a media asset from the Media Library (soft delete — reversible from the dashboard trash). Provide assetId.\",\n z.object({ assetId: z.string().min(1).describe(\"media asset id (from list_media)\") }).shape,\n async (c, a) => ok(\"Deleted media asset.\", await data(c, \"DELETE\", `/management/media/${s(a.assetId)}`))),\n\n def(\"delete_form\", \"Delete a form\",\n \"Delete a form by id. Soft delete — the form stops rendering and accepting submissions, but leads already collected against it are preserved. Use it to clean up forms created by mistake.\",\n z.object({ formId: z.string().min(1).describe(\"form id (from list_forms)\") }).shape,\n async (c, a) => ok(\"Deleted form.\", await data(c, \"DELETE\", `/management/forms/${s(a.formId)}`))),\n\n def(\"list_form_submissions\", \"List a form's submissions (leads)\",\n \"List the SUBMISSIONS (leads) a form has received — each with its submitted field values. Filter with status ('inbox'|'spam') and paginate with limit/page.\",\n z.object({ formId: z.string().min(1), status: z.enum([\"inbox\", \"spam\"]).optional(), limit: z.number().optional(), page: z.number().optional() }).shape,\n async (c, a) => ok(\"Form submissions.\", await data(c, \"GET\", `/management/forms/${s(a.formId)}/submissions${q({ status: a.status, limit: a.limit, page: a.page })}`))),\n def(\"delete_form_submission\", \"Delete a form submission\",\n \"Delete one form submission (lead) — e.g. to clear spam. Provide formId and submissionId (from list_form_submissions).\",\n z.object({ formId: z.string().min(1), submissionId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Deleted submission.\", await data(c, \"DELETE\", `/management/forms/${s(a.formId)}/submissions/${s(a.submissionId)}`))),\n\n // ── Content structure: the Content sidebar's folders and icons ──\n def(\"get_content_structure\", \"Get the Content sidebar structure\",\n `Returns { doc, version, summary }: \\`doc\\` is the raw document ({ schema: 1, folders: [{ id, parentId, name, icon, sort }], items: [{ kind: 'page'|'collection', id, folderId, sort, icon }] }), \\`version\\` is what set_content_structure needs, and \\`summary\\` is the resolved tree with page and collection TITLES (\\`outline\\` is a readable version), ids that no longer resolve (\\`missing\\`), and the pages and collections not in any folder yet. Call it before changing the structure; a 403 SCHEMA_ACCESS_REQUIRED on a change means this connection lacks Admin or Developer: stop and tell the user. ${STRUCTURE_FENCE}`,\n z.object({}).shape,\n async (c) => {\n const d = (await data(c, \"GET\", `/management/content-structure`)) as { summary?: { outline?: string } } | undefined;\n return ok(d?.summary?.outline ? `Content structure:\\n${d.summary.outline}` : \"Content structure.\", d);\n }),\n def(\"suggest_content_structure\", \"Propose the standard Content structure\",\n `READ-ONLY: propose the standard Content sidebar structure for the connected project (${STRUCTURE_PLAYBOOK_URI}) and write NOTHING. Runs the standard over the project's pages, collections, references and built routes: the home page and each collection's list page pinned, one folder per content family named for its detail type (Blog posts, Case studies, Products with its taxonomies and an Attributes subfolder), ordered by entry count (or the caller's nav order), shared taxonomies in Shared, every remaining page in Pages, at most 2 levels deep. Page-bound models are never filed. Returns { doc, version, hasDocument, outline, rationale }. To apply it: show the user the outline, then call set_content_structure with this doc and this version (the If-Match; a 412 means someone changed the sidebar, so suggest again). When hasDocument is true the project already has a structure somebody made: never replace it without the user's yes; file only what is new with move_to_folder instead.`,\n z.object({\n maxDepth: z.number().int().min(1).max(4).optional().describe(\"folder nesting to propose; default 2 (the standard), 4 is the hard limit\"),\n }).shape,\n async (c, a) => {\n const d = (await data(c, \"GET\", `/management/content-structure/suggest${q({ maxDepth: a.maxDepth })}`)) as { outline?: string } | undefined;\n return ok(d?.outline ? `Proposed Content structure (nothing was written):\\n${d.outline}` : \"Proposed Content structure.\", d);\n }),\n def(\"set_content_structure\", \"Replace the Content sidebar structure\",\n `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 ≤4, names 1-80 chars, kit icons (bettercms://icons/dock). 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}`,\n z.object({\n doc: z.object({\n schema: z.literal(1),\n folders: z.array(z.object({\n id: z.string().min(1).describe(\"your own stable id, up to 64 chars\"),\n parentId: z.string().nullable().describe(\"parent folder id; null = top level\"),\n name: z.string(),\n icon: z.string().nullable().describe(\"kit icon name (bettercms://icons/dock) or null\"),\n sort: z.number(),\n })),\n items: z.array(z.object({\n kind: z.enum([\"page\", \"collection\"]),\n id: z.string().min(1).describe(\"page id or collection (content model) id\"),\n folderId: z.string().nullable().describe(\"folder id; \\\"home:root\\\" = pinned at the top level; null = its home (Pages for a page, the Shared list for a collection)\"),\n sort: z.number(),\n icon: z.string().nullable(),\n })),\n }).describe(\"the complete document\"),\n version: z.number().int().min(0).describe(\"the version get_content_structure returned\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"PUT\", `/management/content-structure`, { doc: a.doc, version: a.version }))),\n def(\"create_folder\", \"Create a Content sidebar folder\",\n `Create a folder in the Content sidebar, at the top level or inside \\`parentId\\`, placed after what is already there. Returns the new \\`folderId\\`. Reads, applies and writes with the version check, retrying once on a conflict. ${STRUCTURE_FENCE}`,\n z.object({\n name: z.string().min(1).describe(\"the folder's label, 1-80 chars\"),\n parentId: z.string().min(1).optional().describe(\"optional parent folder id (from get_content_structure); omit it, or send 'root', for the top level\"),\n icon: z.string().min(1).optional().describe(\"optional kit icon name (bettercms://icons/dock), e.g. 'folder'\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"POST\", `/management/content-structure/folders`, { name: a.name, parentId: a.parentId, icon: a.icon }))),\n def(\"rename_folder\", \"Rename a Content sidebar folder\",\n `Rename a Content sidebar folder. ${STRUCTURE_POINTER}`,\n z.object({\n folderId: z.string().min(1).describe(\"folder id (from get_content_structure)\"),\n name: z.string().min(1).describe(\"the new label, 1-80 chars\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"PATCH\", `/management/content-structure/folders/${encodeURIComponent(s(a.folderId))}`, { name: a.name }))),\n def(\"move_to_folder\", \"Move into a Content sidebar folder\",\n `Move a page, a collection or a folder into a folder. folderId null moves it back to its home: Pages for a page, the Shared list for a collection, the top level for a folder. It lands after what is already there. Moving a folder takes its contents with it and is refused if the result would nest deeper than 4 levels or put a folder inside itself. ${STRUCTURE_POINTER}`,\n z.object({\n kind: z.enum([\"page\", \"collection\", \"folder\"]).describe(\n \"what the id IS on this branch — 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.\",\n ),\n id: z.string().min(1).describe(\"the page id, collection (content model) id, or folder id\"),\n folderId: z.string().min(1).nullable().describe(\"target folder id; 'root' pins a page or collection at the top level (for a folder, 'root' is the top level); null moves it back to its home (Pages, the Shared list, or the top level for a folder)\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"POST\", `/management/content-structure/move`, { kind: a.kind, id: a.id, folderId: a.folderId }))),\n def(\"set_brand_assets\", \"Point the brand's logo or favicon at a media asset\",\n `Point the brand's logo (mark) or favicon at a media asset of this project — upload it to this project's media library first if it is not there. A slot a PERSON chose is refused without replace: true, and the refusal says so. ${BRAND_KIT_POINTER}`,\n z.object({\n mark: z.string().min(1).nullable().optional().describe(\"media asset id for the logo; null clears it\"),\n favicon: z.string().min(1).nullable().optional().describe(\"media asset id for the favicon; null clears it\"),\n replace: z.boolean().optional().describe(\"override a slot a person chose (default false)\"),\n }).shape,\n async (c, a) => ok(\"Brand assets.\", await data(c, \"POST\", `/management/projects/current/brand-kit/assets`, { mark: a.mark, favicon: a.favicon, replace: a.replace }))),\n def(\"set_brand_graphics\", \"Add, replace or remove the brand's gradients\",\n `Add, replace or remove the brand's gradients — the blobs and washes a site uses as backgrounds. They are TOKENS, not media. A stop naming a colour the kit does not have is refused; add it to \\`extras\\` first. Upsert matches BY KEY. ${BRAND_KIT_POINTER}`,\n z.object({\n upsert: z.array(z.object({\n key: z.string().min(1).describe(\"token key: lowercase letters, digits and hyphens. Emitted as --brand-gradient-<key>\"),\n label: z.string().optional(),\n kind: z.enum([\"linear\", \"radial\", \"conic\"]),\n angle: z.number().optional().describe(\"degrees 0-360; ignored for radial\"),\n stops: z.array(z.object({\n color: z.string().min(1).describe(\"a kit colour KEY — a colors.* role name or an extras key. Never a hex.\"),\n at: z.number().describe(\"position 0-100\"),\n })).min(2).max(8),\n })).max(12).optional().describe(\"gradients to add or replace, matched BY KEY\"),\n remove: z.array(z.string().min(1)).max(12).optional().describe(\"gradient keys to remove\"),\n }).shape,\n async (c, a) => ok(\"Brand graphics.\", await data(c, \"POST\", `/management/projects/current/brand-kit/graphics`, { upsert: a.upsert, remove: a.remove }))),\n def(\"set_icon\", \"Set a Content sidebar icon\",\n `Set or clear the sidebar icon of a page, a collection or a folder. ${STRUCTURE_POINTER}`,\n z.object({\n kind: z.enum([\"page\", \"collection\", \"folder\"]).describe(\n \"what the id IS on this branch — 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.\",\n ),\n id: z.string().min(1).describe(\"the page id, collection (content model) id, or folder id\"),\n icon: z.string().min(1).nullable().describe(\"kit icon name (bettercms://icons/dock), e.g. 'document-text'; null clears it\"),\n }).shape,\n async (c, a) => structureResult(await data(c, \"POST\", `/management/content-structure/icon`, { kind: a.kind, id: a.id, icon: a.icon }))),\n def(\"delete_folder\", \"Delete a folder (its contents move up; nothing is deleted)\",\n `Delete a folder (its contents move up; nothing is deleted). NOTHING ELSE IS DELETED: its pages, collections and sub-folders move up to the folder's parent, in the same order. ${STRUCTURE_POINTER}`,\n z.object({ folderId: z.string().min(1).describe(\"folder id (from get_content_structure)\") }).shape,\n async (c, a) => structureResult(await data(c, \"DELETE\", `/management/content-structure/folders/${encodeURIComponent(s(a.folderId))}`))),\n\n def(\"list_redirects\", \"List redirects\",\n \"List the URL redirects configured for the connected project (source path → destination, type).\",\n z.object({}).shape,\n async (c) => ok(\"Redirects.\", await data(c, \"GET\", `/management/redirects`))),\n def(\"update_redirect\", \"Update a redirect\",\n \"Update an existing redirect in place — change where it points, its HTTP status, or disable it without deleting. Prefer this over delete+create: it keeps the redirect's id and preserves the chain-collapse rewrites of other rules pointing at it. Only provided fields change. Loops 422, duplicate sources 409.\",\n z.object({ redirectId: z.string().min(1).describe(\"redirect id (from list_redirects)\"), sourcePath: z.string().min(1).optional(), destination: z.string().min(1).optional(), redirectType: z.enum([\"301\", \"302\", \"307\", \"308\", \"410\"]).optional().describe(\"HTTP status; 410 = Gone\"), isActive: z.boolean().optional().describe(\"set false to disable without deleting\") }).shape,\n async (c, a) => ok(\"Updated redirect.\", await data(c, \"PATCH\", `/management/redirects/${s(a.redirectId)}`, { sourcePath: a.sourcePath, destination: a.destination, redirectType: a.redirectType, isActive: a.isActive }))),\n def(\"create_redirect\", \"Create a redirect\",\n \"Create a URL redirect — e.g. a 301 after renaming a page's slug. `sourcePath` is the path to redirect FROM ('/old-page'), `destination` the path/url TO ('/new-page'). Chains collapse; loops/dupes rejected. Defaults to 301.\",\n z.object({ sourcePath: z.string().min(1), destination: z.string().min(1).optional(), redirectType: z.enum([\"301\", \"302\", \"307\", \"308\", \"410\"]).optional().describe(\"default '301'; 410 = Gone, omit destination\"), dryRun: z.boolean().optional().describe(\"true = return the verdict, write nothing\") }).shape,\n async (c, a) => ok(a.dryRun === true ? \"Dry run: nothing written.\" : \"Created redirect.\", await data(c, \"POST\", `/management/redirects`, { sourcePath: a.sourcePath, destination: a.destination, redirectType: a.redirectType, dryRun: a.dryRun }))),\n def(\"import_redirects\", \"Import redirects\",\n NEW_TOOL_TEXT.import_redirects,\n z.object({\n rows: z.array(z.record(z.string(), z.unknown())).optional().describe(\"[{ sourcePath, destination?, redirectType? }]\"),\n text: z.string().optional().describe(\"the file's contents, instead of rows\"),\n format: z.enum([\"csv\", \"_redirects\", \"vercel\"]).optional().describe(\"of `text` (default 'csv')\"),\n dryRun: z.boolean().optional().describe(\"default false\"),\n }).shape,\n async (c, a) => ok(a.dryRun === true ? \"Dry run: nothing written.\" : \"Imported redirects.\", await data(c, \"POST\", `/management/redirects/import`, { rows: a.rows, text: a.text, format: a.format, dryRun: a.dryRun }))),\n def(\"delete_redirect\", \"Delete a redirect\",\n \"Delete a URL redirect by id (from list_redirects). Provide redirectId.\",\n z.object({ redirectId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Deleted redirect.\", await data(c, \"DELETE\", `/management/redirects/${s(a.redirectId)}`))),\n\n def(\"save_reusable_block\", \"Save a section as a reusable block\",\n NEW_TOOL_TEXT.save_reusable_block,\n z.object({ pageId: z.string().min(1), blockId: z.string().min(1).describe(\"a top-level section id (get_page)\"), name: z.string().min(1).describe(\"80 characters at most; a longer one is refused as SAVED_BLOCK_NAME_TOO_LONG\") }).shape,\n async (c, a) => ok(\"Saved the section as a reusable block.\", await data(c, \"POST\", `/management/saved-blocks`, { pageId: a.pageId, blockId: a.blockId, name: a.name }))),\n\n def(\"get_seo\", \"Get site SEO\",\n GET_SEO_DESCRIPTION,\n z.object({}).shape,\n async (c) => ok(\"SEO settings.\", await data(c, \"GET\", `/management/seo`))),\n def(\"update_seo\", \"Update site SEO\",\n UPDATE_SEO_DESCRIPTION,\n seoPatchShape,\n async (c, a) => ok(\"Updated SEO.\", await data(c, \"PATCH\", `/management/seo`, Object.fromEntries(Object.keys(seoPatchShape).filter((k) => a[k] !== undefined).map((k) => [k, a[k]]))))),\n\n def(\"get_site_files\", \"List site files\",\n \"List the AI-crawler files installed on the connected project (llms.txt / llms-full.txt) — metadata only.\",\n z.object({}).shape,\n async (c) => ok(\"Site files.\", await data(c, \"GET\", `/management/site-files`))),\n def(\"set_site_file\", \"Set a site file\",\n \"Create or replace an AI-crawler file served at the site root — `kind` 'llms.txt' or 'llms-full.txt' — with `content` (plain text, max 5 MB). Rebuilds the site.\",\n z.object({ kind: z.enum([\"llms.txt\", \"llms-full.txt\"]), content: z.string() }).shape,\n async (c, a) => ok(\"Saved site file.\", await data(c, \"PUT\", `/management/site-files/${s(a.kind)}`, { content: a.content }))),\n def(\"delete_site_file\", \"Delete a site file\",\n \"Remove an AI-crawler file (llms.txt / llms-full.txt) from the connected project. Provide kind.\",\n z.object({ kind: z.enum([\"llms.txt\", \"llms-full.txt\"]) }).shape,\n async (c, a) => ok(\"Deleted site file.\", await data(c, \"DELETE\", `/management/site-files/${s(a.kind)}`))),\n\n // ── Editorial board ──\n // Publishing is two decisions: may the KEY publish (content:publish, granted at\n // consent) and may the ITEM publish (it must sit in the board's gate stage). These\n // tools are the second one. Without them a publish-enabled connection still dead-ends\n // on a 409 the moment a project uses review columns.\n def(\"get_workflow_board\", \"List editorial workflow stages\",\n \"List the connected project's editorial board columns in order — each stage's `key`, name, and whether it is the `publishGate` (the one stage content may go live from). Read this BEFORE move_stage: stage keys are per-project and not guessable, because a project can rename or replace every column.\",\n z.object({}).shape,\n async (c) => ok(\"Workflow stages.\", await data(c, \"GET\", `/management/workflow/stages`))),\n def(\"move_stage\", \"Move an entry or a page across the board\",\n MOVE_STAGE_DESCRIPTION,\n z.object({\n entryId: z.string().min(1).optional().describe(\"the entry to move; or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of entryId: the page to move\"),\n workflowStage: z.string().max(64).describe(\"stage key from get_workflow_board\"),\n fromStage: z.string().max(64).optional().describe(\"the stage you believe it is in — 409s if it has moved\"),\n }).shape,\n async (c, a) => {\n if (!a.entryId === !a.pageId) return fail(\"Pass exactly one of entryId (a content entry) or pageId (a page).\");\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/workflow` : `/management/content/entries/${s(a.entryId)}/workflow`;\n return ok(a.pageId ? \"Moved page.\" : \"Moved entry.\", await data(c, \"PATCH\", path, { workflowStage: a.workflowStage, fromStage: a.fromStage }));\n }),\n\n def(\"promote_project\", \"Promote staging → production\",\n \"Promote the connected project's STAGED build to PRODUCTION — the one-click publish. Flips prod to the newest staged release (no rebuild) after the QA scan passes. Managed hosting only; needs a publish-enabled connection.\",\n z.object({}).shape,\n async (c) => ok(\"Promoted to production.\", await data(c, \"POST\", `/management/projects/promote`))),\n\n def(\"list_entry_versions\", \"List a content entry's versions\",\n \"List a content entry's version history (newest first) — each version's number, data snapshot, and when it was saved. Use it to find a past state to restore.\",\n z.object({ entryId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Entry versions.\", await data(c, \"GET\", `/management/content/entries/${s(a.entryId)}/versions`))),\n def(\"restore_entry_version\", \"Restore a content entry to a past version\",\n \"Restore a content entry to a past version (undo). Copies that version's data back as the current DRAFT (non-destructive). Publish afterwards to take it live. Provide entryId and the version number (from list_entry_versions).\",\n z.object({ entryId: z.string().min(1), version: z.number().int().positive() }).shape,\n async (c, a) => ok(\"Restored entry version.\", await data(c, \"POST\", `/management/content/entries/${s(a.entryId)}/versions/${a.version}/restore`))),\n\n // ── Project / workspace (parity with remote /mcp) ──\n def(\"get_project\", \"Get the connected project\",\n \"Get the connected project's info — id, name, slug, subdomain, and its live URL (https://<handle>.bettercms.site). Use it to tell the user where their site is published / link the result. It also returns `useCdn` and `mediaBaseUrl` — the origin this project's media is minted and resized on. A deployed site's `PUBLIC_BCMS_MEDIA_URL` / `mediaUrl` must equal `mediaBaseUrl`, or resized images 404 on any rung but production. \" + BRAND_KIT_NOTE,\n z.object({}).shape,\n async (c) => ok(\"Project.\", await data(c, \"GET\", `/management/projects/current`))),\n def(\"list_projects\", \"List projects\",\n \"List the projects this key can see — id, name, slug, and live URL each. A project-scoped key sees only its own project; a workspace-level key sees every project in the workspace. Use it to find a project you created earlier, or to confirm which sites exist before acting.\",\n z.object({}).shape,\n async (c) => ok(\"Projects.\", await data(c, \"GET\", `/management/projects`))),\n {\n name: \"whoami\",\n config: { title: \"Who this connection acts as\", description: WHOAMI_DESCRIPTION, inputSchema: {} },\n /**\n * The stdio server holds a device-grant token and nothing that lists its grants, so it\n * reports only what it can observe: whether GET /projects/current resolves a project with\n * none named (a project-bound grant) or refuses with 400 (a workspace-wide one). The\n * lifted `projectId`, when sent, is checked separately — it must not decide the scope.\n */\n handler: guard(async () => {\n const requested = currentProject.getStore();\n const current = (c: ManagementApi) => data(c, \"GET\", `/management/projects/current`) as Promise<ProjectSummary>;\n const bound = await currentProject.run(undefined, () =>\n withClient(async (c) => {\n try {\n return { apiBaseUrl: c.url(\"\"), project: await current(c) };\n } catch (err) {\n if (err instanceof BetterCMSError && err.status === 400) return { apiBaseUrl: c.url(\"\"), project: null };\n throw err;\n }\n }),\n );\n const target = requested ? await withClient(current) : null;\n const pick = (p: ProjectSummary | null) => (p ? { id: p.id, name: p.name, slug: p.slug } : null);\n const scope = bound.project ? \"project\" : \"workspace\";\n return ok(\n bound.project\n ? `Bound to project '${bound.project.slug}' through a device grant.`\n : \"A workspace-wide device grant: pass projectId on every project tool.\",\n {\n surface: \"stdio\",\n principal: { kind: \"device_grant\" },\n apiBaseUrl: bound.apiBaseUrl,\n scope,\n workspaceSlug: (bound.project ?? target)?.workspaceSlug ?? null,\n project: pick(bound.project),\n ...(requested ? { requestedProject: pick(target) } : {}),\n grants: null,\n note: \"This server cannot see the connection's grants; a missing one is a 403 naming it on the call that needs it. The hosted connector's whoami lists them.\",\n },\n );\n }) as ToolDef[\"handler\"],\n },\n def(\"update_project\", \"Update the connected project\",\n \"Update the connected project's settings — rename it, change its slug/description, SEO defaults, visibility, or `presentation`. Only the provided fields change. `subdomainAlias` renames the staging URL: 'astronapp' serves the site at astronapp.bettercms.site (3–55 lowercase letters, numbers, hyphens; 409 when taken; null goes back to the original). The original <handle>.bettercms.site keeps working; a replaced name is released. `presentation` themes the platform's OWN renderer (the one serving a site built in the CMS with no deployed build, and previewing structural drafts everywhere) with the same closed knobs as bcms-presentation.json — DTCG { $type, $value } tokens keyed like 'page.maxWidth', 'nav.background'. Without it that renderer is a generic 768px document theme. An invalid manifest is 422 PRESENTATION_INVALID.\",\n z.object({ name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), visibility: z.string().optional(), seoDefaults: z.record(z.string(), z.unknown()).optional(), presentation: z.record(z.string(), z.unknown()).optional().describe(\"theme knobs for the platform renderer, keyed like bcms-presentation.json\"), subdomainAlias: z.string().nullable().optional().describe(\"the staging name: 'astronapp' → astronapp.bettercms.site; null = back to the original\") }).shape,\n async (c, a) => ok(\"Updated project.\", await data(c, \"PATCH\", `/management/projects/current`, a))),\n def(\"create_project\", \"Create a new project\",\n \"Create a NEW project (site) in the connected workspace. ASK THE USER WHICH TECHNOLOGY TO BUILD WITH FIRST and pass it as `framework` — 'astro' (recommended default), 'next', 'react-ts' (React + TypeScript), or 'other' for a headless project with no generated frontend. Do not pick for them: called without it, this tool asks them directly (or hands you the question to ask). Sites cannot be created as plain HTML/CSS — every project is backed by one of these starters, which is what makes its content editable in the CMS. Optionally pass templateId to seed curated content. Returns the new project's id and slug. (Use clone_project instead to duplicate an existing project.)\",\n // `framework` is OPTIONAL in the schema on purpose, even though it is required in\n // effect: a required arg is rejected by the SDK before the handler runs, which would\n // kill the elicitation below and leave the model guessing on its own. Optional here,\n // answered by a human there. The backend rejects a create with no framework regardless.\n z.object({ name: z.string().min(1), slug: z.string().optional(), description: z.string().optional(), templateId: z.string().optional(), framework: z.enum(FRAMEWORK_CHOICES).optional().describe(\"REQUIRED in effect — the technology the USER chose. Ask them; never default it.\") }).shape,\n async (c, a) => {\n let framework = a.framework;\n if (framework === undefined) {\n const asked = await askFramework(deps);\n if (\"prompt\" in asked) return fail(asked.prompt);\n framework = asked.value;\n }\n return ok(\"Created project.\", await data(c, \"POST\", `/management/projects`, { ...a, framework }));\n }),\n def(\"set_authoring_preference\", \"Set the site's authoring architecture\",\n \"Record which authoring architecture this site uses — 'components' (RECOMMENDED: reusable section components placed as blocks; editors add, reorder and swap sections without touching a schema — recommend it for every marketing, landing, agency or product site) or 'fields' (a typed field schema per page — only for a blog, catalogue or directory where many rows share one shape). ASK THE USER; do not pick for them. Called without `preference`, this tool asks them directly (or hands you the question to ask). deploy_project and promote_project both refuse with 409 AUTHORING_DECISION_REQUIRED until it is set, carrying this project's real page counts to show the user. Unset, editor_setup componentizes nothing; only `components` lets it place sections. On a site whose pages were DERIVED at import, answering 'components' redoes nothing: after set_authoring_preference, get_componentize_plan proposes one component per section (it reads the PUBLISHED pages — no deploy needed to reach it), you confirm it with the user, then componentize_sections places them with `props.bind` (dry run first — they land as drafts and the page keeps its fields, values and bindings, so click-to-edit and the coverage meter are unchanged), then publish_component each one, publish the pages, run `npx @bettercms-ai/convert --componentize` in the repo, and deploy. Asked once per project; re-callable if the user changes their mind.\",\n // Optional in the schema for exactly the reason `framework` is above: a required arg is\n // rejected by the SDK before the handler runs, which would kill the elicitation below\n // and leave the model guessing. Optional here, answered by a human there. The backend\n // gate refuses the deploy regardless, so nothing ships on a guess.\n z.object({ preference: z.enum(AUTHORING_CHOICES).optional().describe(\"REQUIRED in effect — the architecture the USER chose. Ask them; never default it.\") }).shape,\n async (c, a) => {\n let preference = a.preference;\n if (preference === undefined) {\n const asked = await askAuthoring(deps);\n if (\"prompt\" in asked) return fail(asked.prompt);\n preference = asked.value;\n }\n return ok(\"Recorded the authoring architecture.\", await data(c, \"PATCH\", `/management/projects/current/authoring-preference`, { preference }));\n }),\n def(\"set_binding_mode\", \"Set how the site's bindings are resolved\",\n \"Switch this project between the two binding resolvers, from the NEXT release on. `declaredBindings: true` makes the annotator trust the template's own data-bcms-field / data-bcms-props and never guess from rendered text — the durable state; `false` returns to text-matching, which holds only while the CMS values equal the built copy. Call it ONLY after every page's copy is declared in the template: undeclared fields stop being editable. The order around the flip (push, release, clean get_binding_report, flip, release, confirm): skill bindings. Flipping back is the same call. REQUIRES artifact:write (the authority that deploys the site): this decides what every future release does to every page. On a workspace-wide connection pass `projectId`: the scope is there, but the human who authorized the connection must be able to publish THAT project or it is refused with 403 PROJECT_PUBLISH_DENIED. Playbook section 13.\",\n z.object({ declaredBindings: z.boolean().describe(\"true = trust the template's declared bindings; false = text-match (the default)\") }).shape,\n async (c, a) => ok(\"Recorded the binding mode.\", await data(c, \"PATCH\", `/management/projects/current/binding-mode`, { declaredBindings: a.declaredBindings }))),\n def(\"set_media_delivery\", \"Choose where this site's media is served from\",\n \"Record whether this project's media (images, video, files) is served from the BetterCMS CDN or from the API origin. `useCdn: true` is the DEFAULT and the recommendation: URLs are minted on the CDN host, or on the project's own CDN base when it stores media in its own bucket (BYOK). `useCdn: false` mints them on the API origin instead — the same service serving the same bytes, only under a different hostname. ASK THE USER; do not pick for them. Called without `useCdn`, this tool asks them directly (or hands you the question to ask). 🔴 IT APPLIES TO URLs MINTED FROM NOW ON — new uploads, entry saves, get_media. It does NOT rewrite URLs already stored in published content, and it does not need to: the old URLs keep resolving. To move an existing image, re-save the field that holds it. 🔴 IT IS THE BACKEND HALF ONLY. A deployed frontend builds its own transform URLs with @bettercms-ai/image-url, which has its own media host — set `PUBLIC_BCMS_MEDIA_URL` (or the integration's `mediaUrl` option) to match, or that site's resized images stay on the CDN while everything else moves. Read the current answer from get_project: `useCdn` is the choice, `mediaBaseUrl` is the origin it produces — the value the frontend's `PUBLIC_BCMS_MEDIA_URL` must match. Re-callable; the last answer wins.\",\n // Optional in the schema for the same reason `framework` and `preference` are: a\n // required arg is rejected by the SDK before the handler runs, which would kill the\n // elicitation below and leave the model guessing.\n z.object({ useCdn: z.boolean().optional().describe(\"REQUIRED in effect — the USER's answer. true = CDN (the default), false = API origin. Ask them; never default it.\") }).shape,\n async (c, a) => {\n let useCdn = a.useCdn;\n if (useCdn === undefined) {\n const asked = await askMediaDelivery(deps);\n if (\"prompt\" in asked) return fail(asked.prompt);\n useCdn = asked.value;\n }\n return ok(\"Recorded the media delivery origin.\", await data(c, \"PATCH\", `/management/projects/current/media-delivery`, { useCdn }));\n }),\n def(\"submit_conversion_receipt\", \"Record what the conversion codemod could and could not do\",\n \"Hand BetterCMS the codemod's own account of a run, so the meter can say WHY a path is undeclared. Submit the receipt `npx @bettercms-ai/convert --receipt out.json` wrote as `{ briefDigest, receipt }`, for the SAME `briefDigest` get_conversion_brief { complete: true } returned (its shape: see `receipt`). 🔴 A RECEIPT WITH PENDING PATHS IS A PROGRESS REPORT, NOT A FINISH LINE: the response answers `complete` and `pendingTotal`, and echoes the first 40 pending rows with their `fix` (`action` one of `wrap-span`, `declare-attr`, `bind-expression`, `declare-richtext`, `bind-data`, `manual`; the row shape: skill bindings; a 404 `unknown-brief` means that digest was never issued here). Apply every fix, rerun, resubmit: only `complete: true` ends a conversion — never report a site converted on less. It is a RECORD, not a release: nothing on the site changes; the meter reads it on the get_binding_report after the next deploy. 🔴 The same run owes two more things (playbook §13 steps 2b and 3b): the `--forms` receipt (a SECOND call, same `briefDigest`) and the `styleEdits` of `convert --verify-styles` inside this receipt; any changed class or style is refused with 409 `style-edits`. Requires artifact:write.\",\n z.object({\n briefDigest: z.string().min(1).describe(\"The `briefDigest` get_conversion_brief { complete: true } returned. Must match the receipt's own.\"),\n receipt: z.record(z.string(), z.unknown()).describe(\"The receipt `npx @bettercms-ai/convert --receipt out.json` wrote, verbatim: `paths: { declared, rewritten, alreadyDeclared, pending[{ route, scope, path, kind, file, reason, message, fix }] }` plus `styleEdits`. `paths.declared` must equal rewritten + alreadyDeclared + pending.length; each pending `reason` is the converter's own (IN_EXPRESSION, AMBIGUOUS_LITERAL, REPEATER_FIXED_LENGTH, PARSE_ERROR, …); a path with no row reads `not-declared`.\"),\n }).shape,\n async (c, a) => ok(\"Recorded the conversion receipt.\", await data(c, \"POST\", `/management/projects/current/conversion-receipt`, { briefDigest: a.briefDigest, receipt: a.receipt }))),\n def(\"clone_project\", \"Clone a project\",\n \"Clone (duplicate) a project as a reusable template into the connected workspace. Copies pages, content models + entries, components, media, forms, and SEO/custom-code settings; excludes submissions, analytics, domains, and secrets. Returns the new project's id and slug. Omit sourceProjectId to clone the connected project.\",\n z.object({ sourceProjectId: z.string().optional(), name: z.string().optional(), slug: z.string().optional() }).shape,\n async (c, a) => ok(\"Cloned project.\", await data(c, \"POST\", `/management/projects/clone`, a))),\n\n // ── Content models (read/metadata; parity with remote /mcp) ──\n def(\"list_content_models\", \"List content models\",\n \"List the content models (reusable schemas for dynamic collections like Blog/Products) in the connected project. A project-scoped connection sees its own project's models plus workspace-level ones, which it can read but not change.\",\n z.object({}).shape,\n async (c) => ok(\"Content models.\", await data(c, \"GET\", `/management/content/models`))),\n def(\"get_content_model\", \"Get a content model\",\n \"Get one content model by id INCLUDING its full field schema (keys, types, nested group/repeater children) AND each field's stored authoring props — `helpText`, `showIf`, `ui`. Read it before add_field so you know the existing keys, and AFTER declaring `ui`/`showIf`/`helpText` as the receipt that the declaration actually landed: a prop that is missing from this response was not stored, whatever the write returned. Its `optimisticVersion` is the ifMatch for update_content_model.\",\n z.object({ modelId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Content model.\", await data(c, \"GET\", `/management/content/models/${s(a.modelId)}`))),\n def(\"update_content_model\", \"Update a content model's metadata\",\n UPDATE_MODEL_DESCRIPTION,\n z.object({\n modelId: z.string().min(1).optional().describe(\"content model id (from list_content_models); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of modelId: the page whose schema model to edit; ifMatch is get_page backingModel.optimisticVersion\"),\n name: z.string().optional(),\n slug: z.string().optional(),\n description: z.string().optional(),\n urlPattern: urlPatternArg,\n fieldsets: fieldsetsArg.nullable(),\n fieldUi: z.record(z.string(), z.record(z.string(), z.unknown()).nullable()).optional().describe(FIELD_UI_ARG_NOTE),\n fieldFieldset: z.record(z.string(), z.string().min(1).nullable()).optional().describe(\"path → fieldset id, null takes it out\"),\n fieldOrder: z.strictObject({ parentPath: z.string().min(1).optional(), order: z.array(z.string().min(1)).min(1).max(200) }).optional().describe(\"the full new order of one parent's child keys (top level without parentPath). An array with both zones needs 'KEY.zones.nonRepeatable' or 'KEY.zones.repeatable'; its bare key is a 400\"),\n fieldLabel: z.record(z.string(), z.string().min(1).max(255)).optional().describe(\"path → label\"),\n fieldHelpText: z.record(z.string(), z.string().max(500).nullable()).optional().describe(\"path → help text, null clears it\"),\n override: z.boolean().optional().describe(OVERRIDE_NOTE),\n ifMatch: z.number().int().min(0).optional().describe(MODEL_IF_MATCH_NOTE),\n removeFields: z.array(z.string().min(1)).min(1).max(100).optional().describe(FIELD_REMOVAL_NOTE),\n allowFieldRemoval: z.boolean().optional().describe(ALLOW_FIELD_REMOVAL_NOTE),\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n }).shape,\n // `fields` is sent only by removeFields, rebuilt from the model just read: the PATCH\n // replaces `fields` wholesale when present.\n async (c, a) => {\n if (Boolean(a.modelId) === Boolean(a.pageId)) return fail(\"Send exactly one of modelId or pageId.\");\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/model` : `/management/content/models/${s(a.modelId)}`;\n const body: Record<string, unknown> = Object.fromEntries(\n MODEL_UPDATE_KEYS.filter((k) => a[k] !== undefined).map((k) => [k, k === \"fieldsets\" ? dropProvenance(a[k] as never) : a[k]]),\n );\n let ifMatch = a.ifMatch;\n const removal = fieldRemovalRequest(a);\n if (removal.kind === \"refuse\") return fail(removal.error);\n if (removal.kind === \"remove\") {\n const plan = planFieldRemoval((await data(c, \"GET\", path)) as StoredModel, removal.keys, a.ifMatch as number | undefined);\n if (!plan.ok) return fail(plan.error);\n body.fields = plan.fields;\n body.allowFieldRemoval = true;\n ifMatch = plan.ifMatch;\n }\n return ok(\n \"Updated content model.\",\n (\n await c.fetchJSON<{ data?: unknown }>(c.url(path), {\n method: \"PATCH\",\n body: JSON.stringify(body),\n ...withHeaders({ ...(ifMatch !== undefined ? { \"if-match\": `W/\"${ifMatch}\"` } : {}), ...confirmedHeaders(a.confirmed) }),\n })\n ).data,\n );\n }),\n def(\"get_content_types\", \"Get generated TypeScript types\",\n \"Get the auto-generated TypeScript types for the connected project's content models/pages. Pull these to write correctly-typed code against the BetterCMS delivery SDK in the user's site.\",\n z.object({}).shape,\n async (c) => ok(\"Content types.\", await data(c, \"GET\", `/management/content/types`))),\n\n // ── Pages (metadata edit; parity with remote /mcp) ──\n def(\"remove_page_fields\", \"Remove fields from a page\",\n \"Delete page fields and their stored values (draft, published, every repeater row) in one transaction. Dry run by default: returns removedKeys, entriesWithContent, keysWithContent, liveCopyChanges and writes nothing. A field holding content needs discardContent:true (409 FIELDS_HOLD_CONTENT otherwise). keys: exact get_page keys, dotted for a group/repeater child (`features.icon`). Changing the live copy needs publish permission. Never use it to rename a field.\",\n z.object({\n pageId: z.string().min(1).describe(\"page id (from list_pages)\"),\n keys: z.array(z.string().min(1)).min(1).describe(\"field keys to remove\"),\n dryRun: z.boolean().optional().describe(\"default true\"),\n discardContent: z.boolean().optional().describe(\"delete fields that hold content, and the content\"),\n }).shape,\n // The whole body: a dry run answers with the report and no `data`.\n async (c, a) => {\n const res = await c.fetchJSON<Record<string, unknown>>(c.url(`/management/pages/${s(a.pageId)}/fields/remove`), {\n method: \"POST\",\n body: JSON.stringify({ keys: a.keys, dryRun: a.dryRun, discardContent: a.discardContent }),\n });\n return ok(res.dryRun ? \"Dry run — nothing removed.\" : \"Removed fields.\", res);\n }),\n def(\"update_page\", \"Edit a page\",\n \"Edit a page: title, slug, SEO metaTitle/metaDescription, structured data (`schemaType`, `schema`), publish status (draft|published), and `blockJson` (its block composition — passing an array REPLACES the whole array, so read get_page first and send its `optimisticVersion` as `ifMatch`; an object adds or styles ONE section). An answer that starts with `held` is a draft the live page will NOT show until each of `holds` has its `action` taken, and a publish answers with `outcome`: `partial` lists the values not live. Never report either as done (skill publishing). `warnings`: COMPONENT_SWAP_DROPS_OVERRIDES (skill components), ENTRY_STILL_DRAFT and COMPONENT_DRAFT (skill publishing). It does NOT change the field SCHEMA — use add_field (pageId) / set_page_content for that. Renaming the slug keeps content intact. Publishing copies the draft blocks live in the same call, and a singleton's content entry with them. STRUCTURED DATA is native SEO, never a field: Automatic JSON-LD from the content, unless `schemaType` picks a schema.org type or pasted `schema` (wins over both, null clears it) is set (skill seo). \" + PAGE_HEAD_NOTE + \" \" +\n DOCTRINE,\n z.object({ ...headPatchShape, noindex: z.boolean().optional().describe(\"hide this page from search engines and site search\"), pageId: z.string().min(1).describe(PARAM_TEXT.pageRef), title: z.string().optional(), slug: z.string().optional(), blockJson: z.union([z.array(blockObject), z.object({ insertSection: z.object({ componentId: z.string().min(1), at: z.number().int().min(0).optional(), before: z.string().optional(), after: z.string().optional(), style: z.record(z.string(), z.unknown()).optional(), overrides: z.record(z.string(), z.unknown()).optional() }).strict().optional(), sectionStyle: z.object({ blockId: z.string().min(1), style: z.record(z.string(), z.unknown()) }).strict().optional() }).strict()]).optional().describe(PARAM_TEXT.pageBlockJson), metaTitle: z.string().optional(), metaDescription: z.string().optional(), schemaType: z.enum([\"auto\", ...SCHEMA_ORG_TYPES]).optional().describe(\"structured data type; 'auto' (the default) derives it from the content\"), schema: z.union([z.record(z.string(), z.unknown()), z.array(z.record(z.string(), z.unknown()))]).nullable().optional().describe(\"custom JSON-LD; wins over schemaType; null clears it\"), status: z.enum([\"draft\", \"published\"]).optional(), scheduledAt: z.string().datetime().nullable().optional().describe(PARAM_TEXT.pageScheduledAt), unpublishAt: z.string().datetime().nullable().optional().describe(PARAM_TEXT.pageUnpublishAt), locale: z.string().nullable().optional().describe(PARAM_TEXT.locale), translationOf: z.string().nullable().optional().describe(PARAM_TEXT.translationOf), ifMatch: z.number().int().min(0).optional().describe(UPDATE_PAGE_IF_MATCH_NOTE), dynamic: z.object({ previewPath: z.string().nullable().optional().describe(PARAM_TEXT.previewPath), modelId: z.string().min(1).optional().describe(PARAM_TEXT.pageModelId) }).optional().describe(PARAM_TEXT.pageDynamic) }).shape,\n async (c, a) => {\n // Read the WHOLE body, not just `data`: a rename can come back with `redirectNote` when\n // an existing redirect on the old address was kept pointing elsewhere (CPO-120, QA D-06).\n // The agent is told in the summary line; the page JSON is unchanged.\n // A built-in is a locked blueprint: the page places the project's copy of it.\n // `blockJson` as an OBJECT is one section edit: the tool is at the 20 top-level properties a\n // client keeps, so the two edits ride the argument they stand in for. The page route takes\n // each under its own name.\n const edit = Array.isArray(a.blockJson) ? undefined : (a.blockJson as SectionEdit | undefined);\n const insert = edit?.insertSection;\n const insertSection = insert?.componentId.startsWith(\"builtin:\") ? { ...insert, componentId: await builtinCopyId(c, insert.componentId) } : insert;\n const res = await c.fetchJSON<{ data?: unknown; redirectNote?: { source: string; existingDestination: string }; warnings?: string[]; held?: string; holds?: unknown[]; outcome?: PublishOutcome; section?: { id: string; index: number } }>(\n c.url(`/management/pages/${s(a.pageId)}/meta`),\n {\n method: \"PATCH\",\n ...(a.ifMatch !== undefined ? { headers: { \"If-Match\": `W/\"${a.ifMatch}\"` } } : {}),\n body: JSON.stringify({ title: a.title, slug: a.slug, blockJson: Array.isArray(a.blockJson) ? a.blockJson : undefined, insertSection, sectionStyle: edit?.sectionStyle, metaTitle: a.metaTitle, metaDescription: a.metaDescription, schemaType: a.schemaType, schema: a.schema, status: a.status, noindex: a.noindex, canonical: a.canonical, og: a.og, twitter: a.twitter, scheduledAt: a.scheduledAt, unpublishAt: a.unpublishAt, locale: a.locale, translationOf: a.translationOf, ...(a.dynamic as { previewPath?: string | null; modelId?: string } | undefined) }),\n },\n );\n const note = res.redirectNote;\n // A hold is never \"done\": the draft is saved, and the live page will not show the section\n // change until the action is taken. So it LEADS, and \"Updated page.\" is never said over it.\n const edited = res.section\n ? insertSection ? `Added section ${res.section.id} at position ${res.section.index + 1} of the draft.` : `Set the style of section ${res.section.id} in the draft.`\n : null;\n const saved = res.held ? `${edited ? `${edited} ` : \"\"}The draft is saved; the live page is unchanged.` : edited ?? \"Updated page.\";\n const summary = note\n ? `${saved} An existing redirect from ${note.source} already points to ${note.existingDestination}; it wasn't changed, so the old address does not redirect to the new one.`\n : saved;\n const lines = [...(res.held ? [res.held] : []), ...publishedLines(res.outcome, summary), ...(res.warnings ?? [])].join(\"\\n\");\n const extra = { ...(res.holds?.length ? { holds: res.holds } : {}), ...(res.outcome ? { outcome: res.outcome } : {}), ...(res.section ? { section: res.section } : {}) };\n return ok(lines, Object.keys(extra).length ? { ...(res.data as Record<string, unknown>), ...extra } : res.data);\n }),\n\n // ── Code + deploy (parity with remote /mcp; needs artifact:write) ──\n // Both grant shapes carry that scope now; a workspace-wide one names its target per\n // call via `projectId` and is re-checked against it. @see management/projects.ts\n def(\"pull_project_source\", \"Pull the project's live source\",\n \"Get the connected project's CURRENT live source/build so you can edit it locally. Returns a presigned tarball download url (1h) + the live commit sha — download it, extract, edit the files, then call deploy_project. If the project is connected to a GitHub repo, `github` carries owner, repo, branch and cloneUrl — clone it and work on THAT branch, because it is the one the provisioned Action builds from; a commit on any other branch never reaches the live site. On a workspace-wide connection pass `projectId` (from list_projects) to say which site's source to pull.\",\n z.object({}).shape,\n async (c) => ok(\"Project source.\", await data(c, \"GET\", `/management/projects/source`))),\n def(\"deploy_project\", \"Deploy new source/build\",\n \"Deploy new source/build for the connected project and make it live at its <handle>.bettercms.site. Pass a .tgz or .zip of the project as a base64 string in `data`, or the `uploadKey` of an archive you PUT through create_deploy_upload (no size ceiling: use it for anything large, or after a 413/502). SOURCE (has package.json) is built server-side in an isolated sandbox; a prebuilt static site is served as-is. Returns the release id + sha — then poll get_deploy_status until it is live. IMPORTANT — you MUST exclude node_modules, .git and build output/caches (dist, build, .next, .astro, .cache) from the archive: the source is reinstalled and built server-side, and the ~100 MB upload ceiling is enforced in transit (a 413/502 with no server-side detail) — server-side stripping runs AFTER the upload and cannot rescue an over-limit body. Returns `canvas.lane` (skill bindings) and `editorUrl`, the visual editor to hand the user. On a workspace-wide connection pass `projectId` (from list_projects) to say which site this ships to.\",\n z.object({\n data: z.string().min(1).optional().describe(\"base64 .tgz/.zip of the project; or send uploadKey\"),\n uploadKey: z.string().min(1).optional().describe(\"instead of data: the uploadKey from create_deploy_upload, after PUTting the archive to its uploadUrl\"),\n mimeType: z.string().optional(),\n }).shape,\n async (c, a) => {\n if (!a.data === !a.uploadKey) return fail(\"Pass exactly one of data (the archive, base64) or uploadKey (from create_deploy_upload).\");\n return ok(\"Deploy queued.\", a.uploadKey\n ? await data(c, \"POST\", `/management/projects/deploy/from-upload`, { uploadKey: a.uploadKey })\n : await raw(c, `/management/projects/deploy`, s(a.data), a.mimeType as string | undefined));\n }),\n def(\"create_deploy_upload\", \"Get a presigned deploy-upload URL\",\n \"Get a presigned URL to upload a LARGE deploy archive directly to storage, bypassing the ~100 MB body limit deploy_project's inline `data` hits. Flow: (1) call this for `uploadUrl` + `uploadKey`; (2) PUT your .tgz/.zip to `uploadUrl` (e.g. `curl -X PUT --data-binary @archive.tgz \\\"<uploadUrl>\\\"`) — straight to storage, no size ceiling; (3) call deploy_project with `uploadKey`. Still exclude node_modules/.git/build caches. URL expires in 10 minutes.\",\n z.object({}).shape,\n async (c) => ok(\"Upload URL.\", await data(c, \"POST\", `/management/projects/deploy/upload-url`))),\n\n // ── Git (import a repository, read it, push commits back) ──\n // Same artifact:write authority as the deploy tools: on the build branch a push IS a\n // deploy. Every call runs server-side as the GitHub App installation, so the agent\n // needs no git remote, no clone and no token. @see management/git.ts\n def(\"list_github_repos\", \"List importable GitHub repositories\",\n GIT_TEXT.list_github_repos,\n z.object({}).shape,\n async (c) => ok(\"GitHub repositories.\", await data(c, \"GET\", `/management/git/repos`))),\n def(\"import_github_repo\", \"Import a GitHub repository\",\n GIT_TEXT.import_github_repo,\n z.object({\n installationId: z.number().int().positive().describe(\"from list_github_repos\"),\n owner: z.string().min(1).describe(\"the repository's account, e.g. 'acme'\"),\n repo: z.string().min(1).describe(\"the repository name, e.g. 'website'\"),\n branch: z.string().min(1).optional().describe(\"branch to build from; defaults to the repository's own default branch\"),\n }).shape,\n async (c, a) => ok(\"Repository imported.\", await data(c, \"POST\", `/management/git/connect`, { installationId: a.installationId, owner: a.owner, repo: a.repo, branch: a.branch }))),\n def(\"fork_github_repo\", \"Fork a repository and import it\",\n GIT_TEXT.fork_github_repo,\n z.object({\n installationId: z.number().int().positive().describe(\"the DESTINATION account's installation, from list_github_repos\"),\n owner: z.string().min(1).describe(\"the SOURCE repository's account, anywhere on GitHub\"),\n repo: z.string().min(1).describe(\"the SOURCE repository name\"),\n name: z.string().min(1).optional().describe(\"name for the fork; defaults to the source repository's name\"),\n connect: z.boolean().optional().describe(\"connect the fork to this project (the default); false forks only\"),\n }).shape,\n async (c, a) => ok(\"Repository forked.\", await data(c, \"POST\", `/management/git/fork`, { installationId: a.installationId, owner: a.owner, repo: a.repo, name: a.name, connect: a.connect }))),\n def(\"list_github_branches\", \"List the repository's branches\",\n GIT_TEXT.list_github_branches,\n z.object({}).shape,\n async (c) => ok(\"Branches.\", await data(c, \"GET\", `/management/git/branches`))),\n def(\"list_github_commits\", \"List the repository's commits\",\n GIT_TEXT.list_github_commits,\n z.object({\n branch: z.string().min(1).optional().describe(\"defaults to the build branch\"),\n path: z.string().min(1).optional().describe(\"only commits touching this file or directory\"),\n limit: z.number().int().min(1).max(100).optional(),\n }).shape,\n async (c, a) => ok(\"Commits.\", await data(c, \"GET\", `/management/git/commits${q({ branch: a.branch, path: a.path, limit: a.limit })}`))),\n def(\"push_to_github\", \"Push a commit to the repository\",\n GIT_TEXT.push_to_github,\n z.object({\n message: z.string().min(1).describe(\"the commit message\"),\n files: z.array(z.object({\n path: z.string().min(1).describe(\"repository-relative path, e.g. 'src/pages/index.astro'\"),\n content: z.string().describe(\"the file's contents\"),\n encoding: z.enum([\"utf8\", \"base64\"]).optional().describe(\"'base64' for binary files; defaults to utf8\"),\n })).optional().describe(\"files to write or overwrite\"),\n deletePaths: z.array(z.string().min(1)).optional().describe(\"paths to remove in the same commit\"),\n branch: z.string().min(1).optional().describe(\"defaults to the build branch; a branch that does not exist is created\"),\n baseBranch: z.string().min(1).optional().describe(\"what a newly created `branch` starts from; defaults to the build branch\"),\n expectedHeadSha: z.string().min(7).optional().describe(\"the head you built this change on; the push is refused if the branch moved since\"),\n }).shape,\n async (c, a) => ok(\"Pushed.\", await data(c, \"POST\", `/management/git/commit`, { message: a.message, files: a.files, deletePaths: a.deletePaths, branch: a.branch, baseBranch: a.baseBranch, expectedHeadSha: a.expectedHeadSha }))),\n def(\"create_github_pull_request\", \"Open a pull request\",\n GIT_TEXT.create_github_pull_request,\n z.object({\n head: z.string().min(1).describe(\"the branch you pushed\"),\n base: z.string().min(1).optional().describe(\"defaults to the build branch\"),\n title: z.string().min(1),\n body: z.string().optional(),\n draft: z.boolean().optional(),\n }).shape,\n async (c, a) => ok(\"Pull request opened.\", await data(c, \"POST\", `/management/git/pulls`, { head: a.head, base: a.base, title: a.title, body: a.body, draft: a.draft }))),\n def(\"list_github_pull_requests\", \"List pull requests\",\n GIT_TEXT.list_github_pull_requests,\n z.object({\n state: z.enum([\"open\", \"closed\", \"all\"]).optional(),\n limit: z.number().int().min(1).max(100).optional(),\n }).shape,\n async (c, a) => ok(\"Pull requests.\", await data(c, \"GET\", `/management/git/pulls${q({ state: a.state, limit: a.limit })}`))),\n // ── Insight: what happened, what's working, what's broken ─────────────────\n def(\"update_field\", \"Change one field of a model or a page\",\n UPDATE_FIELD_DESCRIPTION,\n z.object({\n modelId: z.string().min(1).optional().describe(\"the content model (from list_content_models); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of modelId: the page whose schema to edit\"),\n path: z.string().min(1).describe(\"the field's key, or dot-separated keys through its parents, e.g. 'hero.title'\"),\n label: z.string().min(1).optional(),\n helpText: z.string().nullable().optional().describe(\"null clears it\"),\n required: z.boolean().optional(),\n config: z.record(z.string(), z.unknown()).optional().describe(\"per-type validation/config keys, merged into the stored config; null deletes a key\"),\n showIf: z.record(z.string(), z.unknown()).nullable().optional().describe(\"same shape as on add_field; null clears it\"),\n 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\"),\n placement: z.enum([\"cover\", \"title\", \"excerpt\", \"body\", \"inline\", \"panel\"]).nullable().optional(),\n readOnly: z.union([z.literal(true), z.literal(\"developer\")]).nullable().optional().describe(PARAM_TEXT.lockClears),\n lockReason: z.string().max(200).nullable().optional().describe(PARAM_TEXT.lockClears),\n helpMore: z.string().max(2000).nullable().optional().describe(PARAM_TEXT.helpMore),\n advanced: z.boolean().nullable().optional().describe(PARAM_TEXT.advanced),\n recommendedMax: z.number().int().positive().nullable().optional().describe(PARAM_TEXT.recommendedMax),\n openMode: z.enum([\"inline\", \"drill\", \"popover\", \"dialog\"], { error: OPEN_MODE_INVALID }).nullable().optional().describe(PARAM_TEXT.openMode),\n localized: z.boolean().nullable().optional(),\n type: fieldType.optional().describe(\"a new type; needs allowRetype\"),\n key: fieldKey.optional().describe(\"a new key (flat namespace, unique in the schema)\"),\n allowRetype: z.boolean().optional().describe(\"confirm a type change, once the user has agreed\"),\n allowFieldRemoval: z.boolean().optional().describe(\"with a rename: discard the old key's stored values\"),\n mergeHref: z.string().min(1).optional().describe(PARAM_TEXT.mergeHref),\n ifMatch: z.number().int().min(0).optional().describe(\"the model's optimisticVersion; the version read when omitted\"),\n confirmed: z.boolean().optional().describe(PARAM_TEXT.confirmedInput),\n }).shape,\n // Read the model (a page's through its backingModel), patch ONE field with the helper the\n // hosted catalogue uses, and PATCH the whole list at the version read. `mergeHref` is the\n // page route's \"Make it a full button\" instead, at the PAGE's version.\n async (c, a) => {\n if (a.mergeHref !== undefined) {\n if (!a.pageId) return fail(\"mergeHref merges two fields of a PAGE: pass pageId.\");\n const ifMatch = (a.ifMatch as number | undefined)\n ?? ((await data(c, \"GET\", `/management/pages/${s(a.pageId)}`)) as { optimisticVersion?: number } | undefined)?.optimisticVersion\n ?? 0;\n const merged = (await c.fetchJSON<{ data?: unknown; key?: string; entries?: number }>(c.url(`/management/pages/${s(a.pageId)}/fields/merge-button`), {\n method: \"POST\",\n body: JSON.stringify({ labelKey: a.path, hrefKey: a.mergeHref, ...(a.key !== undefined ? { key: a.key } : {}), ifMatch }),\n }));\n return ok(`Made '${s(a.path)}' + '${s(a.mergeHref)}' one button field '${merged.key ?? \"\"}' (${merged.entries ?? 0} draft entries).`, merged);\n }\n let modelId = a.modelId as string | undefined;\n if (a.pageId) {\n const page = (await data(c, \"GET\", `/management/pages/${s(a.pageId)}`)) as { backingModel?: { id?: string } | null } | undefined;\n modelId = page?.backingModel?.id;\n if (!modelId) return fail(\"This page has no backing content model; address its schema by modelId.\");\n }\n if (!modelId) return fail(\"Pass modelId (a content model) or pageId (a page).\");\n const plan = planFieldEdit((await data(c, \"GET\", `/management/content/models/${s(modelId)}`)) as StoredModel, a, a.ifMatch as number | undefined);\n if (!plan.ok) return fail(plan.error);\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/model` : `/management/content/models/${s(modelId)}`;\n const updated = (await c.fetchJSON<{ data?: unknown }>(c.url(path), {\n method: \"PATCH\",\n body: JSON.stringify({ fields: plan.fields, ...(a.allowFieldRemoval === true ? { allowFieldRemoval: true } : {}) }),\n ...withHeaders({ ...(plan.ifMatch !== undefined ? { \"If-Match\": `W/\"${plan.ifMatch}\"` } : {}), ...confirmedHeaders(a.confirmed) }),\n })).data;\n return ok(plan.renamed ? `Renamed '${plan.renamed.from}' to '${plan.renamed.to}'.` : `Updated field '${s(a.path)}'.`, updated);\n }),\n\n // ── Search, batch, localisation, automation, branches and AI images (2026-09-30) ──\n // Descriptions from ./tool-text.ts, shared word for word with the hosted catalogue.\n def(\"search_content\", \"Search published content\",\n NEW_TOOL_TEXT.search_content,\n z.object({\n q: z.string().min(1).max(200).describe(\"the words to find, 1-200 chars\"),\n type: z.enum([\"page\", \"entry\"]).optional().describe(\"only pages, or only entries\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"hits to return; 10 when omitted\"),\n }).shape,\n async (c, a) => ok(\"Search results.\", await c.fetchJSON(c.url(`/management/search${q({ q: a.q, type: a.type, limit: a.limit })}`), { method: \"GET\" }))),\n def(\"discard_draft\", \"Discard unpublished edits\",\n NEW_TOOL_TEXT.discard_draft,\n z.object({\n entryId: z.string().min(1).optional().describe(\"the entry (from list_content_entries); or send pageId\"),\n pageId: z.string().min(1).optional().describe(\"instead of entryId: the page (from list_pages)\"),\n ifMatch: z.number().int().min(0).optional().describe(\"optimisticVersion from get_content_entry or get_page\"),\n }).shape,\n async (c, a) => {\n if (!a.entryId === !a.pageId) return fail(\"Pass exactly one of entryId (an entry) or pageId (a page).\");\n const path = a.pageId ? `/management/pages/${s(a.pageId)}/discard-draft` : `/management/content/entries/${s(a.entryId)}/discard-draft`;\n return ok(\"Draft discarded.\", (await c.fetchJSON<{ data?: unknown }>(c.url(path), {\n method: \"POST\",\n body: JSON.stringify({}),\n ...(a.ifMatch !== undefined ? { headers: { \"If-Match\": `W/\"${a.ifMatch}\"` } } : {}),\n })).data);\n }),\n def(\"refresh_search_index\", \"Refresh IndexNow or site search\",\n NEW_TOOL_TEXT.refresh_search_index,\n z.object({\n action: z.enum([\"indexnow\", \"reindex\"]).describe(\"'indexnow' pings search engines; 'reindex' rebuilds site search\"),\n urls: z.array(z.string().min(1)).min(1).max(1000).optional().describe(\"indexnow only: this site's URLs; every change since the last submission when omitted\"),\n }).shape,\n async (c, a) => ok(a.action === \"reindex\" ? \"Site search rebuilt.\" : \"IndexNow submission.\", a.action === \"reindex\"\n ? await data(c, \"POST\", `/management/search/reindex`, {})\n : await data(c, \"POST\", `/management/seo/indexnow/submit`, { urls: a.urls }))),\n def(\"give_feedback\", \"Send feedback to the BetterCMS team\",\n NEW_TOOL_TEXT.give_feedback,\n z.object({\n kind: z.enum([\"bug\", \"missing_capability\", \"unclear_docs\", \"other\"]).describe(\"what went wrong\"),\n message: z.string().min(1).max(10_000).describe(\"what you tried, what happened and what you expected (1-10000 chars)\"),\n tool: z.string().max(100).optional().describe(\"the tool it is about, if any\"),\n context: z.string().max(4000).optional().describe(\"the request and response, or other detail (up to 4000 chars)\"),\n }).shape,\n async (c, a) => ok(\"Feedback sent.\", await data(c, \"POST\", `/management/feedback`, { kind: a.kind, message: a.message, tool: a.tool, context: a.context }))),\n def(\"publish_entries\", \"Publish or unpublish many entries and pages\",\n NEW_TOOL_TEXT.publish_entries,\n z.object({\n action: z.enum([\"publish\", \"unpublish\", \"hold\", \"release\"]).describe(\"live, back to draft, or hold/release from site publishes\"),\n entryIds: z.array(z.string().min(1)).max(100).optional().describe(\"entry ids (from list_content_entries)\"),\n pageIds: z.array(z.string().min(1)).max(100).optional().describe(\"page ids (from list_pages); not for unpublish\"),\n }).shape,\n async (c, a) => {\n const receipt = await data(c, \"POST\", `/management/publish`, { action: a.action, entryIds: a.entryIds, pageIds: a.pageIds });\n const outcome = (receipt as { outcome?: PublishOutcome } | null | undefined)?.outcome;\n return ok(a.action === \"publish\" ? publishedLines(outcome, \"Publish receipt.\").join(\"\\n\") : a.action === \"unpublish\" ? \"Unpublish receipt.\" : \"Hold receipt.\", receipt);\n }),\n def(\"create_content_entries\", \"Create many draft entries\",\n NEW_TOOL_TEXT.create_content_entries,\n z.object({\n contentModelId: z.string().min(1).describe(\"the collection every entry belongs to (from list_content_models)\"),\n entries: z.array(z.object({ slug: z.string().optional(), data: z.record(z.string(), z.unknown()), ...upsertShape })).min(1).max(200).describe(\"1-200 entries, each {slug?, data}\"),\n dryRun: z.boolean().optional().describe(PARAM_TEXT.dryRun),\n }).shape,\n // The whole body: the per-row receipt is `data`, the counts ride in `meta`.\n async (c, a) => ok(a.dryRun ? DRY_RUN_SUMMARY : \"Batch receipt.\", await c.fetchJSON(c.url(`/management/content/entries/batch`), { method: \"POST\", body: JSON.stringify({ contentModelId: a.contentModelId, entries: a.entries, dryRun: a.dryRun }) }))),\n def(\"translate_entry\", \"Translate an entry into another locale\",\n NEW_TOOL_TEXT.translate_entry,\n z.object({\n entryId: z.string().min(1).describe(\"the SOURCE entry, never another translation\"),\n targetLocale: z.string().min(1).describe(\"BCP-47 locale from the project's locales, e.g. 'fr'\"),\n slug: z.string().optional().describe(\"the translation's slug; <source slug>-<locale> when omitted\"),\n fields: z.array(z.string().min(1)).optional().describe(\"translate only these field keys\"),\n }).shape,\n async (c, a) => ok(\"Translation created.\", await c.fetchJSON(c.url(`/management/content/entries/${s(a.entryId)}/translate`), { method: \"POST\", body: JSON.stringify({ targetLocale: a.targetLocale, slug: a.slug, fields: a.fields }) }))),\n def(\"list_webhooks\", \"List webhooks\",\n NEW_TOOL_TEXT.list_webhooks,\n z.object({}).shape,\n async (c) => ok(\"Webhooks.\", await data(c, \"GET\", `/management/webhooks`))),\n def(\"create_webhook\", \"Create a webhook\",\n NEW_TOOL_TEXT.create_webhook,\n z.object({\n name: z.string().min(1).max(255).describe(\"a label, 1-255 chars\"),\n url: z.string().url().describe(\"the https endpoint that receives the events\"),\n events: z.array(z.enum(WEBHOOK_EVENTS)).min(1).optional().describe(\"events to send; ['content.publish'] when omitted\"),\n isActive: z.boolean().optional().describe(\"default true\"),\n test: z.boolean().optional().describe(\"send a sample delivery now\"),\n }).shape,\n // The whole body: a `test` delivery's outcome rides beside `data`.\n async (c, a) => ok(\"Webhook created. Store the `secret` now: it is never shown again.\", await c.fetchJSON(c.url(`/management/webhooks`), { method: \"POST\", body: JSON.stringify({ name: a.name, url: a.url, events: a.events, isActive: a.isActive, test: a.test }) }))),\n def(\"list_branches\", \"List content branches\",\n NEW_TOOL_TEXT.list_branches,\n z.object({}).shape,\n async (c) => ok(\"Branches.\", await c.fetchJSON(c.url(`/management/branches`), { method: \"GET\" }))),\n def(\"create_branch\", \"Create a content branch\",\n NEW_TOOL_TEXT.create_branch,\n z.object({\n name: z.string().min(1).max(80).describe(\"1-80 chars\"),\n slug: z.string().max(80).optional().describe(\"derived from the name when omitted\"),\n }).shape,\n async (c, a) => ok(\"Branch created.\", await data(c, \"POST\", `/management/branches`, { name: a.name, slug: a.slug }))),\n def(\"apply_branch\", \"Merge a branch into its parent\",\n NEW_TOOL_TEXT.apply_branch,\n z.object({\n branchId: z.string().min(1).describe(\"the branch to merge (from list_branches)\"),\n dryRun: z.boolean().optional().describe(\"true = return the diff and write nothing\"),\n include: z.array(z.string().min(1)).max(500).optional().describe(\"change keys to merge (from the diff); all when omitted\"),\n fields: z.record(z.string(), z.record(z.string(), z.enum([\"keep_branch\", \"keep_parent\"]))).optional().describe(\"change key → field → 'keep_branch' | 'keep_parent', for each conflict\"),\n }).shape,\n async (c, a) => a.dryRun === true\n ? ok(\"Branch diff (nothing was written).\", await data(c, \"GET\", `/management/branches/${s(a.branchId)}/diff`))\n : 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 }) }))),\n def(\"search_docs\", \"Search the BetterCMS docs\",\n NEW_TOOL_TEXT.search_docs,\n z.object({\n q: z.string().min(1).describe(\"the question or words to find\"),\n limit: z.number().int().min(1).max(20).optional().describe(\"pages to return; 5 when omitted\"),\n }).shape,\n async (c, a) => ok(\"Docs.\", await c.fetchJSON(c.url(`/management/docs/search${q({ q: a.q, limit: a.limit })}`), { method: \"GET\" }))),\n def(\"generate_image\", \"Generate an image with AI\",\n NEW_TOOL_TEXT.generate_image,\n z.object({\n prompt: z.string().min(1).max(2000).describe(\"what the image shows, 1-2000 chars\"),\n altText: z.string().optional().describe(\"alt text for the new asset\"),\n width: z.number().int().min(256).max(1440).multipleOf(16).optional(),\n height: z.number().int().min(256).max(1440).multipleOf(16).optional(),\n folderId: z.string().optional().describe(\"Media Library folder id\"),\n }).shape,\n async (c, a) => ok(\"Generated image.\", await data(c, \"POST\", `/management/ai/image`, { prompt: a.prompt, altText: a.altText, width: a.width, height: a.height, folderId: a.folderId }))),\n def(\"transform_image\", \"Edit an image with AI\",\n NEW_TOOL_TEXT.transform_image,\n z.object({\n mediaId: z.string().min(1).describe(\"the image to edit (from list_media)\"),\n prompt: z.string().min(1).max(2000).describe(\"the change to make, 1-2000 chars\"),\n altText: z.string().optional().describe(\"alt text for the new asset\"),\n folderId: z.string().optional().describe(\"Media Library folder id\"),\n }).shape,\n async (c, a) => ok(\"Edited image (a new asset).\", await data(c, \"POST\", `/management/ai/image/transform`, { mediaId: a.mediaId, prompt: a.prompt, altText: a.altText, folderId: a.folderId }))),\n def(\"write_alt_text\", \"Write alt text with AI\",\n NEW_TOOL_TEXT.write_alt_text,\n z.object({ mediaId: z.string().min(1).optional().describe(\"the image (from list_media)\"), url: z.string().optional().describe(\"or an https image URL\") }).shape,\n async (c, a) => ok(\"Alt text suggestion.\", await data(c, \"POST\", `/management/ai/alt-text`, a.url ? { url: a.url } : { mediaId: a.mediaId }))),\n\n def(\"list_activity\", \"List project activity\",\n \"Recent activity in the connected project — who changed what, and when. Filter by `category` (comma-separated: content, pages, media, forms, deployment, settings, members), `actorId`, or a `since`/`until` ISO window. At the start of a turn, pass `since` (your last look) to notice dashboard or agent edits made since.\",\n z.object({ category: z.string().optional(), actorId: z.string().optional(), since: z.string().optional(), until: z.string().optional(), limit: z.number().optional() }).shape,\n async (c, a) => ok(\"Project activity.\", await data(c, \"GET\", `/management/insights/activity${q({ category: a.category, actorId: a.actorId, since: a.since, until: a.until, limit: a.limit })}`))),\n def(\"get_next_steps\", \"Get what to do next\",\n NEXT_STEPS_DESCRIPTION,\n z.object({\n importJunk: z.boolean().optional().describe(\"true = add rule import-junk: what an old import left, with removal calls\"),\n }).shape,\n // The whole body: `receipt` rides beside `data`, and `data()` would drop it.\n async (c, a) =>\n ok(\"Next steps.\", await c.fetchJSON(c.url(`/management/insights/next-steps${a.importJunk === true ? \"?importJunk=true\" : \"\"}`), { method: \"GET\" }))),\n def(\"get_binding_report\", \"Check what on the live site is editable\",\n \"The receipt for 'is this site actually EDITABLE?'. Each release scans the built HTML for the element rendering each CMS field value; per slot this returns `mode` ('text-match' = guessed from rendered text, 'declared' = template-declared), what was bound, and `unmatched`: each path with its reason (reasons: skill bindings). DEPLOY FIRST: before any release there is no report (pages 0, mode null, refreshRequired true). `refreshReason`: a HEADLESS site never gets one (`never-generated`); `layoutRoutes` and `coverage.error`: skill bindings. `unaddressable` is the visible live text no field owns, by route (null = unmeasured: diff visible text against entry values); over `count / visible > 0.02`, fix it in the SOURCE and re-read (playbook §11). `entryRowUnbound`: a bound card's words no field of its entry claims, by route, with `reason` (reference, boolean, locale-format, counter, no-field); never also in `unaddressable`. `canvas.lane`: `none` → get_next_steps.\",\n z.object({ slot: z.enum([\"current\", \"staging\"]).optional().describe(\"which release tree to read — everything here, `unaddressable` included, is measured PER SLOT, so on a promote-gated project pass 'current' to read the tree the editor frames. Defaults to the slot this project's releases land in. The response's `sha` is the build the report describes; `refreshRequired` is true when that is not the build this slot serves. Other per-slot fields: skill bindings.\") }).shape,\n async (c, a) => ok(\"Binding report.\", await data(c, \"GET\", `/management/projects/current/binding-report${q({ slot: a.slot })}`))),\n def(\"get_conversion_brief\", \"Get the brief for making this site's bindings durable\",\n \"The per-project brief for making this site's bindings DURABLE — read it before you touch the templates. Returns what already exists in the CMS: every live page with its route, every bindable field path with its `label`, `kind`, the CMS value (`current`) and the copy the repo renders today (`original`), the exact attributes to declare, and the ordered steps. Call it for any site whose pages were DERIVED at import, and whenever get_next_steps reports `bindings-not-declared`. It REPLACES re-registering a schema: these pages, fields and values exist already, so create_page / add_field / create_content_model would build a second schema over the first — edit values with set_page_content instead. `lane`: 'git-connected' = pull_project_source returns a repo; 'archive' = a tarball. Recipe: playbook §13; get_binding_report is the finish line. Pass `complete: true` before running the CODEMOD (`npx @bettercms-ai/convert`): the brief UNCAPPED and paged, its full path list pinned under a `briefDigest` — what the coverage meter measures the build against. The complete brief also carries `forms`: wiring them and publishing the forms it names, skill bindings.\",\n z.object({\n complete: z.boolean().optional().describe(\"true = the COMPLETE brief for a codemod: nothing truncated, no page omitted, paged 50 pages at a time. Page 1 pins the path list the coverage meter measures against.\"),\n cursor: z.string().optional().describe(\"The `cursor` from the previous page. Implies complete. A 409 BRIEF_CHANGED means the brief was re-derived mid-pagination — start again with no cursor.\"),\n }).shape,\n async (c, a) => ok(\"Conversion brief.\", await data(c, \"GET\", `/management/projects/current/conversion-brief${q({ complete: a.complete, cursor: a.cursor })}`))),\n def(\"get_conversion_plan\", \"Get the approved conversion to apply\",\n \"The APPROVED conversion a human reviewed in the BetterCMS dashboard: the exact new contents of each template file, already checked against this project's real field paths. Apply it instead of writing the bindings by hand. Check out `baseHeadOid` (the exact commit it was written against), branch from there, write each file's `content` verbatim (whole file, no merge, no reformatting), then push or deploy however this project ships. `stale.head` / `stale.brief` say the repository or the CMS moved since it was approved: stop and ask for a fresh proposal. `receipt.paths.pending` lists every field the codemod could NOT bind, each with a reason (`DIALECT_UNSUPPORTED`, `PROP_TARGET_NOT_FOUND`, `REPEATER_FIXED_LENGTH`, …) — apply the plan first, then bind those by hand. Then finish as a hand conversion does: get_binding_report until `unmatched` is empty, then set_binding_mode { declaredBindings: true } and release once more. 404 with `code: \\\"no-approved-plan\\\"` means nobody has approved one: use get_conversion_brief and do the conversion yourself. Requires artifact:write; on a workspace-wide connection pass `projectId`.\",\n z.object({}).shape,\n async (c) => ok(\"Approved conversion plan.\", await data(c, \"GET\", `/management/projects/current/conversion-plan`))),\n def(\"get_site_composition\", \"Check every page is assembled from registered components\",\n \"The receipt for 'is every page assembled from registered components?' — read-only, computed live. Call it before a whole-site componentize run (playbook §12) and after it, as the proof. Per page: `kind`, a block census, `nonComponentBlocks` and every `component` placement with its `status` (a draft renders as an EMPTY STRING on the live site), `inPicker` and `emptyRequiredProps`. Site-wide: counts, `awaitingApproval` (a HUMAN approves in the dashboard; no tool here can), `notInPicker`, `unused` and `layout.placements`. Each field: skill components. `verdict.everyPageComposed` with `verdict.reasons` is the answer to give the user. Pages are read DRAFT-inclusive: check each page's own `status` before claiming the site is live.\",\n z.object({}).shape,\n async (c) => ok(\"Site composition.\", await data(c, \"GET\", `/management/projects/current/composition`))),\n def(\"get_componentize_plan\", \"Get the plan for turning this site's sections into components\",\n \"What this site's SECTIONS would become as components — a proposal that creates nothing and is computed live. For a site whose pages were DERIVED at import, each top-level field GROUP is one section: `hero-*` and `faq-*` keys, and the repeaters the import folded (`group-*`). Per page: each section's `groupKey`, `sectionType` family, leaf `fields` with their CMS values, `shapeHash`, and either the component already rendering it (`reuse.componentId`) or the proposed one (`reuse.proposedSlug`). Under `components`, a NEW one carries the exact `props` and `blockJson` create_component would take; an EXISTING one only `componentId`, `slug` and `name` (nothing is written for it). `pending` says why a group is not offered (its codes: see `summary`). Per-page components, collection templates and chrome (never a section): skill componentize. READ `summary: true` FIRST — the full plan runs to hundreds of KB; `paged` pages it (409 PLAN_CHANGED = start again); the unpaged full read is what `--plan plan.json` takes. Keep the `digest` — componentize_sections refuses any other.\",\n z.object({\n summary: z.boolean().optional().describe(\"true = no values: each section's groupKey, family, pending and component slug. Read this first. `pending` codes (each explained in skill componentize): `NO_GROUP_ROOT`, `NOT_A_SECTION` (`detail`: `ENTRY_METADATA`, `DECLINED`), `IMAGE_AS_TEXT`, `ALREADY_COMPONENTIZED`, `EMPTY_GROUP`, `NESTED_REPEATER`, `PAGE_NOT_EMPTY`.\"),\n paged: z.boolean().optional().describe(\"true = 10 pages at a time; the response carries `page`, `pageCount` and a `cursor` for the next.\"),\n cursor: z.string().optional().describe(\"The `cursor` from the previous page. Implies paged. A 409 `PLAN_CHANGED` means start again with no cursor.\"),\n }).shape,\n async (c, a) => ok(\"Componentize plan.\", await data(c, \"GET\", `/management/projects/current/componentize-plan${q({ summary: a.summary, paged: a.paged, cursor: a.cursor })}`))),\n def(\"componentize_sections\", \"Turn this site's derived sections into components\",\n \"Turn this site's derived sections into components. CONFIRM WITH THE USER FIRST: show them get_componentize_plan's sections, how many components it will create and which pages it will rewrite; `dryRun` first. It creates each proposed component as a DRAFT and replaces each page's DRAFT blocks with ordered `component` instances, one per group. The page keeps its `fields`, values and bindings (see `copy`). Pass the plan's `digest`; a 409 `stale-plan` means the site changed: read the plan again, show the user what changed and confirm again. Read `components.wouldDuplicate` first (skill components). Re-running is safe: a placed group returns as ALREADY_COMPONENTIZED. DRAFTS ONLY — an unpublished component renders as an EMPTY STRING on the live site, so publish_component each one and publish the pages, then call it again with `codemod: true` for the repository half (skill componentize). A group the user says is NOT a section: `decline: true` with those `sections` (skill componentize).\",\n z.object({\n digest: z.string().min(1).describe(\"The `digest` get_componentize_plan returned. A different one is refused with 409 stale-plan.\"),\n pageIds: z.array(z.string().min(1)).optional().describe(\"Componentize only these pages (ids from the plan). Omit for every page the plan lists.\"),\n pages: z.array(z.string().min(1)).optional().describe(\"The same page filter under the name the dashboard uses. Unioned with pageIds; an EMPTY list is refused rather than treated as every page.\"),\n sections: z.array(z.string().min(1)).optional().describe(\"Act only on these section groupKeys (from the plan); every other section keeps its placement.\"),\n copy: z.enum([\"bind\", \"instance\"]).optional().describe(\"Who owns each section's copy. 'bind' (default) leaves it in the page fields. 'instance' moves it onto each placement; the page's fields are KEPT and marked `origin: \\\"componentized\\\"` (skill componentize).\"),\n dryRun: z.boolean().optional().describe(\"true = return the receipt without writing anything. Do this first.\"),\n group: z.string().min(1).max(100).optional().describe(\"File the components this run creates into this Component Group (by NAME, created when missing), else its section family (skill componentize). A reused component keeps its Group; the receipt's `components.groups` lists the Groups filed into.\"),\n decline: z.boolean().optional().describe(\"true = record `sections` as NOT sections (nothing is componentized; the plan stops proposing them). false = offer them again. Needs `sections`.\"),\n joinTwins: z.boolean().optional().describe(\"true = move each locale copy (`/fr`) still on its own component onto its twin's (`bindPaths` keeps its fields). A dry run lists each in `joins`. Whole plan only.\"),\n codemod: z.boolean().optional().describe(PARAM_TEXT.componentizeCodemod),\n }).shape,\n async (c, a) => ok(a.codemod === true ? \"Section-order codemod.\" : \"Componentized the sections.\", await data(c, \"POST\", a.codemod === true ? `/management/projects/current/section-order` : `/management/projects/current/componentize`, { digest: a.digest, pageIds: a.pageIds, pages: a.pages, sections: a.sections, copy: a.copy, dryRun: a.dryRun, group: a.group, decline: a.decline, joinTwins: a.joinTwins, codemod: a.codemod }))),\n def(\"get_analytics_overview\", \"Get traffic overview\",\n \"Traffic totals and the daily series for the connected project — views, unique visitors, bytes, sessions and bounces. Defaults to the last 30 days; pass `from`/`to` as YYYY-MM-DD.\",\n z.object({ from: z.string().optional(), to: z.string().optional() }).shape,\n async (c, a) => ok(\"Analytics overview.\", await data(c, \"GET\", `/management/insights/analytics/overview${q({ from: a.from, to: a.to })}`))),\n def(\"get_analytics_top_pages\", \"Get top pages\",\n \"The most-viewed paths on the live site, with views and bytes. Defaults to the last 30 days; pass `from`/`to` (YYYY-MM-DD) and `limit`.\",\n z.object({ from: z.string().optional(), to: z.string().optional(), limit: z.number().optional() }).shape,\n async (c, a) => ok(\"Top pages.\", await data(c, \"GET\", `/management/insights/analytics/top-pages${q({ from: a.from, to: a.to, limit: a.limit })}`))),\n def(\"list_seo_issues\", \"List SEO issues\",\n \"Scan every published page for SEO problems (missing or over-long titles and descriptions, missing OG image, noindex, invalid pasted schema) and return them with severities. Also reports accessibility issues as `a11y.*` codes with block ids. Computed live — nothing is stored.\",\n z.object({}).shape,\n async (c) => ok(\"SEO issues.\", await data(c, \"GET\", `/management/insights/seo-issues`))),\n def(\"list_ai_reports\", \"List AI report runs\",\n \"Past AI report runs for the connected project — `kind` is 'links' (internal linking) or 'aeo' (AI-answer readiness). Read-only history; starting a run stays a dashboard action.\",\n z.object({ kind: z.enum([\"links\", \"aeo\"]), limit: z.number().optional() }).shape,\n async (c, a) => ok(\"AI reports.\", await data(c, \"GET\", `/management/insights/ai-reports${q({ kind: a.kind, limit: a.limit })}`))),\n\n // ── Bulk: one dataset → many pages ────────────────────────────────────────\n def(\"generate_pages_from_dataset\", \"Generate many pages from a dataset\",\n \"Turn a dataset into many pages at once (programmatic SEO from a keyword list, or ABM pages from an account list). Give a template `pageId`, a `mapping` (contentModelId, a slugTemplate like 'for-{{company}}', and per-field values that are either a column name or {ai:{prompt}}), and `rows`. For an ABM campaign set `mapping.campaign.id` and the run fans out across every page that campaign owns, returning one job id per page in `jobIds`. ALWAYS call with dryRun:true first and show the sample — a real run parks for approval and must be released with approve_ai_job.\",\n z.object({\n pageId: z.string().min(1),\n mapping: z.record(z.string(), z.unknown()),\n rows: z.array(z.record(z.string(), z.string())).min(1),\n dryRun: z.boolean().optional(),\n }).shape,\n async (c, a) => ok(\"Generation queued.\", await data(c, \"POST\", `/management/bulk/generate`, { pageId: a.pageId, mapping: a.mapping, rows: a.rows, dryRun: a.dryRun }))),\n def(\"research_account\", \"Research one account\",\n \"Read one company's public site into a cited brief the page generator can use: what they do, who they sell to, what they say is hard, with a source URL on every fact. `lite` is one fetch and costs nothing extra; `deep` searches the web, costs 3 credits and is capped per day. A brief less than 30 days old is returned from cache for free. Company-scoped by design: it never stores a person, an email or a job title.\",\n z.object({\n campaignId: z.string().min(1),\n domain: z.string().min(1),\n name: z.string().optional(),\n mode: z.enum([\"lite\", \"deep\"]).optional(),\n force: z.boolean().optional(),\n }).shape,\n async (c, a) => ok(\"Account brief.\", await data(c, \"POST\", `/management/campaigns/research`, { campaignId: a.campaignId, domain: a.domain, name: a.name, mode: a.mode, force: a.force }))),\n def(\"build_abm_page\", \"Build one ABM page for one account\",\n \"Build ONE personalized page for ONE account, guided: give the sales motion and a paragraph of context about the target ('Lumina — 300-rep sales team moving off spreadsheets…') and this mints the campaign, the page, the collection and the run. `brandUrl` learns the seller's brand first, once per project, and needs Settings access because it rewrites the project's brand. Research defaults to `lite` and is forced off when no domain is known. It PARKS for the user's approval like every agent generation here — release it with approve_ai_job — and `requestId` makes a retry return the first answer instead of a second page.\",\n z.object({\n motion: z.enum([\"new_account\", \"expand_customer\", \"accelerate_opportunity\", \"reengage_closed_lost\"]),\n context: z.string().min(20),\n website: z.string().optional(),\n name: z.string().optional(),\n research: z.enum([\"lite\", \"deep\", \"off\"]).optional(),\n ctaHref: z.string().optional(),\n formId: z.string().optional(),\n brandUrl: z.string().optional(),\n requestId: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Page queued for approval.\", await data(c, \"POST\", `/management/campaigns/build`, {\n motion: a.motion, context: a.context, website: a.website, name: a.name,\n research: a.research, ctaHref: a.ctaHref, formId: a.formId,\n brandUrl: a.brandUrl, requestId: a.requestId,\n }))),\n def(\"claim_abm_task\", \"Claim an account to research\",\n \"Claim the next account of a campaign that is waiting for YOU to research it. Returns the account, a `taskId` and a `leaseToken` good for ten minutes; `null` means there is nothing left and your loop is done. Research the company however you like, then call complete_abm_task with the brief — or fail_abm_task if you cannot. Never store a person, an email or a job title: the brief is refused if you do.\",\n z.object({ campaignId: z.string().min(1), agentId: z.string().optional() }).shape,\n async (c, a) => ok(\"Claimed task.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/tasks/claim`, { agentId: a.agentId }))),\n def(\"complete_abm_task\", \"Hand back an account brief\",\n \"Hand back the brief for a task you claimed. `brief` is {name, domain, industry?, size?, painPoint?, summary?, facts:[{text, sourceUrl}], logo?, brandColors?} and NOTHING else — an unknown key is refused with brief_invalid and the path. Every fact needs the URL it came from. When the campaign's last task is done the page generation starts on its own.\",\n z.object({\n campaignId: z.string().min(1),\n taskId: z.string().min(1),\n leaseToken: z.string().min(1),\n brief: z.record(z.string(), z.unknown()),\n }).shape,\n async (c, a) => ok(\"Brief accepted.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/tasks/${s(a.taskId)}/complete`, { leaseToken: a.leaseToken, brief: a.brief }))),\n def(\"fail_abm_task\", \"Give an account task back\",\n \"Give a claimed task back when you cannot research the account — the site is down, there is nothing public to read, the domain is wrong. The page is still written, from the dataset alone, and says so.\",\n z.object({\n campaignId: z.string().min(1),\n taskId: z.string().min(1),\n leaseToken: z.string().min(1),\n reason: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Task returned.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/tasks/${s(a.taskId)}/fail`, { leaseToken: a.leaseToken, reason: a.reason }))),\n def(\"get_campaign_review\", \"Review a campaign's pages\",\n \"The campaign's generated pages, SORTED BY DOUBT — flagged first, then least confident. Each row carries its flags (`unsupported_claim:headline` and the like), the claims the model said it made, which fields it wrote, and a preview link for drafts. `filter:'flagged'` is the review queue; `sample:5` is the first look at a big run; `filter:'failed'` lists the rows that produced no page at all and why.\",\n z.object({\n campaignId: z.string().min(1),\n filter: z.enum([\"all\", \"flagged\", \"pending\", \"approved\", \"rejected\", \"low_confidence\", \"failed\"]).optional(),\n sample: z.number().optional(),\n pageId: z.string().optional(),\n runId: z.string().optional(),\n cursor: z.string().optional(),\n limit: z.number().optional(),\n }).shape,\n async (c, a) => ok(\"Campaign review.\", await data(c, \"GET\", `/management/campaigns/${s(a.campaignId)}/review${q({ filter: a.filter, sample: a.sample, pageId: a.pageId, runId: a.runId, cursor: a.cursor, limit: a.limit })}`))),\n def(\"regenerate_entry\", \"Rewrite one account's page\",\n \"Rewrite ONE account's page, optionally with an instruction ('lead with the integration story') and optionally only certain fields. Costs one credit and writes a DRAFT — a published page shows unpublished changes until someone publishes it again. Re-runs from the original spreadsheet row, not from the last answer, so repeated regenerates do not drift.\",\n z.object({\n campaignId: z.string().min(1),\n entryId: z.string().min(1),\n instruction: z.string().optional(),\n fields: z.array(z.string()).optional(),\n }).shape,\n async (c, a) => ok(\"Regeneration queued.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/entries/${s(a.entryId)}/regenerate`, { instruction: a.instruction, fields: a.fields }))),\n def(\"approve_campaign_entries\", \"Mark campaign pages reviewed\",\n \"Mark campaign pages reviewed. `entryIds:'all_unflagged'` clears every page with nothing wrong with it, which is most of them; a FLAGGED page must be named explicitly, because approving one is a person saying they checked the claim. Approving does not publish — publish_campaign does, and it refuses pages that are still flagged.\",\n z.object({\n campaignId: z.string().min(1),\n entryIds: z.union([z.array(z.string()), z.literal(\"all_unflagged\")]),\n status: z.enum([\"approved\", \"rejected\"]),\n note: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Entries reviewed.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/entries/review`, { entryIds: a.entryIds, status: a.status, note: a.note }))),\n def(\"publish_campaign\", \"Publish a campaign\",\n \"Put a campaign's pages on the internet, or schedule them. `confirm: true` is REQUIRED — this is the one action in the ABM lane that a human, not you, decides. It REFUSES with `entry_flagged` if any page still carries an unchecked claim (call get_campaign_review and approve them first) and with `blueprint_missing_disclaimer` if a campaign page has lost its 'not affiliated with' band. Pages somebody rejected are skipped and counted.\",\n z.object({\n campaignId: z.string().min(1),\n scheduledAt: z.string().optional(),\n unpublishAt: z.string().optional(),\n confirm: z.boolean(),\n }).shape,\n async (c, a) => ok(\"Campaign publish queued.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/publish`, { scheduledAt: a.scheduledAt, unpublishAt: a.unpublishAt, confirm: a.confirm }))),\n def(\"get_campaign_share_link\", \"Make a share link\",\n \"Make a link a rep can send before the pages are published. `scope:'campaign'` opens the whole account index; `scope:'account'` with an `externalKey` (the account's domain) opens exactly that account's pages and 404s on anyone else's. At most 14 days, revocable, rate-limited and noindex. The link's `uses` is how a rep sees Not sent / Sent / Visited.\",\n z.object({\n campaignId: z.string().min(1),\n scope: z.enum([\"campaign\", \"account\"]).optional(),\n externalKey: z.string().optional(),\n expiresIn: z.string().optional(),\n label: z.string().optional(),\n }).shape,\n async (c, a) => ok(\"Share link.\", await data(c, \"POST\", `/management/campaigns/${s(a.campaignId)}/share-links`, { scope: a.scope, externalKey: a.externalKey, expiresIn: a.expiresIn, label: a.label }))),\n def(\"revoke_campaign_share_link\", \"Withdraw a share link\",\n \"Withdraw ONE share link by its `jti`, leaving every other link to the same campaign working. The link then answers 404. Safe to call twice.\",\n z.object({ campaignId: z.string().min(1), jti: z.string().min(1) }).shape,\n async (c, a) => ok(\"Share link revoked.\", await data(c, \"DELETE\", `/management/campaigns/${s(a.campaignId)}/share-links/${s(a.jti)}`))),\n def(\"list_ai_jobs\", \"List bulk jobs\",\n \"Recent bulk jobs for the connected project with status and progress. Use it to report how a generation is going.\",\n z.object({}).shape,\n async (c) => ok(\"Bulk jobs.\", await data(c, \"GET\", `/management/bulk/jobs`))),\n def(\"get_ai_job\", \"Get a bulk job\",\n \"One bulk job — its `type` (generate, seo, rename, migrate, publish, unpublish, research), status, rows processed, rows created, conflicts, and the approval plan if it is still parked. `rowResults` is the per-row ledger: every row that FAILED or was skipped, with a reason code, which is the only place “20 rows in, 18 pages out” is explained. `summary` splits a rerun into added / updated / unchanged, and `campaignId` / `collectionSlug` say which campaign and collection the pages landed in.\",\n z.object({ jobId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Bulk job.\", await data(c, \"GET\", `/management/bulk/jobs/${s(a.jobId)}`))),\n def(\"approve_ai_job\", \"Approve a bulk job\",\n \"Release a job that is awaiting approval so the queue can run it. Only call this when the USER has said yes — never approve your own plan unprompted.\",\n z.object({ jobId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Job approved.\", await data(c, \"POST\", `/management/bulk/jobs/${s(a.jobId)}/approve`))),\n def(\"reject_ai_job\", \"Reject a bulk job\",\n \"Discard a job awaiting approval. Nothing was charged and nothing was written.\",\n z.object({ jobId: z.string().min(1) }).shape,\n async (c, a) => ok(\"Job rejected.\", await data(c, \"POST\", `/management/bulk/jobs/${s(a.jobId)}/reject`))),\n\n\n\n def(\"get_deploy_status\", \"Get deploy/build status\",\n \"Get the connected project's deploy/build status: state (idle|queued|building|failed), whether it's publishing, the live commit sha, when it went live, and any build error. `editorSetup`: whether editing is set up for the live build (never or stale = call editor_setup). Poll this after deploy_project until state is idle with your sha live. `release`, `held` and `publishes` (each `live` or `partial`): skill publishing. `runtime` ({state: ok|crash-loop, restarts, oomKilled}) appears for a server app only: crash-loop means its container keeps restarting (often out of memory) though the build went live fine. Also returns `canvas.lane` (skill bindings) and `editorUrl`, the visual editor to hand the user.\",\n z.object({}).shape,\n // Flat body, no `data` envelope: `data()` read it as undefined.\n async (c) => ok(\"Deploy status.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/deploy-status`), { method: \"GET\" }))),\n def(\"editor_setup\", \"Set up editing for the live build\",\n NEW_TOOL_TEXT.editor_setup,\n z.object({\n force: z.boolean().optional().describe(PARAM_TEXT.editorSetupForce),\n check: z.boolean().optional().describe(PARAM_TEXT.editorSetupCheck),\n exempt: z.array(z.record(z.string(), z.unknown())).optional().describe(PARAM_TEXT.editorSetupExempt),\n declare: z.array(z.record(z.string(), z.unknown())).optional().describe(PARAM_TEXT.editorSetupDeclare),\n }).shape,\n // The route answers `{ state, … }` with no `data` envelope, so the whole body is the result.\n // `exempt` records setup-gate exceptions instead of running anything (the gate's one write).\n // `declare` records binding decisions; with `check: true` it is a dry run (the body's `dryRun`).\n async (c, a) => a.exempt\n ? ok(\"Setup gate exceptions.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/setup-gate/exceptions`), { method: \"POST\", body: JSON.stringify({ exempt: a.exempt }) }))\n : a.declare\n ? ok(\"Binding decisions.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/binding-decisions`), { method: \"POST\", body: JSON.stringify({ declare: a.declare, ...(a.check === true ? { dryRun: true } : {}) }) }))\n : ok(\"Editor setup.\", await c.fetchJSON<Record<string, unknown>>(c.url(`/management/projects/editor-setup`), a.check === true\n ? { method: \"GET\" }\n : { method: \"POST\", body: JSON.stringify({ force: a.force }) }))),\n\n // ── Deploy to the user's own host (parity with remote /mcp) ──\n // A person connects Vercel or Netlify in the dashboard; nothing here touches OAuth or a host\n // token. deploy_to_host takes artifact:write like deploy_project. @see management/deploy-targets.ts\n def(\"list_env_vars\", \"List environment variables\",\n HOSTING_TEXT.list_env_vars,\n z.object({}).shape,\n async (c) => ok(\"Environment variables (names only).\", await data(c, \"GET\", `/management/hosting/env`))),\n def(\"list_hosting_connections\", \"List hosting connections\",\n HOSTING_TEXT.list_hosting_connections,\n z.object({}).shape,\n async (c) => ok(\"Hosting connections.\", await data(c, \"GET\", `/management/hosting/connections`))),\n def(\"deploy_to_host\", \"Deploy to Vercel or Netlify\",\n HOSTING_TEXT.deploy_to_host,\n z.object({\n provider: z.enum([\"vercel\", \"netlify\"]),\n connectionId: z.string().min(1).optional().describe(\"a connection id from list_hosting_connections; defaults to the newest working one\"),\n siteName: z.string().min(1).max(63).optional().describe(\"lowercase letters, numbers and hyphens; defaults to the project's handle\"),\n }).shape,\n async (c, a) => ok(\"Host deploy.\", await data(c, \"POST\", `/management/deploy-targets/provision`, { provider: a.provider, connectionId: a.connectionId, siteName: a.siteName }))),\n def(\"get_host_deploy_status\", \"Get host deploy status\",\n HOSTING_TEXT.get_host_deploy_status,\n z.object({}).shape,\n async (c) => ok(\"Host deployments.\", await data(c, \"GET\", `/management/hosting/external-deployments`))),\n ];\n }\n\n const defs: ToolDef[] = [\n {\n name: \"list_pages\",\n config: {\n title: \"List pages in the current project\",\n description:\n \"List the pages in the project this MCP key is bound to, each with its id, `path`, `language`, full field SCHEMA, pageType (singleton|dynamic), and status. Use it to verify WHERE content lands and to read field keys/types before set_page_content / add_field.\",\n inputSchema: {},\n },\n handler: guard(async () =>\n withClient(async (client) => {\n const pages = await client.listPages();\n return ok(\n `${pages.length} page(s) in the bound project.`,\n pages.map((p) => ({\n id: p.id,\n title: p.title,\n slug: p.slug,\n // Its URL and language: slugs are unique per folder, so `about` can be seven pages.\n path: (p as { path?: string }).path,\n language: (p as { language?: string | null }).language,\n pageType: p.pageType,\n status: p.status,\n // Held back from whole-site publishes: only when set, so an unheld list stays the same size.\n ...((p as { publishHeldAt?: string | null }).publishHeldAt ? { publishHeldAt: (p as { publishHeldAt?: string }).publishHeldAt } : {}),\n fields: p.fields,\n })),\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_page\",\n config: {\n title: \"Get a page (with its field schema)\",\n description:\n \"Get one page INCLUDING its full field schema (keys, types, nested group/repeater children), pageType, `path` and `language`. A field with `stale: true` is one the build no longer renders: kept, hidden in the editor. Read this before set_page_content so you write correctly-keyed values, or before add_field so you know the existing keys.\",\n inputSchema: getPageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getPageInput>) =>\n withClient(async (client) => {\n const page = await client.getPage(args.pageId);\n return ok(\n `Page '${page.title}' (${page.pageType ?? \"page\"}, ${page.fields.length} field(s)).`,\n page,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_page\",\n config: {\n title: \"Create a page\",\n description:\n \"Create a page with its own typed schema. Supports pageType 'singleton' (exactly one entry — Home, About, Contact) and 'dynamic' (many entries sharing the schema — Blog posts, Products). Project-scoped from the key. Additive — does not delete or overwrite existing pages. FIRST read the page's real markup and DECOMPOSE it into a destructured tree: each visual section becomes a nested field — a fixed grouped block → type 'group', a repeating list of items (cards, testimonials, features, FAQs) → type 'repeater' — each carrying its own child `fields`. Do NOT flatten sections into many flat top-level fields. Build the full nested tree, then call this once. 🔴 Every field key must be UNIQUE ACROSS THE WHOLE TREE — the namespace is flat, so 'title' cannot appear in two sections; prefix each with its section ('hero_title', 'faq_title'). Prose fields (headings, body copy, descriptions) are created as RICH TEXT by default; pass richText:false for values that must stay bare strings — hrefs, slugs, ids, emails. That tree is the page's SCHEMA — what it holds. \" +\n DOCTRINE,\n inputSchema: createPageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createPageInput>) =>\n withClient(async (client) => {\n // A create has no \"before\", so any collision is new. This is THE path that produced the\n // marketing page's six duplicate rows.\n const dupes = duplicateKeys(flatFieldKeys(args.fields));\n if (dupes.length > 0) return fail(duplicateKeyFailure(dupes));\n const page = await client.createPage({\n title: args.title,\n slug: args.slug,\n pageType: args.pageType ?? \"singleton\",\n ...(args.blockJson ? { blockJson: args.blockJson } : {}),\n // Cast: the SDK's ContentModelField types `options` as string[], narrower than the API,\n // which also takes {label, value} (backend selectFieldSchema).\n ...(args.fields ? { fields: args.fields.map(toField) as CreateManagedPageInput[\"fields\"] } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n ...(args.metaTitle !== undefined ? { metaTitle: args.metaTitle } : {}),\n ...(args.metaDescription !== undefined ? { metaDescription: args.metaDescription } : {}),\n ...(args.locale !== undefined ? { locale: args.locale } : {}),\n ...(args.translationOf !== undefined ? { translationOf: args.translationOf } : {}),\n } as CreateManagedPageInput);\n const { warnings, seedErrors, ...created } = page;\n const summary = `Created ${created.pageType ?? \"page\"} page '${created.title}' (id ${created.id}, slug ${created.slug}) with ${created.fields.length} field(s).`;\n // In the SUMMARY, where it is read, not buried in the page JSON: a create that dropped\n // its values reads as complete success otherwise.\n const notes = [\n ...(warnings ?? []),\n ...(seedErrors ? Object.entries(seedErrors).map(([key, why]) => ` ${key}: ${why}`) : []),\n ];\n return ok(notes.length ? `${summary}\\n${notes.join(\"\\n\")}` : summary, created);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_content_model\",\n config: {\n title: \"Create a content model (reusable schema)\",\n description:\n \"Create a content model — a reusable schema for a dynamic collection (Blog, Products, Testimonials). \" + PAGES_NOT_COLLECTIONS_NOTE + \" `fields` may NEST: type 'group' = one nested object of child fields; type 'repeater' = a repeatable array of child objects. Put child fields in each group/repeater's own `fields` (any depth). Pass kind:'block' to create a BLOCK type instead — see that argument. `fieldsets` ([{id, name}]) are the model's editor cards; a field joins one with `fieldsetId`. The slug must be unique in this project and branch: a taken one is refused with 409 `slug_taken` and free `suggestions`. \" +\n RICH_TEXT_NOTE,\n inputSchema: createModelInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createModelInput>) =>\n withClient(async (client) => {\n const modelDupes = duplicateKeys(flatFieldKeys(args.fields));\n if (modelDupes.length > 0) return fail(duplicateKeyFailure(modelDupes));\n const input = {\n name: args.name,\n slug: args.slug,\n ...(args.description !== undefined ? { description: args.description } : {}),\n ...(args.urlPattern !== undefined ? { urlPattern: args.urlPattern } : {}),\n ...(args.kind !== undefined ? { kind: args.kind } : {}),\n ...(args.fieldsets !== undefined ? { fieldsets: dropProvenance(args.fieldsets) as CreateModelInput[\"fieldsets\"] } : {}),\n fields: toFields(args.fields) as CreateModelInput[\"fields\"],\n };\n if (args.dryRun) return dryRunOf(client, \"POST\", `/management/content/models`, input);\n const model = await client.createModel(input);\n return ok(\n `Created content model '${model.name}' (${model.fields.length} field(s)).`,\n model,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"add_field\",\n config: {\n title: \"Add a field to a content model or a page\",\n description: ADD_FIELD_DESCRIPTION + \" \" + V2_LEAF_TYPES_NOTE + \" \" + RICH_TEXT_NOTE,\n inputSchema: addFieldInput.shape,\n },\n handler: guard(async (args: z.infer<typeof addFieldInput>) =>\n withClient(async (client) => {\n if (!args.modelId === !args.pageId) return fail(\"Pass exactly one of modelId (a content model) or pageId (a page).\");\n // The append routes validate where the field would be written, and store nothing.\n if (args.dryRun) {\n return dryRunOf(\n client,\n args.pageId ? \"PATCH\" : \"POST\",\n args.pageId ? `/management/pages/${args.pageId}` : `/management/content/models/${args.modelId}/fields`,\n { addFields: [toField(args)], ...(args.after !== undefined ? { after: args.after } : {}) },\n confirmedHeaders(args.confirmed),\n );\n }\n if (args.pageId) {\n // No client-side preflight for a page: `addPageFields` is an additive PATCH onto the\n // page-fields route, which refuses a flat-namespace collision itself and splices\n // `after` under the lock it already takes — a check here would be a second authority.\n const input = {\n // Cast: the SDK types `options` as string[], narrower than the API, which also takes\n // {label, value} (backend selectFieldSchema).\n addFields: [toField(args)] as AddPageFieldsInput[\"addFields\"],\n ...(args.after !== undefined ? { after: args.after } : {}),\n };\n // An approved custom input: client.addPageFields's own request plus the header it cannot send.\n const page = args.confirmed === true\n ? (await client.fetchJSON<{ data: Awaited<ReturnType<typeof client.addPageFields>> }>(client.url(`/management/pages/${args.pageId}`), {\n method: \"PATCH\",\n body: JSON.stringify(input),\n headers: confirmedHeaders(true),\n })).data\n : await client.addPageFields(args.pageId, input);\n return ok(`Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).${autoHelpNote(args)}`, page);\n }\n const modelId = args.modelId!;\n const model = await client.getModel(modelId);\n // 🔴 Was `model.fields.some(...)` — TOP LEVEL ONLY, so a key colliding with a group's\n // child sailed through. The namespace is flat; the check has to be too.\n const dupes = duplicateKeys([...flatFieldKeys(model.fields), args.key]);\n if (dupes.length > 0) return fail(duplicateKeyFailure(dupes));\n // `after` splices client-side here because this tool already holds the whole array\n // (it is a read-modify-write via updateModel, not the additive append route). An\n // unknown key FAILS instead of falling back to append: a silent append is how an\n // agent \"succeeds\" at putting a field somewhere it is not.\n const existingFields = model.fields as unknown[];\n let at = existingFields.length;\n if (args.after !== undefined) {\n const idx = existingFields.findIndex(\n (f) => (f as { key?: string }).key === args.after,\n );\n if (idx === -1) {\n return fail(\n `after: '${args.after}' is not a top-level field on this model. Valid keys: ` +\n `${existingFields.map((f) => `'${(f as { key?: string }).key}'`).join(\", \")}. ` +\n `Omit \\`after\\` to append at the end.`,\n );\n }\n at = idx + 1;\n }\n const nextFields = [...existingFields];\n nextFields.splice(at, 0, toField(args) as unknown);\n // The whole array goes back, so it carries every field's `ui`: a model where any field has a\n // dock icon / item label / group needs If-Match (428 without it). Send the version this\n // read-modify-write is based on, which also turns a concurrent edit into a 409, not a lost write.\n const input = { fields: nextFields as Parameters<typeof client.updateModel>[1][\"fields\"] };\n const opts = model.optimisticVersion !== undefined ? { ifMatch: model.optimisticVersion } : undefined;\n // An approved custom input: client.updateModel's own request plus the header it cannot send.\n const updated = args.confirmed === true\n ? (await client.fetchJSON<{ data: Awaited<ReturnType<typeof client.updateModel>> }>(client.url(`/management/content/models/${modelId}`), {\n method: \"PATCH\",\n body: JSON.stringify(input),\n headers: { ...(opts ? { \"If-Match\": `W/\"${opts.ifMatch}\"` } : {}), ...confirmedHeaders(true) },\n })).data\n : opts ? await client.updateModel(modelId, input, opts) : await client.updateModel(modelId, input);\n return ok(\n `Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : \"\"}. Model now has ${updated.fields.length} field(s).${autoHelpNote(args)}`,\n updated,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_content_entry\",\n config: {\n title: \"Create a content entry\",\n description:\n \"Create a content entry under a model. \" + PAGES_NOT_COLLECTIONS_NOTE + \" Pass its field VALUES in `data`, keyed by field key — INCLUDE ALL REQUIRED FIELDS (create validates them). New entries are drafts; pass status:'published' to take it live. Read get_content_model first for the field keys and which are required. One entry per call: for volume, run code against the Management API.\",\n inputSchema: createEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createEntryInput>) =>\n withClient(async (client) => {\n // One-shot create WITH data — the create route validates required fields, so\n // splitting into create-empty-then-update 400s for any model with a required\n // field. Status is draft-only on create server-side, so publishing needs a\n // follow-up update.\n const input = {\n contentModelId: args.contentModelId,\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n // The SDK's input type predates localization; its body is the input as given.\n ...(args.locale !== undefined ? { locale: args.locale } : {}),\n ...(args.translationOf !== undefined ? { translationOf: args.translationOf } : {}),\n ...(args.externalKey !== undefined ? { externalKey: args.externalKey, source: args.source, runId: args.runId } : {}),\n } as CreateEntryInput;\n if (args.dryRun) return dryRunOf(client, \"POST\", `/management/content/entries`, input);\n const created = await client.createEntry(input);\n const published =\n args.status !== undefined && args.status !== \"draft\"\n ? await client.updateEntry(created.id, { status: args.status })\n : created;\n // Advisory notes from either write (a reference to a deleted entry) go in the summary,\n // not the entry JSON.\n const { warnings, ...entry } = published;\n const notes = [...new Set([...(created.warnings ?? []), ...(warnings ?? [])])];\n return ok(\n // With an external key the write may have updated the entry, or left it unchanged.\n [`${args.externalKey ? \"Stored\" : \"Created\"} entry '${entry.slug}' (id ${entry.id}, status ${entry.status}).`, ...notes].join(\"\\n\"),\n entry,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"set_page_content\",\n config: {\n title: \"Set a page's field values (content)\",\n description:\n \"Set a page's field VALUES — the actual content. For a SINGLETON page (Home, About, Site Settings) this creates or updates its one entry, so call it again to edit. `data` is keyed by field key: a nested 'array' (zone) value is an OBJECT { nonRepeatable: { childKey: value }, repeatable: [ { childKey: value } ] }; a primitive 'array' is a plain list; an 'image' value is an asset URL or { url, altText?, focal?, crop? } — focal {x,y} and crop {top,right,bottom,left} (0–1, cut from each edge) frame THIS placement only. Read the schema first with get_page. This is how you populate Home/About/Settings — create_content_entry is for dynamic collections only. Merges by top-level key (a zone value replaces that whole zone); pass replace:true to remove omitted fields.\",\n inputSchema: setPageContentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof setPageContentInput>) =>\n withClient(async (client) => {\n const entry = await client.setPageContent(args.pageId, {\n data: args.data,\n ...(args.status !== undefined ? { status: args.status } : {}),\n ...(args.replace !== undefined ? { replace: args.replace } : {}),\n });\n return ok(\n `Set content on page ${args.pageId} (entry ${entry.id}, status ${entry.status}).`,\n entry,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"list_content_entries\",\n config: {\n title: \"List content entries (incl. drafts)\",\n description:\n \"List content entries — including drafts — 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) — read values with get_content_entry, or pass `detail: true` for full rows.\",\n inputSchema: listEntriesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listEntriesInput>) =>\n withClient(async (client) => {\n // The SDK's filter has no summary, limit, where, sort or page; the route does, so the read\n // goes straight through the client's request plumbing, with the query built by the helper\n // the hosted catalogue uses too.\n const res = await client.fetchJSON<{ data: unknown[]; meta?: { page: number; totalPages: number; total: number } }>(\n client.url(`/management/content/entries${entryListSearch(args)}`),\n { method: \"GET\" },\n );\n const paged = res.meta ? ` Page ${res.meta.page} of ${res.meta.totalPages} (${res.meta.total} in all).` : \"\";\n return ok(`${res.data.length} entr(y/ies).${paged}`, res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_content_entry\",\n config: {\n title: \"Get a content entry (with its values)\",\n description: \"Get one content entry by id INCLUDING its `data` (field values), even when draft.\",\n inputSchema: getEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getEntryInput>) =>\n withClient(async (client) => {\n const entry = await client.getEntry(args.entryId);\n return ok(`Entry '${entry.slug}' (id ${entry.id}, status ${entry.status}).`, entry);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_content_entry\",\n config: {\n title: \"Update a content entry's values\",\n description:\n \"Update a content entry's `data` (field values) and/or status by id. `data` is keyed by field key; a nested 'array' (zone) value is an object { nonRepeatable: {…}, repeatable: [{…}] }, a primitive 'array' is a plain list; an image value may carry this placement's focal {x,y} and crop {top,right,bottom,left} (0–1). Use this to edit an existing entry; for a singleton page prefer set_page_content. `data` MERGES into the stored values by top-level key: a field you leave out is kept, null clears one, and a group or repeater value replaces that whole key. 🔴 merge:false REPLACES the whole value object instead: an optional field you leave out is DELETED, and a required one you leave out fails the whole write. \" + FIELD_LOCKED_NOTE + \" \" + ENTRY_META_NOTE,\n inputSchema: updateEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateEntryInput>) =>\n withClient(async (client) => {\n // merge (the default): read, lay `data` over the stored keys, write at the version read.\n const write =\n mergesEntry(args)\n ? planEntryMerge(await client.getEntry(args.entryId), args.data!, args.ifMatch)\n : { data: args.data, ifMatch: args.ifMatch };\n const input = {\n ...(write.data !== undefined ? { data: write.data } : {}),\n ...(args.status !== undefined ? { status: args.status } : {}),\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.meta !== undefined ? { meta: args.meta } : {}),\n // Not on the SDK's input type yet; the route accepts both (null cancels).\n ...(args.scheduledAt !== undefined ? { scheduledAt: args.scheduledAt } : {}),\n ...(args.unpublishAt !== undefined ? { unpublishAt: args.unpublishAt } : {}),\n ...(args.locale !== undefined ? { locale: args.locale } : {}),\n ...(args.translationOf !== undefined ? { translationOf: args.translationOf } : {}),\n } as UpdateEntryInput;\n const { warnings, ...entry } =\n write.ifMatch === undefined\n ? await client.updateEntry(args.entryId, input)\n : await client.updateEntry(args.entryId, input, { ifMatch: write.ifMatch });\n return ok([`Updated entry '${entry.slug}' (id ${entry.id}, status ${entry.status}).`, ...(warnings ?? [])].join(\"\\n\"), entry);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"upload_asset\",\n config: {\n title: \"Upload an asset to the Media Library\",\n description:\n \"Upload an image/asset from a local file path or a remote URL into the project's Media Library, or have the server fetch a public `sourceUrl` itself. Returns the asset's stable CDN URL — put that URL into a content entry's image field. Use this BEFORE creating entries that reference images.\",\n inputSchema: uploadAssetInput.shape,\n },\n handler: guard(async (args: z.infer<typeof uploadAssetInput>) =>\n withClient(async (client) => {\n const asset = args.sourceUrl && !args.localPath && !args.url\n ? ((await client.fetchJSON<{ data: UploadedAsset }>(client.url(`/management/media/import`), {\n method: \"POST\",\n body: JSON.stringify({ url: args.sourceUrl, altText: args.altText, caption: args.caption, folderId: args.folderId }),\n })).data)\n : await client.uploadAsset(args);\n return ok(\n `Uploaded '${asset.filename}' (id ${asset.id}). Put this URL (or the id ${asset.id}) into an image field to attach it: ${asset.url}`,\n asset,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"delete_page\",\n config: {\n title: \"Delete a page\",\n description:\n \"DELETE a page and its content. Destructive but REVERSIBLE — it soft-deletes (can be restored from the dashboard) and is audit-logged. Use it to remove a page you created by mistake. Confirm with the user before deleting content they may want.\" +\n DELETE_PAGE_RUNTIME_BUNDLE,\n inputSchema: deletePageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deletePageInput>) =>\n withClient(async (client) => {\n if (!args.pageId === !args.runtimeBundle) return fail(\"Pass exactly one of pageId or runtimeBundle.\");\n if (args.runtimeBundle) {\n const res = await client.fetchJSON<{ data?: unknown }>(client.url(\"/management/pages/retire-runtime-bundle\"), {\n method: \"POST\",\n body: JSON.stringify({ dryRun: args.runtimeBundle !== \"apply\" }),\n });\n return ok(args.runtimeBundle === \"apply\" ? \"Bundle pages retired.\" : \"Bundle pages (dry run, nothing written).\", res.data);\n }\n const res = await client.deletePage(args.pageId!);\n return ok(`Deleted page ${res.id} (soft-delete — restorable from the dashboard).`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"delete_content_entry\",\n config: {\n title: \"Delete a content entry\",\n description:\n \"DELETE a single content entry. Destructive but REVERSIBLE (soft-delete, restorable from the dashboard) and audit-logged. Use it to remove content created by mistake.\",\n inputSchema: deleteEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deleteEntryInput>) =>\n withClient(async (client) => {\n const res = await client.deleteEntry(args.entryId);\n return ok(`Deleted entry ${res.id} (soft-delete — restorable from the dashboard).`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"delete_content_model\",\n config: {\n title: \"Delete a content model\",\n description:\n \"DELETE a content model and its entries. Destructive but REVERSIBLE (soft-delete, restorable from the dashboard) and audit-logged. Confirm with the user first — this removes all content under the model.\",\n inputSchema: deleteModelInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deleteModelInput>) =>\n withClient(async (client) => {\n const res = await client.deleteModel(args.modelId);\n return ok(`Deleted content model ${res.id} and its entries (soft-delete — restorable from the dashboard).`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n // ── Forms (read-only — discover dashboard forms to embed into the site) ──\n {\n name: \"list_forms\",\n config: {\n title: \"List forms in the current project\",\n description:\n \"List the forms built in the dashboard for the bound project — each with its id, name, and field schema. Use it to find a form to add to the user's site: read it, then write `<BcmsForm form={getForm('Name')} />` (from @bettercms-ai/next) into the page/component where the user wants it.\",\n inputSchema: {},\n },\n handler: guard(async () =>\n withClient(async (client) => {\n const forms = await client.listForms();\n return ok(\n `${forms.length} form(s) in the bound project.`,\n forms.map((f) => ({ id: f.id, name: f.name, fields: f.fields })),\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_form\",\n config: {\n title: \"Get a form (with its field schema)\",\n description:\n \"Get one form by id INCLUDING its fields (keys, types, required, options, showIf) and settings (submitLabel, successMessage, redirectUrl, turnstileEnabled, honeypotField). Read this before wiring `<BcmsForm>` so you render the right fields.\",\n inputSchema: getFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getFormInput>) =>\n withClient(async (client) => {\n const form = await client.getForm(args.formId);\n return ok(`Form '${form.name}' (${form.fields.length} field(s)).`, form);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_form\",\n config: {\n title: \"Create a form\",\n description:\n \"Create a form in the connected project from a field schema. Confirm the fields with the user first. Field types: text, email, textarea, select (needs options), radio (needs options), checkboxes (needs options), checkbox, number, phone, date, url, consent, hidden, step (a divider: the fields after it are one page). Returns the new form's id. It lands as a DRAFT; call publish_form before embedding (a draft form returns 403 on submit). Embed it with `<BcmsForm form={getForm('Name')} />` from @bettercms-ai/next.\",\n inputSchema: createFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createFormInput>) =>\n withClient(async (client) => {\n const form = await client.createForm(args as ManagedFormInput);\n return ok(`Created form '${form.name}' (id ${form.id}). Embed with <BcmsForm form={getForm('${form.name}')} />.`, form);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_form\",\n config: {\n title: \"Update a form\",\n description:\n \"Update a form by id — name, fields, or settings. Read get_form first. Passing `fields` REPLACES the array (include all fields to keep).\",\n inputSchema: updateFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateFormInput>) =>\n withClient(async (client) => {\n const { formId, ...input } = args;\n const form = await client.updateForm(formId, input as ManagedFormInput);\n return ok(`Updated form '${form.name}' (id ${form.id}).`, form);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"publish_form\",\n config: {\n title: \"Publish a form\",\n description:\n \"Publish a form by id so it accepts submissions. create_form and update_form only ever write a DRAFT, and a draft form answers every submit with 403 — call this before embedding it with `<BcmsForm form={getForm('Name')} />`. It re-bakes the project's site; `meta.rebuildQueued` says whether a rebuild was actually queued (false for a project with no connected source). 403 PUBLISH_NOT_GRANTED means this connection may author but not publish: say so and let the user publish from the dashboard Forms tab. 404 means the form is not in this connection's project.\",\n inputSchema: getFormInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getFormInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data?: { name?: string }; meta?: unknown }>(\n client.url(`/management/forms/${args.formId}/publish`),\n { method: \"POST\" },\n );\n return ok(`Published form '${res.data?.name ?? args.formId}'.`, res);\n }),\n ) as ToolDef[\"handler\"],\n },\n // ── Project/page Layout (draft commands + Global Layout publish; page overrides publish with the page) ──\n {\n name: \"get_layout\",\n config: {\n title: \"Get the project or page Layout\",\n description: \"Read the Global Layout or one page's Layout override, including its optimistic revision. Always read this before update_layout. copy:'published' reads the published copy — the only honest receipt for a publish claim.\",\n inputSchema: getLayoutInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getLayoutInput>) => withClient(async (client) => {\n const layout = await client.getManagedLayout(args);\n return ok(`${layout.scope === \"global\" ? \"Global\" : `Page ${layout.pageSlug}`} Layout ${args.copy === \"published\" ? \"PUBLISHED copy\" : \"draft\"} at revision ${layout.revision}.`, layout);\n })) as ToolDef[\"handler\"],\n },\n {\n name: \"update_layout\",\n config: {\n title: \"Apply Layout draft commands\",\n description: \"Apply permission-shaped values/composition/schema commands to the Global Layout or a page override. Draft-only: this never publishes. Pass the revision from get_layout as ifMatch. ONE command in `command`, or an ordered batch in `commands` (prefer the batch for more than three of anything — placing site chrome is add-section, add-component and set-bindings in sequence): each command is applied against the revision the previous one RETURNED, so you do not re-read get_layout between them. A batch stops at the first failure and tells you how many were applied and the revision it stopped at — the earlier ones stand, because a Layout command is not a transaction. \" + LAYOUT_LOCK_NOTE,\n inputSchema: commandLayoutInput.shape,\n },\n handler: guard(async (args: z.infer<typeof commandLayoutInput>) => withClient(async (client) => {\n const queued = args.commands ?? (args.command ? [args.command] : []);\n if (queued.length === 0) return fail(\"Pass `command` (one) or `commands` (an ordered batch).\");\n if (args.commands && args.command) return fail(\"Pass `command` or `commands`, not both — the order of the two would be undefined.\");\n\n let revision = args.ifMatch;\n let layout: Awaited<ReturnType<ManagementApi[\"commandManagedLayout\"]>> | undefined;\n const applied: Array<{ type: string; revision: number }> = [];\n for (const command of queued) {\n try {\n layout = await client.commandManagedLayout({\n scope: args.scope,\n pageId: args.pageId,\n projectId: args.projectId,\n command: command as ManagementLayoutCommand,\n ifMatch: revision,\n });\n } catch (err) {\n // 🔴 Report what LANDED. The commands before this one are already in the draft, and an\n // agent told only \"it failed\" re-runs the whole batch and duplicates every one of them.\n return fail(\n `Layout command ${applied.length + 1} of ${queued.length} (${command.type}) failed: ${errorText(err)}. ` +\n `${applied.length} command(s) were applied and remain in the draft; the Layout is at revision ${revision}. ` +\n `Re-read get_layout and continue from command ${applied.length + 1}.`,\n );\n }\n revision = layout.revision;\n applied.push({ type: command.type, revision });\n }\n const where = layout!.scope === \"global\" ? \"Global\" : `Page ${layout!.pageSlug}`;\n return ok(\n `Applied ${applied.length} command(s) to the ${where} Layout draft; now at revision ${revision}.`,\n { applied, revision, layout },\n );\n })) as ToolDef[\"handler\"],\n },\n {\n name: \"publish_layout\",\n config: {\n title: \"Publish the Global Layout draft\",\n description: \"Publish the connected project's GLOBAL Layout draft (navigation, footer, every reserved section). On a site BetterCMS serves, a Layout publish never builds: it writes the VALUES into the live pages, and a STRUCTURE change (Sections added, removed, moved) waits for a Rebuild or a push (`layout-rebuild-required`); a custom host gets its deploy hook. Until published, get_layout copy:'published' answers PUBLISHED_LAYOUT_UNAVAILABLE. Pass get_layout's `revision` as ifMatch; a stale one returns 409 — re-read, never retry blindly. A 422 lists validation issues (global, or per page override: pageSlug, copy) to fix with update_layout. A new project's chrome is draft: publish_component navigation-default and footer-default first (the order and the optional logo: skill components). Verify with get_layout copy:'published' — this response is the write's echo, not a receipt. Page Layout overrides go live with the page (update_page status:'published'). 403 PUBLISH_NOT_GRANTED: this connection may author drafts, not publish — say so; the user allows it or publishes from the dashboard.\",\n inputSchema: publishLayoutInput.shape,\n },\n handler: guard(async (args: z.infer<typeof publishLayoutInput>) => withClient(async (client) => {\n const layout = await client.publishManagedLayout(args);\n return ok(`Published the Global Layout at revision ${layout.revision} (copy: published). Verify with get_layout copy:'published'.`, layout);\n })) as ToolDef[\"handler\"],\n },\n // ── Components (discover + author reusable symbols) ──\n {\n name: \"list_components\",\n config: {\n title: \"List reusable components\",\n description: \"List the reusable components in the bound project. By DEFAULT this is the catalogue: id, name, slug, category, `sectionType` (the section family — a component with none is not in the editor's 'Add a section' picker), `status` ('draft' renders as NOTHING on the live site), and the `group` an editor browses it under, plus the locked `builtin:*` blueprints. It deliberately does NOT carry block trees: the full list carries every component's draft AND live `blockJson`, which is the largest response this API produces, and one component's definition is what `get_component` is for. Pass `detail: true` for the old full shape when you genuinely need every definition at once (rendering with `<BcmsBlocks>` from @bettercms-ai/next).\",\n inputSchema: listComponentsInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listComponentsInput>) =>\n withClient(async (client) => {\n // 🔴 The SUMMARY shape is chosen HERE, in the MCP tool, not on the server's default.\n // The route keeps its full shape for the renderers already reading it; what changes is\n // what an AGENT gets, which is the caller that never wanted the block trees and the one\n // whose context the response floods.\n if (args.detail) {\n const list = await client.listComponents();\n return ok(`${list.length} component(s) in the bound project (full definitions).`, list);\n }\n const list = await client.listComponents({ select: \"summary\" });\n return ok(\n `${list.length} component(s) in the bound project.`,\n list.map((cmp) => ({\n id: cmp.id,\n name: cmp.name,\n slug: cmp.slug,\n category: cmp.category,\n sectionType: cmp.sectionType,\n status: cmp.status,\n group: cmp.groupName,\n ...(cmp.builtin ? { builtin: true } : {}),\n })),\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_component\",\n config: {\n title: \"Get a component (with its blockJson)\",\n description: (\"One component with its blockJson and props (stored `ui` on them; `stale: true` = no placement renders it). Read it before update_component to keep its blocks, and after declaring field UI: a prop absent here was not stored.\") + \" \" + VARIANT_GROUP_NOTE,\n inputSchema: getComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getComponentInput>) =>\n withClient(async (client) => {\n if (args.detachedCopy) {\n const res = await client.fetchJSON<{ data: { name: string; fields: unknown } }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/detached-copy`),\n { method: \"POST\", body: JSON.stringify(args.detachedCopy) },\n );\n return ok(`A separate copy of '${res.data.name}': store \\`fields\\` on the embed.`, res.data);\n }\n const cmp = await client.getComponent(args.componentId);\n return ok(`Component '${cmp.name}' (${cmp.blockJson.length} block(s)).`, cmp);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"create_component\",\n config: {\n title: \"Create a reusable component\",\n description: (\"Create a reusable component from a blockJson tree. THIS IS ALSO HOW A PAGE GETS ITS SECTIONS: set `sectionType` (e.g. 'Hero') and the component becomes a placeable section, selectable in the editor's 'Add a section' picker. Components sharing a `sectionType` are its layout VARIANTS — one Hero with a 'Centered' and a 'Two-column' variant, same prop keys, so a swap keeps the content. CONFIRM the structure with the user first. blockJson is an array of blocks — the same set create_page accepts (heading, text/richtext, image, button, spacer, video, columns, section, slider, tabs, navbar, footer, form, component, collection), NOT a narrower one; `section` nests child blocks in props.children and `columns` in props.columns. `props` declares overridable fields. Returns the new id — render with `<BcmsBlocks>`. Always lands as a DRAFT — call publish_component to put it on the live site; until then it renders as NOTHING there, with no error. Buttons auto-join the project's Button family; section buttons link to its looks.\" +\n DOCTRINE) + \" \" + UNPROPPED_COPY_NOTE,\n inputSchema: createComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createComponentInput>) =>\n withClient(async (client) => {\n const cmp = await client.createComponent(args as ManagedComponentInput);\n return ok(`Created component '${cmp.name}' (id ${cmp.id}, slug ${cmp.slug}).`, cmp);\n }),\n ) as ToolDef[\"handler\"],\n },\n /**\n * ── The batch three ──────────────────────────────────────────────────────\n *\n * Sequential SDK calls with PER-ITEM receipts, and no new server route: the throughput\n * problem is one round trip per component, not one query per component, and inventing a bulk\n * endpoint would duplicate every validation, warning and governance gate the single writes\n * already run. A whole-site componentize run is forty creates, a dozen page compositions and\n * forty publishes; as individual tool calls that is a hundred turns of an agent's context\n * spent on plumbing.\n *\n * 🔴 NOTHING STOPS THE RUN. A batch that aborts on item 31 has already written 30 rows that\n * no receipt mentions, and the agent's only safe move is to re-run it and duplicate them.\n * Every item reports its own outcome instead, and the summary line says how many failed.\n */\n {\n name: \"publish_components\",\n config: {\n title: \"Publish many components in one call\",\n description:\n \"Publish up to 100 components in ONE call — the same act as publish_component, once per item, copying each DRAFT definition to the live copy. Each item reports `{ ok, status, error, readiness }` and a failure never stops the run. 🔴 A 409 COMPONENT_IMPLEMENTATION_NOT_READY is NOT retried: only the owner, in the dashboard, clears it (publish_component says when); relay the item's `readiness` to the user as what only they can approve. 403 PUBLISH_NOT_GRANTED means this connection may author but not publish; 422 means the publish would break a Layout, and the item names which.\",\n inputSchema: publishComponentsInput.shape,\n },\n handler: guard(async (args: z.infer<typeof publishComponentsInput>) =>\n withClient(async (client) => {\n const results: Array<Record<string, unknown>> = [];\n for (const componentId of args.componentIds) {\n try {\n const res = await client.fetchJSON<{ data?: { status?: string; slug?: string } }>(\n client.url(`/management/components/${componentId}/publish`),\n { method: \"POST\" },\n );\n results.push({ ok: true, componentId, slug: res.data?.slug, status: res.data?.status ?? \"published\" });\n } catch (err) {\n // The 409 body carries the whole readiness tuple — which evidence is missing, and\n // whether it is now waiting on a person. That is the difference between \"publish\n // failed\" and a sentence the user can act on.\n const readiness = (apiError(err)?.body as { readiness?: unknown } | undefined)?.readiness;\n results.push({\n ok: false,\n componentId,\n error: errorText(err),\n ...(readiness ? { readiness } : {}),\n });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n return ok(\n `Published ${results.length - failed} of ${args.componentIds.length} component(s)${failed ? `; ${failed} could not be published — read each item's error and readiness, and tell the user which ones need THEIR approval in the dashboard` : \"\"}.`,\n results,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"compose_pages\",\n config: {\n title: \"Set many pages' block composition in one call\",\n description:\n \"Give up to 50 pages their block composition in ONE call — the same write as update_page's `blockJson`, once per item, and it REPLACES each page's whole block array. Address a page by `pageId` or by `slug`. Each item reports `{ ok, pageId, slug, error }` and a failure does not stop the run. BEFORE writing anything it reads this project's component catalogue once and REFUSES any item placing a componentId the project does not have — its missing sections would render as empty strings with no error anywhere. Writes DRAFTS: publish each page with update_page status:'published' afterwards. \" +\n \"A page is composed of SECTIONS: a recurring band is a component with a `sectionType`, a one-off band is a `section` block whose `props.children` hold its blocks — never loose top-level heading/text/image blocks, which no editor can move, name or swap as a unit. The full doctrine is in the bettercms://playbook/schema resource, §12.\",\n inputSchema: composePagesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof composePagesInput>) =>\n withClient(async (client) => {\n const known = await client.listComponents({ select: \"summary\" });\n const ids = new Set(known.map((c) => c.id));\n\n const results: Array<Record<string, unknown>> = [];\n for (const page of args.pages) {\n const ref = page.pageId ?? page.slug;\n if (!ref) {\n results.push({ ok: false, error: \"Pass a pageId or path from list_pages.\" });\n continue;\n }\n let pageId: string;\n try {\n pageId = await pageIdOf(client, ref);\n } catch (err) {\n results.push({ ok: false, slug: page.slug, error: errorText(err) });\n continue;\n }\n const unknown = [...new Set(componentIdsIn(page.blockJson))].filter((id) => !ids.has(id));\n if (unknown.length) {\n results.push({\n ok: false,\n pageId,\n slug: page.slug,\n error: `Refused: this page places component id(s) this project does not have — ${unknown.join(\", \")}. A missing component renders as an empty string with no error, so nothing was written for this page.`,\n });\n continue;\n }\n try {\n const written = await client.fetchJSON<{ data?: { id?: string; slug?: string; path?: string }; held?: string; holds?: unknown[] }>(\n client.url(`/management/pages/${pageId}/meta`),\n { method: \"PATCH\", body: JSON.stringify({ blockJson: page.blockJson, ...(args.dryRun ? { dryRun: true } : {}) }) },\n );\n results.push({ ok: true, ...(args.dryRun ? { status: \"would-update\" } : {}), pageId, slug: written.data?.slug ?? page.slug, path: written.data?.path, blocks: page.blockJson.length, ...(written.held ? { held: written.held } : {}), ...(written.holds?.length ? { holds: written.holds } : {}) });\n } catch (err) {\n results.push({ ok: false, pageId, slug: page.slug, error: errorText(err) });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n if (args.dryRun) {\n return ok(DRY_RUN_SUMMARY, { dryRun: true, results, wouldCompose: results.length - failed, failed });\n }\n // A held page leads, by name: its draft is saved and its live page will not show the change.\n const held = results.filter((r) => typeof r.held === \"string\");\n const lead = held.length ? `HELD on ${held.length} of ${args.pages.length} page(s). ${held.map((r) => `${String(r.slug ?? r.pageId)}: ${String(r.held)}`).join(\" \")}\\n` : \"\";\n return ok(\n `${lead}Composed ${results.length - failed} of ${args.pages.length} page(s)${failed ? `; ${failed} failed — see the per-item errors` : \"\"}. These are page DRAFTS: publish each with update_page status:'published'. Then call get_site_composition for the receipt.`,\n results,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"list_extraction_candidates\",\n config: {\n title: \"Find sections that repeat across pages\",\n description:\n \"Find sections that appear IDENTICALLY (same structure and styling, different wording) on 3+ places across this project's pages, each proposed as one reusable component. Read-only — nothing changes. Returns a `hash` per candidate to pass to extract_component, plus how many places it appears, which fields differ between copies, and the exact pages involved. Use this before hand-building a component with create_component: if a section already repeats, extracting it is better than adding a 4th copy.\",\n inputSchema: listExtractionCandidatesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listExtractionCandidatesInput>) =>\n withClient(async (client) => {\n const found = await client.listExtractionCandidates(args.projectId);\n if (found.length === 0) {\n return ok(\"No section repeats on 3 or more pages in this project.\", found);\n }\n const lines = found.map(\n (c) => `- ${c.suggestedName} (hash ${c.hash}) — ${c.uses} places, ${c.props.length} varying field(s)`,\n );\n return ok(`${found.length} repeated section(s):\\n${lines.join(\"\\n\")}`, found);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"extract_component\",\n config: {\n title: \"Extract a repeated section into one component\",\n description:\n \"Fold one candidate from list_extraction_candidates into a single reusable component and repoint EVERY occurrence at it. CONFIRM WITH THE USER FIRST — this rewrites blocks on several pages at once, and name the pages from the candidate's `sites` when you ask. Only page DRAFTS change: the live site is untouched until those pages are published, and the component itself lands as a DRAFT. Fields that differ between copies become component props, so each page keeps its own wording. 409 means the sections were edited since you listed them — re-run list_extraction_candidates and ask again.\",\n inputSchema: extractComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof extractComponentInput>) =>\n withClient(async (client) => {\n const res = await client.extractComponent(args);\n const { component, replaced } = res;\n // The kit entry the matcher SUGGESTS (never recorded; SDK minor, an older SDK build has none to pass on).\n const kit = (res as { kit?: { suggested: string | null; score: number | null; link: string; line: string } }).kit;\n return ok(\n `Created component '${component.name}' (id ${component.id}) and repointed ${replaced} sections to it. Page drafts changed; publish those pages to make it live.${kit?.line ? ` ${kit.line}: only a suggestion, so check its htmlSignals and pitfalls, then confirm or replace it with update_component { kitEntry }.` : \"\"}`,\n { ...component, ...(kit ? { kit } : {}), nextAction: DOCK_UI_NEXT },\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_component\",\n config: {\n title: \"Update a reusable component\",\n description: (\"Update a component by id — blockJson, props, name, or category. Read with get_component, then pass `ifMatch` = the version from that read. Passing `blockJson`/`props` REPLACES them. This writes the DRAFT: call publish_component to push the change live.\") + \" \" + KIT_ENTRY_REBUILD_NOTE + \" \" + UNPROPPED_COPY_NOTE,\n inputSchema: updateComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateComponentInput>) =>\n withClient(async (client) => {\n const { componentId, ifMatch, confirmed, ...input } = args;\n // An approved custom input (the header client.updateComponent cannot send), or a kitEntry\n // (its `kitUiApplied` receipt sits beside `data`): client.updateComponent's own request, read whole.\n const res = confirmed === true || typeof input.kitEntry === \"string\"\n ? await client.fetchJSON<{ data: Awaited<ReturnType<typeof client.updateComponent>>; kitUiApplied?: string[] }>(client.url(`/management/components/${componentId}`), {\n method: \"PATCH\",\n body: JSON.stringify(input),\n headers: { ...(ifMatch !== undefined ? { \"If-Match\": `W/\"${ifMatch}\"` } : {}), ...confirmedHeaders(confirmed) },\n })\n : { data: await client.updateComponent(componentId, input as ManagedComponentInput, { ifMatch }), kitUiApplied: undefined };\n const cmp = res.data;\n const rebuilt = res.kitUiApplied ? ` kitEntry set: rebuilt the derived ui of ${res.kitUiApplied.length} prop(s)${res.kitUiApplied.length ? ` (${res.kitUiApplied.join(\", \")})` : \"\"}.` : \"\";\n return ok(`Updated component '${cmp.name}' (id ${cmp.id}).${rebuilt}`, res.kitUiApplied ? { ...cmp, kitUiApplied: res.kitUiApplied } : cmp);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"set_component_source\",\n config: {\n title: \"Record which file implements a component\",\n description:\n \"Call this RIGHT AFTER you write or locate a component's code in the app's repository: it records which file renders it, so the dashboard's Output button can preview and validate it with no setup (without it nothing is validated). Record ONLY a file that renders exactly this component from its own fields: a component whose props are this component's field keys (`kind: 'file'`, the default), or a section the codemod extracted with `npx @bettercms-ai/convert --componentize` — a file starting `// @bettercms-ai/convert section` whose props are `{ blockId, bind, overrides, page }` (`kind: 'section'`). Never record a different component that merely contains this markup (e.g. a card that needs a `post` object): it cannot render from these fields and validation fails. If the markup is inline in a page, extract it into a section first. `path` is relative to the app root (e.g. 'src/components/sections/Hero.astro'); `export` is the export name, omitted for a default export. Call it again if the file moves; call clear_component_source if a recorded file is wrong.\",\n inputSchema: setComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof setComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: { componentId: string; path: string; export: string } }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/preview-source`),\n { method: \"PUT\", body: JSON.stringify({ path: args.path, ...(args.export ? { export: args.export } : {}), ...(args.kind ? { kind: args.kind } : {}) }) },\n );\n return ok(`Recorded ${res.data.path}${res.data.export === \"default\" ? \"\" : ` (export ${res.data.export})`} as the source of component ${res.data.componentId}.`, res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"submit_componentize_receipt\",\n config: {\n title: \"Record the sources a componentize run wrote\",\n description:\n \"Record every section the componentize codemod extracted as its component's source. Call it right after `npx @bettercms-ai/convert --componentize --receipt componentize.json` (and after pushing the files): pass that receipt verbatim. Each extracted section is recorded as kind 'section' for the component with the same slug, so Output can build and validate it with no set_component_source per component. Answers which components were recorded, and any slug this project has no component for.\",\n inputSchema: submitComponentizeReceiptInput.shape,\n },\n handler: guard(async (args: z.infer<typeof submitComponentizeReceiptInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: { recorded: Array<{ slug: string; componentId: string; path: string }>; unknown: string[]; invalid: string[] } }>(\n client.url(\"/management/components/preview-sources/componentize-receipt\"),\n { method: \"POST\", body: JSON.stringify({ receipt: args.receipt }) },\n );\n const { recorded, unknown, invalid } = res.data;\n return ok(\n `Recorded ${recorded.length} section source${recorded.length === 1 ? \"\" : \"s\"}${unknown.length ? `; no component for ${unknown.join(\", \")}` : \"\"}${invalid.length ? `; unimportable path for ${invalid.join(\", \")}` : \"\"}.`,\n res.data,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"clear_component_source\",\n config: {\n title: \"Remove a component's recorded source file\",\n description:\n \"Remove the file recorded as a component's source (by set_component_source or a conversion receipt). Use it when the recorded file is wrong — Output then shows no source until the right file is recorded. Safe to call when nothing is recorded.\",\n inputSchema: clearComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof clearComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: { componentId: string; cleared: boolean } }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/preview-source`),\n { method: \"DELETE\" },\n );\n return ok(res.data.cleared ? `Removed the recorded source of component ${res.data.componentId}.` : `Component ${res.data.componentId} had no recorded source.`, res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"get_component_readiness\",\n config: {\n title: \"Read a component's Output validation readiness\",\n description: \"Read what stands between a component and a validated Output: `validation.gap` and `validation.fix` say why a validation run cannot take it yet (COMPONENT_SOURCE_NOT_RECORDED: record its file with set_component_source, or place it and deploy a build whose markup carries its data-bcms-block / data-bcms-field attributes), and the readiness says where its request, evidence and approval stand. Call it after authoring a component and after every validation run. outputReady means the Output renders; publishReady also needs the owner's Visual Approval in the dashboard, which no tool can give.\",\n inputSchema: clearComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof clearComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: unknown }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/readiness`),\n );\n return ok(\"Component validation readiness.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"declare_component_route\",\n config: {\n title: \"Declare where a component's preview is served\",\n description: \"Declare where this component's preview is served in the app (the dashboard's \\\"Show preview\\\"). Omit `path` to use the server's default route; pass `nativeViewports` only to check sizes other than the defaults. The origin is the project's preview URL and is never taken from you. Answers the readiness.\",\n inputSchema: componentValidationRouteInput.shape,\n },\n handler: guard(async (args: z.infer<typeof componentValidationRouteInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: unknown }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/adapter`),\n { method: \"PUT\", body: JSON.stringify({ path: args.path, nativeViewports: args.nativeViewports }) },\n );\n return ok(\"Preview route declared.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"request_component_validation\",\n config: {\n title: \"Request Output validation for a component\",\n description: \"Ask for this component's Output to be validated by YOU, the connected agent (provider user-agent). Record its source first (set_component_source, or the componentize codemod plus a deploy): a component nothing renders is refused with 422 and the fix, and no request is opened. After a 202, run `npx @bettercms-ai/preview-runtime validate --local --request <requestId>` in the app's repository with BCMS_API_KEY set in the environment (never pass a key in a tool call), then read get_component_readiness. Your evidence is self-attested: publishing still needs the owner's Visual Approval in the dashboard \\u2014 never claim you approved it. CI validation (github-app) runs in the owner's repository at their cost, so it is refused here with VALIDATION_PROVIDER_DASHBOARD_ONLY: ask the owner to start it from the dashboard. 409 COMPONENT_ORCHESTRATION_V2_REQUIRED means continue in Agent Dock.\",\n inputSchema: clearComponentSourceInput.shape,\n },\n handler: guard(async (args: z.infer<typeof clearComponentSourceInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data: unknown }>(\n client.url(`/management/components/${encodeURIComponent(args.componentId)}/implementation-requests`),\n { method: \"POST\", body: JSON.stringify({}) },\n );\n return ok(\"Validation requested. Run `npx @bettercms-ai/preview-runtime validate --local --request <requestId>` in the repository next.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"publish_component\",\n config: {\n title: \"Publish a component\",\n description:\n \"Publish one project-scoped component variant after its exact implementation evidence and human approval are ready: copy its DRAFT definition to the live copy and re-bake every published page that embeds it. This is the ONLY way a component reaches the live site. Built-in `builtin:*` rows are locked blueprints, not implementations; materialize one with create_component first. Workspace-global component publication is currently fail-closed. Drafts (create_component, update_component) render as NOTHING live, with no error: publish every component you place on a page. 403 PUBLISH_NOT_GRANTED means this connection may author but not publish: say so and let the user publish from the dashboard. 🔴 A 409 COMPONENT_IMPLEMENTATION_NOT_READY is NOT retried and must not be: no tool on this connection can clear it. It asks for exact validation evidence and a human's approval, never of a component you just made with create_component (which ones: skill components). Its `readiness` names what is missing — relay it to the user instead of retrying or routing around it. 422 means publishing would break a Layout that uses it — the response names which.\",\n inputSchema: getComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getComponentInput>) =>\n withClient(async (client) => {\n const res = await client.fetchJSON<{ data?: unknown }>(\n client.url(`/management/components/${args.componentId}/publish`),\n { method: \"POST\" },\n );\n return ok(\"Published component.\", res.data);\n }),\n ) as ToolDef[\"handler\"],\n },\n\n\n // ── AI content + SEO actions (Option B) ────────────────────────────────────\n {\n name: \"write_content\",\n config: {\n title: \"Write, rewrite, or translate content\",\n description:\n \"AI-write a piece of copy: action 'write' (draft from a brief), 'rewrite' (improve existing copy), or 'translate' (needs targetLang). Returns the suggested text — apply it with set_page_content or update_content_entry. Uses the workspace's own Anthropic key (BYOK, unmetered) or platform AI credits.\",\n inputSchema: writeContentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof writeContentInput>) =>\n withClient(async (client) => {\n const suggestion = await client.writeContent(args);\n return ok(`Generated ${args.action} suggestion (${suggestion.length} chars).`, { suggestion });\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"generate_seo_meta\",\n config: {\n title: \"Generate SEO metadata\",\n description:\n \"Generate SEO metadata (metaTitle, metaDescription, keywords, optional JSON-LD) for a piece of content. Pass the page/entry content as `text`. Returns a suggestion: apply a page's with update_page (metaTitle, metaDescription, schemaType, schema) and an entry's with update_content_entry `meta`.\",\n inputSchema: generateSeoMetaInput.shape,\n },\n handler: guard(async (args: z.infer<typeof generateSeoMetaInput>) =>\n withClient(async (client) => {\n const meta = await client.generateSeoMeta(args);\n return ok(`Generated SEO metadata: \"${meta.metaTitle}\".`, meta);\n }),\n ) as ToolDef[\"handler\"],\n },\n\n // ── Native bridge (executor presence) ──────────────────────────────────────\n {\n name: \"connect_native_ai\",\n config: {\n title: \"Connect this client to the project's Native AI Connection\",\n description:\n \"Connect this client to the project's Native AI Connection, so the dashboard shows it as an available executor. Call it ONCE when the user asks to connect — after that, ordinary tool calls on the same project keep it listed, and nothing needs to run on a timer. Idempotent. Returns the project it connected to and `presenceWindowMs`: the executor stays listed for that long after the last tool call, then drops off until the next one. THIS GRANTS NOTHING — it is presence only, and starting a run is still a human act in the dashboard. A 403 BRIDGE_GRANT_REQUIRED means this client is using a bare API key rather than an approved connection; a 400 means the connection covers the whole workspace and you must pass `projectId`.\",\n inputSchema: connectNativeAiInput.shape,\n },\n handler: guard(async (args: z.infer<typeof connectNativeAiInput>) =>\n withClient(async (client) => {\n const result = await client.fetchJSON<{\n state: string;\n projectId: string;\n installationId: string;\n presenceWindowMs: number | null;\n }>(client.url(\"/management/orchestration/bridge/connect\"), {\n method: \"POST\",\n body: JSON.stringify({\n protocolVersion: \"1\",\n ...(args.capabilities ? { capabilities: args.capabilities } : {}),\n }),\n });\n const mins = result.presenceWindowMs\n ? Math.round(result.presenceWindowMs / 60_000)\n : null;\n return ok(\n `Connected to project ${result.projectId}. The dashboard now lists this client as an available executor${mins ? `; it stays listed for ${mins} minutes after the last tool call` : \"\"}.`,\n result,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n\n // ── Lifecycle tools (parity with the remote /mcp surface) ──────────────────\n // Media management, form submissions (leads), redirects, SEO, AEO site-files,\n // promote, and entry version history. These call the management endpoints straight\n // through the client's request plumbing — no bespoke SDK method per endpoint.\n ...lifecycleTools(),\n ];\n\n /**\n * A page named by PATH or slug (`/de/about`, `about`) becomes its id before the tool runs, as\n * the hosted callTool does: a slug two pages share fails with each match's id, path and language.\n */\n const withPageRef = (def: ToolDef): ToolDef => ({\n ...def,\n handler: (args) => {\n const ref = args?.pageId;\n if (typeof ref !== \"string\" || !ref || UUID.test(ref)) return def.handler(args);\n return guard(async () => def.handler({ ...args, pageId: await withClient((c) => pageIdOf(c, ref)) }))(undefined);\n },\n });\n\n // Tail last, so a client that keeps only the first 100 keeps the authoring lane. A stable\n // partition: inside each half the order is still the one the literal above declares.\n return [\n ...defs.filter((d) => !LISTING_TAIL.has(d.name)),\n ...defs.filter((d) => LISTING_TAIL.has(d.name)),\n ].map(withPageRef).map(withProjectId);\n}\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Register the BetterCMS tools on an MCP server — those the toolsets list: BETTERCMS_MCP_TOOLS is a\n * comma list of `core`, `abm` and `all` (the hosted connector's `?tools=`); unset = every tool\n * except the ABM lane. A tool this connection does not list is not registered.\n */\nexport function registerTools(server: McpServer, deps: ToolDeps, tools = process.env.BETTERCMS_MCP_TOOLS): void {\n // Give the tools a way to ask the human directly. Threaded here rather than taken as a\n // dep by the caller so buildToolDefs stays server-free for the tests.\n const withElicit: ToolDeps = {\n ...deps,\n elicit: deps.elicit ?? ((params) => server.server.elicitInput(params as never)),\n };\n const sets = toolsetsOf(tools);\n for (const def of buildToolDefs(withElicit).filter((d) => listsTool(d.name, sets))) {\n const _meta = toolMeta(def.name);\n server.registerTool(def.name, _meta ? { ...def.config, _meta } : def.config, def.handler as never);\n }\n}\n","/**\n * Component — a reusable, Webflow-style block tree (a \"symbol\").\n *\n * A component is authored once and placed across pages via `component` blocks\n * (see `ComponentBlock` in `./block.ts`). Its definition lives in `blockJson`;\n * `props` declares a flat allowlist of values an instance may override.\n */\nimport type { BlockStyle, ContentBlock, VisibilityWindow } from \"./block.js\";\nimport type { ChoiceOption, ContentModelFieldUi, FieldsetKind, OpenMode, ShowIf, UiBefore, UiOrigin } from \"./content-model.js\";\nimport type { DockIconName } from \"./dock-icon-names.js\";\nimport type { VariantInputMapping } from \"./layout.js\";\n\n/**\n * The category a component belongs to (drives library grouping + icons). The first eight\n * are structural (what the component IS); the last four are the \"Add a section\" library\n * tabs (where it appears). One varchar column, not a PG enum — widening is code-only.\n */\n/**\n * 🔴 THE STRUCTURE DOCTRINE — one sentence, one home, spliced into every surface that builds a page.\n *\n * It lives HERE, beside the component contract it describes, because there are THREE places that teach\n * an agent how to build a page and they drifted apart:\n * • `packages/mcp/src/tools.ts` — the MCP tool descriptions (external agents)\n * • `src/lib/ai/agent.ts` — the in-product Studio Agent's system prompt\n * • `packages/mcp/src/prompts.ts` — the authoring playbook, which a tool call does not carry\n *\n * Only the playbook explained sections. `create_page` taught the SCHEMA axis in detail (\"each visual\n * section becomes a nested field\") and said nothing about STRUCTURE; the Studio Agent's prompt named\n * \"pages & reusable components (structure/layout)\" without ever mentioning `sectionType`.\n *\n * Measured consequence, production 2026-08-18: project `acme` has three components, ALL with\n * `section_type = (none)`, and its home page is 18 loose top-level blocks with ZERO sections. Every\n * generated page came out flat, so the visual editor's section lane — outline, name, move, duplicate,\n * delete, variant swap — had nothing to attach to. The editor was faithfully showing pages that were\n * never built out of sections.\n *\n * A constant rather than three paraphrases, because updating some of them is exactly how this happened.\n */\nexport const SECTION_DOCTRINE =\n \"STRUCTURE (separate from schema): a page is composed of SECTIONS. NEVER build a page out of loose top-level heading/text/image/button/spacer blocks — they cannot be moved, duplicated or swapped as a unit, the visual editor cannot outline or name them, and every one of them becomes its own section in the editor. A hero of a headline, a lede and two CTAs is ONE section, not four. TWO SHAPES, and the choice is about REUSE. (1) A band that appears on more than one page, or that needs layout variants, is a COMPONENT with a `sectionType` — see create_component. Components sharing a `sectionType` are that section's VARIANTS (one Hero: 'Centered' for the home page and 'Two-column' for about, same prop keys so a swap keeps the content). This is also the only shape the editor's 'Add a section' picker can insert, and the only one that gets a family name and a variant switcher. (2) A genuinely one-off band on a single page is a `section` BLOCK whose `props.children` hold its blocks. THE TRADEOFF, stated in the present tense because it is real today: inside a component, ONLY the leaves a declared prop TARGETS are click-to-edit on the canvas — each declared prop's `target` is re-keyed to that PLACEMENT's own override address, so editing it changes this page and not the shared definition. A prop with no `target` still SHOWS as a dock control, but its override reaches no rendered slot, so editing it changes nothing on the page. Copy that no prop points at is worse still: no binding and no control, unreachable from click-to-edit AND from the dock, changeable only by editing the component definition, which rewrites every page that places it. A `section` block's children stay click-to-edit unconditionally. So when you choose a component, DECLARE A PROP — WITH A `target` — for every string, link and image a marketer will ever touch; a component with un-propped editable copy is the defect, not the component. In the dock an unset prop shows EMPTY and inherits the definition's default, so set props explicitly when you want the current copy visible there. An IMPORTED site's components are its own (read the repo); its nav, footer and modals are the Layout. On a blank site, do not hand-write a band's JSON: start from a built-in section blueprint (list_components returns locked `builtin:*` blueprints with no projectId — hero-centered, hero-split, feature-grid-three, cta-banner and more), each already rooted in a `section` block with its editable leaves declared as props. INLINE its blockJson as a `section` block for a one-off band; for a recurring band, materialize it with create_component `from` so it becomes project-scoped before implementation validation, Output or publication. Direct `builtin:*` component references exist only for legacy delivery compatibility. Two consecutive call-to-action buttons are two sibling `button` blocks inside the same section — never a `columns` block, which is a `repeat(N,1fr)` grid and would stretch each CTA to half the container. Buttons are inline-level and flow side by side on their own.\";\n\nexport type ComponentCategory =\n | \"navbar\"\n | \"footer\"\n | \"button\"\n | \"section\"\n | \"slider\"\n | \"tabs\"\n | \"form\"\n | \"custom\"\n | \"hero\"\n | \"content\"\n | \"social-proof\"\n | \"conversion\";\n\n/**\n * A single overridable field on a component. `target` points at the block + JSON\n * path inside `blockJson` the override writes to (e.g. blockId \"cta\", path\n * \"props.text\"). Keeping overrides a declared allowlist (not arbitrary nested\n * rewrites) keeps instance data small and the contract explicit.\n */\n/**\n * THE prop vocabulary. One list, imported everywhere a prop type is enumerated.\n *\n * It exists as a value (not just a union) because four places used to spell it out by hand —\n * this file, the Drizzle schema, `COMPONENT_PROP_TYPES` in the backend's Zod schemas, and the\n * MCP tool shape — and the MCP copy is the dangerous one: `update_component` REPLACES the whole\n * `props` array, so a type its enum omits cannot be echoed back, and an agent that reads a\n * component and writes it straight back DESTROYS every prop of that type with a 200.\n *\n * Order is not semantic; append rather than re-sort, so a diff stays readable.\n */\nexport const COMPONENT_PROP_TYPES = [\n \"text\",\n \"richtext\",\n \"image\",\n \"url\",\n \"boolean\",\n \"number\",\n \"select\",\n \"group\",\n \"table\",\n \"slot\",\n \"form\",\n // The seven below each store what the same-named content-model FIELD stores (`icon` and\n // `multiselect` have no field twin; see the value notes on ComponentPropDef.type).\n \"link\",\n \"button\",\n \"date\",\n \"color\",\n \"file\",\n \"icon\",\n \"multiselect\",\n // V2 schema language (F1.x). `object` is ONE nested value of named `config.fields`, stored as\n // `{ [childKey]: value }` like the model field `object`; the six after it store what the\n // same-named content-model FIELD stores (`location` is the V2 geopoint) and are judged by\n // that field's validator.\n \"object\",\n \"datetime\",\n \"slug\",\n \"email\",\n \"phone\",\n \"json\",\n \"location\",\n // V2 leaves, each storing what the same-named content-model FIELD stores: a taxonomy string[],\n // a rating number, a code value (`{ language?, code }` or a string).\n \"tags\",\n \"rating\",\n \"code\",\n // CMS items, as the same-named content-model FIELDS store them: an entry id (or a polymorphic\n // `{ entryId, modelSlug }`), and a list of them. Delivery hydrates them like an entry's.\n \"reference\",\n \"multi-reference\",\n // V2 chrome types, each storing what the same-named content-model FIELD stores: a video value,\n // a primitive list (`config.itemType`), and multi-line text (the field lane's V2 `text`).\n \"video\",\n \"array\",\n \"longtext\",\n] as const;\n\nexport type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];\n\n/**\n * The value a `form` prop STORES: just the id. The form itself is a Form document and stays the\n * single source of truth for its fields — a component references one, it never re-declares it.\n *\n * `.strict()` at the write boundary, so a client that POSTs a hydrated form object alongside the\n * id gets a 400 rather than a silent strip.\n *\n * There is deliberately NO resolved twin of this shape. Every renderer already receives forms the\n * same way — a catalogue beside the blocks (`BcmsBlocks({blocks, forms})`, the site renderer's\n * forms map) — and looks the id up in it. A hydrated `{formId, form}` prop value would be a shape\n * that exists nowhere in delivery.\n */\nexport interface ComponentFormPropRef {\n formId: string;\n}\n\nexport interface ComponentPropDef {\n key: string;\n label: string;\n target: { blockId: string; path: string };\n /**\n * `slot` holds ONE nested component instance — the component-level twin of the\n * content-model field type `component-ref` (see content-model.ts), named differently for\n * the same reason that one is: `component` already means a BLOCK type. Its value is\n * `{ componentId, overrides }` and its `target.path` is `props`, so filling a slot writes\n * that object over an empty `component` block's props.\n *\n * With `config.multiple` it holds a LIST of them and targets a container's child list\n * (`props.children` on a `section`, `props.columns.<n>` on a `columns`): the resolver writes\n * one `component` block per item there, so every renderer draws them as ordinary children.\n * @see slotItems\n *\n * On a PAGE a slot fill is a LIVE reference; a published ENTRY freezes it (resolveDeep).\n */\n /**\n * The EDITOR contract, not a storage one: `applyOverrides` writes the value at\n * `target.path` whatever its shape, so `type` decides which control the inspector renders\n * and what shape that control produces (FLO-1020).\n *\n * number → a number (heading.level, columns.count)\n * select → one string from `config.options`\n * group → an object keyed by `config.fields`\n * table → an array of such objects (slider.slides); with `config.mode: \"data\"` instead ONE\n * V2 `TableValue` (typed, keyed columns × keyed rows, table-value.ts), the value a\n * `table` FIELD stores. Aimed at a text or richtext block's `props.html` it renders\n * as the semantic HTML table. With `config.mode: \"types\"` a V2 polymorphic list: rows of\n * several item types (`config.itemTypes`), each row naming its type in `_type`.\n * link → an href string (URL, internal path or #fragment)\n * button → ONE `ButtonValue` (button-look.ts): label, href and look as a unit, never a text prop plus\n * a url prop that drift apart. Targets the `props` of a `button` block.\n * date → `YYYY-MM-DD`\n * color → a hex colour (`#RGB`, `#RRGGBB`, `#RRGGBBAA`)\n * file → `{ url, name?, size? }`, or a bare URL string\n * icon → a BetterCMS icon name (`DOCK_ICON_NAMES`), or an uploaded icon as an image value\n * multiselect → a `string[]`, each one of `config.options`\n * object → ONE `{ [childKey]: value }` keyed by `config.fields` (the V2 model-field `object`)\n * datetime · slug · email · phone · json · location → what the same-named model FIELD stores\n * tags · rating · code → what the same-named model FIELD stores (a string[], a number,\n * `{ language?, code }` or a string)\n * reference · multi-reference → what the same-named model FIELD stores: an entry id, or a\n * list of them (`config.contentModelId`, or `polymorphic` + `allowedModelSlugs`;\n * `min`/`max` on the list). Delivery and preview hydrate the ids in a page's overrides\n * to entries at the read's `depth`; a plain-text slot renders the entry's title.\n * video → a URL string or `{ url, poster?, autoplay?, loop?, transcript? }` (the video\n * block's props; aimed at a video block it lands as them) @see VideoValue\n * array → a list of `config.itemType` values: text, number, date, image, link or richtext\n * (the model field's primitive `array`; a list of objects is a `table`)\n * longtext → a multi-line string (the model field `longtext`; `text` is one line)\n */\n type: ComponentPropType;\n defaultValue?: unknown;\n /**\n * EDITOR HINTS (playbook §12). Stored in the props JSON, so no migration.\n *\n * 🔴 `required` IS NOT ENFORCED AT WRITE TIME, deliberately. Nothing on the write path\n * refuses an override that omits a required prop — a placement saves either way — because\n * the alternative is a component definition that can retroactively make already-saved pages\n * unsaveable. It is a marker the dashboard renders and `get_site_composition` counts, which\n * is the honest shape: the receipt names what is missing instead of the write refusing it.\n */\n required?: boolean;\n /** Hint shown under the control, muted. */\n helpText?: string;\n /** Server-owned: who wrote `helpText`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /** Ghost text inside a text-ish control. */\n placeholder?: string;\n /**\n * Editor-only conditional visibility: show this prop's control only while sibling props (by\n * key) hold these values. The save schema refuses a key no prop of the component declares.\n */\n showIf?: ShowIf;\n /** V2 editor-only keys, as on a model field. @see ContentModelField.helpMore */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /**\n * F1.x: a list prop's items (a table's rows) distinct; on a table sub-field, no two rows share\n * the value. Refused (`unique_prop_scope`) on a top-level scalar: nothing to be unique across.\n */\n unique?: boolean;\n /** `object` / `group` / `table`: how the value (or each row) opens when edited. */\n openMode?: OpenMode;\n /**\n * The content-model field's `readOnly` / `lockReason` pair, as STORED MARKERS only: the\n * editor may render the prop read-only, and no write of a prop value is refused for them.\n */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization (the locale chip): a stored marker, as on a model field. */\n localized?: boolean;\n /** Per-type settings; the save schema enforces that each is present on the type needing it. */\n config?: {\n /** `slot` — a pick allowlist. */\n componentIds?: string[];\n /** `slot` — the V2 `of.allow` block names it takes (`textBlock`), kept as written; the dock resolves them to components. */\n allow?: string[];\n /**\n * `array` — the V2 item field's own settings (`of[0]`): help under each item, the locale chip,\n * required, and a text / rich text item's length (a text item's pattern). Stored markers.\n */\n item?: { helpText?: string; localized?: boolean; required?: boolean; minLength?: number; maxLength?: number; pattern?: string; patternMessage?: string };\n /** `slot` — the value is a list of instances, not one. @see slotItems */\n multiple?: boolean;\n /** `slot` with `multiple` — bounds on the list. `maxItems` defaults to {@link SLOT_MAX_ITEMS}. */\n minItems?: number;\n maxItems?: number;\n /**\n * `slot` — per-child layout settings (V2 `slotSettings`, e.g. a bento span): what a V2 child's\n * `_settings` holds (`{ _key, _type, _settings, ...props }`, slot-child.ts). Leaf sub-fields.\n */\n slotSettings?: ComponentSubField[];\n /**\n * `table` with `mode: \"types\"` — a V2 polymorphic list: each row is ONE of these item types,\n * named by the row's `_type` (`{ _key?, _type, ...values }`), its values keyed by that type's `fields`.\n */\n itemTypes?: Array<{\n name: string;\n label?: string;\n fields: ComponentSubField[];\n /** How a row of this type reads collapsed: title/subtitle/media name THIS type's fields (dotted ok, e.g. `table.caption`). */\n preview?: { title?: string; subtitle?: string; media?: string; fallback?: string; icon?: DockIconName };\n /** The row icon for this type, a dock icon name. */\n icon?: DockIconName;\n }>;\n /**\n * `select` / `multiselect` — the choices. Required, and a default must be one of them. `{ label, value }`\n * when the stored value is not what an author should read (a component id, for instance).\n */\n options?: Array<string | ChoiceOption>;\n /** `group` / `table` / `object` — the sub-shape; 10 levels at most, counting the prop (MAX_FIELD_DEPTH). */\n fields?: ComponentSubField[];\n /**\n * `table` — which value it holds: `\"rows\"` (the default, an array of `fields` rows) or\n * `\"data\"` (one V2 TableValue, with the table field's options beside it: columnTypes,\n * lockColumns, minRows, maxRows, maxColumns, requireCaption, …). A data table has no `fields`.\n */\n mode?: \"rows\" | \"data\" | \"types\";\n /** `number` — bounds for the control; `multiselect` / `tags` / `multi-reference` — how many items. */\n min?: number;\n max?: number;\n step?: number;\n /** `number` — V2 `validation.min / max`: the error bounds, which win over `min` / `max`. */\n validation?: { min?: number; max?: number };\n /** `text` / `url` / `richtext` — length in characters (richtext: its plain text). */\n minLength?: number;\n maxLength?: number;\n /** `text` / `url` — a regex (≤ 200 characters) and the message shown when it does not match. */\n pattern?: string;\n patternMessage?: string;\n /** `reference` / `multi-reference` — the target model, or `polymorphic` with an allowlist of model slugs. */\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n } & Record<string, unknown>;\n /**\n * AUTHORING CHROME — the same object a content-model FIELD carries ({@link ContentModelFieldUi}),\n * deliberately: an agent that has learned `ui` once has learned it on both lanes.\n *\n * A SIBLING of `config`, not a member of it. `config` is a loose bag, so a `config.ui` already\n * survived the write — and that is the problem this key fixes: surviving is not declared, and\n * an undeclared prop is a typo that saves cleanly and renders as nothing.\n *\n * WHERE EACH KEY IS LEGAL differs from the field lane, because the vocabulary does:\n * `preview`/`layout` on `group`, `table` and `slot`; `reorderable` on `table` ALONE, the only\n * prop type whose value is a list. The save schema refuses the rest with the valid set named.\n */\n ui?: ComponentPropUi;\n /** Server-owned provenance of this prop's chrome. @see UiOrigin */\n uiOrigin?: UiOrigin;\n /** Server-owned revert point. @see UiBefore */\n uiBefore?: UiBefore;\n /** `true`: no placement the last release inspected renders this prop — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n}\n\n/**\n * A top-level prop's dock group. Props have no fieldsets column, so the group rides inline: the\n * first prop to carry an `id` defines it (label, kind, icon, collapsed), later props name `{id}`.\n */\nexport interface PropGroup {\n id: string;\n /** 1–32 chars. Required on the defining prop. */\n label?: string;\n kind?: Exclude<FieldsetKind, \"tab\">;\n icon?: DockIconName;\n collapsed?: boolean;\n /** V2 fieldset keys (CPO D45), on the defining prop: a line under the header (≤200), members side by side, a static header, a breakpoint switcher, and its place among the groups (0–99; absent = where its first prop sits). */\n description?: string;\n columns?: 1 | 2;\n collapsible?: boolean;\n layout?: \"stack\" | \"breakpoints\";\n order?: number;\n}\n\n/**\n * A top-level prop's dock tab (V2 kit schema `groups`: Content | Design | Media | Settings | …).\n * Define-once like {@link PropGroup}: the first prop naming an `id` sets label/icon/order, later\n * props name `{ id }`. At most 8 tabs; never on a sub-field; one group's members share one tab.\n */\nexport interface PropTab {\n id: string;\n /** 1–40 chars, unique per component (case-insensitive). Required on the defining prop. */\n label?: string;\n icon?: DockIconName;\n /** 0–99; the tab's place among the tabs (absent = where its first prop sits). */\n order?: number;\n}\n\n/** A prop's `ui`: the field-lane chrome plus its inline {@link PropGroup} and {@link PropTab}. */\nexport type ComponentPropUi = ContentModelFieldUi & { group?: PropGroup; tab?: PropTab };\n\n/** One field inside a `group` / `object` prop or a `table` row. Recursive, 10 levels at most counting the prop (MAX_FIELD_DEPTH). */\nexport interface ComponentSubField {\n key: string;\n label: string;\n /**\n * No `form`: a form in a table row would mean N form documents per component with no way to\n * author them — the second field model this design exists to avoid. A `slot` sub-field IS\n * accepted by the API (V2 kit entries: an instance in an object or a row, `{ componentId,\n * overrides? }` at its key, the slot prop's config keys), and the `packages/db` schema mirror widened with it.\n */\n type: Exclude<ComponentPropDef[\"type\"], \"form\">;\n defaultValue?: unknown;\n /** The same editor hints as the prop above, one level down. @see ComponentPropDef */\n required?: boolean;\n helpText?: string;\n helpSource?: \"auto\" | \"human\" | \"agent\";\n placeholder?: string;\n options?: Array<string | ChoiceOption>;\n /** The V2 editor keys, one level down. `showIf` names SIBLING sub-fields. @see ComponentPropDef */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** On a table's sub-field: no two rows share the value; on a list: no item repeats. */\n unique?: boolean;\n openMode?: OpenMode;\n showIf?: ShowIf;\n /** The prop's `ui`, inline group included: V2 fieldsets nest, so sub-fields group too. */\n ui?: ComponentPropUi;\n /** V2 sub-field read-only / developer lock: stored markers, as on the prop. `\"developer\"` needs a lockReason. */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization: a stored marker, as on the prop. */\n localized?: boolean;\n /** CANONICAL. A nested `group`/`table`/`object`'s own sub-shape. */\n fields?: ComponentSubField[];\n /**\n * A READ-ONLY MIRROR of `options`/`fields`, in the shape `ComponentPropDef` puts them in.\n *\n * 🔴 WHY A SECOND COPY EXISTS AT ALL. A `group`/`table` PROP declares its sub-shape under\n * `config.fields`; a sub-field of one declares its own under a bare `fields`. So a consumer\n * walking a nested table has to switch shape after the first level, and the componentize lane's\n * repo half (`@bettercms-ai/convert --componentize`) walks exactly that — it reads one node\n * shape at every depth. Mirroring the sub-shape here lets it, without the CMS having to\n * describe a nested table differently from a top-level one.\n *\n * `fields` is the authority. The save schema REFUSES a node whose mirror disagrees with it\n * (`componentPropDefSchema`), because two copies that may drift are worse than one awkward\n * shape — an editor that rewrote `fields` alone would leave a stale row description behind.\n */\n config?: { fields?: ComponentSubField[]; options?: Array<string | ChoiceOption> } & Record<string, unknown>;\n}\n\n/** The value a `slot` prop holds — the draft half of a `component-ref`, deliberately. */\nexport interface SlotValue {\n componentId: string;\n overrides?: Record<string, unknown>;\n}\n\n/**\n * One child of a `multiple` slot: a {@link SlotValue} that may also carry the two placement keys a\n * `component` block has. The child block is built with them, so it hides per breakpoint and\n * shows inside its window exactly as a block placed by hand does.\n */\nexport interface SlotItem extends SlotValue {\n style?: BlockStyle;\n window?: VisibilityWindow;\n}\n\n/** How many children a `multiple` slot holds when its prop sets no `config.maxItems`. */\nexport const SLOT_MAX_ITEMS = 12;\n/** The most `config.maxItems` may ask for: one placement never expands into more blocks than this. */\nexport const SLOT_ITEMS_CAP = 50;\n/** The most a `table` prop's rows or an `array` prop's items may be bounded to (`config.maxItems`). */\nexport const LIST_ITEMS_CAP = 500;\n\n/**\n * A slot value as a list of its instances, whichever shape it was stored in: `[]` for nothing,\n * one item for a single `{ componentId, overrides }`, the array's own items for a `multiple`\n * slot. An item with no `componentId` names no component and is left out.\n *\n * THE one reading of a slot value. A walker that tests `value.componentId` alone sees a\n * `multiple` slot as empty, and for a \"where used\" answer or a delete guard that is a component\n * removed from under the pages that hold it.\n */\nexport function slotItems(value: unknown): SlotItem[] {\n const list = Array.isArray(value) ? value : [value];\n const out: SlotItem[] = [];\n for (const item of list) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const o = item as Record<string, unknown>;\n if (typeof o.componentId === \"string\" && o.componentId !== \"\") out.push(item as SlotItem);\n // A V2 slot child (`{ _key, _type, ...props }`, slot-child.ts): `_type` is the component id and\n // the child ITSELF is the overrides, so a walker that writes into them writes into the stored\n // value. applyOverrides reads declared prop keys only; the `_` keys are never a prop's.\n else if (typeof o.componentId !== \"string\" && typeof o._type === \"string\" && o._type !== \"\") out.push({ componentId: o._type, overrides: o });\n }\n return out;\n}\n\n/**\n * A component is a DRAFT until published; only the published copy reaches a visitor.\n * Mirrors pages and entries. See migration 0186_component_draft_live_split.sql.\n */\nexport type ComponentStatus = \"draft\" | \"published\";\n\n/**\n * Archive state (FLO-1012), deliberately SEPARATE from `ComponentStatus`.\n *\n * Archive takes a component out of the working set — hidden from the components list by\n * default, not offered in the visual editor's insert surfaces — while every existing usage\n * keeps serving. It is not unpublish (which pulls the live copy and re-bakes every page that\n * embeds it) and it is not delete.\n *\n * It is a timestamp rather than a third `status` value because a component can be published\n * AND archived; collapsing the two would lose the bit restore has to put back.\n */\n\n/**\n * How ONE instance of a component reads as a ROW in a parent's slot list (\"Open Rosa Delgado,\n * 2 of 5\"): the V2 /kit schema's document-level `preview`. `title`, `subtitle` and `media` each\n * name a TOP-LEVEL prop key, or a dotted path into one (`slides.0.heading`; the API refuses any\n * other with `preview_key_unknown`); `fallback` is\n * the literal row label while the title prop is empty; `icon` the row's icon while it has no media.\n * Draft-only authoring chrome: never part of the publish snapshot.\n */\nexport interface ComponentPreview {\n title?: string;\n subtitle?: string;\n media?: string;\n fallback?: string;\n icon?: DockIconName;\n}\n\n/**\n * A V2 /kit schema tab (a `groups` entry) NO top-level prop sits in, declared on the component so\n * the schema round-trips: V2 hides a tab with no visible top-level field, and so does the dock. A\n * tab a prop sits in is defined on that prop (`ui.tab`). `order` places it among all the tabs.\n */\nexport interface ComponentTab {\n id: string;\n label: string;\n icon?: DockIconName;\n order?: number;\n}\n\nexport interface Component {\n id: string;\n workspaceId: string;\n projectId?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n /**\n * Section library: the family this component is a LAYOUT of, e.g. \"Hero\". `name` is the\n * layout label (\"Centered\"), so components sharing a sectionType are selectable variants\n * of one section. Null/absent = an ordinary component, not shown in the section library.\n */\n sectionType?: string | null;\n /** First-class variant family membership; exact workspace/project scope is enforced in DB. */\n variantGroupId?: string | null;\n variantInputMappings?: VariantInputMapping[];\n /** Placement governance: `*`, `slug:<page-slug>`, and/or `type:<page-type>`. */\n allowedOn: string[];\n description?: string | null;\n /** The DRAFT definition. Every builder/autosave/import write path targets these two. */\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n /** How an instance reads as a row in a parent's slot list. Null/absent = unset. @see ComponentPreview */\n preview?: ComponentPreview | null;\n /** The block icon (a /kit schema's document-level `icon`): root crumb, slot rows, slot child frames. Null/absent = unset. */\n icon?: DockIconName | null;\n /** Declared tabs no top-level prop sits in. Null/absent = none. @see ComponentTab */\n tabs?: ComponentTab[] | null;\n /** The bettercms://kit entry its V2 dock UI was built from (a kit-catalog id). Null/absent = none named. */\n kitEntry?: string | null;\n status: ComponentStatus;\n /** When it left the working set, or null/absent while active. @see ComponentStatus */\n archivedAt?: string | Date | null;\n /** Derived from `archivedAt`, so a client never has to know the column. */\n archived?: boolean;\n /**\n * The LIVE snapshot get_components_by_handle() serves. Null until the first publish.\n * Returned by GET-one (the Compare view needs it), omitted from list rows for payload.\n */\n publishedBlockJson?: ContentBlock[] | null;\n publishedProps?: ComponentPropDef[] | null;\n publishedAt?: string | null; // ISO 8601\n /**\n * Computed in SQL on list/get, never stored:\n * status='published' AND (blockJson or props has diverged from its published copy).\n * An exact jsonb compare, so it self-clears when an edit is reverted.\n */\n pendingChanges?: boolean;\n thumbnail?: string | null;\n createdAt: string; // ISO 8601\n updatedAt: string; // ISO 8601\n}\n\n/**\n * Public/delivery projection — the fields a renderer needs to resolve instances.\n *\n * DELIBERATELY UNCHANGED by the 0186 draft/live split: delivery aliases\n * publishedBlockJson -> blockJson, so every already-deployed site and every\n * bcms-content.json on disk keeps a byte-identical wire shape. Do not add `status` here —\n * delivery only ever returns published rows, so it would always be the same constant.\n */\nexport interface DeliveryComponent {\n id: string;\n /** The project the component belongs to. */\n projectId?: string | null;\n /** The component's preview image in the editor's library, when it has one. */\n thumbnail?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n sectionType?: string | null;\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n}\n","/**\n * Generated from lucide-react@1.8.0 dynamic icon names.\n * Legacy CamelCase identifiers remain valid for existing Layout documents.\n */\nexport const LAYOUT_SECTION_ICONS: readonly string[] = Object.freeze([\n \"LayoutPanelTop\",\n \"PanelTop\",\n \"PanelBottom\",\n \"Menu\",\n \"Navigation\",\n \"Megaphone\",\n \"GalleryHorizontal\",\n \"Rows3\",\n \"Grid2X2\",\n \"FileText\",\n \"Link\",\n \"Contact\",\n \"BadgeInfo\",\n \"Sparkles\",\n \"a-arrow-down\",\n \"a-arrow-up\",\n \"a-large-small\",\n \"accessibility\",\n \"activity\",\n \"air-vent\",\n \"airplay\",\n \"alarm-clock-check\",\n \"alarm-check\",\n \"alarm-clock-minus\",\n \"alarm-minus\",\n \"alarm-clock-off\",\n \"alarm-clock-plus\",\n \"alarm-plus\",\n \"alarm-clock\",\n \"alarm-smoke\",\n \"album\",\n \"align-center-horizontal\",\n \"align-center-vertical\",\n \"align-end-horizontal\",\n \"align-end-vertical\",\n \"align-horizontal-distribute-center\",\n \"align-horizontal-distribute-end\",\n \"align-horizontal-distribute-start\",\n \"align-horizontal-justify-center\",\n \"align-horizontal-justify-end\",\n \"align-horizontal-justify-start\",\n \"align-horizontal-space-around\",\n \"align-horizontal-space-between\",\n \"align-start-horizontal\",\n \"align-start-vertical\",\n \"align-vertical-distribute-center\",\n \"align-vertical-distribute-end\",\n \"align-vertical-distribute-start\",\n \"align-vertical-justify-center\",\n \"align-vertical-justify-end\",\n \"align-vertical-justify-start\",\n \"align-vertical-space-around\",\n \"align-vertical-space-between\",\n \"ambulance\",\n \"ampersand\",\n \"ampersands\",\n \"amphora\",\n \"anchor\",\n \"angry\",\n \"annoyed\",\n \"antenna\",\n \"anvil\",\n \"aperture\",\n \"app-window-mac\",\n \"app-window\",\n \"apple\",\n \"archive-restore\",\n \"archive-x\",\n \"archive\",\n \"armchair\",\n \"arrow-big-down-dash\",\n \"arrow-big-down\",\n \"arrow-big-left-dash\",\n \"arrow-big-left\",\n \"arrow-big-right-dash\",\n \"arrow-big-right\",\n \"arrow-big-up-dash\",\n \"arrow-big-up\",\n \"arrow-down-0-1\",\n \"arrow-down-01\",\n \"arrow-down-1-0\",\n \"arrow-down-10\",\n \"arrow-down-a-z\",\n \"arrow-down-az\",\n \"arrow-down-from-line\",\n \"arrow-down-left\",\n \"arrow-down-narrow-wide\",\n \"arrow-down-right\",\n \"arrow-down-to-dot\",\n \"arrow-down-to-line\",\n \"arrow-down-up\",\n \"arrow-down-wide-narrow\",\n \"sort-desc\",\n \"arrow-down-z-a\",\n \"arrow-down-za\",\n \"arrow-down\",\n \"arrow-left-from-line\",\n \"arrow-left-right\",\n \"arrow-left-to-line\",\n \"arrow-left\",\n \"arrow-right-from-line\",\n \"arrow-right-left\",\n \"arrow-right-to-line\",\n \"arrow-right\",\n \"arrow-up-0-1\",\n \"arrow-up-01\",\n \"arrow-up-1-0\",\n \"arrow-up-10\",\n \"arrow-up-a-z\",\n \"arrow-up-az\",\n \"arrow-up-down\",\n \"arrow-up-from-dot\",\n \"arrow-up-from-line\",\n \"arrow-up-left\",\n \"arrow-up-narrow-wide\",\n \"sort-asc\",\n \"arrow-up-right\",\n \"arrow-up-to-line\",\n \"arrow-up-wide-narrow\",\n \"arrow-up-z-a\",\n \"arrow-up-za\",\n \"arrow-up\",\n \"arrows-up-from-line\",\n \"asterisk\",\n \"at-sign\",\n \"atom\",\n \"audio-lines\",\n \"audio-waveform\",\n \"award\",\n \"axe\",\n \"axis-3d\",\n \"axis-3-d\",\n \"baby\",\n \"backpack\",\n \"badge-alert\",\n \"badge-cent\",\n \"badge-check\",\n \"verified\",\n \"badge-dollar-sign\",\n \"badge-euro\",\n \"badge-indian-rupee\",\n \"badge-info\",\n \"badge-japanese-yen\",\n \"badge-minus\",\n \"badge-percent\",\n \"badge-plus\",\n \"badge-pound-sterling\",\n \"badge-question-mark\",\n \"badge-help\",\n \"badge-russian-ruble\",\n \"badge-swiss-franc\",\n \"badge-turkish-lira\",\n \"badge-x\",\n \"badge\",\n \"baggage-claim\",\n \"balloon\",\n \"ban\",\n \"banana\",\n \"bandage\",\n \"banknote-arrow-down\",\n \"banknote-arrow-up\",\n \"banknote-x\",\n \"banknote\",\n \"barcode\",\n \"barrel\",\n \"baseline\",\n \"bath\",\n \"battery-charging\",\n \"battery-full\",\n \"battery-low\",\n \"battery-medium\",\n \"battery-plus\",\n \"battery-warning\",\n \"battery\",\n \"beaker\",\n \"bean-off\",\n \"bean\",\n \"bed-double\",\n \"bed-single\",\n \"bed\",\n \"beef-off\",\n \"beef\",\n \"beer-off\",\n \"beer\",\n \"bell-dot\",\n \"bell-electric\",\n \"bell-minus\",\n \"bell-off\",\n \"bell-plus\",\n \"bell-ring\",\n \"bell\",\n \"between-horizontal-end\",\n \"between-horizonal-end\",\n \"between-horizontal-start\",\n \"between-horizonal-start\",\n \"between-vertical-end\",\n \"between-vertical-start\",\n \"biceps-flexed\",\n \"bike\",\n \"binary\",\n \"binoculars\",\n \"biohazard\",\n \"bird\",\n \"birdhouse\",\n \"bitcoin\",\n \"blend\",\n \"blinds\",\n \"blocks\",\n \"bluetooth-connected\",\n \"bluetooth-off\",\n \"bluetooth-searching\",\n \"bluetooth\",\n \"bold\",\n \"bolt\",\n \"bomb\",\n \"bone\",\n \"book-a\",\n \"book-alert\",\n \"book-audio\",\n \"book-check\",\n \"book-copy\",\n \"book-dashed\",\n \"book-template\",\n \"book-down\",\n \"book-headphones\",\n \"book-heart\",\n \"book-image\",\n \"book-key\",\n \"book-lock\",\n \"book-marked\",\n \"book-minus\",\n \"book-open-check\",\n \"book-open-text\",\n \"book-open\",\n \"book-plus\",\n \"book-search\",\n \"book-text\",\n \"book-type\",\n \"book-up-2\",\n \"book-up\",\n \"book-user\",\n \"book-x\",\n \"book\",\n \"bookmark-check\",\n \"bookmark-minus\",\n \"bookmark-off\",\n \"bookmark-plus\",\n \"bookmark-x\",\n \"bookmark\",\n \"boom-box\",\n \"bot-message-square\",\n \"bot-off\",\n \"bot\",\n \"bottle-wine\",\n \"bow-arrow\",\n \"box\",\n \"boxes\",\n \"braces\",\n \"curly-braces\",\n \"brackets\",\n \"brain-circuit\",\n \"brain-cog\",\n \"brain\",\n \"brick-wall-fire\",\n \"brick-wall-shield\",\n \"brick-wall\",\n \"briefcase-business\",\n \"briefcase-conveyor-belt\",\n \"briefcase-medical\",\n \"briefcase\",\n \"bring-to-front\",\n \"brush-cleaning\",\n \"brush\",\n \"bubbles\",\n \"bug-off\",\n \"bug-play\",\n \"bug\",\n \"building-2\",\n \"building\",\n \"bus-front\",\n \"bus\",\n \"cable-car\",\n \"cable\",\n \"cake-slice\",\n \"cake\",\n \"calculator\",\n \"calendar-1\",\n \"calendar-arrow-down\",\n \"calendar-arrow-up\",\n \"calendar-check-2\",\n \"calendar-check\",\n \"calendar-clock\",\n \"calendar-cog\",\n \"calendar-days\",\n \"calendar-fold\",\n \"calendar-heart\",\n \"calendar-minus-2\",\n \"calendar-minus\",\n \"calendar-off\",\n \"calendar-plus-2\",\n \"calendar-plus\",\n \"calendar-range\",\n \"calendar-search\",\n \"calendar-sync\",\n \"calendar-x-2\",\n \"calendar-x\",\n \"calendar\",\n \"calendars\",\n \"camera-off\",\n \"camera\",\n \"candy-cane\",\n \"candy-off\",\n \"candy\",\n \"cannabis-off\",\n \"cannabis\",\n \"captions-off\",\n \"captions\",\n \"subtitles\",\n \"car-front\",\n \"car-taxi-front\",\n \"car\",\n \"caravan\",\n \"card-sim\",\n \"carrot\",\n \"case-lower\",\n \"case-sensitive\",\n \"case-upper\",\n \"cassette-tape\",\n \"cast\",\n \"castle\",\n \"cat\",\n \"cctv-off\",\n \"cctv\",\n \"chart-area\",\n \"area-chart\",\n \"chart-bar-big\",\n \"bar-chart-horizontal-big\",\n \"chart-bar-decreasing\",\n \"chart-bar-increasing\",\n \"chart-bar-stacked\",\n \"chart-bar\",\n \"bar-chart-horizontal\",\n \"chart-candlestick\",\n \"candlestick-chart\",\n \"chart-column-big\",\n \"bar-chart-big\",\n \"chart-column-decreasing\",\n \"chart-column-increasing\",\n \"bar-chart-4\",\n \"chart-column-stacked\",\n \"chart-column\",\n \"bar-chart-3\",\n \"chart-gantt\",\n \"chart-line\",\n \"line-chart\",\n \"chart-network\",\n \"chart-no-axes-column-decreasing\",\n \"chart-no-axes-column-increasing\",\n \"bar-chart\",\n \"chart-no-axes-column\",\n \"bar-chart-2\",\n \"chart-no-axes-combined\",\n \"chart-no-axes-gantt\",\n \"gantt-chart\",\n \"chart-pie\",\n \"pie-chart\",\n \"chart-scatter\",\n \"scatter-chart\",\n \"chart-spline\",\n \"check-check\",\n \"check-line\",\n \"check\",\n \"chef-hat\",\n \"cherry\",\n \"chess-bishop\",\n \"chess-king\",\n \"chess-knight\",\n \"chess-pawn\",\n \"chess-queen\",\n \"chess-rook\",\n \"chevron-down\",\n \"chevron-first\",\n \"chevron-last\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-down-up\",\n \"chevrons-down\",\n \"chevrons-left-right-ellipsis\",\n \"chevrons-left-right\",\n \"chevrons-left\",\n \"chevrons-right-left\",\n \"chevrons-right\",\n \"chevrons-up-down\",\n \"chevrons-up\",\n \"church\",\n \"cigarette-off\",\n \"cigarette\",\n \"circle-alert\",\n \"alert-circle\",\n \"circle-arrow-down\",\n \"arrow-down-circle\",\n \"circle-arrow-left\",\n \"arrow-left-circle\",\n \"circle-arrow-out-down-left\",\n \"arrow-down-left-from-circle\",\n \"circle-arrow-out-down-right\",\n \"arrow-down-right-from-circle\",\n \"circle-arrow-out-up-left\",\n \"arrow-up-left-from-circle\",\n \"circle-arrow-out-up-right\",\n \"arrow-up-right-from-circle\",\n \"circle-arrow-right\",\n \"arrow-right-circle\",\n \"circle-arrow-up\",\n \"arrow-up-circle\",\n \"circle-check-big\",\n \"check-circle\",\n \"circle-check\",\n \"check-circle-2\",\n \"circle-chevron-down\",\n \"chevron-down-circle\",\n \"circle-chevron-left\",\n \"chevron-left-circle\",\n \"circle-chevron-right\",\n \"chevron-right-circle\",\n \"circle-chevron-up\",\n \"chevron-up-circle\",\n \"circle-dashed\",\n \"circle-divide\",\n \"divide-circle\",\n \"circle-dollar-sign\",\n \"circle-dot-dashed\",\n \"circle-dot\",\n \"circle-ellipsis\",\n \"circle-equal\",\n \"circle-fading-arrow-up\",\n \"circle-fading-plus\",\n \"circle-gauge\",\n \"gauge-circle\",\n \"circle-minus\",\n \"minus-circle\",\n \"circle-off\",\n \"circle-parking-off\",\n \"parking-circle-off\",\n \"circle-parking\",\n \"parking-circle\",\n \"circle-pause\",\n \"pause-circle\",\n \"circle-percent\",\n \"percent-circle\",\n \"circle-pile\",\n \"circle-play\",\n \"play-circle\",\n \"circle-plus\",\n \"plus-circle\",\n \"circle-pound-sterling\",\n \"circle-power\",\n \"power-circle\",\n \"circle-question-mark\",\n \"help-circle\",\n \"circle-help\",\n \"circle-slash-2\",\n \"circle-slashed\",\n \"circle-slash\",\n \"circle-small\",\n \"circle-star\",\n \"circle-stop\",\n \"stop-circle\",\n \"circle-user-round\",\n \"user-circle-2\",\n \"circle-user\",\n \"user-circle\",\n \"circle-x\",\n \"x-circle\",\n \"circle\",\n \"circuit-board\",\n \"citrus\",\n \"clapperboard\",\n \"clipboard-check\",\n \"clipboard-clock\",\n \"clipboard-copy\",\n \"clipboard-list\",\n \"clipboard-minus\",\n \"clipboard-paste\",\n \"clipboard-pen-line\",\n \"clipboard-signature\",\n \"clipboard-pen\",\n \"clipboard-edit\",\n \"clipboard-plus\",\n \"clipboard-type\",\n \"clipboard-x\",\n \"clipboard\",\n \"clock-1\",\n \"clock-10\",\n \"clock-11\",\n \"clock-12\",\n \"clock-2\",\n \"clock-3\",\n \"clock-4\",\n \"clock-5\",\n \"clock-6\",\n \"clock-7\",\n \"clock-8\",\n \"clock-9\",\n \"clock-alert\",\n \"clock-arrow-down\",\n \"clock-arrow-up\",\n \"clock-check\",\n \"clock-fading\",\n \"clock-plus\",\n \"clock\",\n \"closed-caption\",\n \"cloud-alert\",\n \"cloud-backup\",\n \"cloud-check\",\n \"cloud-cog\",\n \"cloud-download\",\n \"download-cloud\",\n \"cloud-drizzle\",\n \"cloud-fog\",\n \"cloud-hail\",\n \"cloud-lightning\",\n \"cloud-moon-rain\",\n \"cloud-moon\",\n \"cloud-off\",\n \"cloud-rain-wind\",\n \"cloud-rain\",\n \"cloud-snow\",\n \"cloud-sun-rain\",\n \"cloud-sun\",\n \"cloud-sync\",\n \"cloud-upload\",\n \"upload-cloud\",\n \"cloud\",\n \"cloudy\",\n \"clover\",\n \"club\",\n \"code-xml\",\n \"code-2\",\n \"code\",\n \"coffee\",\n \"cog\",\n \"coins\",\n \"columns-2\",\n \"columns\",\n \"columns-3-cog\",\n \"columns-settings\",\n \"table-config\",\n \"columns-3\",\n \"panels-left-right\",\n \"columns-4\",\n \"combine\",\n \"command\",\n \"compass\",\n \"component\",\n \"computer\",\n \"concierge-bell\",\n \"cone\",\n \"construction\",\n \"contact-round\",\n \"contact-2\",\n \"contact\",\n \"container\",\n \"contrast\",\n \"cookie\",\n \"cooking-pot\",\n \"copy-check\",\n \"copy-minus\",\n \"copy-plus\",\n \"copy-slash\",\n \"copy-x\",\n \"copy\",\n \"copyleft\",\n \"copyright\",\n \"corner-down-left\",\n \"corner-down-right\",\n \"corner-left-down\",\n \"corner-left-up\",\n \"corner-right-down\",\n \"corner-right-up\",\n \"corner-up-left\",\n \"corner-up-right\",\n \"cpu\",\n \"creative-commons\",\n \"credit-card\",\n \"croissant\",\n \"crop\",\n \"cross\",\n \"crosshair\",\n \"crown\",\n \"cuboid\",\n \"cup-soda\",\n \"currency\",\n \"cylinder\",\n \"dam\",\n \"database-backup\",\n \"database-search\",\n \"database-zap\",\n \"database\",\n \"decimals-arrow-left\",\n \"decimals-arrow-right\",\n \"delete\",\n \"dessert\",\n \"diameter\",\n \"diamond-minus\",\n \"diamond-percent\",\n \"percent-diamond\",\n \"diamond-plus\",\n \"diamond\",\n \"dice-1\",\n \"dice-2\",\n \"dice-3\",\n \"dice-4\",\n \"dice-5\",\n \"dice-6\",\n \"dices\",\n \"diff\",\n \"disc-2\",\n \"disc-3\",\n \"disc-album\",\n \"disc\",\n \"divide\",\n \"dna-off\",\n \"dna\",\n \"dock\",\n \"dog\",\n \"dollar-sign\",\n \"donut\",\n \"door-closed-locked\",\n \"door-closed\",\n \"door-open\",\n \"dot\",\n \"download\",\n \"drafting-compass\",\n \"drama\",\n \"drill\",\n \"drone\",\n \"droplet-off\",\n \"droplet\",\n \"droplets\",\n \"drum\",\n \"drumstick\",\n \"dumbbell\",\n \"ear-off\",\n \"ear\",\n \"earth-lock\",\n \"earth\",\n \"globe-2\",\n \"eclipse\",\n \"egg-fried\",\n \"egg-off\",\n \"egg\",\n \"ellipse\",\n \"ellipsis-vertical\",\n \"more-vertical\",\n \"ellipsis\",\n \"more-horizontal\",\n \"equal-approximately\",\n \"equal-not\",\n \"equal\",\n \"eraser\",\n \"ethernet-port\",\n \"euro\",\n \"ev-charger\",\n \"expand\",\n \"external-link\",\n \"eye-closed\",\n \"eye-off\",\n \"eye\",\n \"factory\",\n \"fan\",\n \"fast-forward\",\n \"feather\",\n \"fence\",\n \"ferris-wheel\",\n \"file-archive\",\n \"file-axis-3d\",\n \"file-axis-3-d\",\n \"file-badge\",\n \"file-badge-2\",\n \"file-box\",\n \"file-braces-corner\",\n \"file-json-2\",\n \"file-braces\",\n \"file-json\",\n \"file-chart-column-increasing\",\n \"file-bar-chart\",\n \"file-chart-column\",\n \"file-bar-chart-2\",\n \"file-chart-line\",\n \"file-line-chart\",\n \"file-chart-pie\",\n \"file-pie-chart\",\n \"file-check-corner\",\n \"file-check-2\",\n \"file-check\",\n \"file-clock\",\n \"file-code-corner\",\n \"file-code-2\",\n \"file-code\",\n \"file-cog\",\n \"file-cog-2\",\n \"file-diff\",\n \"file-digit\",\n \"file-down\",\n \"file-exclamation-point\",\n \"file-warning\",\n \"file-headphone\",\n \"file-audio\",\n \"file-audio-2\",\n \"file-heart\",\n \"file-image\",\n \"file-input\",\n \"file-key\",\n \"file-key-2\",\n \"file-lock\",\n \"file-lock-2\",\n \"file-minus-corner\",\n \"file-minus-2\",\n \"file-minus\",\n \"file-music\",\n \"file-output\",\n \"file-pen-line\",\n \"file-signature\",\n \"file-pen\",\n \"file-edit\",\n \"file-play\",\n \"file-video\",\n \"file-plus-corner\",\n \"file-plus-2\",\n \"file-plus\",\n \"file-question-mark\",\n \"file-question\",\n \"file-scan\",\n \"file-search-corner\",\n \"file-search-2\",\n \"file-search\",\n \"file-signal\",\n \"file-volume-2\",\n \"file-sliders\",\n \"file-spreadsheet\",\n \"file-stack\",\n \"file-symlink\",\n \"file-terminal\",\n \"file-text\",\n \"file-type-corner\",\n \"file-type-2\",\n \"file-type\",\n \"file-up\",\n \"file-user\",\n \"file-video-camera\",\n \"file-video-2\",\n \"file-volume\",\n \"file-x-corner\",\n \"file-x-2\",\n \"file-x\",\n \"file\",\n \"files\",\n \"film\",\n \"fingerprint-pattern\",\n \"fingerprint\",\n \"fire-extinguisher\",\n \"fish-off\",\n \"fish-symbol\",\n \"fish\",\n \"fishing-hook\",\n \"fishing-rod\",\n \"flag-off\",\n \"flag-triangle-left\",\n \"flag-triangle-right\",\n \"flag\",\n \"flame-kindling\",\n \"flame\",\n \"flashlight-off\",\n \"flashlight\",\n \"flask-conical-off\",\n \"flask-conical\",\n \"flask-round\",\n \"flip-horizontal-2\",\n \"flip-vertical-2\",\n \"flower-2\",\n \"flower\",\n \"focus\",\n \"fold-horizontal\",\n \"fold-vertical\",\n \"folder-archive\",\n \"folder-check\",\n \"folder-clock\",\n \"folder-closed\",\n \"folder-code\",\n \"folder-cog\",\n \"folder-cog-2\",\n \"folder-dot\",\n \"folder-down\",\n \"folder-git-2\",\n \"folder-git\",\n \"folder-heart\",\n \"folder-input\",\n \"folder-kanban\",\n \"folder-key\",\n \"folder-lock\",\n \"folder-minus\",\n \"folder-open-dot\",\n \"folder-open\",\n \"folder-output\",\n \"folder-pen\",\n \"folder-edit\",\n \"folder-plus\",\n \"folder-root\",\n \"folder-search-2\",\n \"folder-search\",\n \"folder-symlink\",\n \"folder-sync\",\n \"folder-tree\",\n \"folder-up\",\n \"folder-x\",\n \"folder\",\n \"folders\",\n \"footprints\",\n \"forklift\",\n \"form\",\n \"forward\",\n \"frame\",\n \"frown\",\n \"fuel\",\n \"fullscreen\",\n \"funnel-plus\",\n \"funnel-x\",\n \"filter-x\",\n \"funnel\",\n \"filter\",\n \"gallery-horizontal-end\",\n \"gallery-horizontal\",\n \"gallery-thumbnails\",\n \"gallery-vertical-end\",\n \"gallery-vertical\",\n \"gamepad-2\",\n \"gamepad-directional\",\n \"gamepad\",\n \"gauge\",\n \"gavel\",\n \"gem\",\n \"georgian-lari\",\n \"ghost\",\n \"gift\",\n \"git-branch-minus\",\n \"git-branch-plus\",\n \"git-branch\",\n \"git-commit-horizontal\",\n \"git-commit\",\n \"git-commit-vertical\",\n \"git-compare-arrows\",\n \"git-compare\",\n \"git-fork\",\n \"git-graph\",\n \"git-merge-conflict\",\n \"git-merge\",\n \"git-pull-request-arrow\",\n \"git-pull-request-closed\",\n \"git-pull-request-create-arrow\",\n \"git-pull-request-create\",\n \"git-pull-request-draft\",\n \"git-pull-request\",\n \"glass-water\",\n \"glasses\",\n \"globe-lock\",\n \"globe-off\",\n \"globe-x\",\n \"globe\",\n \"goal\",\n \"gpu\",\n \"graduation-cap\",\n \"grape\",\n \"grid-2x2-check\",\n \"grid-2-x-2-check\",\n \"grid-2x2-plus\",\n \"grid-2-x-2-plus\",\n \"grid-2x2-x\",\n \"grid-2-x-2-x\",\n \"grid-2x2\",\n \"grid-2-x-2\",\n \"grid-3x2\",\n \"grid-3x3\",\n \"grid\",\n \"grid-3-x-3\",\n \"grip-horizontal\",\n \"grip-vertical\",\n \"grip\",\n \"group\",\n \"guitar\",\n \"ham\",\n \"hamburger\",\n \"hammer\",\n \"hand-coins\",\n \"hand-fist\",\n \"hand-grab\",\n \"grab\",\n \"hand-heart\",\n \"hand-helping\",\n \"helping-hand\",\n \"hand-metal\",\n \"hand-platter\",\n \"hand\",\n \"handbag\",\n \"handshake\",\n \"hard-drive-download\",\n \"hard-drive-upload\",\n \"hard-drive\",\n \"hard-hat\",\n \"hash\",\n \"hat-glasses\",\n \"haze\",\n \"hd\",\n \"hdmi-port\",\n \"heading-1\",\n \"heading-2\",\n \"heading-3\",\n \"heading-4\",\n \"heading-5\",\n \"heading-6\",\n \"heading\",\n \"headphone-off\",\n \"headphones\",\n \"headset\",\n \"heart-crack\",\n \"heart-handshake\",\n \"heart-minus\",\n \"heart-off\",\n \"heart-plus\",\n \"heart-pulse\",\n \"heart\",\n \"heater\",\n \"helicopter\",\n \"hexagon\",\n \"highlighter\",\n \"history\",\n \"hop-off\",\n \"hop\",\n \"hospital\",\n \"hotel\",\n \"hourglass\",\n \"house-heart\",\n \"house-plug\",\n \"house-plus\",\n \"house-wifi\",\n \"house\",\n \"home\",\n \"ice-cream-bowl\",\n \"ice-cream-2\",\n \"ice-cream-cone\",\n \"ice-cream\",\n \"id-card-lanyard\",\n \"id-card\",\n \"image-down\",\n \"image-minus\",\n \"image-off\",\n \"image-play\",\n \"image-plus\",\n \"image-up\",\n \"image-upscale\",\n \"image\",\n \"images\",\n \"import\",\n \"inbox\",\n \"indian-rupee\",\n \"infinity\",\n \"info\",\n \"inspection-panel\",\n \"italic\",\n \"iteration-ccw\",\n \"iteration-cw\",\n \"japanese-yen\",\n \"joystick\",\n \"kanban\",\n \"kayak\",\n \"key-round\",\n \"key-square\",\n \"key\",\n \"keyboard-music\",\n \"keyboard-off\",\n \"keyboard\",\n \"lamp-ceiling\",\n \"lamp-desk\",\n \"lamp-floor\",\n \"lamp-wall-down\",\n \"lamp-wall-up\",\n \"lamp\",\n \"land-plot\",\n \"landmark\",\n \"languages\",\n \"laptop-minimal-check\",\n \"laptop-minimal\",\n \"laptop-2\",\n \"laptop\",\n \"lasso-select\",\n \"lasso\",\n \"laugh\",\n \"layers-2\",\n \"layers-plus\",\n \"layers\",\n \"layers-3\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-panel-left\",\n \"layout-panel-top\",\n \"layout-template\",\n \"leaf\",\n \"leafy-green\",\n \"lectern\",\n \"lens-concave\",\n \"lens-convex\",\n \"library-big\",\n \"library\",\n \"life-buoy\",\n \"ligature\",\n \"lightbulb-off\",\n \"lightbulb\",\n \"line-dot-right-horizontal\",\n \"line-squiggle\",\n \"line-style\",\n \"link-2-off\",\n \"link-2\",\n \"link\",\n \"list-check\",\n \"list-checks\",\n \"list-chevrons-down-up\",\n \"list-chevrons-up-down\",\n \"list-collapse\",\n \"list-end\",\n \"list-filter-plus\",\n \"list-filter\",\n \"list-indent-decrease\",\n \"outdent\",\n \"indent-decrease\",\n \"list-indent-increase\",\n \"indent\",\n \"indent-increase\",\n \"list-minus\",\n \"list-music\",\n \"list-ordered\",\n \"list-plus\",\n \"list-restart\",\n \"list-start\",\n \"list-todo\",\n \"list-tree\",\n \"list-video\",\n \"list-x\",\n \"list\",\n \"loader-circle\",\n \"loader-2\",\n \"loader-pinwheel\",\n \"loader\",\n \"locate-fixed\",\n \"locate-off\",\n \"locate\",\n \"lock-keyhole-open\",\n \"unlock-keyhole\",\n \"lock-keyhole\",\n \"lock-open\",\n \"unlock\",\n \"lock\",\n \"log-in\",\n \"log-out\",\n \"logs\",\n \"lollipop\",\n \"luggage\",\n \"magnet\",\n \"mail-check\",\n \"mail-minus\",\n \"mail-open\",\n \"mail-plus\",\n \"mail-question-mark\",\n \"mail-question\",\n \"mail-search\",\n \"mail-warning\",\n \"mail-x\",\n \"mail\",\n \"mailbox\",\n \"mails\",\n \"map-minus\",\n \"map-pin-check-inside\",\n \"map-pin-check\",\n \"map-pin-house\",\n \"map-pin-minus-inside\",\n \"map-pin-minus\",\n \"map-pin-off\",\n \"map-pin-pen\",\n \"location-edit\",\n \"map-pin-plus-inside\",\n \"map-pin-plus\",\n \"map-pin-search\",\n \"map-pin-x-inside\",\n \"map-pin-x\",\n \"map-pin\",\n \"map-pinned\",\n \"map-plus\",\n \"map\",\n \"mars-stroke\",\n \"mars\",\n \"martini\",\n \"maximize-2\",\n \"maximize\",\n \"medal\",\n \"megaphone-off\",\n \"megaphone\",\n \"meh\",\n \"memory-stick\",\n \"menu\",\n \"merge\",\n \"message-circle-check\",\n \"message-circle-code\",\n \"message-circle-dashed\",\n \"message-circle-heart\",\n \"message-circle-more\",\n \"message-circle-off\",\n \"message-circle-plus\",\n \"message-circle-question-mark\",\n \"message-circle-question\",\n \"message-circle-reply\",\n \"message-circle-warning\",\n \"message-circle-x\",\n \"message-circle\",\n \"message-square-check\",\n \"message-square-code\",\n \"message-square-dashed\",\n \"message-square-diff\",\n \"message-square-dot\",\n \"message-square-heart\",\n \"message-square-lock\",\n \"message-square-more\",\n \"message-square-off\",\n \"message-square-plus\",\n \"message-square-quote\",\n \"message-square-reply\",\n \"message-square-share\",\n \"message-square-text\",\n \"message-square-warning\",\n \"message-square-x\",\n \"message-square\",\n \"messages-square\",\n \"metronome\",\n \"mic-off\",\n \"mic-vocal\",\n \"mic-2\",\n \"mic\",\n \"microchip\",\n \"microscope\",\n \"microwave\",\n \"milestone\",\n \"milk-off\",\n \"milk\",\n \"minimize-2\",\n \"minimize\",\n \"minus\",\n \"mirror-rectangular\",\n \"mirror-round\",\n \"monitor-check\",\n \"monitor-cloud\",\n \"monitor-cog\",\n \"monitor-dot\",\n \"monitor-down\",\n \"monitor-off\",\n \"monitor-pause\",\n \"monitor-play\",\n \"monitor-smartphone\",\n \"monitor-speaker\",\n \"monitor-stop\",\n \"monitor-up\",\n \"monitor-x\",\n \"monitor\",\n \"moon-star\",\n \"moon\",\n \"motorbike\",\n \"mountain-snow\",\n \"mountain\",\n \"mouse-left\",\n \"mouse-off\",\n \"mouse-pointer-2-off\",\n \"mouse-pointer-2\",\n \"mouse-pointer-ban\",\n \"mouse-pointer-click\",\n \"mouse-pointer\",\n \"mouse-right\",\n \"mouse\",\n \"move-3d\",\n \"move-3-d\",\n \"move-diagonal-2\",\n \"move-diagonal\",\n \"move-down-left\",\n \"move-down-right\",\n \"move-down\",\n \"move-horizontal\",\n \"move-left\",\n \"move-right\",\n \"move-up-left\",\n \"move-up-right\",\n \"move-up\",\n \"move-vertical\",\n \"move\",\n \"music-2\",\n \"music-3\",\n \"music-4\",\n \"music\",\n \"navigation-2-off\",\n \"navigation-2\",\n \"navigation-off\",\n \"navigation\",\n \"network\",\n \"newspaper\",\n \"nfc\",\n \"non-binary\",\n \"notebook-pen\",\n \"notebook-tabs\",\n \"notebook-text\",\n \"notebook\",\n \"notepad-text-dashed\",\n \"notepad-text\",\n \"nut-off\",\n \"nut\",\n \"octagon-alert\",\n \"alert-octagon\",\n \"octagon-minus\",\n \"octagon-pause\",\n \"pause-octagon\",\n \"octagon-x\",\n \"x-octagon\",\n \"octagon\",\n \"omega\",\n \"option\",\n \"orbit\",\n \"origami\",\n \"package-2\",\n \"package-check\",\n \"package-minus\",\n \"package-open\",\n \"package-plus\",\n \"package-search\",\n \"package-x\",\n \"package\",\n \"paint-bucket\",\n \"paint-roller\",\n \"paintbrush-vertical\",\n \"paintbrush-2\",\n \"paintbrush\",\n \"palette\",\n \"panda\",\n \"panel-bottom-close\",\n \"panel-bottom-dashed\",\n \"panel-bottom-inactive\",\n \"panel-bottom-open\",\n \"panel-bottom\",\n \"panel-left-close\",\n \"sidebar-close\",\n \"panel-left-dashed\",\n \"panel-left-inactive\",\n \"panel-left-open\",\n \"sidebar-open\",\n \"panel-left-right-dashed\",\n \"panel-left\",\n \"sidebar\",\n \"panel-right-close\",\n \"panel-right-dashed\",\n \"panel-right-inactive\",\n \"panel-right-open\",\n \"panel-right\",\n \"panel-top-bottom-dashed\",\n \"panel-top-close\",\n \"panel-top-dashed\",\n \"panel-top-inactive\",\n \"panel-top-open\",\n \"panel-top\",\n \"panels-left-bottom\",\n \"panels-right-bottom\",\n \"panels-top-left\",\n \"layout\",\n \"paperclip\",\n \"parentheses\",\n \"parking-meter\",\n \"party-popper\",\n \"pause\",\n \"paw-print\",\n \"pc-case\",\n \"pen-line\",\n \"edit-3\",\n \"pen-off\",\n \"pen-tool\",\n \"pen\",\n \"edit-2\",\n \"pencil-line\",\n \"pencil-off\",\n \"pencil-ruler\",\n \"pencil\",\n \"pentagon\",\n \"percent\",\n \"person-standing\",\n \"philippine-peso\",\n \"phone-call\",\n \"phone-forwarded\",\n \"phone-incoming\",\n \"phone-missed\",\n \"phone-off\",\n \"phone-outgoing\",\n \"phone\",\n \"pi\",\n \"piano\",\n \"pickaxe\",\n \"picture-in-picture-2\",\n \"picture-in-picture\",\n \"piggy-bank\",\n \"pilcrow-left\",\n \"pilcrow-right\",\n \"pilcrow\",\n \"pill-bottle\",\n \"pill\",\n \"pin-off\",\n \"pin\",\n \"pipette\",\n \"pizza\",\n \"plane-landing\",\n \"plane-takeoff\",\n \"plane\",\n \"play\",\n \"plug-2\",\n \"plug-zap\",\n \"plug-zap-2\",\n \"plug\",\n \"plus\",\n \"pocket-knife\",\n \"podcast\",\n \"pointer-off\",\n \"pointer\",\n \"popcorn\",\n \"popsicle\",\n \"pound-sterling\",\n \"power-off\",\n \"power\",\n \"presentation\",\n \"printer-check\",\n \"printer-x\",\n \"printer\",\n \"projector\",\n \"proportions\",\n \"puzzle\",\n \"pyramid\",\n \"qr-code\",\n \"quote\",\n \"rabbit\",\n \"radar\",\n \"radiation\",\n \"radical\",\n \"radio-off\",\n \"radio-receiver\",\n \"radio-tower\",\n \"radio\",\n \"radius\",\n \"rainbow\",\n \"rat\",\n \"ratio\",\n \"receipt-cent\",\n \"receipt-euro\",\n \"receipt-indian-rupee\",\n \"receipt-japanese-yen\",\n \"receipt-pound-sterling\",\n \"receipt-russian-ruble\",\n \"receipt-swiss-franc\",\n \"receipt-text\",\n \"receipt-turkish-lira\",\n \"receipt\",\n \"rectangle-circle\",\n \"rectangle-ellipsis\",\n \"form-input\",\n \"rectangle-goggles\",\n \"rectangle-horizontal\",\n \"rectangle-vertical\",\n \"recycle\",\n \"redo-2\",\n \"redo-dot\",\n \"redo\",\n \"refresh-ccw-dot\",\n \"refresh-ccw\",\n \"refresh-cw-off\",\n \"refresh-cw\",\n \"refrigerator\",\n \"regex\",\n \"remove-formatting\",\n \"repeat-1\",\n \"repeat-2\",\n \"repeat\",\n \"replace-all\",\n \"replace\",\n \"reply-all\",\n \"reply\",\n \"rewind\",\n \"ribbon\",\n \"road\",\n \"rocket\",\n \"rocking-chair\",\n \"roller-coaster\",\n \"rose\",\n \"rotate-3d\",\n \"rotate-3-d\",\n \"rotate-ccw-key\",\n \"rotate-ccw-square\",\n \"rotate-ccw\",\n \"rotate-cw-square\",\n \"rotate-cw\",\n \"route-off\",\n \"route\",\n \"router\",\n \"rows-2\",\n \"rows\",\n \"rows-3\",\n \"panels-top-bottom\",\n \"rows-4\",\n \"rss\",\n \"ruler-dimension-line\",\n \"ruler\",\n \"russian-ruble\",\n \"sailboat\",\n \"salad\",\n \"sandwich\",\n \"satellite-dish\",\n \"satellite\",\n \"saudi-riyal\",\n \"save-all\",\n \"save-off\",\n \"save\",\n \"scale-3d\",\n \"scale-3-d\",\n \"scale\",\n \"scaling\",\n \"scan-barcode\",\n \"scan-eye\",\n \"scan-face\",\n \"scan-heart\",\n \"scan-line\",\n \"scan-qr-code\",\n \"scan-search\",\n \"scan-text\",\n \"scan\",\n \"school\",\n \"scissors-line-dashed\",\n \"scissors\",\n \"scooter\",\n \"screen-share-off\",\n \"screen-share\",\n \"scroll-text\",\n \"scroll\",\n \"search-alert\",\n \"search-check\",\n \"search-code\",\n \"search-slash\",\n \"search-x\",\n \"search\",\n \"section\",\n \"send-horizontal\",\n \"send-horizonal\",\n \"send-to-back\",\n \"send\",\n \"separator-horizontal\",\n \"separator-vertical\",\n \"server-cog\",\n \"server-crash\",\n \"server-off\",\n \"server\",\n \"settings-2\",\n \"settings\",\n \"shapes\",\n \"share-2\",\n \"share\",\n \"sheet\",\n \"shell\",\n \"shelving-unit\",\n \"shield-alert\",\n \"shield-ban\",\n \"shield-check\",\n \"shield-cog-corner\",\n \"shield-cog\",\n \"shield-ellipsis\",\n \"shield-half\",\n \"shield-minus\",\n \"shield-off\",\n \"shield-plus\",\n \"shield-question-mark\",\n \"shield-question\",\n \"shield-user\",\n \"shield-x\",\n \"shield-close\",\n \"shield\",\n \"ship-wheel\",\n \"ship\",\n \"shirt\",\n \"shopping-bag\",\n \"shopping-basket\",\n \"shopping-cart\",\n \"shovel\",\n \"shower-head\",\n \"shredder\",\n \"shrimp\",\n \"shrink\",\n \"shrub\",\n \"shuffle\",\n \"sigma\",\n \"signal-high\",\n \"signal-low\",\n \"signal-medium\",\n \"signal-zero\",\n \"signal\",\n \"signature\",\n \"signpost-big\",\n \"signpost\",\n \"siren\",\n \"skip-back\",\n \"skip-forward\",\n \"skull\",\n \"slash\",\n \"slice\",\n \"sliders-horizontal\",\n \"sliders-vertical\",\n \"sliders\",\n \"smartphone-charging\",\n \"smartphone-nfc\",\n \"smartphone\",\n \"smile-plus\",\n \"smile\",\n \"snail\",\n \"snowflake\",\n \"soap-dispenser-droplet\",\n \"sofa\",\n \"solar-panel\",\n \"soup\",\n \"space\",\n \"spade\",\n \"sparkle\",\n \"sparkles\",\n \"stars\",\n \"speaker\",\n \"speech\",\n \"spell-check-2\",\n \"spell-check\",\n \"spline-pointer\",\n \"spline\",\n \"split\",\n \"spool\",\n \"sport-shoe\",\n \"spotlight\",\n \"spray-can\",\n \"sprout\",\n \"square-activity\",\n \"activity-square\",\n \"square-arrow-down-left\",\n \"arrow-down-left-square\",\n \"square-arrow-down-right\",\n \"arrow-down-right-square\",\n \"square-arrow-down\",\n \"arrow-down-square\",\n \"square-arrow-left\",\n \"arrow-left-square\",\n \"square-arrow-out-down-left\",\n \"arrow-down-left-from-square\",\n \"square-arrow-out-down-right\",\n \"arrow-down-right-from-square\",\n \"square-arrow-out-up-left\",\n \"arrow-up-left-from-square\",\n \"square-arrow-out-up-right\",\n \"arrow-up-right-from-square\",\n \"square-arrow-right-enter\",\n \"square-arrow-right-exit\",\n \"square-arrow-right\",\n \"arrow-right-square\",\n \"square-arrow-up-left\",\n \"arrow-up-left-square\",\n \"square-arrow-up-right\",\n \"arrow-up-right-square\",\n \"square-arrow-up\",\n \"arrow-up-square\",\n \"square-asterisk\",\n \"asterisk-square\",\n \"square-bottom-dashed-scissors\",\n \"scissors-square-dashed-bottom\",\n \"square-centerline-dashed-horizontal\",\n \"flip-horizontal\",\n \"square-centerline-dashed-vertical\",\n \"flip-vertical\",\n \"square-chart-gantt\",\n \"gantt-chart-square\",\n \"square-gantt-chart\",\n \"square-check-big\",\n \"check-square\",\n \"square-check\",\n \"check-square-2\",\n \"square-chevron-down\",\n \"chevron-down-square\",\n \"square-chevron-left\",\n \"chevron-left-square\",\n \"square-chevron-right\",\n \"chevron-right-square\",\n \"square-chevron-up\",\n \"chevron-up-square\",\n \"square-code\",\n \"code-square\",\n \"square-dashed-bottom-code\",\n \"square-dashed-bottom\",\n \"square-dashed-kanban\",\n \"kanban-square-dashed\",\n \"square-dashed-mouse-pointer\",\n \"mouse-pointer-square-dashed\",\n \"square-dashed-text\",\n \"text-selection\",\n \"text-select\",\n \"square-dashed-top-solid\",\n \"square-dashed\",\n \"box-select\",\n \"square-divide\",\n \"divide-square\",\n \"square-dot\",\n \"dot-square\",\n \"square-equal\",\n \"equal-square\",\n \"square-function\",\n \"function-square\",\n \"square-kanban\",\n \"kanban-square\",\n \"square-library\",\n \"library-square\",\n \"square-m\",\n \"m-square\",\n \"square-menu\",\n \"menu-square\",\n \"square-minus\",\n \"minus-square\",\n \"square-mouse-pointer\",\n \"inspect\",\n \"square-parking-off\",\n \"parking-square-off\",\n \"square-parking\",\n \"parking-square\",\n \"square-pause\",\n \"square-pen\",\n \"pen-box\",\n \"edit\",\n \"pen-square\",\n \"square-percent\",\n \"percent-square\",\n \"square-pi\",\n \"pi-square\",\n \"square-pilcrow\",\n \"pilcrow-square\",\n \"square-play\",\n \"play-square\",\n \"square-plus\",\n \"plus-square\",\n \"square-power\",\n \"power-square\",\n \"square-radical\",\n \"square-round-corner\",\n \"square-scissors\",\n \"scissors-square\",\n \"square-sigma\",\n \"sigma-square\",\n \"square-slash\",\n \"slash-square\",\n \"square-split-horizontal\",\n \"split-square-horizontal\",\n \"square-split-vertical\",\n \"split-square-vertical\",\n \"square-square\",\n \"square-stack\",\n \"square-star\",\n \"square-stop\",\n \"square-terminal\",\n \"terminal-square\",\n \"square-user-round\",\n \"user-square-2\",\n \"square-user\",\n \"user-square\",\n \"square-x\",\n \"x-square\",\n \"square\",\n \"squares-exclude\",\n \"squares-intersect\",\n \"squares-subtract\",\n \"squares-unite\",\n \"squircle-dashed\",\n \"squircle\",\n \"squirrel\",\n \"stamp\",\n \"star-half\",\n \"star-off\",\n \"star\",\n \"step-back\",\n \"step-forward\",\n \"stethoscope\",\n \"sticker\",\n \"sticky-note\",\n \"stone\",\n \"store\",\n \"stretch-horizontal\",\n \"stretch-vertical\",\n \"strikethrough\",\n \"subscript\",\n \"sun-dim\",\n \"sun-medium\",\n \"sun-moon\",\n \"sun-snow\",\n \"sun\",\n \"sunrise\",\n \"sunset\",\n \"superscript\",\n \"swatch-book\",\n \"swiss-franc\",\n \"switch-camera\",\n \"sword\",\n \"swords\",\n \"syringe\",\n \"table-2\",\n \"table-cells-merge\",\n \"table-cells-split\",\n \"table-columns-split\",\n \"table-of-contents\",\n \"table-properties\",\n \"table-rows-split\",\n \"table\",\n \"tablet-smartphone\",\n \"tablet\",\n \"tablets\",\n \"tag\",\n \"tags\",\n \"tally-1\",\n \"tally-2\",\n \"tally-3\",\n \"tally-4\",\n \"tally-5\",\n \"tangent\",\n \"target\",\n \"telescope\",\n \"tent-tree\",\n \"tent\",\n \"terminal\",\n \"test-tube-diagonal\",\n \"test-tube-2\",\n \"test-tube\",\n \"test-tubes\",\n \"text-align-center\",\n \"align-center\",\n \"text-align-end\",\n \"align-right\",\n \"text-align-justify\",\n \"align-justify\",\n \"text-align-start\",\n \"text\",\n \"align-left\",\n \"text-cursor-input\",\n \"text-cursor\",\n \"text-initial\",\n \"letter-text\",\n \"text-quote\",\n \"text-search\",\n \"text-wrap\",\n \"wrap-text\",\n \"theater\",\n \"thermometer-snowflake\",\n \"thermometer-sun\",\n \"thermometer\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket-check\",\n \"ticket-minus\",\n \"ticket-percent\",\n \"ticket-plus\",\n \"ticket-slash\",\n \"ticket-x\",\n \"ticket\",\n \"tickets-plane\",\n \"tickets\",\n \"timer-off\",\n \"timer-reset\",\n \"timer\",\n \"toggle-left\",\n \"toggle-right\",\n \"toilet\",\n \"tool-case\",\n \"toolbox\",\n \"tornado\",\n \"torus\",\n \"touchpad-off\",\n \"touchpad\",\n \"towel-rack\",\n \"tower-control\",\n \"toy-brick\",\n \"tractor\",\n \"traffic-cone\",\n \"train-front-tunnel\",\n \"train-front\",\n \"train-track\",\n \"tram-front\",\n \"train\",\n \"transgender\",\n \"trash-2\",\n \"trash\",\n \"tree-deciduous\",\n \"tree-palm\",\n \"palmtree\",\n \"tree-pine\",\n \"trees\",\n \"trending-down\",\n \"trending-up-down\",\n \"trending-up\",\n \"triangle-alert\",\n \"alert-triangle\",\n \"triangle-dashed\",\n \"triangle-right\",\n \"triangle\",\n \"trophy\",\n \"truck-electric\",\n \"truck\",\n \"turkish-lira\",\n \"turntable\",\n \"turtle\",\n \"tv-minimal-play\",\n \"tv-minimal\",\n \"tv-2\",\n \"tv\",\n \"type-outline\",\n \"type\",\n \"umbrella-off\",\n \"umbrella\",\n \"underline\",\n \"undo-2\",\n \"undo-dot\",\n \"undo\",\n \"unfold-horizontal\",\n \"unfold-vertical\",\n \"ungroup\",\n \"university\",\n \"school-2\",\n \"unlink-2\",\n \"unlink\",\n \"unplug\",\n \"upload\",\n \"usb\",\n \"user-check\",\n \"user-cog\",\n \"user-key\",\n \"user-lock\",\n \"user-minus\",\n \"user-pen\",\n \"user-plus\",\n \"user-round-check\",\n \"user-check-2\",\n \"user-round-cog\",\n \"user-cog-2\",\n \"user-round-key\",\n \"user-round-minus\",\n \"user-minus-2\",\n \"user-round-pen\",\n \"user-round-plus\",\n \"user-plus-2\",\n \"user-round-search\",\n \"user-round-x\",\n \"user-x-2\",\n \"user-round\",\n \"user-2\",\n \"user-search\",\n \"user-star\",\n \"user-x\",\n \"user\",\n \"users-round\",\n \"users-2\",\n \"users\",\n \"utensils-crossed\",\n \"fork-knife-crossed\",\n \"utensils\",\n \"fork-knife\",\n \"utility-pole\",\n \"van\",\n \"variable\",\n \"vault\",\n \"vector-square\",\n \"vegan\",\n \"venetian-mask\",\n \"venus-and-mars\",\n \"venus\",\n \"vibrate-off\",\n \"vibrate\",\n \"video-off\",\n \"video\",\n \"videotape\",\n \"view\",\n \"voicemail\",\n \"volleyball\",\n \"volume-1\",\n \"volume-2\",\n \"volume-off\",\n \"volume-x\",\n \"volume\",\n \"vote\",\n \"wallet-cards\",\n \"wallet-minimal\",\n \"wallet-2\",\n \"wallet\",\n \"wallpaper\",\n \"wand-sparkles\",\n \"wand-2\",\n \"wand\",\n \"warehouse\",\n \"washing-machine\",\n \"watch\",\n \"waves-arrow-down\",\n \"waves-arrow-up\",\n \"waves-ladder\",\n \"waves\",\n \"waypoints\",\n \"webcam\",\n \"webhook-off\",\n \"webhook\",\n \"weight-tilde\",\n \"weight\",\n \"wheat-off\",\n \"wheat\",\n \"whole-word\",\n \"wifi-cog\",\n \"wifi-high\",\n \"wifi-low\",\n \"wifi-off\",\n \"wifi-pen\",\n \"wifi-sync\",\n \"wifi-zero\",\n \"wifi\",\n \"wind-arrow-down\",\n \"wind\",\n \"wine-off\",\n \"wine\",\n \"workflow\",\n \"worm\",\n \"wrench\",\n \"x-line-top\",\n \"x\",\n \"zap-off\",\n \"zap\",\n \"zodiac-aquarius\",\n \"zodiac-aries\",\n \"zodiac-cancer\",\n \"zodiac-capricorn\",\n \"zodiac-gemini\",\n \"zodiac-leo\",\n \"zodiac-libra\",\n \"zodiac-ophiuchus\",\n \"zodiac-pisces\",\n \"zodiac-sagittarius\",\n \"zodiac-scorpio\",\n \"zodiac-taurus\",\n \"zodiac-virgo\",\n \"zoom-in\",\n \"zoom-out\",\n]);\n\nexport const LAYOUT_SECTION_ICON_SET: ReadonlySet<string> = new Set(LAYOUT_SECTION_ICONS);\nexport type LayoutSectionIcon = string;\n","/**\n * Generated by scripts/gen-dock-icon-names.mjs from the vendored icon tarball\n * (sha256 0691620e50bdf453c2fed06224d9dc52d521574ab254a149eba47664b92fb889)\n * and the vendored line-icon subset (sha256 06cd85d602d1104d962ed8ace64f6c4d64846ee50bd62bd328252c9d8f697b75).\n * Do not edit by hand: rerun the script (`--check` fails CI on drift).\n *\n * The closed vocabulary for `ui.icon` (field ui, fieldsets, prop ui.group). `as const` because a\n * z.enum needs the literal tuple; a `readonly string[]` would type every string as valid.\n */\nexport const DOCK_ICON_NAMES = [\n \"abc\",\n \"access-denied\",\n \"activity\",\n \"add\",\n \"add-circle\",\n \"add-comment\",\n \"add-document\",\n \"add-user\",\n \"address-book\",\n \"adjustments\",\n \"adjustments-horizontal\",\n \"alarm\",\n \"alert-triangle\",\n \"align-left\",\n \"api\",\n \"app-window\",\n \"apple\",\n \"apps\",\n \"archive\",\n \"arrow-back-up\",\n \"arrow-down\",\n \"arrow-guide\",\n \"arrow-left\",\n \"arrow-right\",\n \"arrow-top-right\",\n \"arrow-up\",\n \"arrows-diagonal\",\n \"arrows-down\",\n \"arrows-exchange\",\n \"arrows-horizontal\",\n \"arrows-left-right\",\n \"arrows-shuffle\",\n \"arrows-sort\",\n \"article\",\n \"aspect-ratio\",\n \"asterisk\",\n \"award\",\n \"axis-x\",\n \"backpack\",\n \"badge\",\n \"badge-cc\",\n \"badges\",\n \"bar-chart\",\n \"basket\",\n \"bell\",\n \"bill\",\n \"binary-document\",\n \"block-content\",\n \"block-element\",\n \"blockquote\",\n \"bold\",\n \"bolt\",\n \"book\",\n \"book-2\",\n \"bookmark\",\n \"bookmark-filled\",\n \"books\",\n \"bottle\",\n \"box\",\n \"brand-dribbble\",\n \"brand-facebook\",\n \"brand-instagram\",\n \"brand-linkedin\",\n \"brand-pinterest\",\n \"brand-tiktok\",\n \"brand-x\",\n \"brand-youtube\",\n \"briefcase\",\n \"broadcast\",\n \"browser\",\n \"bug\",\n \"building\",\n \"building-skyscraper\",\n \"building-store\",\n \"bulb-filled\",\n \"bulb-outline\",\n \"calculator\",\n \"calendar\",\n \"calendar-dollar\",\n \"calendar-event\",\n \"calendar-exclamation\",\n \"calendar-off\",\n \"calendar-plus\",\n \"calendar-star\",\n \"calendar-time\",\n \"camera\",\n \"campfire\",\n \"carousel-horizontal\",\n \"case\",\n \"cash\",\n \"category\",\n \"category-2\",\n \"chart-area\",\n \"chart-arrows\",\n \"chart-bar\",\n \"chart-bar-popular\",\n \"chart-donut\",\n \"chart-dots\",\n \"chart-line\",\n \"chart-upward\",\n \"check\",\n \"checkbox\",\n \"checklist\",\n \"checkmark\",\n \"checkmark-circle\",\n \"chef-hat\",\n \"chevron-down\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-right\",\n \"circle\",\n \"circle-check\",\n \"circle-dot\",\n \"circle-number-1\",\n \"circle-plus\",\n \"click\",\n \"clipboard\",\n \"clipboard-image\",\n \"clipboard-text\",\n \"clock\",\n \"clock-check\",\n \"clock-hour-4\",\n \"close\",\n \"close-circle\",\n \"code\",\n \"code-block\",\n \"cog\",\n \"collapse\",\n \"color-wheel\",\n \"columns\",\n \"columns-2\",\n \"columns-3\",\n \"comment\",\n \"component\",\n \"compose\",\n \"compose-sparkles\",\n \"confetti\",\n \"controls\",\n \"cookie\",\n \"copy\",\n \"credit-card\",\n \"crop\",\n \"cube\",\n \"currency-dollar\",\n \"dashboard\",\n \"database\",\n \"database-search\",\n \"desktop\",\n \"device-desktop\",\n \"device-mobile\",\n \"device-tablet\",\n \"devices\",\n \"diamond\",\n \"discount\",\n \"document\",\n \"document-pdf\",\n \"document-remove\",\n \"document-sheet\",\n \"document-text\",\n \"document-video\",\n \"document-word\",\n \"document-zip\",\n \"documents\",\n \"door-exit\",\n \"dot\",\n \"double-chevron-down\",\n \"double-chevron-left\",\n \"double-chevron-right\",\n \"double-chevron-up\",\n \"double-quote\",\n \"download\",\n \"drag-handle\",\n \"drop\",\n \"droplet\",\n \"droplet-half\",\n \"earth-americas\",\n \"earth-globe\",\n \"edit\",\n \"egg\",\n \"ellipsis-horizontal\",\n \"ellipsis-vertical\",\n \"empty\",\n \"enter\",\n \"enter-right\",\n \"envelope\",\n \"equal\",\n \"error-filled\",\n \"error-outline\",\n \"error-screen\",\n \"expand\",\n \"eye-closed\",\n \"eye-off\",\n \"eye-open\",\n \"face-happy\",\n \"face-indifferent\",\n \"face-sad\",\n \"feather\",\n \"feedback\",\n \"file\",\n \"file-certificate\",\n \"file-code\",\n \"file-download\",\n \"file-text\",\n \"filter\",\n \"flag\",\n \"flame\",\n \"flask\",\n \"focus-2\",\n \"folder\",\n \"folders\",\n \"forms\",\n \"frame\",\n \"generate\",\n \"gift\",\n \"git-branch\",\n \"github\",\n \"grid-dots\",\n \"groq\",\n \"hammer\",\n \"hand-finger\",\n \"hanger\",\n \"hash\",\n \"headphones\",\n \"headset\",\n \"heart\",\n \"heart-filled\",\n \"heart-handshake\",\n \"help-circle\",\n \"highlight\",\n \"history\",\n \"home\",\n \"hourglass\",\n \"ice-cream\",\n \"id-badge\",\n \"id-badge-2\",\n \"image\",\n \"image-remove\",\n \"images\",\n \"inbox\",\n \"infinity\",\n \"info-circle\",\n \"info-filled\",\n \"info-outline\",\n \"info-square-rounded\",\n \"inline\",\n \"inline-element\",\n \"input-search\",\n \"insert-above\",\n \"insert-below\",\n \"italic\",\n \"joystick\",\n \"json\",\n \"language\",\n \"launch\",\n \"layout\",\n \"layout-align-center\",\n \"layout-board\",\n \"layout-board-split\",\n \"layout-bottombar\",\n \"layout-bottombar-expand\",\n \"layout-cards\",\n \"layout-columns\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-navbar\",\n \"layout-rows\",\n \"layout-sidebar\",\n \"layout-sidebar-right\",\n \"leaf\",\n \"leave\",\n \"lemon\",\n \"library-photo\",\n \"lifebuoy\",\n \"link\",\n \"link-removed\",\n \"linkedin\",\n \"list\",\n \"list-check\",\n \"list-details\",\n \"list-numbers\",\n \"list-tree\",\n \"lock\",\n \"logo-js\",\n \"logo-ts\",\n \"mail\",\n \"map-2\",\n \"map-pin\",\n \"map-pins\",\n \"marker\",\n \"marker-removed\",\n \"master-detail\",\n \"math-function\",\n \"meat\",\n \"menu\",\n \"message\",\n \"message-2\",\n \"message-check\",\n \"message-circle\",\n \"message-circle-2\",\n \"message-plus\",\n \"message-star\",\n \"microphone\",\n \"microphone-slash\",\n \"mobile-device\",\n \"mood-empty\",\n \"moon\",\n \"movie\",\n \"news\",\n \"notes\",\n \"number\",\n \"ok-hand\",\n \"olist\",\n \"overage\",\n \"package\",\n \"packages\",\n \"palette\",\n \"panel-left\",\n \"panel-right\",\n \"paperclip\",\n \"pause\",\n \"pencil\",\n \"phone\",\n \"photo\",\n \"photo-scan\",\n \"photo-search\",\n \"pig-money\",\n \"pin\",\n \"pin-filled\",\n \"pin-removed\",\n \"play\",\n \"player-play\",\n \"player-track-next\",\n \"playlist-add\",\n \"plug\",\n \"plug-connected\",\n \"plus-minus\",\n \"point\",\n \"presentation\",\n \"printer\",\n \"progress-50\",\n \"progress-75\",\n \"projects\",\n \"publish\",\n \"qrcode\",\n \"quote\",\n \"read-only\",\n \"receipt\",\n \"recycle\",\n \"redo\",\n \"refresh\",\n \"remove\",\n \"remove-circle\",\n \"repeat\",\n \"reset\",\n \"restore\",\n \"retrieve\",\n \"retry\",\n \"revert\",\n \"robot\",\n \"rocket\",\n \"rosette\",\n \"route\",\n \"ruler\",\n \"ruler-measure\",\n \"salad\",\n \"scale\",\n \"schema\",\n \"school\",\n \"search\",\n \"section\",\n \"select\",\n \"send\",\n \"server\",\n \"settings\",\n \"share\",\n \"shield-check\",\n \"shield-lock\",\n \"shopping-bag\",\n \"shopping-cart\",\n \"shopping-cart-plus\",\n \"signature\",\n \"sitemap\",\n \"slideshow\",\n \"sort\",\n \"sort-descending\",\n \"spacing-vertical\",\n \"sparkle\",\n \"sparkles\",\n \"speakerphone\",\n \"spinner\",\n \"split-horizontal\",\n \"split-vertical\",\n \"square\",\n \"stack\",\n \"stack-2\",\n \"stack-compact\",\n \"stairs\",\n \"stairs-up\",\n \"star\",\n \"star-filled\",\n \"stars\",\n \"stop\",\n \"strikethrough\",\n \"string\",\n \"subtask\",\n \"sun\",\n \"superscript\",\n \"sync\",\n \"table\",\n \"table-options\",\n \"tablet-device\",\n \"tag\",\n \"tags\",\n \"target\",\n \"task\",\n \"template\",\n \"tent\",\n \"terminal\",\n \"terminal-2\",\n \"text\",\n \"th-large\",\n \"th-list\",\n \"thumb-up\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket\",\n \"tiers\",\n \"timeline\",\n \"toggle-arrow-right\",\n \"toggle-right\",\n \"token\",\n \"tool\",\n \"tools-kitchen-2\",\n \"transfer\",\n \"translate\",\n \"trash\",\n \"trend-upward\",\n \"triangle-outline\",\n \"trolley\",\n \"truck\",\n \"truck-delivery\",\n \"truncate\",\n \"twitter\",\n \"typography\",\n \"ulist\",\n \"unarchive\",\n \"underline\",\n \"undo\",\n \"unknown\",\n \"unlink\",\n \"unlock\",\n \"unpublish\",\n \"upload\",\n \"user\",\n \"user-circle\",\n \"user-plus\",\n \"user-search\",\n \"user-star\",\n \"users\",\n \"users-group\",\n \"versions\",\n \"video\",\n \"vocabulary\",\n \"vs\",\n \"warning-filled\",\n \"warning-outline\",\n \"weight\",\n \"world\",\n \"wrench\",\n \"zoom-question\",\n] as const;\n\nexport type DockIconName = (typeof DOCK_ICON_NAMES)[number];\n\nexport const DOCK_ICON_NAME_SET: ReadonlySet<string> = new Set<string>(DOCK_ICON_NAMES);\n","/**\n * The dock's icon vocabulary as an MCP resource (`bettercms://icons/dock`), served by both surfaces.\n *\n * A resource and not an enum in a tool schema: the list is ~6 KB, and every tool that inlines a\n * field or prop definition would pay for it on every tools/list. The schemas carry a string (stdio\n * refines it against DOCK_ICON_SET) and point here; the server's z.enum is the guard.\n */\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET } from \"@bettercms-ai/types\";\n\nexport const DOCK_ICONS_URI = \"bettercms://icons/dock\";\nexport const DOCK_ICON_SET: ReadonlySet<string> = DOCK_ICON_NAME_SET;\n\nexport const DOCK_ICONS_RESOURCE = {\n uri: DOCK_ICONS_URI,\n name: \"dock-icons\",\n title: \"BetterCMS dock icon names\",\n description:\n \"Every name `ui.icon`, a fieldset's `icon` and a prop's `ui.group.icon` accept. Layout section icons are a different list (Lucide names).\",\n mimeType: \"text/markdown\",\n};\n\nexport const DOCK_ICONS_TEXT = `# Dock icon names\n\n\\`ui.icon\\` on a nesting field, \\`icon\\` on a fieldset and \\`ui.group.icon\\` on a component prop take ONE\nname from this list. Any other string is refused with a 400 that names this resource. A leaf field\nnever carries an icon.\n\nTwo vocabularies, on purpose: Layout section icons (update_layout \\`add-section\\`) stay Lucide names.\nA name from one list is not valid in the other.\n\nThe list includes the V2 kit's line-icon names (\\`building\\`, \\`settings\\`, \\`layout-grid\\`, …) as themselves.\n\n${DOCK_ICON_NAMES.length} names:\n\n${DOCK_ICON_NAMES.join(\", \")}\n`;\n","/**\n * How to ORGANISE a BetterCMS project's Content sidebar — the structure standard, as a resource.\n *\n * Same rules as playbook.ts: dependency-free strings, one copy read by both MCP surfaces (the\n * hosted /mcp resource list and the stdio server). The algorithm these rules describe lives in\n * the backend (src/lib/content-navigation/standard.ts) and runs in two places — the import lane\n * that derives a structure for a site imported from GitHub, and the read-only\n * `suggest_content_structure` tool. The worked example below is that algorithm's actual output\n * for the input it describes; a backend test derives it and compares, so the two cannot drift.\n */\n\nexport const STRUCTURE_PLAYBOOK_URI = \"bettercms://playbook/structure\";\n\n/**\n * The server-instructions sentence both MCP surfaces carry: organising is the DEFAULT after an\n * agent creates collections or pages, not something it does only when asked.\n */\nexport const STRUCTURE_DEFAULT_INSTRUCTION =\n `After you create collections or pages, organise them per the structure playbook: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure (read-only), show the user its outline, then apply it with set_content_structure and the version it returned (the If-Match). A project that already has a structure keeps it: file only what you created, with move_to_folder, unless the user asks for a full re-organisation.`;\n\n/**\n * The other sentence both MCP surfaces carry: code-side skills are loaded by their description, so\n * the server points at the one that routes to the rest. Harmless where no skill is installed.\n * The catalog is one core skill whose table names a reference per task (progressive disclosure),\n * so the sentence asks for ONE reference: reading every reference is the context cost it avoids.\n */\nexport const SKILLS_ROUTING_INSTRUCTION =\n \"Before writing code in a repo that uses BetterCMS, explore the repo, then read the installed `bettercms` skill (`npx @bettercms-ai/install --project -y` adds it if missing): its table turns what you found into the one reference the task needs — read only that. Without the skill installed, read the same files as resources: bettercms://skill/bettercms, then bettercms://skill/<reference>.\";\n\n/** Both surfaces: editor chrome (the dock) has one doctrine, one write path and one receipt. */\nexport const DOCK_UI_ROUTING_INSTRUCTION =\n \"How fields and props look in the editor (groups, tabs, rows, icons, item names) is playbook §14 or the `field-ui` prompt: write it with update_content_model field* or update_component prop* plus ifMatch, read it back, and finish when get_next_steps reports no dock-* step.\";\n\n/** Both surfaces: an author's \"Hold edits back\" (V2 D53) is a decision a whole-site publish respects. */\nexport const PUBLISH_HOLD_INSTRUCTION =\n \"An item an author held back from site publishes (`publishHeldAt` set) stays out of whole-site publishes: do not publish it unless the user names it; publish_entries `release` includes it again.\";\n\n/**\n * Receipt first: both MCP surfaces open a project on get_next_steps, whose `receipt` says what\n * the platform already sees as done, what is missing and the one next action. Starting from it is\n * what stops an agent redoing finished work or converting the one page it happened to land on.\n */\nexport const RECEIPT_FIRST_INSTRUCTION =\n \"Start every project with get_next_steps: its `receipt` lists what is already done (`done`), what is still missing (`missing`, each item citing the count it reacted to) and the one `nextAction`. Work from that receipt instead of re-reading the site, call get_next_steps again after each batch of edits, and before you tell the user you are finished. On an imported site the gate is the definition of done: run `receipt.gate.nextAction`, read again, and repeat until `receipt.complete` is true. Record a gap you cannot close with editor_setup `exempt` only for an allowed reason that is true, with a note, never in prose.\";\n\n/** The get_next_steps tool description, shared by both surfaces so they cannot drift. */\nexport const NEXT_STEPS_DESCRIPTION =\n `Call this FIRST on a project. Returns \\`receipt\\` — \\`done\\` (live release, bound elements, conversion coverage, composed pages, published components and Layout), \\`missing\\`, \\`nextAction\\` and \\`notes\\` (unjudged: unknown, not done) — plus \\`data\\`, the unfinished items by \\`ruleId\\` (skill finish-site lists them). Each item cites its count and may carry \\`payload\\` {rows, total}, at most 20 rows. \\`receipt.complete\\` is the setup gate's verdict and \\`receipt.gate\\` its numbers per built route. Run \\`receipt.gate.nextAction\\`, call it again after each batch; you are finished only when \\`complete\\` is true. \\`organise-content\\`: pages and collections are in no folder — read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure and, once the user agrees, set_content_structure.`;\n\n/**\n * Site chrome, routed — the sentence both MCP surfaces carry: nav and footer are the project\n * Layout, never page fields, and the get_next_steps Layout rules point back here.\n */\nexport const LAYOUT_CHROME_INSTRUCTION =\n \"When the user asks to make the navigation, footer or other site chrome editable, or get_next_steps lists a `layout-*` or `chrome-duplicated` item: this is playbook §11 item 3. Chrome is the project Layout, never page fields: in the source, wrap each Section in `data-bcms-layout-section` (the slot, its base slug) and mark each value `data-bcms-layout-field=\\\"layout:<sections[slug].id>:<fieldId>\\\"`, never `data-bcms-field` inside it, then push; the strip removes the page copies, never delete them by hand. On a site BetterCMS serves, publish_layout writes Layout VALUES into the live pages; a structure change waits for a Rebuild. Never place nav, footer or modal blocks or fields on a page: the Layout (or the site's own layout) draws chrome, so a page copy either duplicates it or renders nowhere (get_componentize_plan reports one as LAYOUT_CHROME).\";\n\n/**\n * A call to action, said once for both surfaces: one `button` field, never a label field beside a\n * link field. The management lane refuses the importer's spelling of a pair (`cta_pair`), and\n * update_field `mergeHref` upgrades a pair a page already holds. @see BUTTON_FIELD_NOTE\n */\nexport const CTA_BUTTON_INSTRUCTION =\n \"A call to action is ONE `button` field (value {label, href, variant?, size?, arrow?, icon?, newTab?}), rendered with BcmsButton from @bettercms-ai/astro or @bettercms-ai/next: never a text field beside a link field. A page that already holds such a pair (primaryCtaText + primaryCtaHref) becomes one button with update_field `mergeHref`. Inside a component a CTA is a `button` block whose text and href two props target.\";\n\n/** The worked example's `set_content_structure` payload, exported so the backend test can compare. */\nexport const STRUCTURE_EXAMPLE_PAYLOAD = {\n version: 0,\n doc: {\n schema: 1,\n folders: [\n { id: \"home:pages\", parentId: null, name: \"Pages\", icon: \"documents\", sort: 1000 },\n { id: \"home:collections\", parentId: null, name: \"Shared\", icon: null, sort: 1001 },\n { id: \"fld_std_blog\", parentId: null, name: \"Blog posts\", icon: \"document-text\", sort: 0 },\n { id: \"fld_std_products\", parentId: null, name: \"Products\", icon: \"basket\", sort: 1 },\n ],\n items: [\n { kind: \"page\", id: \"pg_home\", folderId: \"home:root\", sort: 0, icon: null },\n { kind: \"page\", id: \"pg_blog\", folderId: \"home:root\", sort: 1, icon: null },\n { kind: \"page\", id: \"pg_shop\", folderId: \"home:root\", sort: 2, icon: null },\n { kind: \"collection\", id: \"cm_posts\", folderId: \"fld_std_blog\", sort: 0, icon: null },\n { kind: \"collection\", id: \"cm_products\", folderId: \"fld_std_products\", sort: 0, icon: null },\n { kind: \"collection\", id: \"cm_categories\", folderId: \"fld_std_products\", sort: 1, icon: null },\n { kind: \"collection\", id: \"cm_colours\", folderId: \"fld_std_products\", sort: 2, icon: null },\n { kind: \"collection\", id: \"cm_tags\", folderId: \"home:collections\", sort: 0, icon: null },\n { kind: \"page\", id: \"pg_about\", folderId: \"home:pages\", sort: 0, icon: null },\n { kind: \"page\", id: \"pg_contact\", folderId: \"home:pages\", sort: 1, icon: null },\n { kind: \"page\", id: \"pg_404\", folderId: \"home:pages\", sort: 2, icon: \"code\" },\n ],\n },\n} as const;\n\nexport const STRUCTURE_PLAYBOOK = `# Organising a BetterCMS project: the Content structure standard\n\nRead this BEFORE you organise the Content sidebar, and AFTER you create collections or pages:\nthe default is to organise what you made by these rules. The sidebar is one document per\nproject, \\`{ schema: 1, folders: [{ id, parentId, name, icon, sort }], items: [{ kind: 'page' |\n'collection', id, folderId, sort, icon }] }\\`, read with \\`get_content_structure\\` and written with\n\\`set_content_structure\\`. It is ORGANISATION ONLY: no URL, slug, schema, content or publish state\never changes.\n\n## The rules\n\n1. **One place per document.** Every page and every collection sits in exactly ONE place: pinned\n at the top level (\\`folderId: \"home:root\"\\`) or in one folder. A folder lists only its direct\n contents. Never list an id twice.\n2. **Pinned at the top:** the home page, then each collection's LIST page (the dynamic page that\n lists it, e.g. /blog). A single document opens straight into the editor, so it is a pin, not a\n folder with one page in it.\n3. **One folder per content family, named for the DETAIL type its route holds.** /blog gives\n \"Blog posts\", /case-studies \"Case studies\", /careers \"Jobs\".\n - Blog: a \"Blog posts\" folder holding the blog collection. A folder with exactly one\n collection opens that collection's table directly.\n - Commerce: a \"Products\" folder holding the product collection AND its taxonomies (product\n categories, product tags, merch collections, ...). Once there are more than four taxonomies,\n the VARIANT OPTIONS (colours, sizes, materials) move into an \"Attributes\" subfolder; the\n categories and tags stay beside the catalogue.\n - Decide the rest by the REFERENCE GRAPH: a collection that is referenced only by one family,\n or that references only one family (reviews → products), belongs in that family's folder.\n The family's main collection comes first, then the others in the order its fields reference\n them.\n4. **Family order:** the site's navigation order; failing that, entry count, then name.\n5. **Pages.** EVERY remaining standalone page goes in the system folder \\`home:pages\\`\n (\"Pages\") — no standalone page ever gets a top-level folder. Code-only routes (a 404, a\n page built by code with nothing to edit) stay there too, marked with the \\`file-code\\` icon.\n Pages that share a route (/legal/terms, /legal/privacy, /docs/...) get a subfolder of it.\n A site in more than one language files every page, home included, under Pages › <language>\n (named in itself: English, Français, Deutsch), default language first.\n6. **Shared taxonomies.** A vocabulary several families reference (Tags used by posts AND\n products) goes in the system folder \\`home:collections\\`, named \"Shared\". So does supporting\n content no family owns (testimonials, FAQs with no list page).\n7. **Settings closes the sidebar.** \\`home:globals\\` (\"Settings\") holds NO pages or collections —\n navigation, header, footer, site settings and SEO defaults open from it in the dashboard. The\n three system folders always sort BELOW the folders you make: … Pages, Shared, Settings.\n8. **Icons** (kit names, bettercms://icons/dock): \\`document-text\\` for posts, \\`basket\\` for products,\n \\`book\\` for docs, \\`documents\\` for Pages, \\`folder\\` by default. Lucide names already stored\n still draw.\n9. **Depth:** nest at most 2 levels by default. The hard limit is 4; do not use it without a\n reason the user gave you.\n10. **Organisation only.** Never rename a page, change a slug, touch a schema or move content to\n make a structure fit. The structure fits the site, not the other way round.\n11. **Page-bound models are not collections.** A page with fields has a content model bound to\n it; it is never filed (400 \\`NAV_PAGE_BOUND_MODEL\\`). Organise the PAGE.\n12. **Access:** changing the structure needs Admin or Developer, the same as editing the schema;\n reading needs only content access. A 403 \\`SCHEMA_ACCESS_REQUIRED\\` means this connection is\n neither: stop and tell the user, do not retry.\n\n## Refusals\n\nWhat the structure writes refuse, and the code each refusal carries:\n\n- **System folders.** \\`home:pages\\` (Pages), \\`home:collections\\` (Shared) and\n \\`home:globals\\` (Settings) always exist and can never be moved or deleted (400\n \\`NAV_SYSTEM_FOLDER\\`); \\`rename_folder\\` and \\`set_icon\\` work on them.\n- **Type purity** (400 \\`NAV_TYPE_MISMATCH\\`): Pages holds only pages at any depth, Shared\n only collections, Settings neither — globals are not sidebar items.\n- **Pins** sit above the folders in their own order, pages or collections. In a document a pin is\n \\`folderId: \"home:root\"\\`, a virtual id with no folder record; a folder record with that id is\n 400 \\`NAV_SYSTEM_FOLDER\\`. In \\`move_to_folder\\`, \\`folderId: 'root'\\` pins and \\`null\\` returns\n the item to its home (Pages / Shared).\n- **Kind.** \\`move_to_folder\\` and \\`set_icon\\` VERIFY what an id is: a page id sent as a\n collection is 400 \\`NAV_KIND_MISMATCH\\` naming the kind to use. \\`set_content_structure\\` never\n refuses a kind mismatch: it returns \\`warnings\\` and \\`kindMismatches\\` instead.\n- **Page-bound models** are refused with 400 \\`NAV_PAGE_BOUND_MODEL\\` naming their page; organise\n the page, by its page id.\n- **Shape:** folders nest at most 4 levels deep; names are 1-80 characters; icons are kit\n names (bettercms://icons/dock; a-z, 0-9, dashes) and null clears one.\n- **Access:** 403 \\`SCHEMA_ACCESS_REQUIRED\\` (rule 12).\n- **Version:** 412 \\`VERSION_CONFLICT\\` (workflow step 4).\n\n## The workflow\n\n1. \\`get_content_structure\\` — note \\`version\\` and whether a structure exists.\n2. \\`suggest_content_structure\\` — READ-ONLY. It runs the platform's own implementation of these\n rules over the project's pages, collections, references and routes and returns\n \\`{ doc, outline, rationale, version, hasDocument }\\`. It writes nothing.\n3. Show the user the \\`outline\\`. If \\`hasDocument\\` is true the project ALREADY has a structure\n someone made: never replace it without the user's explicit yes. Offer to file only what is\n new (\\`move_to_folder\\` per item) instead.\n4. Apply with \\`set_content_structure { doc, version }\\`, where \\`version\\` is the one you read —\n it is the If-Match. A 412 \\`VERSION_CONFLICT\\` means someone changed the sidebar since: read it\n again and re-apply; never overwrite blind.\n5. For one or two new documents, prefer \\`move_to_folder\\` into the matching family folder.\n\nProjects imported from GitHub get this structure automatically (the \"Organising your content\"\nstep of the import), but only when they have none yet; a later import files NEW documents into\nthe matching folder and changes nothing else.\n\n## Worked example: a blog plus a shop\n\nThe site: a home page (\\`pg_home\\`), a /blog list page (\\`pg_blog\\`, dynamic) for the Blog\ncollection (\\`cm_posts\\`), a /shop list page (\\`pg_shop\\`, dynamic) for Products\n(\\`cm_products\\`), About (\\`pg_about\\`), Contact (\\`pg_contact\\`) and a code-only 404\n(\\`pg_404\\`). Products references Product categories (\\`cm_categories\\`) and Colours\n(\\`cm_colours\\`); both Blog and Products reference Tags (\\`cm_tags\\`).\n\n\\`\\`\\`text\n[pinned page] Home\n[pinned page] Blog (/blog lists Blog)\n[pinned page] Shop (/shop lists Products)\n[folder] Blog posts icon=newspaper\n Blog\n[folder] Products icon=shopping-bag\n Products, Product categories, Colours (referenced only by Products)\n[system folder] Pages icon=files\n About, Contact, Not found (icon=file-code)\n[system folder] Shared\n Tags (referenced by Blog AND Products: shared)\n[system folder] Settings (navigation, header, footer, site settings, SEO defaults)\n\\`\\`\\`\n\nThe exact \\`set_content_structure\\` payload (\\`version: 0\\` because the project had no structure):\n\n\\`\\`\\`json\n${JSON.stringify(STRUCTURE_EXAMPLE_PAYLOAD, null, 2)}\n\\`\\`\\`\n`;\n","/**\n * update_content_entry's merge, planned once for every agent surface (stdio, hosted, Studio).\n *\n * The entry PATCH REPLACES `data` wholesale, so changing one field meant reading the entry and\n * sending every other field back by hand — and an agent that forgot one deleted it. So merge is\n * the default: the host reads the entry, lays the caller's keys over the stored ones, and writes\n * at the version it read: a concurrent edit between the read and the write is a 409, never a\n * silent overwrite. Only an explicit `merge: false` replaces the whole object.\n *\n * Dependency-free on purpose: the hosted catalog (src/routes/mcp/index.ts) imports it across the\n * package boundary, like playbook.ts.\n */\n\nexport interface StoredEntry {\n data?: Record<string, unknown> | null;\n optimisticVersion?: number | null;\n}\n\nexport interface MergedEntryWrite {\n /** The stored data with the caller's keys laid over it, by top-level key. */\n data: Record<string, unknown>;\n /** The If-Match to write at: the caller's own when given, else the version that was read. */\n ifMatch?: number;\n}\n\n/** True unless the caller asked for a full replace (`merge: false`) or sent no `data`. */\nexport const mergesEntry = (args: { merge?: unknown; data?: unknown }): boolean =>\n args.merge !== false && args.data !== undefined;\n\n/**\n * Shallow merge by top-level key. A key the caller sends replaces the stored value whole (a group\n * or repeater value is one key); a key it omits is kept; `null` is a value like any other.\n */\nexport function planEntryMerge(\n stored: StoredEntry,\n patch: Record<string, unknown>,\n callerIfMatch?: number,\n): MergedEntryWrite {\n const data = { ...(stored.data ?? {}), ...patch };\n const ifMatch = callerIfMatch ?? (typeof stored.optimisticVersion === \"number\" ? stored.optimisticVersion : undefined);\n return ifMatch === undefined ? { data } : { data, ifMatch };\n}\n","/**\n * `whoami`: who a connection acts as, for access troubleshooting. One description for both MCP\n * surfaces (the hosted catalog imports it across the package boundary, like playbook.ts).\n *\n * The two surfaces answer from what each can actually know. The hosted connector resolves the\n * caller's credential on every call, so it reports the principal, the scope and the grants. The\n * stdio server holds only an access token and has no route that reports a key's grants, so it\n * reports the scope it can observe (whether the Management API resolves a project without one\n * being named) and says that grants are not visible from there — never a guess.\n */\n\nexport const WHOAMI_DESCRIPTION =\n \"Who this connection acts as. Call it first when a call is refused for access. Returns the principal (`device_grant` from the connect flow, or `api_key`), the workspace, `scope` ('project' = bound to one project; 'workspace' = pass projectId on every project tool) and, where the server can see them, `grants`: content:publish takes content live, artifact:write runs the code and deploy tools, schema:manage changes the Content sidebar. `grants: null` means this server cannot see them, not that there are none. Reads nothing else and changes nothing.\";\n\n/** The grants whoami names, keyed to what each one unlocks. */\nexport const WHOAMI_GRANT_FLAGS = {\n canPublish: \"content:publish\",\n canWriteArtifacts: \"artifact:write\",\n canChangeStructure: \"schema:manage\",\n} as const;\n\n/** `{ canPublish, canWriteArtifacts, canChangeStructure }` from a key's permission list. */\nexport function grantFlags(permissions: readonly string[]): Record<keyof typeof WHOAMI_GRANT_FLAGS, boolean> {\n return {\n canPublish: permissions.includes(WHOAMI_GRANT_FLAGS.canPublish),\n canWriteArtifacts: permissions.includes(WHOAMI_GRANT_FLAGS.canWriteArtifacts),\n canChangeStructure: permissions.includes(WHOAMI_GRANT_FLAGS.canChangeStructure),\n };\n}\n","/**\n * Model-schema edits planned once for both MCP surfaces: `update_content_model` `removeFields`\n * and `update_field`. Both end in the one write the model PATCH offers — a whole `fields` array,\n * sent at the version read — because that PATCH REPLACES the list wholesale, and an agent retyping\n * the whole schema to change one field is how the rest of it gets lost. So the host reads the\n * model, changes exactly what was named, and writes the rest back untouched.\n *\n * Removal: `removeFields` + `allowFieldRemoval` drop named TOP-LEVEL keys (otherwise a key that\n * still has content is a 409). Nothing is removed by accident: both arguments are required\n * together, an unknown key refuses the whole call, and a page's fields go through\n * remove_page_fields, which has a dry run.\n *\n * Edit: `update_field` patches ONE field anywhere in the tree, addressed by a dot path through its\n * group/repeater children. A retype needs `allowRetype`; a key rename leaves the old key's content\n * to the route's orphan guard (409 with the entry count unless allowFieldRemoval).\n *\n * Dependency-free on purpose: the hosted catalog imports it across the package boundary.\n */\n\nexport type FieldRemovalRequest =\n | { kind: \"none\" }\n | { kind: \"refuse\"; error: string }\n | { kind: \"remove\"; keys: string[] };\n\n/** What the caller asked for, judged before anything is read. */\nexport function fieldRemovalRequest(args: {\n removeFields?: unknown;\n allowFieldRemoval?: unknown;\n pageId?: unknown;\n}): FieldRemovalRequest {\n const { removeFields, allowFieldRemoval, pageId } = args;\n if (removeFields === undefined && allowFieldRemoval === undefined) return { kind: \"none\" };\n if (removeFields === undefined) {\n return { kind: \"refuse\", error: \"allowFieldRemoval names no field: pass removeFields with the top-level keys to delete.\" };\n }\n if (!Array.isArray(removeFields) || removeFields.length === 0 || !removeFields.every((k) => typeof k === \"string\" && k)) {\n return { kind: \"refuse\", error: \"removeFields must be a non-empty list of top-level field keys (from get_content_model).\" };\n }\n if (pageId !== undefined) {\n return { kind: \"refuse\", error: \"A page's fields are removed with remove_page_fields, which has a dry run; removeFields takes modelId.\" };\n }\n if (allowFieldRemoval !== true) {\n return {\n kind: \"refuse\",\n error: \"removeFields deletes those fields and DISCARDS their values in every entry: send allowFieldRemoval: true with it, once the user has agreed.\",\n };\n }\n return { kind: \"remove\", keys: [...new Set(removeFields as string[])] };\n}\n\nexport interface StoredModel {\n fields?: Array<{ key?: unknown; [prop: string]: unknown }> | null;\n optimisticVersion?: number | null;\n}\n\nexport type FieldRemovalPlan =\n | { ok: true; fields: Array<{ key?: unknown }>; ifMatch?: number }\n | { ok: false; error: string };\n\n/** The model's `fields` without the named top-level keys, and the If-Match to write at. */\nexport function planFieldRemoval(model: StoredModel, keys: string[], callerIfMatch?: number): FieldRemovalPlan {\n const fields = model.fields ?? [];\n const present = new Set(fields.map((f) => f.key));\n const unknown = keys.filter((k) => !present.has(k));\n if (unknown.length > 0) {\n return {\n ok: false,\n error: `Not top-level fields of this model: ${unknown.join(\", \")}. Nothing was removed; read get_content_model for its keys (a group's child goes with its group, or is edited in the dashboard).`,\n };\n }\n const drop = new Set(keys);\n const ifMatch = callerIfMatch ?? (typeof model.optimisticVersion === \"number\" ? model.optimisticVersion : undefined);\n const kept = fields.filter((f) => !drop.has(f.key as string));\n return ifMatch === undefined ? { ok: true, fields: kept } : { ok: true, fields: kept, ifMatch };\n}\n\n// ── update_field ─────────────────────────────────────────────────────────────\n\ntype Field = Record<string, unknown>;\n\n/** What update_field may change on one field. `null` clears helpText, showIf, ui, placement, the lock pair and the V2 keys. */\nexport interface FieldEdit {\n path?: unknown;\n label?: unknown;\n helpText?: unknown;\n required?: unknown;\n config?: unknown;\n showIf?: unknown;\n ui?: unknown;\n placement?: unknown;\n readOnly?: unknown;\n lockReason?: unknown;\n helpMore?: unknown;\n advanced?: unknown;\n recommendedMax?: unknown;\n openMode?: unknown;\n localized?: unknown;\n type?: unknown;\n key?: unknown;\n allowRetype?: unknown;\n}\n\nexport type FieldEditPlan =\n | { ok: true; fields: Field[]; ifMatch?: number; renamed?: { from: string; to: string } }\n | { ok: false; error: string };\n\n/**\n * Where a field keeps its children, in the shapes a stored schema uses: the off-config `fields`,\n * a group's `config.zones.nonRepeatable` (the list itself), a repeater's\n * `config.zones.repeatable.fields`, and an object array's `config.fields` / `config.itemFields`.\n * Mirrors childListsOf in src/lib/content/field-paths.ts.\n */\nconst CHILD_LISTS: string[][] = [\n [\"fields\"],\n [\"config\", \"zones\", \"nonRepeatable\"],\n [\"config\", \"zones\", \"repeatable\", \"fields\"],\n [\"config\", \"fields\"],\n [\"config\", \"itemFields\"],\n];\n\nconst getIn = (node: unknown, at: string[]): unknown =>\n at.reduce<unknown>((n, k) => (n && typeof n === \"object\" ? (n as Field)[k] : undefined), node);\n\nconst setIn = (node: Field, [head, ...rest]: string[], value: unknown): Field =>\n ({ ...node, [head]: rest.length === 0 ? value : setIn((node[head] ?? {}) as Field, rest, value) });\n\n/** The fields list with the field at `keys` replaced by `edit(field)`, or null when no such field. */\nfunction patchAt(fields: Field[], [key, ...rest]: string[], edit: (f: Field) => Field): Field[] | null {\n const at = fields.findIndex((f) => f.key === key);\n if (at === -1) return null;\n const field = fields[at];\n let next: Field | null = null;\n if (rest.length === 0) next = edit(field);\n else {\n for (const list of CHILD_LISTS) {\n const kids = getIn(field, list);\n const patched = Array.isArray(kids) ? patchAt(kids as Field[], rest, edit) : null;\n if (patched) {\n next = setIn(field, list, patched);\n break;\n }\n }\n }\n return next && fields.map((f, i) => (i === at ? next : f));\n}\n\n/** The field at a dot path, or undefined. */\nfunction fieldAt(fields: Field[], keys: string[]): Field | undefined {\n let found: Field | undefined;\n patchAt(fields, keys, (f) => ((found = f), f));\n return found;\n}\n\n/** Every key in the tree — the namespace is flat, nested fields included. */\nfunction allKeys(fields: Field[]): string[] {\n return fields.flatMap((f) => [\n String(f.key),\n ...CHILD_LISTS.flatMap((list) => {\n const kids = getIn(f, list);\n return Array.isArray(kids) ? allKeys(kids as Field[]) : [];\n }),\n ]);\n}\n\nconst CLEARABLE = [\"helpText\", \"showIf\", \"ui\", \"placement\", \"readOnly\", \"lockReason\", \"helpMore\", \"advanced\", \"recommendedMax\", \"openMode\", \"localized\"] as const;\nconst SETTABLE = [\"label\", \"required\", ...CLEARABLE] as const;\n\n/** Shallow-merge a config patch; a null key deletes it, so a group's zones are never lost. */\nfunction mergeConfig(current: unknown, patch: Record<string, unknown>): Field {\n const out: Field = { ...((current ?? {}) as Field) };\n for (const [k, v] of Object.entries(patch)) {\n if (v === null) delete out[k];\n else out[k] = v;\n }\n return out;\n}\n\nconst wordsOf = (v: unknown): string =>\n (typeof v === \"string\" ? v : typeof (v as { label?: unknown })?.label === \"string\" ? (v as { label: string }).label : \"\")\n .replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim().toLowerCase();\n\n/**\n * Why `helpText` is no help for this field, or null. Help that repeats the field — its label, the\n * value it holds, or `e.g. \"<that value>\"` — tells an editor nothing the input does not already\n * show (`e.g. \"Starter Kit\"` under an input holding \"Starter Kit\"). One check for update_field\n * and the server's fieldHelpText / propHelpText writes, so the two cannot disagree.\n */\nexport function helpTextEcho(helpText: unknown, field: { label?: unknown; defaultValue?: unknown }): string | null {\n if (typeof helpText !== \"string\" || !helpText.trim()) return null;\n const said = wordsOf(helpText.replace(/^\\s*e\\.?g\\.?[:,]?\\s*/i, \"\")).replace(/^[\"'“”‘’]+|[\"'“”‘’.…]+$/g, \"\");\n const value = wordsOf(field.defaultValue);\n const echoes = said === wordsOf(field.label) || (value !== \"\" && (said === value || (/…[\"”]?$/.test(helpText.trim()) && value.startsWith(said))));\n return echoes\n ? \"helpText repeats the field's label or value, which the editor already shows. Say what belongs here or its format in under 60 characters (\\\"Whole number, no currency symbol.\\\"), or send null for none.\"\n : null;\n}\n\n/** The model's `fields` with ONE field changed, and the If-Match to write at. */\nexport function planFieldEdit(model: StoredModel, edit: FieldEdit, callerIfMatch?: number): FieldEditPlan {\n const fields = (model.fields ?? []) as Field[];\n const keys = typeof edit.path === \"string\" && edit.path ? edit.path.split(\".\") : [];\n const current = keys.length ? fieldAt(fields, keys) : undefined;\n if (!current) {\n return { ok: false, error: `No field at path '${String(edit.path ?? \"\")}'. Paths are dot-separated keys from get_content_model or get_page, e.g. 'hero.title'.` };\n }\n const retype = edit.type !== undefined && edit.type !== current.type;\n if (retype && edit.allowRetype !== true) {\n return {\n ok: false,\n error: `Changing '${keys.join(\".\")}' from ${String(current.type)} to ${String(edit.type)} changes how every stored value is read, and values that do not fit are lost. Send allowRetype: true with it, once the user has agreed.`,\n };\n }\n const rename = typeof edit.key === \"string\" && edit.key !== current.key ? edit.key : undefined;\n if (rename !== undefined && allKeys(fields).includes(rename)) {\n return { ok: false, error: `The key '${rename}' is already used in this schema; keys share one flat namespace, nested fields included.` };\n }\n const changes = SETTABLE.filter((k) => edit[k] !== undefined);\n if (!retype && rename === undefined && edit.config === undefined && changes.length === 0) {\n 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.\" };\n }\n const echo = helpTextEcho(edit.helpText, { label: edit.label ?? current.label, defaultValue: current.defaultValue });\n if (echo) return { ok: false, error: echo };\n const next = patchAt(fields, keys, (f) => {\n let out: Field = { ...f };\n for (const k of changes) {\n if (edit[k] === null && (CLEARABLE as readonly string[]).includes(k)) delete out[k];\n else out[k] = edit[k];\n }\n // `ui` merges per key like `fieldUi` (field-ui-write.ts): sending { reorderable: false } must\n // not drop a stored collapsed/preview. A null member clears that key; `ui: null` clears it all.\n if (edit.ui && typeof edit.ui === \"object\") {\n const ui = mergeConfig(f.ui, edit.ui as Record<string, unknown>);\n if (Object.keys(ui).length > 0) out.ui = ui;\n else delete out.ui;\n }\n if (edit.config && typeof edit.config === \"object\") out = { ...out, config: mergeConfig(f.config, edit.config as Record<string, unknown>) };\n if (retype) out.type = edit.type;\n if (rename !== undefined) out.key = rename;\n return out;\n })!;\n const ifMatch = callerIfMatch ?? (typeof model.optimisticVersion === \"number\" ? model.optimisticVersion : undefined);\n return {\n ok: true,\n fields: next,\n ...(ifMatch === undefined ? {} : { ifMatch }),\n ...(rename === undefined ? {} : { renamed: { from: String(current.key), to: rename } }),\n };\n}\n","/**\n * Which tools a connection LISTS, decided once for both MCP surfaces.\n *\n * The hosted connector reads `?tools=` off its URL; the stdio server reads the\n * BETTERCMS_MCP_TOOLS environment variable. Both hand the raw string to `toolsetsOf` and ask\n * `listsTool` per name, so `core`, `abm` and `all` mean the same thing wherever an agent connects.\n *\n * Dependency-free on purpose: the hosted catalog (src/routes/mcp/index.ts) imports it across the\n * package boundary, like entry-merge.ts.\n */\n\n/**\n * 🔴 WHICH 100 SURVIVE A CLIENT THAT KEEPS 100 IS OUR DECISION, NOT ITS.\n *\n * Claude Desktop shows a server's first ~100 tools and silently drops the rest (MCP discussion\n * #537). The tail is what a connector can lose first: the agent-job lane, component evidence,\n * analytics, entry history and the one-off project operations. Both surfaces list it LAST, and\n * every tool in it stays callable.\n * @see MCP-TRUNCATION-FACTS.md\n */\nexport const LISTING_TAIL: ReadonlySet<string> = new Set([\n // The agent-job lane: a dashboard surface an agent rarely drives.\n \"list_ai_jobs\", \"get_ai_job\", \"approve_ai_job\", \"reject_ai_job\", \"list_ai_reports\",\n \"connect_native_ai\",\n // Component validation: a CI lane, not an authoring one.\n \"request_component_validation\", \"declare_component_route\", \"clear_component_source\",\n \"submit_componentize_receipt\",\n // Reporting, history and workflow chrome.\n \"get_analytics_overview\", \"get_analytics_top_pages\", \"list_activity\", \"get_workflow_board\",\n \"move_stage\", \"list_entry_versions\", \"restore_entry_version\",\n // One-off project operations and the extraction lane.\n \"clone_project\", \"promote_project\", \"generate_pages_from_dataset\", \"extract_component\",\n \"list_extraction_candidates\", \"create_deploy_upload\", \"import_redirects\",\n \"set_authoring_preference\", \"set_media_delivery\", \"delete_form_submission\", \"remove_page_fields\",\n // Access troubleshooting and platform feedback: called when something is refused or missing.\n \"whoami\", \"give_feedback\", \"search_docs\",\n // Search, batch and localisation: reached for once the site exists.\n \"search_content\", \"discard_draft\", \"publish_entries\", \"create_content_entries\", \"translate_entry\",\n \"update_field\", \"refresh_search_index\",\n // Automation, branches and AI images.\n \"list_webhooks\", \"create_webhook\", \"list_branches\", \"create_branch\", \"apply_branch\",\n \"generate_image\", \"transform_image\", \"write_alt_text\",\n // The ABM campaign lane — also hidden from the default listing (ABM_TOOLS below).\n \"research_account\", \"build_abm_page\", \"claim_abm_task\", \"complete_abm_task\", \"fail_abm_task\",\n \"get_campaign_review\", \"regenerate_entry\", \"approve_campaign_entries\", \"publish_campaign\",\n \"get_campaign_share_link\", \"revoke_campaign_share_link\",\n]);\n\n/**\n * The ABM campaign lane: a marketer's surface plus the worker tools a task runner claims with.\n * Listed only when asked for (`?tools=abm`, BETTERCMS_MCP_TOOLS=abm), because eleven tools every\n * other connection reads and never calls are a tax on each of them.\n */\nexport const ABM_TOOLS: ReadonlySet<string> = new Set([\n \"research_account\", \"build_abm_page\", \"claim_abm_task\", \"complete_abm_task\", \"fail_abm_task\",\n \"get_campaign_review\", \"regenerate_entry\", \"approve_campaign_entries\", \"publish_campaign\",\n \"get_campaign_share_link\", \"revoke_campaign_share_link\",\n]);\n\nexport const TOOLSETS = [\"core\", \"abm\", \"all\"] as const;\nexport type Toolset = (typeof TOOLSETS)[number];\n\n/** A comma list (`core,abm`) → the named toolsets; unknown names are ignored, empty = default. */\nexport function toolsetsOf(raw: string | null | undefined): Set<Toolset> {\n const names = (raw ?? \"\").toLowerCase().split(\",\").map((s) => s.trim());\n return new Set(names.filter((n): n is Toolset => (TOOLSETS as readonly string[]).includes(n)));\n}\n\n/**\n * Whether a tool is LISTED under these toolsets. The base is the default listing (every tool but\n * the ABM lane), or only the head of the catalogue under `core`; `abm` adds the ABM lane to that\n * base and `all` lists everything. So `abm` alone is the default plus the lane, and `core,abm` is\n * the core plus the lane.\n */\nexport function listsTool(name: string, sets: ReadonlySet<Toolset>): boolean {\n if (sets.has(\"all\")) return true;\n if (ABM_TOOLS.has(name)) return sets.has(\"abm\");\n return !sets.has(\"core\") || !LISTING_TAIL.has(name);\n}\n\n/**\n * 🔴 WHAT AN AGENT CALLS FIRST MUST BE CALLABLE FIRST.\n *\n * A client with tool search (Claude Code) does not put 150 schemas in the prompt: it lists the\n * tools by NAME and loads a schema when the agent searches for it. A call to a tool whose schema\n * it has not loaded never reaches us: the client refuses it (\"Invalid tool parameters\" in Claude\n * Code). After an import that is the agent's second or third call every time, because every\n * instruction, receipt and tool result names the next tool to call (editor_setup, then the brief,\n * then the receipt) and the agent calls it by that name.\n *\n * `_meta[\"anthropic/alwaysLoad\"]` keeps a tool's schema in the prompt. These are the ones a setup\n * starts with and returns to. Few on purpose (about 9,000 characters of a 236,000-character\n * catalogue): each is read on every turn of every connection.\n */\nexport const ALWAYS_LOADED: ReadonlySet<string> = new Set([\n \"get_next_steps\", \"editor_setup\", \"get_deploy_status\", \"get_conversion_brief\", \"get_binding_report\",\n \"list_projects\", \"list_pages\", \"get_page\", \"list_content_models\",\n]);\n\n/** A tool's `_meta` in tools/list, or nothing for a tool a client may defer. */\nexport const toolMeta = (name: string): { \"anthropic/alwaysLoad\": true } | undefined =>\n ALWAYS_LOADED.has(name) ? { \"anthropic/alwaysLoad\": true } : undefined;\n\n/** The other half, for every tool that is deferred: said once, to every client, on connect. */\nexport const TOOL_LOADING_INSTRUCTION =\n \"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.\";\n\n","/**\n * Tool descriptions written ONCE for both MCP surfaces.\n *\n * The hosted catalog (src/routes/mcp/index.ts) and the stdio package (./tools.ts) each declare\n * their own schemas, but a description that says two different things on the two surfaces is a\n * prompt that works from one client and misleads from the other. Text here is imported by both,\n * so it cannot drift; mcp-text-parity pins the tools that use it byte-equal.\n *\n * Dependency-free on purpose: the hosted catalog imports it across the package boundary.\n */\n\nexport const ADD_FIELD_DESCRIPTION =\n \"Append ONE field to a content model (`modelId`) or to a page's schema (`pageId`) — 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; `ui`, `helpText`, `showIf`, `placement` and `fieldsetId` declare how it presents in the editor — 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 — 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): §14 of bettercms://playbook/schema.\";\n\n/** The V2 leaf types, one short line each; appended to add_field after ADD_FIELD_DESCRIPTION. */\nexport const V2_LEAF_TYPES_NOTE =\n \"`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).\";\n\nexport const MOVE_STAGE_DESCRIPTION =\n \"Move a content entry (`entryId`) or a page (`pageId`) to another editorial stage — 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' — approving and publishing are deliberately two separate calls.\";\n\n/** A block's (and a Layout Section's) visibility window, on both surfaces. */\nexport const WINDOW_NOTE =\n \"{from?, until?}, ISO 8601 with offset: shown only between the two instants; null clears (skill publishing).\";\n\n/** The events a webhook can subscribe to — pinned to the route's schema by mcp-tool-routes.test.ts. */\nexport const WEBHOOK_EVENTS = [\n \"content.publish\", \"content.unpublish\", \"content.stage_changed\", \"content.created\",\n \"content.updated\", \"content.deleted\", \"deployment.triggered\",\n] as const;\n\n/** The fourteen tools the Sanity-parity pass added, one description each for both surfaces. */\nexport const NEW_TOOL_TEXT = {\n 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.\",\n search_content:\n \"Full-text search over the project's PUBLISHED pages and entries (the site-search index). Returns id, type ('page'|'entry'), title, slug and a snippet per hit; `type` narrows to one kind. Drafts are not indexed: find those with list_content_entries `where`. `meta.unavailable` means site search is off for this project.\",\n discard_draft:\n \"Throw away unpublished edits to an entry (`entryId`) or a page (`pageId`) — exactly one: the draft returns to exactly what is live and `pendingChanges` becomes false. A page resets its blockJson and its published Layout overrides. 409 no_published_version means it was never published (delete it instead). Pass ifMatch (optimisticVersion) to refuse if it changed since you read it.\",\n give_feedback:\n \"Tell the BetterCMS team about a tool that failed, a capability you needed and did not have, or docs that misled you. Opens a ticket for the team; nothing in the project changes. Name the `tool`, and paste the request and response into `context`. Never include secrets or personal data.\",\n publish_entries:\n \"Publish or unpublish many entries and pages in ONE call (up to 100 ids of each; no page unpublish). Needs a publish-enabled connection, and each item still passes its own gates (editorial stage, required fields). Nothing stops the run: the result lists what changed (`published` or `unpublished`) and every refusal in `failed` with its reason. A publish answers 202 with the routes being rebuilt. `hold` keeps a live item's edits out of whole-site publishes, `release` includes them again; publishing a held item here ends its hold.\",\n create_content_entries:\n \"Create up to 200 DRAFT entries of one collection in ONE call, each {slug?, data} as create_content_entry takes it. Every row reports `created` (with id and slug) or `failed` (with the error), a failure does not stop the others, and `meta` counts them. A row with `externalKey` is safe to send again: its entry is `updated` (draft only), or `unchanged` when the row is the same. A row setting a developer-locked field fails (FIELD_LOCKED). Publish afterwards with publish_entries.\",\n translate_entry:\n \"Create an entry's `targetLocale` translation with AI (uses AI credits: 402/403 when out or not on the plan). Text and longtext fields are translated; rich text and documents are copied for you to translate; the rest is copied. The new entry is a DRAFT with `locale` set and `translationOf` = the source; `meta` lists translated and copied keys. `targetLocale` must be one of the project's locales; 409 locale_conflict means that translation exists, so edit it instead.\",\n list_webhooks:\n \"List the project's outgoing webhooks: name, url, events, whether active, and delivery health (total, failed, last attempt). Signing secrets are never returned.\",\n create_webhook:\n \"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.\",\n list_branches:\n \"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.\",\n create_branch:\n \"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.\",\n apply_branch:\n \"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.\",\n search_docs:\n \"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.\",\n generate_image:\n \"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`.\",\n refresh_search_index:\n \"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.\",\n import_redirects:\n \"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.\",\n editor_setup:\n \"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` when it already ran for the live sha, else it starts (`running`; poll with `check: true`). `state`: never or stale (run it), running, ready, failed. 409 = nothing is live yet: deploy first. Then get_next_steps.\",\n transform_image:\n \"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).\",\n write_alt_text:\n \"Alt text for a Media Library image (mediaId) or an https image URL (url), written from its pixels (1 AI credit). A suggestion: save it with update_media.\",\n} as const;\n\n/**\n * delete_page's second job, on both surfaces: the server-app bundle cleanup. A parameter on an\n * existing delete rather than a tool of its own, because a tool's fixed cost alone would break the\n * tools/list ceiling (mcp-payload-weight.test.ts).\n */\nexport const DELETE_PAGE_RUNTIME_BUNDLE =\n \" 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.\";\n\n/** Parameter descriptions the extended arguments share across both surfaces. */\n/** update_content_entry: what a developer lock does to a value write. One sentence, both catalogs. */\nexport const FIELD_LOCKED_NOTE =\n \"A readOnly 'developer' field keeps its stored value: changing or omitting it without schema access is 403 FIELD_LOCKED.\";\n\nexport const PARAM_TEXT = {\n dryRun: \"validates and reports what would be written; writes nothing\",\n externalKey: \"id in the source system; sent again, it updates that entry's draft or leaves it unchanged\",\n upsertSource: \"source URL, kept with the entry\",\n upsertRunId: \"your run's id, kept with the entry\",\n externalKeyFilter: \"exact externalKey an entry was created with\",\n readOnly: \"'developer' = the value and this lock change only with schema access (needs lockReason); true = an editor marker\",\n lockReason: \"which system owns the value (≤ 200 chars)\",\n lockClears: \"as on add_field; null clears it\",\n helpText: \"shown under the field. Most fields get none: write it only for a format or unit, a place the canvas cannot show, a real constraint or a fallback, as one plain sentence under 90 characters with no semicolons, no dashes and no values from the page, never its label or value. Omitted: the platform writes it where one of those reasons holds.\",\n helpMore: \"longer help behind the ⓘ next to the label, when one helpText line cannot carry it\",\n advanced: \"true = a rare or developer setting: it collects in a closed 'Advanced' section\",\n recommendedMax: \"a SOFT limit (characters, items or value): the editor warns past it, never refuses\",\n openMode: \"object/array/group/repeater: how the value (or each row) opens: 'inline', 'drill', 'popover' or 'dialog'\",\n fromBuiltin: \"a builtin:* id from list_components: copies it into the project; fields you send win\",\n componentPreview: \"a slot row's look: {title?, subtitle?, media?} TOP-LEVEL prop keys, fallback?, icon?; null clears. §3 of bettercms://playbook/schema\",\n componentIcon: \"the block icon, a dock icon name; null clears. §3 of bettercms://playbook/schema\",\n componentTabs: \"/kit tabs no top-level prop sits in: [{id,label,icon?,order?}]. §3 of bettercms://playbook/schema\",\n 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\",\n describes: \"for editors: what it is and holds; omitted: written for you\",\n runtimeBundle: \"instead of pageId: the server-app bundle cleanup\",\n pageRef: \"page id or path ('/de/about'); a bare slug only when one page has it\",\n editorSetupForce: \"re-run a setup already ready for the live build\",\n editorSetupCheck: \"true = only report the state; starts nothing\",\n editorSetupExempt: \"instead of running: record setup-gate exceptions [{ route, check, reason, note }]; reason null removes one. Reasons: get_next_steps `receipt.gate`\",\n editorSetupDeclare: \"instead of running: record binding decisions [{op, id, ...}], max 100, a result each; with `check: true` a dry run. Ops: skill bindings\",\n pageBlockJson:\n \"an ARRAY REPLACES the page's block composition (a `component` block per section). An OBJECT edits ONE section of the stored page instead: `insertSection` adds a component (its id, or a builtin:* id: copied into the project once) at index `at`, or `before` / `after` a section's block id (none = last), with its `style` and `overrides`; `sectionStyle` sets a section's block style (a key replaces the stored one, null unsets it). `section` in the answer names the block (skill publishing)\",\n pageDynamic: \"a dynamic (collection template) page only\",\n previewPath: \"its route pattern, e.g. /blog/{slug}; null clears\",\n pageModelId: \"an existing collection this page lists (when it has no model yet)\",\n formIgnored: \"true = not one of the site's forms (a search box, a widget); false restores it\",\n componentizeCodemod: \"true = componentize nothing; run the section-order codemod in the connected repo on its own Actions, which commits for the next build. After the components and pages are published. `skipped` = no repo to commit to: run `convert --sections` in a checkout (skill componentize)\",\n where:\n \"field filters: {field: value} is equality, {field: {op: value}} with op eq|ne|gt|gte|lt|lte|contains|in, and an array means `in`. System fields slug, status, publishedAt, locale work anywhere; a data field needs modelId. Compares the served copy (live for published, working for draft)\",\n sort: \"comma list, a leading - sorts descending, e.g. '-publishedAt,title'\",\n page: \"1-based page of `limit` rows; the response's meta says totalPages\",\n locale: \"language, a BCP-47 tag (zh-CN → zh-cn), one of the project's locales; null = the default\",\n translationOf:\n \"the SOURCE id this translates (never a translation); null unlinks. One per locale: the translation sets locale and translationOf\",\n pageScheduledAt:\n \"ISO datetime to publish this page's draft at (needs publish permission); null cancels. An edit that omits scheduledAt CANCELS a pending schedule\",\n pageUnpublishAt: \"ISO datetime at which the published page returns to draft; null cancels; omitting it never cancels it\",\n sourceUrl:\n \"instead of data: a public http(s) URL the server fetches and stores (private or internal addresses are refused)\",\n focalX: \"focal point, 0-1 across from the left edge; null resets to the centre\",\n focalY: \"focal point, 0-1 down from the top edge; null resets to the centre\",\n mergeHref:\n \"pageId only: the link field paired with `path` (the label). Both become ONE `button` field keyed `key` (default: their stem, primaryCtaHref → 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\",\n confirmedInput:\n \"true only after the user explicitly approved adding this custom input (`ui.input`); else setting or changing one is refused input_needs_confirmation. Removing one needs no approval\",\n} as const;\n\n/**\n * The header `confirmed: true` travels as, on both surfaces. The server's custom-input gate reads\n * it on every Management write of fields or props. @see src/lib/content/field-ui-write.ts\n */\nexport const INPUT_CONFIRMED_HEADER = \"x-bcms-confirmed-input\";\n\n/**\n * What a `button` field is, said where a field TYPE is chosen. Without it an agent meets the type\n * only through the `cta_pair` refusal. @see packages/types/src/button-look.ts ButtonValue\n */\nexport const BUTTON_FIELD_NOTE =\n \"'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.\";\n\n/**\n * What a `link` value may be, said beside the field types. @see packages/types/src/link-value.ts\n */\nexport const LINK_VALUE_NOTE =\n \"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}.\";\n\nexport const UPDATE_FIELD_DESCRIPTION =\n \"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 — 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`.\";\n\nexport const GET_SEO_DESCRIPTION =\n \"Get the connected project's site-wide SEO settings — 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.\";\n\nexport const UPDATE_SEO_DESCRIPTION =\n \"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.\";\n\n/** One line per update_seo key, shared by both surfaces' schemas. */\nexport const SEO_KEY_TEXT = {\n seoDefaults: \"site-wide meta defaults every page inherits\",\n siteSchema: \"the site's JSON-LD: an object or an array of objects\",\n robotsConfig: \"robots.txt: 'auto' (`disallow` names AI crawlers to block), or 'custom' with its text\",\n sitemapConfig: \"sitemap.xml: generated ('auto') or 'custom', defaults and extra URLs\",\n rssConfig: \"the RSS feed on or off\",\n indexnowConfig: \"IndexNow on publish, minus URL patterns to leave out\",\n searchConfig: \"site search: on/off, the box's placeholder, AI answers\",\n} as const;\n\n/** Round-2 clauses shared by both surfaces. */\nexport const VARIANT_GROUP_NOTE =\n \"`variantGroup`: the family of looks it belongs to, if any, and its looks.\";\n/** get_component `detachedCopy`, on both surfaces. */\nexport const DETACHED_COPY_NOTE =\n \"{overrides?}: a rich-text embed's separate-copy `fields` (playbook §5)\";\n/** update_component `kitEntry`, on both surfaces. */\nexport const KIT_ENTRY_REBUILD_NOTE =\n \"Setting or changing `kitEntry` puts that entry's ui over every prop's server-derived ui: the entry wins where it specifies a tab, group, control or preview key, and derived ui it says nothing about stays (ui a person or an agent set is kept); `kitUiApplied` lists the props it changed.\";\nexport const UNPROPPED_COPY_NOTE =\n \"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.\";\nexport const UPDATE_PAGE_IF_MATCH_NOTE =\n \"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.\";\n/** The list form of a `slot` prop, on create_component `props` of both surfaces. */\nexport const SLOT_MULTIPLE_NOTE =\n \"'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 §5.\";\n/** Sections are props: the V2 field language on create_component of both surfaces. */\nexport const PROP_V2_NOTE =\n \"Props take the fields' V2 keys (§14): 'object' = ONE {child: value} from config.fields, ≤10 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).\";\n/** The Global Layout field lock, on update_layout of both surfaces. */\nexport const LAYOUT_LOCK_NOTE =\n \"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`.\";\n","/**\n * list_content_entries' query string, built once for both MCP surfaces.\n *\n * The management list route takes the Delivery API's filter grammar (`filter[field]=v`,\n * `filter[field][op]=v`, `in` as a comma list — src/lib/delivery/list-query.ts parseFilters)\n * plus `sort`, `page` and `limit`. An agent writes `where` as an object, which is what it gets\n * right; this turns it into that grammar.\n *\n * Dependency-free on purpose: the hosted catalog imports it across the package boundary.\n */\n\n/** The operators the route understands; `eq` is what a bare value means. */\nexport const WHERE_OPS = [\"eq\", \"ne\", \"gt\", \"gte\", \"lt\", \"lte\", \"contains\", \"in\"] as const;\n\nconst text = (v: unknown): string => (Array.isArray(v) ? v.map(String).join(\",\") : String(v));\n\n/**\n * `{ title: \"Hi\", price: { gte: 10 }, tags: [\"a\", \"b\"] }` →\n * `[[\"filter[title]\", \"Hi\"], [\"filter[price][gte]\", \"10\"], [\"filter[tags][in]\", \"a,b\"]]`.\n * An undefined or null condition is skipped.\n */\nexport function whereToQuery(where: Record<string, unknown> | undefined): Array<[string, string]> {\n const out: Array<[string, string]> = [];\n for (const [field, cond] of Object.entries(where ?? {})) {\n if (cond === undefined || cond === null) continue;\n if (Array.isArray(cond)) out.push([`filter[${field}][in]`, text(cond)]);\n else if (typeof cond === \"object\") {\n for (const [op, v] of Object.entries(cond as Record<string, unknown>)) {\n if (v !== undefined && v !== null) out.push([`filter[${field}][${op}]`, text(v)]);\n }\n } else out.push([`filter[${field}]`, text(cond)]);\n }\n return out;\n}\n\nexport interface EntryListArgs {\n modelId?: unknown;\n pageId?: unknown;\n status?: unknown;\n externalKey?: unknown;\n where?: unknown;\n sort?: unknown;\n page?: unknown;\n limit?: unknown;\n /** true = full rows (field data, published copy); otherwise a summary without them. */\n detail?: unknown;\n}\n\n/** The whole `?…` for GET /management/content/entries: a summary list unless `detail` is true. */\nexport function entryListSearch(args: EntryListArgs): string {\n const q = new URLSearchParams();\n for (const key of [\"modelId\", \"pageId\", \"status\", \"externalKey\"] as const) if (args[key]) q.set(key, String(args[key]));\n for (const [k, v] of whereToQuery(args.where as Record<string, unknown> | undefined)) q.append(k, v);\n for (const key of [\"sort\", \"page\", \"limit\"] as const) if (args[key] !== undefined && args[key] !== null) q.set(key, String(args[key]));\n if (args.detail !== true) q.set(\"select\", \"summary\");\n const s = q.toString();\n return s ? `?${s}` : \"\";\n}\n","import { z } from \"zod\";\nimport { SCHEMA_PLAYBOOK } from \"./playbook.js\";\nimport { SECTION_DOCTRINE } from \"@bettercms-ai/types\";\n\n/**\n * The one rule that decides whether a generated page is editable at all, injected into every\n * prompt that can end in a block tree.\n *\n * Only `studio` and `propose_schema` carried the playbook, and the playbook is where the\n * section rules lived — so `new_page`, `build_site` and `generate_landing_pages` could each\n * author a page with no idea that a page is a list of sections. A page authored as loose\n * top-level blocks gets one editor section per block: a hero of headline + lede + two CTAs\n * arrives as four sections, and the two CTAs stack instead of sitting side by side.\n */\nconst STRUCTURE_RULE = `### Page structure (non-negotiable)\n${SECTION_DOCTRINE}`;\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\n/**\n * Guided slash-command prompts that ship WITH the MCP. Claude Code (and other\n * hosts) surface server prompts automatically as `/mcp__bettercms__<name>`, so\n * adding the MCP is all it takes — no per-machine skill files.\n *\n * Design: one **generous parent** (`studio`) that reads the user's intent and\n * routes to the right sub-flow, plus thin direct entry points (`new_page`, ...)\n * for the individual flows. New BetterCMS tools get a new sub-flow section here.\n */\n\n/**\n * THE CONVERSION LOOP, in the fewest lines it fits in.\n *\n * 🔴 IT ENDS WHEN NOTHING IS PENDING, not when the codemod has run once. Measured on a real kit:\n * one pass declared 282 of 767 paths and every agent that read that receipt reported the site\n * converted. The loop below is the fix — apply each pending path's `fix`, rerun, resubmit — and\n * `submit_conversion_receipt` answers `complete` so there is one unambiguous finish line.\n *\n * SHARED WITH THE HOSTED SURFACE (src/routes/mcp/index.ts), which serves the same prompt over the\n * remote transport. Two copies of a loop drift, and the drifted one is the one the agent runs.\n */\n/**\n * The editor-chrome step every import, convert and componentize flow ends on. Without it an agent\n * finishes with every component prop bare and the dock shows none of the V2 vocabulary; the setup\n * gate's `dock` row holds `complete` until it is done. ONE copy, shared by the three prompts.\n */\nexport const DOCK_UI_STEP =\n \"EDITOR CHROME: for every component, run the field-ui lane (the `field-ui` prompt, playbook §14): `get_component`, then one `update_component` with `propUi`, `propTab` and `propHelpText` giving each prop its V2 ui (control, tab, group, collapsed, layout, preview, itemLabel, icon) after the closest `bettercms://kit` entry. The gate's `dock` row stays open until each has it, or a true `default-controls` exception.\";\n\nexport const CONVERT_SITE_TEXT = (projectId?: string): string =>\n `Convert my site so every visible element is editable in BetterCMS${projectId ? `, project ${projectId}` : \"\"}.\nDo not stop at the plan or at a partial receipt — finish the whole site, never editing a class or style.\n\n1. \\`list_projects\\`; pass \\`projectId\\`${projectId ? ` (${projectId})` : \"\"} on every project tool. Not listed = the grant is on\n another workspace: have the user re-authenticate there. Never convert a different project.\n2. \\`editor_setup\\` until it is \\`ready\\` (poll with \\`check: true\\`), then \\`get_conversion_plan\\`; on a 404 \\`no-approved-plan\\`,\n \\`get_conversion_brief { complete: true }\\` and follow \\`cursor\\` to the LAST page, keeping every\n page — a codemod fed the capped brief converts a truncated site. Write them to \\`brief.json\\`.\n3. \\`pull_project_source\\` (or clone the \\`github\\` remote it names) and work from the SOURCE, never\n from the deployed HTML.\n4. \\`npx @bettercms-ai/convert --brief brief.json --root . --receipt receipt.json\\`; read \\`git diff\\`.\n5. For EVERY entry of \\`paths.pending\\`, go to its \\`fix.file\\`:\\`fix.line\\` and do what \\`fix.action\\`\n says: \\`wrap-span\\` wrap the literal in \\`<span data-bcms-field=\"…\">\\`; \\`declare-attr\\` add\n \\`data-bcms-field=\"…\"\\` to that element; \\`bind-expression\\` replace the expression with the\n framework's bcmsField helper; \\`declare-richtext\\` bind the container with the richtext helper;\n \\`bind-data\\` bind the field in the data file it names; \\`manual\\` do what its \\`why\\` says. A row\n with no \\`fix\\` is still yours. Then rerun step 4 until \\`paths.pending\\` is EMPTY.\n6. \\`npx @bettercms-ai/convert --verify-styles --base <commit before step 4>\\`, restore what it lists, then\n \\`submit_conversion_receipt { briefDigest, receipt }\\` with its \\`styleEdits\\`: only \\`complete: true\\` ends it (else step 5).\n7. Deploy the working tree (\\`create_deploy_upload\\`, then \\`deploy_project\\` with its \\`uploadKey\\`); poll \\`get_deploy_status\\` until live. No git yet.\n8. \\`get_binding_report\\`: \\`unmatched\\` 0, \\`unaddressable\\` under 2% per route; fix the SOURCE, deploy, re-read (playbook §11).\n9. \\`set_binding_mode { declaredBindings: true }\\`, deploy AGAIN and poll, then confirm \\`get_binding_report\\`\n reads mode \"declared\", unmatched 0, bound above 0, \\`coverage.pending\\` empty. Send me that report.\n10. \\`get_next_steps\\`: if it lists \\`upgrade-section-roots\\` (section spacing and style handles), in the repo run\n \\`npx @bettercms-ai/convert@latest --upgrade-sections --root . --dry-run\\`, read the plan, then run it for real. For every\n root its receipt lists as \\`skipped\\`, pass the block down by hand: \\`{...sectionRootAttrs(block)}\\` on the section root, or\n \\`data-bcms-style=\"\"\\` plus \\`style={...}\\` from \\`block.style\\`. For \\`upgrade-element-styles\\` (field width, spacing, text handles)\n do the same with \\`npx @bettercms-ai/convert@latest --upgrade-element-styles --root . --dry-run\\`. Run \\`--verify-styles\\` again\n and restore what it lists (the marker, and the inline style from \\`block.style\\` or \\`fieldAttrs\\`, are allowed; changing a class\n or an existing style is not). Deploy, poll, call \\`get_next_steps\\` again and run \\`receipt.gate.nextAction\\` until \\`receipt.complete\\` is true; what else it lists, tell me by name. Not listed: say so; invent no work. Its \\`receipt.gate\\` fails a route on \\`sections\\` or \\`style\\` while I could not add a section to that page, reorder it or space it: run each such row's \\`fix\\` too. A write that answers \\`held\\`, or a publish whose \\`outcome\\` is \\`partial\\`, is not done until its action is taken.\n11. ${DOCK_UI_STEP}\n12. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the next rebuild from my repo drops it). Touch git only as I answer.`;\n\n/**\n * The editor-chrome lane: §14 is the doctrine, this is the order of work and the receipt. Shared with\n * the hosted surface (src/routes/mcp/index.ts), like CONVERT_SITE_TEXT.\n */\nexport const FIELD_UI_PROMPT = {\n title: \"Declare how fields LOOK in the editor (guided)\",\n description:\n \"Set the editor chrome of an existing schema and its component props: groups, tabs, rows, icons, item names, what titles and thumbnails a list's rows, help text, conditional visibility. Derives it from your source, then from the field shapes, and asks only what it cannot know.\",\n request: \"scope, e.g. 'the Team and Testimonials models' or 'the whole project'\",\n};\nexport const FIELD_UI_TEXT = (request?: string): string =>\n `Declare the editor UI for my BetterCMS fields and component props.${request ? ` Scope: \"${request}\".` : \"\"}\n\nRead bettercms://playbook/schema section 14 first: the vocabulary, patterns, budgets, recipes, the\ntabs rule, every refusal, and the three tiers that decide each value (my source, then the field\nshape, then ask me, once and batched). Icon names are in bettercms://icons/dock.\n\n**Order of work**\n1. \\`get_next_steps\\`: its dock-budget, dock-repeater-unnamed and dock-showif-order steps name the\n screens to fix. Read each target with \\`get_content_model\\`, \\`get_page\\` (its \\`backingModel\\`) or\n \\`get_component\\`; note its \\`optimisticVersion\\` and the chrome a person already set.\n2. Decide each field's chrome by the §14 tiers and write down which tier answered.\n3. Apply one write per model or component, always with \\`ifMatch\\` (428 without it; 409\n version-conflict when stale: read again and re-apply, never retry blindly):\n - fields that exist: \\`update_content_model\\` fieldUi / fieldFieldset / fieldOrder / fieldLabel /\n fieldHelpText by field path, plus \\`fieldsets\\`. A singleton page: send \\`pageId\\` instead of\n modelId, with its backingModel's version;\n - component props: \\`update_component\\` propUi / propGroup / propTab / propLabel / propHelpText;\n - a NEW field: ui / helpText / showIf in the same \\`add_field\\` call, with \\`after\\`.\n A 409 \\`ui_human_owned\\` names chrome a person set: leave it, or ask me and send \\`override: true\\`\n only on my word.\n4. **RECEIPT, non-negotiable.** Re-read every target and confirm the stored chrome matches what you\n sent: a key ABSENT from the read was not stored, whatever the write said. Call \\`get_next_steps\\`\n until no dock-* step is left. Report per field the tier that decided it, what you set, and that\n the read-back confirmed it; say plainly what you could not confirm.`;\n\n// ── Reusable sub-flows ──────────────────────────────────────────────────────\n\nconst SCHEMA_PROPOSAL_FLOW = `### Whole-project design (confirm-first) → \\`create_component\\` / \\`create_page\\` / \\`create_content_model\\`\nDesign the WHOLE project from its brief or its code, and **confirm the shape with the user\nBEFORE creating anything**. Never silently guess.\n\n1. **Read the source** — the connected repo, or the uploaded project in your working\n directory. For each page, identify the repeated visual regions and the list-shaped data.\n2. **Classify every part** using the decision tree in the playbook below. The two mistakes\n that matter: flattening a marketing page into loose page fields when its sections should\n be COMPONENTS, and giving a blog a \\`richtext\\` field when its body should be \\`document\\`.\n3. **Present the proposal (REQUIRED gate).** Show the component library (with each section's\n family and variants), the collections and their fields, and the pages that place them.\n Ask the user (AskUserQuestion) to confirm or adjust. Do not create anything before this.\n4. **Build it in the playbook's order** — blocks, collections, components, PUBLISH the\n components, pages, content, publish. Skipping the publish step ships a blank site.\n\n${SCHEMA_PLAYBOOK}\n`;\n\nconst PAGE_FLOW = `### Page authoring → \\`create_page\\` tool\nAuthor a page (the page-first schema). Ask, in order, via AskUserQuestion:\n1. **Page type** — singleton (exactly one entry: Home, About, Contact) vs dynamic\n (many entries sharing the schema: Blog posts, Products).\n2. **Identity** — title; derive a slug (lowercase, a–z 0–9 -) and confirm; optional\n metaTitle/metaDescription.\n3. **Fields (loop until done)** — for each: key (^[a-zA-Z0-9_]+$), label, type,\n required?. Types (14): text, richtext, image, boolean, number, select (needs\n \\`options: string[]\\`), reference / multi-reference (\\`config.contentModelId\\`,\n multi adds min/max), array (primitives — \\`config.itemType\\`: text|number|date),\n date (\\`config.includeTime\\`?), datetime, **button** (ONE call to action, value\n {label, href, variant?, size?, arrow?, icon?, newTab?} — never a text field plus a\n link field), **group** (Non-Repeatable Zone: ONE\n nested object — recurse to collect its \\`fields\\`, e.g. blog_hero → heading,\n description, hero_image), **repeater** (Repeatable Zone: an ARRAY of such objects\n — recurse to collect item \\`fields\\`, e.g. testimonials → quote, author). Nesting\n may go several levels deep.\n4. **Review** the assembled tree, then call \\`create_page\\` with\n { title, slug, pageType, fields, metaTitle?, metaDescription? }. Field object:\n { key, label, type, required?, options?, config?, fields? }.`;\n\nconst FIELD_FLOW = `### Add a field → \\`add_field\\` (a model or a page)\nAppend a field to an existing schema. First decide the target: a **content model**\nor a **page** (Home, About, a blog template). Ask: which target (id — use\n\\`list_pages\\` to find a page id), then the field (key, label, type — any of the 14\nabove, including nested group/repeater), required?. Confirm, then call:\n- a model → \\`add_field\\` { modelId, key, label, type, ... }\n- a page → \\`add_field\\` { pageId, key, label, type, ... }\nIt is additive: it rejects a key that already exists and never retypes/overwrites\nan existing field — change one of those with \\`update_field\\` { path, … }.`;\n\nconst ENTRY_FLOW = `### Create an entry → \\`create_content_entry\\` tool\nCreate a content entry under a model. Ask: which model (id), the field values (data),\nstatus (draft/published). Then call \\`create_content_entry\\` { contentModelId, data?, status?, slug? }.`;\n\nconst FORM_FLOW = `### Form authoring → \\`create_form\\` / \\`update_form\\` tools\nAuthor a form (then the user embeds it with \\`<BcmsForm form={getForm('Name')} />\\` from\n@bettercms-ai/next). Confirm the fields with the user BEFORE creating. Never guess fields.\n1. **Discover** — \\`list_forms\\` to see existing forms; \\`get_form\\` to read one before editing.\n2. **Collect fields (loop)** — for each: key (machine key for the value), label, type. Types:\n text, email, textarea, select (needs \\`options: string[]\\`), checkbox, checkboxes (needs\n \\`options\\`), radio (needs \\`options\\`), number, phone, date, url, consent, hidden, step (divider). Optional per\n field: required?, placeholder?, helpText? (shown under the input), defaultValue?,\n \\`validation\\` (\\`emailPolicy\\` on email, \\`min\\`/\\`max\\` on number, \\`phoneFormat\\` on phone,\n \\`pattern\\` on text/textarea/url — a rule on any other type is a 400),\n \\`ui\\` (\\`countryPicker\\` + \\`defaultCountry\\` on phone — renders a country picker and stores\n E.164; \\`defaultCountry\\` without \\`countryPicker\\` is a 400), and\n \\`showIf: { field, equals }\\` for conditional display.\n3. **Settings** — name (used by getForm('Name')), submitLabel?, successMessage?, redirectUrl?.\n4. **Confirm**, then \\`create_form\\` { name, fields, ... } (returns the new id), or\n \\`update_form\\` { formId, ... } to edit (passing \\`fields\\` REPLACES the array — include all).\n5. The form lands as a DRAFT, and a draft refuses every submission (403): call\n \\`publish_form\\` { formId } (on 403 PUBLISH_NOT_GRANTED, tell the user to publish it in the\n dashboard Forms tab), then offer to wire \\`<BcmsForm>\\` into the page/component where the\n user wants it.`;\n\nconst COMPONENT_FLOW = `### Component authoring → \\`create_component\\` / \\`publish_component\\`\nAuthor a reusable section. blockJson is the visual definition; authoring it blind is\nerror-prone, so go slow and confirm. Never guess the layout.\n1. **Discover** — \\`list_components\\` / \\`get_component\\` (read before update; keep existing blocks).\n2. **Design the tree** — wrap the section in a \\`section\\` block carrying \\`style\\`\n (bg + paddingTop/paddingBottom + contentWidth) and nest content in props.children. See\n \"Anatomy of a real section component\" in the playbook. Give every block a stable id.\n3. **sectionType + category** — set both, or the component never appears in the editor's\n \"Add a section\" picker. Components sharing a sectionType are swappable VARIANTS, so reuse\n the same prop keys across a family or a swap drops content.\n4. **Props** — declare only what should really be editable:\n { key, label, target: { blockId, path },\n type: text|richtext|image|url|boolean|number|select|group|table|slot|form|link|button|date|color|file|icon|multiselect|object|datetime|slug|email|phone|json|location|tags|rating|code|reference|multi-reference|video|array|longtext }.\n 'select'/'multiselect' need config.options; 'group'/'table'/'object' need config.fields; a 'button'\n is ONE prop on a button block's 'props', never a label prop plus a url prop; 'slot' holds ONE nested component (a list with config.multiple);\n 'form' holds ONE Form document — point target.path at 'props' on an empty form block and set\n defaultValue to {formId}. Never re-declare a form's FIELDS as props: the Form document owns\n them, and a second copy is a second source of truth that drifts on the first edit.\n5. **Confirm the structure** (AskUserQuestion: show the block tree), then \\`create_component\\`.\n6. **\\`publish_component\\`.** It lands as a DRAFT, and a draft component renders as NOTHING on\n the live site — no error, no placeholder. This step is not optional.\n`;\n\n/**\n * The WHOLE-SITE componentization ask, mapped onto the platform. Its six headings are the six\n * the request itself arrives with; each line is the platform's answer, and the parts with no\n * answer say so rather than inviting the agent to invent one. The deep version is playbook §12.\n */\nconst COMPONENTIZE_SITE_FLOW = `### Componentize the entire website → playbook §12 + the batch tools\nRead \\`bettercms://playbook/schema\\` §12 first — this is the short form of it.\n1. **Global elements.** Navbar / mobile nav / header / footer are the LAYOUT (\\`get_layout\\`,\n \\`update_layout\\`; a chrome component is placed with the \\`add-component\\` command). CTA buttons\n are \\`button\\` BLOCKS inside the section that uses them, exposed as \\`text\\` + \\`url\\` props —\n variant/size/icon are that block's own props and \\`style\\`; each look joins the project's Button\n family by itself, so never hand-build a Button component. Rich text\n is a \\`richtext\\` prop. Forms are \\`create_form\\` + a \\`form\\` block, and form FIELDS are the only\n place with real \\`required\\` / \\`placeholder\\` / \\`helpText\\` / \\`validation\\`. Cards, badges, tags,\n links, lists and media are blocks inside a section, repeatables as one \\`table\\` prop.\n Accordions/FAQ: \\`builtin:faq-list\\` or a \\`tabs\\` block. NOT MODELLED: cookie banners, modals,\n breadcrumbs, pagination — leave them in the site's code and say so at the end.\n2. **One component per distinct section**, one-offs included. \\`sectionType\\` is the family;\n components sharing one are VARIANTS and must share prop KEYS. A one-off gets its own family\n plus \\`allowedOn: [\"slug:<page>\"]\\`. Start from the \\`builtin:*\\` blueprints in\n \\`list_components\\`. On a DERIVED site (\\`editor_setup\\` derives it) run \\`get_componentize_plan\\` →\n \\`componentize_sections\\` first (dryRun first, and confirm the plan with the user).\n3. **Hierarchy** = \\`group\\` on create_component/update_component (a NAME; created when missing).\n Use Global, Navigation, Actions, Content, Forms, Media, Sections, Page-specific. \\`category\\`\n is the separate picker TAB.\n4. **Fields** = \\`props\\`: text, richtext, image, url, boolean, number, select, group, table, slot.\n Always a \\`defaultValue\\`; \\`helpText\\` / \\`placeholder\\` are editor hints. A placement you SET empty on a\n \\`required\\` prop is refused (\\`required_value\\`). \\`select\\` for styling-only variants, a separate component when the markup\n differs. Nesting goes up to 10 levels; a \\`table\\` row may hold a data table or a polymorphic list.\n5. **Quality.** The componentize lane and \\`npx @bettercms-ai/convert --componentize\\` move markup\n VERBATIM — classes, responsive utilities, aria attributes, alt text all survive. Never\n restyle. Dry-run first.\n6. **Validation** = \\`get_site_composition\\`: every page's placements, each component's status,\n and \\`verdict.everyPageComposed\\` with its reasons. Publishing needs the OWNER's approval in\n the dashboard (evidence via \\`request_component_validation\\` and a run in the repository), then\n \\`publish_components\\`. No tool here can grant that approval, and there is no bulk approve.\n\n**Order:** get_site_composition → (get_componentize_plan → componentize_sections) →\ncreate_component per uncovered section → compose_pages → update_layout { commands } → evidence + owner approval →\npublish_components → publish the pages / publish_layout → get_site_composition → get_next_steps.\nPrefer the batch tools whenever there is more than three of anything.`;\n\nconst LAYOUT_FLOW = `### Project/page Layout authoring → \\`get_layout\\` / \\`update_layout\\` / \\`publish_layout\\`\nEdit the project's draft Global Layout or one page's draft override. \\`update_layout\\` never\nchanges the live site; \\`publish_layout\\` takes the Global Layout draft live (page overrides go\nlive with their page). Until it is called, site chrome you authored is NOT on the live site.\n1. **Read first** — call \\`get_layout\\` with scope \\`global\\`, or scope \\`page\\` + pageId.\n Keep the returned \\`revision\\`; every write must pass it as \\`ifMatch\\`.\n2. **Choose one discriminated command type** — the server derives its authority family;\n callers cannot claim a weaker family for a schema or composition mutation.\n3. **Apply one canonical command** with \\`update_layout\\`, then use the returned revision for\n the next command. A 409 means somebody else edited it: re-read; never blindly retry.\n4. Direct fields are headless data. Only Component items render markup. Navigation/Footer\n are reserved Sections and cannot be deleted or moved; page overrides may inherit,\n override content, customize structure, or disable them.\n5. Read Component/Variant identities before attaching or swapping. Required values and\n bindings must be complete before a human publishes from the dashboard.`;\n\nconst BUILD_SITE_FLOW = `### Build a whole site (schema → pages → AI copy) → composes the flows below\nEnd-to-end authoring from a repo or a brief. Confirm-first at every stage.\n1. **Schema** — run the whole-project schema design above: propose the page/zone/field tree,\n get the user's approval, then \\`create_page\\` per page.\n2. **Copy** — for each page/entry, draft the real text with \\`write_content\\` (action 'write',\n pass the section as the brief + the page title as \\`context\\`). Review with the user, then\n apply via \\`set_page_content\\` / \\`create_content_entry\\` / \\`update_content_entry\\`.\n3. **SEO** — run the SEO flow to fill metaTitle/metaDescription for each page.\nNever invent brand facts — ask the user for anything the repo/brief doesn't state.`;\n\nconst LANDING_PAGES_FLOW = `### Generate landing pages (programmatic SEO / ABM) → \\`generate_pages_from_dataset\\`\nSpin up many pages sharing one template, each personalized per row (company, keyword, persona).\n\nFor an ABM campaign — a page per NAMED COMPANY — the whole flow is eight steps, in this order:\n1. **Research** — \\`research_account\\` per account, or set \\`mapping.campaign.research\\` and let the\n run do it ('lite' reads the company's own site, 'deep' searches the web, 'agent' hands the work\n to YOU through \\`claim_abm_task\\` / \\`complete_abm_task\\`).\n2. **Generate** — \\`generate_pages_from_dataset\\` with \\`mapping.campaign = { id, research,\n externalKeyColumn: 'domain' }\\`. It fans out across every page the campaign owns and parks for\n approval. Re-running the same export UPDATES each account's page rather than duplicating it.\n3. **Approve the job** — \\`approve_ai_job\\`, only once the user has said yes.\n4. **Review** — \\`get_campaign_review\\` with \\`sample: 5\\`, then \\`filter: 'flagged'\\`. A flag reads\n \\`unsupported_claim:headline\\`: a figure that is in none of the account's own facts, so the field\n fell back to the blueprint's copy. \\`filter: 'failed'\\` lists rows that produced no page at all.\n5. **Regenerate** — \\`regenerate_entry\\` with an instruction, one row at a time.\n6. **Approve entries** — \\`approve_campaign_entries\\`; \\`'all_unflagged'\\` clears the rest in one call.\n A FLAGGED page must be named explicitly: approving one says a person checked the claim.\n7. **Publish** — \\`publish_campaign\\` with \\`confirm: true\\`. It refuses \\`entry_flagged\\` while any\n page carries an unresolved flag, and \\`blueprint_missing_disclaimer\\` if a page has lost its\n \"not affiliated with\" band. The user decides this step, never you.\n8. **Share** — \\`get_campaign_share_link\\` for a link a rep can send before publishing.\n\nFor a plain programmatic-SEO run (a page per keyword, no named companies) the same tool works\nwith no \\`campaign\\`, and \\`write_content\\` + \\`create_content_entry\\` per row is still fine for a\nhandful. ALWAYS dry-run first and show the sample.`;\n\nconst SEO_FLOW = `### Optimize SEO → \\`generate_seo_meta\\` + the page/entry update tools\nFill or refresh SEO metadata across the site.\n1. **Target** — pick the pages/entries (\\`list_pages\\` / \\`list_content_entries\\`); confirm scope with the user.\n2. **Per target** — read its content (\\`get_page\\` / \\`get_content_entry\\`), call \\`generate_seo_meta\\` with that\n content as \\`text\\`, review the suggested metaTitle/metaDescription/keywords, then apply it via\n the page/entry update tools (or the dashboard SEO fields).\nKeep titles ~60 chars and descriptions ~155; don't overwrite good existing meta without asking.`;\n\n// ── Registration ─────────────────────────────────────────────────────────────\n\nexport function registerPrompts(server: McpServer): void {\n // Parent router — the generous entry point.\n server.registerPrompt(\n \"studio\",\n {\n title: \"BetterCMS Studio (guided)\",\n description:\n \"One command to author in BetterCMS. Detects what you want — create a page, add a field, create an entry — and runs the matching guided flow, then calls the right tool.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"what you want to do, e.g. 'a blog page with a hero zone'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `You are the BetterCMS authoring assistant (via the bettercms MCP).\n${request ? `The user's request: \"${request}\".\\n` : \"\"}\nFirst, **preflight**: confirm the bettercms tools are loaded (\\`create_page\\`, \\`add_field\\`,\n\\`create_content_entry\\`). If \\`create_page\\` is missing and only \\`create_model\\` shows, the host has a\nstale cached MCP — tell the user to run \\`rm -rf ~/.npm/_npx\\` and restart, then stop.\n\nThen **route** to the matching sub-flow below based on the request and conversation\ncontext. DEFAULT: when setting up a project or designing its schema from the repo (or\nwhen intent is unclear), run the **whole-repo schema design** flow — it proposes the\nstructure and confirms with the user before creating anything. Use the single-page or\nsingle-field flows only for targeted follow-ups. If still unsure, ask the user\n(AskUserQuestion: \"Design the schema from my project\" / \"Create one page\" / \"Add a field\" /\n\"Create an entry\" / \"Build a form\" / \"Build a component\"). Run flows by asking ONE step at\na time, pre-filling sensible defaults from the request but never inventing fields the user\ndidn't imply. Whatever the page/zone/form/component is scoped to follows the MCP key's project.\n\n${SCHEMA_PROPOSAL_FLOW}\n\n${PAGE_FLOW}\n\n${FIELD_FLOW}\n\n${ENTRY_FLOW}\n\n${FORM_FLOW}\n\n${COMPONENT_FLOW}\n\n${COMPONENTIZE_SITE_FLOW}\n\n${LAYOUT_FLOW}\n\n${BUILD_SITE_FLOW}\n\n${LANDING_PAGES_FLOW}\n\n${SEO_FLOW}\n\nThis assistant is extensible: when new BetterCMS tools are added, a new sub-flow appears\nhere — route to it the same way.`,\n },\n },\n ],\n }),\n );\n\n server.registerPrompt(\n \"edit_layout\",\n {\n title: \"Edit project or page Layout (guided)\",\n description:\n \"Safely edit a draft Global Layout or page override with optimistic locking. Publishing remains in the dashboard.\",\n argsSchema: {\n request: z.string().optional().describe(\"what to change, e.g. 'disable the footer on the pricing page'\"),\n },\n },\n ({ request }) => ({\n messages: [{\n role: \"user\",\n content: {\n type: \"text\",\n text: `Edit the BetterCMS Layout draft.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${LAYOUT_FLOW}\n\nReport which scope changed and the new revision. Remind the user that publishing is a separate dashboard action.`,\n },\n }],\n }),\n );\n\n // Direct entry point for whole-repo schema design (the confirm-first default).\n server.registerPrompt(\n \"propose_schema\",\n {\n title: \"Design schema from repo (confirm-first)\",\n description:\n \"Read the repository, propose a destructured content schema (pages → group/repeater zones → nested fields), confirm it with you, then create it via create_page. Use this to set up a project's schema.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"optional focus, e.g. 'just the marketing pages' or 'the whole site'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Design the BetterCMS content schema for this repository.${\n request ? ` Focus: \"${request}\".` : \"\"\n }\n\nPreflight: if \\`create_page\\` isn't available (only create_model/add_field/create_content_entry),\nthe host has a stale cached MCP — tell the user to \\`rm -rf ~/.npm/_npx\\` and restart, then stop.\n\n${SCHEMA_PROPOSAL_FLOW}\n\nAfter creating, report each page's id, path, type, and field count, and the project it\nlanded in. On 409 slug_taken, offer an alternative slug; on 401/403, the MCP key needs\n(re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for the page flow (parent can also dispatch here).\n server.registerPrompt(\n \"new_page\",\n {\n title: \"New page (guided)\",\n description:\n \"Guided creation of a BetterCMS page (singleton or dynamic) with fields, including nested group (Non-Repeatable Zone) and repeater (Repeatable Zone) fields. Calls create_page.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"what the page is, e.g. 'a blog page with a hero'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Create a BetterCMS page via the \\`create_page\\` tool.${\n request ? ` The user wants: \"${request}\".` : \"\"\n }\n\nPreflight: if \\`create_page\\` isn't available (only create_model/add_field/create_content_entry),\nthe host has a stale cached MCP — tell the user to \\`rm -rf ~/.npm/_npx\\` and restart, then stop.\n\n${PAGE_FLOW}\n\n${STRUCTURE_RULE}\n\nAfter creating, report the page id, path, type, field count, and the project it landed in.\nOn 409 slug_taken, offer an alternative slug; on 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for form authoring.\n server.registerPrompt(\n \"new_form\",\n {\n title: \"New form (guided)\",\n description:\n \"Guided creation of a BetterCMS form (fields + settings) you can embed with <BcmsForm>. Calls create_form.\",\n argsSchema: {\n request: z.string().optional().describe(\"what the form is, e.g. 'a contact form with name, email, message'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Author a BetterCMS form via the \\`create_form\\` tool.${\n request ? ` The user wants: \"${request}\".` : \"\"\n }\n\n${FORM_FLOW}\n\nAfter creating, report the form id and name, and how to embed it (\\`<BcmsForm form={getForm('Name')} />\\`).\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for component authoring.\n server.registerPrompt(\n \"new_component\",\n {\n title: \"New component (guided)\",\n description:\n \"Guided creation of a reusable BetterCMS component (a blockJson tree + overridable props) you render with <BcmsBlocks>. Calls create_component.\",\n argsSchema: {\n request: z.string().optional().describe(\"what the component is, e.g. 'a hero with heading, text and a button'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Author a reusable BetterCMS component via the \\`create_component\\` tool.${\n request ? ` The user wants: \"${request}\".` : \"\"\n }\n\n${COMPONENT_FLOW}\n\nAfter creating, report the component id, name, and slug, and how to render it (\\`<BcmsBlocks>\\`).\nOn 409 slug_taken, offer an alternative slug; on 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // The whole-site componentization ask. A direct entry point because the request arrives as one\n // sentence (\"componentize the whole site\") and used to route to §13 — bindings — which makes a\n // site editable in place and never builds the component library the user asked for.\n server.registerPrompt(\n \"componentize_site\",\n {\n title: \"Componentize the entire website (guided)\",\n description:\n \"Turn every section of a site into a reusable component, organised into groups editors can browse: audit with get_site_composition, create the components in one call, compose every page, then publish what the owner has approved.\",\n argsSchema: {\n request: z.string().optional().describe(\"scope or emphasis, e.g. 'marketing pages only'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Componentize this entire website in BetterCMS.${request ? ` Scope: \"${request}\".` : \"\"}\n\n${COMPONENTIZE_SITE_FLOW}\n\n${STRUCTURE_RULE}\n\nLast, before the summary: ${DOCK_UI_STEP}\n\nConfirm the component library with the user before creating it. End with the summary §12 asks\nfor: the group hierarchy, each family and its variants, what you left in the site's code because\nthe platform does not model it, and which components are still waiting for the owner's approval\nin the dashboard — those render as an empty string until they are published.`,\n },\n },\n ],\n }),\n );\n\n // The whole-site conversion ask, and the one prompt the dashboard launcher names. Its whole\n // job is that the agent does not stop early: the loop is written as a loop.\n server.registerPrompt(\n \"convert_site\",\n {\n title: \"Convert a site so nothing is left pending (guided)\",\n description:\n \"Run the conversion end to end: pull the source, run @bettercms-ai/convert, apply every fix it lists as pending, rerun until nothing is pending, and finish only when submit_conversion_receipt returns complete and get_binding_report reads unmatched 0, coverage.pending empty and every route's unaddressable under 2%.\",\n argsSchema: {\n projectId: z.string().optional().describe(\"the project to convert; omit if this connection is scoped to one\"),\n },\n },\n ({ projectId }) => ({\n messages: [{ role: \"user\", content: { type: \"text\", text: CONVERT_SITE_TEXT(projectId) } }],\n }),\n );\n\n // Direct entry point for end-to-end site authoring (schema → pages → AI copy → SEO).\n server.registerPrompt(\n \"build_site\",\n {\n title: \"Build a site (guided, end-to-end)\",\n description:\n \"Author a whole BetterCMS site from a repo or a brief: design the schema, create the pages, draft the copy with AI (write_content), and fill SEO (generate_seo_meta).\",\n argsSchema: {\n request: z.string().optional().describe(\"what to build, e.g. 'a SaaS marketing site from this repo'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Build a BetterCMS site end-to-end.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${SCHEMA_PROPOSAL_FLOW}\n\n${BUILD_SITE_FLOW}\n\n${STRUCTURE_RULE}\n\n${SEO_FLOW}\n\nConfirm each stage with the user before writing. On 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for programmatic-SEO / ABM landing-page generation.\n server.registerPrompt(\n \"generate_landing_pages\",\n {\n title: \"Generate landing pages (programmatic SEO / ABM)\",\n description:\n \"Spin up many personalized landing pages from one template + a dataset. For ABM (a page per named company) this is the research -> generate -> review -> approve -> publish -> share order.\",\n argsSchema: {\n request: z.string().optional().describe(\"the campaign, e.g. 'a page per target company for our ABM push'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Generate programmatic landing pages.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${LANDING_PAGES_FLOW}\n\n${STRUCTURE_RULE}\n\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // Direct entry point for an SEO metadata pass.\n server.registerPrompt(\n \"seo_optimize\",\n {\n title: \"Optimize SEO (guided)\",\n description:\n \"Generate and apply SEO metadata (title, description, keywords, JSON-LD) across pages/entries with generate_seo_meta.\",\n argsSchema: {\n request: z.string().optional().describe(\"scope, e.g. 'all blog posts' or 'the home page'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Optimize SEO metadata.${request ? ` The user wants: \"${request}\".` : \"\"}\n\n${SEO_FLOW}\n\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // FLO-1178 agent-import: the sequence that turns a LIVE imported site into an EDITABLE one.\n // A deploy alone leaves every trap in place — content only in the build (nothing binds),\n // no presentation manifest (generic previews), unpublished components (render as nothing).\n // This prompt is the ordered walk out of all three, mirroring playbook §11.\n server.registerPrompt(\n \"import-site\",\n {\n title: \"Make an imported site editable (guided)\",\n description:\n \"After importing or deploying an existing site: run the editor setup, componentize or convert it, declare its presentation manifest, and publish everything that renders. A build makes a site LIVE, not EDITABLE — this flow closes that gap.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"scope, e.g. 'all routes' or 'just the home page'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Make my imported site editable in BetterCMS.${request ? ` Scope: \"${request}\".` : \"\"}\n\nRead bettercms://playbook/schema section 11 first, then work this order:\n\n1. EDITOR SETUP — the build imported only SEO/meta, media, brand and the models the repo\n declares. Call editor_setup and poll editor_setup { check: true } until \\`ready\\`: it derives\n the pages, collections, forms and bindings from the live build.\n2. AUTHORING GATE — if get_next_steps or a deploy (409 AUTHORING_DECISION_REQUIRED) asks,\n ask ME components-or-fields (do not choose), then set_authoring_preference.\n3. COMPONENTS: get_componentize_plan -> componentize_sections (dryRun first) -> publish the\n components and pages -> componentize_sections { codemod: true } (the section-order codemod in\n the repo). FIELDS: the convert_site loop (get_conversion_brief, the codemod, the receipt).\n Only where the setup derived nothing: create_page (slug = route) -> add_field {pageId} ->\n set_page_content with values EXACTLY equal to the rendered text (binding matches by value; a\n paraphrase binds nothing) -> update_page status 'published'.\n4. PRESENTATION MANIFEST — add bcms-presentation.json to public/ (container width, type\n scale, nav position/background, footer surface as DTCG {\"$type\",\"$value\"} entries) and\n redeploy, or structural draft previews render in a generic theme, not this site's design.\n5. ${DOCK_UI_STEP}\n6. VERIFY — call get_next_steps and fix what it lists (it knows about missing manifests,\n a setup that has not run, and placed-but-unpublished components). You are finished only\n when its receipt.complete is true: run receipt.gate.nextAction, read it again after each\n batch, and record an item you cannot close with editor_setup { exempt } only under an allowed\n reason that is true. Telling me why is not an exception. Then, before you report, rename\n every field and section receipt.gate.naming lists (step names-from-code) from the site's\n source: it never holds the gate open, but the job is not done while those guesses stand.\n\nOn 401/403, the MCP key needs (re)authorizing.`,\n },\n },\n ],\n }),\n );\n\n // The editor-chrome lane. `ui`/`helpText`/`showIf` are declarable on every field-creating\n // tool, but an agent that does not know they exist writes a schema whose repeaters read\n // \"Item 1 … Item 10\". This prompt is the 3-tier rule as a slash command.\n server.registerPrompt(\n \"field-ui\",\n {\n title: FIELD_UI_PROMPT.title,\n description: FIELD_UI_PROMPT.description,\n argsSchema: { request: z.string().optional().describe(FIELD_UI_PROMPT.request) },\n },\n ({ request }) => ({\n messages: [{ role: \"user\", content: { type: \"text\", text: FIELD_UI_TEXT(request) } }],\n }),\n );\n}\n","/**\n * How to design a BetterCMS project — ONE copy, read by both MCP surfaces.\n *\n * WHY IT LIVES HERE AND NOT IN THE BACKEND. `packages/mcp` is a published npm package:\n * tsup bundles `src/index.ts` and externalises only the sdk/mcp-sdk/zod, so an import\n * reaching into backend `src/` would drag Hono, Drizzle and Postgres into the tarball.\n * The backend has no such constraint and already imports from this package (see\n * `src/__tests__/mcp/mcp-parity.test.ts`), so the dependency points backend -> package.\n * This module is deliberately dependency-free strings for exactly that reason.\n *\n * WHY A RESOURCE AND NOT A TOOL DESCRIPTION. Every tool's schema rides in the prompt on\n * every step of every turn; a resource is fetched once, on demand, by a client that wants\n * it. Long-form guidance in a description is a tax on all 82 tools forever. So the\n * remote host serves this at `bettercms://playbook/schema` and MCP_INSTRUCTIONS points at\n * it, while the stdio package folds it into its guided prompts.\n *\n * WHAT IT HAD TO FIX. The previous guidance was page-first: it mapped a site to pages,\n * groups and repeaters and never mentioned components, `sectionType` variants,\n * `kind:'block'` + `modular`, or the `document` body — so an agent asked for \"a marketing\n * site with a blog\" built a pile of flat page fields and a richtext box.\n */\n\nexport const PLAYBOOK_URI = \"bettercms://playbook/schema\";\n\nexport const SCHEMA_PLAYBOOK = `# Designing a BetterCMS project\n\nRead this BEFORE creating anything. Confirm the shape with the user before you build it.\n\n## 1. Pick the architecture first\n\n**Components-first** — a marketing site. A library of reusable *components*, each a\nsection, and thin pages that place them. Editors add, reorder and swap sections without\ntouching a schema. This is what \\`create_component\\` + \\`create_page(blockJson)\\` are for.\n\n**Schema-first** — a blog, a product catalogue, a directory: many rows sharing one shape.\nA collection (\\`create_content_model\\`) plus entries.\n\nMost real sites are both: components for the marketing pages, a collection for the blog.\nDecide before your first call; converting later means rewriting content — unless the site was\nDERIVED by \\`editor_setup\\`, where the componentize lane in §10 reuses every field.\n\n## 2. The decision tree\n\n Designing ANY section? -> FIRST find its closest kit entry in bettercms://kit\n (by category, then edge tag); follow that entry's\n mcp notes and avoid its pitfalls (tag rules below).\n Its props carry NO target: give each one a target\n into YOUR blockJson (§3) before create_component\n Every component names its kitEntry\n (bettercms://kit/entry/{id}). The import's entry\n is only a SUGGESTION: check its htmlSignals and\n pitfalls, confirm or replace it (update_component\n kitEntry rebuilds the derived ui and carries its\n rules; a gate.kit drift row lists rules still missing); exempt with no-kit-match or kit-drift-accepted only with a note\n Repeated visual region on a page? -> a COMPONENT with sectionType (a Section)\n ...and it comes in more than one look? -> siblings sharing that sectionType = VARIANTS\n A stack of mixed, reorderable content? -> kind:'block' models + a \\`modular\\` field\n A row in a list (post, author, tier)? -> a collection (kind:'model'); rows one template\n route renders get urlPattern, e.g. '/blog/:slug'\n Copy for ONE page (home, about, legal)?-> page fields in sections (add_field {pageId} /\n set_page_content) — never a one-entry collection\n The one body of an article? -> type:'document' (exactly one, top level)\n A fixed cluster of fields? -> group (never a 1-item repeater)\n A repeating cluster? -> repeater\n A list of plain strings? -> array (never a repeater of one text)\n A call to action (words + link)? -> ONE \\`button\\` field {label, href, variant?, size?,\n arrow?, icon?, newTab?} — never text + link fields\n (in a component: a \\`button\\` block, §3)\n A link to a page or CMS item? -> a \\`link\\` value {type:'page'|'entry', href, ref:<id>}:\n the write checks ref, delivery resolves it;\n a plain href string stays valid\n Site-wide nav/footer/modal? -> the LAYOUT (get_layout/update_layout), never a\n page section and never one component per page\n\nKit edge tags, one rule each (long form with entry ids: the skill's kit-scenarios reference):\n\n deep-nesting levels = content kinds, not wrappers; past 6, split the deepest subtree out\n repeater one band holds the list; never store what order says (step no., totals)\n polymorphic-array each item names its _type; merge consecutive prose into one text item\n slots children differ in shape; span/surface/phone order go in slotSettings\n variants column count, side, carousel = a variant, never a free number or boolean\n conditional a select reveals one branch; fill only it (hidden values still publish)\n references reference the entry/product/page; store only what differs as overrides\n dynamic-query store collection + filters + sort + limit; import the items as entries first\n global-synced same on ~80% of pages = one global; an instance overrides only what differs\n localized match locales by position, never text; never translate on import; no hreflang\n rich-text one body; callouts, tables, media, instances are islands; no h1, no chrome\n media-heavy largest source, real alt, video poster + caption file, positions in %\n embed store provider + id or canonical URL, never the script; iframes need a title\n form a Form reference by id; never the inputs copied into the section\n commerce the store owns price, stock, SKU, options, cart: reference, never copy\n personalization only with evidence; complete default, audiences hold only the differences\n validation numbers as numbers, datetimes with offset; check cross-field rules on import\n a11y every visual-only element gets text: logo name, pin label, iframe title\n seo-structured JSON-LD is emitted from content; never model meta or JSON-LD fields (§5b)\n responsive-layout per-breakpoint values as settings that inherit desktop; spacing as tokens\n\n## 3. Anatomy of a real section component\n\nA component that is only headings and text renders as an unstyled stack — plain text on white\nin a 768px column, on the live site AND in the visual editor. Every section the product ships\nlooks like this — a \\`section\\` block carrying \\`style\\`, with content nested in\n\\`props.children\\`. \\`create_component\\` and \\`update_component\\` return a \\`warnings\\` entry when a\nSection's root section has no \\`style\\`; treat it as a defect, not a note:\n\n {\n type: \"section\", id: \"root\",\n style: { bg: \"surface\", paddingTop: 96, paddingBottom: 96, contentWidth: \"default\", align: \"center\" },\n props: { children: [\n { type: \"heading\", id: \"h\", props: { text: \"Headline\", level: 2 } },\n { type: \"text\", id: \"sub\", props: { html: \"<p>Supporting copy.</p>\" } },\n { type: \"button\", id: \"cta\", props: { text: \"Get started\", href: \"/signup\", variant: \"primary\" } }\n ] }\n }\n\n\\`style\\` takes the design tokens the editor's dock sliders and pickers write: \\`theme\\`, \\`bg\\` /\n\\`bgCustom\\` / \\`bgImage\\` (an image url), \\`spaceTop\\` / \\`spaceBottom\\` / \\`spaceSides\\` (token steps,\nwinning over the \\`padding*\\` pixels), \\`contentWidth\\`, \\`contentAlign\\`, \\`opacity\\` (0–100), \\`corner\\`,\n\\`shadow\\`, \\`border\\` / \\`borderTop\\` / \\`borderBottom\\`, and on a button \\`hover\\` { bg, bgCustom, textColor,\nborder }.\n\nThen declare what an editor may change, via \\`props\\`:\n\n props: [\n { key: \"headline\", label: \"Headline\", target: { blockId: \"h\", path: \"props.text\" }, type: \"text\" },\n { key: \"body\", label: \"Body\", target: { blockId: \"sub\", path: \"props.html\" }, type: \"richtext\" },\n { key: \"ctaHref\", label: \"CTA link\", target: { blockId: \"cta\", path: \"props.href\" }, type: \"url\" }\n ]\n\nEach prop also takes \\`required\\`, \\`helpText\\` (≤ 200 chars) and \\`placeholder\\` (≤ 120), which the\ndashboard's prop editor renders. \\`helpText\\` is three-state: a string is yours, \\`null\\` is no help on\npurpose (send it for a prop whose /kit schema has no description; nothing refills it), and omitted\nlets the platform write one. They are HINTS: nothing on the write path refuses a placement\nthat leaves a required prop empty, so \\`get_site_composition\\` is what reports one.\nA /kit schema's document-level \\`preview\\` → the component's \\`preview\\`: how ONE instance reads as a ROW in a parent's slot list. {title?, subtitle?, media?} each name a TOP-LEVEL prop key or a dotted path into one (\\`slides.0.heading\\`; 422 \\`preview_key_unknown\\` otherwise), \\`fallback?\\` is a literal row label (≤ 120) and \\`icon?\\` a dock icon name; null clears it.\nA /kit schema's document-level \\`icon\\` → the component's \\`icon\\` (a dock icon name from bettercms://icons/dock, null clears): the block icon on the root crumb, slot rows and slot child frames.\nA /kit schema's \\`groups\\` → each prop's \\`ui.tab\\` (defined on the first top-level prop in it; a nested field's \\`group\\` → its \\`ui.tab: {id}\\`); a group NO top-level prop sits in → the component's \\`tabs\\` ([{id, label, icon?, order?}], 422 \\`component_tab_invalid\\` for a prop's own tab). A slot's \\`of.allow\\` → \\`config.allow\\` (block names); a scalar list's item settings (\\`of[0]\\` validation, description, localized) → \\`config.item\\`.\n\n**Prop types, one rule each.** 'select' REQUIRES \\`config.options\\` (a default must be one of them). 'group'/'table'/'object' REQUIRE \\`config.fields\\` (\\`[{key,label,type,options?,fields?}]\\`); a group writes an object, a table an array of them (\\`config.mode: 'data'\\`: ONE V2 table value, no fields). 'number' takes optional \\`config.min/max/step\\`. 'slot' holds ONE nested component instance: \\`target.path: 'props'\\` on an EMPTY component block (\\`props.componentId: \"\"\\`), \\`config.componentIds\\` restricts fills, defaultValue \\`{componentId, overrides?}\\`. 'form' holds ONE Form document: \\`target.path: 'props'\\` on an EMPTY form block (\\`props.formId: \"\"\\`), defaultValue \\`{formId}\\`, never the hydrated \\`{formId, form}\\` (400); do NOT re-declare the form's FIELDS as props, the Form document owns them. '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).\n\n🔴 **On a components-first page, \\`props\\` is the ONLY editing surface.** Click-to-edit binds\n\\`heading\\`/\\`text\\`/\\`button\\`/\\`image\\` blocks; it does **not** bind a \\`component\\` block, because\na component's blocks belong to the shared definition, not to the instance. So a page built\nfrom \\`component\\` blocks renders correctly and emits ZERO fields on the canvas — editing goes\nthrough the declared props allowlist to per-instance overrides. **A component with no props\nis a section nobody can change.** Declare a prop for every string, link and image a marketer\nwould ever reasonably want to touch; leave out only structure and styling.\n\n## 4. Variants\n\nComponents sharing a \\`sectionType\\` are swappable layouts of one section family — \"Hero\ncentered\" and \"Hero split\" both with \\`sectionType: \"Hero\"\\`. Swapping is one write and\nkeeps content, because overrides are keyed by prop KEY.\n\nSo **use the same prop keys across a family**. A variant that calls it \\`title\\` where its\nsibling calls it \\`headline\\` silently drops that content on the swap.\n\nPair \\`sectionType\\` with a library \\`category\\` (hero, content, social-proof, conversion) or\nthe component never appears in the editor's \"Add a section\" picker.\n\n**An IMPORTED site gets there without you writing any of that.** Its pages are derived by\n\\`editor_setup\\` — flat field groups (\\`hero-title\\`, \\`faq-question\\`, the repeaters folded as \\`group-*\\`)\nand an empty \\`blockJson\\` — so there is nothing in the picker and no section to swap. Read\n\\`get_componentize_plan\\`: it groups those fields into sections, names each family, and proposes\none component per SHAPE (the same hero on two pages is one component with two placements),\nwith every string, link and image already declared as a prop. Show the user the plan and\n**confirm before writing**, then \\`componentize_sections { digest, dryRun: true }\\` and, once the\nreceipt reads right, without \\`dryRun\\`. Each page's blocks become ordered \\`component\\`\ninstances carrying \\`props.bind\\` — the field group keeps the copy, so nothing moves and\nclick-to-edit keeps working. Pass \\`copy: \"instance\"\\` instead when the INSTANCE should own its\nwords (the page-builder model): each placement takes that group's current values into\n\\`props.overrides\\`, records where each came from in \\`props.source\\`, and the page's fields are\nkept and marked \\`origin: \"componentized\"\\` so the editor stops offering a second place to type\nthem. Either way, running it again converts nothing and duplicates nothing. Then run \\`npx @bettercms-ai/convert --componentize\\` in the repo\nso its templates render those sections from \\`pages[].blocks\\`, and finish with the publishes:\n\\`publish_component\\` every new component, \\`publish_layout\\` if you touched site chrome (nav,\nfooter), and publish the pages, or the site renders the sections as empty strings.\n\n## 5. Blocks and modular fields\n\nA \\`kind:'block'\\` model holds no entries of its own; it exists to be stacked inside another\nmodel's \\`modular\\` field. Create the blocks FIRST, then name their slugs (not ids) in\n\\`config.blockSlugs\\`. This is the page-builder shape: one \\`sections\\` field holding an\nordered list of typed blocks.\n\nA \\`slot\\` field (V2 blocks inside a block) takes the same \\`config.blockSlugs\\` (plus\n\\`minItems\\`, \\`maxItems\\` and \\`slotSettings\\`, leaf fields each child's \\`_settings\\` holds),\nbut stores each child INLINE: \\`[{ _key, _type: '<block slug>', _variant?, _settings?, ...values }]\\`,\nits values judged by its block's fields. A component's \\`slot\\` prop with \\`config.multiple\\`\ntakes the same child shape with \\`_type\\` the COMPONENT id (no \\`_variant\\`: a variant is its own\ncomponent). A \\`slot\\` may also be a SUB-FIELD: inside a \\`group\\` / \\`object\\` prop's\n\\`config.fields\\` or a \\`table\\` row (an item type's \\`fields\\` too), with the slot prop's\nconfig keys (\\`componentIds\\`, \\`multiple\\`, \\`minItems\\`/\\`maxItems\\`, \\`slotSettings\\`). Its value\nsits at its key in the object or row, \\`{ componentId, overrides? }\\` or a list with\n\\`config.multiple\\`, judged like a slot prop's: the same allowlist, depth cap and cycle refusal.\nA list of several item shapes on a component is a \\`table\\` prop with\n\\`config.mode: 'types'\\` and \\`config.itemTypes: [{ name, label?, fields, preview?, icon? }]\\`, rows\n\\`[{ _key?, _type: '<name>', ...values }]\\`. An item type's \\`preview\\` names its OWN fields (dotted ok, \\`<table>.caption\\`).\n\n**Block props by type** (a block's \\`props\\` in any \\`blockJson\\`): heading {text, level 1-6}; text/richtext {html} (NOT {text}), both also take level 1-6, rendering the html AS that <hN> with inline marks kept (one line of inline copy only); image {src (asset url), alt, caption?}; button {text, href, variant (hosted pages; else a Button component), size sm|md|lg, fullWidth, arrow, icon (a ui.icon name), newTab, rel nofollow|sponsored|ugc}; spacer {height px}; video {url, poster?}; form {formId}; component {componentId, overrides?}; navbar {links:[{label,href}], logo?, cta?}; footer {columns:[{heading?,links}], copyright?}; section {children: block[], background?, paddingY?, maxWidth?}; columns {columns: block[][], gap} (a column may hold ANY block); slider {slides:[{id,children:block[]}]}; tabs {tabs:[{id,label,children:block[]}]}; collection {cardComponentId?, source? {modelId}, limit?, filters?, sort?, pinnedIds?, excludeCurrent?}: a collection's published entries as cards. Containers nest blocks to any depth.\n\nA component inside a \\`richtext\\` value is \\`{ _type: 'bcmsBlock', _key, schemaKey: 'component',\nschemaLabel?, fields: { componentId, overrides?, variant? } }\\` and FOLLOWS the component: publishing\nit changes this place. A SEPARATE COPY stops following it: \\`fields: { componentId, detached: true,\nprops, blocks, sourcePublishedAt, variant? }\\`, exactly as \\`get_component { componentId,\ndetachedCopy: { overrides } }\\` returns them. It renders its own \\`blocks\\`; \\`componentId\\` stays so\nit can be linked again (write the linked shape), and a \\`sourcePublishedAt\\` older than the\ncomponent's \\`lastPublishedAt\\` (every publish; \\`publishedAt\\` is the first) means the shared\nversion changed since. Refused by name:\n\\`component_copy_invalid\\`, \\`component_copy_not_frozen\\`.\n\n## 5b. NEVER MODEL SEO. It is native.\n\nDo not create \\`seoTitle\\`, \\`metaTitle\\`, \\`metaDescription\\`, \\`ogImage\\`, \\`canonicalUrl\\`,\n\\`noindex\\` or an \\`seo\\` group on ANY model, page or component. Every one of those already\nexists on the platform:\n\n per page metaTitle, metaDescription, schemaType, schema — set with update_page\n per entry metaTitle, metaDescription, noindex, canonical, og, twitter, schemaType,\n schema — set with update_content_entry \\`meta\\` (merges; null clears a key)\n page head extras noindex, canonical, og, twitter — set with update_page (merges; null clears)\n site-wide defaults get_seo / update_seo — { metaTitle, metaDescription, ogImage, twitterHandle }\n generated for you generate_seo_meta\n audited for you list_seo_issues\n\nA modelled copy does not add a capability, it adds a SECOND place the same fact lives — and the\ntwo immediately disagree. The native fields are what the renderer emits into \\`<head>\\`, what\nsitemap and llms.txt read, and what \\`list_seo_issues\\` scans; a field called \\`seoTitle\\` on a\nmodel is a string an author edits that changes nothing on the page. It is worse than useless:\nit looks like the control and is not.\n\nIf a page needs its own meta, set it on the page. If the whole site needs a default, set it with\nupdate_seo. If you want it written for you, call generate_seo_meta and apply the result.\n\nThe one legitimate exception is a field that is genuinely CONTENT and happens to be used in meta\ntoo — a blog post's \\`excerpt\\`, an article's \\`coverImage\\`. Model those as content, name them\nfor what they are, and let \\`generate_seo_meta\\` read them.\n\n## 6. Blogs\n\n author collection: name, avatar, bio\n blog-post collection: title, slug, excerpt, cover (image),\n body (document), author (reference -> author)\n\n\\`document\\` is THE article body: a rich document canvas on pages or collections, at most one\nper schema, top level only (never inside a group or repeater). It cannot coexist with a\nSection zone, which also owns the document canvas. Use \\`richtext\\` for a short formatted field,\n\\`longtext\\` for multi-line plain text.\n\nThen the pages:\n\n create_page slug:\"blog\" pageType:\"dynamic\" fields:[...the post schema...]\n blockJson: [ heading, { type:\"collection\", id:\"list\", props:{} } ]\n\nNever put a \\`navbar\\` or \\`footer\\` block on a page: site chrome is the Layout (get_layout /\nupdate_layout), drawn around every page already, so a page copy duplicates it.\n\n create_content_entry per post, with pageId set to that page\n\nThe \\`collection\\` block is lane-aware: on \\`/blog\\` it renders a card per entry, and on\n\\`/blog/<slug>\\` it renders THAT entry. One page, both jobs. Every OTHER block in the array\nis interpolated per entry with \\`{{fieldKey}}\\` placeholders — \\`{{title}}\\`, \\`{{cover.url}}\\`,\n\\`{{body.html}}\\`. Note that richtext and document bind to \\`.html\\` only, never the bare name.\n\n## 7. Order of operations\n\n 1. blocks create_content_model kind:'block' (before anything references them)\n 2. collections create_content_model\n 3. components create_component (they land as DRAFTS)\n 4. publish publish_component <- every component you intend to place\n (409 COMPONENT_IMPLEMENTATION_NOT_READY: this exact variant still needs passing\n implementation evidence and a HUMAN's approval in the dashboard, which no tool\n can grant; relay the response's readiness to the user, never retry)\n 5. pages create_page with blockJson placing those components\n 6. content create_content_entry / set_page_content\n 7. publish update_page status:'published'\n 7b. layout publish_layout <- if you authored the Global Layout (nav/footer); page overrides publish with the page\n 8. check get_next_steps, and fix what it lists; on an imported site, until receipt.complete is true\n\n## 8. Two ways to ship a blank site\n\n**An unpublished component renders as an empty string.** Not an error, not a placeholder —\nnothing, on a page that returns 200. If a section is missing from the live site, check\n\\`publish_component\\` before anything else.\n\n**A workspace-level component (\\`projectId: null\\`) never reaches a live site.** It resolves\nin preview and is blank in production. Always pass the project's id.\n\n## 9. Check which project you are bound to, BEFORE you build\n\n\\`create_project\\` succeeds on a project-scoped connection and hands back a real new project\n— but every write that follows still lands in the project your grant is bound to.\n\\`projectId\\` is forwarded as a header for a workspace-scoped grant; a **project-scoped grant\naccepts it and ignores it**, silently. No error, no warning, wrong project.\n\nSo call \\`get_project\\` (no arguments) first — it reports the project you are actually\nwriting to.\n\n**If the grant covers the WHOLE WORKSPACE, that is not a blocker and there is nothing to\nstop for.** Pass \\`projectId\\` on every project tool — \\`list_projects\\` gives you the id, and\n\\`get_project { projectId }\\` confirms you are addressing the right site. Every tool takes it,\nincluding the code and deploy ones. Do NOT send the user to re-scope the connection; the only\nthing that genuinely blocks you is a grant on a different WORKSPACE, which is what an empty or\nforeign \\`list_projects\\` tells you.\n\nIf the connected project is simply the WRONG one for the work — a project-scoped grant pointed\nelsewhere — that is the case the user has to fix, in the BetterCMS dashboard under\n**Settings → Connected AI clients**. No tool can switch it.\n\nIf you must probe, probe with a \\`create_content_model\\` — models are deletable\n(\\`delete_content_model\\`, soft-delete) and **there is no \\`delete_component\\`**. A component\nwritten to the wrong project can only be demoted (\\`sectionType: null\\`) and left unpublished.\n\n## 10. You imported a site, or you are about to deploy one\n\n**A build imports what the build itself ships, and nothing more:** SEO and meta, every media\nasset, the brand, and the models the repository declares in \\`bcms-content.json\\`. Everything\nthat makes the site EDITABLE — pages, inferred collections, forms, bindings, button and section\ncomponents — is \\`editor_setup\\`, run on demand against the live build. The import recipe:\n\n import (import_github_repo / deploy_project) -> editor_setup (poll { check: true } until ready)\n -> the authoring answer -> componentize_sections, or get_conversion_brief (§13)\n -> the codemods (componentize_sections { codemod: true } runs the section-order one in the repo)\n -> submit_conversion_receipt / submit_componentize_receipt -> deploy\n\n\\`get_deploy_status\\` \\`editorSetup\\` (and get_next_steps) say when it has not run for the live\nbuild: \\`never\\` or \\`stale\\` → run it before anything below. It also fills missing meta from the\npages' own copy, merges components that are identical, and switches to declared bindings when the\nbuild proves every binding declared; get_next_steps lists only what it could not do.\n\n**Builds run \\`build:bcms\\` instead of \\`build\\`** when package.json declares one: the build alone,\nwithout CI checks (\\`\"build:bcms\": \"astro build\"\\` beside \\`\"build\": \"astro check && astro build\"\\`),\nkeeping any step the build needs. The convert codemod adds it; never edit \\`build\\` for BetterCMS.\n\n\\`deploy_project\\` and \\`promote_project\\` both answer **409\nAUTHORING_DECISION_REQUIRED** until a human has chosen this project's architecture. This is\nasked ONCE per project, ever. It is not an error to retry or route around: read the message\nout, let the user pick, call \\`set_authoring_preference\\`, then deploy again.\n\nUntil someone answers, \\`editor_setup\\` derives the pages but componentizes nothing (the\npreference is null). Once \\`components\\` is recorded, each \\`editor_setup\\` componentizes the\nderived pages' NEW sections in bind mode; \\`fields\\` stops it for good. And a run over the WHOLE plan splits a section component an earlier run placed on\n2 pages into one per page (the first page keeps it, the others get a clone), so two pages' heroes\nstop editing each other; a run narrowed to one page or section never splits.\n\nIt exists because an imported site arrives **field-driven whether anyone chose that or not**\n— a crawl-based import (Webflow, a starter, a template) emits pages with a typed field schema\nand an empty block tree, because that is all a crawl can infer. Nobody decided it. On a\nmarketing site it is the wrong answer. So the platform stops once, at the last moment it is\nstill cheap — and on a derived site that moment costs nothing, because the componentize lane\nbelow reuses every field \\`editor_setup\\` already derived.\n\n**Recommend \\`components\\`.** On a site whose pages were DERIVED by \\`editor_setup\\` — the site §13\ndescribes — it redoes nothing: the componentize lane turns each top-level field GROUP into a\ncomponent placement, and the page keeps its fields, its values and its bindings. In this order:\n\n 1. set_authoring_preference { preference: \"components\" }\n 2. get_componentize_plan one component per section, computed live; creates nothing. It\n reads this project's PUBLISHED pages, so no deploy is needed\n to reach it — the deploy is the last step, not the first.\n On a DERIVED site, each editor_setup after this answer\n runs this plan in bind mode for NEW sections (it never splits\n or joins a placement, and runs nothing while the answer is\n unset) and PUBLISHES what it created, so after one expect\n ALREADY_COMPONENTIZED and skip to step 6 (publish the pages) —\n the lane publishes the COMPONENTS, not the placements, which\n are still draft blocks on the pages. A /fr still on its own\n components joins its twin's with \\`joinTwins: true\\` (step 4)\n 3. show the user the plan and CONFIRM — it says how many components and which pages\n 4. componentize_sections \\`dryRun: true\\` first, then for real; components land as DRAFTS\n and each placement carries \\`props.bind\\` to the page's field\n group, so click-to-edit and the coverage meter do not change\n 5. publish_component each one — unpublished renders as NOTHING, on a page that 200s\n 5b. publish_layout if you authored site chrome — the layout is a separate publish\n 6. publish the pages\n 7. componentize_sections { digest, codemod: true } the section-order codemod\n (\\`--componentize\\`) on the repo's own Actions, so its templates\n render these sections from \\`pages[].blocks\\`; \\`skipped\\` = no\n repo it may commit to: run \\`npx @bettercms-ai/convert\n --componentize\\` in your checkout\n 8. deploy the ONLY deploy this sequence needs\n\nStep 5 is not a formality: \\`componentize_sections\\` and \\`create_component\\` both land components\nas DRAFTS, so \\`publish_component\\` each one and publish the page — otherwise the canvas keeps\npainting the PUBLISHED copy and the editor reports N components unpublished.\n\n**A site with nothing to componentize you author by hand.** Where the plan offers nothing for\na group (\\`NO_GROUP_ROOT\\` — the page's field keys are still the derive lane's own;\n\\`NOT_A_SECTION\\` — a lone scalar with no family), and on a site with no derived pages at all,\nthe order is \\`create_component\\` per section → \\`publish_component\\` each → \\`set_page_content\\`\nplacing \\`component\\` blocks → \\`list_extraction_candidates\\` / \\`extract_component\\` to fold any\nsection repeated 3+ times. \\`extract_component\\` is not a converter and cannot stand in for the\ncomponentize lane: it scans \\`blockJson\\`, which is empty on exactly the pages that would need\nconverting.\n\n**Answering \\`fields\\` is a real answer, not a deferral** — for a SCHEMA-FIRST site. A blog, a\ncatalogue or a directory is schema-first by design (§1) and should stay that way. On anything\nelse it costs the editor the ability to add, reorder or swap sections. Say so and move on.\n\nEither way: ask, do not choose — recommending is not answering. The 409 carries this project's\nactual page counts — how many are field-driven, block-driven, and how many place a reusable\ncomponent — so quote those to the user rather than describing the choice in the abstract.\n\n## 11. The canvas: what makes an imported site EDITABLE\n\nA deploy makes a site LIVE. It does not make it editable — those are different states, and the\ngap between them is the single most common disappointment after an import.\n\n**The canvas is the real site.** A PUBLISHED page of a DEPLOYED site with DECLARED bindings\nframes the project's OWN build, with unpublished text painted over it, whether or not the draft\nhas drifted from the published copy. STRUCTURAL drafts (new\nsections, reordering, a changed component definition) are the one thing that build cannot show,\nand there are four ways to see them: publish and redeploy; the editor's **Draft render** toggle,\nwhich swaps in the platform renderer on demand (approximate theme, one click back); live, through\nthe draft bridge below (Next); or — for server-rendered sites — the node lane, coming.\n\nOnly FOUR states use the platform renderer by default: an UNPUBLISHED page, a page whose route\nthe last build does not carry (\\`get_binding_report.builtRoutes\\`), a project with NO build at\nall, and a \\`mode: \"text-match\"\\` site whose draft has drifted (its elements are found by matching\npage text to stored values, so drifted text may be unclickable — declare the bindings, §13).\nThose are exactly where \\`bcms-presentation.json\\` matters — the renderer previews in a\nGENERIC theme unless the deploy artifact declares one at its root. Put the file in \\`public/\\`\n(the build lands it at the artifact root) declaring the site's presentation — container width,\ntype scale, nav position and background, footer surface — as DTCG \\`{\"$type\": ..., \"$value\": ...}\\`\nentries. Redeclare it on every deploy; absent means \"declared nothing\" and previews fall back\nto platform defaults that will not look like this site.\n\n**Which live-preview lane THIS site has, and what it costs not to have one.**\n\\`get_binding_report.canvas.lane\\` names it: \\`bridge\\` (the build ships \\`BcmsDraftBridge\\` from\n\\`@bettercms-ai/next/draft-bridge\\`, so a structural draft re-renders inside the site's own\nbuild), \\`draft-route\\` (a node runtime whose app renders drafts server-side), or \\`none\\` — no\nlane, so every structural draft falls back to the platform renderer and its generic theme.\n\\`null\\` means the report predates the field; redeploy to learn. When it is \\`none\\`,\n\\`get_next_steps\\` names the recipe for this project's framework (\\`canvas-lane-missing\\`), and\n§13 step 5c has both. The same report carries \\`unaddressable\\`: how much VISIBLE text on the\nlive site no field owns — \\`unmatched\\` cannot see it, because it only ever speaks about fields\nthat already exist. EVERY release measures it server-side, per route, with a denominator and the\nplaces it is (\\`unaddressable.routes[]\\`: \\`path\\`, \\`count\\`, \\`visible\\`, \\`buckets[]\\`). An author\nturning the editor's **\"Unbound text\"** control on posts a bare count of text NODES for the route\nthey opened; it is reported only for a build the release never measured, and never added to\nthe release's characters. Ornaments, skip links and the platform badge are excluded from both sides.\n\n**THE LOOP, and it is not optional — a deploy is not a conversion.**\n\n 1. deploy, then \\`get_binding_report\\`;\n 2. for each \\`unaddressable.routes[]\\` where \\`count / visible > 0.02\\`:\n read its \\`buckets\\` — each one is a TAG in a LANDMARK with a sample of the copy;\n 3. fix it in the SOURCE: wrap that run of text in an element the codemod can bind (a\n \\`<span>\\`, a \\`<p>\\`, a \\`<div>\\` — never a bare text node between tags), or declare it\n yourself with \\`<BcmsField path=\"…\">\\`;\n 4. deploy again and re-read. Repeat until every route is under 2%.\n\n\\`get_next_steps\\` runs the same test and hands you the worst route with its buckets\n(\\`unaddressable-copy\\`). Its \\`receipt.gate\\` holds EVERY built route to that bar, beside its page,\nits images and its links, and \\`receipt.complete\\` stays false until each route passes. A \\`coverage\\` carrying \\`error: \"nothing-bound\"\\` means NOT ONE element\nof the build is bound — usually the singleton lane declined the project (\\`skipReasons\\`\n\\`authored-content\\`: its content models were authored by the repo), so the percentage beside it\ndescribes a site this build is not.\n\n**A site built in the CMS with NO deployed build has only that renderer** — live and in the\neditor — so the generic theme IS the site until you theme it. Theme it without a deploy:\n\\`update_project { presentation: { \"page.maxWidth\": { \"$type\": \"dimension\", \"$value\": 1200 },\n\"nav.background\": { \"$type\": \"color\", \"$value\": \"#0b0b0b\" }, ... } }\\` takes the same knobs as\nbcms-presentation.json, and set \\`style\\` on every Section's root (§3). A later deploy that\nships bcms-presentation.json replaces it wholesale.\n\n**Editing binds by VALUE.** The editor matches CMS field values against the text the site\nrenders. Three consequences, each load-bearing:\n\n 1. Content that exists ONLY in the build can never be click-to-edit. Bring it in, per\n route, in this order (get_next_steps reports the state until it is done):\n\n a. create_page one per route, slug matching the route\n b. add_field {pageId} the fields its content needs (or create_component +\n publish_component + component blocks, per your §10 answer)\n c. set_page_content values EXACTLY equal to the text the site renders —\n binding matches by value, so a paraphrase binds nothing\n d. update_page status 'published' — the canvas binds the PUBLISHED copy\n e. publish_layout if site chrome was authored — the canvas binds the PUBLISHED layout too\n 2. A value that renders in more than one place is still ONE field: bind every element that\n renders it, and the editor keeps them in sync — an edit patches every copy at once.\n Binding only one copy leaves the others showing the old text until the next rebuild.\n 3. Make the chrome ITSELF editable by speaking the layout grammar: the nav/footer\n elements declare \\`data-bcms-layout-section=\"navigation\"\\` / \\`\"footer\"\\`, and each\n CMS-backed text inside them a \\`data-bcms-layout-field=\"layout:<sections[slug].id>:<fieldId>\"\\`\n marker (fieldId is the field's REAL id, verbatim — production layout ids are\n section-prefixed and dotted, e.g. \\`footer.tagline\\`, so the marker reads\n \\`layout:footer:footer.tagline\\`) — the canvas then gives them hover chrome, the\n Layout side panel, and\n double-click editing, writing to the project Layout store (never the page).\n The address reaches INSIDE structured fields by walking the schema: a group's text\n sub appends its slug (\\`layout:navigation:navigation.cta.label\\`), a repeater row its\n STORED index then the slug (\\`layout:navigation:navigation.links.0.label\\`), nesting\n as deep as the schema goes (\\`layout:footer:footer.link-groups.0.links.1.label\\`).\n Five rules, each one a measured defect when broken:\n a. a field rendered by TWO elements gets a marker on BOTH — the editor keeps the copies\n in sync, and a marker on only one leaves the other stale;\n b. PROVENANCE — mark an element only when the LAYOUT supplied its value; a marker\n over a fallback/singleton-sourced string opens an editor for a row that does not\n exist;\n c. row markers use the value's STORED index (a row you filtered out of the render\n still occupies its slot), or the edit lands on the wrong row;\n d. the address names the DELIVERED entry's id, \\`sections[slug].id\\`, never the slug — a\n Section created in the dashboard has a UUID id. On a translated route address the\n entry that fills the slot, by ITS own id: a page's own \\`layout\\` already delivers it\n at \\`sections['navigation']\\`, the Global Layout carries it beside the base at\n \\`sections['navigation--fr']\\`; the \\`data-bcms-layout-section\\` wrapper still names\n the SLOT, the base slug (\\`navigation\\`);\n e. ONE OWNER PER ELEMENT: never a \\`data-bcms-field\\` inside a Layout-declared region.\n The report will not flag one you write: it binds, and the element gets two writers.\n \\`layout-owned\\` names only the page copies left with no element, which the strip removes.\n Text/longtext leaves edit inline; link/select/image leaves are side-panel-only by\n design (their formats need a real control). THE DOCTRINE: every string a marketer\n can see must be addressable — no marker means read-only on the canvas, so an\n unmarked CMS-backed string is a defect, not a style choice.\n On a site BetterCMS serves, a Layout publish never builds: it writes the new VALUES into\n the live pages, and a STRUCTURE change (a Section added, removed or moved) waits for a\n Rebuild or a push — get_next_steps says \\`layout-rebuild-required\\` until a build ships\n it. A custom host gets its deploy hook instead.\n 4. Keep chrome semantic — \\`<nav>\\`, \\`<footer>\\`, page content inside \\`<main>\\`, mastheads\n as a top-level \\`<header>\\`. Chrome is edited through the project Layout, not the page,\n and semantic landmarks are how the editor keeps a nav edit from being written into page\n content. Div-built chrome outside \\`<main>\\` is still excluded; div-built chrome with no\n \\`<main>\\` anywhere loses that protection.\n\n**Structural drafts can render on the real site too, LIVE — the draft bridge.** Wrap your page's\nblocks in \\`BcmsDraftBridge\\` (\\`@bettercms-ai/next/draft-bridge\\`) instead of calling\n\\`BcmsBlocks\\` directly: standalone it renders identically, and inside the visual editor it\nreceives the DRAFT block tree over a same-origin postMessage handshake and re-renders it with\nthe site's own components — so adding, removing or reordering sections previews in the site's\nreal design, with no publish and no Draft render detour. A bridge that answers wins over the\ntoggle. Sites without one keep Draft render's approximate fallback, and a route the build does\nnot carry falls back always (a static build has no file to frame).\n\n**Sections on a site whose CODE renders the page.** The editor's outline is the page's \\`blockJson\\`,\nbut a code-built site ships only what its own templates draw:\n- An added or moved section reaches the live site only when the site renders the page's block list\n itself, in order, each section root stamped \\`data-bcms-block=\"<blockId>\"\\`. \\`npx @bettercms-ai/convert\n --sections\\` wraps a page's sections in \\`<BcmsSections>\\`, which is that loop and the stamps\n (\\`--componentize\\` lifts them into components first, where a plan exists). Until it ships, the canvas\n only ARRANGES the static build to match the draft (a section the build never rendered is stood in for\n by a server render); the editor still saves added, moved and swapped sections but says the live site\n keeps its own order, and offers \"Let BetterCMS control section order\" (that same codemod, committed\n to the connected repository); and each such route leads \\`submit_conversion_receipt\\`'s \\`pending\\`\n with a \\`SECTIONS_UNSTAMPED\\` row, so \\`complete\\` stays false. Never hard-code a page's bands, or\n literal \\`data-bcms-block\\` ids, in a template whose order the CMS owns: a release measures whether\n the stamped roots come out in the CMS order (\\`ordered\\` on the binding report's structure row).\n- To add ONE section or set ONE section's spacing, send \\`update_page\\` an OBJECT \\`blockJson\\`:\n \\`{ insertSection: { componentId, at | before | after, style?, overrides? } }\\` or\n \\`{ sectionStyle: { blockId, style } }\\`. The server edits the stored page, so nothing else is\n resent. An answer that begins with \\`held\\` is a saved draft this site's code will not show:\n take the hold's action first. A publish answers with \\`outcome\\`; \\`partial\\` names each value\n that is not live and its action. Neither is ever \"done\". \\`get_next_steps\\` keeps them listed\n (\\`publish-held\\`), and its gate fails a route on \\`sections\\` or \\`style\\` until the build draws\n the page's sections from the CMS and marks every root for style, or the release writes them in\n place. Each failing row's \\`fixCode\\` says which: the project's switch, the wrap, or a rebuild.\n- A placement the site never renders (a leftover nav, footer or modal its layout draws) moves\n nothing: the editor counts section moves in RENDERED sections only and locks that row. Remove\n such placements; do not reorder around them.\n- Section spacing and style handles need every stamped root to also carry \\`data-bcms-style\\` and\n paint \\`block.style\\`: spread \\`sectionRootAttrs(block)\\` (\\`@bettercms-ai/astro\\`, \\`@bettercms-ai/next\\`)\n on the root. A site converted before that existed shows none (\\`get_next_steps\\`\n \\`upgrade-section-roots\\`): run \\`npx @bettercms-ai/convert@latest --upgrade-sections --root .\\` (with\n \\`--dry-run\\` first), fix the roots it lists as skipped by hand, check \\`--verify-styles\\`, push, release.\n\n**Hosting decides whether a canvas exists at all.** A site deployed here is framed through a\nsame-origin proxy — that is what the canvas requires. A site hosted elsewhere (your own Vercel,\nyour own server) has NO canvas today: the SDK's draft mode with \\`stega: true\\` embeds invisible\nper-field provenance in fetched strings, which prepares the content for editing surfaces, but do\nnot promise a canvas for an externally-hosted site.\n\n**RECEIPTS: a claim about published state needs a read of the PUBLISHED copy.** The\ndoctrine this encodes cost a real incident (FLO-1188): a publish was verified against the\ndraft for ~50 minutes because the reader silently returned the draft, and every check was\ngreen on the wrong document. Three rules, none optional:\n 1. NEVER verify a write by re-reading the store you wrote. Draft writes verify against\n the draft; a PUBLISH claim verifies ONLY via \\`get_layout copy:'published'\\` (or the\n entry/page's published copy) — and check the response's \\`copy\\` echo says\n 'published'. A reader that ignores your copy selector hands you the draft and a\n false green; the echo is how you catch it. \\`publish_layout\\`'s own response echoes\n copy:'published' too — that is the WRITE's echo, not a receipt; still re-read.\n 2. Publish and deploy are SEPARATE claims. \"Published\" means the published copy changed;\n the LIVE SITE changes only after its next deploy/rebuild. Never report \"it's live\"\n from a publish receipt — fetch the live URL (cache-busted) for that claim.\n 3. A tool param the schema does not declare is SILENTLY DROPPED, not rejected. If a\n call's behavior doesn't change when you change a param, treat the param as dead and\n verify through an independent channel before trusting any result built on it.\n\n## 12. Componentize the entire website\n\nThe whole-site ask — \"turn every section into a reusable component, organised for editors\" —\nmapped onto what this platform actually models. Work the order at the end; each numbered part\nbelow is one heading of that ask.\n\n**1. Global elements.** Navbar, mobile nav, header and footer are the LAYOUT, not page content:\n\\`get_layout\\` then \\`update_layout\\`, and a chrome COMPONENT is placed into a Layout section with\nthe \\`add-component\\` command. CTA buttons are \\`button\\` BLOCKS inside the section that uses them,\nexposed as \\`text\\` + \\`url\\` props that target that ONE block — never the words as a separate text\nblock beside it, or the Button panel edits nothing — variant, size and fullWidth are that block's own props and\n\\`style\\`. Do not hand-build a Button component. On a site built here every button look you write joins\nthe project's Button family (Globals/Buttons) on its own, and a new look is \\`create_component\\` with\n\\`variantOf\\` naming a Button. On an IMPORTED site the family is the looks measured in the site and\nnothing you write adds to it: read it with \\`list_components\\`, place a look as a \\`component\\` block,\nand never add CSS for a look the site does not have. On a page's FIELDS a CTA is one \\`button\\` field\n(§2), whose \\`variant\\` picks a look of that family. Rich text is a \\`richtext\\` prop over a\n\\`richtext\\`/\\`text\\` block. Forms are \\`create_form\\` plus a \\`form\\` block, and form FIELDS are the\none place the platform models \\`required\\`, \\`placeholder\\`, \\`helpText\\` and real \\`validation\\`\n(emailPolicy, min/max, phoneFormat, pattern) — put a site's validated inputs there. Cards,\nbadges, tags, links, lists and media are BLOCKS inside a section, exposed through props; a\nrepeatable row of them is ONE \\`table\\` prop whose \\`config.fields\\` describe the row. Accordions\nand FAQs: start from the \\`builtin:faq-list\\` blueprint, or use a \\`tabs\\` block. NOT MODELLED —\ncookie banners, modals, breadcrumbs and pagination have no primitive at all. Leave them in the\nsite's code and say so in your final summary. A modal is chrome, like the nav: never a page section\n(the plan reports it \\`LAYOUT_CHROME\\`).\n\n**2. One component per distinct section, one-offs included.** \\`create_component\\` with a\n\\`sectionType\\` IS the section. \\`sectionType\\` is the FAMILY (Hero, Features, Testimonials,\nPricing, FAQ, Contact, Newsletter, CTA, Stats, Logo cloud, Content…) and components sharing one\nare its VARIANTS — give a family the same prop KEYS or a swap drops content. A one-off band\nstill gets its own component: its own family, plus \\`allowedOn: [\"slug:<page>\"]\\`. A component\nwith NO \\`sectionType\\` never appears in the editor's \"Add a section\" picker. On a BLANK site, start\nfrom the builtin blueprints \\`list_components\\` returns (\\`builtin:*\\`) instead of hand-writing block\nJSON. On an IMPORTED site, never materialize a builtin: read the repo's own components first\n(\\`src/components\\`, its sections folder) and make ONE CMS component per source component, named\nas the source names it — the site's Pricing section is \"Pricing\", not \"Section 2\" or \"Simple\".\nOn a DERIVED site run \\`get_componentize_plan\\` → \\`componentize_sections\\` FIRST — it does most\nof this in one call, and once \\`components\\` is recorded each \\`editor_setup\\` of a derived site\nruns it in bind mode and publishes the components, so expect ALREADY_COMPONENTIZED — the placements it wrote are\nstill DRAFT blocks on the pages, so publish the pages, then \\`componentize_sections { codemod: true }\\`\n(or \\`npx @bettercms-ai/convert --componentize\\` in your checkout).\n\n**3. The hierarchy editors see is the GROUP.** \\`create_component\\` and \\`update_component\\` take\n\\`group\\`: a NAME, resolved against the project's component groups and created when missing. That\nis the folder the dashboard's Components tab shows. Use the names the request asks for — Global,\nNavigation, Actions, Content, Forms, Media, Sections, Page-specific. \\`category\\` is a different\naxis: it is the picker TAB (hero / content / social-proof / conversion for sections; navbar /\nfooter for chrome; form; custom for page-specific).\n\n**3b. Group the fields the way the source groups them.** A price, a stat's figure and a badge are\nprops of their own (\"Price\", \"Stat value\"), never folded into a sentence. Give every component of\nmore than ~8 props \\`ui.group\\`s that mirror its markup — Content, Call to action, Media — and\n\\`ui.collapsed\\` on the secondary ones (§14). A flat list of 20 props named by their copy is the\nform editors cannot read.\n\n**4. Editor fields are \\`props\\`.** Types: \\`text richtext image url boolean number select group\ntable slot form\\`. Always set \\`defaultValue\\`. \\`form\\` points at ONE Form document: target a\n\\`form\\` block's \\`props\\` and set \\`defaultValue\\` to \\`{formId}\\`. NEVER re-declare a form's fields\nas props — the Form document owns them, a second copy drifts on the first edit, and the Forms\ntab is where an author edits them. \\`required\\`, \\`helpText\\` and \\`placeholder\\` are editor\nhints the dashboard renders — they are NOT enforced at write time, so an override missing a\nrequired prop still saves; \\`get_site_composition\\` is what reports those. Use \\`select\\` with\n\\`config.options\\` for layout / theme / alignment / spacing variants that change only styling,\nand a SEPARATE variant component when the markup differs. Repeatable list → \\`table\\`; fixed\ncluster → \\`group\\`. Nesting goes up to 10 levels counting the prop itself. A \\`table\\` row may hold a\n\\`table\\` (rows), a data table (\\`config.mode: \"data\"\\`) or a polymorphic list\n(\\`config.mode: \"types\"\\`), so a size guide's rows can each carry a chart and a multi-step\nform's steps can each carry their fields. Deeper is refused (\\`field_depth_exceeded\\`).\n\n**5. Design, responsiveness and accessibility.** \\`componentize_sections\\` and \\`npx\n@bettercms-ai/convert --componentize\\` move the section's markup VERBATIM — classes, responsive\nutilities, aria attributes and alt text all survive. Never restyle while componentizing. Run\n\\`componentize_sections { dryRun: true }\\` and the codemod's \\`--dry-run\\` first.\n\n**5b. Every component's Output must render — record its SOURCE.** The dashboard's Output builds and\nvalidates a component from the file in the repository that renders it, and only a file whose props\nmatch renders it. A section the codemod extracted is such a file: after \\`npx @bettercms-ai/convert\n--componentize --receipt componentize.json\\`, push the files and call \\`submit_componentize_receipt\n{ receipt }\\` — every extracted section is recorded for the component with the same slug. A section\nyou write BY HAND follows the same contract: props exactly \\`{ blockId, bind, overrides, page }\\`, the\nroot element carries \\`data-bcms-block={blockId}\\`, and copy is read through \\`bcmsSection(page, bind,\noverrides)\\` (or \\`bcmsSectionPaths\\` for a flat field family like \\`wrap-h2-latest\\`); then call\n\\`set_component_source { kind: 'section' }\\`. A component module whose props ARE its fields is\n\\`set_component_source\\` with the default kind. NEVER record a different component that merely\ncontains the markup (a card needing a \\`post\\` object): it cannot render from these fields and its\nvalidation fails every time — \\`clear_component_source\\` removes a wrong one.\n\n**6. The final validation is \\`get_site_composition\\`.** It is the receipt for \"is every page\nassembled from registered components?\": per page its blocks and every component placement with\nthat component's status, plus site totals — unpublished, awaiting evidence, awaiting approval,\nmissing from the picker, placed nowhere — and \\`verdict.everyPageComposed\\` with the reasons it\nis false. A component reaches a visitor only once PUBLISHED, and publishing needs the project\nowner's approval in the DASHBOARD: evidence comes from \\`request_component_validation\\` and a\nvalidation run in the repository, the owner approves there, then \\`publish_components\\`. There is no\nbulk approve, and no tool here can grant that approval. Finish with \\`get_next_steps\\`.\n\n**Order of operations.**\n\n 1. get_site_composition the before picture\n 2. get_componentize_plan DERIVED site only — confirm it with the user\n 3. componentize_sections dryRun first, then for real\n 3b. npx @bettercms-ai/convert --componentize --receipt componentize.json, push,\n then submit_componentize_receipt { receipt } every section's Output source, ONE call\n 4. create_component each section the plan did not cover, each with a group\n 5. compose_pages every page's blockJson, ONE call\n 6. update_layout { commands } nav/footer chrome + add-component, ONE call\n 7. evidence request_component_validation -> the repo's validation run\n 8. owner approves in the dashboard, then publish_components ONE call, per-item receipts\n 9. update_page status:'published', publish_layout\n 10. get_site_composition, then get_next_steps\n\n**What to tell the user at the end.** The group hierarchy and what landed in each; every family\nand its variants; what you left in the site's code because the platform does not model it\n(cookie banners, modals, breadcrumbs, pagination) and why; and exactly which components are\nstill waiting for THEIR approval in the dashboard — until that happens those sections render as\nan empty string on the live site.\n\n## 13. Convert an imported repo into a CMS-backed, editable site\n\n§11 says a deploy does not make a site editable. This is the recipe that does.\n\n🔴 **A CONVERSION ENDS ONLY WHEN NOTHING IS PENDING.** The codemod's first pass never\ndeclares every path — measured on a real site, one pass declared 282 of 767 — and every path it\nleaves in \\`paths.pending\\` carries a \\`fix\\` naming the file, the line and the one edit. Apply\nthem, rerun, resubmit, and repeat until \\`submit_conversion_receipt\\` answers \\`complete: true\\`.\nThat boolean is the finish line; a receipt with pending paths is a progress report. The\n\\`convert_site\\` MCP prompt walks exactly this loop.\n\n**Scope, before you start.**\n\n(a) This is the FIELD-driven conversion — page fields and collections. If the human answered\n\\`components\\` at the §10 gate, go to §10's recipe instead: a component's editing surface is its\ndeclared \\`props\\`, and those bindings are NOT what \\`get_binding_report\\` walks.\n\n(b) It works for any framework that emits STATIC HTML, because the binding contract is plain\nHTML attributes — the annotator, the injector and the canvas stamper never see your source.\nThere are SDK helpers for Astro and Next. A Node-runtime site (\\`bcms-runtime.json\\`) edits on\nthe canvas but skips release annotation and publish-time injection, because there is no HTML on\ndisk to annotate. Copy rendered on the client must carry the attributes in the HYDRATED DOM,\nand only the canvas sees it — a release scan cannot.\n\n**On a workspace-wide connection, pass \\`projectId\\` on every call in this section** — that is\nall it takes; the code and deploy tools work from such a connection and nobody needs to re-scope\nanything. See §9.\n\n**Which recipe.** There are TWO below and they are not alternatives you pick by taste — call\n\\`get_binding_report\\` and \\`get_conversion_brief\\` first and let the answer choose. A brief that\ncomes back WITH PAGES means this project was imported and \\`editor_setup\\` derived its schema and\nvalues already → **Recipe A**. On an import whose \\`get_deploy_status\\` \\`editorSetup\\` is \\`never\\`\nor \\`stale\\`, run \\`editor_setup\\` FIRST and read the brief again. A 404 or an empty brief after\nthat means the site is not in the CMS yet → **Recipe B**. \\`get_next_steps\\` works on every plan and names the next unfinished step\neither way.\n\n**If you know Sanity, this is the same shape under different names:**\n\n defineType schema in code -> content models / page fields (create_content_model,\n add_field, or bcms-content.json \"schema\")\n TypeGen -> @bettercms-ai/codegen\n GROQ query in the page -> @bettercms-ai/sdk read client, or the bcms-content.json\n build snapshot\n <PortableText> body -> @bettercms-ai/richtext portableTextToHtml, field type\n 'document'\n data-sanity / stega -> data-bcms-field + data-bcms-kind (<BcmsField>), stega on\n draft reads\n Presentation tool overlays -> the visual editor canvas, framing your own build\n\n**Imported site whose pages were DERIVED.** If this project was imported and \\`editor_setup\\` ran\nover its build, the schema and the values already exist — a page per route, a field per element, and\nthe original copy carried on each field as its \\`defaultValue\\`. Call \\`get_conversion_brief\\`\nfirst: it lists those pages, their routes, every bindable path with its current and original\nvalue, and the attributes to declare. SKIP Recipe B's steps 3 and 4 below and bind the keys it\nnames — registering the schema again builds a second one over the first.\n\n**Recipe A — imported and deployed: the codemod order.** For a derived site the whole of Recipe\nB's step 5 is mechanical, and there is a tool that does it. Run the codemod rather than editing by\nhand. THE ORDER, and every step of it matters:\n\n1. \\`get_conversion_brief { complete: true }\\` — the COMPLETE brief, not the capped one. It comes\n back uncapped and paged (50 pages at a time): follow \\`cursor\\` until it stops coming back and\n keep every page. The capped read truncates values and omits pages, and a codemod fed a\n truncated \\`original\\` searches the source for a string that is not there. Page 1 PINS the\n path list under a \\`briefDigest\\`; that pinned list is what the coverage meter measures the\n build against, so nothing later can move the denominator. A 409 \\`BRIEF_CHANGED\\` mid-pagination\n means the brief was re-derived under you — start again with no cursor.\n2. Write the pages you collected to \\`brief.json\\` and run\n \\`npx @bettercms-ai/convert --brief brief.json --root . --receipt receipt.json\\`, then read\n \\`git diff\\`. It rewrites the templates to read from BetterCMS, keeps the in-code copy as the\n fallback, and declares each binding.\n2b. IF THE BRIEF CARRIES \\`forms\\`, wire them too:\n \\`npx @bettercms-ai/convert --forms --brief brief.json --root . --receipt forms-receipt.json\\`\n — ITS OWN receipt file, submitted with submit_conversion_receipt as a second call under the\n SAME \\`briefDigest\\` (its \\`paths\\` are all zero): the server stores its \\`forms\\` block\n beside the binding receipt (never counted in coverage), and\n the next release reads \\`wiredForms\\` to say which component renders each form.\n A site imported by phase 1 has a DRAFT form row per \\`<form>\\` in its build, so the Forms tab\n is full while the repository's markup still posts wherever it always did — to nothing, or to\n somebody else's endpoint. This pass writes the endpoint, the form id, a marker per field and\n the submit script onto the \\`<form>\\` the repository already has. Then PUBLISH each form the\n receipt's \\`forms.notes\\` names, in the Forms tab: the public submit route answers 403 to a\n draft, so a wired draft form is a real, inviting form that rejects every visitor. Forms it\n could not match are in \\`forms.pending\\` with a reason (\\`FORM_NOT_IN_SOURCE\\`,\n \\`FIELD_UNMATCHED\\`, \\`FORM_AMBIGUOUS\\`, …) — it refuses rather than guessing, because a form\n wired to the wrong id delivers the customer's leads into another form's inbox.\n3. APPLY EVERY PENDING FIX, THEN RERUN. Each entry of \\`paths.pending\\` carries its reason\n (\\`IN_EXPRESSION\\`, \\`AMBIGUOUS_LITERAL\\`, \\`REPEATER_FIXED_LENGTH\\`, \\`PARSE_ERROR\\`, …) and,\n where the codemod could work one out, a \\`fix\\`: \\`{ action, file, line, col?, snippet, why? }\\`.\n Go to \\`file\\`:\\`line\\` and do what \\`action\\` says — \\`wrap-span\\` (wrap the literal in\n \\`<span data-bcms-field=\"…\">\\`), \\`declare-attr\\` (add \\`data-bcms-field=\"…\"\\` to that element),\n \\`bind-expression\\` (replace the expression with the framework's bcmsField helper),\n \\`declare-richtext\\` (bind the container with the richtext helper), \\`bind-data\\` (bind the field\n in the data file or collection entry it names) or \\`manual\\` (do what its \\`why\\` says). A row\n with no \\`fix\\` is still yours. Then RERUN step 2 and repeat until \\`paths.pending\\` is empty —\n the codemod is idempotent, so a second run over converted source rewrites nothing.\n3b. THE SITE'S DESIGN IS NOT YOURS TO CHANGE. The \\`--verify-styles\\` pass of the same codemod\n (\\`--root .\\`, with \\`--base\\` set to the last commit before you started converting) lists every\n \\`class\\`, \\`className\\` and \\`style\\` the conversion altered as \\`styleEdits\\`; they travel\n inside the receipt, and a non-empty list is refused with 409 \\`style-edits\\` naming every\n token. Restore them in the source, rerun, resubmit.\n4. \\`submit_conversion_receipt { briefDigest, receipt }\\` with the receipt file, verbatim. It\n answers \\`complete\\`, \\`pendingTotal\\` and the first 40 pending rows with their \\`fix\\`. \\`complete: true\\` — nothing\n pending — is the ONLY receipt that ends a conversion; on anything less go back to step 3. It\n is also what lets the coverage meter say WHY a path is undeclared instead of only that it is.\n It records and releases nothing.\n5. Push, or \\`deploy_project\\`. A PLAIN HTML repo — no \\`package.json\\` — deploys by PUSH ONLY:\n \\`deploy_project\\` refuses such an archive by design, so pushing is the whole lane. Either way,\n poll \\`get_deploy_status\\` until \\`slot\\` is \\`current\\` (or \\`awaitingPromote\\` is false) before you\n read the report in step 6 — a report read against the previous release is the previous\n release's verdict.\n6. \\`get_binding_report\\`. Alongside \\`unmatched\\` it now carries \\`coverage\\` — \\`declared\\` (what the\n brief listed), \\`bound\\` (what the build declares) and \\`pending\\` with the reasons. It must read\n \\`unmatched\\` 0 and \\`unaddressable\\` under 2% of each route's visible text (§11). Fix what it\n names IN THE SOURCE and release again until \\`coverage.pending\\` is empty.\n7. \\`set_binding_mode { declaredBindings: true }\\` and release ONE MORE TIME — the mode applies to\n the next release, not to the one already out. (editor_setup sets it itself when the build\n already declares every binding; skip this step when get_binding_report reads \\`declared\\`.)\n\n**Or let BetterCMS propose the edit.** \\`get_conversion_plan\\` returns an APPROVED conversion — the\nexact new contents of each template file, reviewed by a human in the dashboard and already checked\nagainst this project's real field paths. When there is one, apply it instead of Recipe A's step 2\n(the codemod): check out its \\`baseHeadOid\\`, branch from there, write each file's \\`content\\`\nverbatim, and carry on from Recipe A's step 5. A 404 with \\`code: \"no-approved-plan\"\\` means nobody approved one, so the\nconversion is yours to write.\n\n**Recipe B — not in the CMS yet: the steps.**\n\n1. \\`pull_project_source\\` (or clone the \\`github\\` remote it returns — \\`cloneUrl\\` on the \\`branch\\`\n it names, which is the branch the provisioned Action builds). Read the SOURCE. Never\n reconstruct content from the deployed HTML — that is how a site ends up bound to a copy of\n its own stale build.\n2. Decide the architecture WITH the human (§10) and record it: \\`set_authoring_preference\\`.\n3. Register the schema. Per route: \\`create_page\\` + \\`add_field\\` { pageId } (text / longtext /\n richtext / image / array groups). Per repeated content type: \\`create_content_model\\`, with a\n \\`document\\` body for articles. Site chrome goes through \\`update_layout\\`; images through\n \\`create_media_upload\\` / \\`upload_asset\\`, then reference the CMS URL. The repo-owned\n alternative to calling these one by one is a committed \\`bcms-content.json\\` carrying a\n \\`schema\\` block, which seeds models, pages and entries at connect time — the \\`defineType\\`\n analogue.\n4. Seed the entries with the copy EXACTLY as the source renders it (\\`set_page_content\\`,\n \\`create_content_entry\\`). Prose goes in as Portable Text arrays (\\`_type: \"block\"\\`); never\n markup inside a \\`text\\` field.\n **Prose MIGRATED from another CMS needs one extra check.** Every block's \\`_type\\` must be one\n this platform stores — \\`block\\`, \\`table\\` (\\`{_type:\"table\", rows:[{_key, cells:[{_key,\n content:[...blocks], header?, group?, highlight?, sortable?, note?, column?: {type?: \"text\"|\"number\"|\"money\"|\"boolean\"|\"rating\"|\"link\", unit?, currency?, decimals?, align?, trueLabel?, falseLabel?, max?, description?} (first row only), type?, value?: number|boolean (content keeps its words)}], group?, footer?, highlight?, type?}], caption?, notes?, rowGroups?, columnGroups?, filterable?, jsonLd?: {type: \"ItemList\"|\"Dataset\"|\"Offers\", axis?, priceRow?}, design?: {responsive?: \"stack\"|\"cards\", sticky?}, footnotes?: [{_key, text}]}\\`,\n groups \\`[{_key, label}]\\`; Sanity's row of plain strings, \\`rows:[{cells:[\"a\",\"b\"]}]\\`,\n is admitted too), \\`bcmsCode\\`, \\`bcmsDivider\\`, \\`bcmsMention\\`, \\`pullQuote\\`\n (\\`{quote, name, role?, link?}\\`), \\`keyTakeaways\\` (\\`{title?, points:[...strings]}\\`,\n title at most 40 characters, at most 8 points), or \\`bcmsBlock\\` carrying a\n \\`schemaKey\\` — and a foreign node (a Sanity image, \\`{_type:\"image\", asset:{_ref}}\\`, for one)\n is not merely unrendered: it has no component here, so it\n vanishes from the HTML every delivery surface reads while the stored value still looks whole.\n Verify each \\`_type\\` against the schema before you write, not after.\n5. Codemod the templates. Read each value from the CMS (\\`@bettercms-ai/astro\\` /\n \\`@bettercms-ai/next\\` client, or the \\`bcms-content.json\\` build snapshot), KEEP the in-code\n copy as the fallback, and declare the binding on the element that already renders it.\n Read the snapshot ONLY through a supported reader: the helper \\`npx @bettercms-ai/convert\\`\n writes (\\`bcms\\`, \\`bcmsRows\\`, \\`bcmsImage\\`) or \\`publishedEntry(slug)\\` from\n \\`@bettercms-ai/sdk\\`. Never hand-write a parser of the file: a row holds its values under\n \\`data\\`, so \\`row.title\\` is undefined and the page renders its fallback on every publish. An\n editable image is \\`bcmsImage(page, path, importedImage)\\`, never the bare import with a stamp.\n Prefer schema-derived bindings — the TypeGen analogue:\n \\`npx @bettercms-ai/codegen --bindings-out src/bettercms.bindings.generated.ts\\`, then spread\n \\`{...bcms.home.hero.title}\\` / \\`{...bcms.blog.features.$(i)}\\`. The hand form is\n \\`data-bcms-field=\"<path>\"\\` (plus \\`data-bcms-kind=\"richtext\"|\"image\"\\`), the §11 layout markers\n for nav and footer, and \\`<div data-bcms-field=\"body\" data-bcms-kind=\"document\">\\` around a\n Portable Text render, whose per-block elements carry their own \\`data-bcms-kind=\"richtext\"\\`.\n **A value that lives in an ATTRIBUTE — an \\`href\\`, an \\`alt\\`, an \\`src\\` — rides\n \\`data-bcms-props\\`, and its grammar is PIPES, NOT JSON:**\n \\`data-bcms-props=\"<path>|<kind>|<domAttribute>\"\\`, semicolon-separated for several on one\n element, where \\`kind\\` is \\`text | richtext | image | url | number | array\\`. A link is\n \\`data-bcms-props=\"cta.url|url|href\"\\`; an image's alt text is\n \\`data-bcms-props=\"hero.image.alt|text|alt\"\\`; an \\`<a>\\` wrapping an \\`<img>\\` carries both as\n \\`data-bcms-props=\"cta.url|url|href;hero.image.alt|text|alt\"\\`. A JSON object there parses to\n NOTHING — the reader splits on \\`;\\` and \\`|\\` and drops what does not match — so the value stays\n uneditable and the binding report never mentions it. The SDK helpers\n (\\`@bettercms-ai/astro\\`, \\`@bettercms-ai/next\\`) and \\`@bettercms-ai/codegen\\` emit this form\n for you; write it by hand only when you are not using them.\n Bind CONDITIONALLY (\\`fromCms ? path : undefined\\`) so a fallback row is never bound. A value\n rendered in N places carries the binding on ALL N — the editor keeps the copies in sync.\n **Read the LIVE SCHEMA before you bind — \\`get_page\\` / \\`get_content_model\\`, never the\n delivery snapshot.** A field nobody has authored yet is simply ABSENT from the payload, so a\n snapshot cannot tell \"this field does not exist\" from \"this field is empty\": bind against it\n and you declare a path for a \\`cover\\` field that was never created, which the report then\n reports as broken forever. The schema is the list of what exists; the snapshot is only what\n currently has a value.\n **An index or listing route binds NOTHING.** The editor loads ONE entry per route, and an\n index renders many, so a binding there addresses whichever entry the editor happened to\n load. Bind each item's fields on that item's OWN route (\\`/blog/<slug>\\`); on the index,\n render from the CMS and declare nothing.\n5b. **Where the content comes from at build time.** Two lanes, and they differ:\n - GIT-CONNECTED (recommended for a converted site): the platform's build writes\n \\`bcms-content.json\\` into the repo root before \\`build\\`, with a key it mints per build: no\n repo secret feeds it. (The secret a connect sets, \\`BCMS_API_KEY_<RUNG>\\` such as\n \\`BCMS_API_KEY_PROD\\`, is the validation workflows' key; they fall back to the shared\n \\`BCMS_API_KEY\\` only for a repo whose last connect predates it.) Read that file (step 5's readers), with in-code\n fallbacks so a local or CI build without it still renders.\n - ARCHIVE (\\`deploy_project\\`, inline or by \\`uploadKey\\`): the sandbox build runs with no env\n and no network content step, by design. So the archive MUST SHIP its own\n \\`bcms-content.json\\` — generate it locally with a delivery key and commit it. Without\n one the site renders its fallbacks and the report says \\`no-element\\` for every path.\n5c. **Live preview lane.** Static HTML makes a page click-to-edit; it cannot show a STRUCTURAL\n draft — a new section, a reorder, a changed component — so those fall back to the platform\n renderer's generic theme unless the build can render drafts itself. Give it a lane:\n - NEXT: wrap the page's \\`BcmsBlocks\\` in \\`BcmsDraftBridge\\` from\n \\`@bettercms-ai/next/draft-bridge\\` and redeploy. The bridge marks its output\n \\`data-bcms-canvas=\"bridge\"\\`, which is what the release scan records.\n - ASTRO: switch the pages to \\`output: 'server'\\` with \\`@astrojs/node\\` in\n \\`mode: 'standalone'\\` — the \\`bettercms()\\` integration already injects the draft routes,\n do not write them by hand — render pages from \\`loadPage\\` + \\`loadComponents\\`, mount\n \\`<BcmsLive>\\`, set \\`BCMS_DRAFT_SECRET\\` (BetterCMS hosting sets it for you), redeploy,\n then switch the project to \"Run as a server app\" on the Hosting page. Never migrate a\n static site to SSR without asking the human first.\n Then \\`get_binding_report.canvas.lane\\` reads \\`bridge\\` or \\`draft-route\\` instead of \\`none\\`.\n6. Push, or \\`deploy_project\\`. A PLAIN HTML repo — no \\`package.json\\` — deploys by PUSH ONLY:\n \\`deploy_project\\` refuses such an archive by design. Poll \\`get_deploy_status\\` until \\`slot\\` is\n \\`current\\` (or \\`awaitingPromote\\` is false). Then\n \\`get_binding_report\\` — still \\`text-match\\`, and \\`unmatched\\` should be EMPTY because the\n values are byte-equal to what the build renders. On a converted site read \\`coverage\\` too: it\n counts the PINNED brief's paths, which \\`unmatched\\` cannot, because \\`unmatched\\` only ever\n speaks about fields that already hold a value. Now \\`set_binding_mode\n {declaredBindings: true}\\` and release again (an empty commit is enough). Do not flip before\n the report is clean: in declared mode an undeclared field simply stops being editable.\n7. **Receipts.** \\`get_binding_report\\` reads \\`mode: \"declared\"\\`, \\`unmatched: []\\`,\n \\`bound > 0\\`, and — for a site converted against a pinned brief — \\`coverage.pending: []\\`. That certifies one thing only — that every non-empty field has SOME element\n carrying its path. It CANNOT see copy that was never modelled, so diff each route's visible\n text against its entry values yourself before you call the page done. Then publish, and\n fetch the live URL cache-busted (RECEIPTS in §11: publish and deploy are separate claims).\n \\`get_next_steps\\` keeps reporting the gap until every one of these holds.\n\n**The finish line is \\`receipt.complete\\`.** \\`get_next_steps\\` answers it from the setup gate\n(\\`receipt.gate\\`): every route of the live build has a published page (or entry), one page only,\nat most 2% of its visible text unowned, every image a field's and 95% of its links. \\`blocking\\`\nlists what fails, worst route first, each with the \\`fix\\` call to run, and \\`nextAction\\` is the\none to run now (the fix that closes the most rows): run it, read again after each batch, repeat\nuntil \\`complete\\`. A null \\`fix\\` is the user's to decide. A gap left on purpose is RECORDED, \\`editor_setup { exempt: [{ route, check,\nreason, note }] }\\`, with a reason \\`allowedExceptions\\` lists for that check. Running out of time,\ncontext or patience is in \\`neverExceptions\\`: it is refused, and telling the user why instead\nleaves the gate incomplete. \\`bettercms init\\` reads the same gate when you exit and prints it.\n\n**Done means.** Whichever recipe you ran: \\`get_binding_report\\` reads \\`mode \"declared\"\\`,\n\\`unmatched\\` empty, \\`bound\\` above 0, \\`coverage.pending\\` empty, and \\`canvas.lane\\` is \\`bridge\\` or\n\\`draft-route\\` when the site should show structural drafts.\n\n## 14. Declare how a field LOOKS in the editor — \\`ui\\`, \\`helpText\\`, \\`showIf\\`\n\nYou can create the schema. You can also say how it PRESENTS to the person filling it in. These\nthree props ride on any field, on any field-creating tool (\\`create_content_model\\`,\n\\`create_page\\`, \\`add_field\\`), and none of them can move, reshape or hide a\ndelivered value — they change editor chrome only.\n\n\\`\\`\\`jsonc\n{ \"key\": \"testimonials\", \"label\": \"Testimonials\", \"type\": \"repeater\",\n \"ui\": { \"collapsed\": true, \"preview\": { \"title\": \"author\", \"media\": \"avatar\" },\n \"layout\": \"grid\", \"icon\": \"double-quote\", \"itemLabel\": \"Testimonial\" },\n \"helpText\": \"Three to five.\",\n \"fields\": [ { \"key\": \"author\", ... }, { \"key\": \"avatar\", \"type\": \"image\", ... }, ... ] }\n\\`\\`\\`\n\n- **\\`helpText\\`** — the exception: most fields get none. Write it only when the author needs it to\n type the right value: a format or unit (\"Price in cents.\"), a placement the canvas cannot show, a\n real constraint, a fallback. One plain sentence under 90 characters, no semicolons, no dashes, no values copied from the page. Never restate the label (\"The title field\"), never coach (\"Keep it short\").\n- **\\`showIf\\`** — hide a field until another has a value:\n \\`{match:'all',rules:[{field:'link_type',op:'eq',value:'external'}]}\\`. Rules name fields by\n BARE KEY, and the key namespace is FLAT across the model (§ the duplicate-key rule), so the\n key you reference must exist.\n- **\\`ui.collapsed\\`** — start a nesting field's panel closed. For long optional sections.\n- **\\`ui.preview\\`** — how ONE ITEM of a nesting field summarises itself when collapsed. Each\n slot (\\`title\\`, \\`subtitle\\`, \\`media\\`) names a **CHILD FIELD KEY of that field** — not a value, not a dotted path.\n Without it a repeater of ten testimonials reads \"Item 1 … Item 10\" and the author has to open\n each one to find the one they meant. \\`media\\` may point at an \\`image\\`, \\`file\\` or url-ish\n \\`text\\` child; the type is not constrained.\n- **\\`ui.layout\\`** — \\`'list'\\` (the default; omit it), \\`'grid'\\`, or \\`'table'\\`. Grid when the THUMBNAIL is\n what the author scans: a gallery, a logo wall, a team. Table when a repeatable row schema's\n fields are columns, such as pricing or comparison data. List when the words are.\n- **\\`ui.reorderable\\`** — omit it (≡ \\`true\\`) unless the ORDER IS PART OF THE MEANING. \\`false\\`\n LOCKS the list so its items cannot be dragged: a \"three steps\" band that must stay three steps\n in that order, a nav whose order is semantic, a timeline. Locking a list nobody should reorder\n is the declaration there was previously no way to make; locking one out of tidiness takes a\n capability away from the author, so do not set it \"just in case\".\n- **\\`ui.control\\`** — which control a LEAF edits with; omit it for the default. \\`'segmented'\\` on a\n \\`select\\` with a few short options (alignment, theme, size: one click instead of a dropdown);\n \\`'slider'\\` on a \\`number\\` with \\`config.min\\` < \\`config.max\\` (opacity, columns). Anywhere else it\n is refused with the rule named.\n- **\\`ui.icon\\`** — the branch row's icon: ONE name from \\`bettercms://icons/dock\\` (read that resource;\n any other string is a 400). Nesting fields, fieldsets and a prop's \\`ui.group\\` only. Layout\n section icons are a different vocabulary (Lucide names), so a name valid there may be refused here.\n- **\\`ui.itemLabel\\`** — what ONE item of a list is called (\"Slide\", \"Person\"), at most 24 characters:\n the add button, the crumbs and the empty state say it. Nesting fields only.\n\n**Six refusals, all deliberate, all 400 with the fix in the message.**\n1. An unknown key inside \\`ui\\` is REJECTED, not stripped. \\`ui\\` is a strict object precisely so\n that a typo is a refusal you can read instead of a 200 with your declaration gone.\n2. \\`ui.preview\\` on a LEAF field is refused — it summarises an item, and a leaf has no items.\n Valid on \\`group\\`, \\`repeater\\`, an \\`array\\` with \\`config.zones\\`, or \\`modular\\`.\n3. \\`preview.title\\` / \\`preview.subtitle\\` / \\`preview.media\\` naming a key that is not a child of that field is refused,\n and the error lists the valid child keys.\n4. \\`ui.layout\\` follows the same rule as \\`preview\\`: nesting fields only. A leaf has no items\n to arrange.\n5. \\`ui.reorderable\\` is STRICTER — it needs a LIST, not merely children. Valid on \\`repeater\\`,\n an \\`array\\` with \\`config.zones.repeatable\\`, or \\`modular\\`. A \\`group\\` (and a non-repeatable\n zone) holds exactly ONE item, so there is nothing there to drag and the write is refused.\n6. \\`ui.control\\` outside its fit is refused: \\`segmented\\` needs a \\`select\\`, \\`slider\\` a \\`number\\`\n whose \\`config.min\\` and \\`config.max\\` are both set with min < max.\n\n**The same \\`ui\\` rides on COMPONENT PROPS.** \\`create_component\\` / \\`update_component\\` take it on\neach entry of \\`props\\`, with the placement rules the prop vocabulary implies: \\`preview\\` and\n\\`layout\\` on \\`group\\`, \\`table\\` and \\`slot\\`; \\`reorderable\\` on \\`table\\` ALONE, because a table is the\nonly prop whose value is a list (a \\`group\\` is one object, a \\`slot\\` one component instance). A\nprop's \\`preview\\` keys name a SUB-FIELD from its own \\`config.fields\\` and are checked against\nthem — except on a \\`slot\\`, whose children belong to whichever component fills it and therefore\ncannot be resolved at save time. \\`update_component\\` REPLACES the whole \\`props\\` array, so echo\nback each prop's stored \\`ui\\` or you delete it along with the prop. Props have no fieldsets, so a\nprop joins a group with \\`ui.group\\`: the FIRST prop of a group defines \\`{ id, label, kind?, icon?,\ncollapsed? }\\` (kind \\`group\\` or \\`row\\`; a tab is \\`ui.tab\\`, never a group kind), and every later prop\nsends \\`{ id }\\` only. A prop joins a TAB with \\`ui.tab\\` the same way: the FIRST top-level prop in a tab\ndefines \\`{ id, label, icon?, order? }\\`, later props send \\`{ id }\\`; at most 8 tabs, labels ≤40 characters\nand unique; top-level props only (never a sub-field); all members of one \\`ui.group\\` share one tab. A V2\nkit entry's schema \\`groups\\` and each field's \\`group\\` map 1:1 to \\`ui.tab\\`, so its \\`design\\` group is a\ntab named Design holding the theme, sticky and similar props. A FIELD never takes \\`ui.group\\` or\n\\`ui.tab\\`; it joins a fieldset with \\`fieldsetId\\`.\n\n\\`\\`\\`jsonc\n{ \"key\": \"slides\", \"label\": \"Slides\", \"type\": \"table\",\n \"target\": { \"blockId\": \"slider\", \"path\": \"props.slides\" },\n \"ui\": { \"preview\": { \"title\": \"caption\", \"media\": \"image\" }, \"layout\": \"grid\" },\n \"config\": { \"fields\": [ { \"key\": \"image\", \"type\": \"image\", ... },\n { \"key\": \"caption\", \"type\": \"text\", ... } ] } }\n\\`\\`\\`\n\n**Patterns — what the dock draws, and the key that asks for it.**\n- **leaf** — one field, one control. Nothing to declare; \\`ui.control\\` only when the default is wrong.\n- **group** — a \\`kind: 'group'\\` fieldset (a prop: \\`ui.group\\`): a disclosure that shows two values\n when closed. \\`collapsed: true\\` starts it closed.\n- **row** — a \\`kind: 'row'\\` fieldset: at most 3 short scalars (number, rating, color, boolean, date,\n datetime, select) on one line. No \\`ui.control\\` on a row member.\n- **branch** — a nesting field drawn as a drill-in row with its \\`ui.icon\\` and a summary.\n- **list** — repeatable items named by \\`ui.itemLabel\\` and \\`ui.preview\\`.\n- **grid** — \\`layout: 'grid'\\`, media-led: the field needs an image or file child for \\`preview.media\\`.\n- **table** — \\`layout: 'table'\\`: at most 3 scalar columns (text, number, select, boolean, date,\n datetime, slug, email).\n- **section header** — a fieldset's \\`name\\` and \\`description\\` over its fields.\n- **conditional** — \\`showIf\\`, placed AFTER the field it reads.\n\n**Budgets, per dock screen.** \\`get_next_steps\\` measures them (\\`dock-budget\\`):\n- at most **8 ungrouped leaves** at rest (the pinned fields plus any one tab);\n- at most **12 leaves in a group**, and branches at most **3 levels** deep;\n- **any value within 2 activations** of its section screen. A collapsed group, a non-first tab and a\n branch each cost 1, so a group inside tab 2 already costs 2: leave groups in non-first tabs open.\nImportance orders a screen: required fields first, then array order.\n\n**Recipes — named key presets, never code.** Pick the one the section is; adapt the child keys.\n\n| Recipe | Keys |\n|---|---|\n| Gallery | \\`layout:'grid'\\`, \\`preview:{media:'image', title:'caption'}\\`, \\`itemLabel:'Image'\\`, \\`icon:'images'\\` |\n| Logo wall | \\`layout:'grid'\\`, \\`preview:{media:'logo', title:'name'}\\`, \\`itemLabel:'Logo'\\`, \\`icon:'image'\\` |\n| Team | \\`layout:'grid'\\`, \\`preview:{media:'photo', title:'name', subtitle:'role'}\\`, \\`itemLabel:'Person'\\`, \\`icon:'users'\\` |\n| Testimonials | \\`preview:{title:'author', subtitle:'role', media:'avatar'}\\`, \\`itemLabel:'Testimonial'\\`, \\`icon:'double-quote'\\` |\n| Steps | \\`preview:{title:'title'}\\`, \\`itemLabel:'Step'\\`, \\`icon:'olist'\\`; \\`reorderable:false\\` only on Tier-1 evidence |\n| Pricing tiers | \\`preview:{title:'name', subtitle:'price'}\\`, \\`itemLabel:'Tier'\\`, \\`icon:'tiers'\\` |\n| FAQ | \\`preview:{title:'question'}\\`, \\`itemLabel:'Question'\\`, \\`icon:'help-circle'\\` |\n| Nav links | \\`preview:{title:'label', subtitle:'href'}\\`, \\`itemLabel:'Link'\\`, \\`icon:'link'\\` (never a table: a label and its href are one link) |\n| Stats | \\`layout:'table'\\` over ≤3 scalar columns (value, label, suffix), \\`itemLabel:'Stat'\\`, \\`icon:'bar-chart'\\` |\n| CTA | one \\`kind:'group'\\` fieldset holding the heading, text and ONE \\`button\\` field, \\`icon:'launch'\\` |\n| Dimensions | one \\`kind:'row'\\` fieldset of up to 3 numbers (width, height, gap) |\n\n**The V2 schema language — to get X in the editor, write Y.** Every key below is editor-only and stored as sent, EXCEPT \\`type: 'object'\\`: it changes the stored and delivered value to \\`{ [childKey]: value }\\` (a \\`group\\` carries \\`<key>.nonRepeatable.<sub>\\` instead), and codegen types it as a nested object, so swapping group ↔ object moves values and templates.\n\n| To get this in the editor | Write this |\n|---|---|\n| A section that starts closed / a static heading | fieldset \\`collapsed: true\\` / \\`collapsible: false\\` |\n| Two short fields side by side | fieldset \\`columns: 2\\` |\n| One Desktop · Tablet · Phone switcher | three \\`type: 'object'\\` fields named \\`desktop\\`, \\`tablet\\`, \\`phone\\`, each with \\`fieldsetId\\` pointing at ONE fieldset with \\`layout: 'breakpoints'\\` |\n| A small inset of 2–3 fields, or a row that opens its own screen | \\`type: 'object'\\` with \\`fields\\`; \\`openMode: 'inline', 'drill', 'popover', 'dialog'\\` |\n| List rows that drill in instead of expanding | \\`openMode: 'drill'\\` on the array (or repeater) |\n| Tiles instead of rows | \\`ui.layout: 'grid'\\` on a list of objects (V2 \\`arrayLayout: 'grid'\\`); a primitive image array takes \\`'gallery'\\` |\n| BetterCMS-only list layouts | \\`ui.layout: 'rows'\\` (≡ 'list'), \\`'chips'\\`, \\`'gallery'\\`, also on a primitive array. Never chips for a feature list: chips cut long lines |\n| A size capsule with numeric steps | \\`type: 'number'\\`, \\`config.scale: { steps: {min, max, step} or [{value, label}], units?, presets? }\\`. Token (string) steps and an \\`allowCustom\\` object are refused (\\`scale_invalid\\`): use numeric steps and \\`allowCustom: true\\` |\n| Help under the label / longer help behind ⓘ | \\`helpText\\` / \\`helpMore\\` |\n| Calm defaults for rare settings | \\`advanced: true\\` |\n| A soft length warning (amber, never a refusal) | \\`recommendedMax: 60\\` |\n| A marketer cannot change it | \\`readOnly: 'developer'\\` plus \\`lockReason\\` |\n| A field that shows only sometimes | \\`showIf\\` (it SHOWS the field): ops \\`eq\\`, \\`neq\\`, \\`in\\`, \\`notIn\\`, \\`gt\\`, \\`lt\\` (one number as a string), \\`isSet\\`, \\`notEmpty\\`, \\`empty\\` |\n| A good row title and thumbnail | \\`ui.preview: { title, subtitle, media, fallback }\\` (\\`fallback\\` is a literal label) |\n| Labels that classify or filter (topics, keywords), never a feature list | \\`type: 'tags'\\`: a string[], trimmed, de-duplicated, each ≤64 characters; \\`config.options\\` are suggestions, \\`config.max\\`, \\`config.allowCustom: false\\` closes the list (\\`tags_value_invalid\\`) |\n| A star rating | \\`type: 'rating'\\`: a number from 0 to \\`config.max\\` (5), \\`config.step\\` 1 or 0.5 (\\`rating_value_invalid\\`) |\n| A code snippet | \\`type: 'code'\\`: \\`{ language?, code }\\` or a string; \\`config.language\\` default, \\`config.languages\\` allowlist (\\`code_value_invalid\\`) |\n| \"Add question\" instead of \"Add item\" | \\`ui.itemLabel: 'Question'\\` (V2 \\`itemNoun\\`; there is no itemNoun key) |\n| The same section as a component (the dock edits a page section through its props) | the same keys on its \\`props\\`: \\`type: 'object'\\` with \\`config.fields\\` (\\`group\\` and \\`table\\` too, 10 levels), \\`datetime\\`, \\`slug\\`, \\`email\\`, \\`phone\\`, \\`json\\`, \\`location\\`, \\`tags\\`, \\`rating\\`, \\`code\\`, plus the two CMS-item types (\\`reference\\`, \\`multi-reference\\`: \\`config.contentModelId\\` or \\`polymorphic\\` + \\`allowedModelSlugs\\`; page reads hydrate them, a text slot shows the title), and every key above except fieldsets (props group with \\`ui.group\\` and tab with \\`ui.tab\\`) |\n\nAn 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.\n\n**Tabs.** A \\`kind: 'tab'\\` fieldset is a tab:\n- at most **3** tabs, names at most 40 characters and unique;\n- top-level fields only: tabs never nest (a component's props take tabs through \\`ui.tab\\`, its own rules);\n- untabbed fields stay PINNED above the strip;\n- a group or row fieldset joins a tab with \\`tab: '<tab id>'\\`; groups in a non-first tab default open;\n- with fewer than 2 non-empty tabs no strip renders, so a tab for one fieldset is noise.\n\n\\`\\`\\`jsonc\n\"fieldsets\": [\n { \"id\": \"content\", \"name\": \"Content\", \"kind\": \"tab\" },\n { \"id\": \"style\", \"name\": \"Style\", \"kind\": \"tab\" },\n { \"id\": \"cta\", \"name\": \"Button\", \"kind\": \"group\", \"tab\": \"content\", \"icon\": \"launch\" },\n { \"id\": \"size\", \"name\": \"Size\", \"kind\": \"row\", \"tab\": \"style\" }\n]\n\\`\\`\\`\n\n**The write path — existing fields, by path, with If-Match.**\n- A model's fields: \\`update_content_model\\` with \\`fieldUi\\`, \\`fieldFieldset\\`, \\`fieldOrder\\`,\n \\`fieldLabel\\`, \\`fieldHelpText\\` (keyed by dotted key path, \\`'hero.title'\\`) and \\`fieldsets\\`. A page's\n schema: the same call with \\`pageId\\` instead of \\`modelId\\`, and the version from \\`get_page\\`'s\n \\`backingModel\\`.\n- A component's props: \\`update_component\\` with \\`propUi\\`, \\`propGroup\\`, \\`propTab\\`, \\`propLabel\\`, \\`propHelpText\\` (keyed by prop key).\n Name props from the code (\\`plan.cents\\` → Cents); help text only where a format, a hidden placement, a constraint or a fallback needs it (\"Whole number, no currency symbol.\"), one plain sentence under 90 characters with no semicolons or dashes, never repeating\n the value; repeated cards are one \\`table\\` prop. An icon (\\`config.media: \"icon\"\\`) is content: group it, never prune it.\n They write the DRAFT props; no publish is needed for the editor to show them.\n- Always send \\`ifMatch\\`, the \\`optimisticVersion\\` you read.\n- A NEW field carries its chrome in the same \\`add_field\\` call.\n\n**The dock's refusals, each named in the message.**\n- **428** \\`precondition-required\\` — a chrome key without \\`ifMatch\\`. Read, then send it.\n- **409** \\`version-conflict\\` — someone wrote since your read. Read again, re-apply; never retry blindly.\n- **409** \\`ui_human_owned\\` — a person shaped those paths. Leave them, or send \\`override: true\\`, and\n only when the user said so.\n- \\`tab_unknown\\`, \\`tab_nested\\`, \\`tab_props\\`, \\`tab_max\\`, \\`tab_name\\`, \\`tab_depth\\` — the tab rules above.\n- \\`prop_tab_unknown\\`, \\`prop_tab_redefined\\`, \\`prop_group_split_tabs\\` — a prop's \\`ui.tab\\` rules (\\`tab_max\\`,\n \\`tab_name\\` and \\`tab_nested\\` too); \\`tab_props\\` is a \\`ui.group\\` with \\`kind: 'tab'\\` — use \\`ui.tab\\`.\n- \\`fieldset_unknown\\` / \\`fieldset_orphan\\` — a \\`fieldsetId\\` naming no fieldset, or a list that drops a\n fieldset its fields still name.\n- \\`row_member_type\\`, \\`row_member_count\\`, \\`row_member_control\\` — the row rule.\n- \\`pair_split\\` — a legacy button's label and href in different fieldsets.\n- \\`cta_pair\\` — a NEW text field beside a link keyed like it plus \\`-href\\` (\\`hero-span-go\\` + \\`hero-a-go-href\\`): one\n call to action. Add ONE \\`type: \"button\"\\` field (value \\`{ label, href }\\`); on a component, point both props\n at one button block. A pair a page ALREADY holds (\\`primaryCtaText\\` + \\`primaryCtaHref\\`) is never refused:\n turn it into one button with \\`update_field { pageId, path: <label key>, mergeHref: <link key> }\\` —\n drafts only, the old values stay, the live copy changes on publish.\n- \\`ui.icon\\` or \\`ui.itemLabel\\` on a leaf; an icon name not in \\`bettercms://icons/dock\\`.\n- \\`layout_grid\\` — a grid with no image or file child. \\`layout_table\\` — more than 3 columns, or a\n column that is not a scalar.\n- \\`prop_group_unknown\\` / \\`prop_group_redefined\\` — the \\`ui.group\\` define-once rule.\n- \\`field_path_unknown\\` / \\`field_path_ambiguous\\` / \\`field_order_not_permutation\\` — a path that names\n no field or two, or an order that is not exactly the parent's keys.\n\n**THE RECEIPT — read it back.** There is no separate verification tool and no mode to flip.\n\\`get_content_model\\` (and \\`get_page\\` / \\`get_component\\`) return each field's — and each component\nprop's — stored \\`ui\\`, \\`helpText\\` and \\`showIf\\`. A prop that is ABSENT from that response was not\nstored, whatever the write returned — §11 RECEIPTS rule 3, applied to this feature. For a page, read\n\\`get_page\\` and its \\`backingModel\\`. Then call \\`get_next_steps\\`: \\`dock-budget\\`, \\`dock-repeater-unnamed\\`\nand \\`dock-showif-order\\` must all be gone. Declare, then read back, then say it works.\n\n**No \\`order\\` property. Ever.** A field's order IS its index in \\`fields\\`. To put a new field\nsomewhere other than the end, pass \\`after: '<existing top-level field key>'\\` to \\`add_field\\`;\nomit it and the field appends, exactly as before. \\`after\\` is an argument\napplied once at the write — a stored ordering prop would be a second source of truth that\ndisagrees with the array the moment anyone drags a row in the builder.\n\n**Where the values come from — three tiers, in order. Stop at the first that answers.**\n\n TIER 1 DERIVE FROM THE SITE'S SOURCE, when you have a checkout.\n <img src={item.image}> + <h3>{item.name}</h3> inside the map over \\`team\\`\n → ui.preview = { title: 'name', media: 'image' }\n A section rendered inside a <details> or behind a \"Show advanced\" toggle\n → ui.collapsed: true\n grid-cols-* / display:grid on the wrapper of the .map → ui.layout: 'grid'\n A FIXED-ARITY render — steps[0]/steps[1]/steps[2], or copy that names the\n positions (\"Step 1\", \"then\", \"finally\") → ui.reorderable: false\n A prop read only when another is set → showIf\n 🔴 THE SERVER NEVER READS YOUR SOURCE on the add_field path. \\`pull_project_source\\`\n and \\`get_conversion_brief\\` hand YOU the repo; this tier is work you do in your own\n checkout before you call the tool. On a greenfield, schema-first project there is\n no source at all — Tier 1 is vacuous and TIER 2 IS THE FLOOR.\n\n TIER 2 DERIVE FROM THE FIELD SHAPE, when the code is silent.\n A repeater whose children include exactly one image-ish child → that is \\`media\\`.\n Its first required short-text child (name/title/heading/label) → that is \\`title\\`.\n A nesting field with more than ~6 children, or one whose label reads as optional\n (\"Advanced\", \"Extras\", \"SEO overrides\") → \\`collapsed: true\\`.\n A repeatable whose item is MOSTLY its image (gallery, logos, team) → \\`layout:\n 'grid'\\`; anything whose words are the point stays 'list' — so OMIT \\`layout\\`.\n \\`reorderable\\` HAS NO TIER-2 GUESS. The default (true) is the safe one, and\n locking a list the user did not ask to lock takes a capability away from them.\n Leave it absent unless Tier 1 showed you a fixed arity or the user said so.\n Guessing here is CORRECT. A wrong preview costs one edit; asking about every\n repeater on a 40-field schema costs the user the session.\n\n TIER 3 ASK THE USER — only when 1 and 2 are both silent, and only for these three:\n a) MANY fields in one panel, where the grouping and the order depend on which\n content the user considers primary. You cannot know their priorities.\n b) CONDITIONAL VISIBILITY (\\`showIf\\`). It encodes business logic — when a field is\n irrelevant — and nothing in the code or the shape tells you that.\n c) VARIANTS SHARING A \\`sectionType\\`. Their prop keys MUST match (§4), so a preview\n or a rename that diverges between two variants makes a layout swap lose content.\n Confirm the shared key set before you declare per-variant chrome.\n Ask with AskUserQuestion, batched, once — never one field at a time.\n`;\n","/**\n * The `bettercms` skill, served as MCP resources: `bettercms://skill/bettercms` for SKILL.md and\n * `bettercms://skill/<stem>` for each `references/<stem>.md`.\n *\n * A skill is loaded only by a client that has it installed. The same references as resources\n * reach every client — fetched on demand, never in tools/list, never truncated — so an agent\n * without the skill can still read the one reference its task needs.\n *\n * One loader for both surfaces, reading markdown from disk:\n * - the hosted connector runs from source, where this file sits at packages/mcp/src and the\n * skill at packages/skills/bettercms (the runtime image copies the whole packages/ tree);\n * - the npm package ships a copy at dist/skills/bettercms, made by tsup's onSuccess, because\n * node_modules/@bettercms-ai/mcp has no sibling skills package.\n * The first of those that holds a SKILL.md wins. None found = no skill resources, never a crash:\n * a server that cannot serve a reference must still serve its tools.\n */\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const SKILL_URI_PREFIX = \"bettercms://skill/\";\n/** The core skill's own name: SKILL.md is served at bettercms://skill/bettercms. */\nexport const CORE_SKILL = \"bettercms\";\n\nexport interface SkillDoc {\n uri: string;\n name: string;\n title: string;\n description?: string;\n mimeType: \"text/markdown\";\n text: string;\n}\n\n/** Where the skill lives, in the order a build or a checkout would put it. */\nconst CANDIDATES = [\"./skills/bettercms/\", \"../../skills/bettercms/\"];\n\nexport function defaultSkillDir(): string | null {\n for (const rel of CANDIDATES) {\n const dir = fileURLToPath(new URL(rel, import.meta.url));\n if (existsSync(join(dir, \"SKILL.md\"))) return dir;\n }\n return null;\n}\n\n/** `title` / `description` from a leading YAML frontmatter block: plain, quoted or folded scalars. */\nexport function frontmatterOf(text: string): Record<string, string> {\n const m = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n/.exec(text);\n if (!m) return {};\n const out: Record<string, string> = {};\n const lines = m[1]!.split(/\\r?\\n/);\n for (let i = 0; i < lines.length; i++) {\n const kv = /^([A-Za-z_][\\w-]*):\\s*(.*)$/.exec(lines[i]!);\n if (!kv) continue;\n let value = kv[2]!.trim();\n if (value === \">\" || value === \"|\" || value === \">-\" || value === \"|-\") {\n const block: string[] = [];\n while (i + 1 < lines.length && /^\\s+\\S/.test(lines[i + 1]!)) block.push(lines[++i]!.trim());\n value = block.join(value.startsWith(\">\") ? \" \" : \"\\n\");\n } else if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1).replace(/\\\\\"/g, '\"');\n }\n if (value) out[kv[1]!] = value;\n }\n return out;\n}\n\n/** The resource for one markdown file: frontmatter `title`/`description`, else its first `# ` heading. */\nexport function skillDocOf(stem: string, text: string): SkillDoc {\n const fm = frontmatterOf(text);\n const heading = /^#\\s+(.+?)\\s*$/m.exec(text)?.[1];\n const title = fm.title ?? heading ?? stem;\n const description = fm.description ?? heading;\n return {\n uri: `${SKILL_URI_PREFIX}${stem}`,\n name: `skill-${stem}`,\n title,\n ...(description ? { description } : {}),\n mimeType: \"text/markdown\",\n text,\n };\n}\n\n/** SKILL.md first, then every reference by name. */\nexport function loadSkillDocs(dir: string | null = defaultSkillDir()): SkillDoc[] {\n if (!dir) return [];\n const docs = [skillDocOf(CORE_SKILL, readFileSync(join(dir, \"SKILL.md\"), \"utf8\"))];\n const refs = join(dir, \"references\");\n if (!existsSync(refs)) return docs;\n for (const file of readdirSync(refs).filter((f) => f.endsWith(\".md\")).sort()) {\n const stem = file.slice(0, -3);\n if (stem === CORE_SKILL) continue;\n docs.push(skillDocOf(stem, readFileSync(join(refs, file), \"utf8\")));\n }\n return docs;\n}\n","/**\n * The Kit Library catalogue as MCP resources: which schema and blocks a section needs, and when.\n *\n * bettercms://kit the index: categories, edge tags, one line per entry\n * bettercms://kit/<category> every entry's notes in that category (why, HTML signals, mcp, pitfalls)\n * bettercms://kit/entry/{id} one entry: its notes plus the create_component payload (props)\n *\n * Source: kit-catalog.json beside this file, GENERATED by the dashboard (scripts/kit-export.ts) from its\n * KIT_LIBRARY + EXAMPLES. Never edit it here; regenerate from the dashboard with\n * `bun run kit:export -- --backend <this checkout>`, which also rewrites references/kit-catalog.md\n * (scripts/kit-reference.ts). tsup copies the JSON to dist, so the stdio package and the hosted connector\n * (which runs from source) read the same file. A missing file means no kit resources, never a crash.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const KIT_URI = \"bettercms://kit\";\nexport const KIT_ENTRY_URI_PREFIX = \"bettercms://kit/entry/\";\nexport const KIT_ENTRY_URI_TEMPLATE = `${KIT_ENTRY_URI_PREFIX}{id}`;\n\nexport interface KitEntry {\n id: string;\n name: string;\n category: string;\n tags: string[];\n proves: string;\n why: string;\n htmlSignals: string[];\n mcp: string;\n pitfalls: string[];\n notCarried: string[];\n component: { props: unknown[] } & Record<string, unknown>;\n}\nexport interface KitCatalog {\n $comment: string;\n categories: { name: string; slug: string; entries: string[] }[];\n tags: { tag: string; label: string; hint: string; entries: string[] }[];\n entries: KitEntry[];\n}\nexport interface KitDoc {\n uri: string;\n name: string;\n title: string;\n description: string;\n mimeType: \"text/markdown\";\n text: string;\n}\n\nexport function loadKitCatalog(path = fileURLToPath(new URL(\"./kit-catalog.json\", import.meta.url))): KitCatalog | null {\n return existsSync(path) ? (JSON.parse(readFileSync(path, \"utf8\")) as KitCatalog) : null;\n}\n\nconst list = (xs: string[]) => xs.map((x) => `- ${x}`).join(\"\\n\");\n\n/** One entry's notes, as markdown (shared by the category resource, the entry resource and the skill reference). */\nexport function entryNotes(e: KitEntry, h = \"###\"): string {\n const out = [`${h} ${e.name} (\\`${e.id}\\`)`, \"\", `Tags: ${e.tags.join(\", \") || \"none\"}. Proves: ${e.proves}`];\n if (!e.why && !e.mcp) out.push(\"\", \"No model notes in the kit for this entry: read its props.\");\n if (e.why) out.push(\"\", `**Why this shape.** ${e.why}`);\n if (e.htmlSignals.length) out.push(\"\", \"**HTML signals.**\", list(e.htmlSignals));\n if (e.mcp) out.push(\"\", `**Do.** ${e.mcp}`);\n if (e.pitfalls.length) out.push(\"\", \"**Pitfalls.**\", list(e.pitfalls));\n if (e.notCarried.length) out.push(\"\", `Not carried by a stored component: ${e.notCarried.join(\", \")}.`);\n return out.join(\"\\n\");\n}\n\nexport function kitIndexText(k: KitCatalog): string {\n const byId = new Map(k.entries.map((e) => [e.id, e]));\n return [\n \"# BetterCMS kit catalogue\",\n \"\",\n `${k.entries.length} modelled website sections. Before designing a section, find the closest entry by its edge tag or category, read its notes and follow its mcp + pitfalls; its create_component props are at ${KIT_ENTRY_URI_TEMPLATE}.`,\n \"\",\n \"## Categories\",\n \"\",\n ...k.categories.map((c) => `- ${c.name} (${c.entries.length}): ${KIT_URI}/${c.slug}`),\n \"\",\n \"## Edge tags\",\n \"\",\n ...k.tags.map((t) => `- \\`${t.tag}\\` (${t.hint}): ${t.entries.join(\", \") || \"none\"}`),\n \"\",\n \"## Entries\",\n \"\",\n ...k.categories.flatMap((c) => [\n `### ${c.name}`,\n \"\",\n ...c.entries.map((id) => {\n const e = byId.get(id)!;\n return `- \\`${e.id}\\` ${e.name} [${e.tags.join(\", \")}]: ${e.proves}`;\n }),\n \"\",\n ]),\n ].join(\"\\n\");\n}\n\nexport function kitCategoryText(k: KitCatalog, slug: string): string {\n const c = k.categories.find((x) => x.slug === slug)!;\n const byId = new Map(k.entries.map((e) => [e.id, e]));\n return [\n `# Kit: ${c.name}`,\n \"\",\n `${c.entries.length} entries. Each one's create_component props: ${KIT_ENTRY_URI_TEMPLATE}. Index: ${KIT_URI}.`,\n \"\",\n ...c.entries.map((id) => entryNotes(byId.get(id)!, \"##\") + \"\\n\"),\n ].join(\"\\n\");\n}\n\nexport function kitEntryText(e: KitEntry): string {\n return [\n entryNotes(e, \"#\"),\n \"\",\n \"## create_component payload\",\n \"\",\n \"Props in the exact shape create_component accepts. Adapt keys and copy to the site; keep the types, `ui` and config.\",\n \"\",\n \"```json\",\n JSON.stringify(e.component, null, 1),\n \"```\",\n \"\",\n ].join(\"\\n\");\n}\n\nexport const KIT_REFERENCE_FILE = \"packages/skills/bettercms/references/kit-catalog.md\";\n\n/** references/kit-catalog.md: the same notes as the category resources, in one file. Generated, never hand-edited. */\nexport function kitReferenceText(k: KitCatalog): string {\n const byId = new Map(k.entries.map((e) => [e.id, e]));\n const anchor = (s: string) => s.toLowerCase().replace(/[^a-z0-9 -]/g, \"\").replace(/ /g, \"-\");\n return [\n \"---\",\n \"title: Kit catalogue\",\n `description: The ${k.entries.length} modelled website sections of the BetterCMS kit, by category and edge tag, with each one's model notes (why, HTML signals, mcp, pitfalls). Generated from the dashboard kit; do not edit.`,\n \"---\",\n \"\",\n \"# Kit catalogue\",\n \"\",\n `<!-- GENERATED by packages/mcp/scripts/kit-reference.ts from packages/mcp/src/kit-catalog.json. Regenerate from the dashboard: bun run kit:export -- --backend <backend checkout> -->`,\n \"\",\n `Find the closest entry by edge tag or category, then follow its **Do** and **Pitfalls**. Each entry's create_component props: ${KIT_ENTRY_URI_TEMPLATE} (MCP resource). Search this file for an id or a tag rather than reading it whole.`,\n \"\",\n \"## Contents\",\n \"\",\n \"- [Edge tags](#edge-tags)\",\n ...k.categories.map((c) => `- [${c.name}](#${anchor(c.name)})`),\n \"\",\n \"## Edge tags\",\n \"\",\n ...k.tags.map((t) => `- \\`${t.tag}\\` (${t.hint}): ${t.entries.join(\", \") || \"none\"}`),\n \"\",\n ...k.categories.flatMap((c) => [`## ${c.name}`, \"\", ...c.entries.map((id) => entryNotes(byId.get(id)!) + \"\\n\")]),\n ].join(\"\\n\");\n}\n\n/** The listed resources: the index, then one per category. Entries are read through the template. */\nexport function kitDocs(k: KitCatalog | null = loadKitCatalog()): KitDoc[] {\n if (!k) return [];\n const doc = (uri: string, name: string, title: string, description: string, text: string): KitDoc => ({ uri, name, title, description, mimeType: \"text/markdown\", text });\n return [\n doc(KIT_URI, \"kit\", \"BetterCMS kit catalogue\", \"Index of modelled website sections by category and edge tag: find the closest one before designing a section.\", kitIndexText(k)),\n ...k.categories.map((c) =>\n doc(`${KIT_URI}/${c.slug}`, `kit-${c.slug}`, `Kit: ${c.name}`, `Model notes for the ${c.entries.length} ${c.name} entries: why, HTML signals, mcp, pitfalls.`, kitCategoryText(k, c.slug)),\n ),\n ];\n}\n\n/** uri → text for every entry (bettercms://kit/entry/<id>). */\nexport function kitEntryTexts(k: KitCatalog | null = loadKitCatalog()): Record<string, string> {\n return k ? Object.fromEntries(k.entries.map((e) => [`${KIT_ENTRY_URI_PREFIX}${e.id}`, kitEntryText(e)])) : {};\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,iBAAAA,sBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,YAAY,gBAAgB,wBAAwB;;;ACH7D,SAAS,WAAW,wBAAwB;AAC5C,SAAS,iBAAiB;;;ACD1B,SAAS,yBAAyB;AAClC,SAAS,SAAS;;;ACqCX,IAAM,mBACX;AAiCK,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AACF;;;AClHO,IAAM,uBAA0C,OAAO,OAAO;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,0BAA+C,IAAI,IAAI,oBAAoB;;;ACn6DjF,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EA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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["fileURLToPath","list","text","s","input","res","list","z","z","text","existsSync","readFileSync","fileURLToPath","slug","text","text","DeviceAuthClient","loadConfig","fileURLToPath"]}
|