@wangs-ui/skills 1.3.0-alpha.14 → 1.3.0-alpha.16

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 (62) hide show
  1. package/dist/bin.js +2 -2
  2. package/dist/index.js +1 -1
  3. package/dist/skills/wangs-ui/wangs-ui-components/SKILL.md +104 -0
  4. package/dist/{src-ilzo-M7u.js → src-t3vXV084.js} +119 -96
  5. package/package.json +1 -1
  6. package/skills/wangs-ui/wangs-ui-components/SKILL.md +104 -0
  7. package/dist/skills/wangs-ui-components/SKILL.md +0 -202
  8. package/skills/wangs-ui-components/SKILL.md +0 -202
  9. /package/dist/rules/{react19-checklist-and-reference.md → wangs-ui/react19-checklist-and-reference.md} +0 -0
  10. /package/dist/rules/{react19-compiler-render-patterns.md → wangs-ui/react19-compiler-render-patterns.md} +0 -0
  11. /package/dist/rules/{react19-naming-conventions.md → wangs-ui/react19-naming-conventions.md} +0 -0
  12. /package/dist/rules/{react19-no-manual-memoization.md → wangs-ui/react19-no-manual-memoization.md} +0 -0
  13. /package/dist/rules/{react19-primitives-typing.md → wangs-ui/react19-primitives-typing.md} +0 -0
  14. /package/dist/rules/{react19-props-typing.md → wangs-ui/react19-props-typing.md} +0 -0
  15. /package/dist/rules/{react19-purity-and-immutability.md → wangs-ui/react19-purity-and-immutability.md} +0 -0
  16. /package/dist/rules/{react19-tooling-and-opt-out.md → wangs-ui/react19-tooling-and-opt-out.md} +0 -0
  17. /package/dist/rules/{typescript-assertions-last-resort.md → wangs-ui/typescript-assertions-last-resort.md} +0 -0
  18. /package/dist/rules/{typescript-checklist-and-reference.md → wangs-ui/typescript-checklist-and-reference.md} +0 -0
  19. /package/dist/rules/{typescript-discriminated-unions.md → wangs-ui/typescript-discriminated-unions.md} +0 -0
  20. /package/dist/rules/{typescript-explicit-return-types.md → wangs-ui/typescript-explicit-return-types.md} +0 -0
  21. /package/dist/rules/{typescript-interface-vs-type.md → wangs-ui/typescript-interface-vs-type.md} +0 -0
  22. /package/dist/rules/{typescript-literal-unions-vs-enums.md → wangs-ui/typescript-literal-unions-vs-enums.md} +0 -0
  23. /package/dist/rules/{typescript-naming-conventions.md → wangs-ui/typescript-naming-conventions.md} +0 -0
  24. /package/dist/rules/{typescript-narrowing-over-casting.md → wangs-ui/typescript-narrowing-over-casting.md} +0 -0
  25. /package/dist/rules/{typescript-readonly-by-default.md → wangs-ui/typescript-readonly-by-default.md} +0 -0
  26. /package/dist/rules/{typescript-tsconfig-strictness.md → wangs-ui/typescript-tsconfig-strictness.md} +0 -0
  27. /package/dist/rules/{typescript-zero-any.md → wangs-ui/typescript-zero-any.md} +0 -0
  28. /package/dist/skills/{craft-theme → wangs-ui/craft-theme}/SKILL.md +0 -0
  29. /package/dist/skills/{create-form → wangs-ui/create-form}/SKILL.md +0 -0
  30. /package/dist/skills/{data-table → wangs-ui/data-table}/SKILL.md +0 -0
  31. /package/dist/skills/{dialog-modal → wangs-ui/dialog-modal}/SKILL.md +0 -0
  32. /package/dist/skills/{i18n-usage → wangs-ui/i18n-usage}/SKILL.md +0 -0
  33. /package/dist/skills/{layout-navigation → wangs-ui/layout-navigation}/SKILL.md +0 -0
  34. /package/dist/skills/{responsive-design → wangs-ui/responsive-design}/SKILL.md +0 -0
  35. /package/dist/skills/{universal-layout → wangs-ui/universal-layout}/SKILL.md +0 -0
  36. /package/rules/{react19-checklist-and-reference.md → wangs-ui/react19-checklist-and-reference.md} +0 -0
  37. /package/rules/{react19-compiler-render-patterns.md → wangs-ui/react19-compiler-render-patterns.md} +0 -0
  38. /package/rules/{react19-naming-conventions.md → wangs-ui/react19-naming-conventions.md} +0 -0
  39. /package/rules/{react19-no-manual-memoization.md → wangs-ui/react19-no-manual-memoization.md} +0 -0
  40. /package/rules/{react19-primitives-typing.md → wangs-ui/react19-primitives-typing.md} +0 -0
  41. /package/rules/{react19-props-typing.md → wangs-ui/react19-props-typing.md} +0 -0
  42. /package/rules/{react19-purity-and-immutability.md → wangs-ui/react19-purity-and-immutability.md} +0 -0
  43. /package/rules/{react19-tooling-and-opt-out.md → wangs-ui/react19-tooling-and-opt-out.md} +0 -0
  44. /package/rules/{typescript-assertions-last-resort.md → wangs-ui/typescript-assertions-last-resort.md} +0 -0
  45. /package/rules/{typescript-checklist-and-reference.md → wangs-ui/typescript-checklist-and-reference.md} +0 -0
  46. /package/rules/{typescript-discriminated-unions.md → wangs-ui/typescript-discriminated-unions.md} +0 -0
  47. /package/rules/{typescript-explicit-return-types.md → wangs-ui/typescript-explicit-return-types.md} +0 -0
  48. /package/rules/{typescript-interface-vs-type.md → wangs-ui/typescript-interface-vs-type.md} +0 -0
  49. /package/rules/{typescript-literal-unions-vs-enums.md → wangs-ui/typescript-literal-unions-vs-enums.md} +0 -0
  50. /package/rules/{typescript-naming-conventions.md → wangs-ui/typescript-naming-conventions.md} +0 -0
  51. /package/rules/{typescript-narrowing-over-casting.md → wangs-ui/typescript-narrowing-over-casting.md} +0 -0
  52. /package/rules/{typescript-readonly-by-default.md → wangs-ui/typescript-readonly-by-default.md} +0 -0
  53. /package/rules/{typescript-tsconfig-strictness.md → wangs-ui/typescript-tsconfig-strictness.md} +0 -0
  54. /package/rules/{typescript-zero-any.md → wangs-ui/typescript-zero-any.md} +0 -0
  55. /package/skills/{craft-theme → wangs-ui/craft-theme}/SKILL.md +0 -0
  56. /package/skills/{create-form → wangs-ui/create-form}/SKILL.md +0 -0
  57. /package/skills/{data-table → wangs-ui/data-table}/SKILL.md +0 -0
  58. /package/skills/{dialog-modal → wangs-ui/dialog-modal}/SKILL.md +0 -0
  59. /package/skills/{i18n-usage → wangs-ui/i18n-usage}/SKILL.md +0 -0
  60. /package/skills/{layout-navigation → wangs-ui/layout-navigation}/SKILL.md +0 -0
  61. /package/skills/{responsive-design → wangs-ui/responsive-design}/SKILL.md +0 -0
  62. /package/skills/{universal-layout → wangs-ui/universal-layout}/SKILL.md +0 -0
@@ -3,146 +3,147 @@ import fs from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import os from "node:os";
5
5
  import { cancel, intro, isCancel, multiselect, outro } from "@clack/prompts";
6
- //#region skills/craft-theme/SKILL.md?raw
6
+ //#region skills/wangs-ui/craft-theme/SKILL.md?raw
7
7
  var SKILL_default$8 = "---\nname: craft-theme\ndescription: Generate a brand-color theme (13-shade tonal palette + semantic tokens) for a Wangs UI app via the `wangs-ui-generate-palette` CLI — never hand-write hex shade ramps.\nmetadata:\n owner: wangs-ui\n---\n# Skill: Craft Theme\n\nUse this skill whenever the user asks to create, customize, or rebrand the color theme of an app built on `@wangs-ui/react-core` / `@wangs-ui/foundation` — \"make the app's theme orange\", \"use our brand color #ff6b35\", \"add a new palette called sunset\", etc.\n\n## The rule this skill exists to enforce\n\n**Never hand-write a 13-shade tonal ramp, and never hand-pick which shade pairs with which as a text/foreground color.** Wangs UI's own design system shipped with exactly that mistake for a while: hand-tuned palette files drifted from what the perceptual (OKLCH) generator would produce, which caused white text to render at 2.54:1 contrast on one brand's primary color — invisible-adjacent, and only caught by a dedicated audit. The generator and the contrast math it's paired with exist specifically so this class of bug can't happen again. Always reach for the CLI below instead of writing hex values yourself.\n\n## 1. Generate the palette\n\n```bash\nnpx wangs-ui-generate-palette --name=<id> --primary=<#hex> [options] --out=<path>\n```\n\n- `--name` (required): identifier for the palette, e.g. `sunset`. Used for the exported const name (`sunsetPalette`) and, unless `--out` is given, the output filename (`sunset.ts`).\n- `--primary` (required): the brand/key hex color, e.g. `#ff6b35`.\n- Optional per-family overrides — omit any of these to let the generator harmoniously auto-derive it from `--primary` (secondary: boosted-lightness variant of primary's hue; tertiary: +60° hue rotation; general: near-neutral variant of primary's hue) or fall back to the generator's calibrated defaults (success/danger/warning/info):\n `--secondary=#hex --tertiary=#hex --general=#hex --success=#hex --danger=#hex --warning=#hex --info=#hex`\n- `--out=<path>` (optional): where to write the file. Defaults to `./<name>.ts` in the current working directory — always pass an explicit `--out` pointing into the consumer app's own theme directory (e.g. `src/theme/sunset.ts`), don't rely on the default.\n\nIf `@wangs-ui/foundation` isn't already a dependency of the project you're working in, install it first (`pnpm add @wangs-ui/foundation` or the project's equivalent) — the CLI ships as its `bin`.\n\n**The written file is chmod'd read-only (0o444) and headed with an AUTO-GENERATED / DO NOT EDIT BY HAND comment.** If a color needs to change, re-run the command (it clears the read-only bit, rewrites, and re-locks it) — never hand-edit a shade in the output, and never `chmod` it writable to bypass this. Note the read-only bit is a local filesystem attribute only; it is not preserved by git across clones, so it is a deterrent for the person/agent working in this checkout right now, not a hard guarantee for every future contributor.\n\n## 2. Wire it into the app\n\nThe generated file exports a plain `Palette` object — pass it directly to `WangsUiProvider`'s `theme.palette` (or `theme.defaultPalette` for uncontrolled mode):\n\n```tsx\nimport { WangsUiProvider } from '@wangs-ui/react-core/api';\nimport preset from '@wangs-ui/react-presets/fixedasset'; // or whichever preset the app uses\nimport { sunsetPalette } from './theme/sunset';\n\nconst App = () => (\n <WangsUiProvider configOptions={{ preset }} theme={{ palette: sunsetPalette, mode: 'light' }}>\n <YourApp />\n </WangsUiProvider>\n);\n```\n\n`theme.palette` also accepts a built-in palette name (`'blue' | 'emerald' | 'crimson' | 'carbon' | 'gold'`) or a raw hex string — a generated `Palette` object is the right choice once you have brand-specific secondary/tertiary/status colors to preserve, not just a single key color.\n\n## 3. Regenerating / evolving an existing custom palette\n\nTo change a color, re-run the same command with a new hex for the family that changed — **always pass every family you want to keep**, not just the one changing, since each run is a full regeneration from the anchors you give it:\n\n```bash\nnpx wangs-ui-generate-palette --name=sunset --primary=#ff6b35 --tertiary=#2a9d8f --out=src/theme/sunset.ts\n```\n\n## 4. If you're extending Wangs UI itself (contributing a new official palette)\n\nThis is a different, rarer case than theming a consumer app — only relevant if you're working inside the `wangs-ui-react` monorepo itself and adding a 6th built-in palette alongside blue/emerald/crimson/carbon/gold:\n\n1. Run the generator with `--out` pointing at `packages/foundation/theme/tokens/palettes/<name>.ts`.\n2. Register it: add `'<name>'` to the `PaletteName` union and `paletteLoaders` map in `packages/foundation/theme/context/ThemeContext.tsx`, and re-export it from `packages/foundation/theme/tokens/palettes/index.ts`.\n3. Run the contrast regression suite before considering it done: `pnpm exec vitest run --config packages/foundation/vitest.config.ts` — it checks every semantic token pairing (including the new palette) against WCAG AA across both light and dark mode. See `packages/foundation/theme/tokens/COLOR_TOKEN_CONTRACT.md` for the full rule set this is checked against.\n";
8
8
  //#endregion
