feat(design-systems): the master sheet — purpose tokens, not per-element values
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 42s
CI & Build / Build & push image (push) Successful in 34s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 42s
CI & Build / Build & push image (push) Successful in 34s
Operator's new requirement (#2299, architecture in #2296): a design system does not just hold tokens, it generates and manages a master CSS sheet. That settles the milestone's open "authority mechanism" question — the record is authoritative because the stylesheet comes out of it. **The sheet is shaped by purpose and styles no elements.** It declares custom properties, grouped by what they mean, and contains no `.btn-primary`, no `table`, no `input`. That is the design, not a shortcut: a sheet that styled elements would restate the same handful of values once per element and grow with the UI, where purpose-named values are stated once and reused. Components live as SNIPPETS that reference these names — a surface that already exists and already carries prose, locations, drift checks, merge and write-path recall. A token named after an element (`--fs-button-bg`) is the smell that the two have been mixed; a purpose name (`--fs-action-primary`) is reused across all of them. Alongside the CSS the endpoint returns what the text cannot say for itself: which tokens are still valueless, and which VALUES are declared under more than one name. The second is the operator's "reuse consistent values" constraint made checkable — and it reports rather than refuses, because a design system legitimately aligns colours on purpose ("Success = Moss, by design") and only a human knows which case it is. Mode maps to selector the way the codebase already does it: base on the root selector, every other mode layered on `[data-theme="…"]`. The root selector is a PARAMETER — #251 recorded that a container-scoped preview cannot use `:root`, so hardcoding it would have made the generator useless to the preview surface. A token the rulebook names but states no value for is emitted as a commented-out declaration IN ITS GROUP rather than dropped. Its absence is the finding, and a comment puts that finding where the reader already is. Values are validated, not escaped, and this is a real boundary rather than tidiness: design systems are shareable records (rule #47), so `red; } body { display: none` in a system shared with you would otherwise inject CSS into your page. A value containing `{ } ; @ < >`, a comment delimiter or a newline is REFUSED and rendered as a comment saying so — rejecting beats stripping, since a partially-sanitised value is one the operator never wrote and the sheet's whole claim is that it is the record. Not in scope, and deliberately: serving this as the app's actual stylesheet. Generating and exposing a sheet is reversible; swapping theme.css for a generated one is not, and it should be an explicit call rather than a side effect.
This commit is contained in:
@@ -139,6 +139,34 @@ async def delete_design_system(design_system_id: int) -> dict:
|
||||
return {"message": f"Design system {design_system_id} deleted."}
|
||||
|
||||
|
||||
async def get_design_system_stylesheet(
|
||||
design_system_id: int,
|
||||
root_selector: str = ":root",
|
||||
) -> dict:
|
||||
"""The master CSS sheet a design system generates.
|
||||
|
||||
Purpose tokens only — this sheet declares what values MEAN and styles no
|
||||
elements. Components (buttons, tables, input schemes) are SNIPPETS that
|
||||
reference these names, so a value is stated once and reused rather than
|
||||
restated per element. Reach for this when you need the tokens a snippet is
|
||||
allowed to use.
|
||||
|
||||
Also returns `valueless` (tokens the system names but has no value for) and
|
||||
`duplicates` (values declared under more than one name — a deliberate alias,
|
||||
or one idea recorded twice).
|
||||
|
||||
Args:
|
||||
design_system_id: The system to render.
|
||||
root_selector: Selector for the base layer. Defaults to `:root`; pass a
|
||||
container selector to scope the sheet to a preview region.
|
||||
"""
|
||||
uid = current_user_id()
|
||||
result = await ds_svc.stylesheet_for_system(uid, design_system_id, root_selector)
|
||||
if result is None:
|
||||
raise ValueError(f"design system {design_system_id} not found")
|
||||
return result
|
||||
|
||||
|
||||
async def import_design_system_from_rulebook(
|
||||
design_system_id: int,
|
||||
rulebook_id: int,
|
||||
@@ -307,6 +335,7 @@ def register(mcp) -> None:
|
||||
resolve_design_system,
|
||||
update_design_system,
|
||||
delete_design_system,
|
||||
get_design_system_stylesheet,
|
||||
import_design_system_from_rulebook,
|
||||
create_design_token,
|
||||
list_design_tokens,
|
||||
|
||||
Reference in New Issue
Block a user