@bettercms-ai/mcp 0.56.4 → 0.57.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.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","../src/structure-playbook.ts","../src/prompts.ts","../src/playbook.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 } 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 { SKILLS_ROUTING_INSTRUCTION, STRUCTURE_DEFAULT_INSTRUCTION, STRUCTURE_PLAYBOOK, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.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\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 \"When the user asks to make a site or all of its pages editable, to convert it, or to 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 // 🔴 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 — create_components, 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 \"BetterCMS never executes a customer's Section renderer or app code. An ordinary MCP connection is not a push runner: explicitly poll list_section_validation_requests, claim one request at an exact git commit, run implementation and responsive checks inside the user's own repository and real app shell, then submit manifest + validation with that requestId and complete it—or truthfully fail it when implementation/evidence is missing. Never invent a manifest, a passing validation, or visual evidence; these tools cannot grant the separate human Visual Approval required for publication. \" +\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,\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, Other 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 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) =>\n BetterCMS.management({ apiKey, baseUrl: deps.managementBaseUrl, ...(project ? { project } : {}) }),\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 { LAYOUT_SECTION_ICON_SET } from \"@bettercms-ai/types\";\nimport { DeviceAuthPendingError } from \"@bettercms-ai/device-auth\";\nimport { STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.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): 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): 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 createClient: (apiKey: string, project?: 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 // 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]);\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, and underscores 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 }>;\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 /** 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\"; value: string | string[] }>;\n };\n /** Authoring chrome — how the field presents in the editor. @see backend baseField.ui */\n ui?: FieldUi;\n};\n\n/**\n * Shared by FIELDS and by component PROPS — one vocabulary, two lanes, so an agent that has\n * learned `ui` on a repeater already knows it on a `table` prop. @see backend fieldUiSchema.\n */\nexport type FieldUi = {\n collapsed?: boolean;\n preview?: { title?: string; media?: string };\n /** Absent ≡ \"list\". */\n layout?: \"list\" | \"grid\" | \"table\";\n /** Absent ≡ true. `false` locks the order of a list. */\n reorderable?: boolean;\n};\n\n/**\n * ONE `ui` vocabulary, TWO lanes — fields (`fieldShape.ui`) and component props\n * (`componentPropObject.ui`). The KEYS are identical on purpose: an agent that has learned `ui`\n * on a repeater already knows it on a `table` prop. WHERE each key is legal differs, because the\n * shapes do, so each use site carries its own outer `.describe()` naming its own rules — and the\n * server refuses the rest with a 400 that names the valid set.\n */\nconst uiObject = z.object({\n collapsed: z\n .boolean()\n .optional()\n .describe(\"start this panel collapsed. Use it for long optional sections.\"),\n preview: z\n .object({\n title: z.string().min(1).optional().describe(\"CHILD KEY whose value titles a collapsed row\"),\n media: z.string().min(1).optional().describe(\"CHILD KEY whose value is the row's thumbnail (image/file/url all work)\"),\n })\n .optional()\n .describe(\n \"how ONE ITEM summarises itself when collapsed. Both slots name a CHILD KEY of THIS field/prop — not a value, not a dotted path. 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\"])\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. Same placement rule as `preview`.\",\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});\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.\",\n ),\n label: z.string().min(1).describe(\"human label shown in the editor\"),\n type: fieldType,\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(z.union([z.string(), z.object({ label: z.string(), value: z.string() })]))\n .optional()\n .describe(\n \"choices when type is 'select'. A plain string, or {label, value} when the stored value differs from what the editor shows (e.g. {label:'Sold out', value:'soldOut'}).\",\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}, array {itemType: 'text'|'number'|'date'}, date {includeTime}, modular {blockSlugs: ['quote','gallery'], minItems?, maxItems?} — 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\",\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(\n \"one line of guidance shown UNDER this field in the editor — what to write here, not what the field is. Write it for the person typing ('Roughly 60 characters; it becomes the browser tab title'), not for a developer.\",\n ),\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\"]),\n value: z.union([z.string(), z.array(z.string())]),\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 and number. A clash is refused with 409 `unique_conflict`.\",\n ),\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.object({\n id: z.string().min(1),\n name: z.string().min(1).max(60),\n description: z.string().max(500).optional(),\n }),\n )\n .max(30)\n .optional()\n .describe(\n \"the model's editor cards: [{id, name, description?}], at most 30, ids unique, order = array index. `description` is one line under the card title. A field joins one with `fieldsetId`. Editor-only: never changes what is stored or delivered.\",\n );\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 * 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 // ⚠ 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};\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\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 };\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 return { ...base, type: \"array\", config: { zones: { repeatable: { fields: toFields(f.fields) } } } };\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 // add_page_field) inherits it from one place rather than four 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` is the project's brand kit: colors, typography, radius and any typeScale/spacing/elevation/motion/graphics. It is edited in the BetterCMS dashboard AND by set_brand_assets and set_brand_graphics below; every write is a version a person can restore. ASSETS: point `mark`/`favicon` at a media asset OF THIS PROJECT by id (another project's id is refused); null clears one; a slot a person chose needs `replace: true`. GRAPHICS: gradients are STRUCTURED — `kind`, optional `angle`, 2-8 stops naming kit colour keys (`colors.*` or an `extras` key) — never a CSS string and never a hex; a colour the kit lacks is added to `extras` first. CONSUME, DO NOT COPY: on a hosted page the kit is `--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) rather than copying its values into props. Never invent brand facts: read them here.\";\n\n/** update_content_model's optimistic lock. Mirrors the remote catalog's note word for word. */\nconst MODEL_IF_MATCH_NOTE =\n \"optimisticVersion from get_content_model. When sent, the update applies only if the model is still at that version; a 409 means someone changed it since — read it again and re-apply, never retry blindly. Omitted, the last write wins.\";\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.\";\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/** Said on get_content_structure; the other six carry STRUCTURE_FENCE. Mirrors the remote catalog. */\nconst STRUCTURE_NOTE =\n \"ORGANISATION ONLY: Content sidebar folders never change a URL, slug, content or publish state; URL folders (page folders) are set in the dashboard. Folders nest at most 4 levels deep. Icons are lucide icon names (a-z, 0-9, dashes); null clears one. SYSTEM FOLDERS: \\\"home:pages\\\" (Other pages), \\\"home:collections\\\" (Shared) and \\\"home:globals\\\" (Settings) always exist and can never be moved or deleted (400 NAV_SYSTEM_FOLDER); rename_folder and set_icon do work on them. TYPE PURITY (400 NAV_TYPE_MISMATCH): Other pages holds only pages at any depth, Shared only collections, and Settings neither — globals are not sidebar items. ACCESS: changing the structure needs Admin or Developer, the same as editing the schema; reading needs only content access. A 403 SCHEMA_ACCESS_REQUIRED means this connection is neither: stop and tell the user, do not retry. Pins sit above the folders, in their own order, and may be pages or collections. In a document a pin is folderId \\\"home:root\\\", a virtual id with no folder record (a folder record with that id is 400 NAV_SYSTEM_FOLDER). set_content_structure never refuses a kind mismatch: it returns `warnings` and `kindMismatches` (the single writes do — see `kind`). PAGE-BOUND MODELS: a page with fields has a model bound to it. That model is NOT a collection: it is never listed or filed, and the writes refuse it with 400 NAV_PAGE_BOUND_MODEL naming its page. Organise the PAGE instead, by its page id. \";\n\n/**\n * The same fence, one line, for the six tools that are not where the rules are STATED.\n *\n * The long note is 2.6k characters and it was pasted on all seven structure tools — 16k of\n * one paragraph in a catalogue an agent reads whole before it can speak. It stays on\n * `get_content_structure`, which is the call the standard itself tells an agent to make first,\n * and everything else points at it. Byte-identical in both catalogs: `mcp-text-parity` pins\n * 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. A resource is never truncated; a long description is.\";\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 \\u2014 the agent's equivalent of the dashboard's Import from GitHub, and the thing to do BEFORE writing any code for a user who already has a repo. It provisions the deploy workflow, the project API key and the build variables inside 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 one of this workspace's installations can already reach \\u2014 for anyone else's repository (a public starter, a template, another account's site) use fork_github_repo instead. Read `warning` / `contentWarning` / `actionsWarning` back to the user verbatim when they come back \\u2014 they are the cases where the repository connected perfectly and still 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 with the GitHub App's own credentials, so you need no clone, no remote and no 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\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 };\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 ].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/**\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 \"target project id (from list_projects); only for a workspace-wide grant.\",\n );\n\n/** Lift `projectId` onto a tool and bind it for the duration of the call. */\nconst withProjectId = (def: ToolDef): ToolDef => ({\n ...def,\n config: def.config.inputSchema.projectId\n ? def.config\n : { ...def.config, inputSchema: { ...def.config.inputSchema, projectId: projectIdArg } },\n handler: (args) => {\n const project = typeof args?.projectId === \"string\" && args.projectId ? args.projectId : undefined;\n return currentProject.run(project, () => def.handler(args));\n },\n});\n\n/**\n * 🔴 THE TAIL, COPIED FROM THE HOSTED CATALOGUE — Claude Desktop keeps a server's first ~100 tools\n * and silently drops the rest, and THIS is the surface Desktop loads. The hosted route partitions\n * its listing the same way (`LISTING_TAIL` in src/routes/mcp/index.ts); unordered, the stdio cut\n * dropped `get_next_steps`, the SEO lane, the binding/conversion lane and the GitHub lane.\n *\n * The package cannot import from `src/`, so the two lists are pinned identical by\n * src/__tests__/mcp/mcp-parity.test.ts. Every tool stays registered and callable either way.\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\", \"native_bridge_heartbeat\",\n // Section evidence and component validation: a CI lane, not an authoring one.\n \"claim_section_validation_request\", \"complete_section_validation_request\",\n \"fail_section_validation_request\", \"list_section_validation_requests\",\n \"submit_section_validation\", \"submit_section_manifest\", \"request_component_validation\",\n \"declare_component_route\", \"clear_component_source\", \"submit_componentize_receipt\",\n // Reporting, history and workflow chrome.\n \"get_analytics_overview\", \"get_analytics_top_pages\", \"list_activity\", \"get_workflow_board\",\n \"move_entry_stage\", \"move_page_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\", \"deploy_from_upload\",\n \"set_authoring_preference\", \"set_media_delivery\", \"delete_form_submission\",\n // The ABM campaign lane: a marketer's dashboard surface, plus the worker tools a task runner\n // claims with. Ten more tools than the tail was written for, and a connector that truncates\n // would otherwise lose `get_deploy_status` and the GitHub lane to make room for them.\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 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 try {\n return await fn(deps.createClient(token, project));\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));\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));\n }\n throw err;\n }\n }\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> }\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: heading {text, level}; text/richtext {html} (NOT {text}), and both also take level 1-6, rendering the html AS that <hN> with inline marks kept (one line of inline copy only) — use it for a title that carries a styled span; image {src, alt}; button {text, href}; spacer {height}; video {url}; form {formId}; component {componentId, overrides?}; navbar {links:[{label,href}], logo?, cta?}; footer {columns, copyright?}; section {children: block[]}; columns {columns: block[][], gap} — a column may NOT hold columns/section/slider/tabs; slider {slides:[{id,children}]}; tabs {tabs:[{id,label,children}]}; collection {cardComponentId?, detailComponentId?, titleField?, excerptField?, limit?, order?, emptyText?} — lists this page's published entries as cards, and renders ONE entry on /<page>/<entrySlug>\",\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. A real marketing band is a `section` block carrying bg + padding + contentWidth.\",\n ),\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 });\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 const nativeBridgeHeartbeatInput = z.object({\n protocolVersion: z.string().min(1).describe(\"executor protocol version; currently '1'\"),\n capabilities: z\n .array(z.string().min(1))\n .min(1)\n .describe(\n \"what this executor can do: any of inspect, propose, implement, cancel, question. Must include inspect, propose and cancel. An unknown value is refused, never ignored.\",\n ),\n session: z\n .object({ sessionId: z.string(), sessionEpoch: z.number().int().positive() })\n .optional()\n .describe(\"the `session` from the previous response; omit on first contact to reconnect\"),\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(),\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 });\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).describe(\"id of the content model to extend\"),\n ...fieldShape,\n after: afterArg,\n });\n\n const addPageFieldInput = z.object({\n pageId: z.string().min(1).describe(\"id of the page to extend (from list_pages / create_page)\"),\n ...fieldShape,\n after: afterArg,\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 to ingest; provide this OR localPath\"),\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 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 });\n\n const getPageInput = z.object({\n pageId: z.string().min(1).describe(\"page id (from list_pages / create_page)\"),\n });\n\n const setPageContentInput = z.object({\n pageId: z.string().min(1).describe(\"id of the page to write values to\"),\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 });\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 });\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([\"WebPage\", \"AboutPage\", \"ContactPage\", \"CollectionPage\", \"Blog\", \"BlogPosting\", \"Article\", \"Product\", \"FAQPage\", \"Event\", \"Organization\", \"LocalBusiness\"]).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 });\n\n const deletePageInput = z.object({\n pageId: z.string().min(1).describe(\"id of the page to delete (from list_pages)\"),\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\",\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 });\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; config.componentIds restricts what may\n // 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(z.string()).optional(), // 'select' — required, choices\n // 'group'/'table' sub-shape. Typed loosely here (the server validates the full\n // recursive shape) so a 3-level tree does not need a 3-level Zod mirror in the client.\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).optional().describe(\"hint shown under the control, muted (≤ 200 chars)\"),\n placeholder: z.string().max(120).optional().describe(\"ghost text inside a text-ish control (≤ 120 chars)\"),\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: uiObject\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' and 'slot' only; `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) => LAYOUT_SECTION_ICON_SET.has(value), \"Select a supported Lucide icon\")\n .describe(\"Lucide icon name in canonical kebab-case; legacy CamelCase Layout icon names 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\"]) }),\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() }),\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, e.g. 'Hero' — set this with a library category to make the component selectable in the page editor's 'Add a section' picker. Components sharing a sectionType 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 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, addressed by NAME (e.g. 'Sections', 'Navigation', 'Forms'). Resolved against this project's Groups and CREATED when missing, so a whole-site run can file everything without looking any id up first. Separate from `category`, which is the picker tab.\"),\n sectionType: sectionType.optional(),\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(),\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. 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.\",\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 allowedOn: allowedOn.optional().describe(\"REPLACES the placement allowlist\"),\n description: z.string().optional(),\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 });\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 });\n const createComponentsInput = z.object({\n components: z\n .array(createComponentInput)\n .min(1)\n .max(50)\n .describe(\"up to 50 components, each exactly the create_component input\"),\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(\"page id (from list_pages); or pass `slug`\"),\n slug: z.string().min(1).optional().describe(\"page slug, resolved against list_pages; 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 });\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 const sectionEvidenceProjectId = z\n .string()\n .min(1)\n .max(64)\n .describe(\"exact project id from get_project (not a slug); Section evidence is project-local and never reusable across projects\");\n const sectionId = z.string().uuid().describe(\"Section definition id from Section Studio\");\n const sectionVersion = z.number().int().positive().describe(\"exact Section schema version implemented or tested\");\n const sha256 = z.string().regex(/^[0-9a-f]{64}$/i, \"Expected a SHA-256 hex digest\");\n const sectionViewport = z.object({\n name: z.string().trim().min(1).max(64),\n width: z.number().int().min(240).max(7680),\n height: z.number().int().min(240).max(7680),\n });\n const sectionEvidenceDigest = z.string()\n .regex(/^(?:sha256:)?[0-9a-f]{64}$/i, \"Expected a SHA-256 digest\");\n const nonEmptyDescriptor = z.record(z.string(), z.unknown())\n .refine((value) => Object.keys(value).length > 0, \"Descriptor cannot be empty\");\n const sectionRequestId = z.string().uuid().describe(\"durable Section validation request id returned by list_section_validation_requests or the dashboard\");\n const sectionHttpUrl = z.string().url().max(2048).refine((value) => {\n try {\n const protocol = new URL(value).protocol;\n return protocol === \"http:\" || protocol === \"https:\";\n } catch {\n return false;\n }\n }, \"Expected an HTTP or HTTPS URL\");\n const sectionValidationViewport = sectionViewport.extend({\n status: z.enum([\"passed\", \"failed\"]),\n evidenceDigest: sectionEvidenceDigest,\n });\n const submitSectionManifestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId.optional().describe(\"include when fulfilling a claimed dashboard request so the evidence is bound to that exact run\"),\n sectionId,\n version: sectionVersion,\n apiId: z.string().regex(/^[a-z][A-Za-z0-9]*$/, \"Use lower camelCase\").max(100),\n schemaHash: sha256.describe(\"exact SHA-256 hex hash shown for this Section version\"),\n commitSha: z.string().regex(/^[0-9a-f]{7,64}$/i).describe(\"git commit containing the implementation\"),\n loader: nonEmptyDescriptor.describe(\"non-empty serializable loader descriptor emitted by the repo build; never executable code\"),\n previewAdapter: nonEmptyDescriptor.describe(\"non-empty serializable adapter descriptor for the customer's real app shell; never executable code\"),\n nativeViewports: z\n .array(sectionViewport)\n .max(20)\n .optional()\n .describe(\"the customer's named responsive viewports; BetterCMS also enforces Desktop 1440x900, Tablet 768x1024, and Mobile 390x844\"),\n });\n const submitSectionValidationInput = z.object({\n projectId: sectionEvidenceProjectId.describe(\"exact project id from get_project (not a slug); must match the manifest's project\"),\n requestId: sectionRequestId.optional().describe(\"same claimed request id used for the manifest; binds and terminalizes that run\"),\n sectionId: sectionId.describe(\"exact Section definition id\"),\n version: sectionVersion,\n manifestId: z.string().uuid().describe(\"manifest id returned by submit_section_manifest; it pins the schema hash and commit SHA\"),\n status: z.enum([\"passed\", \"failed\"]).describe(\"the actual result of the external repo/app-shell validation\"),\n fixtureHash: sha256.describe(\"SHA-256 hex hash of the canonical preview dataset and stress fixtures used\"),\n evidenceDigest: sectionEvidenceDigest\n .describe(\"SHA-256 digest of the immutable validation evidence bundle (screenshots/report/results)\"),\n appShell: z.object({\n kind: z.literal(\"actual-app\"),\n identifier: z.string().trim().min(1).max(255),\n url: sectionHttpUrl.optional(),\n }).describe(\"the real customer application shell used for the validation run\"),\n viewportResults: z.array(sectionValidationViewport).min(1).max(23)\n .describe(\"one signed result for every required and native manifest viewport\"),\n });\n const listSectionValidationRequestsInput = z.object({\n projectId: sectionEvidenceProjectId,\n limit: z.number().int().min(1).max(100).optional(),\n });\n const claimSectionValidationRequestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId,\n commitSha: z.string().regex(/^[0-9a-f]{7,64}$/i)\n .describe(\"exact git commit the agent will inspect and validate; evidence must use this same commit\"),\n providerRunId: z.string().trim().min(1).max(255).optional(),\n providerRunUrl: sectionHttpUrl.optional().describe(\"optional HTTP(S) link to the user's external agent run\"),\n });\n const completeSectionValidationRequestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId,\n manifestId: z.string().uuid().optional(),\n validationRunId: z.string().uuid().optional(),\n });\n const failSectionValidationRequestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId,\n errorCode: z.string().trim().regex(/^[A-Z][A-Z0-9_]*$/).max(100),\n errorMessage: z.string().trim().min(1).max(2_000),\n providerRunId: z.string().trim().min(1).max(255).optional(),\n providerRunUrl: sectionHttpUrl.optional().describe(\"optional HTTP(S) link to the user's external agent run\"),\n });\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 or transcript. 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 }).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 }))),\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, and read the resource ${STRUCTURE_PLAYBOOK_URI} (the structure standard) before you organise anything. ${STRUCTURE_NOTE}`,\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 platform's own implementation of the standard over the project's pages, collections, their references and the routes its build serves: the home page and each collection's list page pinned at the top, one folder per content family named for the detail type its route holds (Blog posts, Case studies, Jobs, Products with its taxonomies and an Attributes subfolder for its variant options), ordered by entry count (or the site navigation, when the caller supplies its link order), shared taxonomies in Shared, every remaining standalone and code-only page in Other 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, lucide icons. 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(\"lucide icon name 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 (Other 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 lucide icon name, 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_FENCE}`,\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: Other 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_FENCE}`,\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 (Other 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. The asset must already be in this project's media library — upload it first if it is not. null clears a slot. A slot a PERSON chose is refused unless you pass replace: true, and the refusal says so. Every write is a brand version the dashboard can restore. ${BRAND_KIT_NOTE}`,\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 gradient is a value, so it is stored as a kind, an angle and stops that name the kit's own colour keys, never as CSS and never as a hex. A stop naming a colour the kit does not have is refused; add it to extras first. Upsert matches BY KEY. ${BRAND_KIT_NOTE}`,\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_FENCE}`,\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(\"lucide icon name, e.g. 'file-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_FENCE}`,\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\"]).optional(), 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), redirectType: z.enum([\"301\", \"302\", \"307\", \"308\"]).optional() }).shape,\n async (c, a) => ok(\"Created redirect.\", await data(c, \"POST\", `/management/redirects`, { sourcePath: a.sourcePath, destination: a.destination, redirectType: a.redirectType }))),\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(\"get_seo\", \"Get site SEO\",\n \"Get the connected project's site-wide SEO settings — default meta (title/description/ogImage), JSON-LD siteSchema, and robots/sitemap/rss config.\",\n z.object({}).shape,\n async (c) => ok(\"SEO settings.\", await data(c, \"GET\", `/management/seo`))),\n def(\"update_seo\", \"Update site SEO\",\n \"Set site-wide SEO defaults. `seoDefaults` { metaTitle, metaDescription, ogImage, twitterHandle } applies to every page unless overridden. Optionally robotsConfig / sitemapConfig / rssConfig. Each field is REPLACED whole. Rebuilds the site.\",\n z.object({ seoDefaults: z.record(z.string(), z.unknown()).optional(), siteSchema: z.record(z.string(), z.unknown()).optional(), robotsConfig: z.record(z.string(), z.unknown()).optional(), sitemapConfig: z.record(z.string(), z.unknown()).optional(), rssConfig: z.record(z.string(), z.unknown()).optional() }).shape,\n async (c, a) => ok(\"Updated SEO.\", await data(c, \"PATCH\", `/management/seo`, a))),\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_entry_stage / move_page_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_entry_stage\", \"Move a content entry across the board\",\n \"Move a content entry to another editorial stage — this is how you get an entry OUT of review so it can be published. `workflowStage` is a stage key from get_workflow_board (null clears it). Optionally set `workflowAssigneeIds` / `workflowDueDate`, or pass `fromStage` to fail with 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 status:'published' — approving and publishing are deliberately two separate calls.\",\n z.object({ entryId: z.string().min(1), workflowStage: z.string().max(64).describe(\"stage key from get_workflow_board\"), fromStage: z.string().max(64).optional().describe(\"the stage you believe it is in — 409s if it has moved\") }).shape,\n async (c, a) => ok(\"Moved entry.\", await data(c, \"PATCH\", `/management/content/entries/${s(a.entryId)}/workflow`, { workflowStage: a.workflowStage, fromStage: a.fromStage }))),\n def(\"move_page_stage\", \"Move a page across the board\",\n \"Move a page to another editorial stage — the page twin of move_entry_stage, and the only way to take a page out of review so update_page (status:'published') can go live. `workflowStage` is a stage key from get_workflow_board. Moving into the publish-gate stage is an approval and needs a publish-enabled connection.\",\n z.object({ pageId: z.string().min(1), workflowStage: z.string().max(64).describe(\"stage key from get_workflow_board\"), fromStage: z.string().max(64).optional().describe(\"the stage you believe it is in — 409s if it has moved\") }).shape,\n async (c, a) => ok(\"Moved page.\", await data(c, \"PATCH\", `/management/pages/${s(a.pageId)}/workflow`, { workflowStage: a.workflowStage, fromStage: a.fromStage }))),\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 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. `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\") }).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, deploy_from_upload and promote_project all refuse with 409 AUTHORING_DECISION_REQUIRED until it is set, and that refusal carries this project's real page counts to show the user. 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. Recommend components unless the user says the site is schema-first. 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 works once (at import, when the CMS values equal the built copy) and breaks the first time anyone edits a value. Call it ONLY after every page's copy is declared in the template: undeclared fields stop being editable. The order is push → release → get_binding_report shows mode 'text-match' with 0 unmatched → set_binding_mode → release again → get_binding_report shows mode 'declared'. Flipping back is the same call. REQUIRES the artifact:write scope — the same authority that deploys the site — because 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. See section 13 of the bettercms://playbook/schema resource.\",\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` wrote (`--receipt out.json`) for the SAME `briefDigest` get_conversion_brief { complete: true } returned: `{ briefDigest, receipt }`, where the receipt carries `paths: { declared, rewritten, alreadyDeclared, pending[{ route, scope, path, kind, file, reason, message, fix }] }`. `paths.declared` must equal rewritten + alreadyDeclared + pending.length, and each pending `reason` is one of the converter's own (IN_EXPRESSION, AMBIGUOUS_LITERAL, REPEATER_FIXED_LENGTH, PARSE_ERROR, …) — a path with no receipt row simply reads `not-declared`. 🔴 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, file, line, col?, snippet, why?, kind? }`. `action` is `wrap-span`, `declare-attr`, `bind-expression`, `declare-richtext`, `bind-data` or `manual`; each row's `snippet` and `why` say what to change there. On a `declare-richtext` with `kind: document`, bind the ONE element wrapping every block of the Body, never the paragraph holding its first. Apply every fix, rerun, resubmit. `complete: true` is the only receipt that ends a conversion; do not report a site converted on less. It is a RECORD, not a release: it changes nothing about the site, and the meter picks it up on the next get_binding_report after the next deploy. A 404 `unknown-brief` means that digest was never issued here. 🔴 SUBMIT THE `--forms` RECEIPT TOO, AS A SECOND CALL: A `npx @bettercms-ai/convert --forms` run writes a receipt whose `paths` are all zero and whose account is in a `forms` block. Write it to its own file (`--receipt forms-receipt.json`) and submit it under the same `briefDigest`: stored beside the binding receipt, never counted in coverage. Then read `forms.pending` and publish every form it names. 🔴 THE SITE'S DESIGN IS NOT YOURS TO CHANGE: run `npx @bettercms-ai/convert --verify-styles --base <commit before the conversion> --root .` and include its `styleEdits` in the receipt. A receipt listing any changed class, className or style is refused with 409 `style-edits` and every token — restore them; the CMS keeps inline markup exactly as written. Requires artifact:write, the same authority as set_binding_mode.\",\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.\"),\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 def(\"create_template\", \"Save a project/page as a template\",\n \"Save a project (or one page) as a REUSABLE template — a frozen snapshot of its content models, pages, entries, components, and forms (secrets/domains/analytics excluded). Later seed a new project from it with create_project { templateId }. Set visibility 'public' to list it in the cross-workspace gallery. Returns the new template's id.\",\n z.object({ sourceProjectId: z.string().min(1), name: z.string().min(1), scope: z.string().optional(), sourcePageId: z.string().optional(), description: z.string().optional(), visibility: z.string().optional() }).shape,\n async (c, a) => ok(\"Created template.\", await data(c, \"POST\", `/management/templates`, a))),\n def(\"list_templates\", \"List saved templates\",\n \"List your workspace's saved templates (id, name, scope, visibility). Use a template's id as create_project { templateId } to seed a new project from it.\",\n z.object({}).shape,\n async (c) => ok(\"Templates.\", await data(c, \"GET\", `/management/templates`))),\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.\",\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 \"Rename a content model, edit its description/slug/urlPattern, or set its `fieldsets`. Never touches `fields`: use add_field to extend the schema. Provide modelId plus what to change. `fieldsets` REPLACES the list (send null to drop them all); then put a field in one with add_field's `fieldsetId`. `urlPattern` is the collection's entry URL, e.g. '/blog/:slug' (null clears it). A slug already used in this project and branch is refused with 409 `slug_taken`.\",\n z.object({ modelId: z.string().min(1), name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), urlPattern: urlPatternArg, fieldsets: fieldsetsArg.nullable(), ifMatch: z.number().int().min(0).optional().describe(MODEL_IF_MATCH_NOTE) }).shape,\n // `fields` is deliberately not sent: the PATCH replaces `fields` wholesale when present.\n async (c, a) =>\n ok(\n \"Updated content model.\",\n (\n await c.fetchJSON<{ data?: unknown }>(c.url(`/management/content/models/${s(a.modelId)}`), {\n method: \"PATCH\",\n body: JSON.stringify({ name: a.name, slug: a.slug, description: a.description, urlPattern: a.urlPattern, fieldsets: a.fieldsets }),\n ...(a.ifMatch !== undefined ? { headers: { \"if-match\": `W/\"${a.ifMatch}\"` } } : {}),\n })\n ).data,\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(\"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 it REPLACES the whole array, so read get_page first). A `blockJson` that swaps a component block to another component comes back with `warnings` (COMPONENT_SWAP_DROPS_OVERRIDES) naming the overrides the new component does not render; they stay on the block, so swapping back restores them. It does NOT change the field SCHEMA — use add_page_field / set_page_content for that. Renaming the slug keeps content intact. Publishing copies the draft blocks live in the same call — and on a singleton it publishes the page's content entry too; if the entry's workflow stage refuses, the page still goes live and `warnings` carries ENTRY_STILL_DRAFT with the entry id and the reason. STRUCTURED DATA is native SEO, never a field: leave it out and the page gets Automatic JSON-LD from its content (WebSite on the home page, Blog/CollectionPage on a collection's list page, WebPage otherwise); `schemaType` picks an explicit schema.org type whose properties are filled from the content; `schema` is pasted JSON-LD and wins over both (null clears it). \" + 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), title: z.string().optional(), slug: z.string().optional(), blockJson: z.array(blockObject).optional().describe(\"REPLACES the page's block composition\"), metaTitle: z.string().optional(), metaDescription: z.string().optional(), schemaType: z.enum([\"auto\", \"WebPage\", \"AboutPage\", \"ContactPage\", \"CollectionPage\", \"Blog\", \"BlogPosting\", \"Article\", \"Product\", \"FAQPage\", \"Event\", \"Organization\", \"LocalBusiness\"]).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() }).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 const res = await c.fetchJSON<{ data?: unknown; redirectNote?: { source: string; existingDestination: string }; warnings?: string[] }>(\n c.url(`/management/pages/${s(a.pageId)}/meta`),\n {\n method: \"PATCH\",\n body: JSON.stringify({ title: a.title, slug: a.slug, blockJson: a.blockJson, 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 }),\n },\n );\n const note = res.redirectNote;\n const summary = note\n ? `Updated page. 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 : \"Updated page.\";\n return ok(res.warnings?.length ? `${summary}\\n${res.warnings.join(\"\\n\")}` : summary, 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`: 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) BEFORE creating the archive: a source deploy is reinstalled and built server-side, so those are never needed, and the upload has a hard size ceiling (~100 MB) enforced before the request reaches the server — an archive that includes node_modules is rejected in transit (a 413/502 with no server-side detail). Keep the archive to your own source files. Server-side stripping exists as a safety net, but it runs AFTER the upload and cannot rescue an over-limit body. For a LARGE archive (or if this returns a 413/502), use create_deploy_upload + deploy_from_upload instead — that path uploads straight to storage with no size ceiling. Returns `canvas.lane` — which live-preview lane the last release gave the editor (`bridge` / `draft-route` / `none`; see the playbook's section 11) — 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({ data: z.string().min(1).describe(\"base64 .tgz/.zip of the project\"), mimeType: z.string().optional() }).shape,\n async (c, a) => ok(\"Deploy queued.\", await raw(c, `/management/projects/deploy`, s(a.data), a.mimeType as string | undefined))),\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_from_upload 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 def(\"deploy_from_upload\", \"Deploy from a staged upload\",\n \"Deploy from an archive already uploaded via create_deploy_upload (step 3). Pass the `uploadKey` you received. Builds SOURCE server-side or serves a prebuilt site — then poll get_deploy_status until live.\",\n z.object({ uploadKey: z.string().min(1).describe(\"the uploadKey from create_deploy_upload, after PUTting the archive to its uploadUrl\") }).shape,\n async (c, a) => ok(\"Deploy queued.\", await data(c, \"POST\", `/management/projects/deploy/from-upload`, { uploadKey: a.uploadKey }))),\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(\"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.\",\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_changes\", \"Get changes since a timestamp\",\n \"Read the durable project change feed since an ISO timestamp. Call this at the start of a new turn to notice dashboard or agent edits made since your previous observation.\",\n z.object({ since: z.string().datetime(), limit: z.number().int().min(1).max(100).optional() }).shape,\n async (c, a) => ok(\"Project changes.\", await data(c, \"GET\", `/management/insights/activity${q({ since: a.since, limit: a.limit ?? 100 })}`))),\n def(\"get_next_steps\", \"Get what to do next\",\n `What is still unfinished in the connected project, as the platform sees it — pages you created without a meta description, drafts never published, collections with no entries, forms nobody is notified about, writes waiting for human approval. Each item cites the count it reacted to. Call it AFTER a batch of edits to catch what you left behind, and before telling the user you are done. When it lists \\`organise-content\\`, the project's pages and collections are in no folder: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure and apply it with set_content_structure once the user agrees.`,\n z.object({}).shape,\n async (c) => ok(\"Next steps.\", await data(c, \"GET\", `/management/insights/next-steps`))),\n def(\"get_binding_report\", \"Check what on the live site is editable\",\n \"The receipt for 'is this site actually EDITABLE?'. Every release scans the built HTML for the element that renders each CMS field value; this returns what that scan found, per slot: `mode` ('text-match' = bindings guessed from rendered text, 'declared' = the template declares them), what was bound, and `unmatched` — each path with the reason it failed (not-declared / ambiguous-text / no-element). DEPLOY FIRST: before any release there is no report (pages 0, mode null, refreshRequired true). `refreshReason` says which: `never-generated` — only a release BetterCMS builds and serves writes a report, so a HEADLESS site never gets one and redeploying will not change it (verify that site by fetching it); `outdated` — the next release rewrites it. It certifies one thing: every non-empty field has SOME element carrying its path. It cannot see copy that was never modelled, so diff each route's visible text against its entry values yourself before calling a page done. `builtRoutes` lists the routes the live build has HTML for, or null when it cannot say. `canvas.lane` names the live-preview lane this build gives the editor — `bridge`, `draft-route` or `none`, in which case get_next_steps carries the recipe (playbook section 11). `unaddressable` counts visible text on the live site that no field owns — the one thing `unmatched` structurally cannot see, because it only ever speaks about fields that already exist. EVERY release measures it server-side on every inspected page and the result names the routes, their countable characters and the buckets the unowned text sits in, biggest first. Anything over `count / visible > 0.02` is copy the CMS cannot see: fix it in the SOURCE (wrap the run in an element the codemod can bind, or declare `<BcmsField path=…>`), deploy, re-read — playbook section 11 has the loop. `skipReasons` says why pages were not inspected; `coverage.error` = `nothing-bound` means not one element of this build carries a binding, so the percentage beside it describes a site this build is not.\",\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.\") }).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, and every bindable field path with its `label`, `kind`, the value the CMS holds now (`current`) and the copy the repo renders today (`original`, the field's defaultValue) — plus 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_page_field / create_content_model would build a second schema over the first — edit values with set_page_content instead. `lane` says how to get the source ('git-connected' = pull_project_source returns a repo; 'archive' = a tarball). The full recipe is section 13 of the bettercms://playbook/schema resource; get_binding_report is the receipt that says you finished. Pass `complete: true` when you are about to run the CODEMOD (`npx @bettercms-ai/convert`): that returns the brief UNCAPPED and paged — nothing truncated, no page omitted — and pins the full path list under a `briefDigest`, which is the list the coverage meter in get_binding_report measures the build against. Follow `cursor` until it stops coming back; a 409 `BRIEF_CHANGED` means the brief was re-derived while you paged, so start again. The complete brief also carries `forms` — every form of this project with its id, status, fields and submitUrl — which is what `npx @bettercms-ai/convert --forms --brief brief.json --root . --receipt forms-receipt.json` wires into the repository's own <form> elements; run it after the binding pass, read its `forms.pending`, and publish every form its `forms.notes` names in the Forms tab (a draft form rejects every submission with a 403).\",\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 — a plan applied to a different base is a different change), 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 rather than applying it anyway. `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. Finish the loop the same way as a hand conversion — 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, nothing is written. Call it at the START of a whole-site componentize run (playbook §12) for the before picture, and at the END as the proof. Per page: `kind` ('blocks' | 'fields-only' | 'empty'), a block census, `nonComponentBlocks` (loose TOP-LEVEL bands the editor's section lane cannot outline), and every `component` placement with the component's `status` ('published' | 'draft' | 'missing' — a draft renders as an EMPTY STRING on the live site), whether it is `inPicker` (a component with no sectionType is dropped from 'Add a section'), and any `emptyRequiredProps` — `required` is an editor hint the write path does not enforce, so this read is the only thing that reports it. Site-wide: `components` counts published/draft, `awaitingEvidence` and `awaitingApproval` (evidence is exact and a HUMAN must approve it in the BetterCMS dashboard — no tool here can grant that, and there is no bulk approve), plus `notInPicker` and `unused` ids; `layout.placements` is the chrome placed in the Global Layout draft. `verdict.everyPageComposed` with `verdict.reasons` is the answer to give the user. Pages are read DRAFT-inclusive, so a page composed but not yet published still shows its placements — 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, changes nothing and is computed live on every call. For a site whose pages were DERIVED at import (the site get_conversion_brief describes), each top-level field GROUP is one section: `hero-*` and `faq-*` keys, and the repeaters the import already folded (`group-*`). Per page it returns each section's `groupKey`, its `sectionType` family (Hero, FAQ, CTA, Features, Social proof…), its leaf `fields` (key, path, type, the value the CMS holds), a `shapeHash`, and either the component that already renders it (`reuse.componentId`) or the one this plan proposes (`reuse.proposedSlug`) — and the components themselves under `components`: a NEW one carries the exact `props` and `blockJson` create_component would take, while a row for a component that ALREADY EXISTS carries its `componentId`, `slug` and `name` and no definition, because nothing will be written for it. Groups with the SAME shape across pages collapse into ONE component with several placements. `pending` says why a group is not offered: `NO_GROUP_ROOT` (the page's field keys are still the derive lane's own — `h1-welcome`, `p-we-build-things` — so there is no family to group by; rename them into families first), `NOT_A_SECTION` (a lone scalar with no family, or the page's own metadata — a section is a group field, a repeater, or a family two or more leaves share, so a legal page of `title`/`metaDescription`/`intro` proposes nothing), `ALREADY_COMPONENTIZED`, `EMPTY_GROUP`, `NESTED_REPEATER` (a repeater THREE deep; TWO levels are expressed exactly — the group's `table` prop gains a nested `table` sub-field, and each row's nested column is an array of row objects), `PAGE_NOT_EMPTY` (the page holds blocks this lane does not own and will not overwrite). Chrome is NEVER a section: `nav-`/`footer-` keys and everything promoted into the project Layout are edited through the Layout. Keep the `digest` — componentize_sections refuses any other.\",\n z.object({}).shape,\n async (c) => ok(\"Componentize plan.\", await data(c, \"GET\", `/management/projects/current/componentize-plan`))),\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 and say how many components it will create and which pages it will rewrite. It creates each proposed component as a DRAFT and replaces each page's DRAFT blocks with an ordered list of `component` instances — one per group, each carrying `props.bind: \\\"<groupKey>\\\"`, which points at the page field group that already holds the copy. So nothing is copied and nothing moves: the page keeps its `fields`, its values and its bindings, click-to-edit keeps working and the coverage meter does not change. Pass the plan's `digest`; a 409 `stale-plan` means the site changed since you read that plan, so read it again, show the user what changed and confirm again. Read its `components.wouldDuplicate` before applying: each id is an existing component of the same family this run would sit a NEW one beside, because reuse is by identity and slug, never by family. Running it twice is safe: a group that already has a placement comes back in `sections.pending` as ALREADY_COMPONENTIZED and no second component is created. DRAFTS ONLY — an unpublished component renders as an EMPTY STRING on the live site, so publish_component each one and publish the pages before this reaches a visitor. Then run `npx @bettercms-ai/convert --componentize` in the repo so its templates render these sections from `pages[].blocks`. The default `bind` is the above: the words stay in the page's field group. `copy: \\\"instance\\\"` moves the words onto each placement and marks the page's fields `origin: \\\"componentized\\\"` — kept, never deleted (see `copy`). Every component it CREATES is filed into a Component Group (the folders of the dashboard's Components tab): the one you name in `group` (found or created), else its section family — nav, header, footer or menu → Layout, an unnamed section → Sections, otherwise the family name (Hero, FAQ). A component it reuses keeps the Group it has; the receipt's `components.groups` lists the Groups it filed into.\",\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 on the page keeps the placement it already has.\"),\n copy: z.enum([\"bind\", \"instance\"]).optional().describe(\"Who owns each section's copy. 'bind' (default) leaves it in the page fields. 'instance' is the page-builder model: each placement takes that group's CURRENT draft values into its own `props.overrides` (a repeater becomes one table prop holding every row), records which page path each came from in `props.source`, and drops `props.bind`; the page's fields are KEPT and marked `origin: \\\"componentized\\\"`, so nothing is lost and the editor stops showing a second place to type the same words.\"),\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). Omit to file each under its section family.\"),\n }).shape,\n async (c, a) => ok(\"Componentized the sections.\", await data(c, \"POST\", `/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 }))),\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, absent schema) and return them with severities. 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 def(\"list_section_validation_requests\", \"List queued Section validation requests\",\n \"Poll for user-agent Section implementation-validation requests in this exact project. BetterCMS cannot push work into an ordinary MCP client: call this explicitly, claim one request, inspect and run the customer's real repository/app shell, then submit request-bound evidence and complete it. Returns only unclaimed user-agent requests; it never exposes another project.\",\n listSectionValidationRequestsInput.shape,\n async (c, a) => ok(\"Queued user-agent Section validation requests.\", await data(\n c,\n \"GET\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests${q({ limit: a.limit })}`,\n ))),\n def(\"claim_section_validation_request\", \"Claim a Section validation request\",\n \"Atomically claim one queued user-agent request and pin the exact git commit you will inspect. Claim BEFORE submitting evidence. BetterCMS records coordination only; all customer code and responsive checks must run in the user's repository and real app shell.\",\n claimSectionValidationRequestInput.shape,\n async (c, a) => ok(\"Section validation request claimed.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests/${s(a.requestId)}/claim`,\n {\n commitSha: a.commitSha,\n providerRunId: a.providerRunId,\n providerRunUrl: a.providerRunUrl,\n },\n ))),\n def(\"complete_section_validation_request\", \"Complete a Section validation request\",\n \"Complete a claimed request only after submit_section_manifest and submit_section_validation have bound exact, passed evidence to the same requestId and pinned commit. This cannot grant the separate human Visual Approval.\",\n completeSectionValidationRequestInput.shape,\n async (c, a) => ok(\"Section validation request completed.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests/${s(a.requestId)}/complete`,\n { manifestId: a.manifestId, validationRunId: a.validationRunId },\n ))),\n def(\"fail_section_validation_request\", \"Fail a Section validation request\",\n \"Truthfully close a claimed request when the renderer, validation command, app shell, or required evidence is missing or fails. This path intentionally works without a manifest so 'not implemented' is representable instead of being reported as passed or left queued forever.\",\n failSectionValidationRequestInput.shape,\n async (c, a) => ok(\"Section validation request failed.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests/${s(a.requestId)}/fail`,\n {\n errorCode: a.errorCode,\n errorMessage: a.errorMessage,\n providerRunId: a.providerRunId,\n providerRunUrl: a.providerRunUrl,\n },\n ))),\n\n def(\"submit_section_manifest\", \"Submit a Section implementation manifest\",\n \"Record the implementation manifest produced for one exact Section schema version by CI or an agent running INSIDE the user's repository. BetterCMS does not execute customer code: inspect/build the real renderer in the user's app shell first, then submit its exact API ID, schema hash, commit SHA, loader, preview adapter, and native responsive viewports. Requires a project-scoped artifact:write credential. This records evidence only; it does not validate the implementation and cannot create human Visual Approval.\",\n submitSectionManifestInput.shape,\n async (c, a) => ok(\"Section implementation manifest recorded.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/sections/${s(a.sectionId)}/versions/${a.version}/manifests`,\n {\n requestId: a.requestId,\n apiId: a.apiId,\n schemaHash: a.schemaHash,\n commitSha: a.commitSha,\n loader: a.loader,\n previewAdapter: a.previewAdapter,\n nativeViewports: a.nativeViewports,\n },\n ))),\n def(\"submit_section_validation\", \"Submit a Section validation result\",\n \"Record a real validation result for one exact Section schema version and manifest. Run the component in the user's repository and real app shell across the canonical preview dataset, AI stress fixtures, and required/native viewports BEFORE calling this tool; BetterCMS never runs that customer code. Pass status 'passed' only when those checks actually passed, otherwise 'failed'. The manifest pins schemaHash and commitSha; fixtureHash and evidenceDigest pin the tested data and immutable evidence bundle. Requires project-scoped artifact:write and cannot create the separate human Visual Approval required for publication.\",\n submitSectionValidationInput.shape,\n async (c, a) => ok(\"Section validation result recorded.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/sections/${s(a.sectionId)}/versions/${a.version}/validations`,\n {\n requestId: a.requestId,\n manifestId: a.manifestId,\n status: a.status,\n fixtureHash: a.fixtureHash,\n evidenceDigest: a.evidenceDigest,\n appShell: a.appShell,\n viewportResults: a.viewportResults,\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|categorizing|failed), whether it's publishing, the live commit sha, when it went live, and any build error. `categorizing` means the bytes are live but the import's setup lanes (content, pages, bindings) are still running, so `publishing` is still true and the site is not ready to edit yet. Poll this after deploy_project until state is idle with your sha live. Also returns `canvas.lane` (the editor's live-preview lane for this site: `bridge` / `draft-route` / `none`) and `editorUrl`, the visual editor to hand the user.\",\n z.object({}).shape,\n async (c) => ok(\"Deploy status.\", await data(c, \"GET\", `/management/projects/deploy-status`))),\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 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_page_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 pageType: p.pageType,\n status: p.status,\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 by id INCLUDING its full field schema (keys, types, nested group/repeater children) and pageType. Read this before set_page_content so you write correctly-keyed values, or before add_page_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 });\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). `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 model = await client.createModel({\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: args.fieldsets } : {}),\n fields: toFields(args.fields) as CreateModelInput[\"fields\"],\n });\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\",\n description:\n \"Append a field to an existing content model. Reads the model's current fields and adds yours (read-modify-write) — never removes existing fields. For a section/zone, add ONE 'group' (fixed block) or 'repeater' (repeating list) field carrying its child `fields` — don't add the zone's inner fields as separate top-level fields. `fieldsetId` puts it in one of the model's fieldsets (set them with update_content_model). \" +\n RICH_TEXT_NOTE,\n inputSchema: addFieldInput.shape,\n },\n handler: guard(async (args: z.infer<typeof addFieldInput>) =>\n withClient(async (client) => {\n const model = await client.getModel(args.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 const updated = await client.updateModel(args.modelId, {\n fields: nextFields as Parameters<typeof client.updateModel>[1][\"fields\"],\n });\n return ok(\n `Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : \"\"}. Model now has ${updated.fields.length} field(s).`,\n updated,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"add_page_field\",\n config: {\n title: \"Add a field to a page\",\n description:\n \"Append a field to an existing page's schema (Home, About, a blog template, etc.). Additive — the API rejects a key that already exists and never overwrites or retypes existing fields. Use this when the target is a page (singleton or dynamic); use add_field when the target is a content model. For a section/zone, add ONE 'group' (fixed block) or 'repeater' (repeating list) field carrying its child `fields` — don't add the zone's inner fields as separate top-level fields.\",\n inputSchema: addPageFieldInput.shape,\n },\n handler: guard(async (args: z.infer<typeof addPageFieldInput>) =>\n withClient(async (client) => {\n // No client-side preflight here on purpose. `addPageFields` is an additive PATCH onto\n // the page-fields route, which now refuses a NEW flat-namespace collision itself — so a\n // check here would be a second authority AND an extra round-trip, and the two could\n // drift. `add_field` keeps its check only because it already fetches the model.\n // `after` rides to the route (this tool does NOT read the page first, by design —\n // see the note above), which does the splice under the same lock it already takes.\n const page = await client.addPageFields(args.pageId, {\n // Cast: same as create_page. The SDK types `options` as string[], narrower than the\n // API, which also takes {label, value} (backend selectFieldSchema).\n addFields: [toField(args)] as AddPageFieldsInput[\"addFields\"],\n ...(args.after !== undefined ? { after: args.after } : {}),\n });\n return ok(\n `Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).`,\n page,\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. 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.\",\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 created = await client.createEntry({\n contentModelId: args.contentModelId,\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n });\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 [`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. Read the schema first with get_page. This is how you populate Home/About/Settings — create_content_entry is for dynamic collections only.\",\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 });\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. 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.\",\n inputSchema: listEntriesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listEntriesInput>) =>\n withClient(async (client) => {\n const entries = await client.listEntries({\n ...(args.modelId ? { modelId: args.modelId } : {}),\n ...(args.pageId ? { pageId: args.pageId } : {}),\n ...(args.status ? { status: args.status } : {}),\n });\n return ok(`${entries.length} entr(y/ies).`, entries);\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. Use this to edit an existing entry; for a singleton page prefer set_page_content. 🔴 `data` REPLACES the entry's whole value object: an optional field you leave out is DELETED, and a required one you leave out fails the whole write. To change one field, read the entry (get_content_entry), change that key, and send the whole object back. \" + ENTRY_META_NOTE,\n inputSchema: updateEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateEntryInput>) =>\n withClient(async (client) => {\n const { warnings, ...entry } = await client.updateEntry(args.entryId, {\n ...(args.data !== undefined ? { data: args.data } : {}),\n ...(args.status !== undefined ? { status: args.status } : {}),\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.meta !== undefined ? { meta: args.meta } : {}),\n });\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. 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 = 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 inputSchema: deletePageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deletePageInput>) =>\n withClient(async (client) => {\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. 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.\",\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) so the live site builds from it. Until this is called the layout stays draft and get_layout copy:'published' answers PUBLISHED_LAYOUT_UNAVAILABLE — site chrome authored with update_layout is NOT live. Read get_layout first and pass its revision as ifMatch; a stale revision returns 409 — re-read, never retry blindly. A 422 lists validation issues to fix with update_layout first. A new project's chrome is draft: publish_component navigation-default and footer-default first (each can publish while the other is draft), then publish_layout. navigation.logo is a REQUIRED image — new projects get a generated one; if it is empty (required_value) or not a stored asset (image_asset_missing), upload one and set it with update_layout as { id, url, name, altText }. Verify with get_layout copy:'published' and check the copy echo — this tool's own response is the write's echo, not a receipt. Page overrides go live with the page (update_page status:'published'). A 403 PUBLISH_NOT_GRANTED means this connection can author drafts but cannot publish — say so and let the user allow publishing or publish 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:\n \"Get one component by id INCLUDING its blockJson tree and props (with any stored `ui` authoring chrome on them). Read this before update_component so you keep the existing blocks, and after declaring field UI as the receipt that it landed — a prop absent here was not stored.\",\n inputSchema: getComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getComponentInput>) =>\n withClient(async (client) => {\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:\n \"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. \" +\n DOCTRINE,\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: \"create_components\",\n config: {\n title: \"Create many components in one call\",\n description:\n \"Create up to 50 components in ONE call — the same input as create_component, once per item. Prefer it over create_component whenever you are making more than three: a whole-site componentize run (playbook §12) is dozens, and one call each spends the turn on plumbing. Each item reports its own `{ ok, id, slug, error }`: a failure does NOT stop the run and the successful rows stay, so read the receipt and retry only the failures (a 409 on `slug` means that name is taken — change it, do not re-run the batch). Every component lands as a DRAFT, exactly as create_component does — it renders as NOTHING on the live site until it is published, which needs the owner's approval in the dashboard. Pass `group` on each item to file it into the folder editors browse. \" +\n \"DECLARE A PROP — WITH A `target` — for every string, link and image a marketer will ever touch: inside a component only the leaves a declared prop TARGETS are click-to-edit, and copy no prop points at is reachable neither from the canvas nor from the dock. A page is composed of SECTIONS; the full doctrine is in the bettercms://playbook/schema resource, §12.\",\n inputSchema: createComponentsInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createComponentsInput>) =>\n withClient(async (client) => {\n const results: Array<Record<string, unknown>> = [];\n for (const input of args.components) {\n try {\n const cmp = await client.createComponent(input as ManagedComponentInput);\n results.push({ ok: true, slug: cmp.slug, id: cmp.id, name: cmp.name });\n } catch (err) {\n results.push({ ok: false, slug: input.slug, error: errorText(err) });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n return ok(\n `Created ${results.length - failed} of ${args.components.length} component(s)${failed ? `; ${failed} failed — see the per-item errors` : \"\"}. All are DRAFTS: publish_components once the owner has approved them, or they render as empty strings.`,\n results,\n );\n }),\n ) as ToolDef[\"handler\"],\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 and must not be: no tool on this connection can clear it, and it has no bulk form. It is never a component you just made with create_component in no variant group — that is dashboard-managed and publishes on the preflight alone. The refusal is for a REPO-managed component without exact validation evidence and a human's approval, or for a variant-group member (the provisioned navigation and footer) whose group's canonical-input contract is not published. Report its `readiness`. The item's `readiness` names what is missing — relay that to the user as the list of 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 — that page would render the missing sections as empty strings with no error anywhere, which is the single hardest failure on this platform to trace back. 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 needsSlug = args.pages.some((p) => !p.pageId);\n const [known, pageList] = await Promise.all([\n client.listComponents({ select: \"summary\" }),\n needsSlug ? client.listPages() : Promise.resolve([]),\n ]);\n const ids = new Set(known.map((c) => c.id));\n const bySlug = new Map(pageList.map((p) => [p.slug, p.id]));\n\n const results: Array<Record<string, unknown>> = [];\n for (const page of args.pages) {\n const pageId = page.pageId ?? (page.slug ? bySlug.get(page.slug) : undefined);\n if (!pageId) {\n results.push({ ok: false, slug: page.slug, error: `No page with slug '${page.slug}' in this project — pass a pageId from list_pages.` });\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 } }>(\n client.url(`/management/pages/${pageId}/meta`),\n { method: \"PATCH\", body: JSON.stringify({ blockJson: page.blockJson }) },\n );\n results.push({ ok: true, pageId, slug: written.data?.slug ?? page.slug, blocks: page.blockJson.length });\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 return ok(\n `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 { component, replaced } = await client.extractComponent(args);\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.`,\n component,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_component\",\n config: {\n title: \"Update a reusable component\",\n description:\n \"Update a component by id — blockJson, props, name, or category. Read get_component first. Passing `blockJson`/`props` REPLACES them. This writes the DRAFT: call publish_component to push the change live.\",\n inputSchema: updateComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateComponentInput>) =>\n withClient(async (client) => {\n const { componentId, ...input } = args;\n const cmp = await client.updateComponent(componentId, input as ManagedComponentInput);\n return ok(`Updated component '${cmp.name}' (id ${cmp.id}).`, 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 the code for a component in the app's repository. It tells BetterCMS which file renders the component, so the dashboard's Output button can build a live preview and validate it with no setup. Without it Output says no source is recorded and 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. create_component and update_component write drafts, and an unpublished component renders 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 is never a component you just made with create_component in no variant group — that is dashboard-managed and publishes on the preflight alone. The refusal is for a REPO-managed component without exact validation evidence and a human's approval, or for a variant-group member (the provisioned navigation and footer) whose group's canonical-input contract is not published. Report its `readiness`. The response's `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 // ── 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 name: \"native_bridge_heartbeat\",\n config: {\n title: \"Register as a native bridge and report liveness\",\n description:\n \"Register this client as a native-bridge executor for the connected project and report that it is alive. The dashboard's 'Native AI Connection' panel shows an executor as live ONLY while heartbeats keep arriving: call this again every `nextHeartbeatMs` (25s), because liveness lapses 90s after the last call and the panel then stops offering this executor. Idempotent — registration happens on the first call, so a restart or a reconnect is just another call. Echo back the `session` from the previous response so the same connection epoch is kept; omit it to reconnect, which fences the previous one. A 422 names a refused capability or protocol; it does not retry into success. THIS GRANTS NO REPOSITORY MUTATION — it is presence only, and starting a run still requires a human in the dashboard.\",\n inputSchema: nativeBridgeHeartbeatInput.shape,\n },\n handler: guard(async (args: z.infer<typeof nativeBridgeHeartbeatInput>) =>\n withClient(async (client) => {\n // Straight through the request plumbing, like the lifecycle tools: this endpoint has\n // no bespoke SDK method, and adding one per endpoint is what that hatch exists to avoid.\n // The route's body schema is `.strict()`, so only these three keys may travel — the\n // project rides as X-BCMS-Project, which the client sets from `projectId`.\n const result = await client.fetchJSON<{\n installationId: string;\n sessionId: string;\n sessionEpoch: number;\n liveness: string;\n nextHeartbeatMs: number;\n reconnected: boolean;\n }>(client.url(\"/management/orchestration/bridge/heartbeat\"), {\n method: \"POST\",\n body: JSON.stringify({\n protocolVersion: args.protocolVersion,\n capabilities: args.capabilities,\n ...(args.session ? { session: args.session } : {}),\n }),\n });\n return ok(\n `Bridge ${result.liveness}. Call again within ${Math.round(result.nextHeartbeatMs / 1000)}s to stay live.`,\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 // 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(withProjectId);\n}\n\n/** Register all BetterCMS tools on an MCP server. */\nexport function registerTools(server: McpServer, deps: ToolDeps): 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 for (const def of buildToolDefs(withElicit)) {\n server.registerTool(def.name, 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 { ContentBlock } from \"./block.js\";\nimport type { ContentModelFieldUi } from \"./content-model.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. 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 nine 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 the blueprint with create_component 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] 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 * 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)\n *\n * `reference` is absent on purpose: nothing resolves a content-entry id at component render\n * time, so such a prop would save cleanly and render as nothing.\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 /** Ghost text inside a text-ish control. */\n placeholder?: string;\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 /** `select` — the choices. Required, and a default must be one of them. */\n options?: string[];\n /** `group` / `table` — the sub-shape, nestable to 3 levels. */\n fields?: ComponentSubField[];\n /** `number` — bounds for the control. */\n min?: number;\n max?: number;\n step?: number;\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?: ContentModelFieldUi;\n}\n\n/** One field inside a `group` prop or a `table` row. Recursive, capped at 3 levels deep. */\nexport interface ComponentSubField {\n key: string;\n label: string;\n /** No `slot`: a nested component instance belongs on the prop itself, not inside a row. */\n // `slot` and `form` are reference-shaped props: they belong ON a prop, never inside a row of\n // one. A form in a table row would mean N form documents per component with no way to author\n // them — the second field model this design exists to avoid.\n type: Exclude<ComponentPropDef[\"type\"], \"slot\" | \"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 placeholder?: string;\n options?: string[];\n /** CANONICAL. A nested `group`/`table`'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?: string[] } & 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 * 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\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 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 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 * 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.\";\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: \"Other pages\", icon: \"files\", 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: \"newspaper\", sort: 0 },\n { id: \"fld_std_products\", parentId: null, name: \"Products\", icon: \"shopping-bag\", 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: \"file-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. **Other pages.** EVERY remaining standalone page goes in the system folder \\`home:pages\\`\n (\"Other 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.\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: … Other pages, Shared, Settings.\n8. **Icons** (lucide names): \\`newspaper\\` for posts, \\`shopping-bag\\` for products, \\`book-open\\`\n for docs, \\`files\\` for Other pages, \\`folder\\` by default.\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## 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] Other 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","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 */\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. \\`get_conversion_plan\\`. On a 404 \\`no-approved-plan\\`, call\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 (push, or \\`deploy_project\\`) and poll \\`get_deploy_status\\` until the release is live.\n8. \\`get_binding_report\\` must read \\`unmatched\\` 0 and \\`unaddressable\\` under 2% of each route's\n visible text. Fix what it names in the SOURCE, deploy, re-read (playbook section 11).\n9. \\`set_binding_mode { declaredBindings: true }\\`, deploy AGAIN and poll — the mode applies to the\n NEXT release — then confirm \\`get_binding_report\\` reads mode \"declared\", unmatched 0, bound\n above 0, \\`coverage.pending\\` empty. That report is your final answer to me.`;\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 (13): 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, **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\\` (models) / \\`add_page_field\\` (pages)\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 13\nabove, including nested group/repeater), required?. Confirm, then call:\n- a model → \\`add_field\\` { modelId, key, label, type, ... }\n- a page → \\`add_page_field\\` { pageId, key, label, type, ... }\nBoth are additive: they reject a key that already exists and never retype/overwrite\nan existing field (edit those in the dashboard).`;\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. 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 }. 'select' needs\n config.options; 'group'/'table' need config.fields; 'slot' holds ONE nested component;\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\\`, never 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 run \\`get_componentize_plan\\` → \\`componentize_sections\\`\n 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\\`; \\`required\\` / \\`helpText\\` / \\`placeholder\\` are editor hints, not write\n -time enforcement. \\`select\\` for styling-only variants, a separate component when the markup\n differs. Nesting is capped at two levels — flatten anything deeper.\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 \\`submit_section_manifest\\` → \\`submit_section_validation\\`), 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_components → 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, slug, 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, slug, 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\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 deploying an existing site: bring its content into the CMS so the visual editor can bind it, declare its presentation manifest, and publish everything that renders. A deploy 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. AUTHORING GATE — if any deploy answered 409 AUTHORING_DECISION_REQUIRED, ask ME\n components-or-fields (do not choose), then set_authoring_preference.\n2. CONTENT INTO THE CMS, per route: create_page (slug = route) -> add_page_field (or\n create_component + publish_component + component blocks) -> set_page_content with values\n EXACTLY equal to the rendered text (binding matches by value; a paraphrase binds nothing)\n -> update_page status 'published' (the canvas binds the PUBLISHED copy).\n3. 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.\n4. VERIFY — call get_next_steps and fix what it lists (it knows about missing manifests,\n content still only in the build, and placed-but-unpublished components), or tell me why\n an item is being left.\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: \"Declare how fields LOOK in the editor (guided)\",\n description:\n \"Set the authoring chrome on an existing schema — collapsed panels, what titles and thumbnails a repeater's rows, help text, conditional visibility. Derives it from your site's source where there is source, from the field shapes where there isn't, and only asks you about the three things it genuinely cannot know.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"scope, e.g. 'the Team and Testimonials models' or 'the whole project'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Declare the editor UI for my BetterCMS fields.${request ? ` Scope: \"${request}\".` : \"\"}\n\nRead bettercms://playbook/schema section 14 first — it has the exact prop shapes and the refusals.\n\n**What you are setting** (all of these ride on any field, on create_content_model / create_page /\nadd_field / add_page_field; none of them affect delivery):\n ui.collapsed start a nesting field's panel closed\n ui.preview {title,media} which CHILD FIELD KEY titles a collapsed row, and which is its thumb\n ui.layout 'list'|'grid'|'table' how its items are arranged; table is for repeatable row schemas; omit for list\n ui.reorderable omit (= true) unless the ORDER IS THE MEANING; false LOCKS the list\n helpText one line under the field: what to WRITE here\n showIf hide a field until another field has a value\n\n**The same \\`ui\\` rides on COMPONENT PROPS** — create_component / update_component, one per entry\nof \\`props\\`. Placement differs because the vocabulary does: preview/layout on 'group', 'table'\nand 'slot'; reorderable on 'table' ALONE (the only prop whose value is a list). A prop's preview\nkeys name a SUB-FIELD from its own config.fields. If this scope includes components, do them in\nthe same pass — but note update_component REPLACES the whole props array, so read get_component\nfirst and echo every prop back WITH its stored ui.\n\n**Work the three tiers in order. Stop at the first that answers — do not escalate what a tier\nbelow already settled.**\n\nTIER 1 — DERIVE FROM SOURCE, if and only if you have a checkout of the site.\n Read the component that renders each field. \\`<img src={item.photo}>\\` next to\n \\`<h3>{item.name}</h3>\\` in the map over a list IS the answer: preview {title:'name',\n media:'photo'}. A block inside \\`<details>\\` or behind a \"Show more\" is collapsed:true.\n A \\`grid-cols-*\\` wrapper around the map is layout:'grid'. A FIXED-ARITY render —\n steps[0]/steps[1]/steps[2], or copy that names positions (\"Step 1\", \"finally\") — is\n reorderable:false, and it is the ONLY evidence that earns that key.\n 🔴 THE SERVER NEVER READS YOUR SOURCE. \\`pull_project_source\\` / \\`get_conversion_brief\\` hand\n the repo to YOU; add_field does not look at it. This tier is your own reading, in your own\n checkout, before you call any tool. ON A GREENFIELD SCHEMA-FIRST PROJECT THERE IS NO SOURCE —\n Tier 1 does not apply and TIER 2 IS THE FLOOR. Do not stall waiting for code that will\n never exist.\n\nTIER 2 — DERIVE FROM THE FIELD SHAPE, when the code is silent or absent.\n One image-ish child in a repeater → that is \\`media\\`. The first required short-text child\n (name/title/heading/label) → that is \\`title\\`. More than ~6 children, or a label that reads\n optional (\"Advanced\", \"Extras\") → collapsed:true. A repeatable whose item is mostly its\n image (gallery, logos, team) → layout:'grid'; everything else stays list, so OMIT layout.\n \\`reorderable\\` has NO Tier-2 guess — leave it absent. The default is true, and locking a\n list the user did not ask to lock silently removes something they could do yesterday.\n GUESS HERE otherwise. A wrong preview costs one edit; a question per repeater costs the\n user the session.\n\nTIER 3 — ASK ME, and ONLY for these three. Batch them into ONE AskUserQuestion at the end,\n never one field at a time:\n a) A panel with MANY fields, where grouping and order depend on which content I treat as\n primary — you cannot infer my priorities.\n b) CONDITIONAL VISIBILITY (showIf) — it is business logic about when a field is irrelevant.\n Never invent a rule.\n c) VARIANTS SHARING A sectionType — their prop keys must match, or swapping the layout loses\n content. Confirm the shared key set before declaring per-variant chrome.\n\n**Order of work**\n1. \\`list_content_models\\` / \\`list_pages\\`, then \\`get_content_model\\` / \\`get_page\\` for each target.\n Note which fields ALREADY carry ui/helpText/showIf — do not overwrite a human's choice\n without asking.\n2. Decide each field's chrome by the tiers above. Write down which tier answered; you will\n report it.\n3. Apply. For a field that already exists, the declaration goes with the field: use the\n dashboard or a model update — \\`add_field\\` APPENDS and refuses an existing key, so it is\n the wrong tool for editing one. For a NEW field, pass ui/helpText/showIf in the same\n \\`add_field\\` / \\`add_page_field\\` call, and pass \\`after: '<existing key>'\\` if it belongs\n somewhere other than the bottom.\n4. **RECEIPT — non-negotiable.** Re-read every target with \\`get_content_model\\` / \\`get_page\\` /\n \\`get_component\\` and\n confirm the stored \\`ui\\` matches what you sent. A prop ABSENT from that response was NOT\n stored, whatever the write said. Report per field: the tier that decided it, what you set,\n and that the read-back confirmed it. Anything you could not confirm, say so plainly.\n\n**Refusals you should expect and must not work around:** an unknown key inside \\`ui\\` is a 400\n(it is strict on purpose — that is your typo, named); \\`ui.preview\\` or \\`ui.layout\\` on a leaf\nfield is a 400 (both describe ITEMS); \\`ui.reorderable\\` anywhere without a LIST is a 400 — a\n\\`group\\` and a non-repeatable zone hold one item, so only \\`repeater\\`, an \\`array\\` with\nconfig.zones.repeatable, and \\`modular\\` take it; a preview key that is not a child of that field\nis a 400 listing the valid child keys. Fix the declaration; never retry without it and call that\nsuccess.\n\nThere is deliberately NO \\`order\\` property and no mode to turn on — order is the array index,\nand \\`ui\\` only changes editor chrome, so there is nothing to flip.`,\n },\n },\n ],\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 at import, where the componentize lane in §10 reuses every field.\n\n## 2. The decision tree\n\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')\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 Site-wide nav/footer? -> place the project's provisioned components\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\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. 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.\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 were derived at\nimport — 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\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: [ nav, heading, { type:\"collection\", id:\"list\", props:{} }, footer ]\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\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\\`deploy_project\\`, \\`deploy_from_upload\\` and \\`promote_project\\` all 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\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 the import already derived.\n\n**Recommend \\`components\\`.** On a site whose pages were DERIVED at import — 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 site DERIVED at import the release hook has already run\n this plan in bind mode and PUBLISHED what it created, so\n expect ALREADY_COMPONENTIZED and skip to step 6 (publish the\n pages) — the lane publishes the COMPONENTS, not the placements,\n which are still draft blocks on the pages\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. npx @bettercms-ai/convert --componentize in the repo, so its templates render these\n sections from \\`pages[].blocks\\`\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\\`). 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_page_field 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:<sectionId>:<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 Three 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 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 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**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 — variant, size and icon are that block's own props and\n\\`style\\`, never a standalone Button component. 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.\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. Start from the\nbuiltin blueprints \\`list_components\\` returns (\\`builtin:*\\`) instead of hand-writing block JSON.\nOn a DERIVED site run \\`get_componentize_plan\\` → \\`componentize_sections\\` FIRST — it does most\nof this in one call, and on a site derived at IMPORT the release hook has already run it in bind\nmode and published the components, so expect ALREADY_COMPONENTIZED — the placements it wrote are\nstill DRAFT blocks on the pages, so publish the pages, then \\`npx @bettercms-ai/convert\n--componentize\\`.\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**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 is capped at TWO levels from the prop (a \\`table\\` row may hold a\n\\`table\\`, and that inner row is scalars only). Flatten anything deeper.\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 goes \\`submit_section_manifest\\` →\n\\`submit_section_validation\\`, 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_components everything the plan did not cover, ONE call, 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 submit_section_manifest -> submit_section_validation\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 deployed, so its schema and values were\nderived for you already → **Recipe A**. A 404 or an empty brief means the site is not in the CMS\nyet → **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_page_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 made editable from\nits 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: the\n server stores its \\`forms\\` block beside the binding receipt (coverage is untouched), 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.\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.\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_page_field\\` (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?}]}]}\\`; Sanity's row of plain strings, \\`rows:[{cells:[\"a\",\"b\"]}]\\`,\n is admitted too), \\`bcmsCode\\`, \\`bcmsDivider\\`, \\`bcmsMention\\`, 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 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 provisioned workflow\n writes \\`bcms-content.json\\` into the repo root before \\`build\\`, using the repo's\n \\`BCMS_API_KEY\\` secret. Read that file, with in-code fallbacks so a local or CI build\n without it still renders.\n - ARCHIVE (\\`deploy_project\\` / \\`deploy_from_upload\\`): 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**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\\`, \\`add_page_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\", \"reorderable\": true },\n \"helpText\": \"Three to five. Shortest quotes read best.\",\n \"fields\": [ { \"key\": \"author\", ... }, { \"key\": \"avatar\", \"type\": \"image\", ... }, ... ] }\n\\`\\`\\`\n\n- **\\`helpText\\`** — one line UNDER the field telling the author what to write here, not what the\n field is. \"Roughly 60 characters; it becomes the browser tab title\" earns its place.\n \"The title field\" does not.\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. Both\n slots name 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\n**Five 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.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.\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.\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**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. Declare, then read\nback, 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\\` /\n\\`add_page_field\\`; omit 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"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,YAAY,gBAAgB,wBAAwB;;;ACH7D,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;;;ACD1B,SAAS,yBAAyB;AAClC,SAAS,SAAS;;;ACoCX,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;AACF;;;AC/EO,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,E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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["s","list","z","z","DeviceAuthClient","loadConfig"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/tools.ts","../../types/src/component.ts","../../types/src/layout-lucide-icons.ts","../src/structure-playbook.ts","../src/prompts.ts","../src/playbook.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 } 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 { RECEIPT_FIRST_INSTRUCTION, SKILLS_ROUTING_INSTRUCTION, STRUCTURE_DEFAULT_INSTRUCTION, STRUCTURE_PLAYBOOK, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.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\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 RECEIPT_FIRST_INSTRUCTION + \" \" +\n \"When the user asks to make a site or all of its pages editable, to convert it, or to 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 // 🔴 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 — create_components, 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 \"BetterCMS never executes a customer's Section renderer or app code. An ordinary MCP connection is not a push runner: explicitly poll list_section_validation_requests, claim one request at an exact git commit, run implementation and responsive checks inside the user's own repository and real app shell, then submit manifest + validation with that requestId and complete it—or truthfully fail it when implementation/evidence is missing. Never invent a manifest, a passing validation, or visual evidence; these tools cannot grant the separate human Visual Approval required for publication. \" +\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,\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, Other 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 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) =>\n BetterCMS.management({ apiKey, baseUrl: deps.managementBaseUrl, ...(project ? { project } : {}) }),\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 { LAYOUT_SECTION_ICON_SET } from \"@bettercms-ai/types\";\nimport { DeviceAuthPendingError } from \"@bettercms-ai/device-auth\";\nimport { NEXT_STEPS_DESCRIPTION, STRUCTURE_PLAYBOOK_URI } from \"./structure-playbook.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): 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): 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 createClient: (apiKey: string, project?: 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 // 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]);\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, and underscores 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 }>;\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 /** 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\"; value: string | string[] }>;\n };\n /** Authoring chrome — how the field presents in the editor. @see backend baseField.ui */\n ui?: FieldUi;\n};\n\n/**\n * Shared by FIELDS and by component PROPS — one vocabulary, two lanes, so an agent that has\n * learned `ui` on a repeater already knows it on a `table` prop. @see backend fieldUiSchema.\n */\nexport type FieldUi = {\n collapsed?: boolean;\n preview?: { title?: string; media?: string };\n /** Absent ≡ \"list\". */\n layout?: \"list\" | \"grid\" | \"table\";\n /** Absent ≡ true. `false` locks the order of a list. */\n reorderable?: boolean;\n};\n\n/**\n * ONE `ui` vocabulary, TWO lanes — fields (`fieldShape.ui`) and component props\n * (`componentPropObject.ui`). The KEYS are identical on purpose: an agent that has learned `ui`\n * on a repeater already knows it on a `table` prop. WHERE each key is legal differs, because the\n * shapes do, so each use site carries its own outer `.describe()` naming its own rules — and the\n * server refuses the rest with a 400 that names the valid set.\n */\nconst uiObject = z.object({\n collapsed: z\n .boolean()\n .optional()\n .describe(\"start this panel collapsed. Use it for long optional sections.\"),\n preview: z\n .object({\n title: z.string().min(1).optional().describe(\"CHILD KEY whose value titles a collapsed row\"),\n media: z.string().min(1).optional().describe(\"CHILD KEY whose value is the row's thumbnail (image/file/url all work)\"),\n })\n .optional()\n .describe(\n \"how ONE ITEM summarises itself when collapsed. Both slots name a CHILD KEY of THIS field/prop — not a value, not a dotted path. 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\"])\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. Same placement rule as `preview`.\",\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});\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.\",\n ),\n label: z.string().min(1).describe(\"human label shown in the editor\"),\n type: fieldType,\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(z.union([z.string(), z.object({ label: z.string(), value: z.string() })]))\n .optional()\n .describe(\n \"choices when type is 'select'. A plain string, or {label, value} when the stored value differs from what the editor shows (e.g. {label:'Sold out', value:'soldOut'}).\",\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}, array {itemType: 'text'|'number'|'date'}, date {includeTime}, modular {blockSlugs: ['quote','gallery'], minItems?, maxItems?} — 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\",\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(\n \"one line of guidance shown UNDER this field in the editor — what to write here, not what the field is. Write it for the person typing ('Roughly 60 characters; it becomes the browser tab title'), not for a developer.\",\n ),\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\"]),\n value: z.union([z.string(), z.array(z.string())]),\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 and number. A clash is refused with 409 `unique_conflict`.\",\n ),\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.object({\n id: z.string().min(1),\n name: z.string().min(1).max(60),\n description: z.string().max(500).optional(),\n }),\n )\n .max(30)\n .optional()\n .describe(\n \"the model's editor cards: [{id, name, description?}], at most 30, ids unique, order = array index. `description` is one line under the card title. A field joins one with `fieldsetId`. Editor-only: never changes what is stored or delivered.\",\n );\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 * 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 // ⚠ 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};\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\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 };\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 return { ...base, type: \"array\", config: { zones: { repeatable: { fields: toFields(f.fields) } } } };\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 // add_page_field) inherits it from one place rather than four 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` is the project's brand kit: colors, typography, radius and any typeScale/spacing/elevation/motion/graphics. It is edited in the BetterCMS dashboard AND by set_brand_assets and set_brand_graphics below; every write is a version a person can restore. ASSETS: point `mark`/`favicon` at a media asset OF THIS PROJECT by id (another project's id is refused); null clears one; a slot a person chose needs `replace: true`. GRAPHICS: gradients are STRUCTURED — `kind`, optional `angle`, 2-8 stops naming kit colour keys (`colors.*` or an `extras` key) — never a CSS string and never a hex; a colour the kit lacks is added to `extras` first. CONSUME, DO NOT COPY: on a hosted page the kit is `--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) rather than copying its values into props. Never invent brand facts: read them here.\";\n\n/** update_content_model's optimistic lock. Mirrors the remote catalog's note word for word. */\nconst MODEL_IF_MATCH_NOTE =\n \"optimisticVersion from get_content_model. When sent, the update applies only if the model is still at that version; a 409 means someone changed it since — read it again and re-apply, never retry blindly. Omitted, the last write wins.\";\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.\";\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/** Said on get_content_structure; the other six carry STRUCTURE_FENCE. Mirrors the remote catalog. */\nconst STRUCTURE_NOTE =\n \"ORGANISATION ONLY: Content sidebar folders never change a URL, slug, content or publish state; URL folders (page folders) are set in the dashboard. Folders nest at most 4 levels deep. Icons are lucide icon names (a-z, 0-9, dashes); null clears one. SYSTEM FOLDERS: \\\"home:pages\\\" (Other pages), \\\"home:collections\\\" (Shared) and \\\"home:globals\\\" (Settings) always exist and can never be moved or deleted (400 NAV_SYSTEM_FOLDER); rename_folder and set_icon do work on them. TYPE PURITY (400 NAV_TYPE_MISMATCH): Other pages holds only pages at any depth, Shared only collections, and Settings neither — globals are not sidebar items. ACCESS: changing the structure needs Admin or Developer, the same as editing the schema; reading needs only content access. A 403 SCHEMA_ACCESS_REQUIRED means this connection is neither: stop and tell the user, do not retry. Pins sit above the folders, in their own order, and may be pages or collections. In a document a pin is folderId \\\"home:root\\\", a virtual id with no folder record (a folder record with that id is 400 NAV_SYSTEM_FOLDER). set_content_structure never refuses a kind mismatch: it returns `warnings` and `kindMismatches` (the single writes do — see `kind`). PAGE-BOUND MODELS: a page with fields has a model bound to it. That model is NOT a collection: it is never listed or filed, and the writes refuse it with 400 NAV_PAGE_BOUND_MODEL naming its page. Organise the PAGE instead, by its page id. \";\n\n/**\n * The same fence, one line, for the six tools that are not where the rules are STATED.\n *\n * The long note is 2.6k characters and it was pasted on all seven structure tools — 16k of\n * one paragraph in a catalogue an agent reads whole before it can speak. It stays on\n * `get_content_structure`, which is the call the standard itself tells an agent to make first,\n * and everything else points at it. Byte-identical in both catalogs: `mcp-text-parity` pins\n * 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. A resource is never truncated; a long description is.\";\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 \\u2014 the agent's equivalent of the dashboard's Import from GitHub, and the thing to do BEFORE writing any code for a user who already has a repo. It provisions the deploy workflow, the project API key and the build variables inside 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 one of this workspace's installations can already reach \\u2014 for anyone else's repository (a public starter, a template, another account's site) use fork_github_repo instead. Read `warning` / `contentWarning` / `actionsWarning` back to the user verbatim when they come back \\u2014 they are the cases where the repository connected perfectly and still 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 with the GitHub App's own credentials, so you need no clone, no remote and no 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_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, so there is no host CLI to run, no token to paste and no vercel.json rewrite to write; forms keep working because they post to the BetterCMS API. 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`) instead of creating another. `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\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/**\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 \"target project id (from list_projects); only for a workspace-wide grant.\",\n );\n\n/** Lift `projectId` onto a tool and bind it for the duration of the call. */\nconst withProjectId = (def: ToolDef): ToolDef => ({\n ...def,\n config: def.config.inputSchema.projectId\n ? def.config\n : { ...def.config, inputSchema: { ...def.config.inputSchema, projectId: projectIdArg } },\n handler: (args) => {\n const project = typeof args?.projectId === \"string\" && args.projectId ? args.projectId : undefined;\n return currentProject.run(project, () => def.handler(args));\n },\n});\n\n/**\n * 🔴 THE TAIL, COPIED FROM THE HOSTED CATALOGUE — Claude Desktop keeps a server's first ~100 tools\n * and silently drops the rest, and THIS is the surface Desktop loads. The hosted route partitions\n * its listing the same way (`LISTING_TAIL` in src/routes/mcp/index.ts); unordered, the stdio cut\n * dropped `get_next_steps`, the SEO lane, the binding/conversion lane and the GitHub lane.\n *\n * The package cannot import from `src/`, so the two lists are pinned identical by\n * src/__tests__/mcp/mcp-parity.test.ts. Every tool stays registered and callable either way.\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\", \"native_bridge_heartbeat\",\n // Section evidence and component validation: a CI lane, not an authoring one.\n \"claim_section_validation_request\", \"complete_section_validation_request\",\n \"fail_section_validation_request\", \"list_section_validation_requests\",\n \"submit_section_validation\", \"submit_section_manifest\", \"request_component_validation\",\n \"declare_component_route\", \"clear_component_source\", \"submit_componentize_receipt\",\n // Reporting, history and workflow chrome.\n \"get_analytics_overview\", \"get_analytics_top_pages\", \"list_activity\", \"get_workflow_board\",\n \"move_entry_stage\", \"move_page_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\", \"deploy_from_upload\",\n \"set_authoring_preference\", \"set_media_delivery\", \"delete_form_submission\",\n // The ABM campaign lane: a marketer's dashboard surface, plus the worker tools a task runner\n // claims with. Ten more tools than the tail was written for, and a connector that truncates\n // would otherwise lose `get_deploy_status` and the GitHub lane to make room for them.\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 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 try {\n return await fn(deps.createClient(token, project));\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));\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));\n }\n throw err;\n }\n }\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> }\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: heading {text, level}; text/richtext {html} (NOT {text}), and both also take level 1-6, rendering the html AS that <hN> with inline marks kept (one line of inline copy only) — use it for a title that carries a styled span; image {src, alt}; button {text, href}; spacer {height}; video {url}; form {formId}; component {componentId, overrides?}; navbar {links:[{label,href}], logo?, cta?}; footer {columns, copyright?}; section {children: block[]}; columns {columns: block[][], gap} — a column may NOT hold columns/section/slider/tabs; slider {slides:[{id,children}]}; tabs {tabs:[{id,label,children}]}; collection {cardComponentId?, detailComponentId?, titleField?, excerptField?, limit?, order?, emptyText?} — lists this page's published entries as cards, and renders ONE entry on /<page>/<entrySlug>\",\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. A real marketing band is a `section` block carrying bg + padding + contentWidth.\",\n ),\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 });\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 const nativeBridgeHeartbeatInput = z.object({\n protocolVersion: z.string().min(1).describe(\"executor protocol version; currently '1'\"),\n capabilities: z\n .array(z.string().min(1))\n .min(1)\n .describe(\n \"what this executor can do: any of inspect, propose, implement, cancel, question. Must include inspect, propose and cancel. An unknown value is refused, never ignored.\",\n ),\n session: z\n .object({ sessionId: z.string(), sessionEpoch: z.number().int().positive() })\n .optional()\n .describe(\"the `session` from the previous response; omit on first contact to reconnect\"),\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(),\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 });\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).describe(\"id of the content model to extend\"),\n ...fieldShape,\n after: afterArg,\n });\n\n const addPageFieldInput = z.object({\n pageId: z.string().min(1).describe(\"id of the page to extend (from list_pages / create_page)\"),\n ...fieldShape,\n after: afterArg,\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 to ingest; provide this OR localPath\"),\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 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 });\n\n const getPageInput = z.object({\n pageId: z.string().min(1).describe(\"page id (from list_pages / create_page)\"),\n });\n\n const setPageContentInput = z.object({\n pageId: z.string().min(1).describe(\"id of the page to write values to\"),\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 });\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 });\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([\"WebPage\", \"AboutPage\", \"ContactPage\", \"CollectionPage\", \"Blog\", \"BlogPosting\", \"Article\", \"Product\", \"FAQPage\", \"Event\", \"Organization\", \"LocalBusiness\"]).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 });\n\n const deletePageInput = z.object({\n pageId: z.string().min(1).describe(\"id of the page to delete (from list_pages)\"),\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\",\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 });\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; config.componentIds restricts what may\n // 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(z.string()).optional(), // 'select' — required, choices\n // 'group'/'table' sub-shape. Typed loosely here (the server validates the full\n // recursive shape) so a 3-level tree does not need a 3-level Zod mirror in the client.\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).optional().describe(\"hint shown under the control, muted (≤ 200 chars)\"),\n placeholder: z.string().max(120).optional().describe(\"ghost text inside a text-ish control (≤ 120 chars)\"),\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: uiObject\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' and 'slot' only; `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) => LAYOUT_SECTION_ICON_SET.has(value), \"Select a supported Lucide icon\")\n .describe(\"Lucide icon name in canonical kebab-case; legacy CamelCase Layout icon names 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\"]) }),\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() }),\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, e.g. 'Hero' — set this with a library category to make the component selectable in the page editor's 'Add a section' picker. Components sharing a sectionType 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 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, addressed by NAME (e.g. 'Sections', 'Navigation', 'Forms'). Resolved against this project's Groups and CREATED when missing, so a whole-site run can file everything without looking any id up first. Separate from `category`, which is the picker tab.\"),\n sectionType: sectionType.optional(),\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(),\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. 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.\",\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 allowedOn: allowedOn.optional().describe(\"REPLACES the placement allowlist\"),\n description: z.string().optional(),\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 });\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 });\n const createComponentsInput = z.object({\n components: z\n .array(createComponentInput)\n .min(1)\n .max(50)\n .describe(\"up to 50 components, each exactly the create_component input\"),\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(\"page id (from list_pages); or pass `slug`\"),\n slug: z.string().min(1).optional().describe(\"page slug, resolved against list_pages; 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 });\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 const sectionEvidenceProjectId = z\n .string()\n .min(1)\n .max(64)\n .describe(\"exact project id from get_project (not a slug); Section evidence is project-local and never reusable across projects\");\n const sectionId = z.string().uuid().describe(\"Section definition id from Section Studio\");\n const sectionVersion = z.number().int().positive().describe(\"exact Section schema version implemented or tested\");\n const sha256 = z.string().regex(/^[0-9a-f]{64}$/i, \"Expected a SHA-256 hex digest\");\n const sectionViewport = z.object({\n name: z.string().trim().min(1).max(64),\n width: z.number().int().min(240).max(7680),\n height: z.number().int().min(240).max(7680),\n });\n const sectionEvidenceDigest = z.string()\n .regex(/^(?:sha256:)?[0-9a-f]{64}$/i, \"Expected a SHA-256 digest\");\n const nonEmptyDescriptor = z.record(z.string(), z.unknown())\n .refine((value) => Object.keys(value).length > 0, \"Descriptor cannot be empty\");\n const sectionRequestId = z.string().uuid().describe(\"durable Section validation request id returned by list_section_validation_requests or the dashboard\");\n const sectionHttpUrl = z.string().url().max(2048).refine((value) => {\n try {\n const protocol = new URL(value).protocol;\n return protocol === \"http:\" || protocol === \"https:\";\n } catch {\n return false;\n }\n }, \"Expected an HTTP or HTTPS URL\");\n const sectionValidationViewport = sectionViewport.extend({\n status: z.enum([\"passed\", \"failed\"]),\n evidenceDigest: sectionEvidenceDigest,\n });\n const submitSectionManifestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId.optional().describe(\"include when fulfilling a claimed dashboard request so the evidence is bound to that exact run\"),\n sectionId,\n version: sectionVersion,\n apiId: z.string().regex(/^[a-z][A-Za-z0-9]*$/, \"Use lower camelCase\").max(100),\n schemaHash: sha256.describe(\"exact SHA-256 hex hash shown for this Section version\"),\n commitSha: z.string().regex(/^[0-9a-f]{7,64}$/i).describe(\"git commit containing the implementation\"),\n loader: nonEmptyDescriptor.describe(\"non-empty serializable loader descriptor emitted by the repo build; never executable code\"),\n previewAdapter: nonEmptyDescriptor.describe(\"non-empty serializable adapter descriptor for the customer's real app shell; never executable code\"),\n nativeViewports: z\n .array(sectionViewport)\n .max(20)\n .optional()\n .describe(\"the customer's named responsive viewports; BetterCMS also enforces Desktop 1440x900, Tablet 768x1024, and Mobile 390x844\"),\n });\n const submitSectionValidationInput = z.object({\n projectId: sectionEvidenceProjectId.describe(\"exact project id from get_project (not a slug); must match the manifest's project\"),\n requestId: sectionRequestId.optional().describe(\"same claimed request id used for the manifest; binds and terminalizes that run\"),\n sectionId: sectionId.describe(\"exact Section definition id\"),\n version: sectionVersion,\n manifestId: z.string().uuid().describe(\"manifest id returned by submit_section_manifest; it pins the schema hash and commit SHA\"),\n status: z.enum([\"passed\", \"failed\"]).describe(\"the actual result of the external repo/app-shell validation\"),\n fixtureHash: sha256.describe(\"SHA-256 hex hash of the canonical preview dataset and stress fixtures used\"),\n evidenceDigest: sectionEvidenceDigest\n .describe(\"SHA-256 digest of the immutable validation evidence bundle (screenshots/report/results)\"),\n appShell: z.object({\n kind: z.literal(\"actual-app\"),\n identifier: z.string().trim().min(1).max(255),\n url: sectionHttpUrl.optional(),\n }).describe(\"the real customer application shell used for the validation run\"),\n viewportResults: z.array(sectionValidationViewport).min(1).max(23)\n .describe(\"one signed result for every required and native manifest viewport\"),\n });\n const listSectionValidationRequestsInput = z.object({\n projectId: sectionEvidenceProjectId,\n limit: z.number().int().min(1).max(100).optional(),\n });\n const claimSectionValidationRequestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId,\n commitSha: z.string().regex(/^[0-9a-f]{7,64}$/i)\n .describe(\"exact git commit the agent will inspect and validate; evidence must use this same commit\"),\n providerRunId: z.string().trim().min(1).max(255).optional(),\n providerRunUrl: sectionHttpUrl.optional().describe(\"optional HTTP(S) link to the user's external agent run\"),\n });\n const completeSectionValidationRequestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId,\n manifestId: z.string().uuid().optional(),\n validationRunId: z.string().uuid().optional(),\n });\n const failSectionValidationRequestInput = z.object({\n projectId: sectionEvidenceProjectId,\n requestId: sectionRequestId,\n errorCode: z.string().trim().regex(/^[A-Z][A-Z0-9_]*$/).max(100),\n errorMessage: z.string().trim().min(1).max(2_000),\n providerRunId: z.string().trim().min(1).max(255).optional(),\n providerRunUrl: sectionHttpUrl.optional().describe(\"optional HTTP(S) link to the user's external agent run\"),\n });\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 or transcript. 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 }).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 }))),\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, and read the resource ${STRUCTURE_PLAYBOOK_URI} (the structure standard) before you organise anything. ${STRUCTURE_NOTE}`,\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 platform's own implementation of the standard over the project's pages, collections, their references and the routes its build serves: the home page and each collection's list page pinned at the top, one folder per content family named for the detail type its route holds (Blog posts, Case studies, Jobs, Products with its taxonomies and an Attributes subfolder for its variant options), ordered by entry count (or the site navigation, when the caller supplies its link order), shared taxonomies in Shared, every remaining standalone and code-only page in Other 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, lucide icons. 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(\"lucide icon name 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 (Other 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 lucide icon name, 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_FENCE}`,\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: Other 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_FENCE}`,\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 (Other 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. The asset must already be in this project's media library — upload it first if it is not. null clears a slot. A slot a PERSON chose is refused unless you pass replace: true, and the refusal says so. Every write is a brand version the dashboard can restore. ${BRAND_KIT_NOTE}`,\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 gradient is a value, so it is stored as a kind, an angle and stops that name the kit's own colour keys, never as CSS and never as a hex. A stop naming a colour the kit does not have is refused; add it to extras first. Upsert matches BY KEY. ${BRAND_KIT_NOTE}`,\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_FENCE}`,\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(\"lucide icon name, e.g. 'file-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_FENCE}`,\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\"]).optional(), 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), redirectType: z.enum([\"301\", \"302\", \"307\", \"308\"]).optional() }).shape,\n async (c, a) => ok(\"Created redirect.\", await data(c, \"POST\", `/management/redirects`, { sourcePath: a.sourcePath, destination: a.destination, redirectType: a.redirectType }))),\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(\"get_seo\", \"Get site SEO\",\n \"Get the connected project's site-wide SEO settings — default meta (title/description/ogImage), JSON-LD siteSchema, and robots/sitemap/rss config.\",\n z.object({}).shape,\n async (c) => ok(\"SEO settings.\", await data(c, \"GET\", `/management/seo`))),\n def(\"update_seo\", \"Update site SEO\",\n \"Set site-wide SEO defaults. `seoDefaults` { metaTitle, metaDescription, ogImage, twitterHandle } applies to every page unless overridden. Optionally robotsConfig / sitemapConfig / rssConfig. Each field is REPLACED whole. Rebuilds the site.\",\n z.object({ seoDefaults: z.record(z.string(), z.unknown()).optional(), siteSchema: z.record(z.string(), z.unknown()).optional(), robotsConfig: z.record(z.string(), z.unknown()).optional(), sitemapConfig: z.record(z.string(), z.unknown()).optional(), rssConfig: z.record(z.string(), z.unknown()).optional() }).shape,\n async (c, a) => ok(\"Updated SEO.\", await data(c, \"PATCH\", `/management/seo`, a))),\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_entry_stage / move_page_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_entry_stage\", \"Move a content entry across the board\",\n \"Move a content entry to another editorial stage — this is how you get an entry OUT of review so it can be published. `workflowStage` is a stage key from get_workflow_board (null clears it). Optionally set `workflowAssigneeIds` / `workflowDueDate`, or pass `fromStage` to fail with 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 status:'published' — approving and publishing are deliberately two separate calls.\",\n z.object({ entryId: z.string().min(1), workflowStage: z.string().max(64).describe(\"stage key from get_workflow_board\"), fromStage: z.string().max(64).optional().describe(\"the stage you believe it is in — 409s if it has moved\") }).shape,\n async (c, a) => ok(\"Moved entry.\", await data(c, \"PATCH\", `/management/content/entries/${s(a.entryId)}/workflow`, { workflowStage: a.workflowStage, fromStage: a.fromStage }))),\n def(\"move_page_stage\", \"Move a page across the board\",\n \"Move a page to another editorial stage — the page twin of move_entry_stage, and the only way to take a page out of review so update_page (status:'published') can go live. `workflowStage` is a stage key from get_workflow_board. Moving into the publish-gate stage is an approval and needs a publish-enabled connection.\",\n z.object({ pageId: z.string().min(1), workflowStage: z.string().max(64).describe(\"stage key from get_workflow_board\"), fromStage: z.string().max(64).optional().describe(\"the stage you believe it is in — 409s if it has moved\") }).shape,\n async (c, a) => ok(\"Moved page.\", await data(c, \"PATCH\", `/management/pages/${s(a.pageId)}/workflow`, { workflowStage: a.workflowStage, fromStage: a.fromStage }))),\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 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. `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\") }).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, deploy_from_upload and promote_project all refuse with 409 AUTHORING_DECISION_REQUIRED until it is set, and that refusal carries this project's real page counts to show the user. 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. Recommend components unless the user says the site is schema-first. 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 works once (at import, when the CMS values equal the built copy) and breaks the first time anyone edits a value. Call it ONLY after every page's copy is declared in the template: undeclared fields stop being editable. The order is push → release → get_binding_report shows mode 'text-match' with 0 unmatched → set_binding_mode → release again → get_binding_report shows mode 'declared'. Flipping back is the same call. REQUIRES the artifact:write scope — the same authority that deploys the site — because 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. See section 13 of the bettercms://playbook/schema resource.\",\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` wrote (`--receipt out.json`) for the SAME `briefDigest` get_conversion_brief { complete: true } returned: `{ briefDigest, receipt }`, where the receipt carries `paths: { declared, rewritten, alreadyDeclared, pending[{ route, scope, path, kind, file, reason, message, fix }] }`. `paths.declared` must equal rewritten + alreadyDeclared + pending.length, and each pending `reason` is one of the converter's own (IN_EXPRESSION, AMBIGUOUS_LITERAL, REPEATER_FIXED_LENGTH, PARSE_ERROR, …) — a path with no receipt row simply reads `not-declared`. 🔴 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, file, line, col?, snippet, why?, kind? }`. `action` is `wrap-span`, `declare-attr`, `bind-expression`, `declare-richtext`, `bind-data` or `manual`; each row's `snippet` and `why` say what to change there. On a `declare-richtext` with `kind: document`, bind the ONE element wrapping every block of the Body, never the paragraph holding its first. Apply every fix, rerun, resubmit. `complete: true` is the only receipt that ends a conversion; do not report a site converted on less. It is a RECORD, not a release: it changes nothing about the site, and the meter picks it up on the next get_binding_report after the next deploy. A 404 `unknown-brief` means that digest was never issued here. 🔴 SUBMIT THE `--forms` RECEIPT TOO, AS A SECOND CALL: A `npx @bettercms-ai/convert --forms` run writes a receipt whose `paths` are all zero and whose account is in a `forms` block. Write it to its own file (`--receipt forms-receipt.json`) and submit it under the same `briefDigest`: stored beside the binding receipt, never counted in coverage. Then read `forms.pending` and publish every form it names. 🔴 THE SITE'S DESIGN IS NOT YOURS TO CHANGE: run `npx @bettercms-ai/convert --verify-styles --base <commit before the conversion> --root .` and include its `styleEdits` in the receipt. A receipt listing any changed class, className or style is refused with 409 `style-edits` and every token — restore them; the CMS keeps inline markup exactly as written. Requires artifact:write, the same authority as set_binding_mode.\",\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.\"),\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 def(\"create_template\", \"Save a project/page as a template\",\n \"Save a project (or one page) as a REUSABLE template — a frozen snapshot of its content models, pages, entries, components, and forms (secrets/domains/analytics excluded). Later seed a new project from it with create_project { templateId }. Set visibility 'public' to list it in the cross-workspace gallery. Returns the new template's id.\",\n z.object({ sourceProjectId: z.string().min(1), name: z.string().min(1), scope: z.string().optional(), sourcePageId: z.string().optional(), description: z.string().optional(), visibility: z.string().optional() }).shape,\n async (c, a) => ok(\"Created template.\", await data(c, \"POST\", `/management/templates`, a))),\n def(\"list_templates\", \"List saved templates\",\n \"List your workspace's saved templates (id, name, scope, visibility). Use a template's id as create_project { templateId } to seed a new project from it.\",\n z.object({}).shape,\n async (c) => ok(\"Templates.\", await data(c, \"GET\", `/management/templates`))),\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.\",\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 \"Rename a content model, edit its description/slug/urlPattern, or set its `fieldsets`. Never touches `fields`: use add_field to extend the schema. Provide modelId plus what to change. `fieldsets` REPLACES the list (send null to drop them all); then put a field in one with add_field's `fieldsetId`. `urlPattern` is the collection's entry URL, e.g. '/blog/:slug' (null clears it). A slug already used in this project and branch is refused with 409 `slug_taken`.\",\n z.object({ modelId: z.string().min(1), name: z.string().optional(), slug: z.string().optional(), description: z.string().optional(), urlPattern: urlPatternArg, fieldsets: fieldsetsArg.nullable(), ifMatch: z.number().int().min(0).optional().describe(MODEL_IF_MATCH_NOTE) }).shape,\n // `fields` is deliberately not sent: the PATCH replaces `fields` wholesale when present.\n async (c, a) =>\n ok(\n \"Updated content model.\",\n (\n await c.fetchJSON<{ data?: unknown }>(c.url(`/management/content/models/${s(a.modelId)}`), {\n method: \"PATCH\",\n body: JSON.stringify({ name: a.name, slug: a.slug, description: a.description, urlPattern: a.urlPattern, fieldsets: a.fieldsets }),\n ...(a.ifMatch !== undefined ? { headers: { \"if-match\": `W/\"${a.ifMatch}\"` } } : {}),\n })\n ).data,\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(\"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 it REPLACES the whole array, so read get_page first). A `blockJson` that swaps a component block to another component comes back with `warnings` (COMPONENT_SWAP_DROPS_OVERRIDES) naming the overrides the new component does not render; they stay on the block, so swapping back restores them. It does NOT change the field SCHEMA — use add_page_field / set_page_content for that. Renaming the slug keeps content intact. Publishing copies the draft blocks live in the same call — and on a singleton it publishes the page's content entry too; if the entry's workflow stage refuses, the page still goes live and `warnings` carries ENTRY_STILL_DRAFT with the entry id and the reason. STRUCTURED DATA is native SEO, never a field: leave it out and the page gets Automatic JSON-LD from its content (WebSite on the home page, Blog/CollectionPage on a collection's list page, WebPage otherwise); `schemaType` picks an explicit schema.org type whose properties are filled from the content; `schema` is pasted JSON-LD and wins over both (null clears it). \" + 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), title: z.string().optional(), slug: z.string().optional(), blockJson: z.array(blockObject).optional().describe(\"REPLACES the page's block composition\"), metaTitle: z.string().optional(), metaDescription: z.string().optional(), schemaType: z.enum([\"auto\", \"WebPage\", \"AboutPage\", \"ContactPage\", \"CollectionPage\", \"Blog\", \"BlogPosting\", \"Article\", \"Product\", \"FAQPage\", \"Event\", \"Organization\", \"LocalBusiness\"]).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() }).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 const res = await c.fetchJSON<{ data?: unknown; redirectNote?: { source: string; existingDestination: string }; warnings?: string[] }>(\n c.url(`/management/pages/${s(a.pageId)}/meta`),\n {\n method: \"PATCH\",\n body: JSON.stringify({ title: a.title, slug: a.slug, blockJson: a.blockJson, 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 }),\n },\n );\n const note = res.redirectNote;\n const summary = note\n ? `Updated page. 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 : \"Updated page.\";\n return ok(res.warnings?.length ? `${summary}\\n${res.warnings.join(\"\\n\")}` : summary, 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`: 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) BEFORE creating the archive: a source deploy is reinstalled and built server-side, so those are never needed, and the upload has a hard size ceiling (~100 MB) enforced before the request reaches the server — an archive that includes node_modules is rejected in transit (a 413/502 with no server-side detail). Keep the archive to your own source files. Server-side stripping exists as a safety net, but it runs AFTER the upload and cannot rescue an over-limit body. For a LARGE archive (or if this returns a 413/502), use create_deploy_upload + deploy_from_upload instead — that path uploads straight to storage with no size ceiling. Returns `canvas.lane` — which live-preview lane the last release gave the editor (`bridge` / `draft-route` / `none`; see the playbook's section 11) — 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({ data: z.string().min(1).describe(\"base64 .tgz/.zip of the project\"), mimeType: z.string().optional() }).shape,\n async (c, a) => ok(\"Deploy queued.\", await raw(c, `/management/projects/deploy`, s(a.data), a.mimeType as string | undefined))),\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_from_upload 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 def(\"deploy_from_upload\", \"Deploy from a staged upload\",\n \"Deploy from an archive already uploaded via create_deploy_upload (step 3). Pass the `uploadKey` you received. Builds SOURCE server-side or serves a prebuilt site — then poll get_deploy_status until live.\",\n z.object({ uploadKey: z.string().min(1).describe(\"the uploadKey from create_deploy_upload, after PUTting the archive to its uploadUrl\") }).shape,\n async (c, a) => ok(\"Deploy queued.\", await data(c, \"POST\", `/management/projects/deploy/from-upload`, { uploadKey: a.uploadKey }))),\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(\"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.\",\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_changes\", \"Get changes since a timestamp\",\n \"Read the durable project change feed since an ISO timestamp. Call this at the start of a new turn to notice dashboard or agent edits made since your previous observation.\",\n z.object({ since: z.string().datetime(), limit: z.number().int().min(1).max(100).optional() }).shape,\n async (c, a) => ok(\"Project changes.\", await data(c, \"GET\", `/management/insights/activity${q({ since: a.since, limit: a.limit ?? 100 })}`))),\n def(\"get_next_steps\", \"Get what to do next\",\n NEXT_STEPS_DESCRIPTION,\n z.object({}).shape,\n // The whole body: `receipt` rides beside `data`, and `data()` would drop it.\n async (c) => ok(\"Next steps.\", await c.fetchJSON(c.url(`/management/insights/next-steps`), { method: \"GET\" }))),\n def(\"get_binding_report\", \"Check what on the live site is editable\",\n \"The receipt for 'is this site actually EDITABLE?'. Every release scans the built HTML for the element that renders each CMS field value; this returns what that scan found, per slot: `mode` ('text-match' = bindings guessed from rendered text, 'declared' = the template declares them), what was bound, and `unmatched` — each path with the reason it failed (not-declared / ambiguous-text / no-element). DEPLOY FIRST: before any release there is no report (pages 0, mode null, refreshRequired true). `refreshReason` says which: `never-generated` — only a release BetterCMS builds and serves writes a report, so a HEADLESS site never gets one and redeploying will not change it (verify that site by fetching it); `outdated` — the next release rewrites it. It certifies one thing: every non-empty field has SOME element carrying its path. It cannot see copy that was never modelled, so diff each route's visible text against its entry values yourself before calling a page done. `builtRoutes` lists the routes the live build has HTML for, or null when it cannot say. `canvas.lane` names the live-preview lane this build gives the editor — `bridge`, `draft-route` or `none`, in which case get_next_steps carries the recipe (playbook section 11). `unaddressable` counts visible text on the live site that no field owns — the one thing `unmatched` structurally cannot see, because it only ever speaks about fields that already exist. EVERY release measures it server-side on every inspected page and the result names the routes, their countable characters and the buckets the unowned text sits in, biggest first. Anything over `count / visible > 0.02` is copy the CMS cannot see: fix it in the SOURCE (wrap the run in an element the codemod can bind, or declare `<BcmsField path=…>`), deploy, re-read — playbook section 11 has the loop. `skipReasons` says why pages were not inspected; `coverage.error` = `nothing-bound` means not one element of this build carries a binding, so the percentage beside it describes a site this build is not.\",\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.\") }).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, and every bindable field path with its `label`, `kind`, the value the CMS holds now (`current`) and the copy the repo renders today (`original`, the field's defaultValue) — plus 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_page_field / create_content_model would build a second schema over the first — edit values with set_page_content instead. `lane` says how to get the source ('git-connected' = pull_project_source returns a repo; 'archive' = a tarball). The full recipe is section 13 of the bettercms://playbook/schema resource; get_binding_report is the receipt that says you finished. Pass `complete: true` when you are about to run the CODEMOD (`npx @bettercms-ai/convert`): that returns the brief UNCAPPED and paged — nothing truncated, no page omitted — and pins the full path list under a `briefDigest`, which is the list the coverage meter in get_binding_report measures the build against. Follow `cursor` until it stops coming back; a 409 `BRIEF_CHANGED` means the brief was re-derived while you paged, so start again. The complete brief also carries `forms` — every form of this project with its id, status, fields and submitUrl — which is what `npx @bettercms-ai/convert --forms --brief brief.json --root . --receipt forms-receipt.json` wires into the repository's own <form> elements; run it after the binding pass, read its `forms.pending`, and publish every form its `forms.notes` names in the Forms tab (a draft form rejects every submission with a 403).\",\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 — a plan applied to a different base is a different change), 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 rather than applying it anyway. `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. Finish the loop the same way as a hand conversion — 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, nothing is written. Call it at the START of a whole-site componentize run (playbook §12) for the before picture, and at the END as the proof. Per page: `kind` ('blocks' | 'fields-only' | 'empty'), a block census, `nonComponentBlocks` (loose TOP-LEVEL bands the editor's section lane cannot outline), and every `component` placement with the component's `status` ('published' | 'draft' | 'missing' — a draft renders as an EMPTY STRING on the live site), whether it is `inPicker` (a component with no sectionType is dropped from 'Add a section'), and any `emptyRequiredProps` — `required` is an editor hint the write path does not enforce, so this read is the only thing that reports it. Site-wide: `components` counts published/draft, `awaitingEvidence` and `awaitingApproval` (evidence is exact and a HUMAN must approve it in the BetterCMS dashboard — no tool here can grant that, and there is no bulk approve), plus `notInPicker` and `unused` ids; `layout.placements` is the chrome placed in the Global Layout draft. `verdict.everyPageComposed` with `verdict.reasons` is the answer to give the user. Pages are read DRAFT-inclusive, so a page composed but not yet published still shows its placements — 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, changes nothing and is computed live on every call. For a site whose pages were DERIVED at import (the site get_conversion_brief describes), each top-level field GROUP is one section: `hero-*` and `faq-*` keys, and the repeaters the import already folded (`group-*`). Per page it returns each section's `groupKey`, its `sectionType` family (Hero, FAQ, CTA, Features, Social proof…), its leaf `fields` (key, path, type, the value the CMS holds), a `shapeHash`, and either the component that already renders it (`reuse.componentId`) or the one this plan proposes (`reuse.proposedSlug`) — and the components themselves under `components`: a NEW one carries the exact `props` and `blockJson` create_component would take, while a row for a component that ALREADY EXISTS carries its `componentId`, `slug` and `name` and no definition, because nothing will be written for it. Groups with the SAME shape across pages collapse into ONE component with several placements. `pending` says why a group is not offered: `NO_GROUP_ROOT` (the page's field keys are still the derive lane's own — `h1-welcome`, `p-we-build-things` — so there is no family to group by; rename them into families first), `NOT_A_SECTION` (a lone scalar with no family, or the page's own metadata — a section is a group field, a repeater, or a family two or more leaves share, so a legal page of `title`/`metaDescription`/`intro` proposes nothing), `ALREADY_COMPONENTIZED`, `EMPTY_GROUP`, `NESTED_REPEATER` (a repeater THREE deep; TWO levels are expressed exactly — the group's `table` prop gains a nested `table` sub-field, and each row's nested column is an array of row objects), `PAGE_NOT_EMPTY` (the page holds blocks this lane does not own and will not overwrite). Chrome is NEVER a section: `nav-`/`footer-` keys and everything promoted into the project Layout are edited through the Layout. Keep the `digest` — componentize_sections refuses any other.\",\n z.object({}).shape,\n async (c) => ok(\"Componentize plan.\", await data(c, \"GET\", `/management/projects/current/componentize-plan`))),\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 and say how many components it will create and which pages it will rewrite. It creates each proposed component as a DRAFT and replaces each page's DRAFT blocks with an ordered list of `component` instances — one per group, each carrying `props.bind: \\\"<groupKey>\\\"`, which points at the page field group that already holds the copy. So nothing is copied and nothing moves: the page keeps its `fields`, its values and its bindings, click-to-edit keeps working and the coverage meter does not change. Pass the plan's `digest`; a 409 `stale-plan` means the site changed since you read that plan, so read it again, show the user what changed and confirm again. Read its `components.wouldDuplicate` before applying: each id is an existing component of the same family this run would sit a NEW one beside, because reuse is by identity and slug, never by family. Running it twice is safe: a group that already has a placement comes back in `sections.pending` as ALREADY_COMPONENTIZED and no second component is created. DRAFTS ONLY — an unpublished component renders as an EMPTY STRING on the live site, so publish_component each one and publish the pages before this reaches a visitor. Then run `npx @bettercms-ai/convert --componentize` in the repo so its templates render these sections from `pages[].blocks`. The default `bind` is the above: the words stay in the page's field group. `copy: \\\"instance\\\"` moves the words onto each placement and marks the page's fields `origin: \\\"componentized\\\"` — kept, never deleted (see `copy`). Every component it CREATES is filed into a Component Group (the folders of the dashboard's Components tab): the one you name in `group` (found or created), else its section family — nav, header, footer or menu → Layout, an unnamed section → Sections, otherwise the family name (Hero, FAQ). A component it reuses keeps the Group it has; the receipt's `components.groups` lists the Groups it filed into.\",\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 on the page keeps the placement it already has.\"),\n copy: z.enum([\"bind\", \"instance\"]).optional().describe(\"Who owns each section's copy. 'bind' (default) leaves it in the page fields. 'instance' is the page-builder model: each placement takes that group's CURRENT draft values into its own `props.overrides` (a repeater becomes one table prop holding every row), records which page path each came from in `props.source`, and drops `props.bind`; the page's fields are KEPT and marked `origin: \\\"componentized\\\"`, so nothing is lost and the editor stops showing a second place to type the same words.\"),\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). Omit to file each under its section family.\"),\n }).shape,\n async (c, a) => ok(\"Componentized the sections.\", await data(c, \"POST\", `/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 }))),\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, absent schema) and return them with severities. 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 def(\"list_section_validation_requests\", \"List queued Section validation requests\",\n \"Poll for user-agent Section implementation-validation requests in this exact project. BetterCMS cannot push work into an ordinary MCP client: call this explicitly, claim one request, inspect and run the customer's real repository/app shell, then submit request-bound evidence and complete it. Returns only unclaimed user-agent requests; it never exposes another project.\",\n listSectionValidationRequestsInput.shape,\n async (c, a) => ok(\"Queued user-agent Section validation requests.\", await data(\n c,\n \"GET\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests${q({ limit: a.limit })}`,\n ))),\n def(\"claim_section_validation_request\", \"Claim a Section validation request\",\n \"Atomically claim one queued user-agent request and pin the exact git commit you will inspect. Claim BEFORE submitting evidence. BetterCMS records coordination only; all customer code and responsive checks must run in the user's repository and real app shell.\",\n claimSectionValidationRequestInput.shape,\n async (c, a) => ok(\"Section validation request claimed.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests/${s(a.requestId)}/claim`,\n {\n commitSha: a.commitSha,\n providerRunId: a.providerRunId,\n providerRunUrl: a.providerRunUrl,\n },\n ))),\n def(\"complete_section_validation_request\", \"Complete a Section validation request\",\n \"Complete a claimed request only after submit_section_manifest and submit_section_validation have bound exact, passed evidence to the same requestId and pinned commit. This cannot grant the separate human Visual Approval.\",\n completeSectionValidationRequestInput.shape,\n async (c, a) => ok(\"Section validation request completed.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests/${s(a.requestId)}/complete`,\n { manifestId: a.manifestId, validationRunId: a.validationRunId },\n ))),\n def(\"fail_section_validation_request\", \"Fail a Section validation request\",\n \"Truthfully close a claimed request when the renderer, validation command, app shell, or required evidence is missing or fails. This path intentionally works without a manifest so 'not implemented' is representable instead of being reported as passed or left queued forever.\",\n failSectionValidationRequestInput.shape,\n async (c, a) => ok(\"Section validation request failed.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/implementation-requests/${s(a.requestId)}/fail`,\n {\n errorCode: a.errorCode,\n errorMessage: a.errorMessage,\n providerRunId: a.providerRunId,\n providerRunUrl: a.providerRunUrl,\n },\n ))),\n\n def(\"submit_section_manifest\", \"Submit a Section implementation manifest\",\n \"Record the implementation manifest produced for one exact Section schema version by CI or an agent running INSIDE the user's repository. BetterCMS does not execute customer code: inspect/build the real renderer in the user's app shell first, then submit its exact API ID, schema hash, commit SHA, loader, preview adapter, and native responsive viewports. Requires a project-scoped artifact:write credential. This records evidence only; it does not validate the implementation and cannot create human Visual Approval.\",\n submitSectionManifestInput.shape,\n async (c, a) => ok(\"Section implementation manifest recorded.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/sections/${s(a.sectionId)}/versions/${a.version}/manifests`,\n {\n requestId: a.requestId,\n apiId: a.apiId,\n schemaHash: a.schemaHash,\n commitSha: a.commitSha,\n loader: a.loader,\n previewAdapter: a.previewAdapter,\n nativeViewports: a.nativeViewports,\n },\n ))),\n def(\"submit_section_validation\", \"Submit a Section validation result\",\n \"Record a real validation result for one exact Section schema version and manifest. Run the component in the user's repository and real app shell across the canonical preview dataset, AI stress fixtures, and required/native viewports BEFORE calling this tool; BetterCMS never runs that customer code. Pass status 'passed' only when those checks actually passed, otherwise 'failed'. The manifest pins schemaHash and commitSha; fixtureHash and evidenceDigest pin the tested data and immutable evidence bundle. Requires project-scoped artifact:write and cannot create the separate human Visual Approval required for publication.\",\n submitSectionValidationInput.shape,\n async (c, a) => ok(\"Section validation result recorded.\", await data(\n c,\n \"POST\",\n `/projects/${s(a.projectId)}/section-evidence/sections/${s(a.sectionId)}/versions/${a.version}/validations`,\n {\n requestId: a.requestId,\n manifestId: a.manifestId,\n status: a.status,\n fixtureHash: a.fixtureHash,\n evidenceDigest: a.evidenceDigest,\n appShell: a.appShell,\n viewportResults: a.viewportResults,\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|categorizing|failed), whether it's publishing, the live commit sha, when it went live, and any build error. `categorizing` means the bytes are live but the import's setup lanes (content, pages, bindings) are still running, so `publishing` is still true and the site is not ready to edit yet. Poll this after deploy_project until state is idle with your sha live. Also returns `canvas.lane` (the editor's live-preview lane for this site: `bridge` / `draft-route` / `none`) and `editorUrl`, the visual editor to hand the user.\",\n z.object({}).shape,\n async (c) => ok(\"Deploy status.\", await data(c, \"GET\", `/management/projects/deploy-status`))),\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_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 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_page_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 pageType: p.pageType,\n status: p.status,\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 by id INCLUDING its full field schema (keys, types, nested group/repeater children) and pageType. Read this before set_page_content so you write correctly-keyed values, or before add_page_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 });\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). `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 model = await client.createModel({\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: args.fieldsets } : {}),\n fields: toFields(args.fields) as CreateModelInput[\"fields\"],\n });\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\",\n description:\n \"Append a field to an existing content model. Reads the model's current fields and adds yours (read-modify-write) — never removes existing fields. For a section/zone, add ONE 'group' (fixed block) or 'repeater' (repeating list) field carrying its child `fields` — don't add the zone's inner fields as separate top-level fields. `fieldsetId` puts it in one of the model's fieldsets (set them with update_content_model). \" +\n RICH_TEXT_NOTE,\n inputSchema: addFieldInput.shape,\n },\n handler: guard(async (args: z.infer<typeof addFieldInput>) =>\n withClient(async (client) => {\n const model = await client.getModel(args.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 const updated = await client.updateModel(args.modelId, {\n fields: nextFields as Parameters<typeof client.updateModel>[1][\"fields\"],\n });\n return ok(\n `Added field '${args.key}' to '${updated.name}'${args.after ? ` after '${args.after}'` : \"\"}. Model now has ${updated.fields.length} field(s).`,\n updated,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"add_page_field\",\n config: {\n title: \"Add a field to a page\",\n description:\n \"Append a field to an existing page's schema (Home, About, a blog template, etc.). Additive — the API rejects a key that already exists and never overwrites or retypes existing fields. Use this when the target is a page (singleton or dynamic); use add_field when the target is a content model. For a section/zone, add ONE 'group' (fixed block) or 'repeater' (repeating list) field carrying its child `fields` — don't add the zone's inner fields as separate top-level fields.\",\n inputSchema: addPageFieldInput.shape,\n },\n handler: guard(async (args: z.infer<typeof addPageFieldInput>) =>\n withClient(async (client) => {\n // No client-side preflight here on purpose. `addPageFields` is an additive PATCH onto\n // the page-fields route, which now refuses a NEW flat-namespace collision itself — so a\n // check here would be a second authority AND an extra round-trip, and the two could\n // drift. `add_field` keeps its check only because it already fetches the model.\n // `after` rides to the route (this tool does NOT read the page first, by design —\n // see the note above), which does the splice under the same lock it already takes.\n const page = await client.addPageFields(args.pageId, {\n // Cast: same as create_page. The SDK types `options` as string[], narrower than the\n // API, which also takes {label, value} (backend selectFieldSchema).\n addFields: [toField(args)] as AddPageFieldsInput[\"addFields\"],\n ...(args.after !== undefined ? { after: args.after } : {}),\n });\n return ok(\n `Added field '${args.key}' to page '${page.title}'. Page now has ${page.fields.length} field(s).`,\n page,\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. 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.\",\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 created = await client.createEntry({\n contentModelId: args.contentModelId,\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.data !== undefined ? { data: args.data } : {}),\n });\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 [`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. Read the schema first with get_page. This is how you populate Home/About/Settings — create_content_entry is for dynamic collections only.\",\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 });\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. 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.\",\n inputSchema: listEntriesInput.shape,\n },\n handler: guard(async (args: z.infer<typeof listEntriesInput>) =>\n withClient(async (client) => {\n const entries = await client.listEntries({\n ...(args.modelId ? { modelId: args.modelId } : {}),\n ...(args.pageId ? { pageId: args.pageId } : {}),\n ...(args.status ? { status: args.status } : {}),\n });\n return ok(`${entries.length} entr(y/ies).`, entries);\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. Use this to edit an existing entry; for a singleton page prefer set_page_content. 🔴 `data` REPLACES the entry's whole value object: an optional field you leave out is DELETED, and a required one you leave out fails the whole write. To change one field, read the entry (get_content_entry), change that key, and send the whole object back. \" + ENTRY_META_NOTE,\n inputSchema: updateEntryInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateEntryInput>) =>\n withClient(async (client) => {\n const { warnings, ...entry } = await client.updateEntry(args.entryId, {\n ...(args.data !== undefined ? { data: args.data } : {}),\n ...(args.status !== undefined ? { status: args.status } : {}),\n ...(args.slug !== undefined ? { slug: args.slug } : {}),\n ...(args.meta !== undefined ? { meta: args.meta } : {}),\n });\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. 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 = 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 inputSchema: deletePageInput.shape,\n },\n handler: guard(async (args: z.infer<typeof deletePageInput>) =>\n withClient(async (client) => {\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. 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.\",\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) so the live site builds from it. Until this is called the layout stays draft and get_layout copy:'published' answers PUBLISHED_LAYOUT_UNAVAILABLE — site chrome authored with update_layout is NOT live. Read get_layout first and pass its revision as ifMatch; a stale revision returns 409 — re-read, never retry blindly. A 422 lists validation issues to fix with update_layout first. A new project's chrome is draft: publish_component navigation-default and footer-default first (each can publish while the other is draft), then publish_layout. navigation.logo is a REQUIRED image — new projects get a generated one; if it is empty (required_value) or not a stored asset (image_asset_missing), upload one and set it with update_layout as { id, url, name, altText }. Verify with get_layout copy:'published' and check the copy echo — this tool's own response is the write's echo, not a receipt. Page overrides go live with the page (update_page status:'published'). A 403 PUBLISH_NOT_GRANTED means this connection can author drafts but cannot publish — say so and let the user allow publishing or publish 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:\n \"Get one component by id INCLUDING its blockJson tree and props (with any stored `ui` authoring chrome on them). Read this before update_component so you keep the existing blocks, and after declaring field UI as the receipt that it landed — a prop absent here was not stored.\",\n inputSchema: getComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof getComponentInput>) =>\n withClient(async (client) => {\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:\n \"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. \" +\n DOCTRINE,\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: \"create_components\",\n config: {\n title: \"Create many components in one call\",\n description:\n \"Create up to 50 components in ONE call — the same input as create_component, once per item. Prefer it over create_component whenever you are making more than three: a whole-site componentize run (playbook §12) is dozens, and one call each spends the turn on plumbing. Each item reports its own `{ ok, id, slug, error }`: a failure does NOT stop the run and the successful rows stay, so read the receipt and retry only the failures (a 409 on `slug` means that name is taken — change it, do not re-run the batch). Every component lands as a DRAFT, exactly as create_component does — it renders as NOTHING on the live site until it is published, which needs the owner's approval in the dashboard. Pass `group` on each item to file it into the folder editors browse. \" +\n \"DECLARE A PROP — WITH A `target` — for every string, link and image a marketer will ever touch: inside a component only the leaves a declared prop TARGETS are click-to-edit, and copy no prop points at is reachable neither from the canvas nor from the dock. A page is composed of SECTIONS; the full doctrine is in the bettercms://playbook/schema resource, §12.\",\n inputSchema: createComponentsInput.shape,\n },\n handler: guard(async (args: z.infer<typeof createComponentsInput>) =>\n withClient(async (client) => {\n const results: Array<Record<string, unknown>> = [];\n for (const input of args.components) {\n try {\n const cmp = await client.createComponent(input as ManagedComponentInput);\n results.push({ ok: true, slug: cmp.slug, id: cmp.id, name: cmp.name });\n } catch (err) {\n results.push({ ok: false, slug: input.slug, error: errorText(err) });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n return ok(\n `Created ${results.length - failed} of ${args.components.length} component(s)${failed ? `; ${failed} failed — see the per-item errors` : \"\"}. All are DRAFTS: publish_components once the owner has approved them, or they render as empty strings.`,\n results,\n );\n }),\n ) as ToolDef[\"handler\"],\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 and must not be: no tool on this connection can clear it, and it has no bulk form. It is never a component you just made with create_component in no variant group — that is dashboard-managed and publishes on the preflight alone. The refusal is for a REPO-managed component without exact validation evidence and a human's approval, or for a variant-group member (the provisioned navigation and footer) whose group's canonical-input contract is not published. Report its `readiness`. The item's `readiness` names what is missing — relay that to the user as the list of 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 — that page would render the missing sections as empty strings with no error anywhere, which is the single hardest failure on this platform to trace back. 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 needsSlug = args.pages.some((p) => !p.pageId);\n const [known, pageList] = await Promise.all([\n client.listComponents({ select: \"summary\" }),\n needsSlug ? client.listPages() : Promise.resolve([]),\n ]);\n const ids = new Set(known.map((c) => c.id));\n const bySlug = new Map(pageList.map((p) => [p.slug, p.id]));\n\n const results: Array<Record<string, unknown>> = [];\n for (const page of args.pages) {\n const pageId = page.pageId ?? (page.slug ? bySlug.get(page.slug) : undefined);\n if (!pageId) {\n results.push({ ok: false, slug: page.slug, error: `No page with slug '${page.slug}' in this project — pass a pageId from list_pages.` });\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 } }>(\n client.url(`/management/pages/${pageId}/meta`),\n { method: \"PATCH\", body: JSON.stringify({ blockJson: page.blockJson }) },\n );\n results.push({ ok: true, pageId, slug: written.data?.slug ?? page.slug, blocks: page.blockJson.length });\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 return ok(\n `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 { component, replaced } = await client.extractComponent(args);\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.`,\n component,\n );\n }),\n ) as ToolDef[\"handler\"],\n },\n {\n name: \"update_component\",\n config: {\n title: \"Update a reusable component\",\n description:\n \"Update a component by id — blockJson, props, name, or category. Read get_component first. Passing `blockJson`/`props` REPLACES them. This writes the DRAFT: call publish_component to push the change live.\",\n inputSchema: updateComponentInput.shape,\n },\n handler: guard(async (args: z.infer<typeof updateComponentInput>) =>\n withClient(async (client) => {\n const { componentId, ...input } = args;\n const cmp = await client.updateComponent(componentId, input as ManagedComponentInput);\n return ok(`Updated component '${cmp.name}' (id ${cmp.id}).`, 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 the code for a component in the app's repository. It tells BetterCMS which file renders the component, so the dashboard's Output button can build a live preview and validate it with no setup. Without it Output says no source is recorded and 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. create_component and update_component write drafts, and an unpublished component renders 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 is never a component you just made with create_component in no variant group — that is dashboard-managed and publishes on the preflight alone. The refusal is for a REPO-managed component without exact validation evidence and a human's approval, or for a variant-group member (the provisioned navigation and footer) whose group's canonical-input contract is not published. Report its `readiness`. The response's `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 // ── 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 name: \"native_bridge_heartbeat\",\n config: {\n title: \"Register as a native bridge and report liveness\",\n description:\n \"Register this client as a native-bridge executor for the connected project and report that it is alive. The dashboard's 'Native AI Connection' panel shows an executor as live ONLY while heartbeats keep arriving: call this again every `nextHeartbeatMs` (25s), because liveness lapses 90s after the last call and the panel then stops offering this executor. Idempotent — registration happens on the first call, so a restart or a reconnect is just another call. Echo back the `session` from the previous response so the same connection epoch is kept; omit it to reconnect, which fences the previous one. A 422 names a refused capability or protocol; it does not retry into success. THIS GRANTS NO REPOSITORY MUTATION — it is presence only, and starting a run still requires a human in the dashboard.\",\n inputSchema: nativeBridgeHeartbeatInput.shape,\n },\n handler: guard(async (args: z.infer<typeof nativeBridgeHeartbeatInput>) =>\n withClient(async (client) => {\n // Straight through the request plumbing, like the lifecycle tools: this endpoint has\n // no bespoke SDK method, and adding one per endpoint is what that hatch exists to avoid.\n // The route's body schema is `.strict()`, so only these three keys may travel — the\n // project rides as X-BCMS-Project, which the client sets from `projectId`.\n const result = await client.fetchJSON<{\n installationId: string;\n sessionId: string;\n sessionEpoch: number;\n liveness: string;\n nextHeartbeatMs: number;\n reconnected: boolean;\n }>(client.url(\"/management/orchestration/bridge/heartbeat\"), {\n method: \"POST\",\n body: JSON.stringify({\n protocolVersion: args.protocolVersion,\n capabilities: args.capabilities,\n ...(args.session ? { session: args.session } : {}),\n }),\n });\n return ok(\n `Bridge ${result.liveness}. Call again within ${Math.round(result.nextHeartbeatMs / 1000)}s to stay live.`,\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 // 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(withProjectId);\n}\n\n/** Register all BetterCMS tools on an MCP server. */\nexport function registerTools(server: McpServer, deps: ToolDeps): 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 for (const def of buildToolDefs(withElicit)) {\n server.registerTool(def.name, 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 { ContentBlock } from \"./block.js\";\nimport type { ContentModelFieldUi } from \"./content-model.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. 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 nine 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 the blueprint with create_component 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] 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 * 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)\n *\n * `reference` is absent on purpose: nothing resolves a content-entry id at component render\n * time, so such a prop would save cleanly and render as nothing.\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 /** Ghost text inside a text-ish control. */\n placeholder?: string;\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 /**\n * `select` — 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 | { label: string; value: string }>;\n /** `group` / `table` — the sub-shape, nestable to 3 levels. */\n fields?: ComponentSubField[];\n /** `number` — bounds for the control. */\n min?: number;\n max?: number;\n step?: number;\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?: ContentModelFieldUi;\n}\n\n/** One field inside a `group` prop or a `table` row. Recursive, capped at 3 levels deep. */\nexport interface ComponentSubField {\n key: string;\n label: string;\n /** No `slot`: a nested component instance belongs on the prop itself, not inside a row. */\n // `slot` and `form` are reference-shaped props: they belong ON a prop, never inside a row of\n // one. A form in a table row would mean N form documents per component with no way to author\n // them — the second field model this design exists to avoid.\n type: Exclude<ComponentPropDef[\"type\"], \"slot\" | \"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 placeholder?: string;\n options?: string[];\n /** CANONICAL. A nested `group`/`table`'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?: string[] } & 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 * 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\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 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 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 * 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.\";\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. Fix what it lists, or say why you are leaving it.\";\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\\` (what the platform already sees as finished: live release, bound elements, conversion coverage, pages composed from components, published components and Layout), \\`missing\\` and \\`nextAction\\` — plus \\`data\\`, the unfinished items: pages without a meta description, drafts never published, collections with no entries, forms nobody is notified about, writes waiting for human approval, bindings or sections the build has not stamped. Each item cites the count it reacted to. Call it again AFTER a batch of edits to catch what you left behind, and before telling the user you are done. When it lists \\`organise-content\\`, the project's pages and collections are in no folder: read ${STRUCTURE_PLAYBOOK_URI}, call suggest_content_structure and apply it with set_content_structure once the user agrees.`;\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: \"Other pages\", icon: \"files\", 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: \"newspaper\", sort: 0 },\n { id: \"fld_std_products\", parentId: null, name: \"Products\", icon: \"shopping-bag\", 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: \"file-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. **Other pages.** EVERY remaining standalone page goes in the system folder \\`home:pages\\`\n (\"Other 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.\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: … Other pages, Shared, Settings.\n8. **Icons** (lucide names): \\`newspaper\\` for posts, \\`shopping-bag\\` for products, \\`book-open\\`\n for docs, \\`files\\` for Other pages, \\`folder\\` by default.\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## 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] Other 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","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 */\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. \\`get_conversion_plan\\`. On a 404 \\`no-approved-plan\\`, call\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\\` + \\`deploy_from_upload\\`); 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. Ask me whether to commit and push to my repository, commit only, or leave it uncommitted (unpushed, the\n next rebuild from my repo drops it). Touch git only as I answer.`;\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 (13): 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, **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\\` (models) / \\`add_page_field\\` (pages)\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 13\nabove, including nested group/repeater), required?. Confirm, then call:\n- a model → \\`add_field\\` { modelId, key, label, type, ... }\n- a page → \\`add_page_field\\` { pageId, key, label, type, ... }\nBoth are additive: they reject a key that already exists and never retype/overwrite\nan existing field (edit those in the dashboard).`;\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. 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 }. 'select' needs\n config.options; 'group'/'table' need config.fields; 'slot' holds ONE nested component;\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\\`, never 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 run \\`get_componentize_plan\\` → \\`componentize_sections\\`\n 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\\`; \\`required\\` / \\`helpText\\` / \\`placeholder\\` are editor hints, not write\n -time enforcement. \\`select\\` for styling-only variants, a separate component when the markup\n differs. Nesting is capped at two levels — flatten anything deeper.\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 \\`submit_section_manifest\\` → \\`submit_section_validation\\`), 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_components → 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, slug, 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, slug, 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\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 deploying an existing site: bring its content into the CMS so the visual editor can bind it, declare its presentation manifest, and publish everything that renders. A deploy 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. AUTHORING GATE — if any deploy answered 409 AUTHORING_DECISION_REQUIRED, ask ME\n components-or-fields (do not choose), then set_authoring_preference.\n2. CONTENT INTO THE CMS, per route: create_page (slug = route) -> add_page_field (or\n create_component + publish_component + component blocks) -> set_page_content with values\n EXACTLY equal to the rendered text (binding matches by value; a paraphrase binds nothing)\n -> update_page status 'published' (the canvas binds the PUBLISHED copy).\n3. 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.\n4. VERIFY — call get_next_steps and fix what it lists (it knows about missing manifests,\n content still only in the build, and placed-but-unpublished components), or tell me why\n an item is being left.\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: \"Declare how fields LOOK in the editor (guided)\",\n description:\n \"Set the authoring chrome on an existing schema — collapsed panels, what titles and thumbnails a repeater's rows, help text, conditional visibility. Derives it from your site's source where there is source, from the field shapes where there isn't, and only asks you about the three things it genuinely cannot know.\",\n argsSchema: {\n request: z\n .string()\n .optional()\n .describe(\"scope, e.g. 'the Team and Testimonials models' or 'the whole project'\"),\n },\n },\n ({ request }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Declare the editor UI for my BetterCMS fields.${request ? ` Scope: \"${request}\".` : \"\"}\n\nRead bettercms://playbook/schema section 14 first — it has the exact prop shapes and the refusals.\n\n**What you are setting** (all of these ride on any field, on create_content_model / create_page /\nadd_field / add_page_field; none of them affect delivery):\n ui.collapsed start a nesting field's panel closed\n ui.preview {title,media} which CHILD FIELD KEY titles a collapsed row, and which is its thumb\n ui.layout 'list'|'grid'|'table' how its items are arranged; table is for repeatable row schemas; omit for list\n ui.reorderable omit (= true) unless the ORDER IS THE MEANING; false LOCKS the list\n helpText one line under the field: what to WRITE here\n showIf hide a field until another field has a value\n\n**The same \\`ui\\` rides on COMPONENT PROPS** — create_component / update_component, one per entry\nof \\`props\\`. Placement differs because the vocabulary does: preview/layout on 'group', 'table'\nand 'slot'; reorderable on 'table' ALONE (the only prop whose value is a list). A prop's preview\nkeys name a SUB-FIELD from its own config.fields. If this scope includes components, do them in\nthe same pass — but note update_component REPLACES the whole props array, so read get_component\nfirst and echo every prop back WITH its stored ui.\n\n**Work the three tiers in order. Stop at the first that answers — do not escalate what a tier\nbelow already settled.**\n\nTIER 1 — DERIVE FROM SOURCE, if and only if you have a checkout of the site.\n Read the component that renders each field. \\`<img src={item.photo}>\\` next to\n \\`<h3>{item.name}</h3>\\` in the map over a list IS the answer: preview {title:'name',\n media:'photo'}. A block inside \\`<details>\\` or behind a \"Show more\" is collapsed:true.\n A \\`grid-cols-*\\` wrapper around the map is layout:'grid'. A FIXED-ARITY render —\n steps[0]/steps[1]/steps[2], or copy that names positions (\"Step 1\", \"finally\") — is\n reorderable:false, and it is the ONLY evidence that earns that key.\n 🔴 THE SERVER NEVER READS YOUR SOURCE. \\`pull_project_source\\` / \\`get_conversion_brief\\` hand\n the repo to YOU; add_field does not look at it. This tier is your own reading, in your own\n checkout, before you call any tool. ON A GREENFIELD SCHEMA-FIRST PROJECT THERE IS NO SOURCE —\n Tier 1 does not apply and TIER 2 IS THE FLOOR. Do not stall waiting for code that will\n never exist.\n\nTIER 2 — DERIVE FROM THE FIELD SHAPE, when the code is silent or absent.\n One image-ish child in a repeater → that is \\`media\\`. The first required short-text child\n (name/title/heading/label) → that is \\`title\\`. More than ~6 children, or a label that reads\n optional (\"Advanced\", \"Extras\") → collapsed:true. A repeatable whose item is mostly its\n image (gallery, logos, team) → layout:'grid'; everything else stays list, so OMIT layout.\n \\`reorderable\\` has NO Tier-2 guess — leave it absent. The default is true, and locking a\n list the user did not ask to lock silently removes something they could do yesterday.\n GUESS HERE otherwise. A wrong preview costs one edit; a question per repeater costs the\n user the session.\n\nTIER 3 — ASK ME, and ONLY for these three. Batch them into ONE AskUserQuestion at the end,\n never one field at a time:\n a) A panel with MANY fields, where grouping and order depend on which content I treat as\n primary — you cannot infer my priorities.\n b) CONDITIONAL VISIBILITY (showIf) — it is business logic about when a field is irrelevant.\n Never invent a rule.\n c) VARIANTS SHARING A sectionType — their prop keys must match, or swapping the layout loses\n content. Confirm the shared key set before declaring per-variant chrome.\n\n**Order of work**\n1. \\`list_content_models\\` / \\`list_pages\\`, then \\`get_content_model\\` / \\`get_page\\` for each target.\n Note which fields ALREADY carry ui/helpText/showIf — do not overwrite a human's choice\n without asking.\n2. Decide each field's chrome by the tiers above. Write down which tier answered; you will\n report it.\n3. Apply. For a field that already exists, the declaration goes with the field: use the\n dashboard or a model update — \\`add_field\\` APPENDS and refuses an existing key, so it is\n the wrong tool for editing one. For a NEW field, pass ui/helpText/showIf in the same\n \\`add_field\\` / \\`add_page_field\\` call, and pass \\`after: '<existing key>'\\` if it belongs\n somewhere other than the bottom.\n4. **RECEIPT — non-negotiable.** Re-read every target with \\`get_content_model\\` / \\`get_page\\` /\n \\`get_component\\` and\n confirm the stored \\`ui\\` matches what you sent. A prop ABSENT from that response was NOT\n stored, whatever the write said. Report per field: the tier that decided it, what you set,\n and that the read-back confirmed it. Anything you could not confirm, say so plainly.\n\n**Refusals you should expect and must not work around:** an unknown key inside \\`ui\\` is a 400\n(it is strict on purpose — that is your typo, named); \\`ui.preview\\` or \\`ui.layout\\` on a leaf\nfield is a 400 (both describe ITEMS); \\`ui.reorderable\\` anywhere without a LIST is a 400 — a\n\\`group\\` and a non-repeatable zone hold one item, so only \\`repeater\\`, an \\`array\\` with\nconfig.zones.repeatable, and \\`modular\\` take it; a preview key that is not a child of that field\nis a 400 listing the valid child keys. Fix the declaration; never retry without it and call that\nsuccess.\n\nThere is deliberately NO \\`order\\` property and no mode to turn on — order is the array index,\nand \\`ui\\` only changes editor chrome, so there is nothing to flip.`,\n },\n },\n ],\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 at import, where the componentize lane in §10 reuses every field.\n\n## 2. The decision tree\n\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')\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 Site-wide nav/footer? -> place the project's provisioned components\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\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. 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.\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 were derived at\nimport — 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\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: [ nav, heading, { type:\"collection\", id:\"list\", props:{} }, footer ]\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\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\\`deploy_project\\`, \\`deploy_from_upload\\` and \\`promote_project\\` all 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\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 the import already derived.\n\n**Recommend \\`components\\`.** On a site whose pages were DERIVED at import — 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 site DERIVED at import the release hook has already run\n this plan in bind mode and PUBLISHED what it created, so\n expect ALREADY_COMPONENTIZED and skip to step 6 (publish the\n pages) — the lane publishes the COMPONENTS, not the placements,\n which are still draft blocks on the pages\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. npx @bettercms-ai/convert --componentize in the repo, so its templates render these\n sections from \\`pages[].blocks\\`\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\\`). 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_page_field 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:<sectionId>:<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 Three 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 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 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**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 — variant, size and icon are that block's own props and\n\\`style\\`, never a standalone Button component. 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.\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. Start from the\nbuiltin blueprints \\`list_components\\` returns (\\`builtin:*\\`) instead of hand-writing block JSON.\nOn a DERIVED site run \\`get_componentize_plan\\` → \\`componentize_sections\\` FIRST — it does most\nof this in one call, and on a site derived at IMPORT the release hook has already run it in bind\nmode and published the components, so expect ALREADY_COMPONENTIZED — the placements it wrote are\nstill DRAFT blocks on the pages, so publish the pages, then \\`npx @bettercms-ai/convert\n--componentize\\`.\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**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 is capped at TWO levels from the prop (a \\`table\\` row may hold a\n\\`table\\`, and that inner row is scalars only). Flatten anything deeper.\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 goes \\`submit_section_manifest\\` →\n\\`submit_section_validation\\`, 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_components everything the plan did not cover, ONE call, 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 submit_section_manifest -> submit_section_validation\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 deployed, so its schema and values were\nderived for you already → **Recipe A**. A 404 or an empty brief means the site is not in the CMS\nyet → **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_page_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 made editable from\nits 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: the\n server stores its \\`forms\\` block beside the binding receipt (coverage is untouched), 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.\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.\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_page_field\\` (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?}]}]}\\`; Sanity's row of plain strings, \\`rows:[{cells:[\"a\",\"b\"]}]\\`,\n is admitted too), \\`bcmsCode\\`, \\`bcmsDivider\\`, \\`bcmsMention\\`, 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 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 provisioned workflow\n writes \\`bcms-content.json\\` into the repo root before \\`build\\`, using the repo's\n \\`BCMS_API_KEY\\` secret. Read that file, with in-code fallbacks so a local or CI build\n without it still renders.\n - ARCHIVE (\\`deploy_project\\` / \\`deploy_from_upload\\`): 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**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\\`, \\`add_page_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\", \"reorderable\": true },\n \"helpText\": \"Three to five. Shortest quotes read best.\",\n \"fields\": [ { \"key\": \"author\", ... }, { \"key\": \"avatar\", \"type\": \"image\", ... }, ... ] }\n\\`\\`\\`\n\n- **\\`helpText\\`** — one line UNDER the field telling the author what to write here, not what the\n field is. \"Roughly 60 characters; it becomes the browser tab title\" earns its place.\n \"The title field\" does not.\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. Both\n slots name 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\n**Five 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.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.\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.\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**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. Declare, then read\nback, 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\\` /\n\\`add_page_field\\`; omit 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"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,YAAY,gBAAgB,wBAAwB;;;ACH7D,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;;;ACD1B,SAAS,yBAAyB;AAClC,SAAS,SAAS;;;ACoCX,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;AACF;;;AC/EO,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,E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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","names":["s","list","z","z","DeviceAuthClient","loadConfig"]}