9
- //#region skills/create-form/SKILL.md?raw
9
+ //#region skills/wangs-ui/create-form/SKILL.md?raw
10
10
  var SKILL_default$7 = "---\nname: create-form\ndescription: Form architecture, validation workflows, strongly-typed forms (useForm, useDialogForm, useWatchField), initialValues/reset lifecycle, and MCP discovery protocol for building forms and input controls with @wangs-ui/react-core.\nmetadata:\n owner: wangs-ui\n---\n# Skill: Form Architecture & Validation Workflows\n\nUse this skill when building forms, data entry panels, modal forms, settings pages, or multipart forms in Wangs UI applications.\n\n---\n\n## 1. MCP Protocol & Component Rules (Mandatory Single Source of Truth)\n\nDo **NOT** hardcode or guess prop names, component options, preset variations, or Storybook patterns in this document. Always retrieve component definitions, active props, and live Storybook implementations directly via MCP:\n\n### Component & Form API Protocol:\n\n```json\nget_component_api({ \"component\": \"form\" })\nget_component_api({ \"component\": \"field\" })\nget_component_api({ \"component\": \"dialogform\" })\nget_component_api({ \"component\": \"input\" })\nget_component_api({ \"component\": \"numberinput\" })\nget_component_api({ \"component\": \"select\" })\nget_component_api({ \"component\": \"multiselect\" })\nget_component_api({ \"component\": \"datepicker\" })\nget_component_api({ \"component\": \"fileupload\" })\n```\n\n### Curated Form Documentation:\n\n```json\nget_documentation({ \"id\": \"form\" })\nget_documentation({ \"id\": \"dialogform\" })\nget_documentation({ \"id\": \"field\" })\n```\n\n### Live Storybook & Interactive Behavior Protocol:\n\n```json\nget_component_examples({ \"component\": \"form\", \"variant\": \"Default\" })\nget_component_examples({ \"component\": \"form\", \"variant\": \"AsyncInitialValues\" })\nget_component_examples({ \"component\": \"form\", \"variant\": \"ConditionalFields\" })\nget_component_examples({ \"component\": \"form\", \"variant\": \"CascadingOptions\" })\nget_component_examples({ \"component\": \"dialogform\", \"variant\": \"Default\" })\n```\n\n### Knowledge Graph & Symbol Usages:\n\n```json\nquery_graph({ \"query\": \"useForm\" })\nquery_graph({ \"query\": \"useDialogForm\" })\nquery_graph({ \"query\": \"useWatchField\" })\n```\n\n---\n\n## 2. Core Form Concepts & Lifecycle Mechanics\n\n### A. Strongly Typed Form Instance (`useForm<TForm>()`)\n\n`useForm<TForm>()` instantiates a `FormControl` natively bound to model type `TForm`.\n\n- `Field`: `name` is strictly typed to `Path<TForm>` dot-paths.\n- `useWatchField`: `name` is strictly typed to `Path<TForm>`.\n- `control`: Provides `setInitialValues`, `setValues`, `setFieldError`, `setErrors`, and `reset`.\n\n### B. Dynamic Initial Values & Baseline Reset (`setInitialValues` vs `setValues`)\n\n1. **Async Initial Values (`control.setInitialValues(values)`)**:\n - Accepts a `Partial<TForm>` JSON object (e.g. fetched from an API).\n - Establishes an **immutable baseline** for registered fields. Once set for a field path, subsequent calls to `setInitialValues` for that path are ignored.\n2. **Batch Value Updates (`control.setValues(values)`)**:\n - Accepts a `Partial<TForm>` JSON object to update current input values without altering the initial baseline.\n3. **Reset Behavior (`control.reset()`)**:\n - Restores all fields back to their registered initial baseline values (set via `setInitialValues` or field `initialValue`) and clears all field-level validation errors.\n\n### C. Primitive Component Integration Architecture\n\n`Field` serves as the form integration wrapper for primitive UI input components (`Input`, `Select`, `MultiSelect`, `DatePicker`, `NumberInput`, `FileUpload`, `Calendar`, etc.):\n\n- **Children Render Callback**: `Field` yields `{ fieldProps, fieldState }`.\n- **`fieldProps`**: Pass directly to primitive inputs (`<Input {...fieldProps} />`). Contains `name`, `value`, `ref`, `onChange`.\n- **`fieldState`**: Provides `invalid`, `error`, `isDirty`, `isPending`. Pass `invalid={fieldState.invalid}` to primitive components for accessibility and validation styling.\n- **⚠️ Mandatory Destructuring (Never `(field) => ...`)**: `<Field>`'s callback render prop must destructure as `{({ fieldProps, fieldState })}`. Passing a single parameter instead (`{(field) => ...}`) produces `undefined` `value`/`onChange` and permanently locks the input.\n- **Pass `fieldProps.onChange` directly**: `<Field>` is generic and `fieldProps.onChange` is already typed to the field's value type. Do not wrap it in unnecessary `e?.target?.value` extractions.\n\n---\n\n## 3. High-Level Form Architecture & Usage Patterns\n\n### Pattern 1: Page Forms (`useForm<T>()`)\n\n```tsx\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport { useForm } from '@wangs-ui/react-core/primitive/form';\nimport Input from '@wangs-ui/react-core/primitive/input';\nimport { useI18n } from '@wangs-ui/react-i18n';\nimport { useEffect } from 'react';\n\ninterface UserProfile {\n name: string;\n email: string;\n}\n\nexport function UserProfilePage({ userId }: { userId: string }) {\n const { t } = useI18n();\n const { Form, Field, control } = useForm<UserProfile>();\n\n useEffect(() => {\n async function loadData() {\n const data = await fetchUserData(userId);\n // Establish immutable initial baseline from async response\n control.setInitialValues(data);\n }\n loadData();\n }, [userId, control]);\n\n return (\n <Form control={control} onSubmit={(values) => saveUserData(values)}>\n <Field required label={t('Full Name')} name=\"name\">\n {({ fieldProps, fieldState }) => (\n <Input {...fieldProps} invalid={fieldState.invalid} placeholder={t('Enter full name')} />\n )}\n </Field>\n\n <div className=\"flex gap-2\">\n <Button\n label={t('Reset')}\n type=\"button\"\n variant=\"outlined\"\n onClick={() => control.reset()}\n />\n <Button label={t('Save')} type=\"submit\" />\n </div>\n </Form>\n );\n}\n```\n\n### Pattern 2: Modal Forms (`useDialogForm<T>()`)\n\n```tsx\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport { useDialogForm } from '@wangs-ui/react-core/primitive/dialogform';\nimport Input from '@wangs-ui/react-core/primitive/input';\nimport { useI18n } from '@wangs-ui/react-i18n';\nimport { useState } from 'react';\n\ninterface EditUserForm {\n name: string;\n}\n\nexport function EditUserModal() {\n const { t } = useI18n();\n const [open, setOpen] = useState(false);\n const { DialogForm, Field, control } = useDialogForm<EditUserForm>();\n\n return (\n <>\n <Button label={t('Edit')} onClick={() => setOpen(true)} />\n <DialogForm\n closeOnSubmit\n control={control}\n header={t('Edit User')}\n open={open}\n onOpenChange={setOpen}\n onSubmit={(values) => handleSave(values)}\n >\n <Field required label={t('Full Name')} name=\"name\">\n {({ fieldProps, fieldState }) => <Input {...fieldProps} invalid={fieldState.invalid} />}\n </Field>\n </DialogForm>\n </>\n );\n}\n```\n\n---\n\n## 4. Mandatory Implementation Guidelines\n\n1. **Query MCP First**: Never guess component props or story examples — inspect via MCP tools.\n2. **Granular Primitive Subpaths**: Import primitives via exact subpath modules (`@wangs-ui/react-core/primitive/form`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/input`).\n3. **i18n Localization**: Wrap all user-visible labels, placeholders, and error strings in `t('...')` from `@wangs-ui/react-i18n`.\n4. **Server Error Mapping**: Map HTTP validation errors (e.g. 422 response) into the form using `control.setErrors(apiErrors)`.\n";
11
11
  //#endregion
12
- //#region skills/data-table/SKILL.md?raw
12
+ //#region skills/wangs-ui/data-table/SKILL.md?raw
13
13
  var SKILL_default$6 = "---\nname: data-table\ndescription: Architecture, workflows, and MCP discovery protocol for building DataTables with sorting, pagination, filtering, selection, and export.\nmetadata:\n owner: wangs-ui\n---\n# Skill: DataTable Architecture & Integration Workflows\n\nUse this skill when implementing data grids, server-paginated tables, filterable listing views, or batch management interfaces with `@wangs-ui/react-core`.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess table prop names or hardcode table structures. Query the MCP server dynamically to inspect exact TypeScript signatures, live story implementations, and companion controls:\n\n### Inspect Component Contracts (`component` parameter):\n\n```json\nget_component_api({ \"component\": \"datatable\" })\nget_component_api({ \"component\": \"exportbutton\" })\nget_component_api({ \"component\": \"filtercontainer\" })\nget_component_api({ \"component\": \"bulkactionbutton\" })\n```\n\n### Read Curated Documentation:\n\n```json\nget_documentation({ \"id\": \"datatable\" })\nget_documentation({ \"id\": \"exportbutton\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget_component_examples({ \"component\": \"datatable\", \"variant\": \"Basic\" })\nget_component_examples({ \"component\": \"datatable\", \"variant\": \"CursorPagination\" })\nget_component_examples({ \"component\": \"datatable\", \"variant\": \"Sortable\" })\nget_component_examples({ \"component\": \"datatable\", \"variant\": \"MultipleSelection\" })\nget_component_examples({ \"component\": \"datatable\", \"variant\": \"CustomColumn\" })\nget_component_examples({ \"component\": \"exportbutton\", \"variant\": \"WithTable\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"DataTable\" })\nquery_graph({ \"query\": \"useDataTableFetch\" })\n```\n\n---\n\n## 2. Core Architecture & Mental Model\n\nThe Wangs UI `DataTable` is built on a modular, headless-first architecture:\n\n1. **Declarative Column Definitions (`TableColumn<T>[]`)**:\n Columns are configured as typed array objects, not as JSX children. Check `get_component_api({ \"component\": \"datatable\" })` for column field types.\n2. **Table Instance Hook (`useDataTable`)**:\n Coordinates table state (sorting, pagination, selection, column ordering, pinning, visibility).\n3. **Data Fetching Hook (`useDataTableFetch`)**:\n Feeds server-side data, handles loading indicators, manages query parameters (`search`, `filter`, `sort`, `page`, `limit`), and debounces requests automatically.\n4. **Ecosystem Companions**:\n - `FilterContainer` & `FilterToggleButton`: Filter popovers and faceted search.\n - `ExportButton`: Client/server export to Excel, CSV, PDF, or Print.\n - `BulkActionButton`: Contextual batch actions triggered when rows are selected.\n - `CustomColumn`: User-controlled column ordering, visibility toggling, and pinning.\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **Query MCP for Current Code Patterns**: Always run `get_component_examples` for `datatable` before drafting code.\n2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/datatable` and companion primitive paths.\n3. **Always Translate Visible Copy**: All column header labels, empty state messages, and action button labels must be wrapped in `t('...')` from `@wangs-ui/react-i18n`.\n4. **Stable Row Identity**: Always configure a unique key identifier (`dataKey` / `rowId`) for stable selection and row identity.\n5. **Zero Redundant Table Wrappers**: Never wrap `<DataTable />` in an isolated `<div>` or `<Box>` solely to set width or margin. Wangs UI DataTable manages its own container scroll and layout dimensions out of the box.\n";
14
14
  //#endregion
15
- //#region skills/dialog-modal/SKILL.md?raw
15
+ //#region skills/wangs-ui/dialog-modal/SKILL.md?raw
16
16
  var SKILL_default$5 = "---\nname: dialog-modal\ndescription: Patterns, overlay selection criteria, and MCP discovery protocol for Dialog, Modal, and DialogForm components in Wangs UI.\nmetadata:\n owner: wangs-ui\n---\n# Skill: Dialog, Modal & Overlay Workflows\n\nUse this skill when building interactive modals, create/edit dialog forms, destructive action confirmations, or slide-in overlay panels.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess overlay props, event names, or footer slots. Query the MCP server dynamically to inspect exact contracts and live story implementations:\n\n### Inspect Overlay Contracts (`component` parameter):\n\n```json\nget_component_api({ \"component\": \"dialog\" })\nget_component_api({ \"component\": \"dialogform\" })\nget_component_api({ \"component\": \"modal\" })\nget_component_api({ \"component\": \"toast\" })\n```\n\n### Read Curated Overlay Documentation:\n\n```json\nget_documentation({ \"id\": \"dialog\" })\nget_documentation({ \"id\": \"dialogform\" })\nget_documentation({ \"id\": \"modal\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget_component_examples({ \"component\": \"dialog\", \"variant\": \"RichHeaderFooter\" })\nget_component_examples({ \"component\": \"dialogform\", \"variant\": \"Default\" })\nget_component_examples({ \"component\": \"modal\", \"variant\": \"Default\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"Dialog\" })\nquery_graph({ \"query\": \"DialogForm\" })\n```\n\n---\n\n## 2. Overlay Selection Matrix\n\n| Component | Primary Use Case | Key Characteristics |\n| :--------------- | :-------------------------------------------- | :------------------------------------------------------------------------------------ |\n| **`Dialog`** | Confirmations, alerts, simple detail previews | Standard `header`, `footer`, and body layout; built-in backdrop dimming. |\n| **`DialogForm`** | Create/Edit forms embedded inside a dialog | Built-in form submit/cancel action bar, dirty state tracking, and submit lifecycle. |\n| **`Modal`** | Slide-in drawers, complex custom viewports | Headless overlay primitive with flexible animations, size variants, and drawer modes. |\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **Query MCP for Current Code Patterns**: Always inspect `dialog`, `dialogform`, or `modal` stories via MCP before writing overlay code.\n2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/dialog`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/modal`, or `@wangs-ui/react-core/primitive/toast`.\n3. **Prevent Dismissal During Async Mutations**: Guard the close handler so users cannot accidentally dismiss the dialog while a mutation request is in-flight.\n4. **Coordinate with Toast Notifications**: Trigger feedback toasts on successful creation, update, or deletion actions.\n5. **Translate All Overlay Copy**: All dialog titles, confirmation descriptions, and button labels must be localized using `t('...')` from `@wangs-ui/react-i18n`.\n";
17
17
  //#endregion
