@godxjp/ui-mcp 30.7.1 → 30.8.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.
Files changed (2) hide show
  1. package/dist/index.js +3 -3
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2569,7 +2569,7 @@ const notes: Note[] = useNotes();
2569
2569
  </Card>
2570
2570
  )}
2571
2571
  onLayoutChange={(layout) => console.log(layout.length, "tiles placed")}
2572
- />`,docPath:"layout/masonry.tsx",storyPath:"layout/Masonry.stories.tsx",rules:[2,40,44,45]},{name:"Affix",group:"layout",tagline:"Ant Design `Affix` (6.6.5): pin an element to its scrollport once the page scrolls past it, and REPORT that it is pinned. `position: sticky` pins and then says nothing, so a sticky header cannot shrink, swap its logo or raise its shadow; this one exposes the boolean as `data-affixed` for CSS and `onChange` for JavaScript, and holds the flow open with a MEASURED placeholder so the page does not jump by the bar's height at the moment it pins.",props:[{name:"children",type:"ReactNode",description:"What gets pinned. Must not itself be `position: absolute` (antd's note applies here for the same reason: the pin works by making this content `position: fixed`)."},{name:"offsetBlockStart",type:"number",description:"antd `offsetTop`, on its LOGICAL axis. Pixels from the scrollport's block-start edge at which it pins, and the distance it sits at once pinned. Overrides the `--affix-inset-block-start` token per instance; omit it to take the theme's. Default `0` (antd's) via that token."},{name:"offsetBlockEnd",type:"number",description:"antd `offsetBottom`, on its LOGICAL axis \u2014 the sticky FORM FOOTER rather than the sticky header. Passing it (and no `offsetBlockStart`) is what selects block-end pinning, exactly as in antd; block-start wins when both are given."},{name:"target",type:"() => Window | HTMLElement | null",description:"antd `target`, default `() => window` \u2014 the scroll box to pin against, which need not be the nearest scrolling ancestor. Same lazy-getter shape `FloatButton.BackTop.target` uses here, and for the same reason: the element does not exist on the render that declares it."},{name:"onChange",type:"(affixed: boolean) => void",description:"antd `onChange`. Fires on the pin TRANSITION and only on it \u2014 never on a scroll frame that did not change the state. Structural, not guarded: the value is React state, so the effect cannot run without it having flipped, and the mount is skipped."},{name:"offsetTop / offsetBottom",type:"never",description:"NOT props. antd's physical spellings, kept in the type so that arriving from antd's docs is a COMPILE ERROR naming `offsetBlockStart` / `offsetBlockEnd`, plus a development console.warn. See docs/DESIGN-AUTHORITY.md."},{name:"id",type:"string",description:"DOM id of the outer (in-flow) box."},{name:"className",type:"string",description:"Structural class on the outer box."}],usage:["DO use it whenever the pinned state has to be VISIBLE \u2014 a header that condenses, a toolbar that gains a shadow over the rows sliding under it, a filter rail that swaps to a compact form. That state is the entire reason this exists; if you need none of it, plain `position: sticky` is lighter and correct.",'DO style the pinned state off `[data-affixed]` on `data-slot="affix-content"`, and transition on `--duration-fast` / `--ease-standard`. The condensed bar must still be there under `prefers-reduced-motion` \u2014 it snaps to the smaller size, it never fades out.',"DO set the resting offset ONCE in your theme (`:root { --affix-inset-block-start: 4rem; }`) when every affixed bar in the product has to clear the same app header. `offsetBlockStart` is the per-instance override, not the place to repeat a global decision.","DO pass `target` when the page scrolls inside a pane rather than the document \u2014 an AppShell main region, a dialog body, a MasterDetail column.","DON'T put a `transform`, `filter` or `backdrop-filter` on an ancestor. That ancestor becomes the containing block for `position: fixed` and the bar pins to it instead of the scrollport. The same limitation applies to `position: sticky` and to antd's Affix; there is no fix inside the component.","DON'T give the children `position: absolute`, and DON'T expect a horizontally scrolling container to work \u2014 antd documents both, and both are true here.","DON'T hand-roll the placeholder. The height is MEASURED, so it is right at every width and after any re-wrap; a number written once in CSS is wrong at every other width, which is the page-jump bug this component exists to remove."],useCases:["A site or app header that condenses on scroll: the wordmark shrinks to a monogram and the bar loses half its height, driven by `data-affixed` alone.","A table toolbar (search, filters, bulk actions) that stays reachable over a thousand-row list and gains a shadow the moment it starts covering rows.","A form's action footer pinned to the bottom of a long form with `offsetBlockEnd`, released once the real end of the form scrolls into view.","The substrate under `Anchor affix` \u2014 antd specifies Anchor's own `affix` prop as `AffixProps`, so the two are one stack."],related:["Anchor \u2014 takes an `AffixProp` subset as its own `affix` prop and pins its section nav with this.",'PageContainer \u2014 `stickyFooter` / `footerReveal="onScroll"` is the page-level answer; it shares the same `useIntersects` observer this uses.',"FloatButton.BackTop \u2014 the other public scroll-position API, and where `target`'s lazy-getter shape comes from.","Topbar / AppShell \u2014 the app chrome an affixed bar usually sits UNDER; `--affix-inset-block-start` is how it clears it."],example:`import { Affix } from "@godxjp/ui/layout";
2572
+ />`,docPath:"layout/masonry.tsx",storyPath:"layout/Masonry.stories.tsx",rules:[2,40,44,45]},{name:"Affix",group:"layout",tagline:"Ant Design `Affix` (6.6.5): pin an element to its scrollport once the page scrolls past it, and REPORT that it is pinned. `position: sticky` pins and then says nothing, so a sticky header cannot shrink, swap its logo or raise its shadow; this one exposes the boolean as `data-affixed` for CSS and `onChange` for JavaScript, and holds the flow open with a MEASURED placeholder so the page does not jump by the bar's height at the moment it pins.",props:[{name:"children",type:"ReactNode",description:"What gets pinned. Must not itself be `position: absolute` (antd's note applies here for the same reason: the pin works by making this content `position: fixed`)."},{name:"offsetBlockStart",type:"number",description:"antd `offsetTop`, on its LOGICAL axis. Pixels from the scrollport's block-start edge at which it pins, and the distance it sits at once pinned. Overrides the `--affix-inset-block-start` token per instance; omit it to take the theme's. Default `0` (antd's) via that token."},{name:"offsetBlockEnd",type:"number",description:"antd `offsetBottom`, on its LOGICAL axis \u2014 the sticky FORM FOOTER rather than the sticky header. Passing it (and no `offsetBlockStart`) is what selects block-end pinning, exactly as in antd; block-start wins when both are given."},{name:"target",type:"() => Window | HTMLElement | null",description:"antd `target` \u2014 the scroll box to pin against, which need not be the nearest scrolling ancestor. Omitted, it IS the nearest block-axis scroller (`position: sticky`'s rule), else the viewport (gh#984); `() => window` is the viewport. Same lazy-getter shape `FloatButton.BackTop.target` uses here, and for the same reason: the element does not exist on the render that declares it."},{name:"onChange",type:"(affixed: boolean) => void",description:"antd `onChange`. Fires on the pin TRANSITION and only on it \u2014 never on a scroll frame that did not change the state. Structural, not guarded: the value is React state, so the effect cannot run without it having flipped, and the mount is skipped."},{name:"offsetTop / offsetBottom",type:"never",description:"NOT props. antd's physical spellings, kept in the type so that arriving from antd's docs is a COMPILE ERROR naming `offsetBlockStart` / `offsetBlockEnd`, plus a development console.warn. See docs/DESIGN-AUTHORITY.md."},{name:"id",type:"string",description:"DOM id of the outer (in-flow) box."},{name:"className",type:"string",description:"Structural class on the outer box."}],usage:["DO use it whenever the pinned state has to be VISIBLE \u2014 a header that condenses, a toolbar that gains a shadow over the rows sliding under it, a filter rail that swaps to a compact form. That state is the entire reason this exists; if you need none of it, plain `position: sticky` is lighter and correct.",'DO style the pinned state off `[data-affixed]` on `data-slot="affix-content"`, and transition on `--duration-fast` / `--ease-standard`. The condensed bar must still be there under `prefers-reduced-motion` \u2014 it snaps to the smaller size, it never fades out.',"DO set the resting offset ONCE in your theme (`:root { --affix-inset-block-start: 4rem; }`) when every affixed bar in the product has to clear the same app header. `offsetBlockStart` is the per-instance override, not the place to repeat a global decision.","DO pass `target` when the page scrolls inside a pane rather than the document \u2014 an AppShell main region, a dialog body, a MasterDetail column.","DON'T put a `transform`, `filter` or `backdrop-filter` on an ancestor. That ancestor becomes the containing block for `position: fixed` and the bar pins to it instead of the scrollport. The same limitation applies to `position: sticky` and to antd's Affix; there is no fix inside the component.","DON'T give the children `position: absolute`, and DON'T expect a horizontally scrolling container to work \u2014 antd documents both, and both are true here.","DON'T hand-roll the placeholder. The height is MEASURED, so it is right at every width and after any re-wrap; a number written once in CSS is wrong at every other width, which is the page-jump bug this component exists to remove."],useCases:["A site or app header that condenses on scroll: the wordmark shrinks to a monogram and the bar loses half its height, driven by `data-affixed` alone.","A table toolbar (search, filters, bulk actions) that stays reachable over a thousand-row list and gains a shadow the moment it starts covering rows.","A form's action footer pinned to the bottom of a long form with `offsetBlockEnd`, released once the real end of the form scrolls into view.","The substrate under `Anchor affix` \u2014 antd specifies Anchor's own `affix` prop as `AffixProps`, so the two are one stack."],related:["Anchor \u2014 takes an `AffixProp` subset as its own `affix` prop and pins its section nav with this.",'PageContainer \u2014 `stickyFooter` / `footerReveal="onScroll"` is the page-level answer; it shares the same `useIntersects` observer this uses.',"FloatButton.BackTop \u2014 the other public scroll-position API, and where `target`'s lazy-getter shape comes from.","Topbar / AppShell \u2014 the app chrome an affixed bar usually sits UNDER; `--affix-inset-block-start` is how it clears it."],example:`import { Affix } from "@godxjp/ui/layout";
2573
2573
  import { Button, Text } from "@godxjp/ui/general";
