Skip to content

onsystem@0.9.0

Choose a tag to compare

@dgesteves-release dgesteves-release released this 21 Oct 12:44
· 39 commits to main since this release
6eccaea

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.ts files (@dub/ui from 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-color warns when a chart-* token stands in for a status color outside a chart, and init says which status colors the theme has no token for.
  • MCP: search_components says when nothing clearly matches instead of returning a poor best guess, list_components filters and collapses icons, and get_tokens sets 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 after git mv every finding of the file was new to check . and to the GitHub Action with only-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. check says which file it took for moved, and --prune-baseline records 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; check alone 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 check which 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. check without the Action still accepts findings in file order.

    The GitHub Action runs the onsystem the project installed, found in working-directory or 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 runs npx 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-color warns on a chart-* token used outside a chart, such as text-chart-2 on 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 fail check or 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 as chartData, or is named for charts), in an element inside an <svg>, a <figure> or a role="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-sidebar on a shell or header), are not reported.

    onsystem init says 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-name takes a button's name from a <label htmlFor> (or the design system's <Label htmlFor>) whose value is the button's id, 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 compiled dist/ and type declarations alone now gets every rule: its components, props, variant values, parts and the elements they render are read from its .d.ts files, as MUI's are. Before, such an app got the token rules and check said No design-system components found: the component rules did not run. This applies to a package that declares its onsystem config (set up with init), whatever its name; to one without a config that is named like a design system in the app's own npm scope (@acme/ui for @acme/web); and, in any app, to the dependency the app's config names as its importPath: { "importPath": "@dub/ui" } in an app on @dub/ui from 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 .tsx sources the app reads is read from them as before; one that publishes src/ beside exports into dist/ is read from its declarations. A package with no entry of its own is read from each subpath it exports (@acme/ui/button). inspect lists it on its library line (Design-system package (@acme/ui 1.0.0): 10 components from its type declarations), inspect --explain says so, or what would make it read, "libraries": false turns it off, and the app's @import of 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's ClassProp are kept, since its class-variance-authority/dist/types import 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 no ref; props that depend on a generic component through a conditional type are left open, so they are not reported as unknown; and Tabs next to Tab, or a lone CheckboxGroup next to Checkbox, is no longer taken for its part. In a bundle's one index.d.ts, parts go by name only in families of two or more, and icons have none: @dub/ui's UserCheck is not a part of User, nor ButtonTooltip of Button.

  • #198 6bd19f5 - The MCP tools answer better where the design system is thin, large, or has no component for what the agent wants.

    • search_components says when no component clearly matches: "a dropdown menu to pick a country" in a design system with no select used to come back as CardAction, 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 result weak: true in the structured content.
    • A shadcn/ui component without JSDoc, laid out as npx shadcn add writes it (Badge in components/ui/badge.tsx: the file named for it, in a ui folder), 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.), in list_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's src/sheet.tsx, gets no borrowed description. A component with no description is listed without one, not as "No description."
    • list_components takes query, kind ("component" or "icon") and limit. 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 under icons and leaves out empty variants and subcomponents. kind: "icon" lists them one by one.
    • get_component lists 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.Header answers with CardHeader and "There is no Card.Header in this design system: write <CardHeader>."
    • get_tokens lists 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 the build-with-design-system prompt say what to do for a status color the theme has no token for: add a token or keep the Tailwind color as check_ui says, and never use a chart-* or sidebar-* token for it. The prompt no longer asks the agent to follow examples a component does not have.
    • check_ui with code takes a path to a .tsx, .jsx, .ts or .js file as the file the code is for, as filename: it was ignored, so the code was checked as snippet.tsx, without the overrides for that file. Any other path, such as a project folder, picks the project at a monorepo root, and the code is still checked as snippet.tsx. A filename that is not a script file says to pass the .tsx path the code is for, or to leave it out.
    • Library API: searchComponents and DesignSystem.search follow 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 with weak: true.

Patch Changes

  • #195 169ff41 - The postcss dependency now requires 8.5.30 or later (it was ^8.5.29). 8.5.30 fixes a broken source map when PostCSS escapes </style>; onsystem only parses stylesheets and writes no source maps, so what check, the MCP tools and the ESLint plugin report does not change.