Repository navigation
onsystem@0.9.0
onsystem 0.9.0 reads design systems published as compiled packages, keeps baselines right when files move, and gives agents clearer MCP answers.
- An app on a design-system package installed as
dist/plus type declarations now gets every rule: components, props and variants come from its.d.tsfiles (@dub/uifrom npm gives 427 components). - The baseline follows a renamed or moved file, and in the GitHub Action a copied baselined line is reported where it was added. The Action runs the onsystem version the project installed, so the lockfile decides; without an install it runs its own version as before.
no-hardcoded-colorwarns when achart-*token stands in for a status color outside a chart, andinitsays which status colors the theme has no token for.- MCP:
search_componentssays when nothing clearly matches instead of returning a poor best guess,list_componentsfilters and collapses icons, andget_tokenssets chart and sidebar colors apart.
Minor Changes
-
#192
eeb3af0- The baseline follows a file that is renamed or moved. Its entries are keyed by path, so aftergit mvevery finding of the file was new tocheck .and to the GitHub Action withonly-changed-lines: false, and nothing was said about the entries left under the old path. Now a file with no entries of its own, new or not, takes over those of a file that no longer exists when at least half of its findings match them, and half of them match its findings, as git counts a rename from 50% similarity. A rename that changes only the case of a name counts too, also on macOS and Windows, where the old spelling still opens the file.checksays which file it took for moved, and--prune-baselinerecords the new path. Each file that no longer exists is taken over by one file at most, so copies of a file are still new, and a finding the move adds is still reported. In the GitHub Action, a file the pull request did not change keeps the entries it took over, so a copy the pull request adds is the new one, even when the rename was merged without--prune-baseline;checkalone prefers the file whose findings match the old entries most closely, then a file that kept the old name, then one in the old folder. The entries of deleted files in the folders a run checks now count in the "no longer occurs" hint.The GitHub Action tells
checkwhich lines a pull request changed, and the baseline accepts the findings on the other lines first. A pull request that copied a baselined line above the original passed before: the baseline accepted the copy, and the original, reported instead, was on a line the pull request did not change. Now the copy is reported, on the line it was added, and fails the check.checkwithout the Action still accepts findings in file order.The GitHub Action runs the onsystem the project installed, found in
working-directoryor the nearest folder above it up to the repository root, so the version the lockfile pins checks the pull request, and the log says when it is not the action's own version. Without an install, it runsnpx onsystem@<the action's version>as before. With an install, the action's results now follow the installed version, so this can change the result of a job that passed before: an older install can have fewer rules, and one older than this release accepts baselined findings in file order, whatever lines the pull request changed. A newer one can find more. -
#193
b8e0853-no-hardcoded-colorwarns on achart-*token used outside a chart, such astext-chart-2on a green "Connected" label in a theme with no success color. The class is a token, so it was counted as clean, but it changes with the chart palette and does not say what a status color says: in benchmark v2's two tasks that ask for a small green label in such a theme, all 24 runs with onsystem's skill, MCP server and hook together used a chart token for the green, and 0 of 24 without onsystem did. The warning does not failcheckor block the hook, and has no fix: it says to add a status token for a status color (--success, as docs/tokens.md#status-colors shows) or to use the token that fits. Chart tokens are left alone in a file that draws a chart (it imports a chart library, renders a tag such as<ChartContainer>or<BarChart>, declares a name such aschartData, or is named for charts), in an element inside an<svg>, a<figure>or arole="img", and everywhere when the design system's own components use them outside a chart. The real-world corpus has no such finding; sidebar tokens, which apps use for their frame (bg-sidebaron a shell or header), are not reported.onsystem initsays which of success, warning and info the theme has no color for, after the dry run, with a link to the CSS that adds them.icon-button-accessible-nametakes a button's name from a<label htmlFor>(or the design system's<Label htmlFor>) whose value is the button'sid, as for<label htmlFor={id}>Autopilot</label>next to<button id={id} role="switch">. A button is a labelable element, so that label is its accessible name, and the button was reported without one. -
#194
a5eafef- An app on a design-system package installed from a registry as compileddist/and type declarations alone now gets every rule: its components, props, variant values, parts and the elements they render are read from its.d.tsfiles, as MUI's are. Before, such an app got the token rules andchecksaidNo design-system components found: the component rules did not run.This applies to a package that declares its onsystem config (set up withinit), whatever its name; to one without a config that is named like a design system in the app's own npm scope (@acme/uifor@acme/web); and, in any app, to the dependency the app's config names as itsimportPath:{ "importPath": "@dub/ui" }in an app on@dub/uifrom npm reads its 427 components. A kit from another scope named like one (@sanity/ui,@react-email/components) is not read unless the config names it, and a package whose.tsxsources the app reads is read from them as before; one that publishessrc/besideexportsintodist/is read from its declarations. A package with no entry of its own is read from each subpath it exports (@acme/ui/button).inspectlists it on itslibraryline (Design-system package (@acme/ui 1.0.0): 10 components from its type declarations),inspect --explainsays so, or what would make it read,"libraries": falseturns it off, and the app's@importof its stylesheets brings its tokens.Reading declarations also got more exact for MUI and any package: a capitalised export is a component only when it renders (a function returning a string, or a class without
render, is not); variants that tsup inlines with cva'sClassPropare kept, since itsclass-variance-authority/dist/typesimport now resolves by path when the app's"moduleResolution": "bundler"does not; a function component's element comes from its DOM attributes when it takes noref; props that depend on a genericcomponentthrough a conditional type are left open, so they are not reported as unknown; andTabsnext toTab, or a loneCheckboxGroupnext toCheckbox, is no longer taken for its part. In a bundle's oneindex.d.ts, parts go by name only in families of two or more, and icons have none:@dub/ui'sUserCheckis not a part ofUser, norButtonTooltipofButton. -
#198
6bd19f5- The MCP tools answer better where the design system is thin, large, or has no component for what the agent wants.search_componentssays when no component clearly matches: "a dropdown menu to pick a country" in a design system with no select used to come back asCardAction, best first, because its description mentions a menu. A result now matches clearly when a word of the query is in its name, or when it has more than half of the query's words (itself or through a synonym). When some do, the others are left out; when none does, the answer starts "No component clearly matches", lists the nearest and marks each resultweak: truein the structured content.- A shadcn/ui component without JSDoc, laid out as
npx shadcn addwrites it (Badgeincomponents/ui/badge.tsx: the file named for it, in auifolder), is described by what shadcn/ui's component of that name is for, said as shadcn/ui's (shadcn/ui's Badge: A small label for a status, a count or a category.), inlist_components,get_component, resources and the search index, so "status label" finds Badge first in a stock app. A component of the same name elsewhere, such as a design system'ssrc/sheet.tsx, gets no borrowed description. A component with no description is listed without one, not as "No description." list_componentstakesquery,kind("component"or"icon") andlimit. Icons, the components that render an<svg>, are named on one line when there are five or more from one import, or from one folder for an icon set with a module per icon (components/icons/check.tsx, each named with its module), instead of one entry each, in the text and in the structured content, which has them undericonsand leaves out emptyvariantsandsubcomponents.kind: "icon"lists them one by one.get_componentlists the parts before the props, cuts a prop's description longer than 160 characters to its first sentence (the structured content keeps it all), and says so when the name asked for is not how the design system writes it:Card.Headeranswers with CardHeader and "There is noCard.Headerin this design system: write<CardHeader>."get_tokenslists chart and sidebar colors (and other families one part of the UI uses) under their own headings, after the other colors:## chart (5): for charts only, not for status colors. The server instructions and thebuild-with-design-systemprompt say what to do for a status color the theme has no token for: add a token or keep the Tailwind color ascheck_uisays, and never use achart-*orsidebar-*token for it. The prompt no longer asks the agent to follow examples a component does not have.check_uiwithcodetakes apathto a .tsx, .jsx, .ts or .js file as the file the code is for, asfilename: it was ignored, so the code was checked assnippet.tsx, without theoverridesfor that file. Any otherpath, such as a project folder, picks the project at a monorepo root, and the code is still checked assnippet.tsx. Afilenamethat is not a script file says to pass the .tsx path the code is for, or to leave it out.- Library API:
searchComponentsandDesignSystem.searchfollow the same floor. When some results match clearly, they return only those, so a query can return fewer results than before; when none does, they return the nearest, each withweak: true.