2574
2574
  import { Flex } from "@godxjp/ui/layout";
2575
2575
 
@@ -2580,7 +2580,7 @@ const [pinned, setPinned] = useState(false);
2580
2580
  <Text weight="medium">{pinned ? "Invoices" : "All invoices, 2026"}</Text>
2581
2581
  <Button size={pinned ? "sm" : "md"}>New invoice</Button>
2582
2582
  </Flex>
2583
- </Affix>`,docPath:"layout/affix.tsx",storyPath:"layout/Affix.stories.tsx",rules:[2,40,44,45]},{name:"Anchor",group:"navigation",tagline:"Ant Design `Anchor` (6.6.5): the in-page section navigation, and the only thing in this library that COMPUTES which section is current. `NavList activeId` takes that answer as a prop. Resolves by antd's rule \u2014 the last section whose edge has crossed a single decision line \u2014 which is a pure function of scroll position and therefore cannot flicker, suppresses itself during the programmatic scroll a click starts, reads the landing hash before any scroll event, and jumps rather than tweens under `prefers-reduced-motion`.",props:[{name:"items",type:"AnchorItemProp[]",description:'antd `items`, in document order. Each is `{ key, href, title, target?, children?, replace?, targetOffsetBlockStart? }` \u2014 antd\'s AnchorItem, field for field, with its per-link `targetOffset` on the logical axis. `children` is ONE level of nesting and is dropped (with a warning) when `direction="horizontal"`, as in antd.'},{name:"direction",type:'"vertical" | "horizontal"',description:'antd `direction`, default `"vertical"`. Horizontal is one scrolling row: the ink rail moves along the block-end edge and nesting is not available.'},{name:"affix",type:"boolean | Omit<AffixProp, 'offsetBlockStart' | 'offsetTop' | 'target' | 'children'>",description:"antd `affix`, default `true` \u2014 literally antd's own `AffixProps` minus the fields Anchor supplies, which is why Affix is the dependency. `false` leaves the nav in the flow."},{name:"bounds",type:"number",description:"antd `bounds`, default `5`. Pixel tolerance added to the decision line."},{name:"value / defaultValue / onValueChange",type:"string / string / (href: string) => void",description:"The active `href`, as the controlled triad. `onValueChange` is antd's `onChange` under this library's name, and it reports the link the SCROLL POSITION resolved (antd's own note) rather than what `getCurrentAnchor` substituted. antd's `onChange` is typed `never` and warns."},{name:"getCurrentAnchor",type:"(activeLink: string) => string",description:"antd `getCurrentAnchor` \u2014 the last word on the highlight, running INSIDE the resolution with no render round-trip. A controlled `value` outranks it."},{name:"offsetBlockStart",type:"number",description:"antd `offsetTop`, on its LOGICAL axis: where the decision line sits, and the distance `Affix` pins the nav at. Default `0`."},{name:"targetOffsetBlockStart",type:"number",description:"antd `targetOffset`, on its LOGICAL axis: where a CLICKED section lands \u2014 the room a pinned header needs. Defaults to `offsetBlockStart`, and (as in antd) it moves the decision line too, so a click can never leave the entry it just selected unselected."},{name:"target",type:"() => Window | HTMLElement | null",description:"gh#890. The scroll box the sections are measured in AND `Affix` pins the nav against \u2014 one function, both halves. `Affix`'s own name and shape (`AffixTargetProp`), the same lazy getter `FloatButton.BackTop.target` already spells here. `null`, or an absent `target`, means the viewport. Wins over `getContainer` when both are given."},{name:"getContainer",type:"() => HTMLElement | Window",description:"antd `getContainer`, default `() => window` \u2014 the scroll box holding the sections. Superseded by `target` (gh#890), which mirrors `Affix`'s own spelling for the identical idea; kept live for a call site written before `target` existed."},{name:"showInkInFixed",type:"boolean",description:"antd `showInkInFixed`, default `false`. Draw the travelling ink even with `affix={false}`; the static rule is always drawn."},{name:"replace",type:"boolean",description:"antd `replace`, default `false`. Replace the hash in history rather than pushing it; `items[].replace` overrides it per entry."},{name:"onClick",type:"(event: React.MouseEvent<HTMLAnchorElement>, item: AnchorItemProp) => void",description:"antd `onClick`, fired before the scroll. A modified click is never hijacked."},{name:"label",type:"string",description:'Accessible name of the <nav> landmark. antd ships an unnamed <div>; a page routinely carries a breadcrumb, a rail and this, so a localized default ("On this page") applies when omitted.'},{name:"onChange / offsetTop / targetOffset",type:"never",description:"NOT props. antd's spellings, kept in the type so arriving from antd's docs is a COMPILE ERROR naming `onValueChange` / `offsetBlockStart` / `targetOffsetBlockStart`, plus a development console.warn."},{name:"id",type:"string",description:"DOM id of the <nav>."},{name:"className",type:"string",description:"Structural class on the <nav>."}],usage:["DO give every target a real `id` and point `href` at it as `#id`. The links are real anchors: middle-clickable, deep-linkable, and correct before JavaScript boots.","DO set `targetOffsetBlockStart` to the height of whatever is pinned above the content, or a clicked section lands under the header. Leave `offsetBlockStart` alone unless the DECISION LINE also needs moving; it follows `targetOffsetBlockStart` by default.","DO use `value` / `onValueChange` when the router owns the current section; use `getCurrentAnchor` only for antd's narrower job of rewriting the resolved link in place.",'DON\'T reach for NavList for this. NavList is ROUTE navigation \u2014 each row is a page the router renders, and its `activeId` is an answer you already have. Anchor\'s entries are fragments of the page being read, which is also why the current one is `aria-current="location"` and not `"page"`.',"DON'T use Tabs either: the sections are all on the page at once and scroll past each other, where a tab panel shows one at a time.","DON'T nest more than one level, and don't nest at all when horizontal \u2014 antd allows neither, and this warns rather than rendering a second row the ink rail cannot follow.","DON'T hand-roll the scrollspy with an IntersectionObserver band. A section taller than the band reports nothing, and with several short sections in the band at once the answer depends on scroll direction; both are why this measures against a line instead."],useCases:["A long settings or policy page whose sections a reader jumps between, with the current one always visible in the rail.","API or product documentation: the on-this-page rail beside the article, tracking the reader down the page.","A marketing landing page's section nav, pinned under the site header via `affix` and `offsetBlockStart`.","A horizontal section bar on a narrow viewport, where a vertical rail has no column to live in."],related:["Affix \u2014 the pin underneath it. antd specifies `Anchor.affix` as `AffixProps`, so the two ship as one stack.","NavList \u2014 ROUTE navigation inside a page; its `activeId` is the answer Anchor computes, for a different kind of destination.","LegalDocumentShell \u2014 carries its own built-in contents rail for the legal-document case; Anchor is the general one, for content the shell does not own.",'Breadcrumb \u2014 where you ARE in the hierarchy (`aria-current="page"`), not where you are on the page.'],example:`import { Anchor } from "@godxjp/ui/navigation";
2583
+ </Affix>`,docPath:"layout/affix.tsx",storyPath:"layout/Affix.stories.tsx",rules:[2,40,44,45]},{name:"Anchor",group:"navigation",tagline:"Ant Design `Anchor` (6.6.5): the in-page section navigation, and the only thing in this library that COMPUTES which section is current. `NavList activeId` takes that answer as a prop. Resolves by antd's rule \u2014 the last section whose edge has crossed a single decision line \u2014 which is a pure function of scroll position and therefore cannot flicker, suppresses itself during the programmatic scroll a click starts, reads the landing hash before any scroll event, and jumps rather than tweens under `prefers-reduced-motion`.",props:[{name:"items",type:"AnchorItemProp[]",description:'antd `items`, in document order. Each is `{ key, href, title, target?, children?, replace?, targetOffsetBlockStart? }` \u2014 antd\'s AnchorItem, field for field, with its per-link `targetOffset` on the logical axis. `children` is ONE level of nesting and is dropped (with a warning) when `direction="horizontal"`, as in antd.'},{name:"direction",type:'"vertical" | "horizontal"',description:'antd `direction`, default `"vertical"`. Horizontal is one scrolling row: the ink rail moves along the block-end edge and nesting is not available.'},{name:"affix",type:"boolean | Omit<AffixProp, 'offsetBlockStart' | 'offsetTop' | 'target' | 'children'>",description:"antd `affix`, default `true` \u2014 literally antd's own `AffixProps` minus the fields Anchor supplies, which is why Affix is the dependency. `false` leaves the nav in the flow."},{name:"bounds",type:"number",description:"antd `bounds`, default `5`. Pixel tolerance added to the decision line."},{name:"value / defaultValue / onValueChange",type:"string / string / (href: string) => void",description:"The active `href`, as the controlled triad. `onValueChange` is antd's `onChange` under this library's name, and it reports the link the SCROLL POSITION resolved (antd's own note) rather than what `getCurrentAnchor` substituted. antd's `onChange` is typed `never` and warns."},{name:"getCurrentAnchor",type:"(activeLink: string) => string",description:"antd `getCurrentAnchor` \u2014 the last word on the highlight, running INSIDE the resolution with no render round-trip. A controlled `value` outranks it."},{name:"offsetBlockStart",type:"number",description:"antd `offsetTop`, on its LOGICAL axis: where the decision line sits, and the distance `Affix` pins the nav at. Default `0`."},{name:"targetOffsetBlockStart",type:"number",description:"antd `targetOffset`, on its LOGICAL axis: where a CLICKED section lands \u2014 the room a pinned header needs. Defaults to `offsetBlockStart`, and (as in antd) it moves the decision line too, so a click can never leave the entry it just selected unselected."},{name:"target",type:"() => Window | HTMLElement | null",description:"gh#890. The scroll box the sections are measured in AND `Affix` pins the nav against \u2014 one function, both halves. `Affix`'s own name and shape (`AffixTargetProp`), the same lazy getter `FloatButton.BackTop.target` already spells here. `null` means the viewport; absent (with no `getContainer`), the nearest block-axis scroller, else the viewport \u2014 `Affix`'s default (gh#984). Wins over `getContainer` when both are given."},{name:"getContainer",type:"() => HTMLElement | Window",description:"antd `getContainer` \u2014 the scroll box holding the sections; omitted \u2192 the nearest block-axis scroller, else the viewport (gh#984). Superseded by `target` (gh#890), which mirrors `Affix`'s own spelling for the identical idea; kept live for a call site written before `target` existed."},{name:"showInkInFixed",type:"boolean",description:"antd `showInkInFixed`, default `false`. Draw the travelling ink even with `affix={false}`; the static rule is always drawn."},{name:"replace",type:"boolean",description:"antd `replace`, default `false`. Replace the hash in history rather than pushing it; `items[].replace` overrides it per entry."},{name:"onClick",type:"(event: React.MouseEvent<HTMLAnchorElement>, item: AnchorItemProp) => void",description:"antd `onClick`, fired before the scroll. A modified click is never hijacked."},{name:"label",type:"string",description:'Accessible name of the <nav> landmark. antd ships an unnamed <div>; a page routinely carries a breadcrumb, a rail and this, so a localized default ("On this page") applies when omitted.'},{name:"onChange / offsetTop / targetOffset",type:"never",description:"NOT props. antd's spellings, kept in the type so arriving from antd's docs is a COMPILE ERROR naming `onValueChange` / `offsetBlockStart` / `targetOffsetBlockStart`, plus a development console.warn."},{name:"id",type:"string",description:"DOM id of the <nav>."},{name:"className",type:"string",description:"Structural class on the <nav>."}],usage:["DO give every target a real `id` and point `href` at it as `#id`. The links are real anchors: middle-clickable, deep-linkable, and correct before JavaScript boots.","DO set `targetOffsetBlockStart` to the height of whatever is pinned above the content, or a clicked section lands under the header. Leave `offsetBlockStart` alone unless the DECISION LINE also needs moving; it follows `targetOffsetBlockStart` by default.","DO use `value` / `onValueChange` when the router owns the current section; use `getCurrentAnchor` only for antd's narrower job of rewriting the resolved link in place.",'DON\'T reach for NavList for this. NavList is ROUTE navigation \u2014 each row is a page the router renders, and its `activeId` is an answer you already have. Anchor\'s entries are fragments of the page being read, which is also why the current one is `aria-current="location"` and not `"page"`.',"DON'T use Tabs either: the sections are all on the page at once and scroll past each other, where a tab panel shows one at a time.","DON'T nest more than one level, and don't nest at all when horizontal \u2014 antd allows neither, and this warns rather than rendering a second row the ink rail cannot follow.","DON'T hand-roll the scrollspy with an IntersectionObserver band. A section taller than the band reports nothing, and with several short sections in the band at once the answer depends on scroll direction; both are why this measures against a line instead."],useCases:["A long settings or policy page whose sections a reader jumps between, with the current one always visible in the rail.","API or product documentation: the on-this-page rail beside the article, tracking the reader down the page.","A marketing landing page's section nav, pinned under the site header via `affix` and `offsetBlockStart`.","A horizontal section bar on a narrow viewport, where a vertical rail has no column to live in."],related:["Affix \u2014 the pin underneath it. antd specifies `Anchor.affix` as `AffixProps`, so the two ship as one stack.","NavList \u2014 ROUTE navigation inside a page; its `activeId` is the answer Anchor computes, for a different kind of destination.","LegalDocumentShell \u2014 carries its own built-in contents rail for the legal-document case; Anchor is the general one, for content the shell does not own.",'Breadcrumb \u2014 where you ARE in the hierarchy (`aria-current="page"`), not where you are on the page.'],example:`import { Anchor } from "@godxjp/ui/navigation";
2584
2584
 