18
- //#region skills/i18n-usage/SKILL.md?raw
18
+ //#region skills/wangs-ui/i18n-usage/SKILL.md?raw
19
19
  var SKILL_default$4 = "---\nname: i18n-usage\ndescription: Comprehensive guidelines for application internationalization, JIT translations (t), ICU formatting, and locale-aware formatting with @wangs-ui/react-i18n.\nmetadata:\n owner: wangs-ui\n---\n# Skill: Application Internationalization & Formatting Protocol\n\nUse this skill when implementing multi-language interfaces, translating user-facing text, formatting dates, times, currencies, or numbers in React applications built with Wangs UI and `@wangs-ui/react-i18n`.\n\n---\n\n## 1. The MCP Discovery Protocol (Single Source of Truth)\n\nDo **NOT** guess component localization contracts, language switcher variants, or datepicker props. Query the MCP server dynamically to inspect exact props and live story implementations:\n\n### Inspect Localized Component Contracts (`component` parameter):\n\n```json\nget_component_api({ \"component\": \"languageswitcher\" })\nget_component_api({ \"component\": \"currencyinput\" })\nget_component_api({ \"component\": \"datepicker\" })\nget_component_api({ \"component\": \"select\" })\nget_component_api({ \"component\": \"datatable\" })\n```\n\n### Read Curated Localization Documentation:\n\n```json\nget_documentation({ \"id\": \"languageswitcher\" })\nget_documentation({ \"id\": \"currencyinput\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget_component_examples({ \"component\": \"languageswitcher\", \"variant\": \"Default\" })\nget_component_examples({ \"component\": \"currencyinput\", \"variant\": \"Default\" })\nget_component_examples({ \"component\": \"datepicker\", \"variant\": \"Default\" })\n```\n\n---\n\n## 2. Root Provider Setup (`WangsUiI18nProvider`)\n\nWrap the application root with `WangsUiI18nProvider` from `@wangs-ui/react-i18n` to enable dynamic JIT translations, versioned cache invalidation, and locale context:\n\n```tsx\nimport { WangsUiI18nProvider } from '@wangs-ui/react-i18n';\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <WangsUiI18nProvider defaultLocale=\"en\" baseUrl={import.meta.env.VITE_API_URL || ''}>\n <App />\n </WangsUiI18nProvider>\n </React.StrictMode>,\n);\n```\n\n---\n\n## 3. Translation Protocol with `useI18n()`\n\nThe `@wangs-ui/react-i18n` package uses a Just-In-Time (JIT) translation architecture where natural English text strings serve as database keys.\n\n### A. Consumer-Level Translation for `ReactNode` Props (Mandatory)\n\nAll user-facing text props in Wangs UI components (`placeholder`, `label`, `emptyMessage`, `header`, `tooltip`, etc.) are typed as `ReactNode` and rendered as-is. Components do **NOT** automatically translate custom strings. Translation **MUST** be called at the application/consumer level:\n\n```tsx\nimport { useI18n } from '@wangs-ui/react-i18n';\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport DataTable from '@wangs-ui/react-core/primitive/datatable';\nimport Select from '@wangs-ui/react-core/primitive/select';\n\nexport function OrderList() {\n const { t } = useI18n();\n\n return (\n <div>\n <Select placeholder={t('Search category...')} />\n <DataTable emptyMessage={t('No orders found')} />\n <Button label={t('Create new order')} />\n </div>\n );\n}\n```\n\n### B. Natural English Sentence Keys\n\nAlways write full, natural English sentences as translation keys. Never use artificial dotted namespace keys:\n\n```tsx\n// ✅ Good — Natural English\nt('Invoice Summary');\nt('Are you sure you want to delete this customer?');\n\n// ❌ Bad — Artificial dotted keys\nt('invoice.summary.title');\nt('dialog.delete.customer.confirm');\n```\n\n### C. Named Variable Interpolation (Single Braces `{var}`)\n\nPass interpolation values inside a plain object using descriptive named variables. This provides crucial semantic context for AI translation engines:\n\n```tsx\n// ✅ Good — Named variables provide context\nt('Upload {count} files to {groupName}', { count: 5, groupName: 'Marketing' });\nt('Welcome back, {userName}!', { userName: user.name });\n\n// ❌ Bad — Concatenation or positional arguments\nt('Welcome back, ' + user.name);\nt('Upload {0} files to {1}', 5, 'Marketing');\n```\n\n### D. ICU Pluralization & Zero-State (`=0`)\n\nAlways handle singular, plural, and zero states directly within ICU MessageFormat strings. Do **NOT** use JavaScript ternary operators:\n\n```tsx\n// ✅ Good — Clean ICU pluralization with zero-state handling\nt('{count, plural, =0 {No items selected} one {1 item selected} other {{count} items selected}}', {\n count: selectedCount,\n});\n\n// ❌ Bad — Manual JS branching\nselectedCount === 0\n ? t('No items selected')\n : selectedCount === 1\n ? t('1 item selected')\n : t('{count} items selected', { count: selectedCount });\n```\n\n### E. Rich Text / Annotated Strings\n\nUse standard supported HTML tags (`<a>`, `<b>`, `<i>`, `<u>`, `<s>`, `<br/>`, `<sub>`, `<sup>`, `<code>`, `<mark>`) for inline styling. Tags are automatically parsed into React elements without custom regex or string manipulation:\n\n```tsx\nimport { Link } from '@wangs-ui/foundation/theme';\n\nt('You have selected <b>{count} items</b>. Click <a>here</a> to review.', {\n count: selectedCount,\n a: (chunks) => <Link href=\"/review\">{chunks}</Link>,\n});\n```\n\n---\n\n## 4. Locale Formatting Protocol with `useLocaleFormatter()`\n\nFor locale-aware formatting of dates, relative times, currencies, numbers, and display names, use the dedicated `useLocaleFormatter()` hook. All functions automatically adapt to the active locale without triggering backend database requests:\n\n```tsx\nimport { useLocaleFormatter } from '@wangs-ui/react-i18n';\n\nexport function SummaryCard({ updatedAt, amount, count }: Props) {\n const {\n formatDate,\n formatRelativeTime,\n formatCurrency,\n formatNumber,\n formatDisplayName,\n formatList,\n truncateText,\n } = useLocaleFormatter();\n\n return (\n <div>\n {/* Date formatting with Go tokens or date-fns tokens, and timezone */}\n <p>{formatDate(new Date(), 'dd MMMM yyyy, HH:mm', 'Asia/Jakarta')}</p>\n\n {/* Relative time */}\n <p>{formatRelativeTime(updatedAt)}</p>\n\n {/* Currency formatting */}\n <p>{formatCurrency(amount, 'IDR')}</p>\n\n {/* Number formatting with locale grouping */}\n <p>{formatNumber(count)}</p>\n\n {/* ISO code to localized name */}\n <p>{formatDisplayName('id', 'language')}</p>\n\n {/* Localized list */}\n <p>{formatList(['Finance', 'Operations', 'IT'])}</p>\n\n {/* Emoji & multi-byte safe text truncation */}\n <p>{truncateText('Long product description with emojis 🚀', 20)}</p>\n </div>\n );\n}\n```\n\n> [!NOTE]\n> Formatters MUST NOT be called as standalone `t()` keys (e.g. `t(formatRelativeTime(date))`). Instead, pass the formatted result as a named variable:\n>\n> ```tsx\n> const { t } = useI18n();\n> const { formatRelativeTime } = useLocaleFormatter();\n> const label = t('Updated {time}', { time: formatRelativeTime(updatedAt) });\n> ```\n\n---\n\n## 5. Language Switching UI Integration\n\nConnect the Wangs UI `LanguageSwitcher` primitive directly with `useI18n()` state:\n\n```tsx\nimport LanguageSwitcher from '@wangs-ui/react-core/primitive/languageswitcher';\nimport { useI18n } from '@wangs-ui/react-i18n';\n\nexport function HeaderLanguageSwitcher() {\n const { locale, setLocale, languageOptions } = useI18n();\n\n return (\n <LanguageSwitcher\n options={languageOptions}\n value={locale}\n onChange={(code) => setLocale(code)}\n />\n );\n}\n```\n\n---\n\n## 6. Strict Behavioral Constraints (MUST NOT)\n\n- **NO Formatters Destructured from `useI18n()`:** Formatters are isolated in `useLocaleFormatter()`. Never attempt to import `formatDate` or `formatCurrency` from `useI18n()`.\n- **NO String Concatenation in `t()` Keys:** Never concatenate strings or use dynamic template literals (e.g. `t('Hello ' + user.name)` or ``t(`Hello ${user.name}`)``). This creates infinite distinct keys in the translation database and prevents caching.\n- **NO Manual Zero-State JavaScript Branching:** Always use ICU `=0` syntax inside a single plural key.\n- **NO Dotted Artificial Translation Keys:** Never use dotted keys like `t('app.header.title')`. Use natural English sentences.\n- **NO Custom Markdown Formatting Symbols:** Do not use `*bold*` or `_italic_` in translation keys. Use valid HTML tags like `<b>bold</b>`.\n- **NO Hardcoded Static Translation Dictionaries:** Do not bundle static translation files (`id.json`, `zh.json`). The JIT backend broker manages translations dynamically.\n- **NO Unnecessary English Key Modifications:** Minor typos or punctuation changes in keys create orphaned entries in the translation backend and trigger new AI translation costs.\n";
20
20
  //#endregion
21
- //#region skills/layout-navigation/SKILL.md?raw
21
+ //#region skills/wangs-ui/layout-navigation/SKILL.md?raw
22
22
  var SKILL_default$3 = "---\nname: layout-navigation\ndescription: Architecture, navigation hierarchies, and MCP discovery protocol for AppLayout, Sidebar, Breadcrumb, and Tabs in Wangs UI.\nmetadata:\n owner: wangs-ui\n---\n\n# Skill: Application Layout & Navigation Hierarchy\n\nUse this skill when constructing application shells, multi-level sidebars, page headers, breadcrumbs, tabbed views, or feature routing with `@wangs-ui/react-core`, `@wangs-ui/foundation`, and `@wangs-ui/react-navigation`.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess layout block slots, sidebar item interfaces, or breadcrumb props. Query the MCP server dynamically to inspect exact contracts and live story implementations:\n\n### Inspect Layout & Navigation Contracts (`component` parameter):\n\n```json\nget_component_api({ \"component\": \"applayout\" })\nget_component_api({ \"component\": \"sidebar\" })\nget_component_api({ \"component\": \"tabletoolbar\" })\nget_component_api({ \"component\": \"breadcrumb\" })\nget_component_api({ \"component\": \"tabs\" })\n```\n\n\n### Read Curated Layout Documentation (`id` parameter):\n\n```json\nget_documentation({ \"id\": \"applayout\" })\nget_documentation({ \"id\": \"sidebar\" })\nget_documentation({ \"id\": \"react-navigation\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget_component_examples({ \"component\": \"applayout\", \"variant\": \"TopNavbar\" })\nget_component_examples({ \"component\": \"sidebar\", \"variant\": \"WithSubMenu\" })\nget_component_examples({ \"component\": \"breadcrumb\", \"variant\": \"Default\" })\nget_component_examples({ \"component\": \"tabs\", \"variant\": \"Default\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"AppLayout\" })\nquery_graph({ \"query\": \"Sidebar\" })\n```\n\n---\n\n## 2. Layout Architecture & Mental Model\n\n1. **Top-Level App Shell (`AppLayout`)**:\n - Subpath: `@wangs-ui/react-core/blocks/applayout`\n - Outer responsive shell arranging navigation, navbar, sidebars, main viewport, and footer. Inspect slots and layout variants via `get_component_api({ \"component\": \"applayout\" })`.\n2. **Hierarchical Menu (`Sidebar`)**:\n - Subpath: `@wangs-ui/react-core/blocks/sidebar`\n - Primary app navigation drawer/rail supporting nested menus, badges, and collapse states. Inspect items and events via `get_component_api({ \"component\": \"sidebar\" })`.\n3. **Breadcrumb Trail (`Breadcrumb`)**:\n - Subpath: `@wangs-ui/react-core/primitive/breadcrumb`\n - Secondary hierarchy navigation displaying screen depth. Inspect item structure via `get_component_api({ \"component\": \"breadcrumb\" })`.\n4. **Tabbed Sub-Views (`Tabs`)**:\n - Subpath: `@wangs-ui/react-core/primitive/tabs`\n - In-page view switcher for partitioning entity details into distinct panels. Inspect via `get_component_api({ \"component\": \"tabs\" })`.\n5. **Universal Routing (`@wangs-ui/react-navigation`)**:\n - Platform-agnostic route graph abstraction (`buildGraph`, `paramRoute`).\n - Web router bridge: `@wangs-ui/react-navigation/web` (React Router).\n - Native router bridge: `@wangs-ui/react-navigation/native` (React Navigation / Expo).\n\n---\n\n## 3. Structural Page Blueprint (Standard Pattern)\n\n```tsx\nimport AppLayout from '@wangs-ui/react-core/blocks/applayout';\nimport Sidebar from '@wangs-ui/react-core/blocks/sidebar';\nimport Breadcrumb from '@wangs-ui/react-core/primitive/breadcrumb';\nimport { Container, Section, Stack, HStack } from '@wangs-ui/foundation/layout';\nimport { Text } from '@wangs-ui/foundation/theme';\nimport { useI18n } from '@wangs-ui/react-i18n';\nimport { HomeLine, Settings4Line } from '@wangs-ui/react-icons';\nimport { useState } from 'react';\n\nexport function ApplicationShell({ children }: { children: React.ReactNode }) {\n const { t } = useI18n();\n const [activeRoute, setActiveRoute] = useState('dashboard');\n const [collapsed, setCollapsed] = useState(false);\n\n const sidebarItems = [\n { value: 'dashboard', label: t('Dashboard'), icon: HomeLine, to: '/' },\n { value: 'settings', label: t('Settings'), icon: Settings4Line, to: '/settings' },\n ];\n\n return (\n <AppLayout\n variant=\"full-sidebar\"\n sidebar={\n <Sidebar\n items={sidebarItems}\n value={activeRoute}\n onValueChange={setActiveRoute}\n collapsed={collapsed}\n onCollapsedChange={setCollapsed}\n collapseMode=\"rail\"\n />\n }\n >\n <Container size=\"xl\">\n <Section space=\"md\">\n <Stack gap=\"4\">\n <Breadcrumb\n items={[\n { label: t('Home'), href: '/' },\n { label: t('Dashboard') },\n ]}\n />\n <Text variant=\"headlineLarge\">{t('Overview')}</Text>\n {children}\n </Stack>\n </Section>\n </Container>\n </AppLayout>\n );\n}\n```\n\n---\n\n## 4. Mandatory Implementation Rules\n\n1. **Query MCP First**: Always inspect `applayout` and `sidebar` stories via MCP before assembling the layout.\n2. **Strict Subpath Imports**:\n - Blocks: `@wangs-ui/react-core/blocks/*` (`applayout`, `sidebar`, `tabletoolbar`)\n - Primitives: `@wangs-ui/react-core/primitive/*` (`breadcrumb`, `tabs`)\n - Layout Primitives: `@wangs-ui/foundation/layout` (`Container`, `Section`, `Stack`, `HStack`, `Box`, `Grid`)\n - Typography: `@wangs-ui/foundation/theme` (`Text`)\n3. **Standard Layout Containers & Spacing**:\n - Use `Container` (max-width rhythm) and `Section` (vertical rhythm) for page boundaries.\n - Use flat numeric Tailwind spacing (`gap=\"4\"`, `p=\"6\"`). Never use legacy named tokens like `p-3xl` or `gap-md`.\n4. **Typography Scale**:\n - Use `<Text variant=\"headlineLarge\">` or `display*` / `title*` for page headers. Never use obsolete `.heading-*` helper classes or raw HTML heading tags without primitives.\n5. **No Redundant Layout Wrappers**:\n - Do NOT insert intermediate pass-through `<div>` or `<Box>` wrappers between `<Card>`/`<Tabs>` and tab contents.\n - Render active tab content directly as a child of the container:\n ```tsx\n // ✅ Good\n <Card>\n <Tabs items={tabItems} value={activeTab} onValueChange={setActiveTab} />\n {activeTab === 'general' ? <GeneralTab /> : <SecurityTab />}\n </Card>\n ```\n6. **Translate Navigation Labels**: Wrap all sidebar item labels, breadcrumb text, and page headings in `t('...')` from `@wangs-ui/react-i18n`.\n";
23
23
  //#endregion
24
- //#region skills/responsive-design/SKILL.md?raw
24
+ //#region skills/wangs-ui/responsive-design/SKILL.md?raw
25
25
  var SKILL_default$2 = "---\nname: responsive-design\ndescription: Guidelines for implementing responsive UIs with Wangs UI — covering Breakpoint tiers, responsive props (ResponsiveValue), <Show> conditional rendering, and spacing conventions.\nmetadata:\n owner: wangs-ui\n---\n# Skill: Responsive Design (Consumer Guide)\n\nUse this skill when building responsive pages, layouts, or screen adaptations with Wangs UI components.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess responsive prop types or breakpoint keys. Query the MCP server dynamically:\n\n```json\nresolve_type_definition({ \"types\": [\"ResponsiveValue\", \"Breakpoint\", \"SpacingKey\"] })\n```\n\n---\n\n## 2. Breakpoint Reference\n\nWangs UI uses three standardized breakpoints:\n\n| Breakpoint | Viewport Range | Typical Target |\n| :------------- | :------------- | :------------------------- |\n| **`compact`** | `< 600px` | Mobile phones |\n| **`medium`** | `600–839px` | Tablet portrait |\n| **`expanded`** | `≥ 840px` | Tablet landscape & Desktop |\n\n### Reading the Current Breakpoint in Code\n\n```tsx\nimport { useTheme } from '@wangs-ui/foundation/theme';\n\nconst { breakpoint } = useTheme(); // 'compact' | 'medium' | 'expanded'\n```\n\n---\n\n## 3. Responsive Props (`ResponsiveValue`)\n\nVisual scale props (`size`, layout `gap`, `columns`, `p`, `m`) accept either a single value or an object mapped by breakpoint:\n\n```tsx\nimport { Button } from '@wangs-ui/react-core/components/button';\nimport { Grid, Stack } from '@wangs-ui/foundation/layout';\n\n// Static (identical across all devices)\n<Button size=\"md\" />\n<Stack gap=\"4\" />\n\n// Adaptive (changes across breakpoints)\n<Button size={{ compact: 'lg', expanded: 'sm' }} />\n<Grid columns={{ compact: 1, medium: 2, expanded: 4 }} />\n```\n\n> **Rule**: Do **NOT** attempt to use responsive objects on event handlers or boolean flags (e.g. `disabled`, `onClick`). Only visual scale props support responsive objects.\n\n---\n\n## 4. Conditional Rendering (`<Show>`)\n\nUse `<Show>` when a component should be mounted or unmounted based on the active breakpoint:\n\n```tsx\nimport { Show } from '@wangs-ui/foundation/theme';\n\n// Render only on tablet & desktop\n<Show above=\"medium\">\n <SidebarNav />\n</Show>\n\n// Render only on mobile\n<Show below=\"medium\">\n <MobileNavbar />\n</Show>\n\n// Swap component with a fallback\n<Show at=\"compact\" fallback={<DesktopTable />}>\n <MobileCardList />\n</Show>\n```\n\n### When to use `<Show>` vs CSS `hidden`:\n\n- **Use `<Show>`**: If the hidden component has expensive network fetches, subscriptions, or animations (unmounts completely).\n- **Use CSS Tailwind (`hidden md:block`)**: If it's just a visual styling toggle with no side effects.\n\n---\n\n## 5. Spacing Conventions\n\nSpacing tokens are **flat and fixed** (1 unit = 4px):\n\n- **Web**: Use standard Tailwind numeric classes (`gap-2`, `px-4`, `py-3`). **Never** use legacy named classes like `gap-md` or `px-sm`.\n- **Native**: Use `const { spacing } = useTheme();` (`spacing[4]` = 16px).\n\n---\n\n## 6. Anti-Patterns to Avoid\n\n1. **Avoid `hidden md:block` for stateful/heavy trees**: Always prefer `<Show>` so unused components cleanly unmount.\n2. **Never pass responsive objects to behavioral props**: `<Button disabled={{ compact: true }} />` is invalid.\n3. **No manual pixel calculations**: Use Tailwind numeric tokens (`gap-4`, `p-6`) or `ResponsiveValue`.\n";
