[NO-ISSUE] feat(webkit)!: adoption toolkit (in-package) + prop-vocabulary guardrails + canonical prop renames#717
Draft
HerbertJulio wants to merge 69 commits into
Draft
[NO-ISSUE] feat(webkit)!: adoption toolkit (in-package) + prop-vocabulary guardrails + canonical prop renames#717HerbertJulio wants to merge 69 commits into
HerbertJulio wants to merge 69 commits into
Conversation
…e adoption toolkit
…alog, lint, mcp, cli) Catalog generator: parse slot Scope/Notes columns correctly; detect compounds by spec structure so dropdown/paginator classify as compounds with tree-shakeable -root and sub-components get a parent; refine kindFromTarget. Add ./dropdown-root and ./paginator-root exports. Ignore the generated catalog.json in prettier so the drift gate is stable. eslint-plugin: resolve either published package name (@aziontech/webkit or .dev), derive the import prefix from the catalog, and warn (not silently disable) when no catalog resolves; scope no-hardcoded-color so short hex in non-style strings (anchors/ids) is not flagged; cover export-from and dynamic import() in no-barrel; correct the icon-font rule guidance. Add .releaserc, README, engines and test devDeps. webkit-mcp: stop misclassifying sibling @aziontech/webkit-* packages; emit runnable empty literals for required array/object props; read server version from package.json; report treeShakeable honestly. Add README and engines. webkit-cli: document and ship the correct command (webkit-cli init); refuse to overwrite a malformed package.json/.mcp.json; write eslint.config.mjs; husky v9 hook + prepare script; wire stylelint .vue/.scss custom syntax and detect an existing stylelint config; reject unknown flags. Add README and engines. Adds unit tests for every new behavior (44 total).
…est/drift job One publish workflow per new package (eslint-plugin-webkit, stylelint-config-webkit, webkit-mcp, webkit-cli), cloned from package-webkit.yml. Add a governance 'toolkit' job that runs the four unit-test suites and the catalog drift check, and include catalog.json in webkit's semantic-release git assets.
…ules no-deep-internal-import and valid-import-path (only when a single unambiguous candidate exists) now declare meta.fixable and apply the catalog-verified replacement on `eslint --fix`. no-barrel-import verifies each guessed per-subpath against the catalog and only offers the split suggestion when all resolve, so it never proposes an invalid import.
…+ version reporting `webkit-cli doctor` reads the project and reports OK/WARN/FAIL for: catalog resolvable, eslint/stylelint config, .mcp.json webkit server, husky prepare script + pre-commit hook, theme import, and resolved dependency versions (warns on `latest` pins). Read-only; exits non-zero on any FAIL so it works as a CI setup gate. Exposes the shared init predicates (read/firstExisting/readJsonStrict + config-candidate constants) for reuse.
… MCP tool build-catalog now emits a positive `tokens` inventory (CSS custom properties unioned from the theme's generated globals.css across channels, grouped by segment, plus the semantic typography classes) alongside the deny `tokenRules`. The MCP surfaces it via a new list_tokens tool (group index, or a group's tokens by category) — closing the GUIDE loop "don't hardcode #hex → use THIS token". Deterministic + fail-safe; drift-check stays stable.
…workspaces Records the four new workspace packages and their deps (@modelcontextprotocol/sdk, zod, postcss-html, postcss-scss) so `pnpm install --frozen-lockfile` (CI, incl. the toolkit job) passes.
…h/webkit (no new packages)
The eslint plugin, stylelint config, MCP server and CLI now ship INSIDE the existing
@aziontech/webkit package instead of as four new npm packages:
- src moved to packages/webkit/src/{eslint-plugin,stylelint-config,mcp,cli} + cli-templates/
- exports: ./eslint-plugin, ./stylelint-config; bins: webkit (init/doctor), webkit-mcp
- MCP deps (@modelcontextprotocol/sdk, zod) are optionalDependencies; eslint/stylelint/
vue-eslint-parser are optional peers so UI consumers stay lean
- init writes @aziontech/webkit/eslint-plugin + /stylelint-config and runs the MCP via
'npx -p @aziontech/webkit webkit-mcp'; 'npx @aziontech/webkit init' now works
- deleted the 4 package manifests/.releaserc + publish workflows; the toolkit node:test
suites moved to packages/webkit/test/** (test:toolkit); governance runs them + catalog:check
No new package published; nothing lost. 52 toolkit tests green; init + ESLint e2e verified.
… into @aziontech/webkit
build-catalog extracts the spec's Purpose + When-to-use / When-NOT-to-use / Related / Best-practices sections into each catalog entry (empty until backfilled). MCP get_component returns them, a new get_best_practices tool exposes the guidance subset, and suggest_component scores against Purpose/useWhen so sibling picks (Dialog vs Drawer, Badge vs Tag) resolve by intent.
Comment on lines
+135
to
+136
| const text = String(section) | ||
| .replace(/<!--[\s\S]*?-->/g, '') |
Comment on lines
+148
to
+149
| return String(section) | ||
| .replace(/<!--[\s\S]*?-->/g, '') |
…oken tokens.md links enforce-component-create.mjs called skillReferencedInTranscript (undefined; the function is pipelineReferencedInTranscript) → it threw and failed open, so the 'run the spec pipeline first' gate never blocked. Also repoint the dangling ./tokens.md links in no-invention/migration/ dependencies to the real catalog doc (.claude/docs/DESIGN.md § Animations).
… rules
validate-spec-compliance: block forbidden variant-prop names (variant/appearance/intent → kind),
is/has boolean prefixes, and camelCase (non-kebab) event names.
validate-tokens: block JS class presets (const *Classes = {}/[]/computed), component-local <style>
blocks, component-local @Keyframes, arbitrary animate-[…], and hardcoded duration/ease/delay-[…].
Both fire only on NEW matches (baseline diff) so existing components are grandfathered; verified
no false positives on button/input-text/badge and a clean sample.
… + consumer rules Animations: build-catalog now emits tokens.animations (semantic utilities ∪ primitive --animate-*); validate-spec-compliance blocks any animate-* not in it, pointing to /add-animation, which scaffolds the utility+keyframes in semantic/animations.js and records a Theme gap (never a component-local @Keyframes, never DESIGN.md). Consumer rules: no-deprecated-component (blocks importing a component the catalog marks deprecated → replacedBy) and prefer-webkit-component (steers off foreign UI libs like PrimeVue). Catalog also carries deprecated/replacedBy from spec frontmatter. 57 toolkit tests green.
Template gains optional When-to-use / When-NOT-to-use / Related / Best-practices sections (build-catalog already extracts them; not required by the validator, so existing specs keep passing). Backfilled with real content the sibling groups where selection is hardest: badge/tag/chip, dialog/drawer, input-text/textarea/input-number. Checksums recomputed so the edited specs stay tamper-consistent; catalog regenerated (MCP get_best_practices/suggest now answer 'badge vs tag', 'dialog vs drawer').
…-vocab-style # Conflicts: # .specs/chip.md # .specs/textarea.md # packages/webkit/package.json # pnpm-lock.yaml
…heck Bind "what we suggest to the AI" and "what the pipeline blocks" to one definition: - .claude/hooks/_lib/standards.mjs — single registry pairing every .claude/rules standard with its enforcement (write-time hook / lint / CI ratchet) or an explicit reviewGated flag - authoring-checks.mjs exposes STANDARD_BY_CHECK linking each mechanized check to its rule - test/standards/invariant.test.mjs (runs in the CI toolkit job) fails when a rule has no gate, a gate has no rule, a standard is silently unenforced, or the write-time hook and the CI ratchet stop sharing the same engine
Lista item a item cada rule, hook, lint, skill e agent, com o que valida, exemplos tabelados ❌/✅ (criação e implementação) e a garantia fonte-única + meta-check.
Kept as a personal reference (not a shipped repo artifact) per request.
Nothing out of standard is a mere warning: the recommended and performance presets promote every rule to `error`, so a consumer using the design system off-pattern fails its lint instead of getting a skippable warning. BREAKING CHANGE: consumers on the `recommended`/`performance` presets now get errors (not warnings) for no-hardcoded-color, prefer-tree-shakeable-root, no-whole-icon-set-import, prefer-webkit-component, prefer-define-model, and no-style-override.
Model review as a first-class blocking surface: a standard is enforced automatically (hook/lint/CI) and/or by mandatory review (the PR cannot merge without the 2 required approvals). Remove `reviewGated` — nothing is advisory. The invariant test now requires every standard to have at least one enforcement surface.
Add `scope: 'general' | 'webkit'` to every standard — a clear separation between the construction patterns that ship to consuming projects (general) and the rules specific to authoring the design system itself (webkit). Export GENERAL_STANDARDS / WEBKIT_STANDARDS. The invariant test now requires every standard to declare a valid scope.
One page for consumers to see every pattern: Part A (building a component by hand — the general patterns, wrong vs. correct) and Part B (using a webkit component — the consumer rules), with a rendered Mermaid flow of how enforcement blocks the merge.
…und, accurate requirements Replace the stale README (WebkitPlugin/list-data-table no longer exist) with a getting started modeled on best-in-class DS docs: quick start with AI (init + MCP), install, theme CSS wiring, first component, Storybook playground, the all-error lint preset, and terminal exploration (doctor, webkit-mcp). Requirements corrected to Vue 3.5+ (useId).
…lder structure Add the Foundations token table (color/typography/spacing/shape/shadow/motion, use vs never — semantic spacing scale per DESIGN.md), the one-component-one-folder structure, the fixed script-setup order, and a getting-started pointer. Fix the MCP identifier to npx webkit-mcp.
.claude/README.md — the entry-point map of the governance system (folder layout, where each concern lives, the single-source flow). .claude/rules/README.md — index of the 23 rules with scope (general/webkit) and enforcement, as the human-readable summary of standards.mjs. The invariant test ignores README.md when enumerating rule docs.
…xamples The examples taught the primitive scale (--spacing-2/-3/-4/-1) that DESIGN.md forbids in webkit components. Rewritten to the semantic tokens (--spacing-xs/-sm/-md/-xxs) that the components actually use — so no example anywhere shows a token the hooks would block.
Replace the contributor-onboarding page with a consumer getting started modeled on best-in-class DS docs: quick start with AI (init + MCP), install, theme CSS, first component, the all-error lint preset, and terminal exploration — with a short contributor section at the end. Mirrors packages/webkit/README.md.
… the init bundle The consumer bundle now carries the blocking guidance, not only usage tips: - rules/webkit-style-override.md — never restyle a webkit component with class/style (the no-style-override lint blocks it as error); compose in slots, use props, or a styleSeam component - rules/webkit-construction-standards.md — the scope:general standards distilled for components the consumer builds by hand (defineModel, typed props/emits/slots, composables, data-* styling, root element, states, a11y, testid, deprecation) - CLAUDE.md fragment gains both directives; plan + tests updated - templates migrated off the primitive spacing scale (--spacing-4 → --spacing-md)
… examples Prettier's html formatter lowercased <Button>/<Dialog> to native elements, inverting the example's meaning (a native button MAY take a class). Guard the fences with prettier-ignore so the webkit tags stay PascalCase.
One definition, three enforcement surfaces. The authoring-checks engine moves into the
package (src/eslint-plugin/authoring-checks.js) and is now consumed by:
- the design system's write-time hook (via a _lib re-export shim)
- the design system's CI ratchet
- NEW webkit/authoring-standards ESLint rule (error in every preset) — blocks the
consumer at commit (husky) and in their CI: manual modelValue+update:modelValue,
runtime defineProps({})/defineEmits([]), <slot> without defineSlots, composables
returning reactive() or authored as .js, bare @deprecated
The init bundle now carries the full scope:general standards as consumer rules
(webkit-{v-model,props,prop-vocabulary,emits,slots,composables,styling,
component-structure,root-element,component-states,accessibility,testid,deprecation}.md),
with webkit-construction-standards.md as the index. Standards registry records the new
lint surface; the invariant test asserts all three surfaces share the engine.
BREAKING CHANGE: the recommended/strict presets now include webkit/authoring-standards
as error; consumer code with those patterns fails lint.
STYLEGUIDE.md is the programmer's base reference and the exact same rule set the AI pipeline receives: 22 sections covering all 23 standards (foundations/tokens, naming, file organization, props, prop vocabulary, v-model, emits, slots, composables, styling, root element, states, accessibility, testid, deprecation, imports/tree-shaking + bundle budget, compound API, dependencies, spec-first authoring, storybook, releases/git), each with the rule, its concrete decisions, wrong/correct examples, and the gate that blocks it — closing with the enforcement map (one engine, three surfaces). Linked from README and GUIDELINES (which stays as the one-page digest).
Renders packages/webkit/docs/STYLEGUIDE.md verbatim via a raw import (single source, zero drift), placed right after Get Started in the sidebar; Get Started now points to it.
… "Style Guide" title - MDX docs pages (Get Started, Style Guide) now switch with the light/dark toolbar: withThemeByClassName only runs as a story decorator, so preview.js mirrors the theme global onto <html> via a GLOBALS_UPDATED channel listener - class-keyed docs styles in preview.css theme the sbdocs surface, text, tables, inline code, and blockquotes for both azion-light and azion-dark - docs hyperlinks were colorSecondary #585C6D (unreadable on the dark canvas) — now the Azion orange in dark and a darker orange on light - sidebar/tab title renamed Styleguide → "Style Guide"
… bypass the hook validate-tokens' checks (hex/palette/raw typography, class presets, <style>, local @Keyframes, arbitrary motion) previously only ran as a write-time hook inside the AI pipeline — a human pushing from their editor bypassed them, leaving the standard review-only in CI. Extract the 17 checks into a shared engine (src/eslint-plugin/token-checks.js, hook imports via a _lib shim) and run them repo-wide in the check-authoring ratchet with the frozen-baseline mechanism (74 token entries grandfathered; any NEW violation fails the PR). Standards registry records the new CI surface for styling and root-element.
…y gap closed Extract the validate-spec-compliance checks (no-invention, prop/event vocabulary, naming, defaults drift, testid, animations-vs-spec/catalog) into a shared engine (_lib/spec-compliance-checks.mjs); the PostToolUse hook becomes a thin wrapper and the CI ratchet now runs the same checks repo-wide with the frozen baseline (32 spec entries grandfathered). With this, every standard's mechanizable slice has a CI-facing gate: an editor push that never ran the hooks can no longer merge off-spec, off-vocabulary, off-token, or off-standard code. Registry updated (6 standards gain the ci surface).
…dard has a CI-facing gate Extract the "Show code" checks into _lib/story-source-checks.mjs (hook becomes a thin wrapper) and run them repo-wide over apps/storybook/src in the check-authoring ratchet (existing story debt frozen in the baseline). Registry updated: storybook-source and migration gain ci:check-authoring; dependencies records its real CI gate (forbidden libs are uninstalled — any import fails vue-tsc/build). With this, 23/23 standards block in CI or consumer lint — an editor push can no longer bypass any write-time hook.
…talog never ran The toolkit job's three steps filtered @aziontech/webkit.dev, but the package was renamed to @aziontech/webkit when the toolkit was folded in — pnpm --filter with no match exits 0, so catalog drift, the toolkit/invariant tests, and the authoring ratchet were a green no-op in CI. Point the filters at the real package name so the gates actually gate.
…s 'changes' The changes filter only watched packages/webkit/** and .specs/** — a PR touching only .claude/hooks/** (the shared engines + standards registry), .claude/rules/**, or apps/storybook/** (the ratchet's story scan) skipped the toolkit job entirely. Widen the filter, and include the 'changes' job itself in the governance-check results map so the gate no longer passes when change detection fails.
…ce_all
Audit findings, both reproduced live: (1) validate-tokens scanned only the edit
fragments, so a forbidden token split across two edits ('bg-red-' + '-500') passed the
hook; it now reconstructs the resulting file like its siblings. (2) All three
reconstructing hooks modeled Edit as a single first-occurrence replace and ignored
replace_all, so removing every occurrence of a must-have (e.g. defineSlots) in one
replace_all edit evaded the negative checks.
Audit findings: (1) the story scan's walk() missed .stories.tsx/jsx/mjs that STORY_RE
accepts; (2) plain-Set baseline let a SECOND violation of an already-baselined id in the
same file evade — the diff is now a multiset and scanTokens emits one entry per match;
(3) deleting/renaming a spec evaporated every baselined entry as 'fixed' — the ratchet
now requires a spec (missing-spec violation) via collectSpecViolations({ requireSpec });
(4) the spec resolver only matched components/<cat>/<name>/<file>.vue, so nested
sub-component folders, flat components (avatar/tag/overline), and compositions whose
root is <name>-root.vue (tab-view, navigation-menu) received ZERO spec checks on both
surfaces — all three layouts now resolve, and <name>-root.vue counts as the root.
Baseline regenerated: 391 entries (the newly covered surfaces frozen as known debt).
…name Audit findings: (1) the init-generated eslint.config.mjs could not parse the TypeScript SFCs the standards mandate — it now wires @typescript-eslint/parser (added to the dev deps); (2) a pre-existing non-husky "prepare" script silently left the hooks inert — init now advises how to chain it instead; (3) the CLI help still described the old recommended preset; (4) prefer-define-model's message pointed at a DS-internal rule path consumers don't have; (5) webkit-mcp's runtime deps lived in optionalDependencies (an omit=optional install broke the server) — moved to dependencies, error message fixed; (6) apps/storybook still depended on the ghost @aziontech/webkit.dev and aliased onto it — renamed to @aziontech/webkit, alias removed, lockfile regenerated (it could not even re-resolve while the ghost existed). BREAKING CHANGE: @modelcontextprotocol/sdk and zod are now regular dependencies of @aziontech/webkit.
…, and orphan lints The invariant only asserted engine-sharing for authoring-checks — the token, spec, and story engines could silently fork (and 'ci' enforcers were free-form strings, the exact failure mode that let the toolkit job no-op on a ghost package name). It now asserts all four engines are shared hook↔ratchet, validates every ci enforcer against a known-gate whitelist, and fails when a shipped eslint rule is claimed by no standard. Registry: styling claims no-hardcoded-color/no-style-override, imports claims the tree-shaking and icon-set lints.
Audit drift pass: bundle-budget.md and accessibility.md claimed gates that do not run yet (size-limit job, axe) — both now state pending status honestly; the STYLEGUIDE "Enforced by" lines and rules/README "Blocks via" column gain the CI ratchet surfaces that landed after they were written; .claude/README counts 11 lint rules and describes the four shared engines.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three things, all inside the existing
@aziontech/webkitpackage (no new packages published):Branch is merged up to
dev(aligned to avoid conflicts).1. Adoption toolkit — folded into
@aziontech/webkit(no new packages)Everything ships inside the existing package as subpaths + bins, over one source of truth:
catalog.json— generated frompackage.json#exports+.specs(version-locked, regenerated at release). Every tool reads this one file, so nothing drifts from the installed version.@aziontech/webkit/eslint-plugin(8 rules:valid-import-path,no-deep-internal-import,no-barrel-import,no-whole-icon-set-import,no-hardcoded-color,prefer-tree-shakeable-root,no-deprecated-component,prefer-webkit-component,no-style-override) +@aziontech/webkit/stylelint-config.npx -p @aziontech/webkit webkit-mcp, 10 tools) + a Claude Code bundle, wired bynpx @aziontech/webkit init/ verified bydoctor. MCP deps areoptionalDependencies.2. Prop-vocabulary guardrails (
.claude/)A single dictionary —
.claude/hooks/_lib/prop-vocabulary.mjs(documented in.claude/rules/prop-vocabulary.md, surfaced to the MCP viacatalog.vocabulary) — enforced byvalidate-spec-complianceon everyWrite/Edit:variant/appearance/intent/headerVariant/mediaKind/cardStyle→kind,status→severity,dismissable/closeable→dismissible,heading/header→title,isToggled→modelValue); nois/hasprefix; positive booleans (hidden→visible, …);size=small|medium|large(order enforced, noxs/sm/md/lg/xl).<x>-changeis blocked whenupdate:<x>exists (usev-model/@update:<x>; a distinct commit event is a barechange).withDefaults.no-style-override(consumer eslint): flagsclass/:class/style/:styleon a webkit component tag — with an opt-instyle_seamescape hatch andoptions.allow(slot content / composition is never flagged).Propsinterfaces and?: () =>slots.3. Canonical prop renames (⚠️ breaking — major bump)
cardStyle→kindmediaKind→kindheaderVariant→headerKind/variant→kindisToggled→modelValue,type→kind,isFocused→focusedcloseable/dismissable→dismissible(light-dismiss;closablereserved for the X-button — Message/Toast/TabViewItem keep it)heading/header→titlevalue→label(slot-fallback text)status→severity(positive→success)hidden→visible(inverted)Redundant echo events removed (use
v-model/@update:*):value-change(CodeBlock/TabView/NavigationMenu),page-change(Paginator),change(SegmentedButton). Kept: InputNumberchange(commit-on-blur) and Calendarmonth-change(navigation) — genuinely distinct.Deferred (intentional): ToastItem
type→severity(entangled with the publictoast({type})store API — one planned break later; canonical set recorded asneutral|success|info|warning|danger); BreadcrumbItem keepscurrent(maps to nativearia-current="page").How to test
pnpm --filter @aziontech/webkit test(node:test — eslint rules, MCP, CLI, stylelint).<x>-changeecho, or default drift is blocked byvalidate-spec-compliance.no-style-overrideflagsclass/styleon a webkit tag;npx @aziontech/webkit initwires a scratch project.Follow-ups (not blocking this PR)
pnpm install --lockfile-onlyfor the merged lockfile (needs the toolchain).dialog/table(from the dev merge) — reconcile separately.field-switchrequired,menu-itemprops).