@clay-design-system/mcp 0.0.0-stage → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,71 @@
1
- # Temporary Holding Version
1
+ # @clay-design-system/mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The Clay design system as an [MCP](https://modelcontextprotocol.io) server: 12 read-only tools over the
4
+ [Clay Registry](https://www.npmjs.com/package/@clay-design-system/registry) (components, sections and their layouts, tokens, logos and
5
+ icons, rules, copy limits, page recipes). An agent that builds a monday.com landing page asks it instead of reading docs.
6
+
7
+ Node >= 22.13. Serving writes nothing to disk and sends nothing off the machine (only `fetch-version` downloads and writes a pinned database): the server answers from the database that ships in
8
+ `@clay-design-system/registry`.
9
+
10
+ ## Use it
11
+
12
+ ```bash
13
+ npx @clay-design-system/mcp # stdio server
14
+ ```
15
+
16
+ Claude Code / any MCP client (`.mcp.json`):
17
+
18
+ ```json
19
+ {
20
+ "mcpServers": {
21
+ "clay": { "command": "npx", "args": ["-y", "@clay-design-system/mcp"] }
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## Tools
27
+
28
+ | Tool | Ask it |
29
+ |---|---|
30
+ | `clay_route` | What do I need for this stage? (skill x mode x stage, brief in, ordered knowledge out) |
31
+ | `clay_section` | Props, item shapes, copy limits, layouts of a section (no name: every section) |
32
+ | `clay_search` | A question; ranked record ids. `each` resolves several names in one call |
33
+ | `clay_get` | Full records by id, alias or prefix (`web-pmm`, `section:FeaturesSection`, `rule.*`) |
34
+ | `clay_list` | The kinds with counts, or the records of one kind, paged |
35
+ | `clay_related` | Typed edges of a record (variant-of, uses-token, has-item, ...) |
36
+ | `clay_asset_url` | CDN url of a logo, icon, badge, agent image or shape, by variant |
37
+ | `clay_render` | Stored render rows and HTML of a record (arrives with registry Phase 3) |
38
+ | `clay_rules` | Hard Rules and enforced policies for a stage |
39
+ | `clay_check_copy` | A PageSpec's copy against the section limits |
40
+ | `clay_validate_page` | A PageSpec against the schema, the layout/content coupling, normalization and Hard Rule C6 |
41
+ | `clay_components_using_token` | Which components use a token (id, alias or CSS variable) |
42
+
43
+ Every tool takes strict arguments (an unknown key is an error), accepts aliases wherever it takes an id, answers in compact Markdown,
44
+ and returns JSON text with `json: true`. `detail: true` adds the full record. Answers are capped at 80 kB.
45
+
46
+ ## HTTP
47
+
48
+ ```bash
49
+ clay-mcp --http --port 3920 # POST http://127.0.0.1:3920/mcp
50
+ clay-mcp --http --host 0.0.0.0 --allowed-hosts clay.example.com
51
+ clay-mcp fetch-version 0.14.0 --versions-dir ./clay-versions # then POST /v/0.14.0/mcp
52
+ ```
53
+
54
+ Stateless Streamable HTTP (one server per request). `GET /healthz` and `GET /versions` describe what is served. It binds loopback by
55
+ default, checks the `Host` and `Origin` headers, and has no authentication or TLS: put those in front of it if you expose it.
56
+
57
+ ## Versions
58
+
59
+ This package is versioned with `@clay-design-system/registry` and depends on exactly the same version, so `npx @clay-design-system/mcp@0.14.1`
60
+ serves registry 0.14.1. Over HTTP, `POST /v/<version>/mcp` pins an older registry from the versions folder. The server instructions,
61
+ `json` answers and `/healthz` all say which registry (version, schema, content digest) answered.
62
+
63
+ ## Library
64
+
65
+ ```ts
66
+ import { createClayMcpServer } from '@clay-design-system/mcp'
67
+ import { Registry, DB_PATH } from '@clay-design-system/registry'
68
+
69
+ const server = createClayMcpServer({ open: (p) => new Registry(p), db: DB_PATH, version: '0.14.1' })
70
+ await server.connect(transport) // any MCP transport
71
+ ```
package/dist/bin.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import{c as p,g as d,h as m}from"./chunk-4UBF3MA3.js";import{createRequire as h}from"node:module";import{StdioServerTransport as v}from"@modelcontextprotocol/sdk/server/stdio.js";import{DB_PATH as f,Registry as u}from"@clay-design-system/registry";import{resolve as i}from"node:path";var c=`clay-mcp \u2014 the Clay design system as an MCP server
3
+
4
+ clay-mcp [--db <file>] stdio (default)
5
+ clay-mcp --http [--port 3920] [--host 127.0.0.1] [--allowed-hosts a,b] [--versions-dir dir]
6
+ clay-mcp fetch-version <semver> [--versions-dir dir]
7
+ `;function l(r){let s={cmd:"stdio",versionsDir:process.env.CLAY_MCP_VERSIONS_DIR??i(process.cwd(),"clay-versions")},n=(t,o)=>{let e=r[t+1];if(e===void 0||e.startsWith("--"))throw new Error(`${o} needs a value`);return e};for(let t=0;t<r.length;t++){let o=r[t];switch(o){case"--http":s.cmd="http";break;case"--db":s.db=i(n(t++,o));break;case"--port":{let e=Number(n(t++,o));if(!Number.isInteger(e)||e<0||e>65535)throw new Error("--port must be 0-65535");s.port=e;break}case"--host":s.host=n(t++,o);break;case"--allowed-hosts":s.allowedHosts=n(t++,o).split(",").map(e=>e.trim()).filter(Boolean);break;case"--versions-dir":s.versionsDir=i(n(t++,o));break;case"fetch-version":if(s.cmd="fetch-version",s.version=r[++t],!s.version)throw new Error("fetch-version needs a version, e.g. fetch-version 0.13.0");break;case"-h":case"--help":s.cmd="help";break;default:throw new Error(`unknown argument "${o}"
8
+ ${c}`)}}return s}var g=()=>{try{return h(import.meta.url)("@clay-design-system/registry/package.json").version}catch{return"unknown"}};async function w(){let r=l(process.argv.slice(2));if(r.cmd==="help")return void process.stdout.write(c);if(r.cmd==="fetch-version"){let e=d(r.version,r.versionsDir);return void process.stdout.write(`${e}
9
+ `)}let s=r.db??f,n=r.db?"custom":g(),t=e=>new u(e);if(r.cmd==="http"){let e=await m({open:t,db:s,version:n,versionsDir:r.versionsDir,port:r.port,host:r.host,allowedHosts:r.allowedHosts});process.stderr.write(`clay-mcp: listening on ${e.url}/mcp (registry ${n})
10
+ `);let a=()=>void e.close().then(()=>process.exit(0));process.on("SIGINT",a),process.on("SIGTERM",a);return}await p({open:t,db:s,version:n}).connect(new v)}w().catch(r=>{process.stderr.write(`clay-mcp: ${r.message}
11
+ `),process.exit(1)});
@@ -0,0 +1,160 @@
1
+ import{z as x}from"zod";import"@modelcontextprotocol/sdk/server/mcp.js";var Mt=new WeakMap;function Pt(t){let n=Mt.get(t.units);if(n)return n;let e=new Map,s=new Map,i=new Map;for(let r of t.units)if(r.kind==="limit"&&r.facts){let a=r.facts;e.set(`${a.owner}.${a.field}`,{id:r.id,f:a})}else if((r.kind==="section"||r.kind==="component")&&r.authority==="derived"&&r.facts){let a=r.facts;a.name&&a.props&&s.set(a.name,a.props)}else if(r.kind==="item-type"&&r.facts){let a=r.facts;i.set(a.name,a.fields)}let o={limits:e,props:s,items:i};return Mt.set(t.units,o),o}var ii=t=>t.split(/(?<=[.!?])\s+(?=\S)/).filter(n=>n.trim()).length,si=t=>t.trim().split(/\s+/).filter(Boolean).length;function oi(t,n){let e=t.trim(),s=[...e].length,i=si(e),o=ii(e),r=[],a=[];n.chars&&(s>n.chars.max?r.push(`chars ${s} > ${n.chars.max}`):s<n.chars.min&&a.push(`chars ${s} < ${n.chars.min}`)),n.words&&i>n.words.max&&r.push(`words ${i} > ${n.words.max}`),n.sentences&&(o>n.sentences.max?r.push(`sentences ${o} > ${n.sentences.max}`):o<n.sentences.min&&a.push(`sentences ${o} < ${n.sentences.min}`));let l=r.length?"over":a.length?"under":"ok";return{chars:s,words:i,sentences:o,status:l,detail:[...r,...a].join(", ")||"within limits"}}var ri=t=>/^([A-Z][A-Za-z0-9]*)\[\]$/.exec(t.trim())?.[1];function nt(t,n,e={}){let s=Pt(t),i={file:e.file??"PageSpec",checked:0,skipped:e.skipped??0,findings:[]};for(let o of n){let r=o.field.includes(".")?o.field:`${o.component}.${o.field}`,a=s.limits.get(r);if(!a)continue;i.checked++;let l=oi(o.value,a.f);i.findings.push({line:o.line??0,...o.path!==void 0?{path:o.path}:{},component:o.component,field:o.field,limitId:a.id,value:o.value.length>70?`${o.value.slice(0,67)}\u2026`:o.value,...l,hard:a.f.hard,severity:a.f.hard&&l.status!=="ok"?"Critical":"Warning"})}return i}var it={IntegrationsSection:"Integrations"},_e=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function ai(t,n){let e=Pt(t),s=[],i=0;return(_e(n)&&Array.isArray(n.sections)?n.sections:[]).forEach((r,a)=>{if(!_e(r)||typeof r.type!="string"||!_e(r.props))return;let l=it[r.type]??r.type,c=e.props.get(l);if(!c)return;let u=`sections[${a}].props`,p=(f,g,m,$)=>{let S=e.limits.get(`${f}.${g}`),y=f===l?g:`${f}.${g}`;if(typeof m=="string"){s.push({component:l,field:y,value:m,path:$});return}if(S?.f.each&&Array.isArray(m)){m.forEach((v,A)=>{typeof v=="string"?s.push({component:l,field:y,value:v,path:`${$}[${A}]`}):i++});return}S&&m!==void 0&&m!==null&&i++};for(let[f,g]of Object.entries(r.props)){let m=c.find(S=>S.name===f);if(!m)continue;let $=ri(m.type);if($&&e.items.has($)){if(!Array.isArray(g)){g!=null&&i++;continue}g.forEach((S,y)=>{if(!_e(S)){i++;return}for(let[v,A]of Object.entries(S))p($,v,A,`${u}.${f}[${y}].${v}`)})}else p(l,f,g,`${u}.${f}`)}}),{fields:s,skipped:i}}function Nt(t,n,e={}){let{fields:s,skipped:i}=ai(t,n);return nt(t,s,{file:e.file??"PageSpec",skipped:i})}function Oe(t,n={}){let e=t.findings.filter(a=>a.status!=="ok"),s=t.findings.some(a=>a.path);if(n.compact&&!n.all){let a=e.filter(u=>u.hard),l=new Map;for(let u of e.filter(p=>!p.hard)){let p=`${u.component}.${u.field}`,f=l.get(p)??{over:0,under:0,at:[]};f[u.status]++,f.at.push(u.path??String(u.line)),l.set(p,f)}return`${[`# check-copy \xB7 ${t.file} \u2014 ${t.checked} fields \xB7 ${e.length} outside a limit \xB7 ${a.length} hard (Critical) \xB7 ${t.skipped} not static`,...a.map(u=>`- **hard** ${u.path??`L${u.line}`} ${u.component}.${u.field}: ${u.status} (${u.detail}) "${u.value}"`),...l.size?[`Soft flags (copy guidance; Mode B: flag for the PMM, never edit \u2014 \`policy.content-limits\`; \`--all\` for the rows): ${[...l.entries()].map(([u,p])=>`${u} ${[p.over?`${p.over} over`:"",p.under?`${p.under} under`:""].filter(Boolean).join(", ")} (${s?p.at.join(", "):`L${p.at.join(",")}`})`).join(" \xB7 ")}`]:[]].join(`
2
+ `)}
3
+ `}let i=(n.all?t.findings:e).map(a=>`| ${a.path??a.line} | ${a.component} | ${a.field} | ${a.status==="ok"?"ok":`${a.status} (${a.detail})`} | ${a.hard?"hard":"soft"} \xB7 ${a.severity} | "${a.value.replace(/\|/g,"\\|")}" |`),o=e.filter(a=>a.severity==="Critical").length;return`${[`# check-copy \xB7 ${t.file}`,`${t.checked} copy fields checked \xB7 ${e.length} outside a limit (${e.filter(a=>a.status==="over").length} over, ${e.filter(a=>a.status==="under").length} under) \xB7 ${o} Critical (hard limits) \xB7 ${t.skipped} values not statically resolvable.`,"Soft limits are copy guidance: a Warning (in Mode B a flag for the PMM, never an edit \u2014 `policy.content-limits`).",...i.length?["",`| ${s?"path":"line"} | component | field | result | limit | value |`,"|---|---|---|---|---|---|",...i]:[]].join(`
4
+ `)}
5
+ `}function J(t,n,e){t&&!t.served[n]&&(t.served[n]=e)}function Ie(t,n,e){t&&!t.lines[n]&&(t.lines[n]=e)}var Me=(t,n)=>!!t&&(!!t.lines[n]||!!t.served[n]),ue=(t,n)=>!!t&&!!t.served[n];function Pe(t,n,e){if(!t||!n)return;t.sections.includes(n)||t.sections.push(n);let s=e?`${n}.${e}`:"";s&&!t.layouts.includes(s)&&t.layouts.push(s)}var te=["structure","mapping","design","assets","copy","page-file","ux","qa","static","fidelity"];function X(t){return Math.ceil(t.length/4)}var Ft=["id","summary","entities","topic","when","body"],li={id:4,summary:3,entities:2.5,topic:2,when:1,body:1},Bt={id:.3,summary:.5,entities:.3,topic:.3,when:.6,body:.75},ci=1.2,di=.7;function ui(t){if(/^\d/.test(t))return t;let n=t;return n.length>4&&n.endsWith("ies")?n=`${n.slice(0,-3)}y`:n.length>3&&n.endsWith("s")&&!n.endsWith("ss")&&!n.endsWith("us")&&!n.endsWith("is")&&(n=n.slice(0,-1)),n.length>5&&n.endsWith("ing")?n=pi(n.slice(0,-3)):n.length>4&&n.endsWith("ed")&&(n=n.slice(0,-2)),n}function pi(t){return/([b-df-hj-np-tv-z])\1$/.test(t)&&!/(?:ll|ss|zz)$/.test(t)?t.slice(0,-1):t.length<=4&&/[b-df-hj-np-tv-z][aeiou][b-df-hj-np-tvz]$/.test(t)?`${t}e`:t}var gi=new Set("a an and are as at be been but by can could did do does for from had has have how i if in into is it its me my of on or our should so than that the their them then there these they this those to too was we were what when where which while who why will with would you your use used using get page pages need needs want any all also just one two only very about there here does".split(" ")),mi={tap:["touch","target"],touch:["tap","target"],cta:["button","action"],button:["cta"],gray:["grey"],muted:["grey","tint","theme"],hero:["headersection"],faq:["faqsection"],testimonial:["testimonialssection","quote"],quote:["testimonial"],logos:["logo","customerlogosection"],marquee:["logo","customerlogosection","autoscroll"],widow:["orphan","balance","nbsp"],contrast:["wcag","aa"],breakpoint:["mq","media"],video:["mediaslot","autoplay"],limit:["char","chars"],chars:["limit"],characters:["char","limit"],stat:["brand_stats","number"],stats:["brand_stats","number"],padding:["spacing"],colour:["color"],pmm:["mode-b","modeb"],mode:["mode-b"],asset:["media"],image:["media","mediaslot"],screenshot:["media","mediaslot"],placeholder:["placeholderlabel","mediaslot"],nav:["navbarmenu","navbar"],navbar:["navbarmenu"],footer:["footersection"],pill:["tab"],accordion:["accordion-media-right","numbered-accordion"],"two-column":["split","side"],eyebrow:["topic","minititle","topiclabel","sectiontopic","tagline"],subheadline:["description","subheading"],subheading:["description","subheadline"],subtitle:["description"],body:["description"],tinted:["muted","tint"],shortest:["min","minimum"],longest:["max","maximum"],marketer:["pmm"],letterboxed:["contain"],"side-by-side":["split"]},fi={two:2,three:3,four:4,five:5,six:6,seven:7,eight:8,nine:9,ten:10,eleven:11,twelve:12};function hi(t){let n=/\b(\d{1,2}|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)\s+(?:[a-z-]+\s+){0,2}?(?:tabs?|items?|cards?|entries|steps?|logos?|features?|quotes?|stats?|pillars?|columns?)\b/i.exec(t);if(!n)return null;let e=/^\d+$/.test(n[1])?Number(n[1]):fi[n[1].toLowerCase()];return e>=1&&e<=24?e:null}var yi=/\b(?:tokens?|var\(|--clay|hex|colou?r value|icons?|logos?|keys?|illustrations?|agent images?|shapes?|svg)\b/i;function Ne(t){let n=[],e=t.replace(/`/g," ");for(let s of e.split(/[^A-Za-z0-9_\-.:]+/))if(s)for(let i of s.split(/[.:]+/)){if(!i)continue;let o=i.toLowerCase().replace(/^-+|-+$/g,"");if(!o)continue;let r=o.split(/[-_]+/).filter(Boolean),a=i.replace(/^-+/,"").split(/[-_]+/).flatMap(c=>c.split(/(?<=[a-z0-9])(?=[A-Z])/)),l=c=>{c.length<2&&!/^\d$/.test(c)||gi.has(c)||n.push(ui(c))};r.length>1&&n.push(r.join(""));for(let c of new Set([...r,...a.map(u=>u.toLowerCase())]))l(c)}return n}function st(t){let n=new Map;for(let e of Ne(t))n.set(e,Math.max(n.get(e)??0,1));for(let e of t.toLowerCase().split(/[^a-z0-9-]+/))for(let s of mi[e]??[])for(let i of Ne(s))n.has(i)||n.set(i,.5);return n}function Kt(t){return t?.length?t.includes("all")||t.includes("email")&&t.some(n=>n==="web"||n==="ds")?"all":t.includes("email")?"email":"web":"web"}var bi=["web","ds","shared"];function $i(t,n){if(t.authority==="background"&&!n.includeBackground&&!n.authority?.includes("background")||n.kind?.length&&!n.kind.includes(t.kind)&&!(t.subkind&&n.kind.includes(t.subkind)))return!1;let e=n.scope?.length?n.scope:bi;return!(!e.includes("all")&&!e.includes(t.scope)||n.authority?.length&&!n.authority.includes(t.authority)||n.stage?.length&&!t.stages.some(s=>n.stage.includes(s))||n.mode&&t.modes&&!t.modes.includes(n.mode)||n.entity?.length&&!t.entities.some(s=>n.entity.includes(s)))}function qt(t,n,e,s){let i=new Map;for(let[o,r]of t){let a=e(o);if(!a.length)continue;let l=Math.log(1+(n.n-a.length+.5)/(a.length+.5));for(let[c,u]of a){let p=s(c),f=0;Ft.forEach((g,m)=>{u[m]&&(f+=li[g]*u[m]/(1-Bt[g]+Bt[g]*p[g]/n.avg[g]))}),i.set(c,(i.get(c)??0)+r*l*(f/(ci+f)))}}return i}function Ut(t,n){let e=new Set,s=n.split(/[^A-Za-z0-9-]+/).filter(Boolean);for(let i of s)if(!(i.length<3))for(let o of t.get(i.toLowerCase())??[])e.add(o);for(let i=0;i<s.length;i++)for(let o of[2,3]){if(i+o>s.length)continue;let r=s.slice(i,i+o).join("").toLowerCase();for(let a of t.get(r)??[])e.add(a)}return[...e]}function Ht(t,n,e,s,i){let o=e.k??10,r=yi.test(t),a=new Set(Ut(s,t)),l=hi(t),c=/\btokens?\b|--clay|var\(/i.test(t),u=/\bskills?\b|\bslash commands?\b|\bworkflows?\b|\bpipelines?\b/i.test(t),p=` ${t.toLowerCase().replace(/[^a-z0-9-]+/g," ")} `,f=/\bshould i\b|\bwhich (?:rule|one) wins\b|\bwins?\b|\bblock or\b|\bor (?:just )?(?:flag|warn)\b/i.test(t),g=/\bhow many\b|\b(?:fit|fits|hold|holds)\b/i.test(t)||/\btakes?\b/i.test(t)&&l!=null,m=/\b(?:how long|shortest|longest|minimum|maximum|length|max|min|chars?|characters?)\b/i.test(t)&&!/\bshould\b|\bblock\b|\bflag\b|\bwarn\b|\bwins?\b/i.test(t),$=new Set(st(t).keys()),S=[];for(let[y,v]of n){if(!$i(y,e))continue;let A=v;if(!r&&!e.kind?.length&&(y.kind==="token"||y.kind==="asset")&&(A*=.4),y.kind==="token"&&c&&(A*=2),(y.kind==="skill"||y.kind==="page")&&!e.kind?.length&&!u&&!p.includes(` ${y.id.slice(y.id.indexOf(".")+1).toLowerCase()} `)&&(A*=di),y.authority==="guidance"&&(A*=.85),y.status==="deprecated"&&(A*=.5),g&&y.kind==="layout"&&(A*=1.3),f&&(y.kind==="policy"||y.kind==="procedure")&&(A*=1.4),m&&(y.kind==="limit"||y.kind==="item-type")&&(A*=1.4),l!=null&&y.kind==="layout"){let b=y.facts?.items;b&&(b.min!=null||b.max!=null)&&(A*=(b.max==null||l<=b.max)&&(b.min==null||l>=b.min)?1.35:.85)}if(y.kind==="token"){let b=new Set(Ne(y.id.replace(/^token\./,"")).filter(C=>!$.has(C)&&C!=="clay"));A*=.85**Math.min(b.size,6)}if(y.kind==="asset"&&p.includes(` ${y.id.slice(y.id.lastIndexOf(".")+1).toLowerCase()} `)&&(A*=1.5),a.size){let b=y.entities.filter(C=>a.has(C));b.some(C=>C.startsWith("layout:"))?A*=1.6:b.length&&(A*=1.3)}S.push({id:y.id,score:Math.round(A*1e3)/1e3,kind:y.kind,authority:y.authority,summary:y.summary})}return S.sort((y,v)=>v.score-y.score||(y.id<v.id?-1:1)),(i?ki(S,i):S).slice(0,o)}function Si(t){return t?[...t.matchAll(/`(\w+(?:\[['"][^'"`]+['"]\])+)`/g)].map(n=>n[1]):[]}function ki(t,n){if(!t.some(a=>a.kind==="asset"))return t;let e=new Map,s=a=>{let l=e.get(a);return l||e.set(a,l=Si(n(a))),l},i=new Map;for(let a of t){if(a.kind!=="asset"||!a.id.startsWith("asset.logo."))continue;let l=s(a.id);for(let c of l){let u=i.get(c);(!u||s(u.id).length>l.length)&&i.set(c,a)}}if(!i.size)return t;let o=new Set;for(let a of t){if(a.kind!=="asset"||a.id.startsWith("asset.logo."))continue;let l=s(a.id),c=l.length?i.get(l[0]):void 0;!c||!l.every(u=>i.get(u)===c)||(c.aliases=[...c.aliases??[],a.id],c.score=Math.max(c.score,a.score),o.add(a))}let r=t.filter(a=>!o.has(a));return r.sort((a,l)=>l.score-a.score||(a.id<l.id?-1:1)),r}var Dt=new WeakMap;function wi(t){let n=Dt.get(t);return n||Dt.set(t,n=new Map(t.units.map(e=>[e.id,e.body]))),n}function W(t,n,e,s={}){if("searchHits"in n)return n.searchHits(e,s);let i=Kt(s.scope),o=n.channels?.[i]??{n:n.n,avg:n.avg},r=c=>i==="all"||(i==="email"?!!c.email:!c.email),a=c=>{let u=n.postings.get(c);return u?i==="all"?u:u.filter(([p])=>r(n.docs[p])):[]},l=qt(st(e),o,a,c=>n.docs[c].len);return Ht(e,[...l].map(([c,u])=>[t.units[c],u]),s,n.entityNames,c=>wi(t).get(c))}var Be=t=>/^email-/.test(t)||t==="campaign-brief",ot={"email-compose":{structure:["Stage 1 \u2014 Structure (`email-structure`)","Stage 1.5 \u2014 Custom sections (`email-section`, `new` mode) \u2014 CONDITIONAL"],mapping:["Stage 1 \u2014 Structure (`email-structure`)"],design:["Stage 2 \u2014 Design (`email-design`)"],assets:["Stage 2.5 \u2014 Assets + Icons (`email-assets`)"],copy:["Stage 3 \u2014 Copy injection"],"page-file":["Stage 4 \u2014 Compose the MJML"],static:["Stage 5 \u2014 Static fallback (optional)","Stage 7 \u2014 Package for delivery"],qa:["Stage 6 \u2014 QA (`email-qa`)"]},"email-campaign":{structure:["Step 1: Normalize to Campaign Brief","Step 2: Theme arc validation"],mapping:["Step 1: Normalize to Campaign Brief"],copy:["Step 2: Theme arc validation"],"page-file":["Step 3: Fan out to `email-compose` \xD7 N"],qa:["Step 4: Campaign manifest"]},"email-structure":{structure:["Process"],mapping:["Process"]},"email-design":{design:["Process"]},"email-assets":{assets:["Process"]},"email-qa":{qa:["Pipeline"],static:["Step 5 \u2014 Static fallback (only if one was authored \u2014 it's optional)","Step 6 \u2014 Package for delivery (runs after PASS)"]},"email-section":{structure:["Mode `new` \u2014 build a section for a `[GAP]` (last resort)"],"page-file":["Authoring rules"]}},pe={"email-campaign":["email-compose","email-structure","email-design","email-assets","email-qa","email-section","campaign-brief"],"email-compose":["email-structure","email-section","email-design","email-assets","email-qa","knowledge-capture","email-design-brain"]},xi=[{re:/var\(--clay-/,what:"var(--clay-*) guidance",negatable:!0},{re:/calc\(var\(/,what:"calc(var(\u2026)) units"},{re:/@media \(min-width|min-width`?\*{0,2} (?:queries )?only|queries use \W{0,4}min-width/i,what:"min-width (mobile-first) breakpoints"},{re:/@layer\b|\bclay\.components\b/,what:"CSS cascade layers"},{re:/\.module\.css\b/,what:"CSS Modules"},{re:/`rule\.A\d+`|\bHard Rule A\d+/,what:"a web authoring Hard Rule (A1\u2013A15)"}],vi=/\b(?:never|no|not|can't|cannot|don't|doesn't|isn't|without|stripped|ignored|instead)\b/i;function Ci(t){let n=new Set;for(let e of t.split(/(?<=[.!?;:])\s+|\n+/))for(let s of xi)s.re.test(e)&&!(s.negatable&&vi.test(e))&&n.add(s.what);return[...n]}function zt(t,n){return Be(n)?t.scope==="email"?!0:t.scope==="shared"&&Ci(`${t.summary??""}
6
+ ${t.body??""}`).length===0:t.scope!=="email"}var Ri=new Set(["email-compose"]);function Wt(t,n){let e=ot[t]?.[n];if(!e?.length){let s=(pe[t]??[]).find(i=>ot[i]?.[n]?.length);return s?`## Do (this stage belongs to \`${s}\`)
7
+ - \`${t}\` has no step of its own at ${n}: each \`${s}\` run does it \u2014 \`skills/${s}/SKILL.md\` \xA7 ${ot[s][n][0]} (\`pnpm clay route --skill ${s} --stage ${n}\`). The units below are the knowledge it needs.`:null}return`## Do (the pipeline step stays in the skill)
8
+ ${e.map(s=>`- \`skills/${t}/SKILL.md\` \xA7 ${s}`).join(`
9
+ `)}
10
+ Follow that step${Ri.has(t)?' and its "Validate before proceeding" list':""}; the units below are the knowledge it needs (\`pnpm clay get <id>\`).`}function Gt(t){return t.filter(n=>n.kind==="rule"&&n.scope==="email"&&n.severity==="Critical").sort((n,e)=>n.id<e.id?-1:1)}var Ai="policy.email.recipes.section-alias-map-for-explicit-section-list";function Ei(t){let n=t.units.find(s=>s.id===Ai);if(!n)return[];let e=[];for(let s of n.body.split(`
11
+ `)){let i=s.split("|").map(a=>a.trim());if(i.length<4||/^-+$/.test(i[1])||/brief word/i.test(i[1]))continue;let o=i[1].replace(/\([^)]*\)/g,"").split(",").map(a=>a.trim().toLowerCase()).filter(Boolean),r=[...i[2].matchAll(/`([a-z0-9-]+)`/g)].map(a=>a[1]);o.length&&r.length&&e.push([o,r])}return e}function Vt(t,n,e,s,i=3){let o=` ${e.toLowerCase().replace(/[^a-z0-9 -]+/g," ").replace(/\s+/g," ")} `,r=c=>t.units.some(u=>u.id===`section.email.${c}`||u.id===`component.email.${c}`),a={len:0,ids:[]};for(let[c,u]of Ei(t))for(let p of c)p.length>a.len&&o.includes(` ${p} `)&&(a={len:p.length,ids:u});let l=a.ids.filter(r).map(c=>t.units.some(u=>u.id===`section.email.${c}`)?`section.email.${c}`:`component.email.${c}`);for(let c of W(t,n,`${e} ${e} ${s}`,{kind:["section"],scope:["email"],k:i+3})){if(l.length>=i)break;l.includes(c.id)||l.push(c.id)}return l.slice(0,i)}var ji=2500,Li=2500,Ti={A:[],B:["policy.mode-b.precedence","policy.mode-b.defaults"]};function Yt(t,n){if(!n)return t;let e=t.split(`
12
+ `),s=e.map((o,r)=>({i:r,m:/^\*\*Mode ([AB])\b/.exec(o)?.[1]})).filter(o=>o.m);if(new Set(s.map(o=>o.m)).size<2)return t;let i=e.slice(0,s[0].i);return s.forEach((o,r)=>{o.m===n&&i.push(...e.slice(o.i,r+1<s.length?s[r+1].i:e.length))}),i.join(`
13
+ `).replace(/\n{3,}/g,`
14
+
15
+ `).trim()}var _i=10,Oi=.1,Ii=.15,Mi=12,Pi=5,Ni=new Set(["copy","page-file"]);function on(t){let n=t.split(`
16
+ `),e=[],s=/^(?:section\s+)?(\d+)(?:[.)]\s*|\s*[—–:-]\s*|\s+)/i,i=!1;n.forEach((l,c)=>{if(/^\s*(?:```|~~~)/.test(l)&&(i=!i),i)return;let u=/^(#{2,3})\s+(.+)$/.exec(l);if(!u)return;let p=u[2].trim();e.push({i:c,level:u[1].length,title:p,numbered:s.test(p)&&/^(?:section\s+)?\d+(?:[.)]|\s*[—–:-]|\s)/i.test(p)})});let o=l=>e.filter(c=>c.level===l&&c.numbered).length,r=o(2)>=o(3)?o(2)?2:o(3)?3:2:3,a=e.some(l=>l.numbered&&l.level===r)?e.filter(l=>l.numbered&&l.level===r):e.filter(l=>l.level===2&&!/^pmm brief\b/i.test(l.title));return a.map((l,c)=>{let u=Math.min(c+1<a.length?a[c+1].i:n.length,e.find(m=>m.i>l.i&&m.level<=l.level)?.i??n.length),p=n.slice(l.i+1,u).join(`
17
+ `),f=Number(s.exec(l.title)?.[1]??c+1),g=l.title.replace(s,"");return{n:f,title:g,text:p,items:qi(`${g}
18
+ ${p}`)}})}var Bi={two:2,three:3,four:4,five:5,six:6,seven:7,eight:8,nine:9,ten:10,twelve:12};function Fe(t){let e=(/^\s*-\s+\*\*Layout \(derived\):\*\*\s*(.*)$/m.exec(t)?.[1]??"").split("\xB7").map(i=>i.trim()),s=e.slice(1).map(i=>/^(\d+)\s+([a-z]+)/.exec(i)).filter(i=>!!i).map(i=>({n:Number(i[1]),kind:i[2]}));return{top:e[0]??"",groups:s}}function Ke(t){let n=t.split(`
19
+ `),e=[];for(let s=0;s<n.length;s++){let i=/^-\s+\*\*Items \((\d+), ([a-z]+)\b[^)]*\):\*\*(.*)$/.exec(n[s]);if(!i)continue;let o=0,r=i[3].trim();if(r)for(let a of r.split(/\s·\s(?=\d+\.\s)/))/^\d+\.\s+(?:img|video|image|svg|lottie)\b/i.test(a.trim())||o++;for(let a=s+1;a<n.length&&!/^-\s/.test(n[a])&&!/^#/.test(n[a]);a++){let l=/^\s{2,3}\d+\.\s+(.*)$/.exec(n[a]);l&&!/^(?:img|video|image|svg|lottie)\b/i.test(l[1].trim())&&o++}e.push({n:Number(i[1]),kind:i[2],text:o})}return e}function Fi(t){let n=Ke(t).filter(e=>e.kind!=="logos"&&e.n>=2&&e.text>=2&&!(e.kind==="tabs"&&e.n===2));for(let e=0;e+1<n.length;e++){let s=n[e],i=n.slice(e+1).find(o=>o.kind!==s.kind||o.n!==s.n);if(i)return{a:{n:s.n,kind:s.kind},b:{n:i.n,kind:i.kind}}}return null}function Ki(t){let n=t.split(`
20
+ `),e=Ke(t);for(let r of Fe(t).groups){if(r.kind==="logos"||r.n<2)continue;let a=e.find(l=>l.kind===r.kind&&l.n===r.n)??e.find(l=>l.kind===r.kind);if(!(a&&a.text===0)&&!(!a&&!["tabs","accordion","list"].includes(r.kind)))return r.n}let s=e.filter(r=>r.text>0&&r.kind!=="logos");if(s.length)return s[0].n>=2?s[0].n:null;if(e.length)return null;let i=new Map;for(let r of n){let a=/^-\s+\*\*CTA:\*\*\s*(.+?)\s*→/.exec(r)?.[1];a&&i.set(a.toLowerCase(),(i.get(a.toLowerCase())??0)+1)}let o=Math.max(0,...i.values());return o>=2?o:null}var ae=t=>/^\s*-\s+\*\*Layout \(derived\):\*\*/m.test(t);function qi(t){if(ae(t))return Ki(t);let n=t.split(`
21
+ `),e=n.filter(m=>/^\s*\|/.test(m)&&!/^\s*\|?\s*:?-{3,}/.test(m)),s=e.length>1?e.length-1:0,i=0,o=0;for(let m of n){let $=/^\s{0,4}(\d+)[.)]\s+\S/.exec(m);$&&(o=Number($[1])===1?1:o+1,i=Math.max(i,o))}let r=n.filter(m=>/^\s*[-*]\s+\*\*([^*]+?)\*\*\s*(?:[—–-]|:)\s*\S/.test(m)&&!/^\s*[-*]\s+\*\*[^*]*:\*\*/.test(m)).length,a=0;for(let m of n){if(!/\b(?:tabs?|chips?|logos?|items?|categories|cards?)\b/i.test(m))continue;let $=m.split("\xB7").length;$>a&&$>2&&(a=$);let S=/:\s*([^.]+)$/.exec(m)?.[1]?.split(",").length??0;/logos?/i.test(m)&&S>a&&S>2&&(a=S)}let l=0,c=0;for(let m of n)/^\s{2,}[-*]\s+(?:\([^)]{1,20}\)\s*)?[^*:]{2,60}?\s[—–]\s\S/.test(m)?c++:/^\s{4,}/.test(m)||(c=0),l=Math.max(l,c);let u=n.filter(m=>/^\s*[-*]\s+(?:\*\*)?(?:Card|Tab|Item|Step|Panel)\s+(?:[A-Z]|\d{1,2})\b/.test(m)).length,p=/\b(two|three|four|five|six|seven|eight|nine|ten|twelve|\d{1,2})\s+(?:[a-z-]+\s+){0,2}?(?:cards?|items?|tabs?|steps?|pillars?|columns?|features?|stats?|quotes?|categories)\b/i.exec(t)?.[1],f=p?/^\d+$/.test(p)?Number(p):Bi[p.toLowerCase()]:0,g=Math.max(s,i,r>=2?r:0,a,l>=2?l:0,u>=2?u:0,f);return g>=2?g:null}var Ui=/^[$€£]?\d[\d.,]*\s*(?:%|[KMB]\+?|x|\+)?$/i;function ne(t){let n=t.split(`
22
+ `),e=i=>/^\s{2,3}\d+\.\s+(.*)$/.exec(i)??/^\s?\d+[.)]\s+(.*)$/.exec(i),s={n:0,named:0,bullets:0,tags:0,media:0,rich:0,stats:0,quotes:0};for(let i=0;i<n.length;i++){let o=e(n[i]);if(!o)continue;let r=[];for(let g=i+1;g<n.length&&!e(n[g])&&!/^-\s|^#/.test(n[g]);g++)r.push(n[g]);let a=o[1],l=/^\*\*(.+?)\*\*/.exec(a)?.[1]?.trim()??"",c=r.join(`
23
+ `),u=/\*\*Items \(\d+, list\b/.test(c)||/\bbullets?\s*:/i.test(a),p=/\*\*Items \(\d+, (?:labels|tags)\b/.test(c)||/\btags?\s*:/i.test(a),f=/\b(?:video|img|image)\b/i.test(a);s.n++,l&&s.named++,u&&s.bullets++,p&&s.tags++,f&&s.media++,l&&(u||p||f||/\*\*\s+[—–]\s+\S/.test(a))&&s.rich++,Ui.test(l)||/^\s*(?:\*\*)?stat\b/i.test(a)?s.stats++:(l.length>=30&&/[.!?"”]$/.test(l)||/^\s*(?:\*\*)?quote\b/i.test(a))&&s.quotes++}return s}var rn=t=>t.n>=2&&t.named>=t.n*.8&&t.bullets>=t.n*.5&&t.media>=t.n*.5;function an(t){if(t.items==null||t.items<2)return null;let n=ne(t.text);if(n.rich<2||n.rich<n.n*.5)return null;let e=/^-\s+\*\*(?:Media|Image|Visual|Video|Hero (?:image|media|video))\b/im.test(t.text);return{n:t.items,agentCards:rn(n),heroMedia:e}}function rt(t){let n=[];for(let e of t.split(`
24
+ `)){let s=/^\s{2,3}\d+\.\s+(.*)$/.exec(e)??/^\s?\d+[.)]\s+(.*)$/.exec(e);if(!s)continue;let i=/^\*\*(.+?)\*\*/.exec(s[1])?.[1]?.trim()??"",o=(/^\*\*.+?\*\*\s+[—–]\s+(.*)$/.exec(s[1])?.[1]??"").split(/\s[—–]\s(?=(?:CTA|img|video|image)\b)/)[0].replace(/\s*_\([^)]*\)_\s*$/,"").trim();n.push({name:i,desc:o})}return n}function me(t){let n=t.items;if(n==null||n<2||fe(t))return null;let e=t.text;if(/^\s{2,}-\s+\*\*Items \(/m.test(e))return null;let s,i,o=e.split(`
25
+ `).filter(p=>/^-\s+\*\*(?:Layout|Pattern|Interactive|Interaction|Format)\b/i.test(p)).join(" ");if(/\bhorizontal\b|\btab (?:row|strip|bar)\b|\btabs? (?:in|on) a row\b/i.test(o))return null;if(ae(e)){let p=Fe(e).groups.find($=>$.kind!=="logos"&&$.n>=2);if(!p||p.kind!=="tabs"&&p.kind!=="accordion"||p.n!==n)return null;s=p.kind;let f=e.split(`
26
+ `),g=f.findIndex($=>new RegExp(`^-\\s+\\*\\*Items \\(${n}, ${p.kind}\\b`).test($));if(g<0)return null;let m=[];for(let $=g+1;$<f.length&&!/^-\s|^#/.test(f[$]);$++)m.push(f[$]);i=m.join(`
27
+ `)}else{let p=e.split(`
28
+ `).filter(f=>!/\bmobile\b/i.test(f)&&/\b(?:interactive|layout|pattern|interaction|format)\b/i.test(f)).join(" ");if(!/\baccordion\b|\bvertical (?:tabs?|list)\b|\bexpand(?:s|able)?\b/i.test(p))return null;s=/\btabs?\b/i.test(p)?"tabs":"accordion",i=e}let r=rt(i);if(r.length<2||r.filter(p=>p.name&&p.desc.length>=20).length<r.length*.8)return null;let a=ne(i),l=Ke(e).some(p=>p.n===n&&p.text===0),c=a.media>=r.length*.5||l||!ae(e)&&/\b(?:per|each|every) (?:item|tab|step)\b[^.\n]{0,40}\b(?:visual|image|media|screenshot|video)|\b(?:visual|image|media|screenshot)s? (?:swap|switch|change)s?\b/i.test(e),u=he(e);return!c&&!u?null:{n,visual:c?"item":"shared",labelled:s}}function fe(t){let n=rt(t.text);return n.length>=2&&n.filter(e=>/\?\s*$/.test(e.name)).length>n.length/2?!0:/\bfaqs?\b|\bfrequently asked\b/i.test(t.title)}var he=t=>/^-\s+\*\*(?:Media|Image|Visual|Video|Screenshot)\b/im.test(t),ln=["layout.FeaturesSection.side-by-side","layout.FeaturesSection.side-by-side-lines","layout.FeaturesSection.accordion-media-right"];function Hi(t,n,e=()=>!1){let s=new Map,i=new Map;return t.forEach((o,r)=>{if(e(r))return;let a=o.candidates.findIndex(S=>!S.part),l=o.candidates[a];if(!l||!ln.includes(l.id))return;let c=i.get(l.id);if(c==null){i.set(l.id,o.section.n);return}let u=me(o.section),g=((u?u.visual==="shared":he(o.section.text)&&ne(o.section.text).media===0)?["layout.FeaturesSection.accordion-media-right"]:["layout.FeaturesSection.side-by-side-lines","layout.FeaturesSection.side-by-side",...he(o.section.text)?["layout.FeaturesSection.accordion-media-right"]:[]]).find(S=>!i.has(S)&&n.has(S)&&lt(n.get(S),o.section.items)!=="over");if(!g){s.set(r,{prev:c,from:l.id,to:null});return}let m=o.candidates.findIndex(S=>S.id===g),$=m>=0?o.candidates[m]:ye(n.get(g),o.section);o.candidates=o.candidates.filter((S,y)=>y!==a&&y!==m),o.candidates.splice(a,0,$),i.set(g,o.section.n),s.set(r,{prev:c,from:l.id,to:g})}),s}function Di(t){let n=t.items;if(n==null||n<2||fe(t))return null;let e=t.text.split(`
29
+ `),s;if(ae(t.text)){let o=Fe(t.text).groups.find(c=>c.kind!=="logos"&&c.n>=2);if(!o||o.kind!=="accordion"||o.n!==n)return null;let r=e.findIndex(c=>new RegExp(`^-\\s+\\*\\*Items \\(${n}, accordion\\b`).test(c));if(r<0)return null;let a=new RegExp(`^-\\s+\\*\\*Items \\(${n}, accordion\\b`);s=[];let l=!0;for(let c=r;c<e.length;c++)/^-\s|^#/.test(e[c])&&(l=a.test(e[c])),l||s.push(e[c])}else{let o=e.filter(r=>!/\bmobile\b/i.test(r)&&/\b(?:interactive|layout|pattern|interaction|format)\b/i.test(r)).join(" ");if(!/\baccordion\b/i.test(o)||!/\b(?:carousel|slider|cards)\b/i.test(o)||!/\b(?:driv|swap|switch|select|chang|control)\w*/i.test(o))return null;s=e}let i=s.map(o=>/^\s*\d+[.)]\s+\*\*(.+?)\*\*\s+[—–]\s+(.*)$/.exec(o)).filter(o=>!!o&&!/^CTA\b/.test(o[2].trim())&&o[2].split(/\s[—–]\s/)[0].trim().length>=20);return ae(t.text)?i.length>=2?{n,cards:i.length}:null:{n,cards:Math.max(0,i.length-n)}}var Jt=t=>t>5?"layout.CardsSection.horizontal-reveal":"layout.CardsSection.side-by-side",zi=["layout.FeaturesSection.tab-cards-carousel","layout.FeaturesSection.accordion-media-right"];function Wi(t,n,e=()=>!1){let[s,i]=zi,o=t.map((c,u)=>e(u)?null:Di(c.section)),r=t.find((c,u)=>!e(u)&&!o[u]&&c.candidates.find(p=>!p.part)?.id===s)?.section.n??null,a=new Map,l=r;return t.forEach((c,u)=>{let p=o[u];if(!p)return;let f=l==null?s:i,g=l;l==null&&(l=c.section.n);let m=c.candidates.find(v=>v.id===f)??(n.has(f)?ye(n.get(f),c.section):null),$=c.candidates.filter(v=>v.id!==f&&!v.part&&!(f===i&&v.id===s)).slice(0,1),S=p.cards>=2&&n.has(Jt(p.cards))?Jt(p.cards):null,y=S?{...ye(n.get(S),{...c.section,items:p.cards}),part:"b"}:null;c.candidates=[...m?[m]:[],...$,...y?[y]:[]],a.set(u,{takenBy:f===i?g:null,layout:f,cards:p.cards,nb:S})}),a}var ge=["layout.FeaturesSection.stacked-rows","layout.FeaturesSection.stacked-media-left"];function Gi(t,n,e,s=()=>!1){let i=new Map,o=new Map;return t.forEach((r,a)=>{let l=r.candidates.find(c=>!c.part)?.id;!s(a)&&!e(a)&&l?.startsWith("layout.FeaturesSection.")&&!o.has(l)&&o.set(l,r.section.n)}),t.forEach((r,a)=>{if(s(a)||!e(a))return;let l=ge.find(p=>!o.has(p)&&n.has(p));if(!l){i.set(a,{prev:o.get(ge[0])??null,to:null});return}let c=l===ge[0]?null:o.get(ge[0])??null,u=r.candidates.find(p=>p.id===l)??ye(n.get(l),r.section);r.candidates=[u,...r.candidates.filter(p=>p.id!==l&&!ge.includes(p.id))].slice(0,2),o.set(l,r.section.n),i.set(a,{prev:c,to:l})}),i}function cn(t){let n=t.text.split(`
30
+ `).filter(i=>!/\bmobile\b/i.test(i)&&!/^\s*-\s+\*\*(?:Headline|Body|Subheadline|Description|CTA|Eyebrow|Items \(|Layout \(derived\))/i.test(i)&&!/^\s+\d+[.)]\s/.test(i)).join(" ").replace(/https?:\/\/\S+|\bCDN2?\/\S+|\S+\.(?:avif|png|jpe?g|webp|mp4|webm|svg|gif)\b/gi," ");if(/\btext[- ]only\b|\bno (?:hero )?(?:media|visual|image)\b/i.test(n))return{dir:"text",why:"cue"};if(/\bsplit\b|\bside[- ]by[- ]side\b|\btwo[- ]column\b|\b(?:copy|text|headline)\s+(?:on\s+the\s+)?left\b|\b(?:media|image|visual|video|screenshot|photo)\s+(?:on\s+the\s+)?right\b/i.test(n))return{dir:"split",why:"cue"};if(/\bcent(?:er|re)d?\b|\b(?:copy|text)\s+above\b|\b(?:media|image|visual|video|screenshot)\s+below\b/i.test(n))return{dir:"centered",why:"cue"};let e=Ke(t.text),s=e.find(i=>i.n>=2&&i.text===i.n&&ne(t.text).rich===0);return s&&e.some(i=>i!==s&&i.n===s.n&&i.text===0)?{dir:"split",why:"selector"}:he(t.text)||e.some(i=>i.text===0)?{dir:"centered",why:"default"}:null}var Xt={split:["split","split-full-image","split-mosaic","split-strip","split-search","floating-left"].map(t=>`layout.HeaderSection.${t}`),centered:["centered-image","left-center-image","centered-strips"].map(t=>`layout.HeaderSection.${t}`),text:["layout.HeaderSection.text-only"]};function Zt(t){let n=t.items;if(n==null||n<4||n>8||/\b(?:faq|questions?|testimonials?|quotes?|stats?|numbers?|logos?|pricing)\b/i.test(t.title))return null;let e=D(t);if(e.tabs||e.accordion||e.hasMedia||e.itemCta||/^\s{2,}-\s+\*\*Items \(/m.test(t.text))return null;let s=rt(t.text),i=ne(t.text);if(s.length!==n||i.media||i.bullets||i.tags||i.stats||i.quotes||s.some(r=>!r.name||r.desc.length<20))return null;let o=s.filter(r=>r.name.length<=18&&r.desc.length<=84).length>=n*.8;return{n,short:o}}var Vi=[{name:"agent cards (name + bullets + tags + media)",test:(t,n)=>rn(n),layout:"layout.CardsSection.horizontal-reveal",factor:3,unit:"policy.mode-b.hero-item-split"},{name:"vertical item list + a visual per item",test:t=>{let n=me(t);return!!n&&n.visual==="item"&&n.n<=5},layout:"layout.FeaturesSection.side-by-side",factor:4,unit:"policy.tabs.layout-by-count"},{name:"vertical item list + one shared visual (or a visual per item past 5)",test:t=>{let n=me(t);return!!n&&(n.visual==="shared"||n.n>5)},layout:"layout.FeaturesSection.accordion-media-right",factor:4,unit:"policy.tabs.layout-by-count"},{name:"FAQ by its questions (title not FAQ)",test:t=>fe(t)&&!/\bfaqs?\b|\bquestions\b/i.test(t.title),layout:"layout.FaqSection.centered",factor:4,unit:"section.FaqSection.usage"},{name:"FAQ by its questions, side-by-side (title not FAQ)",test:t=>fe(t)&&!/\bfaqs?\b|\bquestions\b/i.test(t.title),layout:"layout.FaqSection.side-by-side",factor:3,unit:"section.FaqSection.usage"},{name:"text cards (name + description, no media)",test:t=>!!Zt(t),layout:"layout.FeaturesSection.split-icon-list",factor:4,unit:"policy.layout.chooser.FeaturesSection"},{name:"short text cards (fit BulletItem limits)",test:t=>!!Zt(t)?.short,layout:"layout.BulletsSection.icons",factor:2.5,unit:"section.BulletsSection.usage"},{name:"stat + quote cards",test:(t,n)=>n.stats>=1&&n.quotes>=1,layout:"layout.TestimonialsSection.mixed-stat-and-quote",factor:4,unit:"policy.layout.chooser.TestimonialsSection"}],Yi=new Set(["layout.TestimonialsSection.mixed-stat-and-quote","layout.TestimonialsSection.carousel-with-stat"]);function Ji(t){let n=/\bbg rgb\((\d+),\s*(\d+),\s*(\d+)\)/.exec(t.text);if(n){let e=n.slice(1,4).map(Number);return Math.min(...e)>=225&&Math.max(...e)<=250&&Math.max(...e)-Math.min(...e)<=10}return/\b(?:grey|gray|muted)\s+(?:band|background|bg|section)\b|\btheme:?\s*`?muted\b/i.test(t.text)}function D(t){let n=`${t.title}
31
+ ${t.text}`,e=/\b(?:logos?|testimonials?|quotes?|faq|questions?|stats?|numbers?|integrations?|badges?|g2|pricing|form)\b/i.test(t.title),s=Fe(t.text),i=s.groups.find(m=>m.kind!=="logos"&&m.n===t.items)?.kind??"",o=t.text.split(`
32
+ `).filter(m=>!/\bmobile\b/i.test(m)&&/\b(?:interactive|layout|pattern|interaction|format)\b|\d+\s+(?:tabs|accordion)/i.test(m)).join(" "),r=/\*\*Logos \((\d+)\):\*\*\s*(.*)$/m.exec(t.text),a=r?Number(r[1]):s.groups.filter(m=>m.kind==="logos").map(m=>m.n)[0]??null,l=/^\s*-\s+\*\*(?:Body|Subheadline|Description)\b/im.test(t.text),c=/\*\*\s*cta\b|^\s*-\s*cta\b/im.test(n),u=a!=null&&t.items==null&&!l&&!c&&(s.top==="logos"||s.top===""||/\blogos?\b/i.test(t.title)),p=/\bintegrat|\bconnect (?:all )?your (?:tools|apps)|\bapps?\b|\btools\b/i.test(`${t.title} ${r?.[2]??""}`),f=/^\s*-\s+\*\*Visible:\*\*\s*(mobile|desktop) only/im.exec(t.text)?.[1]?.toLowerCase(),g=!!me(t);return{statement:t.items==null&&!e&&!u,grid:/\bgrid\b|\d\s*[×x]\s*\d|\bcolumns?\b|\bicons?\b|\bicon\s*·/i.test(n.split(`
33
+ `).filter(m=>!/mobile/i.test(m)).join(`
34
+ `)),hasCta:c,hasMedia:/\b(?:media|visual|image|video|illustration|screenshot|diagram)\b|\.(?:avif|png|jpe?g|webp|mp4|webm)\b/i.test(n),...Zi(t),tabs:!g&&(i==="tabs"||!i&&/\btabs?\b/i.test(o)),accordion:g||i==="accordion"||!i&&/\baccordion\b/i.test(o),logoStrip:u?p?"integration":"customer":null,logos:a,caseStudy:(t.text.match(/case[- ]stud(?:y|ies)/gi)??[]).length>=2,visibleAt:f??null,variantOf:Number(/responsive variant of §(\d+)/i.exec(t.text)?.[1]??"")||null}}var Qt=t=>new Set(t.toLowerCase().replace(/[^a-z0-9 ]/g," ").split(/\s+/).filter(n=>n.length>2&&!["the","and","for","with","your","our"].includes(n)));function Xi(t,n){let e=D(t[n]);if(e.variantOf)return{n:e.variantOf,marked:!0};if(e.visibleAt!=="mobile"||n===0)return null;if(n<=3&&t[n].items==null&&D(t[0]).visibleAt==="desktop"&&e.hasCta&&he(t[n].text)&&!t.slice(1,n).some(o=>D(o).visibleAt==="mobile"))return{n:t[0].n,marked:!1,hero:!0};let s=Qt(t[n].title),i=null;return t.forEach((o,r)=>{if(r===n)return;let a=D(o);if(a.visibleAt===e.visibleAt||a.variantOf)return;let l=Qt(o.title),c=[...s].filter(p=>l.has(p)).length,u=c/Math.max(1,Math.min(s.size,l.size))+(o.items!=null&&o.items===t[n].items?.4:0);c&&u>=.75&&(!i||u>i.score)&&(i={n:o.n,score:u})}),i?{n:i.n,marked:!1}:null}function Zi(t){let n=t.text.split(`
35
+ `),e=n.filter(o=>/^\s*[-*]\s+(?:\*\*)?(?:primary |secondary )?cta\b/i.test(o)).length,s=n.filter(o=>/^\s*[-*]\s+(?:\*\*)?(?:image|visual|media|screenshot|video)\b/i.test(o)||/^\s{0,4}\d+[.)]\s.*\b(?:img|image|video)\b/i.test(o)).length,i=t.items??0;return{itemMedia:i>=2&&s>=2,itemCta:i>=2&&e>=2}}var Qi={Critical:3,Major:2,Minor:1},es={procedure:2.5,policy:2,rule:2,gotcha:1.8,recipe:1.2,section:1,layout:1,component:.8,limit:.6,"item-type":.6,stat:.8,"brand-fact":.6},ts=new Set(["section","layout","limit","item-type","component"]),at={"web-compose":["web-structure","web-design","web-assets","web-qa","web-static","knowledge-capture","web-design-brain"],"web-pmm":["web-compose","web-structure","web-design","web-assets","web-qa","web-static"],"web-benchmark":["web-compose","web-qa","web-static"],"web-remix":["web-compose","web-static","web-qa"],"web-custom-section":["web-qa"]};function ns(t,n){let e=t.entities.filter(i=>i.startsWith("skill:")).map(i=>i.slice(6));if(!e.length)return!1;let s=new Set([n,...at[n]??pe[n]??[]]);return!e.some(i=>s.has(i))}var en=t=>`skill:${t}`,tn=t=>t.entities.find(n=>n.startsWith("skill:"))?.slice(6),is=(t,n)=>t.authority!=="background"&&t.status==="active"&&t.stages.includes(n.stage)&&(!n.mode||!t.modes||t.modes.includes(n.mode))&&zt(t,n.skill)&&t.kind!=="token"&&t.kind!=="asset";function le(t){let n=t.facts??{},e=[],s=n.items;s&&(s.min!=null||s.max!=null)&&e.push(s.min===s.max?`${s.min}`:`${s.min??"?"}\u2013${s.max??"\u2026"}`),n.tabLabel?.length&&e.push(`tab label ${n.tabLabel[0]}${n.tabListScrollable?", scrolls":""}`);let i=(n.propsIgnored??[]).filter(r=>["sectionDescription","sectionTopic","sectionHeading","sectionCta","tagline"].includes(r));i.length&&e.push(`drops ${i.join("/")}`);let o=(n.buttons??[]).filter(r=>r.heightPx!=null&&r.heightPx<44);return o.length&&e.push(`CTA ${o[0].heightPx}px`),`${n.section??""} ${n.layout??t.id}${e.length?` (${e.join("; ")})`:""}`.trim()}function ye(t,n,e=D(n)){let s=le(t),i=t.facts?.section??t.id.split(".")[1],o=(t.facts??{}).propsRendered;return e.hasCta&&o&&!o.some(r=>/cta|button|action/i.test(r))&&!["HeaderSection","CtaSection"].includes(i)&&(s=s.endsWith(")")?`${s.slice(0,-1)}; no section CTA)`:`${s} (no section CTA)`),{id:t.id,line:s,fit:lt(t,n.items)}}function lt(t,n){let e=t.facts?.items;return!e||n==null?"unknown":e.max!=null&&n>e.max?"over":e.min!=null&&n<e.min?"under":"fits"}function dn(t,n,e,s,i={first:!1,last:!1},o=2){let r=ls(e),a=k=>k.facts?.section??k.id.split(".")[1],l=new Map;for(let k of W(t,n,r,{kind:["section"],k:40})){if(k.id.includes(".example."))continue;let R=k.id.split(".")[1];l.set(R,Math.max(l.get(R)??0,k.score))}let c=Math.max(1,...l.values()),u=new Map;for(let k of W(t,n,r,{kind:["layout"],authority:["derived"],k:40}))u.set(k.id,k.score);let p=Math.max(1,...u.values()),f=t.units.filter(k=>k.kind==="layout"&&k.authority==="derived"),g=D(e),m=Vi.filter(k=>k.test(e,ne(e.text))),$=fe(e),S=/\b(?:closing|final)\b.*\bcta\b|\bcta\b/i.test(e.title)||i.last&&g.hasCta&&e.items==null,y=k=>/Use for: ([^\n]*)/.exec(k.body)?.[1]??"",v=f.map(k=>{let R=a(k),E=(u.get(k.id)??0)/p+.8*((l.get(R)??0)/c);R==="HeaderSection"?E*=i.first?2:.2:i.first&&(E*=.5),R==="CtaSection"&&S&&(E*=1.8),["NavbarMenu","FooterSection"].includes(R)&&(E*=.1);for(let[j,M,B]of ss)j.test(e.title)&&M.test(k.id)&&(E*=B);if(k.id==="layout.CtaSection.floating-card"&&(E*=i.last?S?3:1.5:.3),!i.first&&!i.last&&!S){let j=`${e.title} ${e.text.split(`
36
+ `).filter(M=>!/^\s*-\s+\*\*(?:Items \(|Layout \(derived\))/.test(M)).join(" ")}`;R==="CardsSection"&&e.items!=null&&/\bcards?\b/i.test(j)&&(E*=1.5),g.tabs&&/^layout\.FeaturesSection\.(?:tabs-|tab-cards-carousel)/.test(k.id)&&(E*=2),g.accordion&&/^layout\.FeaturesSection\.(?:side-by-side|numbered-accordion|accordion-media-right)/.test(k.id)&&(E*=2),(g.tabs||g.accordion)&&/^layout\.CardsSection\./.test(k.id)&&(E*=.5),g.caseStudy&&/^layout\.TestimonialsSection\.(?:carousel-case-study|mixed-stat-and-quote)/.test(k.id)&&(E*=2),g.grid&&e.items!=null&&(/\bgrid\b|\bicon/i.test(y(k))&&(E*=1.8),/accordion|carousel|tabs?\b/i.test(k.id)&&(E*=.6)),g.statement&&(g.hasMedia&&/^layout\.FeaturesSection\.(?:side-by-side|stacked-rows)$/.test(k.id)||!g.hasMedia&&k.id==="layout.CtaSection.centered"?E*=3:g.hasCta&&k.id==="layout.CtaSection.centered"&&(E*=1.6),/^layout\.(?:Integrations|TrustSection|NumbersSection|TestimonialsSection|CustomerLogoSection|FaqSection)\./.test(k.id)&&(E*=.3))}let O=Object.values((k.facts??{}).itemFields??{}).flatMap(j=>j.rendered);if(O.length&&!($&&R==="FaqSection")&&(g.itemMedia&&!O.some(j=>/^(?:media|image|visual|video)/i.test(j))&&(E*=.5),g.itemCta&&!O.some(j=>/^(?:actions?|cta\d?|link\w*|href)$/i.test(j))&&(E*=.6)),g.logoStrip){let j=g.logoStrip==="integration"?/^layout\.Integrations\./:/^layout\.CustomerLogoSection\./;E*=j.test(k.id)?4:/^layout\.(?:CustomerLogoSection|Integrations)\./.test(k.id)?1.5:.2}if(!i.first)for(let j of m)j.layout===k.id&&(E*=j.factor);let I=lt(k,e.items);return E*=I==="fits"?1.25:I==="over"?.8:I==="under"?.75:1,{u:k,fit:I,s:E}});v.sort((k,R)=>R.s-k.s||(k.u.id<R.u.id?-1:1));let A=v.slice(0,o),b=i.first?cn(e):null;if(b){let k=Xt[b.dir],R=v.filter(j=>a(j.u)==="HeaderSection"),E=R.filter(j=>k.includes(j.u.id)),O=(b.why==="selector"?E.find(j=>j.u.id==="layout.HeaderSection.split"):void 0)??E[0],I=b.why==="default"?R.find(j=>Xt.split.includes(j.u.id)):E.find(j=>j!==O);O&&A.splice(0,A.length,O,...[I??R.find(j=>j!==O)].filter(j=>!!j&&j!==O))}if(!i.first){for(let k of m)if(!A.some(R=>R.u.id===k.layout)){let R=v.find(E=>E.u.id===k.layout);R&&A.push(R)}}if(e.items!=null&&!A.some(k=>k.fit==="fits")){let k=new Set(A.map(E=>a(E.u))),R=v.slice(o,12).find(E=>E.fit==="fits"&&k.has(a(E.u)));R&&A.push(R)}let C=A.map(({u:k})=>ye(k,e,g));if(i.first&&an(e)){let k=dn(t,n,e,s,{first:!1,last:!1},1).filter(R=>!R.id.startsWith("layout.HeaderSection."));for(let R of k)C.push({...R,part:"b"})}return C}var ss=[[/\b(?:customer )?logos?\b(?!.*integrat)|\btrusted by\b(?!.*(?:enterprise|leader))/i,/^layout\.CustomerLogoSection\./,2.5],[/\bintegrations?\b/i,/^layout\.Integrations\./,2],[/\b(?:trust(?:ed)?|security|compliance|enterprise[- ]grade)\b/i,/^layout\.TrustSection\./,2],[/\bfaq\b|\bquestions\b/i,/^layout\.FaqSection\./,2.5],[/\bstats?\b|\bnumbers?\b|\bmetrics?\b/i,/^layout\.NumbersSection\./,1.8],[/\b(?:case[- ]stud(?:y|ies)|testimonials?|customer (?:results|stories|quotes))\b/i,/^layout\.TestimonialsSection\./,1.8],[/\bcase[- ]stud(?:y|ies)\b/i,/case-study/,1.4]];function os(t,n,e,s=[],i={}){let o=[];for(let r of rs){let a=r.hint({sec:t,pos:n,twin:e,candidates:s,page:i});if(a&&(o.push(a),r.stop))break}return o.join(" \xB7 ")}var rs=[{name:"responsive twin",stop:!0,hint:({twin:t,sec:n})=>t?t.hero?`mobile-only hero \u2192 likely twin of \xA7${t.n}: fold into it, add no section; its own copy (headline, form) is a \`[COPY: mobile hero, \xA7${n.n}]\` flag, not a section (\`policy.mode-b.responsive-variants\`)`:`${t.marked?"":"likely "}twin of \xA7${t.n} \u2192 fold into it, add no section (\`policy.mode-b.responsive-variants\`)`:""},{name:"logo strip",stop:!0,hint:({sec:t})=>{let n=D(t);return n.logoStrip?`${n.logos} logos, not items`:""}},{name:"hero direction (K11 F1)",hint:({sec:t,pos:n})=>{let e=n.first?cn(t):null;return e?`${e.why==="cue"?`brief says ${e.dir==="split"?"split":e.dir==="text"?"text-only":"centered"}`:e.why==="selector"?"tabs + a visual per tab = selector hero: copy + tabs (`options`) left, visual right \u2192 `split`":"direction not in the brief: copy above the visual \u2192 `centered-image`, copy left + visual right \u2192 `split*`; check the live hero"} (wrong direction \u221220, \`policy.benchmark.rubric-layout-hero\`)`:""}},{name:"hero + items no HeaderSection slot holds (K11)",stop:!0,hint:({sec:t,pos:n})=>{let e=n.first?an(t):null;if(!e)return"";let s=e.agentCards?"`CardsSection.horizontal-reveal` (agent cards)":"one item section";return`hero + ${e.n} items no HeaderSection slot holds \u2192 \xA7${t.n}a HeaderSection${e.heroMedia?"":" `text-only`"} (copy) + \xA7${t.n}b ${s} directly below; keep every copy beats never split (\`policy.mode-b.hero-item-split\`)`}},{name:"accordion driving a card carousel (K11 F1)",stop:!0,hint:({sec:t,page:n})=>{let e=n?.carousel;if(!e)return"";let s=e.takenBy==null?"`tab-cards-carousel`":`\xA7${e.takenBy} has \`tab-cards-carousel\` \u2192 \`accordion-media-right\``,i=e.nb?`; the ${e.cards} cards with copy \u2192 \xA7${t.n}b \`${e.nb.replace(/^layout\./,"")}\` below`:"";return`accordion driving a card carousel: ${s} + \`[GAP: accordion-driven carousel]\` (\u22125 once)${i} (\`policy.layout.accordion-carousel\`)`}},{name:"two item groups",stop:!0,hint:({sec:t,pos:n})=>{let e=!n.first&&ae(t.text)?Fi(t.text):null;return e?`2 item groups (${e.a.n} ${e.a.kind} + ${e.b.n} ${e.b.kind}) \u2192 two adjacent sections \xA7${t.n}a/\xA7${t.n}b, nothing dropped (\`policy.mode-b.two-item-groups\`)`:""}},{name:"vertical item list labelled tabs (K11 B2)",hint:({sec:t,pos:n,candidates:e})=>{let s=n.first?null:me(t);if(!s||s.labelled!=="tabs")return"";let i=e.find(r=>!r.part)?.id,o=i&&ln.includes(i)?`\`${i.replace(/^layout\./,"")}\``:s.visual==="item"&&s.n<=5?"`FeaturesSection.side-by-side`":"`FeaturesSection.accordion-media-right`";return`${s.n} "tabs" that show their own copy = a vertical list (expands in place), not a tab row \u2192 ${o}, not tabs-* (\`policy.tabs.layout-by-count\`)`}},{name:"live grey band + grey cards (K11)",hint:({sec:t,pos:n,candidates:e})=>{if(n.first||!Ji(t))return"";let s=e.filter(r=>Yi.has(r.id)).map(r=>`\`${r.id.replace(/^layout\./,"")}\``),i=ne(t.text);return!s.length&&!(i.stats>=1&&i.quotes>=1)?"":`live grey band + grey cards (${s.length?s.join(" / "):"stat + quote cards: the TestimonialsSection carousels"}) \u2192 the grey-on-grey Critical beats the band: \`theme="default"\`, log \`[COPY: grey band dropped, grey cards]\` (\`policy.mode-b.precedence\` tint exception 2)`}},{name:"statement",hint:({sec:t,pos:n,page:e})=>{let s=D(t);if(n.first||n.last||!s.statement)return"";if(!s.hasMedia)return"[GAP?] statement: no single-statement section; CtaSection centered if it carries a CTA";let i=e?.statement;return i&&!i.to?`[GAP?] statement + media: both 1-item stand-ins are taken (\xA7${i.prev} has \`stacked-rows\`): keep \`stacked-media-left\`, log \`[GAP: layout-diversity]\` (\`policy.layout.statement-stand-in\`)`:`[GAP?] statement + media \u2192 a single-item FeaturesSection ${i?.to?`\`${i.to.replace(/^layout\.FeaturesSection\./,"")}\`${i.prev!=null?` (\xA7${i.prev} has \`stacked-rows\`)`:""}`:"`stacked-rows`"}; never \`''\` (\`policy.layout.statement-stand-in\`)`}}];function ct(t){let n=t?.facts??{},e=(s,i)=>!s||s.min==null&&s.max==null?"":s.min!=null&&s.max!=null?s.min===s.max?`${s.max}${i}`:`${s.min}\u2013${s.max}${i}`:s.max!=null?`\u2264${s.max}${i}`:`\u2265${s.min}${i}`;return[e(n.chars,"c"),e(n.words,"w"),e(n.sentences,"s")].filter(Boolean).join(" ")}function as(t,n){let e=t.facts??{},s=[];for(let[i,{rendered:o}]of Object.entries(e.itemFields??{})){let l=((n.get(`item.${i}`)?.facts??{}).fields??[]).filter(u=>o.includes(u.name));if(!l.length)continue;let c=u=>{let p=ct(u.limitId?n.get(u.limitId):void 0),f=/^\{/.test(u.type)?`{${[...u.type.matchAll(/(\w+)\??:/g)].map(g=>g[1]).filter(g=>g!=="onClick").join(",")}}`:"";return`${u.required?"\u25CF":""}${u.name}${f}${p?` ${p}`:""}`};s.push(`- \`clay section ${e.section} --layout ${e.layout}\` \xB7 ${i}: ${l.map(c).join(" \xB7 ")}`)}return s}function ls(t){let n=t.text.replace(/https?:\/\/\S+|`[^`]*`/g," "),e=n.split(`
37
+ `).filter(s=>/\b(?:layout|interactive|columns?|grid|carousel|tabs?|accordion|marquee|cards?)\b/i.test(s)&&!/^\s*\|/.test(s)&&!/\bmobile\b/i.test(s)).map(s=>s.slice(0,200)).join(" ");return`${t.title} ${t.title} ${e} ${e} ${n.slice(0,400)}`}function nn(t){let n=t.split(`
38
+ `),e=/^\s*\*\*Section\s+\d+:?\*\*:?\s*(.+)$/i,s=n.map((o,r)=>({i:r,m:e.exec(o)?.[1]?.replace(/\*\*/g,"").trim()})).filter(o=>o.m);if(s.length)return s.slice(0,20).map((o,r)=>({title:o.m,text:n.slice(o.i+1,r+1<s.length?s[r+1].i:Math.min(n.length,o.i+25)).join(" ").slice(0,400)}));let i=n.findIndex(o=>/must-have blocks/i.test(o));if(i>=0){let o=[];for(let r=i+1;r<n.length&&o.length<12;r++)if(/^\s*[-*]\s+/.test(n[r]))o.push(n[r].replace(/^\s*[-*]\s+/,"").trim());else if(o.length&&n[r].trim()&&!/^\s{2,}/.test(n[r]))break;if(o.length)return o.map(r=>({title:r,text:""}))}return on(t).map(o=>({title:o.title,text:o.text.slice(0,400)}))}var cs=new Set(["procedure.compose.inputs"]),ds=["section.NavbarMenu.example.full","section.FooterSection.example.default"],sn=t=>t.replace(/\n[ \t]*\n+/g,`
39
+ `).trim();function dt(t,n,e){let s=e.budget??(e.brief&&(e.stage==="mapping"||e.stage==="structure")?Li:ji),i=new Map(t.units.map(h=>[h.id,h])),o=t.units.filter(h=>is(h,e)),r=new Set,a=[],l=[],c=!!e.compact,u=h=>`${h.join(c?`
40
+ `:`
41
+
42
+ `)}
43
+ `,p=(h="")=>X(u(h?[...l,h]:l)),f=h=>p(h)<=s,g=e.brief?on(e.brief):[],m=Be(e.skill),$=m?`# clay route \xB7 ${e.skill} \xB7 stage ${e.stage} (scope email)
44
+ ${e.brief?`Brief: ${e.briefLabel??"(inline)"} \u2014 ${nn(e.brief).length} blocks. `:""}Units are the source of truth (\`pnpm clay get <id>\` for any id below; \`pnpm clay section email.<id>\` for one email section: slots, brief fields, limits, gotchas).`:c?`# clay route \xB7 ${e.skill}${e.mode?` \xB7 mode ${e.mode}`:""} \xB7 stage ${e.stage}${e.brief?` \xB7 brief: ${g.length} sections`:""} (\`clay get <id>\` for any id)`:`# clay route \xB7 ${e.skill}${e.mode?` \xB7 mode ${e.mode}`:""} \xB7 stage ${e.stage}
45
+ ${e.brief?`Brief: ${e.briefLabel??"(inline)"} \u2014 ${g.length} sections. `:""}Units are the source of truth (\`pnpm clay get <id>\` for any id below; \`pnpm clay section <Section> --layout <l>\` for a layout).`;l.push($);let S=o.filter(h=>h.kind==="procedure"&&h.entities.includes(en(e.skill))).sort((h,w)=>+!!w.modes-+!!h.modes||+(tn(w)===e.skill)-+(tn(h)===e.skill)||(h.id<w.id?-1:1)),y=h=>`### ${h.id}
46
+ ${c?sn(Yt(h.body,e.mode)):Yt(h.body,e.mode)}`,v=new Set(e.mode?Ti[e.mode]:[]),A=[],b=h=>!!e.seen?.bodies.has(h),C=h=>b(h)||!!e.seen?.lines.has(h),k=[],R=[];for(let h of S){if(b(h.id)){k.push(h.id),r.add(h.id);continue}if(c&&e.brief&&cs.has(h.id)){R.push(h.id),r.add(h.id);continue}let w=y(h);(!A.length||X([...A,w].join(`
47
+ `))<=s*.3)&&(A.push(w),r.add(h.id),a.push({id:h.id,tier:"do",inlined:"body"}))}A.length&&l.push(`## Do
48
+ ${A.join(c?`
49
+ `:`
50
+
51
+ `)}`);let E=Be(e.skill);if(E){let h=Wt(e.skill,e.stage);h&&l.push(h);let w=Gt(o).filter(L=>!r.has(L.id));if(w.length){l.push(`## Gates (Critical email rules of this stage \u2014 \`pnpm email:check\` fails on them)
52
+ ${w.map(L=>`- \`${L.id}\` \u2014 ${L.summary.replace(/^Email rule \S+ \([^)]*\): /,"")}`).join(`
53
+ `)}`);for(let L of w)r.add(L.id),a.push({id:L.id,tier:"decides",inlined:"summary"})}}let O=[];for(let h of S.filter(w=>r.has(w.id)))for(let w of h.relations?.precedence??[]){let L=i.get(w);L&&L.authority!=="background"&&!r.has(w)&&!O.includes(L)&&O.push(L)}for(let h of o)e.mode&&h.modes?.includes(e.mode)&&h.kind==="policy"&&h.severity==="Critical"&&!O.includes(h)&&!r.has(h.id)&&O.push(h);let I=[],j=[...v].map(h=>i.get(h)).filter(h=>!!h&&h.authority!=="background"&&!r.has(h.id)&&!b(h.id));for(let h of v)b(h)&&!r.has(h)&&r.add(h);if(j.length){I.push(`Fetched once at the start of mode ${e.mode} (\`pnpm clay get ${j.map(h=>h.id).join(" ")}\`), not repeated here: ${j.map(h=>`\`${h.id}\` \u2014 ${h.summary}`).join(" \xB7 ")}`);for(let h of j)r.add(h.id),a.push({id:h.id,tier:"decides",inlined:"summary"})}for(let h of O){if(v.has(h.id))continue;if(b(h.id)){k.push(h.id),r.add(h.id);continue}let w=y(h);X([...l,...I,w].join(`
54
+ `))<=s*.7&&(I.push(w),r.add(h.id),a.push({id:h.id,tier:"decides",inlined:"body"}))}if(I.length&&l.push(`## Decides collisions
55
+ ${I.join(c?`
56
+ `:`
57
+
58
+ `)}`),k.length&&l.push(`Served earlier in this session, not repeated (\`clay get <id> --full\` to re-read): ${k.map(h=>`\`${h}\``).join(" \xB7 ")}`),R.length&&l.push(`Brief format not printed (you have the brief): ${R.map(h=>`\`${h}\``).join(" \xB7 ")}`),e.layouts?.length&&Ni.has(e.stage)){let h=e.layouts.map(w=>i.get(`layout.${w}`)).filter(w=>!!w).map(w=>`- ${le(w)}`);h.length&&c?l.push(`Layouts you looked at (facts printed earlier; \`clay section <S> --layout <l>\` re-prints): ${e.layouts.join(" \xB7 ")}`):h.length&&l.push(`## Your layouts (from \`clay section\` in this session)
59
+ ${h.join(`
60
+ `)}`)}if(c&&!m&&e.stage==="page-file"){let h=ds.map(w=>i.get(w)).filter(w=>!!w&&!b(w.id)&&!r.has(w.id));if(h.length){l.push(`## Chrome (Hard Rule C4: use as is; another brand swaps only the logo key, \`procedure.logo.decision-tree\`)
61
+ ${h.map(w=>sn(w.body)).join(`
62
+ `)}`);for(let w of h)r.add(w.id),a.push({id:w.id,tier:"do",inlined:"body"})}}let M=[],B=new Set;if(E&&e.brief&&(e.stage==="mapping"||e.stage==="structure")){let h=nn(e.brief).map((L,N)=>{let Ee=Vt(t,n,L.title,L.text);for(let de of Ee)a.push({id:de,tier:"brief",inlined:"id"});return`| ${N+1} | ${L.title.slice(0,48)} | ${Ee.map(de=>`\`${de.replace(/^(?:section|component)\.email\./,"")}\``).join(" \xB7 ")||"\u2014 (no match: a [GAP]?)"} |`}),w=`## Brief \u2192 email section candidates (search; alias map first; an explicit brief structure wins \u2014 \`clay get section.email.<id>\`)
63
+ | # | brief block | candidates |
64
+ |---|---|---|
65
+ ${h.join(`
66
+ `)}`;h.length&&f(w)&&l.push(w)}if(!E&&g.length&&(e.stage==="mapping"||e.stage==="structure")){let h=g.map((_,T)=>Xi(g,T)),w=h.reduce((_,T,q)=>T?_:q,g.length-1);g.forEach((_,T)=>{let q=h[T]?[]:dn(t,n,_,i,{first:T===0,last:T===w});M.push({section:_,candidates:q});for(let V of q){let P=i.get(V.id);for(let U of P.entities)(U.startsWith("section:")||U.startsWith("layout:")||U.startsWith("item:"))&&B.add(U)}});let L=_=>_===0||!!h[_],N=Wi(M,i,L),Ee=Hi(M,i,_=>L(_)||N.has(_)),de=Gi(M,i,_=>_!==w&&(()=>{let T=D(M[_].section);return T.statement&&T.hasMedia})(),L),je=null,tt=M.map(_=>{let T=_.candidates[0];if(!T)return null;let q=je&&je.id===T.id?je.n:null;return je={id:T.id,n:_.section.n},q}),It=`## Brief \u2192 layout candidates (search + item-count fit; you decide)
67
+ | \xA7 | brief section | items | candidates (range; notes) |
68
+ |---|---|---|---|
69
+ ${M.map((_,T)=>{let q=os(_.section,{first:T===0,last:T===w},h[T],_.candidates,{carousel:N.get(T),statement:de.get(T)}),V=tt[T]!=null?`\u26A0 same first pick as \xA7${tt[T]}: keep \xA7${tt[T]}, take this section's next closest layout (\`policy.layout.no-repeat-fallback\`)`:"",P=Ee.get(T),U=Y=>`\`${Y.replace(/^layout\.FeaturesSection\./,"")}\``,Le=P?P.to?`\xA7${P.prev} has ${U(P.from)} \u2192 ${U(P.to)} (same accordion + media family; \`policy.features.layout-diversity\`)`:`\u26A0 \xA7${P.prev} has ${U(P.from)}, no other family layout fits: keep, log \`[GAP: layout-diversity]\` (\`policy.features.layout-diversity\`)`:"",Te=[q,Le,V].filter(Boolean).join(" \xB7 ");return`| ${_.section.n} | ${_.section.title.slice(0,38)} | ${_.section.items??"\u2014"} | ${[..._.candidates.map(Y=>`${Y.part?`\xA7${_.section.n}${Y.part} `:""}\`${Y.id.replace(/^layout\./,"")}\` ${Y.line.replace(/^\S+ \S+ ?/,"")}${Y.fit==="over"?" \u26A0 over":Y.fit==="under"?" \u26A0 under":""}`),...Te?[Te]:[]].join(" \xB7 ")} |`}).join(`
70
+ `)}`;if(f(It)){l.push(It);for(let V of M)for(let P of V.candidates)a.push({id:P.id,tier:"brief",inlined:"summary"});let _=new Set,T=[];for(let V of M)for(let P of c?V.candidates:V.candidates.slice(0,1))if(!(!P||_.has(P.id))){_.add(P.id);for(let U of as(i.get(P.id),i)){let Le=U.replace(/^- `[^`]*` · /,"");!/·.*·/.test(Le)||T.some(Te=>Te.endsWith(Le))||T.push(U)}}let q=`### Item shapes of the ${c?"":"first "}candidates (\u25CF required; c chars \xB7 w words \xB7 s sentences)
71
+ ${[...new Set(T)].join(`
72
+ `)}`;T.length&&f(q)&&l.push(q)}}let Ce=new Map;if(e.brief){let h=new Set(o.map(L=>L.id)),w=g.length?g.map(L=>`${L.title} ${L.text.replace(/https?:\/\/\S+|`[^`]*`/g," ").slice(0,400)}`):[e.brief.slice(0,2e3)];for(let L of w)for(let N of W(t,n,L,{stage:[e.stage],mode:e.mode,k:25,scope:E?["email","shared"]:void 0}))h.has(N.id)&&Ce.set(N.id,Math.max(Ce.get(N.id)??0,N.score))}let Qn=Math.max(1,...Ce.values()),Tt=new Set(e.sections??[]),ei=h=>{if(!Tt.size)return!1;let w=h.entities.filter(L=>L.startsWith("section:")||L.startsWith("layout:")).map(L=>L.split(":")[1]);return w.length>0&&!w.some(L=>Tt.has(L))},_t=o.filter(h=>!r.has(h.id)&&!ei(h)&&(!ts.has(h.kind)||h.authority!=="derived"||E&&h.kind==="limit")).map(h=>{let w=(es[h.kind]??.5)+(Qi[h.severity??""]??0)*.6;h.severity==="Critical"&&(w+=Oi),h.entities.includes(en(e.skill))&&(w+=1),ns(h,e.skill)&&(w-=2.5),e.mode&&h.modes?.includes(e.mode)&&(w+=1.5),w+=3*((Ce.get(h.id)??0)/Qn);let L=h.entities.filter(N=>B.has(N));return L.some(N=>N.startsWith("layout:"))?w+=2.5:L.length&&(w+=1.2),{u:h,s:w}}).sort((h,w)=>w.s-h.s||(h.u.id<w.u.id?-1:1)),Re=[],ce=[],ti=140;if(E){let h=[];for(let{u:w}of _t.slice(0,6)){if(h.length>=3||w.kind==="limit")continue;let L=`### ${w.id}
73
+ ${w.body}`;X([...l,"## Key units",...h,L].join(`
74
+ `))>s*.65||(h.push(L),r.add(w.id),a.push({id:w.id,tier:"watch",inlined:"body"}))}h.length&&l.push(`## Key units (top-ranked for this stage, inlined)
75
+ ${h.join(`
76
+
77
+ `)}`)}let Qe=c?Pi:_i,Ae=0,et=0,ni=us(_t.filter(({u:h})=>!r.has(h.id)),Qe,({u:h})=>C(h.id));for(let{u:h}of ni){if(r.has(h.id))continue;if(C(h.id)){Ae<Qe&&(Ae++,et++),r.add(h.id);continue}let w=`- \`${h.id}\`${h.severity?` (${h.severity})`:""} \u2014 ${h.summary}`;Ae<Qe&&X([...l,"## Watch",...Re,w].join(`
78
+ `))<=s-ti?(Ae++,Re.push(w),r.add(h.id),a.push({id:h.id,tier:"watch",inlined:"summary"})):ce.push(h.id)}if(Re.length&&l.push(`## Watch (this stage; ranked by severity, brief and candidates)${et?` \u2014 ${et} more listed earlier this session`:""}
79
+ ${Re.join(`
80
+ `)}`),ce.length){let h=[];for(let w of ce){if(h.length>=(c?8:Mi))break;let L=`## More (\`pnpm clay get <id>\`; ${ce.length} more units tagged ${e.stage})
81
+ ${[...h,w].join(" \xB7 ")}`;if(!f(L))break;h.push(w)}if(h.length){l.push(`## More (\`pnpm clay get <id>\`; ${ce.length} more units tagged ${e.stage})
82
+ ${h.join(" \xB7 ")}`);for(let w of h)a.push({id:w,tier:"more",inlined:"id"})}}let Ot=u(l);return{text:Ot,tokens:X(Ot),budget:s,units:a,brief:M}}function us(t,n,e=()=>!1,s=Ii){let i=[...t];if(n<=0||i.length<=n)return i;let o=n,r=n-1;for(;;){for(;o<i.length&&(i[o].u.severity!=="Critical"||e(i[o]));)o++;for(;r>=0&&(i[r].u.severity!=="Minor"||e(i[r]));)r--;if(o>=i.length||r<0||i[r].s-i[o].s>s)return i;let a=i[o],l=i[r];i.splice(o,1),i.splice(r,1),i.splice(n-1,0,a,l),o++,r--}}function gt(t){let n=t.trim(),e=/^var\(\s*(--[A-Za-z0-9_-]+)\s*(?:,[^)]*)?\)$/.exec(n);return e?`token:${e[1]}`:/^--[A-Za-z0-9_-]+$/.test(n)?`token:${n}`:n}var Ue=t=>t.replace(/\n[ \t]*\n+/g,`
83
+ `).trim();function mn(t,n,e={}){let s=[],i=[],o=[],r={},a=e.resolve??t.resolve;for(let u of n){if(u.endsWith("*")){let m=u.slice(0,-1),$=t.kb.units.filter(S=>S.id.startsWith(m)).slice(0,25);$.length||i.push(u),s.push(...$);continue}let p=t.byId.get(u);if(p){s.push(p);continue}let f=a?.(gt(u)),g=f?t.byId.get(f):void 0;g?(r[u]=g.id,s.includes(g)||s.push(g)):i.push(u)}let l=s.filter(u=>!e.full&&ue(e.session,u.id)?(o.push(u.id),!1):!0);for(let u of l)J(e.session,u.id,"get");return{text:`${[...Object.keys(r).length?[Object.entries(r).map(([u,p])=>`${u} \u2192 ${p}`).join(" \xB7 ")]:[],...o.length?[`Served earlier in this session (\`--full\` to re-print): ${o.map(u=>`\`${u}\` (${e.session.served[u]})`).join(" \xB7 ")}`]:[],...l.map(u=>{let p=[u.kind,u.authority,u.severity,u.modes?.length?`mode ${u.modes.join("/")}`:"",`stages ${u.stages.join(", ")||"\u2014"}`].filter(Boolean).join(" \xB7 "),f=Object.entries(u.relations??{}).filter(([,g])=>g?.length).map(([g,m])=>`${g}: ${m.join(", ")}`).join(" \xB7 ");return`## ${u.id} \xB7 _${p}${f?` \xB7 ${f}`:""}_${e.full?` \xB7 source \`${u.source.path}${u.source.anchor?`#${u.source.anchor}`:""}\``:""}
84
+ ${e.full?Ue(u.body):ps(t,Ue(u.body))}`}),...i.length?[`Not found: ${i.join(", ")} (try \`clay search\`).`]:[]].join(`
85
+ `)}
86
+ `,data:{units:s,missing:i,repeated:o,...Object.keys(r).length?{resolved:r}:{}}}}var un=8;function ps(t,n){let e=new Set,s=n.replace(/`('[^'`]*'(?:\s*\\?\|\s*'[^'`]*')+)`/g,(i,o)=>{let r=[...o.matchAll(/'([^']*)'/g)].map(l=>l[1]);if(r.length<=un*2)return i;let a=o.includes("\\|")?" \\| ":" | ";return r.slice(0,3).every(l=>t.byId.has(`asset.icon.${l}`))&&e.add('Icon names: `clay search "<what it shows> icon" --kind asset` (or `clay get asset.icon.<name>`).'),`\`${r.slice(0,un).map(l=>`'${l}'`).join(a)}${a}\u2026\` (${r.length} values; \`--full\` prints all)`});return e.size?`${s}
87
+ ${[...e].join(`
88
+ `)}`:s}function ut(t){let n=t.aliases??[],e=n.length?` (also \`${n.slice(0,2).join("`, `")}\`${n.length>2?` +${n.length-2} more`:""})`:"";return`\`${t.id}\` (${t.kind}, ${t.authority}, ${t.score.toFixed(1)}) \u2014 ${t.summary}${e}`}function fn(t,n,e={}){let s=n.map(o=>({term:o,hits:W(t.kb,t.index,o,{...e,k:e.k??1})}));return{text:`${s.map(({term:o,hits:r})=>r.length===1?`- ${o} \u2192 ${ut(r[0])}`:r.length?[`- ${o}:`,...r.map((a,l)=>` ${l+1}. ${ut(a)}`)].join(`
89
+ `):`- ${o} \u2192 no match`).join(`
90
+ `)}
91
+ `,data:{results:s}}}function hn(t,n,e={}){let s=W(t.kb,t.index,n,e),i=!e.scope?.length&&/\b(?:e-?mails?|mjml|braze|preheader|subject lines?|newsletter|mj-[a-z]+)\b/i.test(n);return{text:`${(s.length?s.map((r,a)=>`${a+1}. ${ut(r)}`).join(`
92
+ `):"No units match.")+(i?"\n(Email knowledge is a separate scope: add `--scope email`, or `--scope all`.)":"")}
93
+ `,data:{hits:s}}}function yn(t,n){let e=n,s=n.resolve??t.resolve,i=t.byId.has(`skill.${n.skill}`)||n.skill in at||n.skill in pe;if(s&&!i){let c=s(n.skill);c?.startsWith("skill.")&&t.byId.has(c)&&(e={...n,skill:c.slice(6)})}let o=e.brief;if(!te.includes(e.stage))throw new Error(`route: unknown stage "${e.stage}" (one of ${te.join(", ")})`);let r=e.session,a={bodies:new Set(Object.keys(r?.served??{})),lines:new Set(Object.keys(r?.lines??{}))};if(e.since){if(!te.includes(e.since))throw new Error(`route: unknown --since stage "${e.since}"`);for(let c of te.slice(te.indexOf(e.since),te.indexOf(e.stage))){let u=dt(t.kb,t.index,{skill:e.skill,mode:e.mode,stage:c,brief:c==="mapping"||c==="structure"?o:void 0});for(let p of u.units)(p.inlined==="body"?a.bodies:a.lines).add(p.id)}}let l=dt(t.kb,t.index,{...e,brief:o,briefLabel:e.briefLabel??e.briefPath,seen:r||e.since?a:void 0,sections:r?.sections,layouts:r?.layouts});if(r){let c=`route ${e.stage}`;for(let u of l.units)(u.inlined==="body"?J:Ie)(r,u.id,c);r.stages.includes(e.stage)||r.stages.push(e.stage)}return{text:l.text,data:l}}function pn(t,n){if(!n)return"";let e=t.byId.get(n);return e?e.summary.replace(/^[^:]+:\s*/,"").replace(/\s*·\s*soft \(copy guidance\)\.?$/,""):""}var gs=/^(?:source|source reference|re-file to|qa history|related)$/i,ms=[["Structure",/^structure$/i],["Tokens",/^tokens$/i],["Mobile",/^mobile behaviou?r$/i],["Dark mode",/^dark mode$/i]];function pt(t,n=0,e=[]){for(let s of t){let i=Object.entries(s.attrs).map(([o,r])=>`${o}="${r}"`).join(" ");s.el==="repeat"?e.push(`${" ".repeat(n)}- \xD7${s.count} (these ${s.children.length} elements repeat as a group; copy differs per repeat)`):e.push(`${" ".repeat(n)}- ${s.count>1?`\xD7${s.count} `:""}\`${s.el}\`${i?` ${i}`:""}${s.text?` \u2014 "${s.text}"`:""}`),pt(s.children,n+1,e)}return e}function fs(t,n,e){let s=e.facts,i=[e.id],o=s.emailId,r=[`# ${n} \xB7 ${s.title}`,e.summary.replace(/^Email (?:section|component) `[^`]+` \([^)]*\): /,""),"",`Flags: ${s.flags.join(" \xB7 ")}.`,`Include: \`${s.include}\` (paste the fragment inline to change copy).`],a=s.notes.find(f=>f.label==="Note"||f.label==="Intro");if(a&&r.splice(2,0,"",a.text.replace(/\s*\n\s*/g," ")),s.fields.length){r.push("","## Brief fields \u2192 slots (limits: `clay get limit.email.<key>`)");let f=[...new Set(s.fields.map(g=>g.block))];for(let g of f){let m=s.fields.filter($=>$.block===g);r.push(`- ${m[0].repeat?"repeating block":"block"}: ${m.map($=>{let S=$.limitId?t.byId.get($.limitId):void 0;return S&&i.push(S.id),`${$.label} (${$.kind}${S?` \u2014 ${/\*\*Email [^:]+: ([^*]+?)\.?\*\*/.exec(S.body)?.[1]??S.summary}`:""})`}).join(" \xB7 ")}`)}}else r.push("","## Brief fields: none (structural \u2014 keep the fragment as is)");let l=s.notes.filter(f=>!gs.test(f.label)),c=new Set;for(let[f,g]of ms){let m=l.find($=>g.test($.label));if(m&&(c.add(m.label),r.push("",`## ${f}`,m.text),f==="Structure"&&s.slots.length)){let $=pt(s.slots);r.push("",`## Slots (\`${s.mjmlPath}\` \u2014 keep each element's attributes; copy and asset placeholders are replaced)`,...$.slice(0,40),...$.length>40?[`- \u2026 ${$.length-40} more lines (\`${s.mjmlPath}\`)`]:[])}}if(!c.has("Structure")&&s.slots.length){let f=pt(s.slots);r.push("",`## Slots (\`${s.mjmlPath}\` \u2014 keep each element's attributes; copy and asset placeholders are replaced)`,...f.slice(0,40),...f.length>40?[`- \u2026 ${f.length-40} more lines`]:[])}let u=l.filter(f=>!c.has(f.label)&&f.label!=="Intro"&&f.label!=="Note"),p=t.kb.units.filter(f=>f.scope==="email"&&f.authority!=="derived"&&f.authority!=="background"&&f.entities.includes(`section:email.${o}`)&&f.entities.filter(g=>g.startsWith("section:email.")).length<=3).sort((f,g)=>(f.kind==="gotcha"?0:1)-(g.kind==="gotcha"?0:1)||(f.id<g.id?-1:1));if(u.length||p.length){r.push("","## Gotchas and usage (`clay get <id>`)");for(let f of u){let g=f.text.split(`
94
+ `).reduce((m,$)=>/^\s*-\s/.test($)||!m.length?[...m,$.trim()]:[...m.slice(0,-1),`${m[m.length-1]} ${$.trim()}`],[]).filter(Boolean);g.length>1&&g.every(m=>m.startsWith("- "))?r.push(`- **${f.label}:**`,...g.map(m=>` ${m}`)):r.push(`- **${f.label}:** ${g.join(" ")}`)}for(let f of p)r.push(`- \`${f.id}\`${f.severity?` (${f.severity})`:""} \u2014 ${f.summary}`),i.push(f.id)}return{text:`${r.join(`
95
+ `)}
96
+ `,data:{section:n,units:i}}}function bn(t,n,e=[],s={}){if(!n.length)throw new Error("section: pass at least one section name");let i=n.map((o,r)=>He(t,o,e.length===n.length?e[r]||void 0:r===0&&e.join(",")||void 0,s));return{text:i.map(o=>o.text).join(""),data:i.map(o=>o.data)}}function $n(t,n={}){let e=n.scope==="email",s=t.kb.units.filter(o=>o.kind==="section"&&o.authority==="derived"&&(e?o.scope==="email":o.scope!=="email")),i=[`# ${e?"Email":"Web"} sections (${s.length}) \u2014 \`clay section <name> [--layout <l>]\``];for(let o of s){let r=o.id.replace(/^section\./,""),a=t.kb.units.filter(c=>c.kind==="layout"&&c.authority==="derived"&&c.id.startsWith(`layout.${r}.`)).map(c=>c.id.split(".").pop()),l=/ — ([^—]+)$/.exec(o.summary)?.[1]?.replace(/\.$/,"")??"";i.push(e?`- \`${r}\` \u2014 ${o.summary.replace(/^Email section `[^`]+` /,"").slice(0,90)}`:`- \`${r}\`${l?` (${l})`:""}${a.length?`: ${a.join(" \xB7 ")}`:""}`)}if(!e){let o=t.kb.units.filter(r=>r.kind==="component"&&r.authority==="derived"&&r.scope!=="email"&&!r.id.includes(".",10)).map(r=>r.id.slice(10));i.push("",`Atoms (\`clay section <Atom>\` for props): ${o.join(", ")}.`,"Email sections: `clay section --scope email`.")}return{text:`${i.join(`
97
+ `)}
98
+ `,data:{sections:s.map(o=>o.id)}}}function hs(t){let n=t.trim();return n==="string"?"":/^\(.*\)\s*=>/.test(n)||/^\(\(.*\)\)$/.test(n)?"()":/^\{/.test(n)?`{${[...n.matchAll(/(\w+)\??:/g)].map(e=>e[1]).filter(e=>e!=="onClick").join(",")}}`:/^'[^']*'(\s*\|\s*'[^']*')+$/.test(n)?n.replace(/\s*\|\s*/g,"|"):n==="ReactNode"||n==="React.ReactNode"?"node":n.length>40?`${n.slice(0,37)}\u2026`:n}function qe(t,n){let e=hs(n.type),s=n.limitId?ct(t.byId.get(n.limitId)):"",i=n.defaultValue&&n.defaultValue!=="[]"?`=${n.defaultValue.length>28?`${n.defaultValue.slice(0,26)}\u2026`:n.defaultValue}`:"";return[`${n.required?"\u25CF":""}${n.name}`,e,i,s].filter(Boolean).join(" ")}var ys=/^(?:Use for:|Tab label:|Section CTA:|Item CTAs|Media slots|Always rendered|Item count|Grid|Columns|Note)/;function bs(t,n,e,s,i){let o=e.facts??{},r=[e.id],a=[],l=/ — ([^—]+)$/.exec(e.summary)?.[1]?.replace(/\.$/,"")??"",c=y=>y.entities.includes(`section:${n}`)||y.entities.includes(`component:${n}`);if(!s.length){let y=t.kb.units.filter(b=>b.kind==="layout"&&b.authority==="derived"&&b.id.startsWith(`layout.${n}.`)),v=be(y[0]);a.push(`# ${n}${l?` \u2014 ${l}`:""}${y.length?` (${y.length} ${v==="layout"?"layouts":`\`${v}\` values, passed as \`${v}="\u2026"\``}; \`clay section ${n} --layout a,b\` for what they render)`:""}`);for(let b of y){let C=/Use for: ([^\n]*)/.exec(b.body)?.[1]?.replace(/\.$/,"");a.push([`- \`${b.id.split(".").pop()}\``,le(b).replace(/^\S+ \S+ ?/,""),C?`\u2014 ${C}`:""].filter(Boolean).join(" ")),r.push(b.id)}let A=(o.props??[]).filter(b=>b.name!=="layout");A.length&&a.push(`Props (\u25CF required; c chars \xB7 w words): ${A.map(b=>qe(t,b)).join(" \xB7 ")}`);for(let b of[...new Set(A.map(C=>/^([A-Z][A-Za-z0-9]*)\[\]$/.exec(C.type)?.[1]).filter(Boolean))]){let C=t.byId.get(`item.${b}`);C&&(r.push(C.id),a.push(`${b}: ${((C.facts??{}).fields??[]).map(k=>qe(t,k)).join(" \xB7 ")}`))}}for(let y of s){let v=t.byId.get(`layout.${n}.${y}`);if(!v){let R=t.kb.units.filter(E=>E.kind==="layout"&&E.id.startsWith(`layout.${n}.`)&&E.authority==="derived").map(E=>E.id.split(".").pop());throw new Error(`section: ${n} has no layout "${y}". Layouts: ${R.join(", ")}`)}r.push(v.id);let A=v.facts??{},b=le(v).replace(/^\S+ \S+ ?/,"").replace(/^\(|\)$/g,"");a.push(`# ${n} \xB7 ${be(v)}="${y}"${A.headingTier?` \xB7 heading tier ${A.headingTier}`:""}${b?` \xB7 ${b}`:" \xB7 items: no documented range"}`);let C=new Set(A.propsRendered??[]),k=(o.props??[]).filter(R=>C.has(R.name));k.length&&a.push(`Props: ${k.map(R=>qe(t,R)).join(" \xB7 ")}`),A.propsIgnored?.length&&a.push(`Ignored here: ${A.propsIgnored.join(" \xB7 ")}`);for(let[R,{rendered:E}]of Object.entries(A.itemFields??{})){let O=t.byId.get(`item.${R}`),I=(O?.facts??{}).fields??[];O&&r.push(O.id);let j=I.filter(B=>E.includes(B.name)),M=I.filter(B=>!E.includes(B.name)).map(B=>B.name);j.length&&a.push(`${R}: ${j.map(B=>qe(t,B)).join(" \xB7 ")}${M.length?` (not rendered by this ${be(v)}: ${M.join(", ")})`:""}`)}for(let R of Ue(v.body).split(`
99
+ `))ys.test(R)&&a.push(R)}let u=y=>y.kind!=="policy"||y.id.split(".").includes(n)||y.entities.some(v=>v.startsWith(`layout:${n}:`)),p=t.kb.units.filter(y=>y.authority!=="background"&&y.authority!=="derived"&&c(y)&&["gotcha","section","policy","component","layout"].includes(y.kind)&&u(y)).filter(y=>!y.id.startsWith("gotcha.page.")&&!y.id.startsWith("gotcha.ai-page.")&&!y.id.includes(".example.")).filter(y=>!s.length||!y.entities.some(v=>v.startsWith(`layout:${n}:`))||s.some(v=>y.entities.includes(`layout:${n}:${v}`))).sort((y,v)=>(gn[v.severity??""]??0)-(gn[y.severity??""]??0)||(y.kind==="gotcha"?0:1)-(v.kind==="gotcha"?0:1)||(y.id<v.id?-1:1)),f=p.filter(y=>!Me(i,y.id)),g=f.slice(0,4);for(let y of g)a.push(`- \`${y.id}\`${y.severity?` (${y.severity})`:""} \u2014 ${y.summary}`),r.push(y.id);let m=f.slice(4).map(y=>`\`${y.id}\``),$=p.length-f.length;(m.length||$)&&a.push(`${m.length?`More about ${n}: ${m.join(" \xB7 ")}`:""}${m.length&&$?" \xB7 ":""}${$?`${$} listed earlier this session`:""}`);let S=t.kb.units.filter(y=>y.id.startsWith(`section.${n}.example.`)&&(!s.length||s.some(v=>y.id.endsWith(`.example.${v}`))));if(S.length&&a.push(`Example${S.length>1?"s":""}: ${S.map(y=>`\`clay get ${y.id}\``).join(" \xB7 ")}`),i){for(let v of s.length?s:[void 0])Pe(i,n,v);let y=`section ${n}${s.length?` --layout ${s.join(",")}`:""}`;s.length||J(i,`${e.id}#overview`,y);for(let v of r)(v===e.id||v.startsWith("layout.")||v.startsWith("item.")?J:Ie)(i,v,y)}return{text:`${a.join(`
100
+ `)}
101
+ `,data:{section:n,layout:s.join(",")||void 0,units:r}}}var gn={Critical:3,Major:2,Minor:1};function be(t){return(t?.facts??{}).variantProp??"layout"}function He(t,n,e,s={}){let i=(e??"").split(",").map(b=>b.trim()).filter(Boolean);if(s.compact||i.length>1){let b=t.byId.get(`section.${n}`)??t.byId.get(`component.${n}`);if(b&&!(b.scope==="email"&&b.facts?.emailId)){if(s.compact)return bs(t,n,b,i,s.session);let C=i.map(k=>He(t,n,k,{session:s.session}));return{text:C.map(k=>k.text).join(""),data:{section:n,layout:i.join(","),units:C.flatMap(k=>k.data.units)}}}}let o=s.session,r=t.byId.get(`section.${n}`)??t.byId.get(`component.${n}`);if(r&&r.scope==="email"&&r.facts?.emailId)return fs(t,n,r);if(!r){let b=t.kb.units.filter(C=>C.kind==="section"&&C.authority==="derived"&&C.scope!=="email").map(C=>C.id.slice(8));throw new Error(`section: no section or component "${n}". Sections: ${b.join(", ")} (web; atoms: \`clay section\`; several: \`clay section A,B --layout x,y\`)`)}let a=r.facts??{},l=[r.id],c=[`# ${n}${e?` \xB7 ${be(t.byId.get(`layout.${n}.${e}`))}="${e}"`:""}`,r.summary],u=`${r.id}#props`,p=ue(o,u);if(!e&&ue(o,`${r.id}#overview`))return Pe(o,n),{text:`# ${n}
102
+ Served earlier in this session (\`clay section ${n}\`); \`clay section ${n} --layout <l>\` for one layout.
103
+ `,data:{section:n,units:[]}};let f=b=>b.entities.includes(`section:${n}`)||b.entities.includes(`component:${n}`);if(e){let b=t.byId.get(`layout.${n}.${e}`);if(!b){let C=t.kb.units.filter(k=>k.kind==="layout"&&k.id.startsWith(`layout.${n}.`)&&k.authority==="derived").map(k=>k.id.split(".").pop());throw new Error(`section: ${n} has no layout "${e}". Layouts: ${C.join(", ")}`)}l.push(b.id),c.push("",`## ${b.id}`,Ue(b.body))}else{let b=t.kb.units.filter(C=>C.kind==="layout"&&C.authority==="derived"&&C.id.startsWith(`layout.${n}.`));if(b.length){let C=be(b[0]);c.push("",`## Layouts${C==="layout"?"":` \u2014 values of the \`${C}\` prop`} (\`clay section ${n} --layout <l>\` for what one renders)`);for(let k of b)c.push(`- \`${k.id.split(".").pop()}\` ${le(k).replace(/^\S+ \S+ ?/,"")}`),l.push(k.id)}}let g=e?new Set((t.byId.get(`layout.${n}.${e}`)?.facts??{}).propsRendered??[]):void 0,m=(a.props??[]).filter(b=>!g||g.has(b.name));if(m.length&&p)c.push("",`Props${g?" this layout renders":""}: ${m.map(b=>`${b.required?"\u25CF":""}\`${b.name}\``).join(" \xB7 ")} (types and limits: printed earlier by \`clay section ${n}\`).`);else if(m.length){c.push("",`## Props${g?" this layout renders":""} (\u25CF required)`);for(let b of m){let C=pn(t,b.limitId);c.push(`- ${b.required?"\u25CF":"\u25CB"} \`${b.name}\`: \`${b.type.length>70?`${b.type.slice(0,67)}\u2026`:b.type}\`${b.defaultValue?` = ${b.defaultValue.length>40?`${b.defaultValue.slice(0,37)}\u2026`:b.defaultValue}`:""}${C?` \xB7 ${C}`:""}`)}}let $=[...new Set(m.map(b=>/^([A-Z][A-Za-z0-9]*)\[\]$/.exec(b.type)?.[1]).filter(Boolean))];for(let b of $){let C=t.byId.get(`item.${b}`);if(!C)continue;if(ue(o,C.id)){c.push("",`${b}: fields printed earlier in this session (\`clay get ${C.id} --full\`).`);continue}l.push(C.id);let k=(C.facts??{}).fields??[];c.push("",`## ${b}`,...k.map(R=>`- ${R.required?"\u25CF":"\u25CB"} \`${R.name}\`: \`${R.type.length>60?`${R.type.slice(0,57)}\u2026`:R.type}\`${R.limitId?` \xB7 ${pn(t,R.limitId)}`:""}`))}let S=b=>b.kind!=="policy"||b.id.split(".").includes(n)||b.entities.some(C=>C.startsWith(`layout:${n}:`)),y=t.kb.units.filter(b=>b.authority!=="background"&&b.authority!=="derived"&&f(b)&&["gotcha","section","policy","component","layout"].includes(b.kind)&&S(b)).filter(b=>!b.id.startsWith("gotcha.page.")&&!b.id.startsWith("gotcha.ai-page.")).filter(b=>!e||!b.entities.some(C=>C.startsWith(`layout:${n}:`))||b.entities.includes(`layout:${n}:${e}`)).sort((b,C)=>(b.kind==="gotcha"?0:1)-(C.kind==="gotcha"?0:1)||(b.id<C.id?-1:1)),v=y.filter(b=>!Me(o,b.id)),A=y.filter(b=>Me(o,b.id));if(v.length){c.push("","## Gotchas and usage (`clay get <id>`)");for(let b of v)c.push(`- \`${b.id}\`${b.severity?` (${b.severity})`:""} \u2014 ${b.summary}`),l.push(b.id)}if(A.length&&c.push("",`Also about ${n} (listed earlier this session): ${A.map(b=>`\`${b.id}\``).join(", ")}`),o){Pe(o,n,e);let b=`section ${n}${e?` --layout ${e}`:""}`;m.length&&!p&&!e&&J(o,u,b),e||J(o,`${r.id}#overview`,b);for(let C of l)(C===r.id||C.startsWith("layout.")||C.startsWith("item.")?J:Ie)(o,C,b)}return{text:`${c.join(`
104
+ `)}
105
+ `,data:{section:n,layout:e,units:l}}}function Sn(t,n={}){let e=n.scope==="email",s=l=>(!n.stage||l.stages.includes(n.stage))&&(!n.mode||!l.modes||l.modes.includes(n.mode))&&(e?l.scope==="email":l.scope!=="email"),i=t.kb.units.filter(l=>l.kind==="rule"&&s(l)),o=t.kb.units.filter(l=>l.kind==="policy"&&l.authority==="canonical"&&(l.severity==="Critical"||l.severity==="Major")&&l.enforcement?.length&&s(l)).sort((l,c)=>l.severity===c.severity?l.id<c.id?-1:1:l.severity==="Critical"?-1:1),r=l=>`- \`${l.id}\`${l.severity?` ${l.severity}`:""}${l.enforcement?.length?` \xB7 ${l.enforcement.join("/")}`:""} \u2014 ${l.summary}`;return{text:`${[`# Rules${n.stage?` \xB7 stage ${n.stage}`:""}${n.mode?` \xB7 mode ${n.mode}`:""}`,`## ${e?"Email rules":"Hard Rules"} (${i.length})`,...i.map(r),`## Policies with enforcement (${o.length}; Critical first)`,...o.map(r)].join(`
106
+ `)}
107
+ `,data:{units:[...i,...o].map(l=>l.id)}}}var kn=["structure","mapping","design","assets","copy","page-file","ux","qa","static","fidelity"],wn=["A","B"],xn=["web","ds","shared","email","all"],vn=["web","email"];function ie(t,n,e){if(e==null||e==="")throw new Error(`${t}: missing required argument "${n}"`)}function Cn(t,n){if(!Array.isArray(t.units)||t.index==null||typeof t.fingerprint!="string")throw new Error("createClayKbFromSource: source needs units, index, and fingerprint");let e=t.units;return $s({kb:{fingerprint:t.fingerprint,units:e},index:t.index,byId:new Map(e.map(s=>[s.id,s])),resolve:t.resolve},n)}function $s(t,n){let e=n?.session;return{search(i){return ie("clay_search","query",i.query),hn(t,i.query,{k:i.k,kind:i.kind,entity:i.entity,stage:i.stage,mode:i.mode,scope:i.scope,includeBackground:i.includeBackground})},searchEach(i){(!Array.isArray(i.each)||i.each.length===0)&&ie("clay_search","each",void 0);let o=i.query?i.each.map(r=>`${r} ${i.query}`):i.each;return fn(t,o,{k:i.k,kind:i.kind,entity:i.entity,stage:i.stage,mode:i.mode,scope:i.scope,includeBackground:i.includeBackground})},get(i){(!Array.isArray(i.ids)||i.ids.length===0)&&ie("clay_get","ids",void 0);let o=mn(t,i.ids,{session:e});return{text:o.text,data:{...o.data,resolved:o.data.resolved??{}}}},section(i){return ie("clay_section","name",i.name),He(t,i.name,i.layout,{session:e})},sections(i){(!Array.isArray(i.names)||i.names.length===0)&&ie("clay_section","names",void 0);let o=bn(t,i.names,i.layouts??[],{session:e});return{text:o.text,data:{sections:o.data}}},sectionList(i={}){return $n(t,{scope:i.scope})},rules(i={}){return Sn(t,{stage:i.stage,mode:i.mode,scope:i.scope})},route(i){ie("clay_route","skill",i.skill),ie("clay_route","stage",i.stage);let o=yn(t,{skill:i.skill,stage:i.stage,mode:i.mode,brief:i.brief,budget:i.budget,session:e}),{text:r,...a}=o.data;return{text:o.text,data:a}},resolve:i=>t.byId.has(i)?i:t.resolve?t.resolve(i)??null:null,checkCopy(i){if(i.spec===void 0&&!i.fields)throw new Error('clay_check_copy: pass "spec" (a PageSpec) or "fields"');let o=i.fields?nt(t.kb,i.fields,{file:i.file}):Nt(t.kb,i.spec,{file:i.file});return{text:Oe(o,{all:i.all}),data:o}}}}import{existsSync as An,readFileSync as Ss,realpathSync as mt,statSync as ks}from"node:fs";import{isAbsolute as ft,join as Rn,relative as En,resolve as jn,sep as ws}from"node:path";var xs=1048576,se=class extends Error{};function vs(t,n){let e=mt(t),s=ft(n)?n:jn(t,n);if(!An(s))throw new se(`no such file: ${n}`);let i=mt(s),o=En(e,i);if(o===""||o.startsWith(`..${ws}`)||o===".."||ft(o))throw new se(`${n} is outside the repo root \u2014 only files inside it can be read`);let r=ks(i);if(!r.isFile())throw new se(`${n} is not a file`);if(r.size>xs)throw new se(`${n} is larger than 1 MB`);return i}function ht(t,n){let e=vs(t,n);return{text:Ss(e,"utf8"),label:En(mt(t),e)}}function Ln(t,n){let e=[n,Rn("apps/pages/src/pages",n),Rn("apps/pages/src/pages",`${n}.tsx`)];for(let s of e){if(!s.endsWith(".tsx"))continue;let i;try{i=ft(s)?s:jn(t,s)}catch{continue}if(An(i))return ht(t,s)}throw new se(`no page "${n}" (tried ${e.filter(s=>s.endsWith(".tsx")).join(", ")})`)}function Cs(t,n,e){if(Buffer.byteLength(t)<=n)return t;let s=t.slice(0,n);for(;Buffer.byteLength(s)>n;)s=s.slice(0,Math.floor(s.length*.95));let i=s.lastIndexOf(`
108
+ `);i>n*.5&&(s=s.slice(0,i));let o=Buffer.byteLength(t)-Buffer.byteLength(s);return`${s}
109
+ \u2026 ${o} more bytes not shown: ${e}
110
+ `}var yt=t=>({content:[{type:"text",text:t}]}),bt=t=>({content:[{type:"text",text:t}],isError:!0}),Tn={section:"name",get:"ids",search:"query",route:"skill",rules:"","check-copy":"page"},Rs=/^(?:Units are the source of truth|## More \(|Follow that step and its|# Web sections|.*several: `clay section)/;function As(t){return Rs.test(t)?t.replace(/`pnpm clay get <id>`/g,'`clay_get {"ids":["<id>"]}`').replace(/`pnpm clay section <Section> --layout <l(?:ayout)?>`/g,'`clay_section {"name":"<Section>","layout":"<l>"}`').replace(/`pnpm clay section email\.<id>`/g,'`clay_section {"name":"email.<id>"}`'):t}function $t(t){return t.split(`
111
+ `).map(As).join(`
112
+ `).replace(/(?<!pnpm (?:-s )?)`clay (section|get|search|route|rules|check-copy)((?: [^`]*)?)`/g,(n,e,s)=>{let i={},o=s.trim()?s.trim().split(/\s+/):[],r=[];for(let c=0;c<o.length;c++)o[c].startsWith("--")?i[o[c].slice(2)]=o[c+1]&&!o[c+1].startsWith("--")?o[++c]:"true":r.push(o[c]);let a=r.length&&Tn[e]?{[Tn[e]]:r.join(" "),...i}:i,l=Object.keys(a).length?` ${JSON.stringify(a)}`:"";return`\`clay_${e.replace("-","_")}${l}\``})}function _n(t,n,e,s){if(t.isError)return bt(t.text);if(!n)return yt(Cs($t(t.text),8e4,s));let i=JSON.stringify({registry:e,...t.data});return Buffer.byteLength(i)<=8e4?yt(i):yt(JSON.stringify({registry:e,truncated:!0,bytes:Buffer.byteLength(i),hint:s}))}function z(t){if(!t)return"";let n=[];return t.import&&n.push(`import ${t.import}`),t.story&&n.push(`story ${t.story}`),t.figma&&n.push(`figma ${t.figma}`),t.figmaVariable&&n.push(`figma-variable ${t.figmaVariable}`),t.cdn&&n.push(`cdn ${t.cdn}`),n.join(" \xB7 ")}function Z(t,n=200){if(t==null)return"";if(typeof t=="string")return t.length>n?`${t.slice(0,n-1)}\u2026`:t;if(typeof t=="number"||typeof t=="boolean")return String(t);let e=JSON.stringify(t);return e.length>n?`${e.slice(0,n-1)}\u2026`:e}import{z as d}from"zod";var St={"side-by-side":"cards",grid:"cards","media-top":"cards","horizontal-reveal":"revealCards","value-cards":"valueCards","one-media":"oneMediaCards","icon-with-link":"iconLinkCards"},De={"carousel-with-stat":"cards","centered-single":"cards","carousel-split-media-left":"cards","quote-cards":"cards","quote-cards-with-media":"cards","single-card-stat-quote":"cards","carousel-case-study":"caseStudyCards","mixed-stat-and-quote":"carouselCards"};function ze(t){let n=t.props.layout;if(!n&&t.type==="CardsSection"&&(n="side-by-side"),!n&&t.type==="TestimonialsSection"&&(n="carousel-with-stat"),!n)return!1;if(t.type==="CardsSection"&&n==="one-media"){let o=t.props.oneMediaCards,r=Array.isArray(o)&&o.length>0,a=t.props.oneMedia!=null;return!r&&!a}let e;if(t.type==="CardsSection"?e=St:t.type==="TestimonialsSection"&&(e=De),!e||!(n in e))return!1;let s=e[n],i=t.props[s];return!Array.isArray(i)||i.length===0}var kt=d.object({label:d.string(),href:d.string(),color:d.enum(["black","iris","white","grey"]).optional(),showArrow:d.boolean().optional(),size:d.enum(["large","regular","mini"]).optional()}),G=d.enum(["default","wide","full"]).optional(),On=d.enum(["default","muted"]).optional(),Q=d.object({src:d.string().optional(),placeholder:d.boolean().optional(),placeholderLabel:d.string().optional(),type:d.enum(["image","video"]).optional(),alt:d.string().optional(),fit:d.enum(["contain","cover","fill"]).optional(),aspectRatio:d.string().transform(t=>["1/1","4/5","5/4","3/2","16/9","9/16"].includes(t)?t:{"4/3":"5/4","21/9":"16/9","3/4":"4/5"}[t]??"16/9").optional(),radius:d.enum(["none","x-small","small","medium","large","x-large"]).optional(),poster:d.string().optional(),autoPlay:d.boolean().optional(),loop:d.boolean().optional()}),Es=d.object({layout:d.enum(["centered-image","centered-strips","default","floating-card","floating-left","left-center-image","split","split-full-image","split-mosaic","split-search","split-strip","text-only"]).optional(),heading:d.string(),description:d.string().optional(),actionCaption:d.string().optional(),logoKeys:d.array(d.string()).optional(),ctas:d.array(kt).optional(),media:Q.optional(),containerWidth:G}),js=d.object({heading:d.string().optional(),logoKeys:d.array(d.string()),colorMode:d.enum(["black","colored","random"]).optional(),animate:d.union([d.boolean(),d.literal("auto")]).optional()}),Ls=d.object({layout:d.enum(["side-by-side","side-by-side-lines","tabs-background","tabs-stroke","tab-cards-carousel","stacked-rows","horizontal-media-top","stacked-media-left","horizontal-icons","horizontal-cards","tabs-media-right","list-right-media","content-carousel","stacked-cards-carousel","accordion-media-right","numbered-accordion","split-icon-list","steps-numbered"]).optional(),sectionHeading:d.string().optional(),sectionTopic:d.string().optional(),sectionDescription:d.string().optional(),theme:On,items:d.array(d.object({heading:d.string(),description:d.string(),topic:d.string().optional(),bullets:d.array(d.string()).optional(),cta:d.object({label:d.string(),href:d.string().optional()}).optional(),cta2:d.object({label:d.string(),href:d.string().optional()}).optional(),media:Q.optional(),icon:d.string().optional()})),containerWidth:G}),Ts=d.object({layout:d.enum(["side-by-side","horizontal-reveal","grid","value-cards","one-media","icon-with-link","media-top"]).optional(),tagline:d.string().optional(),sectionHeading:d.string().optional(),sectionDescription:d.string().optional(),cards:d.array(d.object({miniTitle:d.string().optional(),heading:d.string(),description:d.string().optional(),media:Q.optional()})).optional(),revealCards:d.array(d.object({name:d.string(),bulletPoints:d.array(d.string()).optional(),tags:d.array(d.string()).optional(),media:Q.optional()})).optional(),valueCards:d.array(d.object({heading:d.string(),description:d.string().optional(),icon:d.string().optional()})).optional(),iconLinkCards:d.array(d.object({heading:d.string(),description:d.string().optional(),linkLabel:d.string().optional(),icon:d.string().optional()})).optional(),oneMediaCards:d.array(d.object({heading:d.string(),description:d.string().optional()})).optional(),oneMedia:Q.optional(),autoScroll:d.boolean().optional(),autoScrollDuration:d.number().optional(),containerWidth:G}).superRefine((t,n)=>{let e=t.layout;if(!e||!ze({type:"CardsSection",props:t}))return;let s=e==="one-media"?"'oneMedia' or non-empty 'oneMediaCards'":`non-empty '${St[e]}'`;n.addIssue({code:d.ZodIssueCode.custom,message:`CardsSection layout '${e}' requires ${s}`})}),_s=d.object({layout:d.enum(["carousel-with-stat","mixed-stat-and-quote","centered-single","carousel-split-media-left","carousel-case-study","single-card-stat-quote","quote-cards","quote-cards-with-media"]).optional(),heading:d.string().optional(),description:d.string().optional(),miniTitle:d.string().optional(),ctaLabel:d.string().optional(),ctaHref:d.string().optional(),cards:d.array(d.object({quote:d.string(),authorName:d.string(),authorRole:d.string(),stars:d.number().optional(),stat:d.string().optional(),statLabel:d.string().optional(),logoKey:d.string().optional(),ctaLabel:d.string().optional(),ctaHref:d.string().optional(),media:Q.optional()})).optional(),carouselCards:d.array(d.object({type:d.enum(["stat","quote"]),category:d.string().optional(),stat:d.string().optional(),statLabel:d.string().optional(),quote:d.string().optional(),authorName:d.string().optional(),authorRole:d.string().optional(),logoKey:d.string().optional(),media:Q.optional()})).optional(),caseStudyCards:d.array(d.object({stat:d.string(),statLabel:d.string(),category:d.string().optional(),ctaLabel:d.string().optional(),ctaHref:d.string().optional(),logoKey:d.string().optional(),media:Q.optional()})).optional(),containerWidth:G}).superRefine((t,n)=>{let e=t.layout;if(!e||!(e in De))return;let s=De[e],i=t[s];(!Array.isArray(i)||i.length===0)&&n.addIssue({code:d.ZodIssueCode.custom,message:`TestimonialsSection layout '${e}' requires non-empty '${s}'`})}),Os=d.object({layout:d.enum(["side-by-side","centered"]).optional(),heading:d.string().optional(),items:d.array(d.object({question:d.string(),answer:d.string()})),containerWidth:G}),Is=d.object({layout:d.enum(["icons","cardsRight"]).optional(),miniTitle:d.string().optional(),heading:d.string(),description:d.string().optional(),items:d.array(d.object({title:d.string(),description:d.string(),icon:d.string().optional()})),columns:d.union([d.literal(2),d.literal(3)]).optional(),cta:kt.optional(),containerWidth:G}),Ms=d.object({layout:d.enum(["centered","floating-card"]).optional(),heading:d.string(),description:d.string().optional(),ctas:d.array(kt).optional(),containerWidth:G}),Ps=d.object({logoKey:d.string().optional(),logoAlt:d.string().optional()}),Ns=d.object({heading:d.string().optional(),description:d.string().optional(),ratingValue:d.string().optional(),ratingLabel:d.string().optional(),formTitle:d.string().optional(),submitLabel:d.string().optional(),fields:d.array(d.object({name:d.string(),placeholder:d.string(),type:d.enum(["text","email","tel","select","textarea"]).optional(),options:d.array(d.string()).optional(),required:d.boolean().optional()})).optional(),logos:d.array(d.object({key:d.string(),name:d.string()})).optional(),badges:d.array(d.object({src:d.string().describe("A G2_BADGES/COMPLIANCE_LOGOS/ANALYST_LOGOS key or a `data:` URI. Unknown/external values are dropped by the SSR renderer."),label:d.string()})).optional(),containerWidth:G}),Bs=d.object({layout:d.enum(["badges","bento"]).optional(),heading:d.string().optional(),ratingValue:d.string().optional(),ratingOut:d.number().optional(),ratingLabel:d.string().optional(),badges:d.array(d.object({src:d.string().describe("A G2_BADGES/COMPLIANCE_LOGOS/ANALYST_LOGOS key or a `data:` URI. Unknown/external values are dropped by the SSR renderer."),label:d.string(),size:d.enum(["regular","large"]).optional()})).optional(),ctaLabel:d.string().optional(),ctaHref:d.string().optional(),topicLabel:d.string().optional(),securityTitle:d.string().optional(),securityDescription:d.string().optional(),securityLinkLabel:d.string().optional(),securityLinkHref:d.string().optional(),complianceLogos:d.array(d.object({src:d.string().describe("A COMPLIANCE_LOGOS/G2_BADGES/ANALYST_LOGOS key or a `data:` URI. Unknown/external values are dropped by the SSR renderer."),label:d.string()})).optional(),statCards:d.array(d.object({topLabel:d.string(),stat:d.string(),description:d.string(),linkLabel:d.string().optional(),linkHref:d.string().optional()})).optional()}),Fs=d.object({layout:d.enum(["bento","stack-bento"]).optional(),heading:d.string(),theme:On,items:d.array(d.object({value:d.string(),label:d.string()})),containerWidth:G}),Ks=d.object({layout:d.enum(["grid","card-grid","logo-strip"]).optional(),heading:d.string().optional(),description:d.string().optional(),integrations:d.array(d.object({name:d.string(),key:d.string()})).optional(),statValue:d.string().optional(),statLabel:d.string().optional(),ctaLabel:d.string().optional(),ctaHref:d.string().optional(),animate:d.boolean().optional()}),We={HeaderSection:Es,CustomerLogoSection:js,FeaturesSection:Ls,CardsSection:Ts,TestimonialsSection:_s,FaqSection:Os,BulletsSection:Is,CtaSection:Ms,FooterSection:Ps,ContactSection:Ns,TrustSection:Bs,NumbersSection:Fs,IntegrationsSection:Ks},$e=Object.keys(We),qs=d.object({colorScheme:d.enum(["purple","black"]).optional(),logoAriaLabel:d.string().optional(),navItems:d.array(d.object({label:d.string(),href:d.string().optional(),active:d.boolean().optional(),showChevron:d.boolean().optional(),dropdownColumns:d.array(d.object({heading:d.string().optional(),items:d.array(d.object({label:d.string(),href:d.string().optional(),description:d.string().optional(),isHeading:d.boolean().optional()}))})).optional()})).optional(),contactSalesHref:d.string().optional(),pricingHref:d.string().optional(),loginHref:d.string().optional(),actionLabel:d.string().optional(),actionHref:d.string().optional(),actionSize:d.enum(["large","regular","mini"]).optional()}),In=d.object({brand:d.string().optional(),nav:qs.optional(),sections:d.array(d.object({type:d.enum($e),props:d.record(d.string(),d.unknown())}))});var Us={CustomerLogoSection:["logoKeys"],FeaturesSection:["items"],CardsSection:["cards","valueCards","revealCards","iconLinkCards","oneMediaCards"],TestimonialsSection:["cards","carouselCards","caseStudyCards"],FaqSection:["items"],BulletsSection:["items"],NumbersSection:["items"],IntegrationsSection:["integrations"]};function Mn(t){return Array.isArray(t)?t:[]}function Hs(t){let n=t.props;if(t.type==="CardsSection"||t.type==="TestimonialsSection")return ze({type:t.type,props:n});let e=Us[t.type];return e?e.every(s=>Mn(n[s]).length===0):!1}function Ge(t){return Mn(t).filter(n=>typeof n=="string")}function Pn(t,n){let e=JSON.parse(JSON.stringify(t)),s=[],i=e.sections.map((a,l)=>({section:a,originalIndex:l}));for(let{section:a,originalIndex:l}of i){if(a.type!=="CustomerLogoSection"&&a.type!=="HeaderSection")continue;let c=a.props,u=Ge(c.logoKeys);if(u.length===0)continue;let p=[...new Set(u)];p.length!==u.length&&(c.logoKeys=p,s.push({rule:"dedupe-logo-keys",sectionIndex:l,message:`Removed ${u.length-p.length} duplicate logo key(s) within ${a.type}.`}))}let o=new Set;for(let{section:a}of i)if(a.type==="CustomerLogoSection")for(let l of Ge(a.props.logoKeys))o.add(l);if(o.size>0)for(let{section:a,originalIndex:l}of i){if(a.type!=="HeaderSection")continue;let c=a.props,u=Ge(c.logoKeys);if(u.length===0)continue;let p=u.filter(f=>!o.has(f));p.length!==u.length&&(p.length===0?delete c.logoKeys:c.logoKeys=p,s.push({rule:"dedupe-logos-cross-section",sectionIndex:l,message:`Removed ${u.length-p.length} hero logo(s) already shown in a CustomerLogoSection (avoids doubling).`}))}i=i.filter(({section:a,originalIndex:l})=>{if(a.type==="CustomerLogoSection"&&n?.resolveLogoKey){let c=Ge(a.props.logoKeys);if(c.length>0&&c.every(u=>!n.resolveLogoKey(u)))return s.push({rule:"drop-empty-section",sectionIndex:l,message:"Dropped CustomerLogoSection \u2014 no logo keys resolved."}),!1}return Hs(a)?(s.push({rule:"drop-empty-section",sectionIndex:l,message:`Dropped ${a.type} with no content.`}),!1):!0}),i=i.filter((a,l,c)=>{if(l===0)return!0;let u=c[l-1];return u.section.type===a.section.type&&JSON.stringify(u.section.props)===JSON.stringify(a.section.props)?(s.push({rule:"collapse-duplicate-adjacent",sectionIndex:a.originalIndex,message:`Dropped ${a.section.type} identical to the section immediately before it.`}),!1):!0});let r=i.findIndex(({section:a})=>a.type==="HeaderSection");if(r>0){let[a]=i.splice(r,1);i.unshift(a),s.push({rule:"hero-first",sectionIndex:a.originalIndex,message:"Moved HeaderSection to the top \u2014 a marketing page must open with its hero."})}return e.sections=i.map(({section:a})=>a),{spec:e,changes:s}}function Nn(t){let n="";for(let e of t)n+=typeof e=="number"?`[${e}]`:n?`.${String(e)}`:String(e);return n||"$"}function Ds(t,n){let e=Array.from({length:t.length+1},(s,i)=>[i,...new Array(n.length).fill(0)]);for(let s=1;s<=n.length;s++)e[0][s]=s;for(let s=1;s<=t.length;s++)for(let i=1;i<=n.length;i++)e[s][i]=Math.min(e[s-1][i]+1,e[s][i-1]+1,e[s-1][i-1]+(t[s-1]===n[i-1]?0:1));return e[t.length][n.length]}function zs(t,n=3){let e=t.toLowerCase().replace(/section$/,"");return[...$e].map(s=>{let i=s.toLowerCase().replace(/section$/,"");return{t:s,d:i.includes(e)||e.includes(i)?0:Ds(e,i)}}).sort((s,i)=>s.d-i.d||(s.t<i.t?-1:1)).slice(0,n).map(s=>s.t)}var Se=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function Bn(t){let n=[],e=[],s=t;if(typeof t=="string")try{s=JSON.parse(t)}catch(l){return{valid:!1,errors:[{path:"$",rule:"page-spec.json",message:`the spec string is not valid JSON: ${l.message}`}],warnings:e,sections:0}}if(!Se(s))return{valid:!1,errors:[{path:"$",rule:"page-spec.shape",message:"a PageSpec is an object: { brand?, nav?, sections: [{ type, props }] }"}],warnings:e,sections:0};let i=In.safeParse(s),o=Array.isArray(s.sections)?s.sections:[];if(!i.success)for(let l of i.error.issues){let c=Nn(l.path);if(l.path.length===3&&l.path[0]==="sections"&&l.path[2]==="type"){let p=o[l.path[1]]?.type;n.push({path:c,rule:"page-spec.section-type",message:typeof p=="string"?`unknown section type "${p}" \u2014 nearest: ${zs(p).join(", ")} (all: ${$e.join(", ")})`:`a section needs a "type": one of ${$e.join(", ")}`})}else n.push({path:c,rule:"page-spec.shape",message:l.message})}o.forEach((l,c)=>{if(!Se(l)||typeof l.type!="string"||!(l.type in We)||!Se(l.props))return;let u=We[l.type].safeParse(l.props);if(!u.success)for(let p of u.error.issues){let f=`sections[${c}].props`,g=p.path.length?`${f}.${Nn(p.path)}`.replace(".[","["):f;n.push({path:g,rule:p.code==="custom"?"page-spec.layout-content":"page-spec.props",message:`${l.type}: ${p.message}`})}});let r=l=>Se(l)&&Se(l.props)&&l.props.theme==="muted";o.forEach((l,c)=>{c>0&&r(l)&&r(o[c-1])&&n.push({path:`sections[${c}].props.theme`,rule:"rule.C6",message:`two theme="muted" sections back to back (sections[${c-1}] and sections[${c}]): alternate the tint (Hard Rule C6)`})});let a;if(i.success)try{let l=Pn(i.data);a=l.spec;for(let c of l.changes)e.push({path:c.sectionIndex===void 0?"$":`sections[${c.sectionIndex}]`,rule:`page-spec.normalize:${c.rule}`,message:c.message})}catch(l){e.push({path:"$",rule:"page-spec.normalize",message:`normalizePageSpec could not run: ${l.message}`})}return{valid:n.length===0,errors:n,warnings:e,...a!==void 0?{normalized:a}:{},sections:o.length}}function Fn(t,n={}){let e=i=>`- \`${i.path}\` \xB7 ${i.rule} \u2014 ${i.message}`,s=[t.valid?`# valid PageSpec \xB7 ${t.sections} sections`:`# invalid PageSpec \xB7 ${t.errors.length} error(s) \xB7 ${t.sections} sections`];return t.errors.length&&s.push("## errors",...t.errors.map(e)),t.warnings.length&&s.push("## warnings (what normalizePageSpec changes at render time)",...t.warnings.map(e)),t.valid&&!t.warnings.length&&s.push("No findings. Next: clay_check_copy on the same spec."),n.detail&&t.normalized!==void 0&&s.push("## normalized spec","```json",JSON.stringify(t.normalized,null,1),"```"),`${s.join(`
113
+ `)}
114
+ `}var F=x.boolean().optional().describe("Return the answer as JSON text (same content plus the registry version) instead of Markdown."),ee=t=>x.boolean().optional().describe(t),xt=x.enum(kn).describe("Page-build stage."),vt=x.enum(wn).describe("web-compose mode: A = page brief, B = PMM brief (structure and copy already decided)."),Ye=(t,n=25)=>x.array(x.string()).min(1).max(n).describe(t),Kn=t=>x.number().int().min(1).max(200).optional().describe(`Page size (default ${t}, at most 200).`),qn=x.number().int().min(0).optional().describe("Skip this many rows (paging)."),Un=t=>x.string().min(1).describe(`${t}. Accepts a record id (section.FeaturesSection), an entity id (section:FeaturesSection), a skill alias (web-pmm), a handbook id or a CSS variable (--clay-web-type-family).`),Hn=(t,n)=>`\`${t}\` needs repo mode (this server was not started inside the Clay repo); pass ${n} instead.`,oe=t=>({text:t,data:{error:t},isError:!0}),Je=(t,n)=>t.reg.resolve(gt(n)),Ct=(t,n)=>t.reg.get(n),Dn=(t,n)=>{let e=Array.from({length:t.length+1},(s,i)=>[i,...new Array(n.length).fill(0)]);for(let s=1;s<=n.length;s++)e[0][s]=s;for(let s=1;s<=t.length;s++)for(let i=1;i<=n.length;i++)e[s][i]=Math.min(e[s-1][i]+1,e[s][i-1]+1,e[s-1][i-1]+(t[s-1]===n[i-1]?0:1));return e[t.length][n.length]};function Rt(t,n,e,s=3){let i=[],o=a=>a.toLowerCase().replace(/^(?:var\()?--clay-/,"").replace(/\)$/,"").replace(/\bclay-/g,"").replace(/section$/,""),r=o(n);if(r.length>=3){let a=Math.max(2,Math.floor(r.length*.3)),l=[];for(let c of t.units){if(e&&!e.includes(c.kind))continue;let u=c.id.split("."),p=Number.POSITIVE_INFINITY;for(let f=0;f<Math.min(3,u.length);f++){let g=o(u.slice(f).join("."));Math.abs(g.length-r.length)>a||(p=Math.min(p,Dn(r,g)))}p<=a&&l.push({id:c.id,d:p})}i.push(...l.sort((c,u)=>c.d-u.d||(c.id<u.id?-1:1)).slice(0,s).map(c=>c.id))}try{let a=t.kb.search({query:n,k:s,...e?{kind:e}:{},scope:["all"]}).data.hits;for(let l of a)i.includes(l.id)||i.push(l.id)}catch{}return i.slice(0,s)}function ke(t,n,e,s){let i=Rt(t,e,s);return oe(`no ${n} "${e}"${i.length?` \u2014 closest: ${i.join(", ")}`:" \u2014 try clay_search"}`)}var we=t=>`- \`${t.id}\` \u2014 ${t.summary}`;function Ws(t){if(typeof t!="string")return t;try{return JSON.parse(t)}catch(n){throw new Error(`"spec" is a string but not valid JSON: ${n.message}`)}}function Gs(t,n){let e=t.reg.get(n,{detail:!0});if(!e)return null;let s=e,i=[`### registry \xB7 ${n}`],o=Object.entries(s).filter(([S,y])=>!["body","data","facts","aliases","links","relations","renders","content_hash"].includes(S)&&y!==null&&y!==""&&!(Array.isArray(y)&&!y.length)).map(([S,y])=>`${S}: ${Z(y,120)}`);i.push(o.join(" \xB7 "));for(let S of["data","facts"])s[S]!==null&&s[S]!==void 0&&i.push(`${S}: ${Z(s[S],1500)}`);e.aliases.length&&i.push(`aliases: ${e.aliases.map(S=>`${S.alias} (${S.type})`).join(", ")}`);let r=e.links;if(r.length){i.push(`links (${r.length}):`);for(let S of r.slice(0,40)){let y=S.url??(S.import_path?`${S.import_path}#${S.export_name}`:S.variable_id??S.ref);i.push(`- ${[S.type,S.role,S.variant].filter(Boolean).join("/")} \u2192 ${Z(y,160)}`)}r.length>40&&i.push(`- \u2026 ${r.length-40} more links (json: true for all)`)}let a=S=>{let y=e.relations[S];i.push(`relations ${S} (${y.length}${y.length>50?`, first ${50}; clay_related pages the rest`:""}):`);for(let v of y.slice(0,50))i.push(`- ${v.type} ${v.target?`\`${v.target.id}\` \u2014 ${v.target.summary}`:`\`${v.to_ref??"?"}\` (unresolved)`}`)};e.relations.out.length&&a("out"),e.relations.in.length&&a("in");let l=e.renders;l.length&&i.push(`renders: ${l.map(S=>[S.variant,S.theme].filter(Boolean).join("/")||"default").join(", ")} (clay_render for the rows)`);let c;if(s.kind==="recipe"||s.kind==="page"){let S=t.reg.pageRecipe(n);c=S,S.length&&i.push("pageRecipe:",...S.map(y=>`${y.ord}. ${y.record?`\`${y.record.id}\``:y.ref}`))}let{body:u,data:p,facts:f,...g}=s,m=S=>S.slice(0,50),$={...g,relations:{out:m(e.relations.out),in:m(e.relations.in),counts:{out:e.relations.out.length,in:e.relations.in.length}},...c?{pageRecipe:c}:{}};return{text:i.join(`
115
+ `),data:$}}function K(t,n,e,s,i){let o=async r=>{try{let a=await n.getEngine(),l=await i(r,a);return _n(l,r.json,a.info,s.hint)}catch(a){let l=a?.message?.trim()||String(a)||"failed";return bt($t(`${e}: ${l.replace(new RegExp(`^${e.replace(/^clay_/,"")}: `),"")}`))}};t.registerTool(e,{title:s.title,description:s.description,inputSchema:s.schema,annotations:{readOnlyHint:!0,idempotentHint:!0,openWorldHint:!1,title:s.title}},o)}function zn(t,n){K(t,n,"clay_search",{title:"Search Clay",description:"Ask the Clay design system a question; returns the top record ids with summaries (BM25 + facets). Follow up with clay_get. Use `each` to resolve several names (logos, icons, sections) in one call.",hint:"lower k, add kind/entity filters, or search each term separately.",schema:x.strictObject({query:x.string().optional().describe("Words to search for. Required unless `each` is given."),each:Ye("Several names to resolve in one call (logos, icons): the best hit per term; `query`, if set, is added to each.",25).optional(),k:x.number().int().min(1).max(50).optional().describe("How many hits (default 10; with `each`: per term, default 1)."),kind:x.array(x.string()).optional().describe("Record kinds or subkinds, e.g. gotcha, policy, layout, limit, rule, section, token, logo, icon."),entity:x.array(x.string()).optional().describe("Entity ids, e.g. section:FeaturesSection."),stage:x.array(xt).optional().describe("Only records that apply to these stages."),mode:vt.optional(),scope:x.array(x.enum(xn)).optional().describe('Default web + ds + shared; email knowledge needs ["email"] (or ["all"]).'),includeBackground:x.boolean().optional().describe("Also search research/background records (never routed)."),detail:ee("Per hit: subkind, name, status and links."),json:F})},(e,s)=>{if(!e.query&&!e.each?.length)return oe('clay_search needs "query" (or "each").');let i={k:e.k,kind:e.kind,entity:e.entity,stage:e.stage,mode:e.mode,scope:e.scope,includeBackground:e.includeBackground},o,r,a;if(e.each?.length){let l=s.kb.searchEach({each:e.each,query:e.query,...i});o=l.text,a={results:l.data.results},r=l.data.results.flatMap(c=>c.hits)}else{let l=s.kb.search({query:e.query,...i});o=l.text,a={hits:l.data.hits},r=l.data.hits,l.data.hits.length||(o=`No records match "${e.query}". Try fewer or different words, scope ["all"] (email knowledge), or clay_list for the kinds.
116
+ `)}if(e.detail&&r.length){let l=r.map(c=>({h:c,c:Ct(s,c.id)})).filter(c=>c.c);o+=`
117
+ ## details
118
+ ${l.map(({c})=>`- \`${c.id}\` \xB7 ${[c.subkind,c.name,c.status].filter(Boolean).join(" \xB7 ")}${z(c.links)?` \xB7 ${z(c.links)}`:""}`).join(`
119
+ `)}
120
+ `,a={...a,details:l.map(c=>c.c)}}return{text:o,data:a}}),K(t,n,"clay_get",{title:"Get Clay records",description:"Full bodies of Clay records by id, up to 25 ids in ONE call (an id ending in * expands to that prefix). Aliases work: web-pmm, section:FeaturesSection, --clay-web-type-family. Each record has a links line (import path, Storybook, Figma, CDN).",hint:"ask for fewer ids per call.",schema:x.strictObject({ids:x.union([x.string().min(1),Ye("Record ids.",25)]).describe("One id or up to 25. An id ending in * expands to that prefix."),detail:ee("Add the full registry record: columns, aliases, links, relations (50 per direction, with counts), render metadata; recipes and pages add pageRecipe."),json:F})},(e,s)=>{let i=typeof e.ids=="string"?[e.ids]:e.ids,o=s.kb.get({ids:i});if(!o.data.units.length)return ke(s,"record",i.join(", "));let r=[];for(let c of o.text.split(`
121
+ `)){r.push(c);let u=/^## (\S+) · /.exec(c);if(u){let p=z(Ct(s,u[1])?.links);p&&r.push(`links: ${p}`)}}let a=r.join(`
122
+ `);if(o.data.missing.length){let c=o.data.missing.filter(u=>!u.endsWith("*")).map(u=>({m:u,ids:Rt(s,u)})).filter(u=>u.ids.length);c.length&&(a+=`Closest: ${c.map(u=>`${u.m}: ${u.ids.join(", ")}`).join(" \xB7 ")}
123
+ `)}let l={units:o.data.units,missing:o.data.missing,resolved:o.data.resolved};if(e.detail){let c=o.data.units.map(u=>Gs(s,u.id)).filter(u=>u!==null);a+=`
124
+ ${c.map(u=>u.text).join(`
125
+
126
+ `)}
127
+ `,l={...l,records:c.map(u=>u.data)}}return{text:a,data:l}}),K(t,n,"clay_list",{title:"List Clay records",description:"Without `kind`: the record kinds and subkinds with counts. With `kind` (a kind or a subkind, e.g. section, token, logo, rule): its records as `id \u2014 summary`, paged.",hint:"use limit and offset.",schema:x.strictObject({kind:x.string().optional().describe("A kind or subkind. Omit to list the kinds."),scope:x.string().optional().describe("Only this scope: web, email, ds, shared."),status:x.string().optional().describe("Only this status, e.g. active, deprecated."),limit:Kn(50),offset:qn,detail:ee("Add each record's links."),json:F})},(e,s)=>{if(!e.kind){let u=s.reg.db.prepare("SELECT kind, subkind, count(*) AS n FROM records GROUP BY kind, subkind ORDER BY kind, subkind").all(),p=new Map;for(let m of u){let $=p.get(m.kind)??{total:0,subs:[]};$.total+=m.n,m.subkind&&$.subs.push({subkind:m.subkind,n:m.n}),p.set(m.kind,$)}let f=u.reduce((m,$)=>m+$.n,0);return{text:`${[`# Registry ${s.info.version} \xB7 ${f} records \xB7 kinds (clay_list kind=<kind or subkind>)`,...[...p].map(([m,$])=>`- ${m} (${$.total})${$.subs.length?`: ${$.subs.map(S=>`${S.subkind} ${S.n}`).join(" \xB7 ")}`:""}`)].join(`
128
+ `)}
129
+ `,data:{total:f,kinds:[...p].map(([m,$])=>({kind:m,count:$.total,subkinds:$.subs}))}}}let i=s.reg.list(e.kind,{scope:e.scope,status:e.status}),o=e.limit??50,r=e.offset??0,a=i.slice(r,r+o);if(!i.length)return{text:`No records of kind "${e.kind}"${e.scope?` in scope ${e.scope}`:""}${e.status?` with status ${e.status}`:""}. clay_list with no kind shows the kinds.
130
+ `,data:{kind:e.kind,total:0,records:[]}};let l=r+a.length<i.length;return{text:`${[`# ${e.kind} \xB7 ${i.length?`${r+1}\u2013${r+a.length} of ${i.length}`:"0"}`,...a.map(u=>e.detail?`${we(u)}${z(u.links)?`
131
+ ${z(u.links)}`:""}`:we(u)),...l?[`\u2026 ${i.length-r-a.length} more: call again with offset ${r+a.length}.`]:[]].join(`
132
+ `)}
133
+ `,data:{kind:e.kind,total:i.length,offset:r,limit:o,records:a}}}),K(t,n,"clay_related",{title:"Related Clay records",description:"Typed edges of a record, out and in (variant-of, uses-token, uses-component, has-item, composes, \u2026), grouped by type.",hint:"use limit and offset, or filter by type and kind.",schema:x.strictObject({id:Un("The record"),type:x.array(x.string()).optional().describe("Only these relation types, e.g. uses-token, variant-of, has-item."),direction:x.enum(["out","in","both"]).optional().describe("Default both."),kind:x.array(x.string()).optional().describe("Only edges whose other end has one of these kinds or subkinds."),limit:Kn(50),offset:qn,detail:ee("Add each target's links."),json:F})},(e,s)=>{let i=Je(s,e.id);if(!i)return ke(s,"record",e.id);let o=s.reg.related(i,{type:e.type,direction:e.direction,kind:e.kind}),r=e.limit??50,a=e.offset??0,l=o.slice(a,a+r);if(!o.length)return{text:`\`${i}\` has no ${e.direction&&e.direction!=="both"?`${e.direction} `:""}relations${e.type?` of type ${e.type.join(", ")}`:""}${e.kind?` to kind ${e.kind.join(", ")}`:""}.
134
+ `,data:{id:i,total:0,edges:[]}};let c=new Map;for(let f of o)c.set(`${f.direction} \xB7 ${f.type}`,(c.get(`${f.direction} \xB7 ${f.type}`)??0)+1);let u=[`# \`${i}\` \xB7 ${a+1}\u2013${a+l.length} of ${o.length} edges`],p="";for(let f of l){let g=`${f.direction} \xB7 ${f.type}`;g!==p&&(u.push(`## ${g} (${c.get(g)})`),p=g),u.push(`${we(f.record)}${e.detail&&z(f.record.links)?`
135
+ ${z(f.record.links)}`:""}`)}return a+l.length<o.length&&u.push(`\u2026 ${o.length-a-l.length} more: call again with offset ${a+l.length}.`),{text:`${u.join(`
136
+ `)}
137
+ `,data:{id:i,total:o.length,offset:a,limit:r,edges:l}}}),K(t,n,"clay_asset_url",{title:"Asset URLs",description:"The CDN URL of a logo, icon, badge, agent image or shape (`id \u2192 url`). A logo family resolves to the file in `variant` (default: the default file). Use `ids` for many.",hint:"ask for fewer ids.",schema:x.strictObject({id:x.string().min(1).optional().describe("One asset: a record id (asset.logo.customer.adevinta, asset.icon.calendar) or an alias."),ids:Ye("Several assets in one call.",50).optional(),format:x.enum(["svg","png"]).optional().describe("Default svg, else png."),variant:x.string().optional().describe("A logo variant (white, black, default, \u2026); an unmatched variant gives no url rather than another colour."),detail:ee("For a logo family: every variant with its url."),json:F})},(e,s)=>{let i=[...e.id?[e.id]:[],...e.ids??[]];if(!i.length)return oe('clay_asset_url needs "id" or "ids".');let o=[],r=[];for(let a of i){let l=Je(s,a);if(!l){let g=Rt(s,a,["asset","logo","icon","agent","badge","shape"]);o.push({id:a,resolved:null,url:null}),r.push(`${a} \u2192 not found${g.length?` (closest: ${g.join(", ")})`:""}`);continue}let c=s.reg.assetUrl(l,{format:e.format,variant:e.variant}),u=s.reg.assetVariants(l),p=l===a?l:`${a} (${l})`;c?r.push(`${p} \u2192 ${c}`):r.push(`${p} \u2192 no url${e.variant?` for variant "${e.variant}"`:""}${e.format?` as ${e.format}`:""}${u.length?` \u2014 variants: ${u.map(g=>g.variant).join(", ")}`:""}`);let f={id:a,resolved:l,url:c};if(e.detail&&u.length){f.variants=u.map(g=>({...g,url:s.reg.assetUrl(l,{format:e.format,variant:g.variant})}));for(let g of f.variants)r.push(` - ${g.variant} \u2192 ${g.url??"no url"}`)}o.push(f)}return o.every(a=>!a.resolved)?oe(r.join(`
138
+ `)):{text:`${r.join(`
139
+ `)}
140
+ `,data:{assets:o}}}),K(t,n,"clay_render",{title:"Rendered output",description:"What a section, layout or component renders to: the stored render rows (variant, theme, screenshots, mirror, version). `html: true` adds the HTML (capped at 60 kB). Renders arrive with registry Phase 3; until a record has one this says so.",hint:"ask for one variant and theme.",schema:x.strictObject({id:Un("The record"),variant:x.string().optional().describe("Only this variant (e.g. a layout name)."),theme:x.string().optional().describe("Only this theme (default, muted, \u2026)."),html:x.boolean().optional().describe("Include the render HTML (capped at 60 kB; beyond that the mirror url is given)."),json:F})},(e,s)=>{let i=Je(s,e.id);if(!i)return ke(s,"record",e.id);let r=(s.reg.get(i,{detail:!0,html:e.html===!0})?.renders??[]).filter(Boolean),a=r.filter(p=>(!e.variant||p.variant===e.variant)&&(!e.theme||p.theme===e.theme)),l=Ct(s,i)?.links?.story;if(!r.length)return{text:`No render for ${i} yet (registry Phase 3).${l?` Storybook: ${l}`:""}
141
+ `,data:{id:i,renders:[]}};if(!a.length)return{text:`No render of ${i} matches variant ${e.variant??"*"} theme ${e.theme??"*"}. Available: ${r.map(p=>[p.variant,p.theme].filter(Boolean).join("/")||"default").join(", ")}.
142
+ `,data:{id:i,renders:[]}};let c=[`# ${i} \xB7 ${a.length} render(s)${l?` \xB7 Storybook ${l}`:""}`];for(let p of a){let f=Object.entries(p).filter(([g,m])=>g!=="html"&&g!=="record_id"&&m!==null&&m!==""&&m!==void 0).map(([g,m])=>`${g}: ${Array.isArray(m)?`${m.length} item(s)`:Z(m,160)}`);if(c.push(`- ${[p.variant,p.theme].filter(Boolean).join("/")||"default"} \xB7 ${f.join(" \xB7 ")}`),e.html){let g=typeof p.html=="string"?p.html:void 0;g?Buffer.byteLength(g)>6e4?c.push(` HTML is ${Buffer.byteLength(g)} bytes, over the ${6e4} cap${p.mirror_url?`; read it at ${Z(p.mirror_url)}`:""}.`):c.push("```html",g,"```"):c.push(` (no HTML stored for this render${p.mirror_url?`; mirror: ${Z(p.mirror_url)}`:""})`)}}let u=a.map(p=>e.html&&typeof p.html=="string"&&Buffer.byteLength(p.html)>6e4?{...p,html:void 0,html_omitted:!0}:p);return{text:`${c.join(`
143
+ `)}
144
+ `,data:{id:i,renders:u}}}),K(t,n,"clay_section",{title:"Section facts",description:'Sections and layouts: props, item shapes with their copy limits, layouts with item ranges and what each drops, gotchas. Several at once in ONE call: names ["A","B"] with layouts ["x",""] paired by position (an unknown name is reported, the rest still answer). No name lists every section with its layouts.',hint:"ask for one section and layout.",schema:x.strictObject({name:x.string().min(1).optional().describe("e.g. FeaturesSection. Omit (and names) to list every section."),names:Ye("Several sections in one call.",10).optional(),layout:x.string().optional().describe("e.g. tab-cards-carousel. Several layouts may be comma-separated."),layouts:x.array(x.string()).max(10).optional().describe("Layouts paired with `names` by position (an empty string = none for that section)."),scope:x.enum(["email"]).optional().describe("`email` lists the email sections (no name)."),detail:ee("Add what the section can hold: item types, nested components, media slots."),json:F})},(e,s)=>{let i=e.names??(e.name?[e.name]:[]);if(!i.length){let g=s.kb.sectionList({scope:e.scope});return{text:g.text,data:{...g.data}}}let o=g=>!!(s.reg.resolve(`section.${g}`)||s.reg.resolve(`component.${g}`)||s.reg.resolve(g)),r=i.map((g,m)=>({n:g,l:e.layouts?.[m]??(e.names&&e.layout?e.layout.split(",")[m]:void 0)})),a=r.filter(g=>!o(g.n)).map(g=>g.n),l=(s.kb.sectionList({}).data.sections??[]).map(g=>g.replace(/^section\./,"")),c=a.length?`${a.map(g=>{let m=S=>S.toLowerCase().replace(/section$/,""),$=l.filter(S=>Dn(m(S),m(g))<=Math.max(2,Math.floor(m(g).length/4)));return`no section or component "${g}"${$.length?` \u2014 closest: ${$.map(S=>`section.${S}`).join(", ")}`:" (Clay has no section by that name)"}`}).join("; ")}. Sections: ${l.join(", ")}; atoms and email sections: clay_section with no name.`:"";if(a.length===i.length)return{text:c,data:{unknown:a,sections:l},isError:!0};let u=r.filter(g=>o(g.n)),p,f;if(e.names){let g=s.kb.sections({names:u.map(m=>m.n),layouts:u.some(m=>m.l)?u.map(m=>m.l??""):void 0});p=g.text,f={sections:g.data.sections}}else{let g=s.kb.section({name:i[0],layout:e.layout??(e.layouts?.length?e.layouts.join(","):void 0)});p=g.text,f={...g.data}}if(c&&(p=`${c}
145
+
146
+ ${p}`,f={...f,unknown:a}),e.detail){let m=i.map($=>({n:$,id:s.reg.resolve(`section.${$}`)})).filter($=>$.id).map(({n:$,id:S})=>({n:$,c:s.reg.allowedChildren(S)}));p+=`
147
+ ${m.map(({n:$,c:S})=>[`## allowed children \xB7 ${$}`,`item types: ${S.itemTypes.map(y=>`\`${y.id}\``).join(", ")||"\u2014"}`,`components in layouts: ${S.components.map(y=>`\`${y.id}\``).join(", ")||"\u2014"}`,`media slots: ${S.mediaSlots.length?Z(S.mediaSlots,800):"\u2014"}`].join(`
148
+ `)).join(`
149
+
150
+ `)}
151
+ `,f={...f,allowedChildren:m.map(({n:$,c:S})=>({section:$,...S}))}}return{text:p,data:f}}),K(t,n,"clay_route",{title:"Route a stage",description:"What do I need for this stage? The ordered, minimal Clay knowledge for one skill \xD7 mode \xD7 stage (procedure bodies, the policies that decide collisions, brief \u2192 layout candidates, ranked gotchas), inlined within a token budget. Call it at the start of every page-build stage.",hint:"lower the budget or drop the brief.",schema:x.strictObject({skill:x.string().min(1).describe("Skill running the stage, e.g. web-compose, web-pmm, web-assets, web-qa, email-compose (email skills route over the email scope). Aliases work."),stage:xt,mode:vt.optional(),brief:x.string().max(1048576).optional().describe("The brief text (Markdown), inline."),briefPath:x.string().optional().describe("Repo mode only: a brief file inside the repo."),budget:x.number().int().min(200).max(2e4).optional().describe("Token budget (default 2500)."),json:F})},(e,s)=>{let i=e.brief;if(!i&&e.briefPath){if(!n.root)return oe(Hn("briefPath","`brief` inline"));i=ht(n.root,e.briefPath).text}if(!s.reg.resolve(`skill.${e.skill}`)&&!s.reg.resolve(e.skill))return ke(s,"skill",e.skill,["skill"]);let o=s.kb.route({skill:e.skill,stage:e.stage,mode:e.mode,brief:i,budget:e.budget});return{text:`${o.text}
152
+ <!-- ${o.data.tokens} tokens (budget ${o.data.budget}) -->
153
+ `,data:o.data}}),K(t,n,"clay_rules",{title:"Rules for a stage",description:'The Hard Rules and the Critical/Major policies with enforcement that apply to a stage (and mode); scope "email" lists the email rules instead.',hint:"filter by stage.",schema:x.strictObject({stage:xt.optional(),mode:vt.optional(),scope:x.enum(vn).optional().describe("`email` lists the email rules; web or omitted lists the web ones."),json:F})},(e,s)=>{let i=s.kb.rules({stage:e.stage,mode:e.mode,scope:e.scope});return{text:i.text,data:{...i.data}}}),K(t,n,"clay_check_copy",{title:"Check copy limits",description:"Copy strings checked against the section limits (chars, words, sentences; hard limits are Critical). Pass a PageSpec as `spec`. Repo mode also takes a page file (`page`) or TSX text (`source`).",hint:"pass fewer sections.",schema:x.strictObject({spec:x.union([x.record(x.string(),x.unknown()),x.string()]).optional().describe("A PageSpec object (or its JSON text)."),page:x.string().optional().describe("Repo mode only: a page name (apps/pages/src/pages/<Page>.tsx) or a .tsx path inside the repo."),source:x.string().max(1048576).optional().describe("Repo mode only: TSX source text of a page."),all:x.boolean().optional().describe("List every checked field, not only the ones outside a limit."),json:F})},(e,s)=>{if([e.spec!==void 0,e.page!==void 0,e.source!==void 0].filter(Boolean).length!==1)return oe('clay_check_copy needs exactly one of "spec" (a PageSpec), "page" or "source" (repo mode).');let o,r="";if(e.spec!==void 0){let a=Ws(e.spec);o=s.kb.checkCopy({spec:a}).data;let l=[...new Set((a.sections??[]).map(c=>String(c?.type??"")).filter(c=>!c||!(s.reg.resolve(`section.${it[c]??c}`)||s.reg.resolve(`component.${c}`))))];l.length&&(r=`
154
+ Not checked: section type${l.length>1?"s":""} ${l.map(c=>`"${c||"(none)"}"`).join(", ")} unknown to Clay \u2014 run clay_validate_page.
155
+ `)}else{if(!n.root||!n.checkCopyTsx)return oe(Hn(e.page!==void 0?"page":"source","`spec` (a PageSpec) inline"));let{text:a,label:l}=e.page!==void 0?Ln(n.root,e.page):{text:e.source,label:"source"};o=n.checkCopyTsx({file:l,text:a,kb:{fingerprint:s.fingerprint,units:s.units}})}return{text:Oe(o,{all:e.all,compact:!e.all})+r,data:o}}),K(t,n,"clay_validate_page",{title:"Validate a PageSpec",description:"Check a PageSpec before rendering it: the schema, unknown section types (with the nearest names), each section's props, the layout-to-content coupling, what the renderer would normalize, and Hard Rule C6 (no two muted sections back to back). Every finding has a JSON path and a rule id.",hint:"validate fewer sections.",schema:x.strictObject({spec:x.union([x.record(x.string(),x.unknown()),x.string()]).describe("The PageSpec: { brand?, nav?, sections: [{ type, props }] } as an object or JSON text."),detail:ee("Add the normalized spec."),json:F})},e=>{let s=Bn(e.spec);return{text:Fn(s,{detail:e.detail}),data:{...s,...e.detail?{}:{normalized:void 0}}}}),K(t,n,"clay_components_using_token",{title:"Components using a token",description:"Which components and layouts use a design token: `id \u2014 summary`. Takes a token id, an alias or a CSS variable (--clay-web-type-family, var(--clay-web-type-family)).",hint:"none.",schema:x.strictObject({token:x.string().min(1).describe("A token id (token.clay-web-type-family), alias (token:--clay-web-type-family) or CSS variable (--clay-web-type-family)."),detail:ee("Add each component's links."),json:F})},(e,s)=>{let i=Je(s,e.token);if(!i)return ke(s,"token",e.token,["token"]);let o=s.reg.componentsUsingToken(i);if(!o.length)return{text:`No component or layout uses \`${i}\`.
156
+ `,data:{token:i,components:[]}};let r=o.slice(0,100);return{text:`${[`# \`${i}\` \xB7 used by ${o.length}`,...r.map(l=>e.detail&&z(l.links)?`${we(l)}
157
+ ${z(l.links)}`:we(l)),...o.length>r.length?[`\u2026 ${o.length-r.length} more (clay_related id=${i} type=uses-token direction=in offset=100).`]:[]].join(`
158
+ `)}
159
+ `,data:{token:i,total:o.length,components:r}}})}var nr=["clay_search","clay_get","clay_list","clay_related","clay_asset_url","clay_render","clay_section","clay_route","clay_rules","clay_check_copy","clay_validate_page","clay_components_using_token"];import{McpServer as Ys}from"@modelcontextprotocol/sdk/server/mcp.js";import{statSync as Vs}from"node:fs";var Wn=1,Gn=t=>{let n=Vs(t);return`${n.ino}:${n.mtimeMs}`};function xe(t,n,e){let s;try{s=t(n)}catch(i){throw new Error(`cannot open the registry database ${n}: ${i.message}`)}try{let i=s.meta("schema_version")??"",o=Number.parseInt(i.split(".")[0]??"",10);if(!Number.isFinite(o))throw new Error(`${n} is not a Clay registry database (no meta.schema_version)`);if(o>Wn)throw new Error(`${n} has registry schema ${i}, newer than this server supports (${Wn}.x): upgrade @clay-design-system/mcp`);let r=s.meta("content_digest")??"",a=s.meta("kb_fingerprint")??r,l=s.allUnits(),c=Cn({units:l,fingerprint:a,index:s,resolve:u=>s.resolve(u)});return{reg:s,kb:c,units:l,fingerprint:a,info:{version:e,schema:i,digest:r},stamp:Gn(n)}}catch(i){try{s.close()}catch{}throw i}}var Xe=class{constructor(n){this.opts=n;this.engine=xe(n.open,n.db,n.version)}engine;get current(){return this.engine}async get(){if(this.opts.beforeCall&&await this.opts.beforeCall(),this.opts.watch){let n;try{n=Gn(this.opts.db)}catch{return this.engine}if(n!==this.engine.stamp){let e=xe(this.opts.open,this.opts.db,this.opts.version),s=this.engine;this.engine=e,setTimeout(()=>{try{s.reg.close()}catch{}},1e4).unref()}}return this.engine}close(){try{this.engine.reg.close()}catch{}}};function Js(t){let n=[`Clay: monday.com's marketing design system, registry ${t.version} (schema ${t.schema}). Read-only.`,"Pages compose sections and components exported by @clay-design-system/react (never hand-coded sections); tokens are CSS custom properties, numeric ones unitless: calc(var(--clay-size-16) * 1px).","Page build: clay_route per stage; clay_section for props, item shapes, copy limits and layouts; clay_rules for the Hard Rules; clay_search, then clay_get for anything else.","Batch: clay_section takes names[] + layouts[], clay_get up to 25 ids, clay_search each[], clay_asset_url ids[].","Before rendering a PageSpec: clay_validate_page, then clay_check_copy. Ids accept aliases (web-pmm, section:FeaturesSection, --clay-*). json:true returns JSON."].join(" ");return n.length<=1e3?n:`${n.slice(0,999)}\u2026`}function At(t,n,e={}){let s=new Ys({name:"clay",version:n.version},{instructions:Js(n)});return zn(s,{getEngine:t,root:e.root,checkCopyTsx:e.checkCopyTsx}),s}function dr(t){let n=new Xe({open:t.open,db:t.db,version:t.version,watch:t.watch,beforeCall:t.beforeCall}),e=At(()=>n.get(),n.current.info,{root:t.root,checkCopyTsx:t.checkCopyTsx});return Object.defineProperty(e,"registryInfo",{get:()=>n.current.info}),e.closeRegistry=()=>n.close(),e}import{spawnSync as Vn}from"node:child_process";import{copyFileSync as Xs,existsSync as Yn,mkdirSync as Jn,mkdtempSync as Zs,readdirSync as Xn,rmSync as Qs}from"node:fs";import{tmpdir as eo}from"node:os";import{join as re,resolve as to}from"node:path";var no=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/,Ze=t=>no.test(t);function Et(t,n){if(!Ze(n))throw new Error(`"${n}" is not a semver version (x.y.z)`);return re(to(t),n,"clay.sqlite")}function ve(t){if(!t||!Yn(t))return[];let n=(e,s)=>{let i=e.split(/[.-]/).slice(0,3).map(Number),o=s.split(/[.-]/).slice(0,3).map(Number);for(let r=0;r<3;r++)if(i[r]!==o[r])return o[r]-i[r];return e<s?1:-1};return Xn(t,{withFileTypes:!0}).filter(e=>e.isDirectory()&&Ze(e.name)&&Yn(re(t,e.name,"clay.sqlite"))).map(e=>e.name).sort(n)}function hr(t,n){let e=Et(n,t),s=Zs(re(eo(),"clay-mcp-fetch-"));try{let i=Vn("npm",["pack",`@clay-design-system/registry@${t}`,"--pack-destination",s,"--silent"],{cwd:s,encoding:"utf8"});if(i.status!==0)throw new Error(`npm pack @clay-design-system/registry@${t} failed: ${(i.stderr||i.stdout).trim().split(`
160
+ `).slice(-1)[0]}`);let o=Xn(s).find(l=>l.endsWith(".tgz"));if(!o)throw new Error("npm pack produced no tarball");let r=re(s,"x");Jn(r);let a=Vn("tar",["-xzf",re(s,o),"-C",r,"package/data/clay.sqlite"],{encoding:"utf8"});if(a.status!==0)throw new Error(`could not extract data/clay.sqlite from ${o}: ${a.stderr.trim()}`);return Jn(re(e,".."),{recursive:!0}),Xs(re(r,"package/data/clay.sqlite"),e),e}finally{Qs(s,{recursive:!0,force:!0})}}import{createServer as io}from"node:http";import{existsSync as so}from"node:fs";import{StreamableHTTPServerTransport as oo}from"@modelcontextprotocol/sdk/server/streamableHttp.js";var ro=1048576,Zn=new Set(["127.0.0.1","localhost","[::1]","::1"]),jt=t=>{let n=t.trim().toLowerCase();return n.startsWith("[")?n.slice(0,n.indexOf("]")+1):n.split(":")[0]};function H(t,n,e,s={}){let i=JSON.stringify(e);t.writeHead(n,{"content-type":"application/json","content-length":Buffer.byteLength(i),...s}),t.end(i)}var Lt=(t,n,e,s,i)=>H(t,n,{jsonrpc:"2.0",error:{code:e,message:s},id:null},i);async function ao(t){let n=[],e=0;for await(let s of t){if(e+=s.length,e>ro)throw Object.assign(new Error("request body larger than 1 MB"),{status:413});n.push(s)}try{return JSON.parse(Buffer.concat(n).toString("utf8"))}catch{throw Object.assign(new Error("request body is not JSON"),{status:400})}}async function vr(t){let n=["root","beforeCall","checkCopyTsx"].filter(m=>t[m]!==void 0);if(n.length)throw new Error(`startHttp: ${n.join(", ")} are repo-mode options and are not accepted over HTTP`);let e=t.host??"127.0.0.1",s=Zn.has(e.toLowerCase()),i=(t.allowedHosts??[]).map(m=>jt(m));if(!s&&!i.length)throw new Error(`startHttp: binding ${e} (not loopback) needs allowedHosts, e.g. ["clay.example.com"]`);let o=new Set([...Zn,...i]),r=Math.max(1,t.maxEngines??3),a,l;try{a=xe(t.open,t.db,t.version)}catch(m){l=m.message}let c=new Map,u=m=>{let $=c.get(m);if($)return c.delete(m),c.set(m,$),$;if(!t.versionsDir)return null;let S=Et(t.versionsDir,m);if(!so(S))return null;let y=xe(t.open,S,m);for(c.set(m,y);c.size>r;){let v=c.keys().next().value,A=c.get(v);c.delete(v),setTimeout(()=>{try{A?.reg.close()}catch{}},1e4).unref()}return y},p=async(m,$)=>{let S=m.headers.host;if(!S||!o.has(jt(S)))return H($,403,{error:"Host not allowed"});let y=m.headers.origin;if(y!==void 0){let j=!1;try{j=o.has(jt(new URL(y).host))}catch{j=!1}if(!j)return H($,403,{error:"Origin not allowed"})}let A=new URL(m.url??"/","http://x").pathname;if(A==="/healthz"&&m.method==="GET"){let j=ve(t.versionsDir);return a?H($,200,{ok:!0,registry:a.info,versions:j}):H($,503,{ok:!1,error:l??"registry database unavailable",versions:j})}if(A==="/versions"&&m.method==="GET")return H($,200,{latest:a?.info??null,available:ve(t.versionsDir)});let b=/^(?:\/v\/([^/]+))?\/mcp$/.exec(A);if(!b)return H($,404,{error:"not found",routes:["POST /mcp","POST /v/<semver>/mcp","GET /healthz","GET /versions"]});if(m.method!=="POST")return Lt($,405,-32e3,"Method not allowed: this server is stateless, POST only.",{allow:"POST"});let C,k=b[1];if(k!==void 0){if(!Ze(k))return H($,404,{error:`"${k}" is not a version`,available:ve(t.versionsDir)});try{C=u(k)}catch(j){return H($,503,{error:`version ${k} cannot be served: ${j.message}`})}if(!C)return H($,404,{error:`version ${k} is not available`,available:ve(t.versionsDir)})}else if(C=a,!C)return H($,503,{error:l??"registry database unavailable"});let R;try{R=await ao(m)}catch(j){return Lt($,j.status??400,-32700,j.message)}let E=C,O=At(async()=>E,E.info),I=new oo({sessionIdGenerator:void 0,enableJsonResponse:!0});$.on("close",()=>{I.close(),O.close()}),await O.connect(I),await I.handleRequest(m,$,R)},f=io((m,$)=>{p(m,$).catch(S=>{$.headersSent?$.end():Lt($,500,-32603,`internal error: ${S.message}`)})});f.requestTimeout=3e4,f.headersTimeout=1e4,f.keepAliveTimeout=5e3,await new Promise((m,$)=>{f.once("error",$),f.listen(t.port??3920,e,()=>m())});let g=f.address().port;return{server:f,port:g,host:e,url:`http://${e.includes(":")?`[${e}]`:e}:${g}`,close:()=>new Promise(m=>{f.close(()=>{for(let $ of[a,...c.values()])try{$?.reg.close()}catch{}m()}),f.closeAllConnections()})}}export{nr as a,Js as b,dr as c,Ze as d,Et as e,ve as f,hr as g,vr as h};
@@ -0,0 +1,168 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { Registry } from '@clay-design-system/registry';
3
+ import type { Server } from 'node:http';
4
+
5
+ /** The versions present in `dir` (a semver-named folder holding a `clay.sqlite`), newest first. */
6
+ export declare function availableVersions(dir: string | undefined): string[];
7
+
8
+ /** Repo mode only: checks the copy of a TSX page (needs `typescript`, so it is injected, never bundled). */
9
+ declare type CheckCopyTsx = (input: {
10
+ file: string;
11
+ text: string;
12
+ kb: {
13
+ fingerprint: string;
14
+ units: ClayKbUnit[];
15
+ };
16
+ }) => CopyReport;
17
+
18
+ declare const CLAY_MODES: readonly ["A", "B"];
19
+
20
+ declare const CLAY_STAGES: readonly ["structure", "mapping", "design", "assets", "copy", "page-file", "ux", "qa", "static", "fidelity"];
21
+
22
+ declare interface ClayKbUnit {
23
+ id: string;
24
+ kind: string;
25
+ scope: 'web' | 'email' | 'ds' | 'shared';
26
+ topic: string;
27
+ authority: 'canonical' | 'derived' | 'guidance' | 'background';
28
+ stages: ClayStage[];
29
+ modes?: ClayMode[];
30
+ entities: string[];
31
+ summary: string;
32
+ body: string;
33
+ when?: string;
34
+ notWhen?: string;
35
+ severity?: 'Critical' | 'Major' | 'Minor';
36
+ enforcement?: ('lint' | 'script' | 'test' | 'qa' | 'review' | 'types')[];
37
+ relations?: ClayKbUnitRelations;
38
+ source?: {
39
+ path: string;
40
+ anchor?: string;
41
+ generatedBy?: string;
42
+ };
43
+ status: 'active' | 'deprecated';
44
+ verifiedAt?: string;
45
+ handbookId?: string;
46
+ data?: unknown;
47
+ facts?: unknown;
48
+ }
49
+
50
+ declare interface ClayKbUnitRelations {
51
+ supersedes?: string[];
52
+ conflictsWith?: string[];
53
+ seeAlso?: string[];
54
+ precedence?: string[];
55
+ }
56
+
57
+ export declare interface ClayMcpServer extends McpServer {
58
+ /** Closes the registry handle. */
59
+ closeRegistry(): void;
60
+ readonly registryInfo: RegistryInfo;
61
+ }
62
+
63
+ declare type ClayMode = (typeof CLAY_MODES)[number];
64
+
65
+ declare type ClayStage = (typeof CLAY_STAGES)[number];
66
+
67
+ declare interface CopyFinding {
68
+ /** 1-based source line (TSX front); 0 for a PageSpec field, which has a `path`. */
69
+ line: number;
70
+ /** JSON path of a PageSpec field, e.g. `sections[2].props.items[0].title`. */
71
+ path?: string;
72
+ component: string;
73
+ field: string;
74
+ limitId: string;
75
+ value: string;
76
+ chars: number;
77
+ words: number;
78
+ sentences: number;
79
+ status: 'over' | 'under' | 'ok';
80
+ /** What broke: `chars 120 > 84`, `words 5 > 3`. */
81
+ detail: string;
82
+ hard: boolean;
83
+ severity: 'Critical' | 'Warning';
84
+ }
85
+
86
+ declare interface CopyReport {
87
+ file: string;
88
+ checked: number;
89
+ skipped: number;
90
+ findings: CopyFinding[];
91
+ }
92
+
93
+ /** Throws (one line) when the database is missing, unreadable, or its schema major is newer than this server understands. */
94
+ export declare function createClayMcpServer(opts: CreateClayMcpServerOptions): ClayMcpServer;
95
+
96
+ export declare interface CreateClayMcpServerOptions {
97
+ /** Opens a registry database read-only: `(path) => new Registry(path)`. */
98
+ open: (path: string) => RegistryLike;
99
+ /** The database file. */
100
+ db: string;
101
+ /** The registry package version this database belongs to (shown in `instructions`, `json` answers and `/healthz`). */
102
+ version: string;
103
+ /** Repo root. Present = repo mode: enables `briefPath`, `page` and `source`, confined to this directory. */
104
+ root?: string;
105
+ /** Re-check the database file before each call and reopen it when it was replaced (repo mode). */
106
+ watch?: boolean;
107
+ /** Runs before each call (repo mode: `ensureRegistry`). */
108
+ beforeCall?: () => Promise<void> | void;
109
+ /** Repo mode: checks the copy of TSX text. Needs `typescript`, so it is injected. */
110
+ checkCopyTsx?: CheckCopyTsx;
111
+ }
112
+
113
+ export declare interface HttpHandle {
114
+ server: Server;
115
+ port: number;
116
+ host: string;
117
+ url: string;
118
+ close(): Promise<void>;
119
+ }
120
+
121
+ /**
122
+ * Server `instructions`: what an agent needs before its first call — the happy path, how to batch, and the few orientation
123
+ * facts every Clay page depends on (the MCP's equivalent of the repo's CLAUDE.md "Start here"). At most 1,000 characters.
124
+ */
125
+ export declare function instructionsFor(info: RegistryInfo): string;
126
+
127
+ export declare const isSemver: (v: string) => boolean;
128
+
129
+ /** Which database a server answers from: the package version, the schema version and the content digest (`meta`). */
130
+ export declare interface RegistryInfo {
131
+ version: string;
132
+ schema: string;
133
+ digest: string;
134
+ }
135
+
136
+ /** What the server needs from a registry handle: the package's `Registry` class, or the repo's identical `kb/registry/query` one. */
137
+ export declare type RegistryLike = Pick<Registry, 'path' | 'close' | 'meta' | 'resolve' | 'allUnits' | 'get' | 'search' | 'searchHits' | 'list' | 'related' | 'assetUrl' | 'assetVariants' | 'componentsUsingToken' | 'allowedChildren' | 'pageRecipe' | 'db'>;
138
+
139
+ export declare function startHttp(opts: StartHttpOptions): Promise<HttpHandle>;
140
+
141
+ export declare interface StartHttpOptions {
142
+ /** Opens a registry database read-only: `(path) => new Registry(path)`. */
143
+ open: (path: string) => RegistryLike;
144
+ /** The latest database (`POST /mcp`). */
145
+ db: string;
146
+ /** Its package version. */
147
+ version: string;
148
+ /** Pinned versions: `<versionsDir>/<semver>/clay.sqlite`. Without it only `/mcp` is served. */
149
+ versionsDir?: string;
150
+ /** Default 3920; 0 picks a free port. */
151
+ port?: number;
152
+ /** Default 127.0.0.1. A non-loopback address needs `allowedHosts`. */
153
+ host?: string;
154
+ /** Host header names (no port) accepted besides the loopback ones, e.g. `["clay.example.com"]`. */
155
+ allowedHosts?: string[];
156
+ /** How many pinned engines stay open (default 3). */
157
+ maxEngines?: number;
158
+ root?: never;
159
+ beforeCall?: never;
160
+ checkCopyTsx?: never;
161
+ }
162
+
163
+ export declare const TOOL_NAMES: readonly ["clay_search", "clay_get", "clay_list", "clay_related", "clay_asset_url", "clay_render", "clay_section", "clay_route", "clay_rules", "clay_check_copy", "clay_validate_page", "clay_components_using_token"];
164
+
165
+ /** `<dir>/<version>/clay.sqlite`; throws for anything that is not a strict semver (no path segment can come from user text). */
166
+ export declare function versionDbPath(versionsDir: string, version: string): string;
167
+
168
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{a as r,b as e,c as t,d as o,e as p,f as a,h as s}from"./chunk-4UBF3MA3.js";export{r as TOOL_NAMES,a as availableVersions,t as createClayMcpServer,e as instructionsFor,o as isSemver,s as startHttp,p as versionDbPath};
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@clay-design-system/mcp",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.16.0",
4
+ "description": "The Clay MCP server: monday.com's marketing design system as 12 read-only tools over the Clay Registry (stdio and Streamable HTTP).",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ },
12
+ "./package.json": "./package.json"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "bin": {
17
+ "clay-mcp": "./dist/bin.js"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "engines": {
24
+ "node": ">=22.13"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.32.1",
31
+ "zod": "^4.4.3",
32
+ "@clay-design-system/registry": "0.16.0"
33
+ },
34
+ "devDependencies": {
35
+ "@microsoft/api-extractor": "^7.52.0",
36
+ "@types/node": "^22.0.0",
37
+ "esbuild": "^0.25.0",
38
+ "tsx": "^4.0.0",
39
+ "typescript": "^5.7.0",
40
+ "vitest": "^2.1.0"
41
+ },
42
+ "scripts": {
43
+ "build": "tsx scripts/build.ts",
44
+ "test": "vitest run",
45
+ "typecheck": "tsc --noEmit"
46
+ }
6
47
  }