26
26
  //#endregion
27
- //#region skills/universal-layout/SKILL.md?raw
27
+ //#region skills/wangs-ui/universal-layout/SKILL.md?raw
28
28
  var SKILL_default$1 = "---\nname: universal-layout\ndescription: Universal layout primitives (Box, Flex, Stack, Grid, Container, Section) with ResponsiveValue patterns for Web and React Native in Wangs UI.\nmetadata:\n owner: wangs-ui\n---\n# Skill: Universal Layout Primitives\n\nUse this skill when arranging page structure, spacing, or responsive grids with\n`@wangs-ui/foundation/layout`.\nFor app shells (sidebar, breadcrumb, tabs), see the `layout-navigation` skill instead.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess layout prop names, spacing scales, or breakpoint keys. Query the MCP\nserver dynamically:\n\n```json\nlist_catalog({ \"query\": \"layout\" })\nresolve_type_definition({ \"types\": [\"ResponsiveValue\", \"SpacingKey\", \"StackProps\", \"GridProps\", \"BoxProps\", \"ScrollAreaProps\"] })\n```\n\n---\n\n## 2. Choosing the Right Primitive\n\n1. **Stack (Vertical)** — default for vertical flows (forms, cards, page sections).\n Fixed `column` direction, uniform `gap`, optional auto-`separator`.\n2. **HStack** — horizontal rows with vertical centering (avatar + label + action,\n toolbar clusters). Fixed `row` direction.\n3. **Flex** — only when you need explicit `direction`, `wrap`, `align`, or `justify`\n control beyond what Stack/HStack fix. Prefer Stack/HStack otherwise.\n4. **Grid** — two-dimensional placement or multi-column flows:\n - explicit `columns={{ compact: 1, medium: 2, expanded: 4 }}` for fixed column counts;\n - `minItemWidth` for auto-fit (columns grow/shrink with container width, no media query);\n - `GridItem` with `colSpan` / `rowSpan` for featured tiles.\n5. **Box** — leaf-level spacing/sizing wrapper (`p`, `m`, `radius`, `overflow`), or\n polymorphic `as=\"section\" | \"main\" | \"article\"` for landmarks.\n6. **Container / Section** — page-level rhythm only: `Container` bounds max-width\n (`size`, default `'xl'`) with consistent horizontal padding; `Section` sets\n vertical rhythm (`space: 'sm' | 'md' | 'lg'`, default `'md'`). Never nest\n `Container` inside `Container`.\n7. **ZStack** — overlays (badge on card, status dot on avatar, hero overlay).\n8. **ScrollArea** — styled, accessible scrollable viewports (`orientation: 'vertical' | 'horizontal' | 'both'`, `variant: 'hover' | 'always' | 'scroll'`).\n9. **AspectRatio / Bleed / Spacer** — media frames (`ratio`), full-bleed breakouts\n inside padded containers (`Bleed`), and flexible fillers in stacks (`Spacer`).\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **ResponsiveValue everywhere**: scalar for static (`gap=\"4\"`), object for\n adaptive (`gap={{ compact: '2', medium: '4', expanded: '6' }}`,\n `columns={{ compact: 1, medium: 2, expanded: 4 }}`). Breakpoints are\n `compact` (mobile-first base), `medium` (`md:`), `expanded` (`lg:`).\n2. **Separators, not manual dividers**: `<Stack separator={<Divider />}>` inserts\n dividers between children with no trailing element. Never hand-place a divider\n after every child.\n3. **Spacing scale**: `gap`/`p`/`m` use `SpacingKey` (Tailwind numeric scale strings,\n e.g. `'0'`, `'1'`, `'2'`, `'4'`, `'6'`, `'8'`, `'12'`, `'16'`). Never pass raw pixel strings to spacing props.\n4. **Strict subpath imports**:\n ```tsx\n import { Stack, HStack, Grid, Container, Box, Flex, ScrollArea } from '@wangs-ui/foundation/layout';\n ```\n5. **Translate visible labels** inside layout children via `t('...')` from\n `@wangs-ui/react-i18n` (layout props themselves are never translated).\n\n---\n\n## 4. Anti-Patterns (Forbidden)\n\n1. **Gap vs margin**: NEVER hardcode `marginBottom`/`mb-*` on children inside a\n Stack/Flex/Grid to fake spacing — always use the parent's `gap`/`gapX`/`gapY`.\n Margins collapse unpredictably and break `separator` insertion.\n2. **No nested Containers** and no `Container` for non-page content (cards, modals).\n3. **No `Flex` with hardcoded `flexDirection` styles** when `Stack`/`HStack` express it.\n4. **No raw media queries** for `direction`/`gap`/`columns` — use `ResponsiveValue`.\n5. **No `Grid` for one-dimensional lists** — that is `Stack`/`HStack` territory.\n";
29
29
  //#endregion
30
- //#region skills/wangs-ui-components/SKILL.md?raw
31
- var SKILL_default = "---\nname: wangs-ui-components\ndescription: Foundational rules, subpath imports, design tokens, and the MCP Discovery Protocol for building React apps with Wangs UI.\nmetadata:\n owner: wangs-ui\n---\n\n# Skill: Wangs UI Component Fundamentals & MCP Protocol\n\nUse this skill whenever you write or modify UI components using Wangs UI (`@wangs-ui/react-core`, `@wangs-ui/foundation`, `@wangs-ui/react-icons`, `@wangs-ui/react-presets`, `@wangs-ui/form`).\n\n---\n\n## 1. The MCP Discovery Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess component props, Pass-Through (`pt`) slots, or event names. Always query the MCP server dynamically to retrieve the current API signatures and live story implementations:\n\n```mermaid\ngraph TD\n A[Identify Component / Token Needed] --> B[list_catalog to confirm name/id]\n B --> C[get_component_api for typed contract]\n B --> D[get_documentation for curated guidance]\n C --> E{Need live story / variant code?}\n D --> E\n E -->|Yes| F[get_component_examples]\n E -->|No| G[Implement with Modular Subpaths]\n F --> G\n```\n\n### Discovery Steps:\n\n1. **Confirm Available Components & Blocks**:\n ```json\n list_catalog({ \"query\": \"button\" })\n list_catalog({ \"category\": \"component\" })\n ```\n2. **Inspect Component Contract & Props** (`component` parameter):\n ```json\n get_component_api({ \"component\": \"button\" })\n get_component_api({ \"component\": \"input\" })\n get_component_api({ \"component\": \"datatable\" })\n get_component_api({ \"component\": \"modal\" })\n ```\n3. **Inspect Curated Documentation** (`id` parameter):\n ```json\n get_documentation({ \"id\": \"foundation\" })\n get_documentation({ \"id\": \"button\" })\n get_documentation({ \"id\": \"form\" })\n ```\n4. **Inspect Live Usage & Story Variants**:\n ```json\n get_component_examples({ \"component\": \"button\", \"variant\": \"Sizes\" })\n get_component_examples({ \"component\": \"datatable\", \"variant\": \"CursorPagination\" })\n ```\n5. **Query Knowledge Graph & Symbol Relationships**:\n ```json\n query_graph({ \"query\": \"DataTable\" })\n query_graph({ \"query\": \"usePT\" })\n ```\n\n---\n\n## 2. Modular Subpath Imports (Mandatory)\n\nAlways import via specific subpaths to guarantee tree-shaking and avoid bundling entire packages:\n\n```tsx\n// 1. Core Primitives (@wangs-ui/react-core/primitive/*)\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport Input from '@wangs-ui/react-core/primitive/input';\nimport NumberInput from '@wangs-ui/react-core/primitive/numberinput';\nimport Textarea from '@wangs-ui/react-core/primitive/textarea';\nimport Select from '@wangs-ui/react-core/primitive/select';\nimport MultiSelect from '@wangs-ui/react-core/primitive/multiselect';\nimport Checkbox from '@wangs-ui/react-core/primitive/checkbox';\nimport Badge from '@wangs-ui/react-core/primitive/badge';\nimport Card from '@wangs-ui/react-core/primitive/card';\nimport DataTable from '@wangs-ui/react-core/primitive/datatable';\nimport Modal from '@wangs-ui/react-core/primitive/modal';\nimport Dialog from '@wangs-ui/react-core/primitive/dialog';\nimport DialogForm from '@wangs-ui/react-core/primitive/dialogform';\nimport { useForm, Form } from '@wangs-ui/react-core/primitive/form';\nimport Field from '@wangs-ui/react-core/primitive/field';\n\n// 2. Layout Primitives (@wangs-ui/foundation/layout)\nimport {\n Box,\n Flex,\n Stack,\n HStack,\n VStack,\n Grid,\n Container,\n Section,\n Show,\n} from '@wangs-ui/foundation/layout';\n\n// 3. Typography Primitives (@wangs-ui/foundation/theme)\nimport { Text, Code, Kbd, Link, Mark, Blockquote, List } from '@wangs-ui/foundation/theme';\n\n// 4. Blocks & Navigation (@wangs-ui/react-core/blocks/*)\nimport AppLayout from '@wangs-ui/react-core/blocks/applayout';\nimport Sidebar from '@wangs-ui/react-core/blocks/sidebar';\nimport TableToolbar from '@wangs-ui/react-core/blocks/tabletoolbar';\n\n// 5. Providers & System Hooks\nimport { WangsUiProvider } from '@wangs-ui/react-core/api';\nimport { ThemeProvider, useTheme } from '@wangs-ui/foundation/theme';\nimport { useI18n } from '@wangs-ui/react-i18n';\n\n// 6. Vector Icons (@wangs-ui/react-icons)\nimport { SearchLine, AddLine, DeleteBin6Line, CheckLine } from '@wangs-ui/react-icons';\n```\n\n---\n\n## 3. Strict Primitive Substitution Rule\n\nZero raw HTML elements. Never write raw HTML tags when a Wangs UI primitive exists:\n\n| Forbidden Raw HTML | Mandatory Wangs UI Primitive | Import Path | MCP Doc / Catalog ID |\n|:-------------------------------|:-----------------------------------------------------|:---------------------------------------------|:------------------------|\n| `<button>` | `Button` | `@wangs-ui/react-core/primitive/button` | `button` |\n| `<input type=\"text\">` | `Input` | `@wangs-ui/react-core/primitive/input` | `input` |\n| `<input type=\"number\">` | `NumberInput` | `@wangs-ui/react-core/primitive/numberinput` | `numberinput` |\n| `<input type=\"checkbox\">` | `Checkbox` | `@wangs-ui/react-core/primitive/checkbox` | `checkbox` |\n| `<select>` | `Select` / `MultiSelect` | `@wangs-ui/react-core/primitive/select` | `select`, `multiselect` |\n| `<textarea>` | `Textarea` | `@wangs-ui/react-core/primitive/textarea` | `textarea` |\n| `<form>` | `Form` / `DialogForm` | `@wangs-ui/react-core/primitive/form` | `form`, `dialogform` |\n| `<dialog>` / alert modal | `Modal` / `Dialog` | `@wangs-ui/react-core/primitive/modal` | `modal`, `dialog` |\n| `<table>` | `DataTable` | `@wangs-ui/react-core/primitive/datatable` | `datatable` |\n| `<div>` (layout / flex / grid) | `Stack`, `HStack`, `Flex`, `Grid`, `Box` | `@wangs-ui/foundation/layout` | `universal-layout` |\n| `<div>` (surface card) | `Card` | `@wangs-ui/react-core/primitive/card` | `card` |\n| Pill / status chip | `Badge` | `@wangs-ui/react-core/primitive/badge` | `badge` |\n| `<h1>` - `<h6>` | `<Text variant=\"headline*\">` / `display*` / `title*` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<p>`, `<span>` (body text) | `<Text variant=\"body*\">` / `label*` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<a>` | `Link` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<code>` | `Code` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<kbd>` | `Kbd` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<blockquote>` | `Blockquote` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<ul>`, `<ol>` | `List` | `@wangs-ui/foundation/theme` | `foundation` |\n\n---\n\n## 4. Typography System & `<Text>` Primitive\n\nWangs UI uses a unified typography token system with standard and emphasized variants. Do **NOT** use arbitrary text utilities (`text-[16px]`, `text-lg`) or obsolete `.heading-*` classes.\n\n### Primary Typography Primitive: `<Text>`\n\n```tsx\nimport { Text } from '@wangs-ui/foundation/theme';\n\n// Headings & Displays\n<Text variant=\"displayMedium\">Hero Title</Text>\n<Text variant=\"headlineLarge\">Page Header</Text>\n<Text variant=\"titleMedium\">Card Section Header</Text>\n\n// Body & Labels\n<Text variant=\"bodyMedium\">Standard reading paragraph text.</Text>\n<Text variant=\"bodySmall\" color=\"secondary\">Helper caption text.</Text>\n<Text variant=\"labelLarge\" weight=\"bold\">Interactive button or badge label</Text>\n\n// Polymorphic HTML Tag Override (default maps automatically: display/headline -> h1/h2, body -> p, label -> span)\n<Text variant=\"titleMedium\" as=\"h3\">Custom Tag Title</Text>\n```\n\n### Typography Roles:\n\n- **Display**: Page heroes (`displayLarge`, `displayMedium`, `displaySmall`)\n- **Headline**: Screen and page titles (`headlineLarge`, `headlineMedium`, `headlineSmall`)\n- **Title**: Card and modal section headers (`titleLarge`, `titleMedium`, `titleSmall`)\n- **Body**: Main copy and paragraphs (`bodyLarge`, `bodyMedium`, `bodySmall`)\n- **Label**: Buttons, inputs, and badges (`labelLarge`, `labelMedium`, `labelSmall`)\n- Append `Emphasized` for high-emphasis weights (e.g. `headlineMediumEmphasized`, `titleLargeEmphasized`).\n\n---\n\n## 5. Spacing Scale & Theming Invariants\n\n### Flat 4px Spacing Scale\n\nKeys follow the flat numeric Tailwind step (`1` unit `= 4px`):\n`0`, `0.5` (2px), `1` (4px), `1.5` (6px), `2` (8px), `2.5` (10px), `3` (12px), `3.5` (14px), `4` (16px), `5` (20px), `6` (24px), `8` (32px), `10` (40px), `12` (48px), `16` (64px).\n\n- **In Layout Primitives**: Pass keys directly: `<HStack gap=\"3\" p=\"4\">`\n- **In Tailwind Utilities**: Use standard numeric utilities: `p-4`, `gap-3`, `px-6`\n- **In React Native**: Read pixels via `useTheme().spacing`: `spacing[4] === 16`\n\n### Theming & Dark Mode Invariants\n\n- **Theme Provider**: Wrap app root with `<ThemeProvider defaultPalette=\"blue\" defaultMode=\"light\">`.\n- **Engine Invariant**: **NEVER** override `:root`, `[data-mode='dark']`, or `--color-*` variables in custom CSS. Always customize themes via `ThemeProvider` or `WangsUiProvider.configOptions.preset`.\n- **Dark Mode**: Toggle only via `useTheme().setMode('dark' | 'light')` — never mutate `document.documentElement.classList`.\n\n---\n\n## 6. Layout Governance & Redundant Wrapper Rule\n\n1. **Use Layout Primitives**: Arrange layouts using `Stack`, `HStack`, `VStack`, `Flex`, `Grid`, and `Box` from `@wangs-ui/foundation/layout`.\n2. **Zero Redundant Wrappers**: Never wrap a single component in an unnecessary `<div>` or `<Box>` (e.g. `<div><DataTable /></div>` or `<Box><Card /></Box>`).\n3. **No Inline Styling Overrides**: Component visual styling lives in global presets. Do not pass ad-hoc utility classes (`className=\"h-5 w-5\"`, `rounded-lg`) directly to primitives or icons unless documented as an MCP exception.\n";
30
+ //#region skills/wangs-ui/wangs-ui-components/SKILL.md?raw
31
+ var SKILL_default = "---\nname: wangs-ui-components\ndescription: MCP Discovery Protocol, modular subpath import map, and primitive substitution map for Wangs UI applications.\nmetadata:\n owner: wangs-ui\n---\n\n# Skill: Wangs UI Component Fundamentals & MCP Protocol\n\nUse this skill to navigate the Wangs UI ecosystem. **MCP is the single source of truth** for all component APIs, props, variants, slots, and examples. Do not hardcode or assume props — always query MCP dynamically.\n\n---\n\n## 1. The MCP Discovery Protocol (Single Source of Truth)\n\nDo **NOT** guess component props, Pass-Through (`pt`) slots, or event names. Always query the MCP server dynamically:\n\n```mermaid\ngraph TD\n A[Identify Component / Primitive Needed] --> B[list_catalog to confirm name/id]\n B --> C[get_component_api for typed contract]\n B --> D[get_documentation for curated guidance]\n C --> E{Need live story / variant code?}\n D --> E\n E -->|Yes| F[get_component_examples]\n E -->|No| G[Implement with Subpath Import Map]\n F --> G\n```\n\n### Discovery Steps:\n\n1. **Discover Catalog Entries**:\n ```json\n list_catalog({ \"query\": \"button\" })\n list_catalog({ \"category\": \"component\" })\n ```\n2. **Inspect Typed Contracts & Props** (`component` parameter):\n ```json\n get_component_api({ \"component\": \"button\" })\n get_component_api({ \"component\": \"datatable\" })\n get_component_api({ \"component\": \"field\" })\n ```\n3. **Read Curated Narrative Documentation** (`id` parameter):\n ```json\n get_documentation({ \"id\": \"button\" })\n get_documentation({ \"id\": \"foundation\" })\n get_documentation({ \"id\": \"form\" })\n ```\n4. **Fetch Live Storybook TSX Examples**:\n ```json\n get_component_examples({ \"component\": \"button\", \"variant\": \"Sizes\" })\n get_component_examples({ \"component\": \"datatable\", \"variant\": \"Basic\" })\n ```\n5. **Explore Knowledge Graph Relationships**:\n ```json\n query_graph({ \"query\": \"DataTable\" })\n query_graph({ \"query\": \"useForm\" })\n ```\n\n---\n\n## 2. Modular Subpath Import Map\n\nAlways import via specific subpath modules to guarantee tree-shaking and avoid bundling entire packages:\n\n| Ecosystem Layer | Subpath Pattern | Example Imports |\n| :--- | :--- | :--- |\n| **Core Primitives** | `@wangs-ui/react-core/primitive/<name>` | `Button`, `Input`, `Select`, `DataTable`, `Dialog`, `Modal`, `Field`, `Form`, `Card`, `Badge` |\n| **Layout Primitives** | `@wangs-ui/foundation/layout` | `Stack`, `HStack`, `VStack`, `Flex`, `Grid`, `Box`, `Container`, `Section`, `ScrollArea` |\n| **Typography Primitives** | `@wangs-ui/foundation/theme` | `Text`, `Code`, `Kbd`, `Link`, `Blockquote`, `List`, `Mark` |\n| **Blocks & Shells** | `@wangs-ui/react-core/blocks/<name>` | `AppLayout`, `Sidebar`, `TableToolbar` |\n| **Form Engine** | `@wangs-ui/form/core`, `@wangs-ui/form/react` | Headless form state, hooks, validation adapters |\n| **Universal Navigation** | `@wangs-ui/react-navigation/web`, `@wangs-ui/react-navigation/native` | `buildGraph`, `paramRoute`, platform router bridges |\n| **Theme & Providers** | `@wangs-ui/react-core/api`, `@wangs-ui/foundation/theme` | `WangsUiProvider`, `ThemeProvider`, `useTheme` |\n| **Vector Icons** | `@wangs-ui/react-icons` | `SearchLine`, `AddLine`, `DeleteBin6Line`, `CheckLine` |\n| **i18n & Localization** | `@wangs-ui/react-i18n` | `useI18n`, `t`, `WangsUiI18nProvider` |\n\n---\n\n## 3. Primitive Substitution Map\n\nZero raw HTML elements. Never write raw HTML tags when a Wangs UI primitive exists:\n\n| Forbidden Raw HTML | Mandatory Wangs UI Primitive | Import Path | MCP Catalog / Doc ID |\n| :--- | :--- | :--- | :--- |\n| `<button>` | `Button` | `@wangs-ui/react-core/primitive/button` | `button` |\n| `<input type=\"text\">` | `Input` | `@wangs-ui/react-core/primitive/input` | `input` |\n| `<input type=\"number\">` | `NumberInput` | `@wangs-ui/react-core/primitive/numberinput` | `numberinput` |\n| `<input type=\"checkbox\">` | `Checkbox` | `@wangs-ui/react-core/primitive/checkbox` | `checkbox` |\n| `<select>` | `Select` / `MultiSelect` | `@wangs-ui/react-core/primitive/select` | `select`, `multiselect` |\n| `<textarea>` | `Textarea` | `@wangs-ui/react-core/primitive/textarea` | `textarea` |\n| `<form>` | `Form` / `DialogForm` | `@wangs-ui/react-core/primitive/form` | `form`, `dialogform` |\n| `<dialog>` / alert modal | `Modal` / `Dialog` | `@wangs-ui/react-core/primitive/modal` | `modal`, `dialog` |\n| `<table>` | `DataTable` | `@wangs-ui/react-core/primitive/datatable` | `datatable` |\n| `<div>` (layout / flex / grid) | `Stack`, `HStack`, `Flex`, `Grid`, `Box` | `@wangs-ui/foundation/layout` | `universal-layout` |\n| `<div>` (surface card) | `Card` | `@wangs-ui/react-core/primitive/card` | `card` |\n| Pill / status chip | `Badge` | `@wangs-ui/react-core/primitive/badge` | `badge` |\n| `<h1>` - `<h6>` | `<Text variant=\"...\">` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<p>`, `<span>` (body text) | `<Text variant=\"...\">` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<a>` | `Link` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<code>` | `Code` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<kbd>` | `Kbd` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<blockquote>` | `Blockquote` | `@wangs-ui/foundation/theme` | `foundation` |\n| `<ul>`, `<ol>` | `List` | `@wangs-ui/foundation/theme` | `foundation` |\n";
32
32
  //#endregion