2585
2585
  <Anchor
2586
2586
  offsetBlockStart={64}
@@ -4914,7 +4914,7 @@ A block with no reason is IGNORED and the finding stands. An unclosed block runs
4914
4914
  The class-shaped rules (gap-*/p-*/m-*, bg-<palette>-*, w-[\u2026], pr-*, dark:*) only read class
4915
4915
  expressions \u2014 a className/class attribute, a class-named binding (\`baseClass\`, \`statusStyles\`,
4916
4916
  \`badgeVariants\`) or a cn()/clsx()/cva() call \u2014 so prose that merely spells a utility is not a
4917
- finding and needs no suppression.`,oe=[{id:"dialog-needs-body",severity:"error",category:"composition",standard:null,fix:"Wrap a Dialog/Sheet's middle in <DialogBody>/<SheetBody>. The scroll lives on the body \u2014 the content box is `overflow: hidden` with no max-height \u2014 so an overlay without one clips long content at BOTH ends and takes the footer's buttons with it, leaving Escape as the only way out. It only shows on real data, never on demo data (gh#617)."},{id:"no-utility-spacing",severity:"error",category:"composition",standard:null,fix:"Remove gap-*/p-*/m-* from your own markup; space siblings with <Flex gap> / <ResponsiveGrid>. Page sections are spaced by <PageContainer> (docs/CONSUMER-RULES.md \xA73)."},{id:"no-utility-layout",severity:"error",category:"composition",standard:null,fix:'Replace className="flex \u2026" / "grid \u2026" with <Flex> (row), <Flex direction="col"> (stack) or <ResponsiveGrid columns>.'},{id:"no-hand-rolled-surface",severity:"warn",category:"composition",standard:null,fix:"A rounded+border/bg div is a fake surface \u2014 use Card, Badge, Avatar, ListRow, Descriptions or EmptyState so height, padding and radius come from tokens. A read-only sample of a colour a USER chose is Swatch, which takes that value as a prop (gh#527)."},{id:"sibling-cards-need-flex",severity:"warn",category:"composition",standard:null,fix:'Wrap adjacent <Card>s in <Flex direction="col" gap="lg"> or <ResponsiveGrid>; direct children of PageContainer are spaced by the page already.'},{id:"no-raw-palette-color",severity:"error",category:"tokens",standard:null,fix:"Use semantic tokens (bg-primary, text-muted-foreground), never raw palette (bg-blue-500)."},{id:"no-arbitrary-hex",severity:"error",category:"tokens",standard:null,fix:"No hardcoded hex in className; read design-system color tokens."},{id:"no-arbitrary-spacing",severity:"error",category:"tokens",standard:null,fix:"No p-[13px]/gap-[7px]; use the token scale / <Flex gap> / <PageContainer>."},{id:"no-arbitrary-size",severity:"error",category:"tokens",standard:null,fix:"No w-[37px]/h-[260px]; use token sizes or a sizing prop (min-w-[\u2026] allowed)."},{id:"no-arbitrary-typography",severity:"error",category:"tokens",standard:null,fix:"No text-[20px]/leading-[1.7]; use the golden-ratio type-scale tokens."},{id:"no-arbitrary-radius",severity:"error",category:"tokens",standard:null,fix:"No rounded-[6px]; use rounded-sm/md/lg radius tokens."},{id:"no-off-scale-token-value",severity:"warn",category:"tokens",standard:null,fix:"A design-system knob you override takes a step (style={{ '--card-space-inset': 'var(--space-4)' }}) or a calc() from one (calc(var(--space-4) + 2px)), not a raw 13px. Only axes that HAVE a scale count: space/padding/gap/margin, font-size, radius, icon-size (width/height/size/offset have none yet, so a number there is fine). A value that is genuinely off the grid keeps its literal and says why in place, with a /* scale-exempt: 6px status dot, below --space-1 */ comment on that line or the one above."},{id:"no-dark-color-override",severity:"warn",category:"tokens",standard:null,fix:"Drop dark: color overrides \u2014 semantic tokens already adapt."},{id:"raw-white-black",severity:"warn",category:"tokens",standard:null,fix:"Prefer semantic tokens (text-primary-foreground, bg-background) over raw white/black."},{id:"no-domain-tracking-token",severity:"error",category:"tokens",standard:null,fix:"No package-tracking/domain tokens; use semantic tokens or app theme overrides."},{id:"no-space-xy",severity:"error",category:"tokens",standard:null,fix:"Use <Flex gap> instead of space-x/y-*."},{id:"no-raw-select",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Select> from @godxjp/ui, not a raw <select>."},{id:"no-raw-table",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use the <Table>/<DataTable> family, not a raw <table>."},{id:"no-raw-input",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Input> from @godxjp/ui, not a raw <input>."},{id:"no-raw-textarea",severity:"warn",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Textarea> from @godxjp/ui, not a raw <textarea>."},{id:"no-raw-button",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Button> from @godxjp/ui, not a raw <button>."},{id:"card-manual-padding",severity:"error",category:"composition",standard:null,fix:"Wrap the body in <CardContent>; don't hand-roll padding on <Card>."},{id:"card-needs-content",severity:"error",category:"composition",standard:null,fix:"<Card> body must be in <CardContent> (no padding otherwise); flush only for a full-bleed table."},{id:"bare-control-needs-formfield",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.3.1 \xB7 3.3.2 \xB7 @godxjp/ui FormField (cardinal rule 227)",fix:"Wrap a labelled control in <FormField label=\u2026> \u2014 it owns label\u2194control id wiring, aria/error, AND the field rhythm; never pair a bare <Label> with an <Input>."},{id:"manual-field-error",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 3.3.1",fix:"Use <FormField error=\u2026>, not a hand-rolled <p class='text-destructive'>."},{id:"manual-field-helper",severity:"warn",category:"composition",standard:null,fix:"Use <FormField helper=\u2026>, not a hand-rolled helper <p>."},{id:"status-tone-not-variant",severity:"error",category:"api",standard:null,fix:"Badge/Tag/StatCard status uses tone, not variant (variant is structural)."},{id:"value-callback-on-value-change",severity:"error",category:"api",standard:null,fix:"Abstract value components use onValueChange, not onChange."},{id:"icon-button-needs-name",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 4.1.2 \xB7 1.1.1 \xB7 WAI-ARIA 1.2 \xB7 Accessible Name Computation 1.2",fix:"Name <Button size='icon'> with aria-label={t('\u2026')} OR from content \u2014 a <VisuallyHidden>/sr-only child beside the aria-hidden glyph. Text inside an aria-hidden subtree names nothing."},{id:"img-needs-alt",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 1.1.1 \xB7 HTML Living Standard",fix:"Add alt to every <img> (alt='' if decorative); prefer <Avatar>/<AspectRatio>."},{id:"no-positive-tabindex",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.4.3 \xB7 WAI-ARIA APG",fix:"Use tabIndex 0 or -1 only; never positive \u2014 it breaks focus order."},{id:"hand-rolled-close-glyph",severity:"warn",category:"a11y",standard:"WAI-ARIA 1.2 (dialog) \xB7 WCAG 2.2 SC 4.1.2",fix:"Pass onDismiss to <Alert>, or use <Dialog>/<Sheet>'s built-in labelled close \u2014 not a bare \u2715."},{id:"no-hand-rolled-scrollport",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.1.1 (Keyboard) \xB7 WAI-ARIA 1.2 (group) \xB7 Deque axe-core scrollable-region-focusable",fix:'Replace className="overflow-auto / overflow-y-auto / overflow-x-auto / overflow-scroll" on your own element with <ScrollArea label={t("\u2026")} orientation>, which is the tab stop, the role and the localized name \u2014 and withholds all three while there is nothing to scroll. A browser audit only fails a scrollport whose content has NO focusable child, so the same markup is clean or broken depending on the data; this reads the markup instead (gh#825). overflow-hidden is a clipping box, not a scrollport, and is not flagged.'},{id:"no-emoji-in-ui",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"No emoji in product UI; quiet i18n copy + Lucide icon + Badge tone."},{id:"no-emoji-flag",severity:"warn",category:"i18n",standard:"ISO 3166-1 \xB7 ECMA-402 Intl.DisplayNames \xB7 Unicode UTS #51",fix:"Derive country names from Intl.DisplayNames; no emoji flags."},{id:"hardcoded-currency",severity:"warn",category:"i18n",standard:"ISO 4217 \xB7 ECMA-402 Intl.NumberFormat",fix:"Format money with Intl.NumberFormat({ style: 'currency', currency }), not \xA5{amount}."},{id:"raw-intl-date",severity:"warn",category:"i18n",standard:"ISO 8601 \xB7 IANA tz \xB7 ECMA-402 Intl.DateTimeFormat",fix:"Use formatDate from @godxjp/ui/datetime, not hand-built or locale-default dates."},{id:"no-physical-direction",severity:"warn",category:"rtl",standard:"W3C CSS Logical Properties L1 \xB7 WCAG 2.2 (1.3.2)",fix:"Use logical utilities (ms-/me-/ps-/pe-, start-/end-, text-start/end, border-s/e, rounded-s/e)."},{id:"no-em-dash-in-copy",severity:"warn",category:"copy",standard:"@godxjp/ui reference-design typography",fix:"No em-dash (\u2014) in copy; use a middot \xB7 or two calm sentences."},{id:"lucide-icon-needs-size",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.4.4 \xB7 @godxjp/ui icon scale (--icon-size-*)",fix:'A lucide glyph outside a sizing context draws at its intrinsic 24px. Render it as <Icon as={Lock} size="sm" tone="muted" /> \u2014 the primitive puts it on the --icon-size-* scale and is aria-hidden unless you pass a label.'},{id:"no-hand-rolled-list",severity:"warn",category:"composition",standard:"WAI-ARIA 1.2 (list / listitem) \xB7 HTML Living Standard (ul/ol/li) \xB7 WCAG 2.2 SC 1.3.1",fix:'Build the list as <Flex as="ul" marker="none" direction="col" gap="none"> with <ListRow as="li"> rows \u2014 not a raw <ul>/<ol> (no gap token), not <div role="list">/<div role="listitem">, and never a wrapper around each row: the divider is :not(:last-child) among SIBLINGS, so a row alone in its own wrapper loses it silently (a consumer lost every divider in a settings menu and a dashboard this way). marker="none" keeps the element, the <li> semantics and the gap, and drops the bullet and the --space-5 indent (gh#714). A deliberate exception \u2014 a drag-and-drop Kanban column, an evidence list inside a TableCell \u2014 takes an ui-audit-disable-line that says so.'},{id:"no-hand-rolled-break-anywhere",severity:"warn",category:"composition",standard:"CSS Text 3 \xA75.5 (overflow-wrap) \xB7 WCAG 2.2 SC 1.4.10 (Reflow)",fix:`Replace className="[overflow-wrap:anywhere] break-words whitespace-normal" (or wrap-anywhere) with <Text break="anywhere">, which emits overflow-wrap: anywhere AND releases a table cell's inherited nowrap, so an email, code or id shrinks its column to the viewport. Not whitespace="pre-wrap": its break-word does not lower min-content, so a table cell stays wide (gh#927).`}];function re(e){return e?oe.filter(t=>t.category===e):oe}var le="node node_modules/@godxjp/ui/scripts/visual-audit.mjs <baseUrl> [route \u2026] (optional peers, TESTED range: playwright >=1.55 <2 [1.61.1] + @axe-core/playwright >=4.10 <5 [4.12.1] + axe-core >=4.10 <5 [4.12.1] + a chromium via `playwright install chromium`; --strict for a CI gate, --format json ALWAYS emits valid JSON with a status of ok|partial|error separating infra errors[] from product findings[], --rules to print this catalog)",se=[{id:"css-layers-missing",severity:"error",category:"layout",standard:"@godxjp/ui styles contract (styles / styles/core are the only entries)",fix:"Import `@godxjp/ui/styles` (or `styles/core` without fonts \u2014 86 KB instead of 367 KB gzip, since the bundled @font-face declarations are most of the CSS, gh#971); never cherry-pick *-layout.css \u2014 a missing layer renders naked menus and unsized Select rows."},{id:"control-height-mismatch",severity:"error",category:"layout",standard:"@godxjp/ui control tier (--control-height) \xB7 Nielsen consistency heuristic",fix:"Every control in one row must share --control-height; replace hand-rolled pills with Avatar/Button/Badge, never restyle a control's height."},{id:"sibling-card-gap",severity:"error",category:"layout",standard:"@godxjp/ui spacing scale (docs/SPACING.md)",fix:'Adjacent Cards need one space step between them \u2014 <Flex direction="col" gap>, <ResponsiveGrid>, or direct children of PageContainer.'},{id:"row-content-starved",severity:"warn",category:"layout",standard:"WCAG 2.2 SC 1.4.10 reflow",fix:`A sibling (a w-full SelectTrigger) takes the row's width and truncates its neighbours \u2014 give the Select width="auto" or move it out of the row.`},{id:"axe-violations",severity:"warn",category:"a11y",standard:"WCAG 2.2 A/AA \xB7 WAI-ARIA 1.2 (axe-core engine)",fix:"Fix each axe node \u2014 contrast (1.4.3), name/role/value (4.1.2), ARIA, landmarks. Runs on the REAL DOM, catching what static analysis cannot."},{id:"target-size-min",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.5.8 (24\xD724 AA) \xB7 2.5.5 (44\xD744 AAA)",fix:"Interactive targets must be \u226524\xD724 CSS px; size from the --control-height tier."},{id:"oversaturated-accent",severity:"warn",category:"color",standard:"@godxjp/ui reference-design \u6E0B\u307F (OKLCH chroma \u2264 0.18)",fix:"Desaturate brand/primary surfaces (OKLCH chroma \u2264 0.18); read --primary tokens, no raw vivid bars. The accent @godxjp/ui itself ships is exempt (gh#823) \u2014 this finding is always a colour someone chose."},{id:"emoji-rendered",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"Remove emoji from rendered product text; quiet i18n copy + Lucide icon + Badge tone."},{id:"alert-controls-misplaced",severity:"warn",category:"layout",standard:"@godxjp/ui Alert anatomy \xB7 WAI-ARIA 1.2 \xB7 WCAG 2.2 SC 4.1.2",fix:"Use <Alert>: one leading tone icon, <Alert.Actions> trailing-right normal width, onDismiss \xD7 top-right, one horizontal row."}];function de(e){return e?se.filter(t=>t.category===e):se}var h={name:"@godxjp/ui-mcp",version:"30.7.1",godxUiCompatibility:"30.7.x",description:"Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",type:"module",main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",bin:{"godx-ui-mcp":"./dist/index.js"},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org/",access:"public"},repository:{type:"git",url:"git+https://github.com/godx-jp/godxjp-ui.git",directory:"mcp"},homepage:"https://github.com/godx-jp/godxjp-ui/tree/main/mcp#readme",license:"Apache-2.0",scripts:{build:"tsup",dev:"tsup --watch",start:"node dist/index.js",inspect:"npx @modelcontextprotocol/inspector node dist/index.js","type-check":"tsc --noEmit",test:"vitest run",prepublishOnly:"npm run build"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.4.3"},devDependencies:{"@types/node":"^22.10.0",tsup:"^8.5.1",typescript:"^6.0.3",vitest:"^4.1.6"},keywords:["mcp","model-context-protocol","godxjp","ui","design-system","react","claude","cursor"],author:"GoDX (https://godx.jp)",bugs:{url:"https://github.com/godx-jp/godxjp-ui/issues"}};var H=[{name:"list_skills",description:"List every design/taste skill bundled by this MCP (id + name + whenToUse + section ids). Use FIRST to discover skills; then `get_skill_section` to drill in.",inputSchema:{type:"object",properties:{}}},{name:"list_primitives",description:"List every @godxjp/ui primitive/composite/shell (group + tagline per entry). Optionally filter by group. Then `get_component` for one's full API.",inputSchema:{type:"object",properties:{group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{name:"list_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:"Fuzzy-search primitives by name / tagline / prop. Returns ranked matches.",inputSchema:{type:"object",properties:{query:{type:"string"}},required:["query"]}},{name:"get_frame_coverage",description:"Verified preview-contract coverage for a component (issue #163). Answers 'is this state actually PROVEN?' \u2014 returns, per contract dimension (variants, tones, sizes, shapes, density, controlled/uncontrolled ownership, disabled/read-only/loading/empty/error/success, async retry/cancel/offline, responsive viewport matrix, RTL, long/localized content, keyboard/focus, accessible name/description/error, reduced motion / coarse touch), whether an EXECUTED case proves it (covered), whether nothing proves it (UNTESTED), or whether it cannot exist (not-applicable, with a reason). UNTESTED IS NOT A PASS: never infer that a component supports a state because an example renders. Call this before telling a user a component 'supports' anything. Omit `name` for the repo-wide summary and the tracked known gaps.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Public export name (e.g. 'Button', 'DataTable', 'CardFooter'). Omit for the repo-wide coverage summary."}}}},{name:"lint_jsx",description:"Heuristic check of a JSX snippet for common violations \u2014 raw `<button>` / `<input>`, `color='error'` on Tag/Badge, missing aria-label, missing source.code override on stories with cell renderers (rule 34), etc.",inputSchema:{type:"object",properties:{jsx:{type:"string"}},required:["jsx"]}}],Re=new Set(H.map(e=>e.name));function Ie(e=j()){let t=h.godxUiCompatibility??h.version,a=`@godxjp/ui-mcp ${h.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let o=e.source==="node_modules"?"read from node_modules at answer time":"from GODX_UI_VERSION at launch \u2014 node_modules/@godxjp/ui not resolved";return`${a} \u2014 installed @godxjp/ui ${e.version} (${o})`}function ze(e=j()){let t=e?L(e.version):null,a=L(h.version);return!e||!t||!a?null:He(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${h.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog is BEHIND the package and may be missing props and components that exist. Do not conclude from this answer that a prop is unavailable. Restart the session so the server relaunches on the installed version (run \`npx @godxjp/ui sync-rules\` first if the project's .mcp.json still pins an older @godxjp/ui-mcp).`:t.major===a.major?null:`\u26A0\uFE0F MAJOR MISMATCH: this server is @godxjp/ui-mcp ${h.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog may describe components that do not exist in the installed package. Pin the MCP to @godxjp/ui-mcp@${e.version} (\`npx @godxjp/ui sync-rules\` updates the project's .mcp.json; a registration outside the project needs \`claude mcp remove <key>\`), then restart the agent.`}async function me(e,t){let a=await Pe(e,t);if(!Re.has(e))return a;let o=j(),n=ze(o);return`${Ie(o)}
4917
+ finding and needs no suppression.`,oe=[{id:"dialog-needs-body",severity:"error",category:"composition",standard:null,fix:"Wrap a Dialog/Sheet's middle in <DialogBody>/<SheetBody>. The scroll lives on the body \u2014 the content box is `overflow: hidden` with no max-height \u2014 so an overlay without one clips long content at BOTH ends and takes the footer's buttons with it, leaving Escape as the only way out. It only shows on real data, never on demo data (gh#617)."},{id:"no-utility-spacing",severity:"error",category:"composition",standard:null,fix:"Remove gap-*/p-*/m-* from your own markup; space siblings with <Flex gap> / <ResponsiveGrid>. Page sections are spaced by <PageContainer> (docs/CONSUMER-RULES.md \xA73)."},{id:"no-utility-layout",severity:"error",category:"composition",standard:null,fix:'Replace className="flex \u2026" / "grid \u2026" with <Flex> (row), <Flex direction="col"> (stack) or <ResponsiveGrid columns>.'},{id:"no-hand-rolled-surface",severity:"warn",category:"composition",standard:null,fix:"A rounded+border/bg div is a fake surface \u2014 use Card, Badge, Avatar, ListRow, Descriptions or EmptyState so height, padding and radius come from tokens. A read-only sample of a colour a USER chose is Swatch, which takes that value as a prop (gh#527)."},{id:"sibling-cards-need-flex",severity:"warn",category:"composition",standard:null,fix:'Wrap adjacent <Card>s in <Flex direction="col" gap="lg"> or <ResponsiveGrid>; direct children of PageContainer are spaced by the page already.'},{id:"no-raw-palette-color",severity:"error",category:"tokens",standard:null,fix:"Use semantic tokens (bg-primary, text-muted-foreground), never raw palette (bg-blue-500)."},{id:"no-arbitrary-hex",severity:"error",category:"tokens",standard:null,fix:"No hardcoded hex in className; read design-system color tokens."},{id:"no-arbitrary-spacing",severity:"error",category:"tokens",standard:null,fix:"No p-[13px]/gap-[7px]; use the token scale / <Flex gap> / <PageContainer>."},{id:"no-arbitrary-size",severity:"error",category:"tokens",standard:null,fix:"No w-[37px]/h-[260px]; use token sizes or a sizing prop (min-w-[\u2026] allowed)."},{id:"no-arbitrary-typography",severity:"error",category:"tokens",standard:null,fix:"No text-[20px]/leading-[1.7]; use the golden-ratio type-scale tokens."},{id:"no-arbitrary-radius",severity:"error",category:"tokens",standard:null,fix:"No rounded-[6px]; use rounded-sm/md/lg radius tokens."},{id:"no-off-scale-token-value",severity:"warn",category:"tokens",standard:null,fix:"A design-system knob you override takes a step (style={{ '--card-space-inset': 'var(--space-4)' }}) or a calc() from one (calc(var(--space-4) + 2px)), not a raw 13px. Only axes that HAVE a scale count: space/padding/gap/margin, font-size, radius, icon-size (width/height/size/offset have none yet, so a number there is fine). A value that is genuinely off the grid keeps its literal and says why in place, with a /* scale-exempt: 6px status dot, below --space-1 */ comment on that line or the one above."},{id:"no-dark-color-override",severity:"warn",category:"tokens",standard:null,fix:"Drop dark: color overrides \u2014 semantic tokens already adapt."},{id:"raw-white-black",severity:"warn",category:"tokens",standard:null,fix:"Prefer semantic tokens (text-primary-foreground, bg-background) over raw white/black."},{id:"no-domain-tracking-token",severity:"error",category:"tokens",standard:null,fix:"No package-tracking/domain tokens; use semantic tokens or app theme overrides."},{id:"no-space-xy",severity:"error",category:"tokens",standard:null,fix:"Use <Flex gap> instead of space-x/y-*."},{id:"no-raw-select",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Select> from @godxjp/ui, not a raw <select>."},{id:"no-raw-table",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use the <Table>/<DataTable> family, not a raw <table>."},{id:"no-raw-input",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Input> from @godxjp/ui, not a raw <input>."},{id:"no-raw-textarea",severity:"warn",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Textarea> from @godxjp/ui, not a raw <textarea>."},{id:"no-raw-button",severity:"error",category:"composition",standard:"HTML Living Standard (WHATWG)",fix:"Use <Button> from @godxjp/ui, not a raw <button>."},{id:"card-manual-padding",severity:"error",category:"composition",standard:null,fix:"Wrap the body in <CardContent>; don't hand-roll padding on <Card>."},{id:"card-needs-content",severity:"error",category:"composition",standard:null,fix:"<Card> body must be in <CardContent> (no padding otherwise); flush only for a full-bleed table."},{id:"bare-control-needs-formfield",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.3.1 \xB7 3.3.2 \xB7 @godxjp/ui FormField (cardinal rule 227)",fix:"Wrap a labelled control in <FormField label=\u2026> \u2014 it owns label\u2194control id wiring, aria/error, AND the field rhythm; never pair a bare <Label> with an <Input>."},{id:"manual-field-error",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 3.3.1",fix:"Use <FormField error=\u2026>, not a hand-rolled <p class='text-destructive'>."},{id:"manual-field-helper",severity:"warn",category:"composition",standard:null,fix:"Use <FormField helper=\u2026>, not a hand-rolled helper <p>."},{id:"status-tone-not-variant",severity:"error",category:"api",standard:null,fix:"Badge/Tag/StatCard status uses tone, not variant (variant is structural)."},{id:"value-callback-on-value-change",severity:"error",category:"api",standard:null,fix:"Abstract value components use onValueChange, not onChange."},{id:"icon-button-needs-name",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 4.1.2 \xB7 1.1.1 \xB7 WAI-ARIA 1.2 \xB7 Accessible Name Computation 1.2",fix:"Name <Button size='icon'> with aria-label={t('\u2026')} OR from content \u2014 a <VisuallyHidden>/sr-only child beside the aria-hidden glyph. Text inside an aria-hidden subtree names nothing."},{id:"img-needs-alt",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 1.1.1 \xB7 HTML Living Standard",fix:"Add alt to every <img> (alt='' if decorative); prefer <Avatar>/<AspectRatio>."},{id:"no-positive-tabindex",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.4.3 \xB7 WAI-ARIA APG",fix:"Use tabIndex 0 or -1 only; never positive \u2014 it breaks focus order."},{id:"hand-rolled-close-glyph",severity:"warn",category:"a11y",standard:"WAI-ARIA 1.2 (dialog) \xB7 WCAG 2.2 SC 4.1.2",fix:"Pass onDismiss to <Alert>, or use <Dialog>/<Sheet>'s built-in labelled close \u2014 not a bare \u2715."},{id:"no-hand-rolled-scrollport",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.1.1 (Keyboard) \xB7 WAI-ARIA 1.2 (group) \xB7 Deque axe-core scrollable-region-focusable",fix:'Replace className="overflow-auto / overflow-y-auto / overflow-x-auto / overflow-scroll" on your own element with <ScrollArea label={t("\u2026")} orientation>, which is the tab stop, the role and the localized name \u2014 and withholds all three while there is nothing to scroll. A browser audit only fails a scrollport whose content has NO focusable child, so the same markup is clean or broken depending on the data; this reads the markup instead (gh#825). overflow-hidden is a clipping box, not a scrollport, and is not flagged.'},{id:"no-emoji-in-ui",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"No emoji in product UI; quiet i18n copy + Lucide icon + Badge tone."},{id:"no-emoji-flag",severity:"warn",category:"i18n",standard:"ISO 3166-1 \xB7 ECMA-402 Intl.DisplayNames \xB7 Unicode UTS #51",fix:"Derive country names from Intl.DisplayNames; no emoji flags."},{id:"hardcoded-currency",severity:"warn",category:"i18n",standard:"ISO 4217 \xB7 ECMA-402 Intl.NumberFormat",fix:"Format money with Intl.NumberFormat({ style: 'currency', currency }), not \xA5{amount}."},{id:"raw-intl-date",severity:"warn",category:"i18n",standard:"ISO 8601 \xB7 IANA tz \xB7 ECMA-402 Intl.DateTimeFormat",fix:"Use formatDate from @godxjp/ui/datetime, not hand-built or locale-default dates."},{id:"no-physical-direction",severity:"warn",category:"rtl",standard:"W3C CSS Logical Properties L1 \xB7 WCAG 2.2 (1.3.2)",fix:"Use logical utilities (ms-/me-/ps-/pe-, start-/end-, text-start/end, border-s/e, rounded-s/e)."},{id:"no-em-dash-in-copy",severity:"warn",category:"copy",standard:"@godxjp/ui reference-design typography",fix:"No em-dash (\u2014) in copy; use a middot \xB7 or two calm sentences."},{id:"lucide-icon-needs-size",severity:"warn",category:"composition",standard:"WCAG 2.2 SC 1.4.4 \xB7 @godxjp/ui icon scale (--icon-size-*)",fix:'A lucide glyph outside a sizing context draws at its intrinsic 24px. Render it as <Icon as={Lock} size="sm" tone="muted" /> \u2014 the primitive puts it on the --icon-size-* scale and is aria-hidden unless you pass a label.'},{id:"no-hand-rolled-list",severity:"warn",category:"composition",standard:"WAI-ARIA 1.2 (list / listitem) \xB7 HTML Living Standard (ul/ol/li) \xB7 WCAG 2.2 SC 1.3.1",fix:'Build the list as <Flex as="ul" marker="none" direction="col" gap="none"> with <ListRow as="li"> rows \u2014 not a raw <ul>/<ol> (no gap token), not <div role="list">/<div role="listitem">, and never a wrapper around each row: the divider is :not(:last-child) among SIBLINGS, so a row alone in its own wrapper loses it silently (a consumer lost every divider in a settings menu and a dashboard this way). marker="none" keeps the element, the <li> semantics and the gap, and drops the bullet and the --space-5 indent (gh#714). A deliberate exception \u2014 a drag-and-drop Kanban column, an evidence list inside a TableCell \u2014 takes an ui-audit-disable-line that says so.'},{id:"no-hand-rolled-break-anywhere",severity:"warn",category:"composition",standard:"CSS Text 3 \xA75.5 (overflow-wrap) \xB7 WCAG 2.2 SC 1.4.10 (Reflow)",fix:`Replace className="[overflow-wrap:anywhere] break-words whitespace-normal" (or wrap-anywhere) with <Text break="anywhere">, which emits overflow-wrap: anywhere AND releases a table cell's inherited nowrap, so an email, code or id shrinks its column to the viewport. Not whitespace="pre-wrap": its break-word does not lower min-content, so a table cell stays wide (gh#927).`}];function re(e){return e?oe.filter(t=>t.category===e):oe}var le="node node_modules/@godxjp/ui/scripts/visual-audit.mjs <baseUrl> [route \u2026] (optional peers, TESTED range: playwright >=1.55 <2 [1.61.1] + @axe-core/playwright >=4.10 <5 [4.12.1] + axe-core >=4.10 <5 [4.12.1] + a chromium via `playwright install chromium`; --strict for a CI gate, --format json ALWAYS emits valid JSON with a status of ok|partial|error separating infra errors[] from product findings[], --rules to print this catalog)",se=[{id:"css-layers-missing",severity:"error",category:"layout",standard:"@godxjp/ui styles contract (styles / styles/core are the only entries)",fix:"Import `@godxjp/ui/styles` (or `styles/core` without fonts \u2014 86 KB instead of 367 KB gzip, since the bundled @font-face declarations are most of the CSS, gh#971); never cherry-pick *-layout.css \u2014 a missing layer renders naked menus and unsized Select rows."},{id:"control-height-mismatch",severity:"error",category:"layout",standard:"@godxjp/ui control tier (--control-height) \xB7 Nielsen consistency heuristic",fix:"Every control in one row must share --control-height; replace hand-rolled pills with Avatar/Button/Badge, never restyle a control's height."},{id:"sibling-card-gap",severity:"error",category:"layout",standard:"@godxjp/ui spacing scale (docs/SPACING.md)",fix:'Adjacent Cards need one space step between them \u2014 <Flex direction="col" gap>, <ResponsiveGrid>, or direct children of PageContainer.'},{id:"row-content-starved",severity:"warn",category:"layout",standard:"WCAG 2.2 SC 1.4.10 reflow",fix:`A sibling (a w-full SelectTrigger) takes the row's width and truncates its neighbours \u2014 give the Select width="auto" or move it out of the row.`},{id:"axe-violations",severity:"warn",category:"a11y",standard:"WCAG 2.2 A/AA \xB7 WAI-ARIA 1.2 (axe-core engine)",fix:"Fix each axe node \u2014 contrast (1.4.3), name/role/value (4.1.2), ARIA, landmarks. Runs on the REAL DOM, catching what static analysis cannot."},{id:"target-size-min",severity:"warn",category:"a11y",standard:"WCAG 2.2 SC 2.5.8 (24\xD724 AA) \xB7 2.5.5 (44\xD744 AAA)",fix:"Interactive targets must be \u226524\xD724 CSS px; size from the --control-height tier."},{id:"oversaturated-accent",severity:"warn",category:"color",standard:"@godxjp/ui reference-design \u6E0B\u307F (OKLCH chroma \u2264 0.18)",fix:"Desaturate brand/primary surfaces (OKLCH chroma \u2264 0.18); read --primary tokens, no raw vivid bars. The accent @godxjp/ui itself ships is exempt (gh#823) \u2014 this finding is always a colour someone chose."},{id:"emoji-rendered",severity:"warn",category:"i18n",standard:"Unicode UTS #51 \xB7 WCAG 2.2 SC 1.1.1",fix:"Remove emoji from rendered product text; quiet i18n copy + Lucide icon + Badge tone."},{id:"alert-controls-misplaced",severity:"warn",category:"layout",standard:"@godxjp/ui Alert anatomy \xB7 WAI-ARIA 1.2 \xB7 WCAG 2.2 SC 4.1.2",fix:"Use <Alert>: one leading tone icon, <Alert.Actions> trailing-right normal width, onDismiss \xD7 top-right, one horizontal row."}];function de(e){return e?se.filter(t=>t.category===e):se}var h={name:"@godxjp/ui-mcp",version:"30.8.0",godxUiCompatibility:"30.8.x",description:"Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",type:"module",main:"./dist/index.js",module:"./dist/index.js",types:"./dist/index.d.ts",bin:{"godx-ui-mcp":"./dist/index.js"},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org/",access:"public"},repository:{type:"git",url:"git+https://github.com/godx-jp/godxjp-ui.git",directory:"mcp"},homepage:"https://github.com/godx-jp/godxjp-ui/tree/main/mcp#readme",license:"Apache-2.0",scripts:{build:"tsup",dev:"tsup --watch",start:"node dist/index.js",inspect:"npx @modelcontextprotocol/inspector node dist/index.js","type-check":"tsc --noEmit",test:"vitest run",prepublishOnly:"npm run build"},dependencies:{"@modelcontextprotocol/sdk":"^1.29.0",zod:"^4.4.3"},devDependencies:{"@types/node":"^22.10.0",tsup:"^8.5.1",typescript:"^6.0.3",vitest:"^4.1.6"},keywords:["mcp","model-context-protocol","godxjp","ui","design-system","react","claude","cursor"],author:"GoDX (https://godx.jp)",bugs:{url:"https://github.com/godx-jp/godxjp-ui/issues"}};var H=[{name:"list_skills",description:"List every design/taste skill bundled by this MCP (id + name + whenToUse + section ids). Use FIRST to discover skills; then `get_skill_section` to drill in.",inputSchema:{type:"object",properties:{}}},{name:"list_primitives",description:"List every @godxjp/ui primitive/composite/shell (group + tagline per entry). Optionally filter by group. Then `get_component` for one's full API.",inputSchema:{type:"object",properties:{group:{type:"string",enum:["general","layout","data-display","data-entry","feedback","navigation","composites","shell","providers"]}}}},{name:"list_utilities",description:'List every NON-component public export of @godxjp/ui \u2014 hooks, helper functions and constants (cn, formatDate, formatCurrency, toast, useDebouncedValue, buttonVariants, CHART_COLORS, SHOW_PARENT \u2026). Reach for this before hand-writing a className merger, a date/money formatter, a debounce hook or a chart palette: two products in this org each re-implemented `cn` because it could not be found. Optionally filter by kind. Then `get_component name="<name>"` for its signature, usage and example.',inputSchema:{type:"object",properties:{kind:{type:"string",enum:["hook","function","value"],description:"hook = only legal inside a component body; function = callable anywhere; value = a constant to read."}}}},{name:"list_patterns",description:"List every canonical copy-paste code pattern (signup-form, settings-page, data-table-page, async-data-state, confirm-destructive, \u2026); common aliases resolve too. Use before `get_pattern`.",inputSchema:{type:"object",properties:{}}},{name:"list_anti_ai_tells",description:"List every AI-tell pattern to AVOID (optionally by category). Use to self-audit a design before shipping; then `get_anti_ai_tell` for the fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["visual","layout","copy","interaction","imagery","structure"]}}}},{name:"list_redesign_checks",description:"List the redesign audit checklist (50+ checks; optionally by category). Use when auditing an existing project; then `get_redesign_check` for a symptom's fix.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["typography","color-surface","layout","interactivity","content","components","iconography","code-quality","omissions"]}}}},{name:"list_audit_rules",description:"List the LOCAL static ui-audit rules (scripts/ui-audit.mjs) to run BEFORE any visual review \u2014 each cites the standard it enforces (WCAG/WAI-ARIA/Intl/ISO/IANA/CSS-Logical) + a fix + the run command. Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["tokens","composition","api","a11y","i18n","rtl","copy"]}}}},{name:"list_visual_checks",description:"List the RUNTIME visual-audit checks (scripts/visual-audit.mjs \u2014 Playwright + axe-core) to run against the RUNNING app: contrast/ARIA (axe), target size, rendered-accent chroma, DOM emoji, banner layout. Needs a browser (vs list_audit_rules, static). Optionally by category.",inputSchema:{type:"object",properties:{category:{type:"string",enum:["a11y","color","i18n","layout"]}}}},{name:"get_anti_ai_tell",description:"Fetch ONE anti-AI-tell \u2014 full body + concrete fix. Use after `list_anti_ai_tells`.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Exact tell name from list_anti_ai_tells."}},required:["name"]}},{name:"get_redesign_check",description:"Fetch redesign check(s) matching a symptom snippet. Returns full fix + UI note. Use after `list_redesign_checks`.",inputSchema:{type:"object",properties:{symptom:{type:"string",description:"Fragment of the symptom text (e.g. 'Inter everywhere' / '100vh')."}},required:["symptom"]}},{name:"get_skill_section",description:"Fetch ONE section of ONE skill \u2014 token-efficient. E.g. `skill='soft', section='double-bezel'`. Use after `list_skills` narrowed the relevant skill + section.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Skill id (e.g. 'soft', 'minimalist', 'taste')."},section:{type:"string",description:"Section id within that skill."}},required:["skill","section"]}},{name:"get_component",description:"Full guide for one @godxjp/ui component \u2014 import path, props/types/defaults, HOW to use it (DO/DON'T), WHEN to reach for it (use cases), related components (don't reinvent/confuse), a copy-paste example, story path, and cardinal rules. Use this before hand-rolling anything. Design-token knobs are listed compactly (name+default); pass `verbose:true` for what each token controls.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Component name (e.g. 'Button', 'DataTable')."},verbose:{type:"boolean",description:"Include the full design-token table with a 'what it controls' description per token. Default false (compact token+default only) to save context."}},required:["name"]}},{name:"get_pattern",description:"Full code snippet for one canonical pattern \u2014 copy-paste-ready.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Pattern slug (use list_patterns first)."}},required:["name"]}},{name:"get_rule",description:"Read one cardinal rule from CLAUDE.md (by number) OR all if no number.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Rule number (1-N)."}}}},{name:"get_vocab",description:"Read shared prop-vocabulary type (`SizeProp`, `StatusProp`, `ColorProp`, `LoadingProp`, etc.) OR all if no name.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Vocab type name."}}}},{name:"get_tokens",description:"Read design tokens, optionally filtered by tier category (primitive / semantic / component).",inputSchema:{type:"object",properties:{category:{type:"string",enum:["primitive","semantic","component"]}}}},{name:"list_consumer_skills",description:"List the design skills relevant to an app-dev BUILDING WITH @godxjp/ui (audience consumer/both). Hides core library-maintenance skills. START HERE if you import @godxjp/ui and want guidance (design-to-page, compose-a-screen, taste, \u2026). Returns id + name + whenToUse + section ids.",inputSchema:{type:"object",properties:{}}},{name:"get_consumer_skill",description:"Fetch ONE section of ONE consumer-facing skill. Same as get_skill_section but refuses core-only skills (steers app-devs away from library-maintenance material). Use after list_consumer_skills / route_consumer_task.",inputSchema:{type:"object",properties:{skill:{type:"string",description:"Consumer skill id (e.g. 'design-to-page', 'compose-a-screen')."},section:{type:"string",description:"Section id within that skill."}},required:["skill"]}},{name:"route_consumer_task",description:"Natural-language task \u2192 consumer skill+section pointer. Like route_task but only points to consumer-facing skills (never core library-maintenance). Use FIRST when you're building an app with @godxjp/ui.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"draft_bug_report",description:"When @godxjp/ui ITSELF is at fault (missing token, a primitive lacking the controlled-vocabulary prop, a real a11y/behaviour bug, a wrong catalog example) and you cannot follow a rule \u2014 DON'T fake a workaround. This drafts a detailed GitHub issue body + a copy-paste `gh issue create` command so you can report it. Prints the command only; never runs gh.",inputSchema:{type:"object",properties:{summary:{type:"string",description:"One-line title of the bug / blocked rule."},repro:{type:"string",description:"Minimal steps or code to reproduce."},expected:{type:"string",description:"What SHOULD happen (per the rule/spec)."},actual:{type:"string",description:"What actually happens."},component:{type:"string",description:"Affected component name, if any (links to get_component)."},rule:{type:"number",description:"Cardinal rule number that can't be followed, if any."},version:{type:"string",description:"Installed @godxjp/ui version (e.g. '12.1.0')."},env:{type:"string",description:"Environment (browser/OS/framework), if relevant."}},required:["summary"]}},{name:"check_compatibility",description:"Report whether the @godxjp/ui version installed in the target project matches THIS catalog (which describes one release train). A mismatched minor means the props/tokens/patterns may describe a build they never installed (#140). Pass the installed version (`npm ls @godxjp/ui`); call it at the START of a consumer session.",inputSchema:{type:"object",properties:{version:{type:"string",description:"Installed @godxjp/ui version in the target project, e.g. '16.10.0'. Omit to just read the catalog's own version + compatible range."}}}},{name:"route_task",description:"Natural-language task \u2192 skill+section pointer (e.g. 'design a premium agency hero' \u2192 soft/vibe-archetypes). Use FIRST when you don't know which skill applies.",inputSchema:{type:"object",properties:{task:{type:"string",description:"Describe what you want to build."}},required:["task"]}},{name:"suggest_primitive",description:"Use case \u2192 primitive recommendation. E.g. 'confirm a destructive delete' \u2192 DangerZone pattern + Dialog suggestion.",inputSchema:{type:"object",properties:{use_case:{type:"string"}},required:["use_case"]}},{name:"search_components",description:"Fuzzy-search primitives by name / tagline / prop. Returns ranked matches.",inputSchema:{type:"object",properties:{query:{type:"string"}},required:["query"]}},{name:"get_frame_coverage",description:"Verified preview-contract coverage for a component (issue #163). Answers 'is this state actually PROVEN?' \u2014 returns, per contract dimension (variants, tones, sizes, shapes, density, controlled/uncontrolled ownership, disabled/read-only/loading/empty/error/success, async retry/cancel/offline, responsive viewport matrix, RTL, long/localized content, keyboard/focus, accessible name/description/error, reduced motion / coarse touch), whether an EXECUTED case proves it (covered), whether nothing proves it (UNTESTED), or whether it cannot exist (not-applicable, with a reason). UNTESTED IS NOT A PASS: never infer that a component supports a state because an example renders. Call this before telling a user a component 'supports' anything. Omit `name` for the repo-wide summary and the tracked known gaps.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Public export name (e.g. 'Button', 'DataTable', 'CardFooter'). Omit for the repo-wide coverage summary."}}}},{name:"lint_jsx",description:"Heuristic check of a JSX snippet for common violations \u2014 raw `<button>` / `<input>`, `color='error'` on Tag/Badge, missing aria-label, missing source.code override on stories with cell renderers (rule 34), etc.",inputSchema:{type:"object",properties:{jsx:{type:"string"}},required:["jsx"]}}],Re=new Set(H.map(e=>e.name));function Ie(e=j()){let t=h.godxUiCompatibility??h.version,a=`@godxjp/ui-mcp ${h.version} (catalog for @godxjp/ui ${t})`;if(!e)return a;let o=e.source==="node_modules"?"read from node_modules at answer time":"from GODX_UI_VERSION at launch \u2014 node_modules/@godxjp/ui not resolved";return`${a} \u2014 installed @godxjp/ui ${e.version} (${o})`}function ze(e=j()){let t=e?L(e.version):null,a=L(h.version);return!e||!t||!a?null:He(t,a)>0?`\u26A0\uFE0F SERVER OLDER THAN INSTALLED PACKAGE: this server is @godxjp/ui-mcp ${h.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog is BEHIND the package and may be missing props and components that exist. Do not conclude from this answer that a prop is unavailable. Restart the session so the server relaunches on the installed version (run \`npx @godxjp/ui sync-rules\` first if the project's .mcp.json still pins an older @godxjp/ui-mcp).`:t.major===a.major?null:`\u26A0\uFE0F MAJOR MISMATCH: this server is @godxjp/ui-mcp ${h.version}, the project has @godxjp/ui ${e.version} installed \u2014 this catalog may describe components that do not exist in the installed package. Pin the MCP to @godxjp/ui-mcp@${e.version} (\`npx @godxjp/ui sync-rules\` updates the project's .mcp.json; a registration outside the project needs \`claude mcp remove <key>\`), then restart the agent.`}async function me(e,t){let a=await Pe(e,t);if(!Re.has(e))return a;let o=j(),n=ze(o);return`${Ie(o)}
4918
4918
  ${n?`${n}
4919
4919
  `:""}
4920
4920
  ${a}`}async function Pe(e,t){switch(e){case"list_skills":return Le();case"list_primitives":return ve(t.group);case"list_utilities":return Ze(t.kind);case"list_patterns":return Ge();case"list_anti_ai_tells":return _e(t.category);case"list_redesign_checks":return Ye(t.category);case"list_audit_rules":return We(t.category);case"list_visual_checks":return qe(t.category);case"get_anti_ai_tell":return Ke(String(t.name??""));case"get_redesign_check":return $e(String(t.symptom??""));case"get_skill_section":return ye(String(t.skill??""),String(t.section??""));case"get_component":return et(String(t.name??""),t.verbose===!0);case"get_pattern":return ot(String(t.name??""));case"get_rule":return nt(typeof t.number=="number"?t.number:void 0);case"get_vocab":return it(t.name==null?void 0:String(t.name));case"get_tokens":return rt(t.category);case"list_consumer_skills":return Fe();case"get_consumer_skill":return Me(String(t.skill??""),String(t.section??""));case"route_consumer_task":return pe(String(t.task??""),{consumerOnly:!0});case"draft_bug_report":return Be(t);case"check_compatibility":return fe(t.version==null?void 0:String(t.version));case"route_task":return pe(String(t.task??""));case"suggest_primitive":return st(String(t.use_case??""));case"search_components":return lt(String(t.query??""));case"get_frame_coverage":return at(t.name===void 0?void 0:String(t.name));case"lint_jsx":return dt(String(t.jsx??""));default:return`Unknown tool: ${e}`}}function Le(){let e=`# Available skills (${T.length})
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui-mcp",
3
- "version": "30.7.1",
4
- "godxUiCompatibility": "30.7.x",
3
+ "version": "30.8.0",
4
+ "godxUiCompatibility": "30.8.x",
5
5
  "description": "Model Context Protocol server for @godxjp/ui \u2014 gives Claude Code / Codex CLI / Cursor / any MCP-aware agent live access to the component catalog, prop vocabulary, design tokens, 45 cardinal rules, copy-paste-ready patterns, 12 design / taste skills synthesised from Leonxlnx/taste-skill, 20+ anti-AI-tell patterns, and a 50-check redesign audit \u2014 token-efficient (list \u2192 drill-down).",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",