1import{t as b,a as g,c as Y}from"../chunks/disclose-version.DE-liGRC.js";import{s as a,c as t,r as e,n as M,t as $,g as s,f as L,p as pe,a as ve,h as le,e as me,d as de}from"../chunks/runtime.vEvs2zhv.js";import{M as ge}from"../chunks/MetaTags.BewDlfzo.js";import"../chunks/legacy.B3rupc9m.js";import{A as ue}from"../chunks/arrow-right.BrcQa09R.js";import{s as u,l as F,a as E,d as he,i as J,p as ye}from"../chunks/props.CdrK0jyI.js";import{e as A,I as R,d as U,s as Q,a as B}from"../chunks/Icon.VaO0A4Wf.js";import{C as ce}from"../chunks/CodeBlock.CzBzBA-N.js";import{G as be}from"../chunks/git-branch.BTIm3pg5.js";import{C as we}from"../chunks/copy.BcV599FY.js";var _e=b(`<div class="overflow-hidden rounded-2xl border shadow-2xl" style="background: var(--e-bg); border-color: var(--e-line); color: var(--e-fg); 2 --e-bg:#16180f; --e-line:#2a2e1f; --e-fg:#d7d6c8; --e-dim:#8a8d78; --e-faint:#62654f; --e-panel:#14160e;"><div class="flex items-center gap-2 border-b px-4 py-2.5" style="border-color: var(--e-line); background: var(--e-panel)"><span class="size-2.5 rounded-full bg-[#e06c5b]"></span> <span class="size-2.5 rounded-full bg-[#d9a441]"></span> <span class="size-2.5 rounded-full bg-[#7fb84a]"></span> <span class="ml-2.5 font-mono text-xs" style="color: var(--e-dim)"><b class="font-semibold" style="color: var(--e-fg)">product-docs</b> · main</span> <span class="ml-auto rounded-md bg-lime-500 px-3 py-1 text-[11.5px] font-semibold text-lime-950">Save</span></div> <div class="grid min-h-[26rem] grid-cols-1 min-[900px]:grid-cols-[212px_minmax(0,1fr)_286px]"><div class="hidden border-r py-3 font-mono text-[12.5px] min-[900px]:block" style="border-color: var(--e-line); color: var(--e-dim)"><div class="px-4 py-1 text-[10.5px] uppercase tracking-wider" style="color: var(--e-faint)">Project</div> <div class="flex items-center gap-1.5 px-4 py-1"><span style="color: var(--e-faint)">â</span> .vale.ini</div> <div class="px-4 py-1 text-[10.5px] uppercase tracking-wider" style="color: var(--e-faint)">Styles / House</div> <div class="flex items-center gap-1.5 py-1 pl-7 pr-4 text-lime-50" style="background: rgb(98 165 39 / 0.14); box-shadow: inset 2px 0 0 #62a527"><span class="text-lime-600 dark:text-lime-400">â¸</span> Passive.yml</div> <div class="flex items-center gap-1.5 py-1 pl-7 pr-4"><span style="color: var(--e-faint)">â¸</span> Terms.yml</div> <div class="flex items-center gap-1.5 py-1 pl-7 pr-4"><span style="color: var(--e-faint)">â¸</span> Headings.yml <span class="ml-auto text-[11px]" style="color: var(--e-faint)">+11</span></div> <div class="px-4 py-1 text-[10.5px] uppercase tracking-wider" style="color: var(--e-faint)">Assets</div> <div class="flex items-center gap-1.5 px-4 py-1"><span style="color: var(--e-faint)">â¤</span> Vocab / Base</div> <div class="flex items-center gap-1.5 px-4 py-1"><span style="color: var(--e-faint)">â¤</span> en_US.dic · .aff</div> <div class="flex items-center gap-1.5 px-4 py-1"><span style="color: var(--e-faint)">â¤</span> Filters · Views</div></div> <div class="flex min-w-0 flex-col border-r" style="border-color: var(--e-line)"><div class="flex h-10 items-center border-b px-3" style="border-color: var(--e-line)"><div class="flex h-full items-center border-b-2 border-lime-500 px-3 font-mono text-xs" style="color: var(--e-fg)">Passive.yml</div> <div class="ml-auto flex overflow-hidden rounded-md border text-[11px]" style="border-color: var(--e-line)"><span class="bg-lime-500/20 px-2.5 py-1" style="color: var(--e-fg)">Form</span> <span class="px-2.5 py-1" style="color: var(--e-dim)">Raw</span></div></div> <div class="flex-1 overflow-x-auto px-4 py-3.5 font-mono text-[13px] leading-[1.8]"><div class="whitespace-pre"><span style="color: var(--e-faint)">1</span><span class="ml-4 italic" style="color:#6c7059"># "be" + optional adverb + past participle.</span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">2</span><span class="ml-4 text-lime-400">extends</span>: <span style="color:#e3b168">sequence</span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">3</span><span class="ml-4 text-lime-400">message</span>: <span style="color:#e3b168">"'%s' looks like passive voice."</span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">4</span><span class="ml-4 text-lime-400">level</span>: <span style="color:#e3b168">warning</span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">5</span><span class="ml-4 text-lime-400">tokens</span>:</div> <div class="whitespace-pre"><span style="color: var(--e-faint)">6</span><span class="ml-4"> - <span class="text-lime-400">pattern</span>: <span style="color:#c9a6f2">
2'(?:is|are|was|were|been)'</span></span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">7</span><span class="ml-4"> - <span class="text-lime-400">tag</span>: <span style="color:#e3b168">RB</span></span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">8</span><span class="ml-4"> <span class="text-lime-400">optional</span>: <span style="color:#7cc7f2">true</span></span></div> <div class="whitespace-pre"><span style="color: var(--e-faint)">9</span><span class="ml-4"> - <span class="text-lime-400">tag</span>: <span style="color:#e3b168">VBN</span></span></div></div> <div class="flex flex-wrap items-baseline gap-x-2.5 gap-y-1 border-t px-4 py-2.5 font-mono text-[11.5px]" style="border-color: var(--e-line); background: var(--e-panel); color: var(--e-dim)"><span class="text-lime-600 dark:text-lime-400">compiled</span> <span style="color:#c9a6f2">(?:is|are|was|were|been)</span> <span style="color: var(--e-faint)">â</span> <span style="color:#e3b168">RB?</span> <span style="color: var(--e-faint)">â</span> <span style="color:#e3b168">VBN</span> <span style="color:#6c7059">â exactly what the engine runs</span></div></div> <div class="hidden min-w-0 flex-col gap-3 p-4 min-[900px]:flex"><div class="text-[11px] font-semibold uppercase tracking-wider" style="color: var(--e-faint)">Test · release-notes.md</div> <div class="text-[15px] leading-[1.8]" style="color: var(--e-fg)">The schema <span class="underline decoration-[#e0a63c] decoration-wavy decoration-2 underline-offset-4">was carefully reviewed</span> by legal. Older keys <span class="underline decoration-[#e0a63c] decoration-wavy decoration-2 underline-offset-4">were deprecated</span> last week. Please <span class="underline decoration-[#6ea0ff] decoration-wavy decoration-2 underline-offset-4">utilise</span> the new endpoint.</div> <div class="flex flex-col gap-2 border-t pt-3" style="border-color: var(--e-line)"><div class="flex items-start gap-2"><span class="mt-px shrink-0 rounded bg-[#e0a63c]/15 px-1.5 py-0.5 text-[9.5px] font-bold uppercase tracking-wide text-[#e0a63c]">warning</span> <span class="text-[12.5px] leading-tight" style="color: var(--e-fg)">'was carefully reviewed' looks like passive voice. <span class="font-mono text-[11px]" style="color: var(--e-faint)">House.Passive</span></span></div> <div class="flex items-start gap-2"><span class="mt-px shrink-0 rounded bg-[#e0a63c]/15 px-1.5 py-0.5 text-[9.5px] font-bold uppercase tracking-wide text-[#e0a63c]">warning</span> <span class="text-[12.5px] leading-tight" style="color: var(--e-fg)">'were deprecated' looks like passive voice. <span class="font-mono text-[11px]" style="color: var(--e-faint)">House.Passive</span></span></div> <div class="flex items-start gap-2"><span class="mt-px shrink-0 rounded bg-[#6ea0ff]/15 px-1.5 py-0.5 text-[9.5px] font-bold uppercase tracking-wide text-[#6ea0ff]">suggestion</span> <span class="text-[12.5px] leading-tight" style="color: var(--e-fg)">Prefer 'use'. <span class="font-mono text-[11px]" style="color: var(--e-faint)">House.Terms</span></span></div></div> <p class="mt-auto text-[11.5px] leading-snug" style="color: var(--e-faint)">The optional <span class="font-mono">RB</span> is why the first match includes <span class="font-mono">carefully</span>.</p></div></div> <div class="flex items-center gap-4 border-t px-4 py-2 font-mono text-[11px]" style="border-color: var(--e-line); background: var(--e-panel); color: var(--e-dim)"><span class="text-lime-600 dark:text-lime-400">â engine ready</span> <span>16 assets</span> <span>3 alerts</span> <span class="ml-auto">saved · main</span></div></div>`);function ke(f){var r=_e();g(f,r)}var $e=b(`<section class="relative overflow-hidden border-b border-border/60"><div class="pointer-events-none absolute inset-0 -z-10 [background-image:radial-gradient(hsl(var(--foreground)/0.06)_1px,transparent_1px)] [background-size:22px_22px] [mask-image:radial-gradient(ellipse_65%_55%_at_50%_0%,#000_55%,transparent_100%)]"></div> <div class="mx-auto max-w-6xl px-6 pb-16 pt-16 sm:pb-20 sm:pt-24 lg:px-8"><div class="mx-auto max-w-3xl text-center"><span class="inline-flex items-center gap-2 rounded-full border border-border bg-muted/40 px-3 py-1 text-sm text-muted-foreground"><span class="inline-flex h-1.5 w-1.5 rounded-full bg-lime-500"></span> A Vale Labs project</span> <h1 class="mt-6 text-balance text-4xl font-semibold tracking-tight sm:text-6xl">A style guide that doesn't compile is <span class="text-lime-600 dar
2k:text-lime-400">just a document.</span></h1> <p class="mx-auto mt-6 max-w-2xl text-pretty text-lg leading-8 text-muted-foreground">Vale CMS is the hosted editor for your whole Vale project â and a hosted MCP server that 3 hands the same engine to your AI assistant. Rules get checked as they are written, by you or 4 by it, so one that silently never fires can't reach your repo.</p> <div class="mt-9 flex flex-col items-center justify-center gap-3 sm:flex-row"><a href="https://cms.vale.sh" class="group inline-flex h-11 items-center justify-center gap-1.5 rounded-lg bg-primary px-6 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90">Open the editor <!></a> <a href="#surfaces" class="inline-flex h-11 items-center justify-center gap-2 rounded-lg border border-border bg-background px-6 text-sm font-medium text-foreground transition-colors hover:bg-muted/60">See how it works</a></div> <p class="mt-5 text-sm text-muted-foreground">Vale itself stays free, open source, and MIT licensed. <span class="text-foreground">Vale CMS is the authoring layer on top.</span></p></div> <div class="mt-14 sm:mt-16"><!> <p class="mx-auto mt-4 max-w-2xl text-center text-sm text-muted-foreground">A sequence rule matching a "be" verb, an optional adverb, and a past participle â with the 5 token sequence the engine resolved it to, and the alerts it produces, live.</p></div></div></section>`);function Ce(f){var r=$e(),o=a(t(r),2),p=t(o),c=a(t(p),6),i=t(c),l=a(t(i));ue(l,{class:"h-4 w-4 transition-transform group-hover:translate-x-0.5"}),e(i),M(2),e(c),M(2),e(p);var d=a(p,2),m=t(d);ke(m),M(2),e(d),e(o),e(r),g(f,r)}var Te=b('<div class="rounded-xl border border-border/60 bg-background px-4 py-3.5 text-center"><div class="text-sm font-semibold"> </div> <div class="mt-0.5 font-mono text-[11.5px] text-muted-foreground"> </div></div>'),Se=b(`<div class="rounded-2xl border border-border/60 bg-card p-6 sm:p-8"><div class="flex flex-col items-stretch gap-0"><div class="grid gap-4 sm:grid-cols-2"></div> <div class="hidden sm:block" aria-hidden="true"><div class="grid h-8 grid-cols-2"><div class="border-r-2 border-lime-500/50"></div> <div class="border-l-2 border-lime-500/50"></div></div> <div class="-mt-8 flex h-8 items-end justify-center"><div class="h-4 w-px bg-lime-500/50"></div></div></div> <div class="flex h-6 justify-center sm:hidden" aria-hidden="true"><div class="w-px bg-lime-500/50"></div></div> <div class="rounded-xl border-2 border-lime-500 bg-lime-500/5 px-4 py-4 text-center"><div class="text-sm font-semibold">Vale's engine</div> <div class="mt-1 flex flex-wrap justify-center gap-x-3 gap-y-1 font-mono text-[11px] text-muted-foreground"><span>12 check types</span> <span>regex compilation</span> <span>POS tagging</span> <span>scopes</span></div></div> <div class="flex h-7 justify-center" aria-hidden="true"><div class="w-px bg-border"></div></div> <div class="rounded-xl border border-border/60 bg-background px-4 py-3.5 text-center"><div class="text-sm font-semibold">Your repository</div> <div class="mt-0.5 font-mono text-[11.5px] text-muted-foreground">ordinary files · the free CLI reads them in CI</div></div></div> <p class="mt-6 text-pretty text-center text-sm leading-6 text-muted-foreground">Nothing about a rule depends on which way in you took. A rule the assistant proves compiles is 6 the same rule the editor lints with, in the same file your CI already reads.</p></div>`);function Me(f){const r=[{label:"You",via:"the hosted editor"},{label:"Your assistant",via:"the MCP server"}];var o=Se(),p=t(o),c=t(p);A(c,5,()=>r,i=>i.label,(i,l)=>{var d=Te(),m=t(d),h=t(m,!0);e(m);var v=a(m,2),n=t(v,!0);e(v),e(d),$(()=>{u(h,s(l).label),u(n,s(l).via)}),g(i,d)}),e(c),M(10),e(p),M(2),e(o),g(f,o)}function Ae(f,r){const o=F(r,["children","$$slots","$$events","$$legacy"]);R(f,E({name:"monitor-smartphone"},()=>o,{iconNode:[["path",{d:"M18 8V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h8"}],["path",{d:"M10 19v-3.96 3.15"}],["path",{d:"M7 19h5"}],["rect",{width:"6",height:"10",x:"16",y:"12",rx:"2"}]],children:(c,i)=>{var l=Y(),d=L(l);U(d,r,"default",{}),g(c,l)},$$slots:{default:!0}}
6))}function Ve(f,r){const o=F(r,["children","$$slots","$$events","$$legacy"]);R(f,E({name:"bot"},()=>o,{iconNode:[["path",{d:"M12 8V4H8"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2"}],["path",{d:"M2 14h2"}],["path",{d:"M20 14h2"}],["path",{d:"M15 13v2"}],["path",{d:"M9 13v2"}]],children:(c,i)=>{var l=Y(),d=L(l);U(d,r,"default",{}),g(c,l)},$$slots:{default:!0}}))}var Pe=b('<div class="group flex flex-col rounded-2xl border border-border/60 bg-card p-7 transition-colors hover:border-lime-500/50"><div class="flex items-center gap-3"><div class="inline-flex rounded-lg bg-lime-500/10 p-2 text-lime-600 dark:text-lime-400"><!></div> <span class="font-mono text-[11px] font-bold uppercase tracking-wider text-muted-foreground"> </span></div> <h3 class="mt-4 text-xl font-semibold"> </h3> <p class="mt-2.5 text-pretty text-sm leading-6 text-muted-foreground"> </p> <a class="mt-5 inline-flex items-center gap-1.5 text-sm font-semibold text-lime-600 hover:underline dark:text-lime-400"> <span aria-hidden="true" class="transition-transform group-hover:translate-x-0.5">â</span></a></div>'),He=b(`<section id="surfaces" class="scroll-mt-20 border-b border-border/60 py-14 sm:py-16"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="mx-auto max-w-2xl text-center"><p class="text-balance text-2xl font-semibold tracking-tight sm:text-3xl">One engine. Two ways to reach it.</p> <p class="mt-3 text-pretty leading-7 text-muted-foreground">Both run Vale's engine itself â the twelve check types, the same regex compilation, the same 7 scopes. Whoever writes the rule, it is a linter that decides whether it works, not a model's 8 opinion of whether it looks right.</p></div> <div class="mt-10 grid gap-5 sm:grid-cols-2"></div> <div class="mt-6"><!></div> <p class="mt-8 text-center text-sm text-muted-foreground">Both are included on every paid plan.</p></div></section>`);function Ie(f){const r=[{icon:Ae,eyebrow:"You write",title:"The hosted editor",body:"Your whole Vale project in the browser â config, rules, vocabularies, dictionaries, filters, templates. The engine lints every keystroke and refuses to ship a rule that does not compile.",href:"#assets",cta:"What you can edit"},{icon:Ve,eyebrow:"Your assistant writes",title:"The hosted MCP server",body:"The same engine, exposed as tools your assistant can call. It writes a rule, the engine tells it whether that rule compiles and what it actually matches, and it fixes its own mistake before you ever see one.",href:"#mcp",cta:"See it catch an error"}];var o=He(),p=t(o),c=a(t(p),2);A(c,5,()=>r,d=>d.title,(d,m)=>{var h=Pe(),v=t(h),n=t(v),x=t(n);s(m).icon(x,{class:"size-5"}),e(n);var y=a(n,2),_=t(y,!0);e(y),e(v);var w=a(v,2),k=t(w,!0);e(w);var S=a(w,2),T=t(S,!0);e(S);var I=a(S,2),G=t(I);M(),e(I),e(h),$(()=>{u(_,s(m).eyebrow),u(k,s(m).title),u(T,s(m).body),Q(I,"href",s(m).href),u(G,`${s(m).cta??""} `)}),g(d,h)}),e(c);var i=a(c,2),l=t(i);Me(l),e(i),M(2),e(p),e(o),g(f,o)}var je=b('<span class="rounded px-1.5 py-0.5 text-[11.5px]" style="background:#243016; color:#a8d861"> </span>'),Ne=b('<span class="rounded px-1.5 py-0.5 text-[11.5px] line-through" style="background:#33201c; color:#e08a78"> </span>'),Ge=b('<div class="border-t pt-2.5" style="border-color: var(--a-line)"><div><span style="color: var(--a-fg)"> </span><span style="color: var(--a-faint)">/</span><span style="color:#e3b168"> </span></div> <div class="mt-1.5 flex flex-wrap gap-1.5"><!> <!></div></div>'),De=b(`<div class="overflow-hidden rounded-2xl border shadow-xl" style="background: var(--a-bg); border-color: var(--a-line); color: var(--a-fg); 9 --a-bg:#16180f; --a-line:#2a2e1f; --a-fg:#d7d6c8; --a-dim:#8a8d78; --a-faint:#62654f; --a-panel:#14160e;"><div class="flex items-center gap-2 border-b px-4 py-2" style="border-color: var(--a-line); background: var(--a-panel)"><span class="font-mono text-[11px]" style="color: var(--a-dim)"><b class="font-semibold" style="color: var(--a-fg)">acme.dic</b> · affix coverage</span></div> <div class="p-4 font-mono text-[12.5px] leading-[1.7]"><div class="mb-3 flex flex-wrap gap-x-4 gap-y-1" style="color: var(--a-faint)"><span><b style="color:#e3b168">S</b> plural</span> <span><b style="color:#e3b168">D</b> past</span> <span><b style="color:#e3b168">G</b> progressive</span></div> <div class="flex flex-col gap-3"></div> <div class="mt-4 border-t pt-3 text-[11.5px]" style="border-color: var(--a-line); color: var(--a-dim)">Same three flags on all three words. <span style="color:#e08a78">Struck-through forms are never generated</span> â the affix conditions exclude them, and the spell-checker will flag every one as a misspelling.</div></div></div>`);function qe(f){const r=[{word:"deploy",flags:"SDG",got:["deploy","deploying"],missing:["deploys","deployed"]},{word:"index",flags:"SDG",got:["index","indexes","indexed","indexing"],missing:[]},{word:"verify",flags:"SDG",got:["verify","verified","verifying"],missing:["verifies"]}];var o=De(),p=a(t(o),2),c=a(t(p),2);A(c,5,()=>r,i=>i.word,(i,l)=>{var d=Ge(),m=t(d),h=t(m),v=t(h,!0);e(h);var n=a(h,2),x=t(n,!0);e(n),e(m);var y=a(m,2),_=t(y);A(_,1,()=>s(l).got,k=>k,(k,S)=>{var T=je(),I=t(T,!0);e(T),$(()=>u(I,s(S))),g(k,T)});var w=a(_,2);A(w,1,()=>s(l).missing,k=>k,(k,S)=>{var T=Ne(),I=t(T,!0);e(T),$(()=>u(I,s(S))),g(k,T)}),e(y),e(d),$(()=>{u(v,s(l).word),u(x,s(l).flags)}),g(i,d)}),e(c),M(2),e(p),e(o),g(f,o)}var Be=b('<span class="inline-flex items-baseline gap-1.5 rounded-lg border border-border/60 bg-card px-2.5 py-1.5">
9<code class="font-mono text-[11.5px] text-lime-600 dark:text-lime-400"> </code> <span class="text-xs text-muted-foreground"> </span></span>'),Le=b('<div class="flex flex-col rounded-2xl border border-border/60 bg-card p-6"><h3 class="text-balance text-base font-semibold leading-6"> </h3> <p class="mt-2.5 text-sm leading-6 text-muted-foreground"> </p> <p class="mt-4 border-t border-border/60 pt-3.5 text-sm leading-6 text-foreground/80 [text-wrap:pretty]"> </p></div>'),Oe=b('<div class="flex flex-col rounded-2xl border border-border/60 bg-card p-6"><h3 class="text-balance text-base font-semibold leading-6"> </h3> <p class="mt-2.5 text-sm leading-6 text-muted-foreground"> </p> <p class="mt-4 border-t border-border/60 pt-3.5 text-sm leading-6 text-foreground/80 [text-wrap:pretty]"> </p></div>'),ze=b(`<section id="assets" class="scroll-mt-20 border-b border-border/60 py-16 sm:py-20"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="max-w-3xl"><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">Not a rule editor</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">A text editor opens these files. It can't tell you what they do.</p> <p class="mt-5 text-pretty text-lg leading-8 text-muted-foreground">A mature Vale setup is an editorial system â rule logic, exceptions, package dependencies, 10 scopes, ignore patterns, dictionaries. Vale CMS edits every part of it, and for each one it 11 answers the question the file itself can't.</p></div> <div class="mt-9 flex flex-wrap items-center gap-2"></div> <div class="mt-10 grid items-start gap-5 lg:grid-cols-[1.05fr_0.95fr]"><div class="grid gap-5 sm:grid-cols-2 lg:grid-cols-1"></div> <!></div> <div class="mt-5 grid gap-5 md:grid-cols-2 lg:grid-cols-4"></div></div></section>`);function We(f){const r=[{tag:".vale.ini",label:"Config"},{tag:".yml",label:"Rules"},{tag:".dic · .aff",label:"Dictionaries"},{tag:"accept.txt",label:"Vocabularies"},{tag:"filters",label:"Filters"},{tag:"views",label:"Views"},{tag:".tmpl",label:"Templates"}],o=[{title:"It shows the regex the engine built",body:"A rule is not the YAML you typed â it is the pattern the engine compiles out of it, word boundaries, alternation, wrapper and all. That compiled source is on screen, highlighted, with each construct explained on hover.",why:'Most rules that "look right and never fire" are wrong in the part you never see.'},{title:"It knows which affixes apply to a word",body:"Type a word into a Hunspell dictionary and the affix classes that actually apply to it light up â conditions checked, not guessed â with a preview of the forms each flag buys. If a shorter stem already derives it, it offers that instead.",why:'deploy/D looks fine and never produces "deployed". The condition excludes it.'},{title:"It answers the reverse question too",body:"Given a word, which dictionary entry generates it â and through which affix? A reverse lookup across the whole dictionary, including imported ones large enough that nothing precomputes an index for them.",why:"The fastest way to find out why the spell-checker accepts something it should not."},{title:"It resolves the config instead of describing it",body:"Styles, per-rule toggles and format sections cascade. The visualizer shows the state each rule ends up in, per glob, after all of it â beside a grounded preview of what your ignore patterns actually swallow.",why:"The .vale.ini text cannot tell you which rules run in this file, at what level."},{title:"Filters, views and templates get live previews",body:"A filter expression evaluated against your resolved rules, showing exactly which survive. A view run over a sample, showing what each scope extracts. A template rendered against real alerts â or the error it fails with.",why:"All three are the kind of asset you otherwise write blind and debug in CI."},{title:"Rule tests are snapshots, not forms",body:"Every field of an alert is machine-made â the check, the severity, the line and column nobody can predict without running. So you run the rule and accept the alerts it produced, and the suite tells you when a later edit changes them.",why:"The edit that silently stops a rule firing is the one no one writes a test for."}];var p=ze(),c=t(p),i=a(t(c),2);A(i,5,()=>r,v=>v.tag,(v,n)=>{var x=Be(),y=t(x),_=t(y,!0);e(y);var w=a(y,2),k=t(w,!0);e(w),e(x),$(()=>{u(_,s(n).tag),u(k,s(n).label)}),g(v,x)}),e(i);var l=a(i,2),d=t(l);A(d,5,()=>o.slice(1,3),v=>v.title,(v,n)=>{var x=Le(),y=t(x),_=t(y,!0);e(y);var w=a(y,2),k=t(w,!0);e(w);var S=a(w,2),T=t(S,!0);e(S),e(x),$(()=>{u(_,s(n).title),u(k,s(n).body),u(T,s(n).why)}),g(v,x)}),e(d);var m=a(d,2);qe(m),e(l);var h=a(l,2);A(h,5,()=>[o[0],...o.slice(3)],v=>v.title,(v,n)=>{var x=Oe(),y=t(x),_=t(y,!0);e(y);var w=a(y,2),k=t(w,!0);e(w);var S=a(w,2),T=t(S,!0);e(S),e(x),$(()=>{u(_,s(n).title),u(k,s(n).body),u(T,s(n).why)}),g(v,x)}),e(h),e(c),e(p),g(f,p)}var Ye=b('<div class="border-t pt-2.5" style="border-color: var(--d-line)"><div style="color: var(--d-dim)"> <span style="color: var(--d-faint)"> </span></div> <div class="mt-0.5"> <span class="rounded px-0.5" style="background:#4a2420; color:#f0a08e"> </span> </div></div>'),Fe=b(`<div class="overflow-hidden rounded-2xl border shadow-xl" style="background: var(--d-bg); border-color: var(--d-line); color: var(--d-fg); 12 --d-bg:#16180f; --d-line:#2a2e1f; --d-fg:#d7d6c8; --d-dim:#8a8d78; --d-faint:#62654f; --d-panel:#14160e;"><div class="flex flex-wrap items-center gap-x-3 gap-y-1 border-b px-4 py-2 font-mono text-[11px]" style="border-color: var(--d-line);
12 background: var(--d-panel); color: var(--d-dim)"><span><b class="font-semibold" style="color: var(--d-fg)">Wordy.yml</b> · before â after</span> <span class="ml-auto rounded px-1.5 py-0.5" style="background:#243016; color:#a8d861">coverage: exercised</span></div> <div class="p-4 font-mono text-[12.5px] leading-[1.7]"><div style="color: var(--d-faint)">the edit</div> <div class="mt-1"><span style="color:#a8d861">+</span>nonword: <span style="color:#e3b168">true</span></div> <div class="mt-4" style="color: var(--d-faint)">what it changed</div> <div class="mt-1"><span style="color:#e08a78">+2 alerts</span> <span style="color: var(--d-dim)">· â0 · 2 of 2 files</span></div> <div class="mt-3 flex flex-col gap-2.5"></div> <div class="mt-4 border-t pt-3 text-[11.5px]" style="border-color: var(--d-line); color: var(--d-dim)">One word added to a working rule made <b style="color: var(--d-fg)">very</b> match inside <b style="color: var(--d-fg)">every</b>. Both are new false positives, in files nobody would 13 have thought to re-check.</div></div></div>`);function Ee(f){const r=[{file:"docs/guide.md",line:1,span:"23â26",text:"Be very careful with e",hit:"very",tail:"ry setting."},{file:"docs/intro.md",line:3,span:"2â5",text:"E",hit:"very",tail:" release ships on Friday."}];var o=Fe(),p=a(t(o),2),c=a(t(p),8);A(c,5,()=>r,i=>i.file,(i,l)=>{var d=Ye(),m=t(d),h=t(m,!0),v=a(h),n=t(v);e(v),e(m);var x=a(m,2),y=t(x,!0),_=a(y),w=t(_,!0);e(_);var k=a(_,1,!0);
13e(x),e(d),$(()=>{u(h,s(l).file),u(n,`:${s(l).line??""}:${s(l).span??""}`),u(y,s(l).text),u(w,s(l).hit),u(k,s(l).tail)}),g(i,d)}),e(c),M(2),e(p),e(o),g(f,o)}var Re=b('<li class="relative sm:pl-8 lg:pl-0 lg:pt-8"><span class="absolute left-0 top-1.5 hidden size-3.5 place-items-center rounded-full border-2 border-lime-500 bg-background sm:grid lg:top-0" aria-hidden="true"></span> <div class="font-mono text-xs font-bold tracking-widest text-lime-600 dark:text-lime-400"> </div> <h3 class="mt-2 text-lg font-semibold"> </h3> <p class="mt-1.5 text-sm leading-6 text-muted-foreground"> </p></li>'),Ue=b(`<section id="loop" class="scroll-mt-20 border-b border-border/60 bg-muted/30 py-16 sm:py-20"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="max-w-2xl"><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">The loop</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">Author, preview, and ship â without leaving the browser</p></div> <div class="relative mt-14"><div class="pointer-events-none absolute left-[7px] top-2 hidden h-[calc(100%-1rem)] w-px bg-gradient-to-b from-lime-500 via-lime-500/40 to-transparent sm:block lg:left-0 lg:top-[7px] lg:h-px lg:w-full lg:bg-gradient-to-r lg:from-lime-500 lg:via-lime-500/40 lg:to-transparent" aria-hidden="true"></div> <ol class="grid gap-8 sm:grid-cols-1 sm:gap-10 lg:grid-cols-4 lg:gap-8"></ol></div> <div class="mt-12 grid items-center gap-8 lg:grid-cols-[0.9fr_1.1fr] lg:gap-12"><div><h3 class="text-balance text-xl font-semibold tracking-tight sm:text-2xl">The dangerous edit is the one to a rule that already works</h3> <p class="mt-3 text-pretty leading-7 text-muted-foreground">A new rule gets read carefully. A one-word change to a rule that has been fine for a year 14 gets waved through â and it is the one that quietly starts flagging a word inside another 15 word, in files nobody re-reads.</p> <p class="mt-3 text-pretty leading-7 text-muted-foreground">Every edit is run against a corpus both ways, and you see the alerts it adds and removes 16 before it lands.</p></div> <!></div></div></section>`);function Xe(f){const r=[{n:"01",label:"Author",title:"Open your repo",body:"Connect GitHub or GitLab, or open a local folder. Your content stays the source of truth â none of it is stored on our servers."},{n:"02",label:"Preview",title:"Lint as you type",body:"The real Vale engine runs on every keystroke: each alert, its severity, and the rule that fired. The same output your CI will produce."},{n:"03",label:"Validate",title:"Prove it loads",body:"Before anything ships, the engine confirms the config parses, references resolve, and every rule compiles. No broken style guides."},{n:"04",label:"Ship",title:"Commit or open a PR",body:"Write changes straight back to your branch, or propose them as a pull request. Enforcement stays with the Vale CLI and your CI."}];var o=Ue(),p=t(o),c=a(t(p),2),i=a(t(c),2);A(i,5,()=>r,m=>m.n,(m,h)=>{var v=Re(),n=a(t(v),2),x=t(n);$(()=>u(x,`${s(h).n??""} · ${s(h).label.toUpperCase()??""}`)),e(n);var y=a(n,2),_=t(y,!0);e(y);var w=a(y,2),k=t(w,!0);e(w),e(v),$(()=>{u(_,s(h).title),u(k,s(h).body)}),g(m,v)}),e(i),e(c);var l=a(c,2),d=a(t(l),2);Ee(d),e(l),e(p),e(o),g(f,o)}var Ke=b('<span class="rounded-lg border border-border/60 bg-card px-2.5 py-1.5 font-mono text-xs text-foreground"> </span>'),Ze=b(`<section id="mcp" class="scroll-mt-20 border-b border-border/60 bg-muted/30 py-16 sm:py-20"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="max-w-3xl"><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">Your assistant, connected to the engine</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">Models already know Vale. What they can't do is check.</p> <p class="mt-5 text-pretty text-lg leading-8 text-muted-foreground">Ask any assistant for a Vale rule and it will write you plausible YAML. Whether it compiles, 17 whether the regex matches anything, whether the config still loads â it has no way to find 18 out, so you find out later, in CI. A hosted MCP server gives it the real engine to check 19 against, so a rule that doesn't work never reaches you.</p></div> <div class="mt-12 grid items-start gap-8 lg:grid-cols-[0.95fr_1.05fr] lg:gap-12"><div class="min-w-0"><div class="overflow-hidden rounded-2xl border font-mono text-[13px] leading-[1.75]" style="background:#16180f; border-color:#2a2e1f; color:#d7d6c8" aria-hidden="true"><div class="border-b px-4 py-2 text-[11px]" style="border-color:#2a2e1f; background:#14160e;
19 color:#8a8d78">vale-cms · MCP</div> <div class="overflow-x-auto p-4"><div><span class="text-lime-600 dark:text-lime-400">you</span> ⺠add a rule that flags passive 20 voice</div> <div class="mt-2"><span style="color:#7cc7f2">scaffold_rule</span> <span style="color:#8a8d78">sequence · styles/House/Passive.yml</span></div> <div class="mt-2"><span style="color:#7cc7f2">diagnose_rule</span></div> <div class="text-[#f0745a]"> â error parsing regexp: missing closing )</div> <div style="color:#6c7059"> in \`(?m)\\b(?:(?<!\\bthe )(â¦\`</div> <div style="color:#6c7059"> â³ group balanced, retrying</div> <div><span style="color:#7cc7f2">diagnose_rule</span> <span class="text-lime-400">â compiles</span></div> <div class="mt-2"><span style="color:#7cc7f2">trace_rule</span></div> <div class="text-[#f0745a]"> â did not fire, though every slot</div> <div class="text-[#f0745a]"> accepts some word here</div> <div style="color:#6c7059"> â³ "carefully" sits between them; skip: 1</div> <div><span style="color:#7cc7f2">lint_text</span> <span class="text-lime-400">â 1 alert on your sample</span></div> <div class="mt-2" style="color:#6c7059"># written to styles/House/Passive.yml</div> <div style="color:#6c7059"># enabled in .vale.ini</div></div></div> <p class="mt-4 text-sm leading-6 text-muted-foreground">Two mistakes, neither of which reached you: one the rule would not compile, one it 21 compiled and silently matched nothing. The second is the kind CI does not catch either â a 22 rule that never fires looks exactly like a rule with nothing to report.</p></div> <div class="flex flex-col gap-6"><div><h3 class="font-semibold">Works in what you already use</h3> <div class="mt-3 flex flex-wrap gap-2"></div> <p class="mt-3 text-sm leading-6 text-muted-foreground">One token, pasted into your client's config. Nothing to install and nothing to run 23 locally.</p></div> <div class="rounded-2xl border border-border/60 bg-card p-6"><h3 class="font-semibold">It is a linter, not a lookup</h3> <p class="mt-2 text-sm leading-6 text-muted-foreground">The tools your assistant calls run Vale's engine in process â not a reimplementation of 24 it, and not a search over its documentation. A rule it says compiles, compiles. A rule 25 it says fires, fires â on the text you gave it, with the severity you'll actually see.</p> <p class="mt-3 text-sm leading-6 text-muted-foreground">Included on <strong class="text-foreground">every paid plan</strong>, because one 26 developer with one client is exactly who it's for.</p></div></div></div></div></section>`);function Je(f){const r=["Claude Code","Cursor","VS Code","Claude Desktop","Claude.ai","ChatGPT"];var o=Ze(),p=t(o),c=a(t(p),2),i=a(t(c),2),l=t(i),d=a(t(l),2);A(d,5,()=>r,m=>m,(m,h)=>{var v=Ke(),n=t(v,!0);e(v),$(()=>u(n,s(h))),g(m,v)}),e(d),M(2),e(l),M(2),e(i),e(c),e(p),e(o),g(f,o)}const ne=[{name:"Author",body:"Start from something that already compiles â not a blank file and a guess at the schema.",tools:[{name:"scaffold_rule",desc:"A valid starter rule for any check type, compiled against the engine before you ever see it.",example:{call:`scaffold_rule 27 check_type: "substitution" 28 style: "House" 29 name: "Terms" 30 level: "warning"`,result:`{ 31 "files": { 32 "styles/House/Terms.yml": 33 "level: warning\\nextends: substitution\\n 34 message: \\"Use '%s' instead of '%s'.\\"\\n 35 swap:\\n utilise: use" 36 }, 37 "enable": "Add \`BasedOnStyles = House\` to 38 the [*] section of .vale.ini.", 39 "valid": true, 40 "note": "valid â" 41}`,note:"It comes back with the path it belongs at and the line that switches it on, so nothing is left to guess."}},{name:"assemble_style",desc:"Assemble validated rules into a style package. Pass the guide's own avoid and prefer examples and every rule is checked against them.",example:{call:`assemble_style 42 style: "House" 43 rules: 44 - name: GenderBias 45 yaml: "extends: existence 46 tokens: [his/her]" 47 avoid: ["Give him/her the file."] 48 prefer: ["Give them the file."]`,result:`{ 49 "compiled": 1, 50 "verified": 0, 51 "unverified": [{ 52 "name": "GenderBias", 53 "cases": [{ 54 "kind": "avoid", 55 "text": "Give him/her the file.", 56 "problem": "the guide rejects this and
57 the rule did not flag it" 58 }] 59 }] 60}`,note:"The rule compiled and still did the wrong thing: the token said his/her, the sentence said him/her. Compiling alone would have called that a success."}},{name:"fetch_guide",desc:"Turn a published style guide into plain text you can derive rules from, headings and list markers intact.",example:{call:`fetch_guide 61 url: "https://learn.microsoft.com/en-us/ 62 style-guide/word-choice/â¦"`,result:`{ 63 "title": "Use simple words, concise 64 sentences â Microsoft Style Guide", 65 "chars": 1771, 66 "truncated": false, 67 "source": "page", 68 "text": "# Use simple words, concise 69 sentences\\n\\nMake every word 70 count. Concise, clear 71 sentences save spaceâ¦" 72}`,note:"A page that renders client-side falls back to the site's llms.txt automatically. `source` tells you which one answered."}},{name:"scaffold_vocab",desc:"A vocabulary â the accept and reject word lists, at the path Vale looks for them.",example:{call:`scaffold_vocab 73 name: "Acme" 74 accept: ["Kubernetes", "kubectl", "Acme Corp"] 75 reject: ["k8s", "webserver"]`,result:`{ 76 "files": { 77 "styles/config/vocabularies/Acme/accept.txt": 78 "Kubernetes\\nkubectl\\nAcme Corp\\n", 79 "styles/config/vocabularies/Acme/reject.txt": 80 "k8s\\nwebserver\\n" 81 }, 82 "enable": "Add \`Vocab = Acme\` to the [*] 83 section of .vale.ini." 84}`,note:"Entries are case-insensitive regular expressions, not just literals â which is easy to forget and hard to notice."}},{name:"scaffold_dictionary",desc:"A custom Hunspell dictionary: the .dic and .aff pair, plus the spelling rule that uses it.",example:{call:`scaffold_dictionary 85 name: "acme" 86 words: ["Acme", "kubectl", "deploy/DG"]`,result:`{ 87 "files": { 88 "â¦/dictionaries/acme.dic": 89 "3\\nAcme\\nkubectl\\ndeploy/DG\\n", 90 "â¦/dictionaries/acme.aff": 91 "SET UTF-8\\nSFX S Y 2\\nâ¦" 92 }, 93 "rule": "extends: spelling\\n 94 dictionaries:\\n - acme\\n", 95 "note": "The .dic first line MUST be the 96 entry count." 97}`,note:"The count header on line 1 is required and is the usual reason a hand-written dictionary silently fails to load."}},{name:"scaffold_filter",desc:"A result filter â an expr-lang expression over alerts.",example:{call:`scaffold_filter 98 name: "errors-only" 99 expression: '.Level == "error" and 100 .Check contains "House"'`,result:`{ 101 "files": { 102 "styles/config/filters/errors-only": 103 ".Level == \\"error\\" and 104 .Check contains \\"House\\"\\n" 105 }, 106 "enable": "vale --filter='styles/config/ 107 filters/errors-only' â¦", 108 "note": "fields include .Check, .Level, 109 .Rule, .Message, .Match, 110 .Line, .Span" 111}`}},{name:"scaffold_view",desc:"A view: a named projection of structured or source files, via dasel or tree-sitter.",example:{call:`scaffold_view 112 name: "frontmatter" 113 engine: "dasel" 114 scope: "title" 115 expr: ".title"`,result:`{ 116 "files": { 117 "styles/config/views/frontmatter.yml": 118 "engine: dasel\\nscopes:\\n 119 - name: title\\n expr: \\".title\\"\\n" 120 }, 121 "enable": "Reference it from a rule's scope, 122 e.g. scope: text.view.<name>" 123}`,note:"Lets a rule target only the title in your front matter, and leave the body alone."}},{name:"scaffold_template",desc:"An output template that formats Vale's results.",example:{call:`scaffold_template 124 name: "compact"`,result:`{ 125 "files": { 126 "styles/config/templates/compact.tmpl": 127 "{{- range .Files}}\\n{{.Path}}\\n 128 {{- range .Alerts}}\\n {{.Line}}: 129 {{.Span.0}} {{.Severity}} 130 {{.Message}} ({{.Check}})\\n 131 {{- end}}\\n{{end -}}\\n" 132 }, 133 "enable": "vale --output='â¦/compact.tmpl'" 134}`}}]},{name:"Verify",body:"The half generation cannot do for itself: does it compile, does it fire, and does it fire on the right things.",tools:[{name:"test_rule",desc:"Lint each input against the rule alone and check whether it should match â unit tests for one rule.",example:{call:`test_rule 135 rule: "tokens: ['\\\\b[1-9]\\\\b']" 136 tests: 137 - input: "Select 3 options." 138 expectMatch: true 139 - input: "Use version 1.2.3 of the CLI." 140 expectMatch: false`,result:`[ 141 { "pass": true, "matched": true, "count": 1 }, 142 143 { "pass": false, "matched": true, "count": 3, 144 "matches": [ 145 { "match": "1", "span": [13, 13] }, 146 { "match": "2", "span": [15, 15] }, 147 { "match": "3", "span": [17, 17] } 148 ]} 149]`,note:"\\b treats a dot as a word boundary, so one version number matched three times. Nothing in the YAML tells you that."}},{name:"stress_rule",desc:"Generate near-miss inputs from the rule's own tokens and report the ones it wrongly fires on.",example:{call:`stress_rule 150 rule: "tokens: ['\\\\b[1-9]\\\\b']"`,result:`{ 151 "probed": 9, 152 "clean": 6, 153 "fired": [
154 { "kind": "version", 155 "text": "Use version 1.2.3 of the CLI.", 156 "why": "matched inside a version number" }, 157 { "kind": "section", 158 "text": "See section 2.1 for details.", 159 "why": "matched inside a section number" } 160 ] 161}`,note:"Examples you write only test what you thought of. These come from the rule itself, which is how they catch what you did not."}},{name:"diff_rule",desc:"Run both versions of a rule over a corpus and report exactly which alerts the edit adds and removes.",example:{call:`diff_rule 162 old_rule: "tokens: [very]" 163 new_rule: "nonword: true 164 tokens: [very]" 165 corpus: 166 docs/intro.md: "â¦Every release shipsâ¦" 167 docs/guide.md: "â¦with every setting."`,result:`{ 168 "added": 2, 169 "removed": 0, 170 "filesAffected": 2, 171 "coverage": "exercised", 172 "files": [ 173 { "path": "docs/guide.md", 174 "added": [{ "match": "very", 175 "line": 1, "span": [23, 26] }]}, 176 { "path": "docs/intro.md", 177 "added": [{ "match": "very", 178 "line": 3, "span": [2, 5] }]} 179 ] 180}`,note:'One word added to the rule made "very" match inside "every", twice. `coverage: exercised` says the corpus really tested the change â a clean result on a corpus that did not would prove nothing.'}},{name:"audit_style",desc:"Correctness and performance defects no compile step catches â plus what the style costs before it reads a byte.",example:{call:`audit_style 181 files: { "styles/House/Numbers.yml": ⦠} 182 sample: { text: "Select 3 optionsâ¦" }`,result:`{ 183 "findings": [ 184 { "costClass": "pattern", 185 "reason": "may backtrack on regexp2 186 (lookaround)" }, 187 { "costClass": "pattern", 188 "reason": "nonword: true drops word 189 boundaries" } 190 ], 191 "measured": { 192 "compileFloorMs": 0.524, 193 "rules": [{ "lintMs": 0.056, "alerts": 3 }] 194 } 195}`,note:"Compile cost is paid on every run whether or not the rule fires â and on a short document it is most of the wall clock."}},{name:"diagnose_rule",desc:"Compile a rule and report the error â a bad regex, field, or structure â with its position.",example:{call:`diagnose_rule 196 rule: "extends: existence 197 tokens: 198 - '(?<!\\\\bthe )(unclosed'"`,result:`[ 199 { 200 "line": 1, 201 "col": 1, 202 "severity": "error", 203 "message": "error parsing regexp: 204 missing closing ) in 205 \`(?m)\\\\b(?:(?<!\\\\bthe ) 206 (unclosed)\\\\b\`" 207 } 208]`,note:"It shows the pattern the engine actually built, wrapper and all â which is where the mismatched paren usually turns out to be."}},{name:"check_config",desc:"Load a whole proposed project through the engine: does the .vale.ini parse, do references resolve, do the rules compile.",example:{call:`check_config 209 config: "StylesPath = styles 210 Vocab = Missing 211 [*] 212 BasedOnStyles = House" 213 files: { "styles/House/Terms.yml": ⦠}`,result:`{ 214 "ok": false, 215 "error": "'config/vocabularies/Missing' 216 directory does not exist" 217}`,note:"A rule can compile perfectly and the project still not load. This is the check that catches the reference nobody created."}},{name:"lint_text",desc:"The alerts a config actually produces on
217sample prose â the same output your CI will print.",example:{call:`lint_text 218 config: "BasedOnStyles = House" 219 text: "In order to build, 220 simply run make."`,result:`[ 221 { "Check": "House.Wordy", "Span": [1, 11], 222 "Message": "Use 'to' instead of 223 'In order to'." }, 224 { "Check": "House.Avoid", "Span": [20, 25], 225 "Message": "Don't use 'simply'." } 226]`}}]},{name:"Understand",body:"Answers about the engine, from the engine â the tags, blocks, and scopes a rule will actually see.",tools:[{name:"trace_rule",desc:"For a sequence rule: what each slot requires, which words it would accept, and the alerts it produced.",example:{call:`trace_rule 227 rule: "extends: sequence 228 tokens: 229 - tag: VB[DZP] 230 pattern: (am|are|is|was|were) 231 - tag: VBN" 232 text: "The report was carefully 233 reviewed by the team."`,result:`words: The/DT report/NN was/VBD 234 carefully/RB reviewed/VBN ⦠235 236slot 0 requires tag: VB[DZP], pattern: ⦠237 accepts [2] ("was") 238slot 1 requires tag: VBN 239 accepts [4] ("reviewed") 240 241alerts: none 242 243"the rule did not fire, though every slot 244 accepts some word here: the words that 245 satisfy the slots are in the wrong order, 246 too far apart, or consumed by another slot"`,note:'Both slots match and the rule still stays silent â "carefully" sits between them and there is no skip. That is invisible in the YAML and obvious here.'}},{name:"show_blocks",desc:"How a format splits text into the blocks rules run over, with each block's scope.",example:{call:`show_blocks 247 text: "First paragraph here. 248 249 Second paragraph here." 250 format: "txt"`,result:`{ 251 "format": "txt", 252 "count": 2, 253 "scopes": ["raw.txt", "text.txt"], 254 "note": "the \`text\` scope covers the whole 255 input: this format does not end a block 256 at a blank line, so a rule can match 257 across what reads as two paragraphs â 258 a pattern joining words with \`\\\\s+\`⦠259 \`.md\` or \`.adoc\` splits them." 260}`,note:"This is why the same rule behaves in Markdown and misfires in plain text. The format is the bug, not the pattern."}},{name:"tag_text",desc:"Part-of-speech tags from Vale's own tagger â the Penn Treebank tags sequence checks match on.",example:{call:`tag_text 261 text: "Does the mistake change the 262 meaning of the quotation?"`,result:`Does VBZ 263the DT 264mistake NN 265change NN â not a verb, to Vale 266the DT 267meaning NN 268of IN 269quotation NN`,note:'A rule guarding on "a verb follows" will not fire here. That is a tagger disagreement, not a broken rule â and the fix is an exception, not a rewrite.'}},{name:"resolve_config",desc:"The configuration the engine actually resolved: which styles apply per glob, and each rule's state after the cascade.",example:{call:`resolve_config 270 config: "[*] 271 BasedOnStyles = House 272 [*.md] 273 House.Terms = error 274 House.Wordy = NO"`,result:`glob "*" 275 House.Terms override level: error 276 House.Wordy active 277 â active 1, disabled 0, overridden 1 278 279glob "*.md" 280 House.Terms override level: error 281 House.Wordy disabled 282 â active 0, disabled 1, overridden 1`,note:"Precedence the config text does not show you. Answers which rules run in this file, at what level â before you wonder why one never fired."}},{name:"expand_dictionary",desc:"The exact word forms a Hunspell entry accepts, continuation classes included â before you add the word.",example:{call:`expand_dictionary 283 aff: "SFX D Y 2 284 SFX D 0 ed [^ey] 285 SFX D y ied [^aeiou]y 286 SFX G Y 1 287 SFX G 0 ing [^e]" 288 entries: ["deploy/DG", "verify/D"]`,result:`{ 289 "expansions": [ 290 { "entry": "deploy/DG", 291 "forms": ["deploy", "deploying"] }, 292 293 { "entry": "verify/D", 294 "forms": ["verify", "verified"] } 295 ] 296}`,note:'No "deployed". The D suffix needs a word not ending in y, or a consonant before the y â "deploy" is neither, so the form you wanted is quietly missing.'}},{name:"explain_check",desc:"What a check type detects, the fields that matter, and a working example rule.",example:{call:`explain_check 297 type: "occurrence"`,result:`## occurrence (Matching) 298 299Counts matches of one token per scope and 300flags when the count is over max (or 301under min). 302 303Syntax: token (regex) · max · min · scope 304 305 extends: occurrence 306 message: "More than 3 commas." 307 scope: sentence 308 token: ',' 309 max: 3`}},{name:"list_check_types",desc:"All twelve of Vale's check extension points, one line each.",example:{call:"list_check_types",result:`existence flags every occurrence of the 310 listed patterns 311substitution flags a term, suggests a 312 preferred one 313occurrence counts matches per scope 314repetition flags "the the" 315consistency enforces one choice project-wide 316conditional flags "second" unless "first" 317 appeared
318capitalization $sentence / $title / $lower ⦠319readability flags when the grade is too high 320spelling Hunspell, with custom dictionaries 321sequence an ordered run of tokens, by text, 322 POS tag, or scope 323metric a formula over document metrics 324script a Tengo program â the escape hatch`}},{name:"project_layout",desc:"Where every asset belongs on disk, and the .vale.ini line that enables it.",example:{call:"project_layout",result:`.vale.ini 325styles/<Style>/<Rule>.yml 326styles/config/vocabularies/<name>/ 327 accept.txt + reject.txt â Vocab = <name> 328styles/config/dictionaries/<name>.dic/.aff 329 â spelling rule dictionaries: [<name>] 330styles/config/filters/<name> 331 â --filter='â¦/filters/<name>' 332styles/config/views/<name>.yml 333 â rule scope: â¦view.<name> 334styles/config/templates/<name>.tmpl 335 â --output='â¦/templates/<name>.tmpl'`,note:"Call it first when creating an asset: every scaffold_* tool writes to these paths, so nothing lands somewhere the engine will not look."}}]},{name:"Change safely",body:"Editing a rule already in use is the risky edit. Compiling proves it is valid; these prove the change is safe.",tools:[{name:"diff_style",desc:"Two versions of a whole package over a corpus, attributed per rule and per file.",example:{call:`diff_style 336 old_files: { â¦Wordy.yml, Terms.yml } 337 new_deltas: 338 "styles/House/Wordy.yml": 339 "tokens: 340 - very 341 - really" 342 corpus: { docs/a.md, docs/b.md }`,result:`{ 343 "added": 1, 344 "removed": 0, 345 "filesAffected": 1, 346 "filesScanned": 2, 347 "rules": [ 348 { "rule": "House.Wordy", 349 "added": 1, "removed": 0 } 350 ], 351 "files": [{ "path": "docs/a.md", 352 "added": [{ "match": "really", 353 "line": 1, "span": [23, 28] }]}] 354}`,note:"It also reports rules the corpus never triggered, so you know which parts of a clean result mean nothing at all."}},{name:"render_template",desc:"See what an output template produces against a document's real alerts â or the error it fails with.",example:{call:`render_template 355 template: "{{range .Files}}{{$p := .Path}} 356 {{range .Alerts}}{{$p}}:{{.Line}}: 357 {{index .Span 0}} [{{.Check}}] 358 {{.Message}}â¦" 359 text: "In order to build, 360 simply run make."`,result:`input.md:1:20 [House.Avoid] 361 Don't use 'simply'. 362input.md:1:1 [House.Wordy] 363 Use 'to' instead of 'In order to'. 3641 file(s) linted.`,note:"The rendered output, not a description of it â including the compile error when the template has one."}},{name:"put_files",desc:"Upload a project once and name it by content hash, then send only what changed on every later call.",example:{call:`put_files 365 files: 366 "styles/House/Terms.yml": ⦠367 "styles/House/Wordy.yml": â¦`,result:`{ 368 "ref": "sha256:a6e1d3f67c017eceae6ee406 369 de9333d6ee4174027ecd698bff3â¦", 370 "files": 2, 371 "bytes": 207, 372 "note": "pass this as \`ref\` instead of 373 \`files\`; add \`deltas\` for edits 374 on top of it" 375}`,note:"An edit-and-recheck loop then costs one changed file per call instead of the whole tree. The ref is a content hash, so one you did not create is unguessable."}}]}];var Qe=(f,r,o)=>le(r,ye(s(o).name)),et=b('<button type="button"> </button>'),tt=b('<div><div class="flex items-baseline justify-between gap-4"><h3 class="text-sm font-semibold"> </h3> <span class="font-mono text-[11px] text-muted-foreground"> </span></div> <p class="mt-1 text-xs leading-5 text-muted-foreground"> </p> <div class="mt-2.5 flex flex-wrap gap-1.5"></div></div>'),at=b('<p class="mt-3.5 text-sm leading-6 text-muted-foreground"> </p>'),st=b(`<section id="toolbelt" class="scroll-mt-20 border-b border-border/60 bg-muted/30 py-16 sm:py-20"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="max-w-3xl"><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">The MCP surface</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl"></p> <p class="mt-5 text-pretty text-lg leading-8 text-muted-foreground">An assistant with a documentation search can tell you what Vale <em>should</em> do. These 376 tools run the engine, so they answer what it <em>does</em>. Open any of them â every panel 377 is a real call and what actually came back.</p></div> <div class="mt-12 grid gap-6 lg:grid-cols-[0.9fr_1.1fr] lg:gap-8"><div class="flex min-w-0 flex-col gap-5"></div> <div class="min-w-0 lg:sticky lg:top-24 lg:self-start"><div class="rounded-2xl border border-border/60 bg-card p-6"><div class="flex flex-wrap items-center gap-2"><code class="font-mono text-base font-semibold text-lime-600 dar
377k:text-lime-400"> </code> <span class="rounded-md bg-muted px-2 py-0.5 text-[11px] text-muted-foreground"> </span></div> <p class="mt-3 text-sm leading-6 text-muted-foreground"> </p> <div class="mt-5 overflow-hidden rounded-xl border border-border/60"><div class="border-b border-border/60 bg-muted/60 px-3 py-1.5 font-mono text-[10.5px] font-bold uppercase tracking-wider text-muted-foreground">the call</div> <!> <div class="border-y border-border/60 bg-muted/60 px-3 py-1.5 font-mono text-[10.5px] font-bold uppercase tracking-wider text-muted-foreground">what came back</div> <!></div> <!></div> <p class="mt-3 text-center text-xs text-muted-foreground"> <a href="https://docs.vale.sh/topics/mcp" class="font-semibold hover:underline">full reference →</a></p></div></div></div></section>`);function rt(f,r){pe(r,!0);const o=ne.flatMap(V=>V.tools),p=o.length;let c=me("test_rule");const i=de(()=>o.find(V=>V.name===s(c))??o[0]),l=de(()=>{var V;return((V=ne.find(H=>H.tools.some(C=>C.name===s(c))))==null?void 0:V.name)??""});var d=st(),m=t(d),h=t(m),v=a(t(h),2);v.textContent=`${p??""} tools, and every one of them can say ânoâ`,M(2),e(h);var n=a(h,2),x=t(n);A(x,21,()=>ne,V=>V.name,(V,H)=>{var C=tt(),P=t(C),j=t(P),K=t(j,!0);e(j);var W=a(j,2),se=t(W);e(W),e(P);var re=a(P,2),fe=t(re,!0);e(re);var ie=a(re,2);A(ie,21,()=>s(H).tools,oe=>oe.name,(oe,Z)=>{var q=et();q.__click=[Qe,c,Z];var xe=t(q,!0);e(q),$(()=>{Q(q,"aria-pressed",s(c)===s(Z).name),B(q,`rounded-md border px-2 py-1 font-mono text-[11.5px] transition-colors ${(s(c)===s(Z).name?"border-lime-500 bg-lime-500/15 font-semibold text-lime-700 dark:text-lime-400":"border-border/60 bg-background text-foreground hover:border-lime-500/50 hover:bg-lime-500/5")??""}`),u(xe,s(Z).name)}),g(oe,q)}),e(ie),e(C),$(()=>{u(K,s(H).name),u(se,`${s(H).tools.length??""} tools`),u(fe,s(H).body)}),g(V,C)}),e(x);var y=a(x,2),_=t(y),w=t(_),k=t(w),S=t(k,!0);e(k);var T=a(k,2),I=t(T,!0);e(T),e(w);var G=a(w,2),ee=t(G,!0);e(G);var N=a(G,2),X=a(t(N),2);ce(X,{get html(){return r.exampleHtml[s(i).name].call},bare:!0});var O=a(X,4);ce(O,{get html(){return r.exampleHtml[s(i).name].result},bare:!0}),e(N);var te=a(N,2);{var z=V=>{var H=at(),C=t(H,!0);e(H),$(()=>u(C,s(i).example.note)),g(V,H)};J(te,V=>{s(i).example.note&&V(z)})}e(_);var D=a(_,2),ae=t(D);ae.nodeValue=`Every one of the ${p??""} carries a real call and its real output · `,M(),e(D),e(y),e(n),e(m),e(d),$(()=>{u(S,s(i).name),u(I,s(l)),u(ee,s(i).desc)}),g(f,d),ve()}he(["click"]);var ot=b('<li><div class="text-sm font-medium"> </div> <div class="mt-0.5 text-xs leading-5 text-muted-foreground"> </div></li>'),nt=b('<li><div class="text-sm font-medium"> </div> <div class="mt-0.5 text-xs leading-5 text-muted-foreground"> </div></li>'),lt=b(`<div class="rounded-2xl border border-border/60 bg-card p-6"><div class="grid gap-5 sm:grid-cols-2"><div class="rounded-xl border border-lime-500/40 bg-lime-500/5 p-5"><div class="flex items-baseline justify-between gap-3"><h3 class="text-sm font-semibold">Never leaves you</h3> <span class="font-mono text-[10.5px] uppercase tracking-wider text-lime-600 dark:text-lime-400">your browser</span></div> <ul class="mt-3.5 flex flex-col gap-3"></ul></div> <div class="rounded-xl border border-border/60 bg-background p-5"><div class="flex items-baseline justify-between gap-3"><h3 class="text-sm font-semibold">Passes through, unstored</h3> <span class="font-mono text-[10.5px] uppercase tracking-wider text-muted-foreground">our engine</span></div> <ul class="mt-3.5 flex flex-col gap-3"></ul> <div class="mt-4 border-t border-border/60 pt-3 text-xs leading-5 text-muted-foreground">Stateless: each request carries what it needs, is processed in memory, and leaves nothing 378 behind.</div></div></div> <p class="mt-5 text-pretty text-center text-sm leading-6 text-muted-foreground">The column on the left is the reason the column on the right is short.</p></div>`);function it(f){const r=[{what:"Your GitHub / GitLab token",how:"held in your browser, sent to them, never to us"},{what:"Your repository",how:"we commit to it; we keep no second copy"}
378,{what:"Your style guide",how:"ordinary files, in your Git history"}],o=[{what:"The text being linted",how:"held only long enough to lint, then dropped"},{what:"Your rules, to compile",how:"same â nothing is written down"}];var p=lt(),c=t(p),i=t(c),l=a(t(i),2);A(l,5,()=>r,h=>h.what,(h,v)=>{var n=ot(),x=t(n),y=t(x,!0);e(x);var _=a(x,2),w=t(_,!0);e(_),e(n),$(()=>{u(y,s(v).what),u(w,s(v).how)}),g(h,n)}),e(l),e(i);var d=a(i,2),m=a(t(d),2);A(m,5,()=>o,h=>h.what,(h,v)=>{var n=nt(),x=t(n),y=t(x,!0);e(x);var _=a(x,2),w=t(_,!0);e(_),e(n),$(()=>{u(y,s(v).what),u(w,s(v).how)}),g(h,n)}),e(m),M(2),e(d),e(c),M(2),e(p),g(f,p)}function dt(f,r){const o=F(r,["children","$$slots","$$events","$$legacy"]);R(f,E({name:"key-round"},()=>o,{iconNode:[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor"}]],children:(c,i)=>{var l=Y(),d=L(l);U(d,r,"default",{}),g(c,l)},$$slots:{default:!0}}))}function ct(f,r){const o=F(r,["children","$$slots","$$events","$$legacy"]);R(f,E({name:"server-off"},()=>o,{iconNode:[["path",{d:"M7 2h13a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-5"}],["path",{d:"M10 10 2.5 2.5C2 2 2 2.5 2 5v3a2 2 0 0 0 2 2h6z"}],["path",{d:"M22 17v-1a2 2 0 0 0-2-2h-1"}],["path",{d:"M4 14a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16.5l1-.5.5.5-8-8H4z"}],["path",{d:"M6 18h.01"}],["path",{d:"m2 2 20 20"}]],children:(c,i)=>{var l=Y(),d=L(l);U(d,r,"default",{}),g(c,l)},$$slots:{default:!0}}))}function pt(f,r){const o=F(r,["children","$$slots","$$events","$$legacy"]);R(f,E({name:"shield-check"},()=>o,{iconNode:[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["path",{d:"m9 12 2 2 4-4"}]],children:(c,i)=>{var l=Y(),d=L(l);U(d,r,"default",{}),g(c,l)},$$slots:{default:!0}}))}var vt=b('<div class="rounded-2xl border border-border/60 bg-card p-6"><div class="inline-flex rounded-lg bg-lime-500/10 p-2 text-lime-600 dark:text-lime-400"><!></div> <h3 class="mt-4 font-semibold"> </h3> <p class="mt-2 text-sm leading-6 text-muted-foreground"> </p></div>'),mt=b(`<section class="border-b border-border/60 py-16 sm:py-20"><div class="mx-auto grid max-w-6xl gap-10 px-6 lg:grid-cols-[0.85fr_1.15fr] lg:gap-14 lg:px-8"><div><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">Built for private repositories</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">We don't keep the things worth keeping safe.</p> <p class="mt-5 text-pretty text-lg leading-8 text-muted-foreground">Vale CMS has to open your project and write changes back to it. Your credentials stay in 379 your browser and your writing is forgotten as soon as it is linted, so the parts that matter 380 never pile up on our servers in the first place.</p> <a href="https://cms.vale.sh/security" class="mt-6 inline-flex items-center gap-1.5 text-sm font-semibold text-lime-600 hover:underline dark:text-lime-400">Read the full security page <span aria-hidden="true">â</span></a></div> <div class="flex flex-col gap-5"><!> <div class="grid gap-5 sm:grid-cols-2"></div></div></div></section>`);function ut(f){const r=[{icon:be,title:"Your files stay in your repo",body:"Vale CMS edits your repository directly. There is no second copy of your style guide living somewhere else, and nothing to migrate out of if you stop paying."},{icon:dt,title:"Your GitHub login never reaches us",body:"The access token stays in your browser. We hand it to GitHub or GitLab when you ask for something, then drop it. We never store it."},{icon:ct,title:"We do not keep your writing",body:"Your content is checked and forgotten. The engine holds it just long enough to lint it and writes none of it down."},{icon:pt,title:"Only our own code runs",body:"Every script is fingerprinted before it ships, so anything injected later simply will not run â and if it somehow did, it could not send your data anywhere we have not listed by n
380ame."}];var o=mt(),p=t(o),c=a(t(p),2),i=t(c);it(i);var l=a(i,2);A(l,5,()=>r,d=>d.title,(d,m)=>{var h=vt(),v=t(h),n=t(v);s(m).icon(n,{class:"size-5"}),e(v);var x=a(v,2),y=t(x,!0);e(x);var _=a(x,2),w=t(_,!0);e(_),e(h),$(()=>{u(y,s(m).title),u(w,s(m).body)}),g(d,h)}),e(l),e(c),e(p),e(o),g(f,o)}var ht=(f,r)=>le(r,!1),ft=(f,r)=>le(r,!0),xt=b('<span class="mb-2 self-start rounded-md bg-lime-500/10 px-2 py-0.5 font-mono text-[10.5px] font-bold uppercase tracking-wider text-lime-600 dark:text-lime-400">Most popular</span>'),gt=b('<span class="text-sm text-muted-foreground"> </span>'),yt=b('<li class="flex items-start gap-2.5 text-sm leading-6"><!> <span> </span></li>'),bt=b('<div class="mt-2.5 text-center text-xs text-muted-foreground"> </div>'),wt=b('<div><!> <div class="text-xl font-semibold"> </div> <div class="mt-3 flex items-baseline gap-1.5"><span class="text-4xl font-semibold tabular-nums tracking-tight"> </span> <!></div> <div> </div> <p class="mt-3 min-h-[2.5rem] text-sm text-muted-foreground"> </p> <ul class="mb-6 mt-5 flex flex-col gap-3"></ul> <a href="https://cms.vale.sh"> </a> <!></div>'),_t=b(`<section id="pricing" class="scroll-mt-20 border-b border-border/60 bg-muted/30 py-16 sm:py-20"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="mx-auto max-w-2xl text-center"><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">Pricing</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">Explore free. Author on Pro.</p> <p class="mt-5 text-pretty text-lg leading-8 text-muted-foreground">Vale stays free and open source. Vale CMS is the hosted authoring layer on top of it.</p></div> <div class="mt-10 flex flex-wrap items-center justify-center gap-3"><div class="inline-flex rounded-xl border border-border/60 bg-background p-1" role="group" aria-label="Billing period"><button type="button">Pay monthly</button> <button type="button">Pay yearly</button></div> <span class="rounded-md bg-lime-500/10 px-2 py-1 font-mono text-[11px] font-bold uppercase tracking-wider text-lime-600 dark:text-lime-400">2 months free</span></div> <div class="mt-8 grid items-start gap-5 sm:grid-cols-3"></div> <p class="mx-auto mt-8 max-w-2xl text-center text-sm text-muted-foreground">Pro and Site unlock the same product. Site buys coverage for a whole domain instead of one 381 person â every colleague and every automated account, on one invoice, with no seat to run out 382 of.</p></div></section>`);function kt(f){let r=me(!1);const o=[{name:"Free",monthly:"$0",annual:"$0",unit:"",note:"free forever",who:"A real linting tool, in the browser, with no account.",features:["Open your own folders and zips","Live linting against the real engine","Browse the full sample project, read-only"],cta:"Open it, no signup",featured:!1,annualOnly:!1,trial:""},{name:"Pro",monthly:"$19",annual:"$15",unit:"/ month",note:"$180 billed yearly · 21% off",who:"The full editor and your own repositories, for one person.",features:["Full editor â rules, vocab, dictionaries, filters, views, templates","Edit and ship GitHub or GitLab repos â commit, open pull requests","Hosted MCP server for every client","Discord support"],cta:"Start free trial",featured:!0,annualOnly:!1,trial:"1 month free · cancel anytime"},{name:"Site",monthly:"$1,000",annual:"$1,000",unit:"/ year",note:"billed yearly ·
382no per-seat count",who:"Everyone at your domain, and everything they automate.",features:["Everything in Pro, for every address at your domain","No seats to assign, reassign, or run out of","MCP for the accounts your CI and agents run as","Priority support â private Discord channel"],cta:"Start free trial",featured:!1,annualOnly:!0,trial:"1 month free · cancel anytime"}];var p=_t(),c=t(p),i=a(t(c),2),l=t(i),d=t(l);d.__click=[ht,r];var m=a(d,2);m.__click=[ft,r],e(l),M(2),e(i);var h=a(i,2);A(h,21,()=>o,v=>v.name,(v,n)=>{var x=wt(),y=t(x);{var _=C=>{var P=xt();g(C,P)};J(y,C=>{s(n).featured&&C(_)})}var w=a(y,2),k=t(w,!0);e(w);var S=a(w,2),T=t(S),I=t(T,!0);e(T);var G=a(T,2);{var ee=C=>{var P=gt(),j=t(P,!0);e(P),$(()=>u(j,s(n).unit)),g(C,P)};J(G,C=>{s(n).unit&&C(ee)})}e(S);var N=a(S,2),X=t(N,!0);e(N);var O=a(N,2),te=t(O,!0);e(O);var z=a(O,2);A(z,20,()=>s(n).features,C=>C,(C,P)=>{var j=yt(),K=t(j);we(K,{class:"mt-1 size-4 shrink-0 text-lime-600 dark:text-lime-400"});var W=a(K,2),se=t(W,!0);e(W),e(j),$(()=>u(se,P)),g(C,j)}),e(z);var D=a(z,2),ae=t(D,!0);e(D);var V=a(D,2);{var H=C=>{var P=bt(),j=t(P,!0);e(P),$(()=>u(j,s(n).trial)),g(C,P)};J(V,C=>{s(n).trial&&C(H)})}e(x),$(()=>{B(x,`flex flex-col rounded-2xl border bg-card p-6 ${(s(n).featured?"border-lime-500 ring-1 ring-lime-500":"border-border/60")??""}`),u(k,s(n).name),u(I,s(r)?s(n).annual:s(n).monthly),B(N,`mt-1 min-h-[1.25rem] text-xs ${(s(r)&&s(n).featured?"text-lime-600 dark:text-lime-400":"text-muted-foreground")??""}`),u(X,s(n).name==="Free"||s(n).annualOnly?s(n).note:s(r)?s(n).note:"billed monthly"),u(te,s(n).who),B(D,`mt-auto inline-flex h-10 items-center justify-center rounded-lg px-4 text-sm font-medium transition-colors ${(s(n).featured?"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90":"border border-border bg-background text-foreground hover:bg-muted/60")??""}`),u(ae,s(n).cta)}),g(v,x)}),e(h),M(2),e(c),e(p),$(()=>{Q(d,"aria-pressed",!s(r)),B(d,`rounded-lg px-4 py-1.5 text-sm transition-colors ${(s(r)?"text-muted-foreground hover:text-foreground":"bg-lime-500/15 font-semibold text-lime-700 dark:text-lime-400")??""}`),Q(m,"aria-pressed",s(r)),B(m,`rounded-lg px-4 py-1.5 text-sm transition-colors ${(s(r)?"bg-lime-500/15 font-semibold text-lime-700 dark:text-lime-400":"text-muted-foreground hover:text-foreground")??""}`)}),g(f,p)}he(["click"]);var $t=b('<div><dt class="text-base font-semibold"> </dt> <dd class="mt-2 text-pretty text-sm leading-6 text-muted-foreground"> </dd></div>'),Ct=b(`<section id="faq" class="scroll-mt-20 border-b border-border/60 bg-muted/30 py-16 sm:py-20"><div class="mx-auto max-w-6xl px-6 lg:px-8"><div class="max-w-2xl"><h2 class="text-base font-semibold text-lime-600 dark:text-lime-400">Before you ask</h2> <p class="mt-2 text-balance text-3xl font-semibold tracking-tight sm:text-4xl">The questions we'd ask too</p></div> <dl class="mt-12 grid gap-x-10 gap-y-9 sm:grid-cols-2"></dl></div></section>`);function Tt(f){const r=[{q:"Do I need Vale CMS to use Vale?",a:"No, and that is deliberate. Vale is MIT licensed and always will be â the CLI, the engine, the styles. Vale CMS is a hosted place to author the project and an MCP server for your assistant. Everything it writes is ordinary files in your repository that the free CLI reads."},{q:"Does it replace Vale in my CI?",a:"No. Enforcement stays with the Vale CLI on your own runners, where it belongs. Vale CMS is where rules get written and proved before they get there, so CI stops being the place you discover a rule never compiled."},{q:"What happens to my work if I cancel?",a:"Nothing. Your style guide lives in your Git repository the whole time â there is no second copy on our side to export, and no format only we can read. Cancelling costs you the editor and the MCP server, not your project."},{q:"Can my assistant use it without me?",a:"On a Site license, yes. Entitlement resolves by the email domain on the subscription, so an account your CI or an agent signs in as is covered like any colleague. On Pro the MCP token is tied to you personally."},{q:"What can I do without paying?",a:"Open your own folders and zips, lint them against the real engine, and read the full sample project. It is read-only until you subscribe â editing, Git, and MCP are the paid parts."},{q:"Is there a Team plan?",a:"Not any more. Per-seat pricing meant counting who was allowed to write a rule, which is a strange thing to meter on a docs team â and it left automated accounts with no seat to hold. Site covers everyone at your domain instead, for a flat $1,000 a year."}];var o=Ct(),p=t(o),c=a(t(p),2);A(c,5,()=>r,i=>i.q,(i,l)=>{var d=$t(),m=t(d),h=t(m,!0);e(m);var v=a(m,2),n=t(v,!0);e(v),e(d),$(()=>{u(h,s(l).q),u(n,s(l).a)}),g(i,d)}),e(c),e(p),e(o),g(f,o)}var St=b(`<section class="relative overflow-hidden border-t border-border/60"><div class="pointer-events-none absolute inset-0 -z-10 [background-image:radial-gradient(hsl(var(--foreground)/0.06)_1px,transparent_1px)] [background-size:22px_22px] [mask-image:radial-gradient(ellipse_60%_70%_at_50%_100%,#000_50%,transparent_100%)]"></div> <div class="mx-auto max-w-6xl px-6 py-20 sm:py-24 lg:px-8"><div class="mx-auto max-w-3xl text-center"><h2 class="text-balance text-3xl font-semibold tracking-tight sm:text-5xl">
382Stop shipping rules you <span class="text-lime-600 dark:text-lime-400">hope</span> work.</h2> <p class="mx-auto mt-5 max-w-2xl text-pretty text-lg leading-8 text-muted-foreground">A month of the full editor and the MCP server, on your own repository. If it hasn't caught 383 something your CI would have missed, cancel and keep using Vale for free.</p> <div class="mt-9 flex flex-col items-center justify-center gap-3 sm:flex-row"><a href="https://cms.vale.sh" class="group inline-flex h-11 items-center justify-center gap-1.5 rounded-lg bg-primary px-7 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90">Start your free month <!></a> <a href="https://cms.vale.sh" class="inline-flex h-11 items-center justify-center rounded-lg border border-border bg-background px-6 text-sm font-medium text-foreground transition-colors hover:bg-muted/60">Or open the sample first</a></div> <p class="mt-5 text-sm text-muted-foreground">Cancel anytime · the sample needs no account · Vale itself stays free and MIT licensed</p></div></div></section>`);function Mt(f){var r=St(),o=a(t(r),2),p=t(o),c=a(t(p),4),i=t(c),l=a(t(i));ue(l,{class:"h-4 w-4 transition-transform group-hover:translate-x-0.5"}),e(i),M(2),e(c),M(2),e(p),e(o),e(r),g(f,r)}var At=b("<!> <!> <!> <!> <!> <!> <!> <!> <!> <!> <!>",1);function Lt(f,r){pe(r,!0);const o="Vale CMS is the hosted editor for your whole Vale project â config, rules, vocabularies, and every asset â with the real engine linting as you type, then shipping straight to your repo.";var p=At(),c=L(p);ge(c,{title:"Vale CMS â author your style guide with the linter running",description:o,canonical:"https://vale.sh/cms",openGraph:{url:"https://vale.sh/cms",title:"Vale CMS",description:o,images:[{url:"/android-chrome-512x512.png",width:512,height:512,alt:"Vale"}]}});var i=a(c,2);Ce(i);var l=a(i,2);Ie(l);var d=a(l,2);Je(d);var m=a(d,2);rt(m,{get exampleHtml(){return r.data.exampleHtml}});var h=a(m,2);We(h);var v=a(h,2);Xe(v);var n=a(v,2);ut(n);var x=a(n,2);kt(x);var y=a(x,2);Tt(y);var _=a(y,2);Mt(_),g(f,p),ve()}export{Lt as component};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.