33
- //#region rules/react19-checklist-and-reference.md?raw
33
+ //#region rules/wangs-ui/default-props-precedence.md?raw
34
+ var default_props_precedence_default = "---\ntrigger: model_decision\ndescription: \"Apply when deciding whether a prop belongs in global defaultProps config or per-instance JSX.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Wangs UI Fact: `configOptions.defaultProps` Precedence\n\n`WangsUiProvider.configOptions.defaultProps` lets any project set global\ndefault prop values per component. Per-instance JSX props always win over\nthat global default — the merge order is global-default-then-instance, never\nthe reverse. This is a `WangsUiProvider` mechanism, true in any project that\nuses it, independent of what values a given project actually configures.\n";
35
+ //#endregion
36
+ //#region rules/wangs-ui/forms-destructuring-lock.md?raw
37
+ var forms_destructuring_lock_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing a <Field> render-prop callback in a Wangs UI Form/DialogForm.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Wangs UI Fact: `<Field>` Render-Prop Must Destructure `{ fieldProps, fieldState }`\n\n`<Field>`'s callback render prop must destructure as `{({ fieldProps, fieldState })}`.\nPassing a single parameter instead (`{(field) => ...}`) produces `undefined`\n`value`/`onChange` and permanently locks the input — the field never becomes\ninteractive, even on initial render. This is a real `@wangs-ui/form` quirk,\nnot a project convention; it reproduces the same way in any consumer.\n\n`<Field>` is generic — `fieldProps.onChange` is already typed to the field's\nactual value type. Pass it straight through (`fieldProps.onChange`); don't\nwrap it in a defensive `typeof`/`e?.target?.value` extraction, that's fighting\na type the field already guarantees.\n";
38
+ //#endregion
39
+ //#region rules/wangs-ui/no-raw-html.md?raw
40
+ var no_raw_html_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing JSX markup — enforce Wangs UI primitives over raw HTML elements.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: No Raw HTML Controls\n\nZero raw HTML elements. Use Wangs UI primitives and Foundation theme typography.\n\n## Prohibitions\n\n- No `<button>`, `<input>`, `<select>`, `<textarea>`, `<form>`, `<table>`, `<dialog>`.\n- No `<h1>`-`<h6>`, `<p>`, `<span>` for text typography without Wangs UI theme primitives.\n\n## Mandatory Imports\n\n- Primitives via subpath:\n - `@wangs-ui/react-core/primitive/button`\n - `@wangs-ui/react-core/primitive/input`\n - `@wangs-ui/react-core/primitive/datatable`\n - `@wangs-ui/react-core/primitive/modal`\n - `@wangs-ui/react-core/primitive/dialogform`\n - `@wangs-ui/react-core/primitive/card`\n - `@wangs-ui/react-core/primitive/badge`\n- Typography via Foundation theme:\n - `@wangs-ui/foundation/theme` (`Text`, `Code`, `Kbd`, `Link`, `Mark`, `Blockquote`, `List`)\n - Use variants: `display*`, `headline*`, `title*`, `body*`, `label*`.\n";
41
+ //#endregion
42
+ //#region rules/wangs-ui/no-redundant-wrappers.md?raw
43
+ var no_redundant_wrappers_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing JSX layout for redundant wrapper containers.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: No Redundant Layout & Container Wrappers\n\n> **Severity**: **ARCHITECTURAL CODE SMELL / LINT FAILURE**.\n\nComponents must not be wrapped in an unnecessary layout element. A `<div>` (or `Box`/`Stack`) wrapping a single component without active layout coordination is strictly prohibited — see `.agents/skills/universal-layout` and `.agents/rules/no-inline-component-styling.md` §2 for which primitive replaces a raw `<div>` when layout coordination is genuinely needed.\n\n---\n\n## 1. Prohibited Anti-Patterns\n\n1. **Single-Child Wrapper `<div>`**:\n Never wrap a single component (e.g. `<DataTable />`, `<Card />`, `<Tabs />`, `<Input />`, `<Button />`) inside an isolated `<div>` that has no layout siblings.\n2. **Intermediate Tab/Card Wrappers**:\n Do not insert pass-through `<div>` wrappers between `<Card>`/`<Tabs>` and feature content:\n ```tsx\n // ❌ Bad — Redundant intermediate div wrapping a single tab component\n function TabbedPage() {\n return (\n <Card>\n <Tabs ... />\n <div>\n {activeTab === 'general' ? <GeneralTab /> : <AdvancedTab />}\n </div>\n </Card>\n );\n }\n\n // ✅ Good — Render active tab directly as Card child\n function TabbedPage() {\n return (\n <Card>\n <Tabs ... />\n {activeTab === 'general' ? <GeneralTab /> : <AdvancedTab />}\n </Card>\n );\n }\n ```\n3. **Redundant Table Wrappers**:\n Never wrap `<DataTable />` in a `Box`/`div` solely to set width or margin. Wangs UI DataTable manages its own container scroll and dimensions out of the box.\n\n---\n\n## 2. When a Layout Wrapper Is Permitted\n\nA layout wrapper is **ONLY** warranted when coordinating **2 or more siblings** in a structural layout — and even then it's a `universal-layout` primitive, not a raw `<div>`:\n\n1. **Alignment bars**: header title + search + action buttons → `<HStack justify=\"between\">`.\n2. **Multi-column/card grids**: responsive multi-card or multi-field layouts → `<Grid columns={{ compact: 1, medium: 2, expanded: 3 }}>`.\n3. **Fragment Alternative**: when returning multiple adjacent elements without layout coordination, use React Fragment (`<>...</>`) — not an empty wrapper.\n";
44
+ //#endregion
45
+ //#region rules/wangs-ui/react19-checklist-and-reference.md?raw
34
46
  var react19_checklist_and_reference_default = "---\ntrigger: model_decision\ndescription: \"Apply when doing a final review pass on React 19 component or hook code for compiler-optimization compliance.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Review Checklist & Quick Reference\n\n## Checking Compiler Optimization\n\n- **React DevTools** — an optimized component shows a \"Memo ✨\" badge next to its name in the component tree.\n- **ESLint / Oxlint** — compiler's recommended rules flag Rules-of-React violations at lint time.\n\n## Review Checklist\n\n- [ ] Compiler confirmed active (\"Memo ✨\" badge) before removing any _existing_ manual memoization\n- [ ] No new `useMemo`/`useCallback`/`React.memo` added without documented reason (confirmed bail-out, or external boundary)\n- [ ] No prop/state/context mutation anywhere in render\n- [ ] All hooks called unconditionally at top level, same order every render\n- [ ] Side effects live in `useEffect`/event handlers, never during render\n- [ ] Components are `PascalCase`; hooks are `camelCase` and prefixed `use`\n- [ ] `ref` accepted as normal prop instead of `forwardRef`\n- [ ] Action/optimistic-update state modeled as discriminated union, not optional fields\n- [ ] Mutually exclusive prop combinations modeled as discriminated union `Props` type\n- [ ] Any `\"use no memo\"` usage has a comment explaining why\n\n## Quick Reference\n\n| Situation | Do |\n| ----------------------------------------------------------- | ------------------------------------------------------------- |\n| Tempted to write `useMemo`/`useCallback` | Don't — write plain expression, let compiler decide |\n| Need a ref on a function component | Accept `ref` as a prop, skip `forwardRef` |\n| Form/async state with distinct outcomes | Discriminated union via `useActionState`, not optional fields |\n| Callback needs latest props/state without re-running effect | `useEffectEvent` |\n| A hook/library is known-incompatible with compiler | `\"use no memo\"` at top of that function, with comment |\n| Checking if optimization is happening | React DevTools \"Memo ✨\" badge + compiler lint rules |\n";
35
47
  //#endregion
36
- //#region rules/react19-compiler-render-patterns.md?raw
48
+ //#region rules/wangs-ui/react19-compiler-render-patterns.md?raw
37
49
  var react19_compiler_render_patterns_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing render logic in a React 19 component.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Compiler-Friendly Render Patterns\n\n- Creating new object/array/function literals inline in render (`style={{ color }}`, `onClick={() => ...}`) is fine — stop manually hoisting or `useMemo`-wrapping these preemptively; the compiler memoizes them if it determines it's worthwhile.\n- Avoid module-level mutable variables read or written during render — that state is invisible to the compiler and breaks idempotence.\n- Don't use `useRef` to store a value that should trigger a re-render when it changes — refs are an imperative escape hatch, not state, and the compiler treats them as such.\n- Keep components small and composable. The compiler optimizes per component/hook boundary, so a single 300-line component gives it far less to work with than several focused ones.\n";
38
50
  //#endregion
39
- //#region rules/react19-naming-conventions.md?raw
51
+ //#region rules/wangs-ui/react19-naming-conventions.md?raw
40
52
  var react19_naming_conventions_default = "---\ntrigger: model_decision\ndescription: \"Apply when naming a React 19 component, hook, or prop.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Naming Conventions\n\nThe compiler identifies what to optimize by naming heuristics, same as the Rules of Hooks linter:\n\n| Kind | Convention | Notes |\n| ------------------------------------------------------------------------ | ------------------------------- | ----------------------------------------------------------------------------- |\n| Components | `PascalCase`, returns JSX | Compiler treats it as a component to optimize |\n| Custom hooks | `camelCase`, prefixed `use` | Required for both Rules-of-Hooks lint and compiler analysis |\n| Plain helper functions that return JSX-like values but aren't components | Avoid `PascalCase`/`use` naming | Prevents the compiler (and other devs) from mistaking it for a component/hook |\n";
41
53
  //#endregion
42
- //#region rules/react19-no-manual-memoization.md?raw
54
+ //#region rules/wangs-ui/react19-no-manual-memoization.md?raw
43
55
  var react19_no_manual_memoization_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing a React 19 component or hook that uses or is tempted to use useMemo/useCallback/React.memo.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Stop Hand-Rolling Memoization\n\nDon't reach for `useMemo`, `useCallback`, or `React.memo` by default — the compiler adds this automatically wherever it determines it helps.\n\n```tsx\n// ❌ Old habit — noisy, and a mismatched dependency array is a whole class of bugs\nconst filteredUsers = useMemo(() => users.filter((u) => u.isActive), [users]);\nconst handleClick = useCallback(() => onSelect(user.id), [onSelect, user.id]);\n\n// ✅ New default — just write the logic; the compiler memoizes what's worth memoizing\nconst filteredUsers = users.filter((u) => u.isActive);\nconst handleClick = () => onSelect(user.id);\n```\n\n## When manual memoization is still justified:\n\n- You've **confirmed a compiler bail-out** on a genuine hot path via profiling, and fixing the underlying Rules-of-React violation isn't possible right now.\n- A value must have **stable referential identity across a boundary the compiler can't see** — e.g. passed into a non-React library, a WebSocket subscription, or a third-party hook incompatible with the compiler (`react-hook-form`'s `useForm`, `@tanstack/react-table`'s `useReactTable` are known cases).\n- Keep any manual memoization it produces isolated and commented with _why_, so it doesn't silently rot into a bail-out later when the code around it changes.\n";
44
56
  //#endregion
45
- //#region rules/react19-primitives-typing.md?raw
57
+ //#region rules/wangs-ui/react19-primitives-typing.md?raw
46
58
  var react19_primitives_typing_default = "---\ntrigger: model_decision\ndescription: \"Apply when typing React 19 primitives — ref props, useActionState, useOptimistic, use(), useEffectEvent.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Typing React 19 Primitives\n\n## `ref` as a Normal Prop\n\n`forwardRef` is no longer required for most cases; function components accept `ref` directly.\n\n```tsx\ntype InputProps = {\n ref?: React.Ref<HTMLInputElement>;\n placeholder?: string;\n};\n\nfunction TextInput({ ref, placeholder }: InputProps) {\n return <input ref={ref} placeholder={placeholder} />;\n}\n```\n\n## Actions with `useActionState`\n\nType the state and payload as generics; model the result as a discriminated union rather than optional fields.\n\n```tsx\ntype FormState = { status: 'idle' } | { status: 'error'; message: string } | { status: 'success' };\n\nconst [state, formAction, isPending] = useActionState<FormState, FormData>(\n async (_previous, formData) => {\n const email = formData.get('email');\n if (typeof email !== 'string' || !email.includes('@')) {\n return { status: 'error', message: 'Invalid email' };\n }\n await submit(email);\n return { status: 'success' };\n },\n { status: 'idle' },\n);\n```\n\n## Optimistic Updates with `useOptimistic`\n\nType both the state and the update shape.\n\n```tsx\nconst [optimisticTodos, addOptimisticTodo] = useOptimistic<Todo[], Todo>(\n todos,\n (state, newTodo) => [...state, newTodo],\n);\n```\n\n## Reading Promises or Context with `use()`\n\nType the resolved value, not the promise wrapper; `use()` is not a hook and may be called conditionally.\n\n```tsx\nfunction Comments({ commentsPromise }: { commentsPromise: Promise<Comment[]> }) {\n const comments = use(commentsPromise); // suspends until resolved\n return (\n <ul>\n {comments.map((c) => (\n <li key={c.id}>{c.text}</li>\n ))}\n </ul>\n );\n}\n```\n\n## Stable Event Callbacks with `useEffectEvent` (React 19.2+)\n\nSeparates \"event\" logic from \"reactive\" effect logic so the callback always sees latest props/state without being listed as an effect dependency.\n\n```tsx\nconst onVisit = useEffectEvent((url: string) => {\n logVisit(url, theme); // always fresh `theme`, never re-triggers the effect\n});\n\nuseEffect(() => {\n onVisit(url);\n}, [url]); // `theme` intentionally omitted — onVisit is stable\n```\n";
47
59
  //#endregion
48
- //#region rules/react19-props-typing.md?raw
60
+ //#region rules/wangs-ui/react19-props-typing.md?raw
49
61
  var react19_props_typing_default = "---\ntrigger: model_decision\ndescription: \"Apply when defining a component's Props type or interface.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Typing Props\n\n- `interface` for a component's `Props` — it's an entity shape, often extended.\n- A discriminated union when a component has mutually exclusive prop combinations, instead of a pile of optional props that can contradict each other.\n\n```tsx\n// ❌ Bad — nothing stops passing both `href` and `onClick` incoherently\ninterface ButtonProps {\n label: string;\n href?: string;\n onClick?: () => void;\n}\n\n// ✅ Good — the two variants can't be mixed\ntype ButtonProps =\n | { variant: 'link'; label: string; href: string }\n | { variant: 'action'; label: string; onClick: () => void };\n```\n";
50
62
  //#endregion
51
- //#region rules/react19-purity-and-immutability.md?raw
63
+ //#region rules/wangs-ui/react19-purity-and-immutability.md?raw
52
64
  var react19_purity_and_immutability_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing a React 19 component or hook body for purity and immutability.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Purity and Immutability (Load-Bearing)\n\nThe compiler assumes your components and hooks are pure. Violating these rules causes the compiler to silently skip optimizing that component:\n\n- **Idempotent renders** — given the same props/state/context, a component must return the same output. No random values, no `Date.now()`, no side effects during render.\n- **Immutability** — never mutate props, state, or context directly. Always create new objects/arrays for changes.\n- **Side effects only in effects or event handlers** — never during render.\n- **Hooks called unconditionally, top-level, same order every render** — no hooks inside conditionals, loops, or nested functions.\n\n```tsx\n// ❌ Mutates a prop — breaks purity and the compiler can't safely memoize this\nfunction TodoList({ todos }: { todos: Todo[] }) {\n todos.sort((a, b) => a.priority - b.priority); // mutates caller's array\n return (\n <ul>\n {todos.map((t) => (\n <li key={t.id}>{t.title}</li>\n ))}\n </ul>\n );\n}\n\n// ✅ Creates a new array — pure, compiler-safe\nfunction TodoList({ todos }: { todos: Todo[] }) {\n const sorted = [...todos].sort((a, b) => a.priority - b.priority);\n return (\n <ul>\n {sorted.map((t) => (\n <li key={t.id}>{t.title}</li>\n ))}\n </ul>\n );\n}\n```\n";
53
65
  //#endregion
54
- //#region rules/react19-tooling-and-opt-out.md?raw
66
+ //#region rules/wangs-ui/react19-tooling-and-opt-out.md?raw
55
67
  var react19_tooling_and_opt_out_default = "---\ntrigger: model_decision\ndescription: 'Apply when configuring React Compiler tooling or opting a component out via \"use no memo\".'\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: React 19 — Tooling Setup & Compiler Opt-Out\n\n## Tooling Setup\n\n**The compiler is opt-in — no default setup enables it automatically.** Plain `@vitejs/plugin-react` (`react()`), plain Next.js, plain Babel/webpack config, etc. do **not** run the compiler on their own. Verify it's actually wired up before assuming manual memoization can be dropped.\n\n```bash\n# Compiler (build-time transform)\nnpm install --save-dev --save-exact babel-plugin-react-compiler@latest\n```\n\n### Lint rules — oxlint\n\nOxlint ships a **native, Rust-based** `react/react-compiler` rule:\n\n```json\n// .oxlintrc.json\n{\n \"plugins\": [\"react\"],\n \"rules\": {\n \"react/react-compiler\": \"error\"\n }\n}\n```\n\nThis single rule reports:\n\n- **Rules-of-React violations** (conditional hooks, reading a ref during render, mutating props) — must-fix bugs.\n- **Compiler bail-outs** — places compiler declined to optimize without rule violation.\n\n### Wiring into Vite 8\n\n```js\n// vite.config.js\nimport { defineConfig } from 'vite';\nimport react, { reactCompilerPreset } from '@vitejs/plugin-react';\nimport babel from '@rolldown/plugin-babel';\n\nexport default defineConfig({\n plugins: [\n babel({ presets: [reactCompilerPreset()] }), // must run before react()\n react(),\n ],\n});\n```\n\n```bash\nnpm install --save-dev @rolldown/plugin-babel @babel/core babel-plugin-react-compiler\n```\n\n## Incompatibility Escape Hatch (`\"use no memo\"`)\n\nIf a specific function is genuinely incompatible with compiler (e.g. calls `useForm` from `react-hook-form`), opt out with `\"use no memo\"` directive as **first line of function body** — leave a comment explaining why:\n\n```tsx\nfunction LegacyForm() {\n 'use no memo';\n const form = useForm(); // incompatible with the compiler today\n // ...\n}\n```\n";
56
68
  //#endregion
57
- //#region rules/typescript-assertions-last-resort.md?raw
69
+ //#region rules/wangs-ui/theme-variable-override-breaks-engine.md?raw
70
+ var theme_variable_override_breaks_engine_default = "---\ntrigger: model_decision\ndescription: \"Apply when tempted to override a Wangs UI theme CSS variable directly.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Wangs UI Fact: Theme Variables Are Engine-Internal, Never Override Directly\n\nManually defining or overriding `:root`, `[data-mode='dark']`, or `.dark` custom\nproperties owned by `@wangs-ui/foundation/theme` (`--color-*`, `--z-index-*`,\n`--spacing-*`, `--size-*`, `--shadow-*`, `--radius-*`) breaks the theme token\nengine: it destroys automatic light/dark mode transitions, corrupts sub-tree\ndensity overrides made via `<ThemeProvider>`, and causes cross-module visual\nbugs that don't reproduce consistently. This is true for any project consuming\n`@wangs-ui/foundation`, not specific to one app's setup.\n\nThe supported customization surface is `WangsUiProvider.configOptions.preset`\n— discover it via the `design-system`/`wangs-ui-components` skills' MCP calls,\nnever by reading or guessing the CSS variable names.\n";
71
+ //#endregion
72
+ //#region rules/wangs-ui/typescript-assertions-last-resort.md?raw
58
73
  var typescript_assertions_last_resort_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing a type assertion (`as X`) or non-null assertion (`x!`).\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Type Assertions & Non-Null Assertions are a Last Resort\n\n- `as X` and `x!` tell the compiler \"trust me\" — they produce zero runtime safety and actively hide bugs if wrong.\n- Acceptable only when the compiler genuinely cannot know something you do (e.g. a DOM query you've already null-checked, or narrowing a third-party type at a well-tested boundary) — and even then, prefer a type guard or a runtime check over a bare assertion.\n- Never use `as any` or `as unknown as X` to force an incompatible cast — that's `any` wearing a disguise.\n- `x!` should almost always be replaceable by an actual null check or optional chaining (`x?.y`) plus a real fallback.\n";
59
74
  //#endregion
60
- //#region rules/typescript-checklist-and-reference.md?raw
75
+ //#region rules/wangs-ui/typescript-checklist-and-reference.md?raw
61
76
  var typescript_checklist_and_reference_default = "---\ntrigger: model_decision\ndescription: \"Apply when doing a final TypeScript review pass on a file.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Review Checklist & Quick Reference\n\n## Review Checklist\n\nBefore considering TypeScript code \"done,\" verify:\n\n- [ ] No `any` anywhere (including implicit `any` from missing annotations)\n- [ ] External/uncertain data enters as `unknown` and is narrowed before use\n- [ ] Variant state is a discriminated union, not optional fields + booleans\n- [ ] `interface` used for object/entity shapes; `type` used for unions/aliases/intersections\n- [ ] No stray `I` prefixes on interfaces\n- [ ] Naming follows casing conventions consistently\n- [ ] `as` / `!` are rare, justified, and can't be replaced by a guard or null check\n- [ ] Exported functions/methods have explicit return types\n- [ ] Switch statements over unions have an exhaustiveness (`never`) check\n- [ ] `tsconfig.json` includes the strictness baseline\n\n## Quick Reference\n\n| Situation | Use |\n| ---------------------------------------------- | ------------------------------------------------------------- |\n| External/uncertain data | `unknown` + narrowing |\n| \"This value is definitely one of these shapes\" | Discriminated union (`type`) |\n| Object with identity, may be extended | `interface` |\n| Union, intersection, tuple, mapped type | `type` |\n| Need to prove a type through logic | Type guard / narrowing |\n| Tempted to write `any` | Stop — use `unknown`, a generic, or a local interface instead |\n";
62
77
  //#endregion
63
- //#region rules/typescript-discriminated-unions.md?raw
78
+ //#region rules/wangs-ui/typescript-discriminated-unions.md?raw
64
79
  var typescript_discriminated_unions_default = "---\ntrigger: model_decision\ndescription: \"Apply when modeling a variant or multi-shape state in TypeScript.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Discriminated Unions for Variant State\n\nWhenever a value can be one of several distinct \"shapes\" (loading/success/error states, event types, API response variants), model it as a **discriminated union** with a literal tag field — never as a loose object with optional fields or boolean flags.\n\n```ts\n// ❌ Bad — booleans can contradict each other; unclear which fields are valid together\ninterface FetchState {\n isLoading: boolean;\n isError: boolean;\n data?: User;\n error?: string;\n}\n\n// ✅ Good — only one shape is possible at a time, and the compiler enforces it\ntype FetchState =\n | { status: 'idle' }\n | { status: 'loading' }\n | { status: 'success'; data: User }\n | { status: 'error'; error: string };\n\nfunction render(state: FetchState) {\n switch (state.status) {\n case 'success':\n return state.data.name; // `data` is guaranteed to exist here\n case 'error':\n return state.error; // `error` is guaranteed to exist here\n default:\n return null;\n }\n}\n```\n\nUse a consistent tag field name across a codebase (`kind`, `type`, or `status` — pick one and stick with it) so narrowing patterns stay predictable.\n";
65
80
  //#endregion
66
- //#region rules/typescript-explicit-return-types.md?raw
81
+ //#region rules/wangs-ui/typescript-explicit-return-types.md?raw
67
82
  var typescript_explicit_return_types_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing an exported function, class method, or public API surface in TypeScript.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Explicit Return Types on Exported Functions\n\nInference is fine for local, private helpers, but exported functions, class methods, and anything forming a public API should declare an explicit return type. This prevents an internal implementation change from silently widening/narrowing the public contract.\n\n```ts\n// ❌ Return type is inferred and can silently drift\nexport function getActiveUsers(users: User[]) {\n return users.filter((u) => u.active);\n}\n\n// ✅ Explicit, intentional contract\nexport function getActiveUsers(users: User[]): User[] {\n return users.filter((u) => u.active);\n}\n```\n";
68
83
  //#endregion
69
- //#region rules/typescript-interface-vs-type.md?raw
84
+ //#region rules/wangs-ui/typescript-interface-vs-type.md?raw
70
85
  var typescript_interface_vs_type_default = "---\ntrigger: model_decision\ndescription: \"Apply when deciding between `interface` and `type` for a new TypeScript declaration.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — `interface` vs `type`\n\nBoth can describe object shapes, but they signal different intent. Default rule:\n\n| Use `interface` for... | Use `type` for... |\n| -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |\n| Object / entity shapes (a `User`, a `Product`, a component's `Props`) | Unions (`\"a\" \\| \"b\"`) and discriminated unions |\n| Public API contracts meant to be `implements`-ed by classes | Intersections (`A & B`) |\n| Shapes that consumers may want to **extend/augment** (declaration merging) | Tuples (`[string, number]`) |\n| | Function types / callback signatures |\n| | Mapped, conditional, or utility-derived types (`Partial<T>`, `Pick<T, K>`) |\n| | Aliasing a primitive or another type for readability |\n\n```ts\n// ✅ interface — an entity with identity, extendable\ninterface User {\n id: string;\n email: string;\n role: UserRole;\n}\n\ninterface AdminUser extends User {\n permissions: Permission[];\n}\n\n// ✅ type — union, alias, derived shape\ntype UserRole = 'admin' | 'editor' | 'viewer';\ntype UserId = User['id'];\ntype PartialUser = Partial<User>;\ntype Callback<T> = (value: T) => void;\n```\n\nDon't mix conventions arbitrarily within one file — if a shape is a plain data object that will never need a union/intersection, `interface` is the default; the moment it needs to express \"one of several shapes,\" reach for `type`.\n";
71
86
  //#endregion
72
- //#region rules/typescript-literal-unions-vs-enums.md?raw
87
+ //#region rules/wangs-ui/typescript-literal-unions-vs-enums.md?raw
73
88
  var typescript_literal_unions_vs_enums_default = "---\ntrigger: model_decision\ndescription: \"Apply when modeling a fixed set of string or numeric variants in TypeScript.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Prefer Literal Unions Over Numeric Enums\n\nString literal unions are simpler, tree-shake better, and produce clearer error messages than TypeScript `enum`. Reserve `enum` (or `as const` object maps) for cases that need reverse lookup or genuinely benefit from a namespaced runtime value.\n\n```ts\n// ✅ Preferred\ntype OrderStatus = 'pending' | 'shipped' | 'delivered' | 'cancelled';\n\n// Acceptable when a namespaced runtime object is actually needed\nconst OrderStatus = {\n Pending: 'pending',\n Shipped: 'shipped',\n} as const;\ntype OrderStatus = (typeof OrderStatus)[keyof typeof OrderStatus];\n```\n";
74
89
  //#endregion
75
- //#region rules/typescript-naming-conventions.md?raw
90
+ //#region rules/wangs-ui/typescript-naming-conventions.md?raw
76
91
  var typescript_naming_conventions_default = "---\ntrigger: model_decision\ndescription: \"Apply when naming a TypeScript type, variable, or constant.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Naming Conventions\n\n| Kind | Convention | Example |\n| ---------------------------------------------------------- | ------------------------------------------- | ----------------------------------- |\n| Types, interfaces, classes, enums | `PascalCase` | `UserProfile`, `OrderStatus` |\n| Interfaces | `PascalCase`, **no `I` prefix** | `User`, not `IUser` |\n| Type aliases | `PascalCase` | `type ApiResponse<T> = ...` |\n| Variables, functions, methods, properties | `camelCase` | `getUserById`, `isValid` |\n| Booleans | `camelCase` with `is/has/should/can` prefix | `isLoading`, `hasPermission` |\n| True constants (module-level, never reassigned, primitive) | `UPPER_SNAKE_CASE` | `MAX_RETRIES`, `DEFAULT_TIMEOUT_MS` |\n| Enum members | `PascalCase` | `enum Status { Active, Archived }` |\n| Generic type parameters (simple, single-purpose) | Single uppercase letter | `T`, `K`, `V`, `E` for errors |\n| Generic type parameters (multiple / non-obvious) | Descriptive, prefixed with `T` | `TInput`, `TOutput`, `TContext` |\n| Discriminated union tag field | Consistent across the codebase | `kind`, `type`, or `status` |\n| Files with a single exported entity | Match the entity name | `UserProfile.ts`, `useAuth.ts` |\n\nNaming should describe **intent**, not implementation — `fetchUser` not `getUserFromApiEndpoint`; `retryCount` not `numRetries2`.\n";
77
92
  //#endregion
78
- //#region rules/typescript-narrowing-over-casting.md?raw
93
+ //#region rules/wangs-ui/typescript-narrowing-over-casting.md?raw
79
94
  var typescript_narrowing_over_casting_default = "---\ntrigger: model_decision\ndescription: \"Apply when narrowing an `unknown` or union-typed value in TypeScript.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — `unknown` + Narrowing, Not Casting\n\nPrefer proving a type through control flow over asserting it with `as`.\n\n## Narrowing techniques, in order of preference:\n\n1. **`typeof`** — primitives (`string`, `number`, `boolean`, `undefined`, `function`)\n2. **`instanceof`** — class instances, `Error`, `Date`, custom classes\n3. **`in`** — checking a property exists before accessing it on a union/unknown\n4. **User-defined type guards** — `function isUser(x: unknown): x is User`\n5. **Discriminated union tag checks** — `switch (value.kind) { ... }`\n6. **Exhaustiveness checks** — a `never`-typed default branch so adding a new variant is a compile error until every switch/if-chain handles it\n\n```ts\n// ✅ Type guard\nfunction isUser(value: unknown): value is User {\n return typeof value === 'object' && value !== null && 'id' in value && 'email' in value;\n}\n\n// ✅ Exhaustiveness check\nfunction assertNever(x: never): never {\n throw new Error(`Unhandled case: ${JSON.stringify(x)}`);\n}\n\nfunction area(shape: Shape): number {\n switch (shape.kind) {\n case 'circle':\n return Math.PI * shape.radius ** 2;\n case 'square':\n return shape.side ** 2;\n default:\n return assertNever(shape); // compile error if a variant is missed\n }\n}\n```\n\nType assertions (`as X`) and the non-null assertion (`!`) bypass this entirely — treat them as a last resort, not a shortcut.\n";
80
95
  //#endregion
81
- //#region rules/typescript-readonly-by-default.md?raw
96
+ //#region rules/wangs-ui/typescript-readonly-by-default.md?raw
82
97
  var typescript_readonly_by_default_default = "---\ntrigger: model_decision\ndescription: \"Apply when declaring a TypeScript collection or object shape.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Readonly by Default\n\nPrefer immutable shapes unless mutation is intentional and localized.\n\n```ts\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\nfunction config(values: readonly string[]) {\n /* ... */\n}\n\nconst ROLES = ['admin', 'editor', 'viewer'] as const;\ntype UserRole = (typeof ROLES)[number];\n```\n";
83
98
  //#endregion
84
- //#region rules/typescript-tsconfig-strictness.md?raw
99
+ //#region rules/wangs-ui/typescript-tsconfig-strictness.md?raw
85
100
  var typescript_tsconfig_strictness_default = "---\ntrigger: model_decision\ndescription: \"Apply when configuring or reviewing tsconfig.json compiler strictness options.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Baseline `tsconfig.json` Strictness\n\nTreat these as the non-negotiable floor for any project this rule touches:\n\n```json\n{\n \"compilerOptions\": {\n \"strict\": true,\n \"noImplicitAny\": true,\n \"strictNullChecks\": true,\n \"strictFunctionTypes\": true,\n \"strictPropertyInitialization\": true,\n \"noUncheckedIndexedAccess\": true,\n \"exactOptionalPropertyTypes\": true,\n \"noImplicitOverride\": true,\n \"noFallthroughCasesInSwitch\": true,\n \"noUnusedLocals\": true,\n \"noUnusedParameters\": true,\n \"forceConsistentCasingInFileNames\": true\n }\n}\n```\n\n`strict: true` alone enables the core group (`noImplicitAny`, `strictNullChecks`, etc.), but `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` are commonly missed and close real gaps (array/object index access returning `T` instead of `T | undefined`; optional properties silently accepting `undefined` as an explicit value).\n";
86
101
  //#endregion
87
- //#region rules/typescript-zero-any.md?raw
102
+ //#region rules/wangs-ui/typescript-zero-any.md?raw
88
103
  var typescript_zero_any_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing any TypeScript type annotation.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: TypeScript — Never Use `any`\n\n`any` is not \"unknown type,\" it's \"type checking off.\" It's contagious — once a value is `any`, everything it touches becomes unchecked too.\n\n- Never write `any` for parameters, return types, variables, or generics.\n- Use `unknown` for genuinely unknown external data (API responses, `JSON.parse`, catch clauses, third-party callbacks) and narrow it before use.\n- Use generics (`<T>`) when a function needs to work across types but preserve the relationship between input and output.\n- If a library ships untyped, write a minimal local type/interface for the surface area you actually use instead of reaching for `any`.\n\n```ts\n// ❌ Bad\nfunction parseConfig(json: any) {\n return json.settings.theme; // no safety, no autocomplete, silent runtime crash\n}\n\n// ✅ Good\nfunction parseConfig(json: unknown): string {\n if (\n typeof json === 'object' &&\n json !== null &&\n 'settings' in json &&\n typeof (json as { settings: unknown }).settings === 'object'\n ) {\n // still narrow further or validate with a schema library (zod, valibot, etc.)\n }\n throw new Error('Invalid config shape');\n}\n```\n\nThe only acceptable `any` is a well-justified, isolated, and commented one (e.g. interfacing with a genuinely untyped legacy module) — never a default.\n";
89
104
  //#endregion
90
- //#region rules/wangs-ui/default-props-precedence.md?raw
91
- var default_props_precedence_default = "---\ntrigger: model_decision\ndescription: \"Apply when deciding whether a prop belongs in global defaultProps config or per-instance JSX.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Wangs UI Fact: `configOptions.defaultProps` Precedence\n\n`WangsUiProvider.configOptions.defaultProps` lets any project set global\ndefault prop values per component. Per-instance JSX props always win over\nthat global default — the merge order is global-default-then-instance, never\nthe reverse. This is a `WangsUiProvider` mechanism, true in any project that\nuses it, independent of what values a given project actually configures.\n";
92
- //#endregion
93
- //#region rules/wangs-ui/forms-destructuring-lock.md?raw
94
- var forms_destructuring_lock_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing a <Field> render-prop callback in a Wangs UI Form/DialogForm.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Wangs UI Fact: `<Field>` Render-Prop Must Destructure `{ fieldProps, fieldState }`\n\n`<Field>`'s callback render prop must destructure as `{({ fieldProps, fieldState })}`.\nPassing a single parameter instead (`{(field) => ...}`) produces `undefined`\n`value`/`onChange` and permanently locks the input — the field never becomes\ninteractive, even on initial render. This is a real `@wangs-ui/form` quirk,\nnot a project convention; it reproduces the same way in any consumer.\n\n`<Field>` is generic — `fieldProps.onChange` is already typed to the field's\nactual value type. Pass it straight through (`fieldProps.onChange`); don't\nwrap it in a defensive `typeof`/`e?.target?.value` extraction, that's fighting\na type the field already guarantees.\n";
95
- //#endregion
96
- //#region rules/wangs-ui/no-raw-html.md?raw
97
- var no_raw_html_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing JSX markup — enforce Wangs UI primitives over raw HTML elements.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: No Raw HTML Controls\n\nZero raw HTML elements. Use Wangs UI primitives and Foundation theme typography.\n\n## Prohibitions\n\n- No `<button>`, `<input>`, `<select>`, `<textarea>`, `<form>`, `<table>`, `<dialog>`.\n- No `<h1>`-`<h6>`, `<p>`, `<span>` for text typography without Wangs UI theme primitives.\n\n## Mandatory Imports\n\n- Primitives via subpath:\n - `@wangs-ui/react-core/primitive/button`\n - `@wangs-ui/react-core/primitive/input`\n - `@wangs-ui/react-core/primitive/datatable`\n - `@wangs-ui/react-core/primitive/modal`\n - `@wangs-ui/react-core/primitive/dialogform`\n - `@wangs-ui/react-core/primitive/card`\n - `@wangs-ui/react-core/primitive/badge`\n- Typography via Foundation theme:\n - `@wangs-ui/foundation/theme` (`Text`, `Code`, `Kbd`, `Link`, `Mark`, `Blockquote`, `List`)\n - Use variants: `display*`, `headline*`, `title*`, `body*`, `label*`.\n";
98
- //#endregion
99
- //#region rules/wangs-ui/no-redundant-wrappers.md?raw
100
- var no_redundant_wrappers_default = "---\ntrigger: model_decision\ndescription: \"Apply when writing or reviewing JSX layout for redundant wrapper containers.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Rule: No Redundant Layout & Container Wrappers\n\n> **Severity**: **ARCHITECTURAL CODE SMELL / LINT FAILURE**.\n\nComponents must not be wrapped in an unnecessary layout element. A `<div>` (or `Box`/`Stack`) wrapping a single component without active layout coordination is strictly prohibited — see `.agents/skills/universal-layout` and `.agents/rules/no-inline-component-styling.md` §2 for which primitive replaces a raw `<div>` when layout coordination is genuinely needed.\n\n---\n\n## 1. Prohibited Anti-Patterns\n\n1. **Single-Child Wrapper `<div>`**:\n Never wrap a single component (e.g. `<DataTable />`, `<Card />`, `<Tabs />`, `<Input />`, `<Button />`) inside an isolated `<div>` that has no layout siblings.\n2. **Intermediate Tab/Card Wrappers**:\n Do not insert pass-through `<div>` wrappers between `<Card>`/`<Tabs>` and feature content:\n ```tsx\n // ❌ Bad — Redundant intermediate div wrapping a single tab component\n function TabbedPage() {\n return (\n <Card>\n <Tabs ... />\n <div>\n {activeTab === 'general' ? <GeneralTab /> : <AdvancedTab />}\n </div>\n </Card>\n );\n }\n\n // ✅ Good — Render active tab directly as Card child\n function TabbedPage() {\n return (\n <Card>\n <Tabs ... />\n {activeTab === 'general' ? <GeneralTab /> : <AdvancedTab />}\n </Card>\n );\n }\n ```\n3. **Redundant Table Wrappers**:\n Never wrap `<DataTable />` in a `Box`/`div` solely to set width or margin. Wangs UI DataTable manages its own container scroll and dimensions out of the box.\n\n---\n\n## 2. When a Layout Wrapper Is Permitted\n\nA layout wrapper is **ONLY** warranted when coordinating **2 or more siblings** in a structural layout — and even then it's a `universal-layout` primitive, not a raw `<div>`:\n\n1. **Alignment bars**: header title + search + action buttons → `<HStack justify=\"between\">`.\n2. **Multi-column/card grids**: responsive multi-card or multi-field layouts → `<Grid columns={{ compact: 1, medium: 2, expanded: 3 }}>`.\n3. **Fragment Alternative**: when returning multiple adjacent elements without layout coordination, use React Fragment (`<>...</>`) — not an empty wrapper.\n";
101
- //#endregion
102
- //#region rules/wangs-ui/theme-variable-override-breaks-engine.md?raw
103
- var theme_variable_override_breaks_engine_default = "---\ntrigger: model_decision\ndescription: \"Apply when tempted to override a Wangs UI theme CSS variable directly.\"\nowner: wangs-ui\nmetadata:\n owner: wangs-ui\n---\n# Wangs UI Fact: Theme Variables Are Engine-Internal, Never Override Directly\n\nManually defining or overriding `:root`, `[data-mode='dark']`, or `.dark` custom\nproperties owned by `@wangs-ui/foundation/theme` (`--color-*`, `--z-index-*`,\n`--spacing-*`, `--size-*`, `--shadow-*`, `--radius-*`) breaks the theme token\nengine: it destroys automatic light/dark mode transitions, corrupts sub-tree\ndensity overrides made via `<ThemeProvider>`, and causes cross-module visual\nbugs that don't reproduce consistently. This is true for any project consuming\n`@wangs-ui/foundation`, not specific to one app's setup.\n\nThe supported customization surface is `WangsUiProvider.configOptions.preset`\n— discover it via the `design-system`/`wangs-ui-components` skills' MCP calls,\nnever by reading or guessing the CSS variable names.\n";
104
- //#endregion
105
105
  //#region src/registry.ts
106
106
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
107
107
  var EMBEDDED_SKILLS_RAW = /* #__PURE__ */ Object.assign({
108
- "../skills/craft-theme/SKILL.md": SKILL_default$8,
109
- "../skills/create-form/SKILL.md": SKILL_default$7,
110
- "../skills/data-table/SKILL.md": SKILL_default$6,
111
- "../skills/dialog-modal/SKILL.md": SKILL_default$5,
112
- "../skills/i18n-usage/SKILL.md": SKILL_default$4,
113
- "../skills/layout-navigation/SKILL.md": SKILL_default$3,
114
- "../skills/responsive-design/SKILL.md": SKILL_default$2,
115
- "../skills/universal-layout/SKILL.md": SKILL_default$1,
116
- "../skills/wangs-ui-components/SKILL.md": SKILL_default
108
+ "../skills/wangs-ui/craft-theme/SKILL.md": SKILL_default$8,
109
+ "../skills/wangs-ui/create-form/SKILL.md": SKILL_default$7,
110
+ "../skills/wangs-ui/data-table/SKILL.md": SKILL_default$6,
111
+ "../skills/wangs-ui/dialog-modal/SKILL.md": SKILL_default$5,
112
+ "../skills/wangs-ui/i18n-usage/SKILL.md": SKILL_default$4,
113
+ "../skills/wangs-ui/layout-navigation/SKILL.md": SKILL_default$3,
114
+ "../skills/wangs-ui/responsive-design/SKILL.md": SKILL_default$2,
115
+ "../skills/wangs-ui/universal-layout/SKILL.md": SKILL_default$1,
116
+ "../skills/wangs-ui/wangs-ui-components/SKILL.md": SKILL_default
117
117
  });
118
118
  var EMBEDDED_RULES_RAW = /* #__PURE__ */ Object.assign({
119
- "../rules/react19-checklist-and-reference.md": react19_checklist_and_reference_default,
120
- "../rules/react19-compiler-render-patterns.md": react19_compiler_render_patterns_default,
121
- "../rules/react19-naming-conventions.md": react19_naming_conventions_default,
122
- "../rules/react19-no-manual-memoization.md": react19_no_manual_memoization_default,
123
- "../rules/react19-primitives-typing.md": react19_primitives_typing_default,
124
- "../rules/react19-props-typing.md": react19_props_typing_default,
125
- "../rules/react19-purity-and-immutability.md": react19_purity_and_immutability_default,
126
- "../rules/react19-tooling-and-opt-out.md": react19_tooling_and_opt_out_default,
127
- "../rules/typescript-assertions-last-resort.md": typescript_assertions_last_resort_default,
128
- "../rules/typescript-checklist-and-reference.md": typescript_checklist_and_reference_default,
129
- "../rules/typescript-discriminated-unions.md": typescript_discriminated_unions_default,
130
- "../rules/typescript-explicit-return-types.md": typescript_explicit_return_types_default,
131
- "../rules/typescript-interface-vs-type.md": typescript_interface_vs_type_default,
132
- "../rules/typescript-literal-unions-vs-enums.md": typescript_literal_unions_vs_enums_default,
133
- "../rules/typescript-naming-conventions.md": typescript_naming_conventions_default,
134
- "../rules/typescript-narrowing-over-casting.md": typescript_narrowing_over_casting_default,
135
- "../rules/typescript-readonly-by-default.md": typescript_readonly_by_default_default,
136
- "../rules/typescript-tsconfig-strictness.md": typescript_tsconfig_strictness_default,
137
- "../rules/typescript-zero-any.md": typescript_zero_any_default,
138
119
  "../rules/wangs-ui/default-props-precedence.md": default_props_precedence_default,
139
120
  "../rules/wangs-ui/forms-destructuring-lock.md": forms_destructuring_lock_default,
140
121
  "../rules/wangs-ui/no-raw-html.md": no_raw_html_default,
141
122
  "../rules/wangs-ui/no-redundant-wrappers.md": no_redundant_wrappers_default,
142
- "../rules/wangs-ui/theme-variable-override-breaks-engine.md": theme_variable_override_breaks_engine_default
123
+ "../rules/wangs-ui/react19-checklist-and-reference.md": react19_checklist_and_reference_default,
124
+ "../rules/wangs-ui/react19-compiler-render-patterns.md": react19_compiler_render_patterns_default,
125
+ "../rules/wangs-ui/react19-naming-conventions.md": react19_naming_conventions_default,
126
+ "../rules/wangs-ui/react19-no-manual-memoization.md": react19_no_manual_memoization_default,
127
+ "../rules/wangs-ui/react19-primitives-typing.md": react19_primitives_typing_default,
128
+ "../rules/wangs-ui/react19-props-typing.md": react19_props_typing_default,
129
+ "../rules/wangs-ui/react19-purity-and-immutability.md": react19_purity_and_immutability_default,
130
+ "../rules/wangs-ui/react19-tooling-and-opt-out.md": react19_tooling_and_opt_out_default,
131
+ "../rules/wangs-ui/theme-variable-override-breaks-engine.md": theme_variable_override_breaks_engine_default,
132
+ "../rules/wangs-ui/typescript-assertions-last-resort.md": typescript_assertions_last_resort_default,
133
+ "../rules/wangs-ui/typescript-checklist-and-reference.md": typescript_checklist_and_reference_default,
134
+ "../rules/wangs-ui/typescript-discriminated-unions.md": typescript_discriminated_unions_default,
135
+ "../rules/wangs-ui/typescript-explicit-return-types.md": typescript_explicit_return_types_default,
136
+ "../rules/wangs-ui/typescript-interface-vs-type.md": typescript_interface_vs_type_default,
137
+ "../rules/wangs-ui/typescript-literal-unions-vs-enums.md": typescript_literal_unions_vs_enums_default,
138
+ "../rules/wangs-ui/typescript-naming-conventions.md": typescript_naming_conventions_default,
139
+ "../rules/wangs-ui/typescript-narrowing-over-casting.md": typescript_narrowing_over_casting_default,
140
+ "../rules/wangs-ui/typescript-readonly-by-default.md": typescript_readonly_by_default_default,
141
+ "../rules/wangs-ui/typescript-tsconfig-strictness.md": typescript_tsconfig_strictness_default,
142
+ "../rules/wangs-ui/typescript-zero-any.md": typescript_zero_any_default
143
143
  });
144
144
  function parseSkillContent(id, content) {
145
- let name = id;
145
+ const cleanId = id.replace(/\\/g, "/").replace(/^\.\.\/skills\//, "").replace(/^skills\//, "").replace(/\/SKILL\.md$/, "");
146
+ let name = path.basename(cleanId);
146
147
  let description = "Wangs UI consumer skill";
147
148
  let owner = "wangs-ui";
148
149
  const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
@@ -156,7 +157,7 @@ function parseSkillContent(id, content) {
156
157
  if (ownerMatch) owner = ownerMatch[1].trim();
157
158
  }
158
159
  return {
159
- id,
160
+ id: cleanId,
160
161
  name,
161
162
  description,
162
163
  content,
@@ -195,10 +196,7 @@ function parseRuleContent(relativePath, content) {
195
196
  function loadAllSkills() {
196
197
  if (Object.keys(EMBEDDED_SKILLS_RAW).length > 0) {
197
198
  const skills = [];
198
- for (const [key, content] of Object.entries(EMBEDDED_SKILLS_RAW)) {
199
- const match = key.match(/\.\.\/skills\/([^/]+)\/SKILL\.md$/);
200
- if (match) skills.push(parseSkillContent(match[1], content));
201
- }
199
+ for (const [key, content] of Object.entries(EMBEDDED_SKILLS_RAW)) skills.push(parseSkillContent(key, content));
202
200
  if (skills.length > 0) return skills.sort((a, b) => a.id.localeCompare(b.id));
203
201
  }
204
202
  const candidates = [
@@ -207,23 +205,34 @@ function loadAllSkills() {
207
205
  path.resolve(__dirname, "../../skills")
208
206
  ];
209
207
  for (const skillsDir of candidates) if (fs.existsSync(skillsDir)) {
210
- const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
211
208
  const skills = [];
212
- for (const entry of entries) if (entry.isDirectory()) {
213
- const skillMdPath = path.join(skillsDir, entry.name, "SKILL.md");
214
- if (fs.existsSync(skillMdPath)) {
215
- const content = fs.readFileSync(skillMdPath, "utf-8");
216
- skills.push(parseSkillContent(entry.name, content));
209
+ function scanSkills(dir, prefix = "") {
210
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
211
+ for (const entry of entries) {
212
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
213
+ if (entry.isDirectory()) {
214
+ const skillMdPath = path.join(dir, entry.name, "SKILL.md");
215
+ if (fs.existsSync(skillMdPath)) {
216
+ const content = fs.readFileSync(skillMdPath, "utf-8");
217
+ skills.push(parseSkillContent(rel, content));
218
+ } else scanSkills(path.join(dir, entry.name), rel);
219
+ }
217
220
  }
218
221
  }
222
+ scanSkills(skillsDir);
219
223
  if (skills.length > 0) return skills.sort((a, b) => a.id.localeCompare(b.id));
220
224
  }
221
225
  return [];
222
226
  }
223
227
  function getSkill(id) {
224
228
  const all = loadAllSkills();
225
- const normalized = id.toLowerCase();
226
- return all.find((s) => s.id.toLowerCase() === normalized || s.name.toLowerCase() === normalized);
229
+ const normalized = id.toLowerCase().replace(/\\/g, "/").replace(/\/SKILL\.md$/i, "");
230
+ const baseName = path.basename(normalized);
231
+ return all.find((s) => {
232
+ const sId = s.id.toLowerCase();
233
+ const sBase = path.basename(sId);
234
+ return sId === normalized || s.name.toLowerCase() === normalized || sBase === normalized || sBase === baseName;
235
+ });
227
236
  }
228
237
  function loadAllRules() {
229
238
  if (Object.keys(EMBEDDED_RULES_RAW).length > 0) {
@@ -285,9 +294,11 @@ function getAgentSkillDirs(baseDir = process.cwd()) {
285
294
  }
286
295
  function isSkillInstalled(skillId, baseDir = process.cwd()) {
287
296
  const dirs = getAgentSkillDirs(baseDir);
297
+ const baseName = path.basename(skillId);
288
298
  for (const d of dirs) {
289
299
  const skillPath = path.join(d, skillId, "SKILL.md");
290
- if (fs.existsSync(skillPath)) return true;
300
+ const legacyPath = path.join(d, baseName, "SKILL.md");
301
+ if (fs.existsSync(skillPath) || fs.existsSync(legacyPath)) return true;
291
302
  }
292
303
  return false;
293
304
  }
@@ -295,11 +306,18 @@ function getInstalledSkills(baseDir = process.cwd()) {
295
306
  const dirs = getAgentSkillDirs(baseDir);
296
307
  const installed = /* @__PURE__ */ new Set();
297
308
  for (const d of dirs) if (fs.existsSync(d)) {
298
- const entries = fs.readdirSync(d, { withFileTypes: true });
299
- for (const entry of entries) if (entry.isDirectory()) {
300
- const skillMd = path.join(d, entry.name, "SKILL.md");
301
- if (fs.existsSync(skillMd)) installed.add(entry.name);
309
+ function scan(current, prefix = "") {
310
+ const entries = fs.readdirSync(current, { withFileTypes: true });
311
+ for (const entry of entries) {
312
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
313
+ if (entry.isDirectory()) {
314
+ const skillMd = path.join(current, entry.name, "SKILL.md");
315
+ if (fs.existsSync(skillMd)) installed.add(rel);
316
+ else scan(path.join(current, entry.name), rel);
317
+ }
318
+ }
302
319
  }
320
+ scan(d);
303
321
  }
304
322
  return Array.from(installed);
305
323
  }
@@ -326,6 +344,8 @@ function removeSkill(skillId, baseDir = process.cwd()) {
326
344
  force: true
327
345
  });
328
346
  removedPaths.push(destDir);
347
+ const parent = path.dirname(destDir);
348
+ if (parent !== baseSkillDir && fs.existsSync(parent) && fs.readdirSync(parent).length === 0) fs.rmdirSync(parent);
329
349
  }
330
350
  }
331
351
  return removedPaths;
@@ -395,7 +415,7 @@ function removeRule(ruleRelativePath, baseDir = process.cwd()) {
395
415
  //#endregion
396
416
  //#region src/commands/list.ts
397
417
  function listSkills(baseDir = process.cwd()) {
398
- intro(`\x1b[1m\x1b[36m📦 Wangs UI Skills & Rules Registry\x1b[0m (v1.3.0-alpha.13)`);
418
+ intro(`\x1b[1m\x1b[36m📦 Wangs UI Skills & Rules Registry\x1b[0m (v1.3.0-alpha.15)`);
399
419
  const allSkills = loadAllSkills();
400
420
  const allRules = loadAllRules();
401
421
  const skillDirs = getAgentSkillDirs(baseDir);
@@ -476,15 +496,18 @@ async function addSkills(targets, baseDir = process.cwd()) {
476
496
  continue;
477
497
  }
478
498
  if (key === "bundle:wangs-ui-rules" || key === "wangs-ui-rules") {
479
- for (const r of allRules.filter((rule) => rule.relativePath.startsWith("wangs-ui/"))) rulesToInstall.set(r.relativePath, r);
499
+ for (const r of allRules.filter((rule) => {
500
+ const base = path.basename(rule.relativePath);
501
+ return !base.startsWith("react19-") && !base.startsWith("typescript-");
502
+ })) rulesToInstall.set(r.relativePath, r);
480
503
  continue;
481
504
  }
482
505
  if (key === "bundle:react19-rules" || key === "react19-rules") {
483
- for (const r of allRules.filter((rule) => rule.relativePath.startsWith("react19-"))) rulesToInstall.set(r.relativePath, r);
506
+ for (const r of allRules.filter((rule) => path.basename(rule.relativePath).startsWith("react19-"))) rulesToInstall.set(r.relativePath, r);
484
507
  continue;
485
508
  }
486
509
  if (key === "bundle:typescript-rules" || key === "typescript-rules") {
487
- for (const r of allRules.filter((rule) => rule.relativePath.startsWith("typescript-"))) rulesToInstall.set(r.relativePath, r);
510
+ for (const r of allRules.filter((rule) => path.basename(rule.relativePath).startsWith("typescript-"))) rulesToInstall.set(r.relativePath, r);
488
511
  continue;
489
512
  }
490
513
  if (key === "--skills" || key === "skills" || key === "all-skills" || key === "bundle:all-skills") {