@revikornmann/muka-ui 0.17.0 → 0.19.0

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 (182) hide show
  1. package/README.md +81 -60
  2. package/cli/bin/muka-ui.js +12 -5
  3. package/cli/commands/brand.js +33 -14
  4. package/cli/commands/init.js +21 -17
  5. package/cli/commands/install-skill.js +84 -26
  6. package/cli/templates/AGENTS.md +128 -0
  7. package/cli/templates/CLAUDE.md +8 -88
  8. package/cli/templates/muka-ui-guidelines.md +50 -14
  9. package/dist/cjs/components/ActionSheet/ActionSheet.js +1 -1
  10. package/dist/cjs/components/Breadcrumb/Breadcrumb.css +11 -3
  11. package/dist/cjs/components/Breadcrumb/Breadcrumb.js +19 -1
  12. package/dist/cjs/components/Breadcrumb/Breadcrumb.js.map +1 -1
  13. package/dist/cjs/components/Combobox/Combobox.css +116 -132
  14. package/dist/cjs/components/Combobox/Combobox.js +175 -52
  15. package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
  16. package/dist/cjs/components/Combobox/index.js.map +1 -1
  17. package/dist/cjs/components/ContextSelect/ContextSelect.css +117 -0
  18. package/dist/cjs/components/ContextSelect/ContextSelect.js +49 -0
  19. package/dist/cjs/components/ContextSelect/ContextSelect.js.map +1 -0
  20. package/dist/cjs/components/ContextSelect/index.js +11 -0
  21. package/dist/cjs/components/ContextSelect/index.js.map +1 -0
  22. package/dist/cjs/components/DropdownSelect/DropdownSelect.css +225 -0
  23. package/dist/cjs/components/DropdownSelect/DropdownSelect.js +106 -0
  24. package/dist/cjs/components/DropdownSelect/DropdownSelect.js.map +1 -0
  25. package/dist/cjs/components/DropdownSelect/index.js +6 -0
  26. package/dist/cjs/components/DropdownSelect/index.js.map +1 -0
  27. package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js +11 -0
  28. package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
  29. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js +11 -0
  30. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  31. package/dist/cjs/components/Icon/iconRegistry.js +11 -0
  32. package/dist/cjs/components/Icon/iconRegistry.js.map +1 -1
  33. package/dist/cjs/components/Input/Input.css +45 -8
  34. package/dist/cjs/components/Input/Input.js +14 -3
  35. package/dist/cjs/components/Input/Input.js.map +1 -1
  36. package/dist/cjs/components/Menu/Menu.css +213 -17
  37. package/dist/cjs/components/Menu/Menu.js +429 -39
  38. package/dist/cjs/components/Menu/Menu.js.map +1 -1
  39. package/dist/cjs/components/Menu/index.js +5 -1
  40. package/dist/cjs/components/Menu/index.js.map +1 -1
  41. package/dist/cjs/components/ProgressTracker/ProgressTracker.css +273 -22
  42. package/dist/cjs/components/ProgressTracker/ProgressTracker.js +109 -9
  43. package/dist/cjs/components/ProgressTracker/ProgressTracker.js.map +1 -1
  44. package/dist/cjs/components/Scrollbar/Scrollbar.css +124 -0
  45. package/dist/cjs/components/Scrollbar/Scrollbar.js +118 -0
  46. package/dist/cjs/components/Scrollbar/Scrollbar.js.map +1 -0
  47. package/dist/cjs/components/Scrollbar/index.js +11 -0
  48. package/dist/cjs/components/Scrollbar/index.js.map +1 -0
  49. package/dist/cjs/components/index.js +13 -16
  50. package/dist/cjs/components/index.js.map +1 -1
  51. package/dist/esm/components/ActionSheet/ActionSheet.js +1 -1
  52. package/dist/esm/components/Breadcrumb/Breadcrumb.css +11 -3
  53. package/dist/esm/components/Breadcrumb/Breadcrumb.js +19 -1
  54. package/dist/esm/components/Breadcrumb/Breadcrumb.js.map +1 -1
  55. package/dist/esm/components/Combobox/Combobox.css +116 -132
  56. package/dist/esm/components/Combobox/Combobox.js +177 -54
  57. package/dist/esm/components/Combobox/Combobox.js.map +1 -1
  58. package/dist/esm/components/Combobox/index.js +1 -1
  59. package/dist/esm/components/Combobox/index.js.map +1 -1
  60. package/dist/esm/components/ContextSelect/ContextSelect.css +117 -0
  61. package/dist/esm/components/ContextSelect/ContextSelect.js +45 -0
  62. package/dist/esm/components/ContextSelect/ContextSelect.js.map +1 -0
  63. package/dist/esm/components/ContextSelect/index.js +3 -0
  64. package/dist/esm/components/ContextSelect/index.js.map +1 -0
  65. package/dist/esm/components/DropdownSelect/DropdownSelect.css +225 -0
  66. package/dist/esm/components/DropdownSelect/DropdownSelect.js +102 -0
  67. package/dist/esm/components/DropdownSelect/DropdownSelect.js.map +1 -0
  68. package/dist/esm/components/DropdownSelect/index.js +2 -0
  69. package/dist/esm/components/DropdownSelect/index.js.map +1 -0
  70. package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js +7 -0
  71. package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
  72. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js +7 -0
  73. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  74. package/dist/esm/components/Icon/iconRegistry.js +11 -0
  75. package/dist/esm/components/Icon/iconRegistry.js.map +1 -1
  76. package/dist/esm/components/Input/Input.css +45 -8
  77. package/dist/esm/components/Input/Input.js +14 -3
  78. package/dist/esm/components/Input/Input.js.map +1 -1
  79. package/dist/esm/components/Menu/Menu.css +213 -17
  80. package/dist/esm/components/Menu/Menu.js +428 -40
  81. package/dist/esm/components/Menu/Menu.js.map +1 -1
  82. package/dist/esm/components/Menu/index.js +1 -1
  83. package/dist/esm/components/Menu/index.js.map +1 -1
  84. package/dist/esm/components/ProgressTracker/ProgressTracker.css +273 -22
  85. package/dist/esm/components/ProgressTracker/ProgressTracker.js +110 -10
  86. package/dist/esm/components/ProgressTracker/ProgressTracker.js.map +1 -1
  87. package/dist/esm/components/Scrollbar/Scrollbar.css +124 -0
  88. package/dist/esm/components/Scrollbar/Scrollbar.js +114 -0
  89. package/dist/esm/components/Scrollbar/Scrollbar.js.map +1 -0
  90. package/dist/esm/components/Scrollbar/index.js +3 -0
  91. package/dist/esm/components/Scrollbar/index.js.map +1 -0
  92. package/dist/esm/components/index.js +4 -2
  93. package/dist/esm/components/index.js.map +1 -1
  94. package/dist/styles/components/Breadcrumb.css +11 -3
  95. package/dist/styles/components/Combobox.css +116 -132
  96. package/dist/styles/components/ContextSelect.css +117 -0
  97. package/dist/styles/components/DropdownSelect.css +225 -0
  98. package/dist/styles/components/Input.css +45 -8
  99. package/dist/styles/components/Menu.css +213 -17
  100. package/dist/styles/components/ProgressTracker.css +273 -22
  101. package/dist/styles/components/Scrollbar.css +124 -0
  102. package/dist/styles/components/Typography.css +89 -0
  103. package/dist/styles/index.css +1526 -480
  104. package/dist/styles/muka-dark.css +1526 -480
  105. package/dist/styles/muka-light.css +1526 -480
  106. package/dist/styles/tokens-bouwplan-dark.css +9 -6
  107. package/dist/styles/tokens-bouwplan-light.css +9 -6
  108. package/dist/styles/tokens-fscl-dark.css +29 -26
  109. package/dist/styles/tokens-fscl-light.css +29 -26
  110. package/dist/styles/tokens-grip-dark.css +8 -5
  111. package/dist/styles/tokens-grip-light.css +8 -5
  112. package/dist/styles/tokens-muka-dark.css +8 -5
  113. package/dist/styles/tokens-muka-light.css +8 -5
  114. package/dist/styles/tokens-wireframe-dark.css +53 -50
  115. package/dist/styles/tokens-wireframe-light.css +53 -50
  116. package/dist/styles/wireframe-dark.css +1571 -525
  117. package/dist/styles/wireframe-light.css +1571 -525
  118. package/dist/types/components/ActionSheet/ActionSheet.d.ts +1 -1
  119. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +27 -3
  120. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  121. package/dist/types/components/Combobox/Combobox.d.ts +38 -38
  122. package/dist/types/components/Combobox/Combobox.d.ts.map +1 -1
  123. package/dist/types/components/Combobox/index.d.ts +1 -1
  124. package/dist/types/components/Combobox/index.d.ts.map +1 -1
  125. package/dist/types/components/ContextSelect/ContextSelect.d.ts +62 -0
  126. package/dist/types/components/ContextSelect/ContextSelect.d.ts.map +1 -0
  127. package/dist/types/components/ContextSelect/index.d.ts +3 -0
  128. package/dist/types/components/ContextSelect/index.d.ts.map +1 -0
  129. package/dist/types/components/DataTable/DataTable.d.ts +1 -1
  130. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts +71 -0
  131. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts.map +1 -0
  132. package/dist/types/components/DropdownSelect/index.d.ts +2 -0
  133. package/dist/types/components/DropdownSelect/index.d.ts.map +1 -0
  134. package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts +9 -0
  135. package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts.map +1 -0
  136. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts +9 -0
  137. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts.map +1 -0
  138. package/dist/types/components/Icon/iconRegistry.d.ts.map +1 -1
  139. package/dist/types/components/Input/Input.d.ts +5 -0
  140. package/dist/types/components/Input/Input.d.ts.map +1 -1
  141. package/dist/types/components/Menu/Menu.d.ts +99 -29
  142. package/dist/types/components/Menu/Menu.d.ts.map +1 -1
  143. package/dist/types/components/Menu/index.d.ts +2 -2
  144. package/dist/types/components/Menu/index.d.ts.map +1 -1
  145. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts +29 -8
  146. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts.map +1 -1
  147. package/dist/types/components/Scrollbar/Scrollbar.d.ts +19 -0
  148. package/dist/types/components/Scrollbar/Scrollbar.d.ts.map +1 -0
  149. package/dist/types/components/Scrollbar/index.d.ts +3 -0
  150. package/dist/types/components/Scrollbar/index.d.ts.map +1 -0
  151. package/dist/types/components/index.d.ts +5 -4
  152. package/dist/types/components/index.d.ts.map +1 -1
  153. package/docs/consumers/README.md +116 -37
  154. package/docs/consumers/brand.md +261 -0
  155. package/docs/consumers/figma-console-mcp.md +116 -0
  156. package/docs/consumers/setup-instructions.md +98 -12
  157. package/docs/consumers/skills.md +79 -0
  158. package/package.json +4 -6
  159. package/scripts/postinstall-nudge.js +8 -4
  160. package/skills/add-brand/SKILL.md +204 -0
  161. package/skills/add-brand/reference.md +160 -0
  162. package/skills/figma-to-code/SKILL.md +127 -0
  163. package/skills/pull-from-figma/SKILL.md +123 -0
  164. package/skills/push-to-figma/SKILL.md +172 -0
  165. package/skills/setup-muka/SKILL.md +73 -13
  166. package/tokens/README.md +40 -18
  167. package/tokens/t2-alias/brand/bouwplan/fonts.json +1 -1
  168. package/tokens/t2-alias/brand/fscl/fonts.json +3 -3
  169. package/tokens/t2-alias/brand/wireframe/fonts.json +2 -2
  170. package/tokens/t4-components/menu.json +20 -5
  171. package/dist/cjs/components/ContextMenu/ContextMenu.js +0 -186
  172. package/dist/cjs/components/ContextMenu/ContextMenu.js.map +0 -1
  173. package/dist/cjs/components/ContextMenu/index.js +0 -17
  174. package/dist/cjs/components/ContextMenu/index.js.map +0 -1
  175. package/dist/esm/components/ContextMenu/ContextMenu.js +0 -145
  176. package/dist/esm/components/ContextMenu/ContextMenu.js.map +0 -1
  177. package/dist/esm/components/ContextMenu/index.js +0 -2
  178. package/dist/esm/components/ContextMenu/index.js.map +0 -1
  179. package/dist/types/components/ContextMenu/ContextMenu.d.ts +0 -188
  180. package/dist/types/components/ContextMenu/ContextMenu.d.ts.map +0 -1
  181. package/dist/types/components/ContextMenu/index.d.ts +0 -3
  182. package/dist/types/components/ContextMenu/index.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,91 +1,112 @@
1
- # Muka Design System
1
+ <img src=".storybook/public/logo-on-light.svg" alt="Muka UI" height="40" />
2
2
 
3
- A comprehensive design system that provides a consistent and scalable foundation for building user interfaces.
3
+ # Muka UI
4
4
 
5
- ## Overview
5
+ A multi-brand, multi-theme React design system for mobile-first web apps, built
6
+ so that coding agents can consume it accurately. Five brands × light and dark =
7
+ **ten themes**, one component library, no per-brand component code.
6
8
 
7
- Muka is a design system that combines design tokens, components, and guidelines to create a cohesive user experience across different brands and platforms.
9
+ - **Storybook:** <https://muka.kornmann.com> — component APIs, Playgrounds, token docs
10
+ - **npm:** [`@revikornmann/muka-ui`](https://www.npmjs.com/package/@revikornmann/muka-ui)
11
+ (public — no registry config or auth token)
8
12
 
9
- ## Key Features
13
+ > **Under active development.** Releases can bring breaking changes — visual
14
+ > shifts, changed component APIs, altered token values. Pin a version and
15
+ > re-test your app when you upgrade.
10
16
 
11
- - **Design Tokens**: A robust token system for colors, typography, spacing, and more
12
- - **Component Library**: Reusable UI components built with design tokens
13
- - **Theme Support**: Light and dark mode support with brand-specific variations
14
- - **Responsive Design**: Built-in support for mobile, tablet, and desktop layouts
17
+ ## Use it in your app
15
18
 
16
- ## Documentation
17
-
18
- - [Design Tokens](./tokens/README.md): Comprehensive documentation of our design token system
19
- - Components: Coming soon
20
- - Guidelines: Coming soon
21
-
22
- ## Installation
23
-
24
- Muka is a **public npm package** published under the scoped name
25
- `@revikornmann/muka-ui` (the bare `muka-ui` name is taken on npm by an unrelated
26
- package). No registry config or auth token is needed.
19
+ Five steps from an empty repo to a branded, designed, working app. Each one is a
20
+ skill or a single command.
27
21
 
28
22
  ```bash
29
23
  npm install @revikornmann/muka-ui
24
+ npx muka-ui install-skill # make the Muka skills discoverable
30
25
  ```
31
26
 
32
- Import the stylesheet once in your app root, then components anywhere:
27
+ Then, in Claude Code or Cursor:
33
28
 
34
- ```ts
35
- import '@revikornmann/muka-ui/styles';
36
- import { Button, Card, Input } from '@revikornmann/muka-ui';
37
- ```
29
+ | # | Step | How |
30
+ |---|---|---|
31
+ | 1 | Create your repo | Any React app with a bundler that imports CSS |
32
+ | 2 | Install and wire up Muka UI | `/setup-muka [brand]` |
33
+ | 3 | Add your own brand, overriding Muka's brand layer | `/add-brand acme` |
34
+ | 4 | Design against the Muka UI Figma Library | `/push-to-figma` to publish your brand to Figma |
35
+ | 5 | Hand the Figma link to your agent | `/figma-to-code <figma-url>` |
36
+
37
+ And voilà — a branded app built from a component library you didn't write, that
38
+ follows brand changes centrally and updates itself on each release.
39
+
40
+ **Full guide: [`docs/consumers/README.md`](docs/consumers/README.md).**
41
+
42
+ ### Skills shipped in the package
43
+
44
+ | Skill | What it does |
45
+ |---|---|
46
+ | `/setup-muka` | Install the package, wire up styles and fonts, add the auto-update workflow, register as a consumer |
47
+ | `/add-brand` | Create a custom brand in your repo that overrides Muka's brand layer |
48
+ | `/figma-to-code` | Turn a Figma link into a screen composed from Muka components and tokens |
49
+ | `/push-to-figma` | Publish your brand tokens to Figma as variables, so designers design in your brand |
50
+ | `/pull-from-figma` | Bring a designer's brand edits in Figma back into your token files |
51
+
52
+ `npx muka-ui install-skill --list` prints these from the installed version.
53
+
54
+ `/push-to-figma` and `/pull-from-figma` read and write Figma **variables**, which
55
+ the REST API cannot do, so they drive
56
+ [**Figma Console MCP**](https://github.com/southleft/figma-console-mcp) — an
57
+ open-source (MIT) MCP server by **[Southleft](https://southleft.com)**. It needs
58
+ a one-time setup: [`docs/consumers/figma-console-mcp.md`](docs/consumers/figma-console-mcp.md).
59
+ The other three skills don't require it.
38
60
 
39
- For a brand theme, also import the brand token CSS and set the data attributes
40
- (`<brand>` is e.g. `muka`, `fscl`, `grip`, `bouwplan`):
61
+ Reference: [`docs/consumers/skills.md`](docs/consumers/skills.md).
62
+
63
+ ### Installing by hand
41
64
 
42
65
  ```ts
43
- import '@revikornmann/muka-ui/styles/tokens-<brand>-light.css';
66
+ import '@revikornmann/muka-ui/styles'; // muka-light, fonts included
67
+ import { Button, Card, Input } from '@revikornmann/muka-ui';
44
68
  ```
45
69
 
46
- ```html
47
- <html data-brand="<brand>" data-theme="light">
48
- ```
70
+ Other brands load a different stylesheet — `muka-dark`, `wireframe-light`, and
71
+ `wireframe-dark` are pre-bundled; `grip`, `fscl`, and `bouwplan` compose from
72
+ `base.css` + `tokens-<brand>-<mode>.css` + `fonts-<brand>.css`. Brand and theme
73
+ are selected by **which stylesheet loads**, not by data attributes. See
74
+ [`docs/consumers/setup-instructions.md`](docs/consumers/setup-instructions.md).
49
75
 
50
- ### Fastest path: the `/setup-muka` skill
76
+ ## How the token system works
51
77
 
52
- If you use Claude Code / Cursor, let the skill wire everything up — install,
53
- styles, the auto-update workflow, and consumer registration:
78
+ Four layers, each resolving through the one below:
54
79
 
55
- ```bash
56
- npx muka-ui install-skill # makes /setup-muka discoverable in .claude/skills
57
- # then in Claude Code:
58
- /setup-muka [brand]
59
- ```
80
+ | Layer | Purpose | Example |
81
+ |---|---|---|
82
+ | **T1 Primitives** | Raw ramps, never used directly | `color.indigo.9`, `spacing.4` |
83
+ | **T2 Alias** | Brand-specific references — **the layer a brand swaps** | `alias.color.accent.default` |
84
+ | **T3 Semantics** | Design intent | `color.surface.level1`, `color.action.default` |
85
+ | **T4 Components** | Component-specific | `button.color.primary.background.default` |
86
+
87
+ Components read T3 and T4 only. Swapping T2 cascades a whole new visual identity
88
+ through the library, which is what makes both the five shipped brands and your
89
+ own brand possible without touching component code.
60
90
 
61
- See [docs/consumers/README.md](docs/consumers/README.md) and
62
- [docs/consumers/setup-instructions.md](docs/consumers/setup-instructions.md) for
63
- the full consumer flow and the release-gated auto-update mechanism.
91
+ Details: [`tokens/README.md`](tokens/README.md) and the Design Tokens section of
92
+ the Storybook.
64
93
 
65
- ## Getting Started (local development)
94
+ ## Contribute to Muka itself
66
95
 
67
96
  ```bash
68
- # Install dependencies
69
97
  npm install
70
-
71
- # Start development server
72
- npm run dev
98
+ npm run build:tokens # required before Storybook — postinstall does not do it
99
+ npm run dev # Storybook on port 6006
73
100
  ```
74
101
 
75
- ## Project Structure
76
-
77
- ```
78
- muka/
79
- ├── tokens/ # Design tokens
80
- ├── components/ # UI components
81
- ├── styles/ # Global styles
82
- └── docs/ # Documentation
83
- ```
102
+ [`DEVELOPMENT.md`](DEVELOPMENT.md) is the maintainer guide: commands, token
103
+ layers, component structure, CI, and releases. Maintainer skills live in
104
+ [`.claude/skills/`](.claude/skills) and are not shipped to consumers.
84
105
 
85
- ## Contributing
106
+ ## License
86
107
 
87
- Please read our [Contributing Guide](./CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
108
+ MIT.
88
109
 
89
- ## License
110
+ ---
90
111
 
91
- This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
112
+ Created by **Revi Körnmann** · [LinkedIn](https://linkedin.com/in/revikornmann) · [kornmann.com](https://kornmann.com)
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Commands:
7
7
  * init - Set up a project to use Muka UI
8
- * install-skill - Copy shipped skills into .claude/skills (e.g. /setup-muka)
8
+ * install-skill - Copy shipped skills into .claude/skills
9
9
  * brand init <name> - Scaffold a custom brand override
10
10
  * link [path] - Set up npm link for local development
11
11
  * components - List available components
@@ -24,8 +24,8 @@ Usage:
24
24
  muka-ui <command> [options]
25
25
 
26
26
  Commands:
27
- init Set up project for Muka UI (creates CLAUDE.md, guidelines)
28
- install-skill Copy shipped skills into .claude/skills (e.g. /setup-muka)
27
+ init Set up project for Muka UI (creates AGENTS.md, guidelines)
28
+ install-skill Copy shipped skills into .claude/skills
29
29
  brand init <name> Scaffold a custom brand (T2 tokens, manifest, build script)
30
30
  link [path] Set up npm link for local muka-ui development
31
31
  components List available Muka UI components
@@ -35,11 +35,18 @@ Options:
35
35
  --version, -v Show version
36
36
 
37
37
  Examples:
38
+ npx muka-ui install-skill --list # what skills ship with the package
39
+ npx muka-ui install-skill # install them, then run /setup-muka
38
40
  npx muka-ui init
39
- npx muka-ui install-skill
40
- npx muka-ui brand init fscl
41
+ npx muka-ui brand init acme
41
42
  npx muka-ui link /path/to/muka
42
43
  npx muka-ui components
44
+
45
+ Typical flow:
46
+ npm install @revikornmann/muka-ui
47
+ npx muka-ui install-skill
48
+ /setup-muka # in your agent
49
+ /add-brand acme # optional: your own brand
43
50
  `;
44
51
 
45
52
  // Version from package.json
@@ -19,24 +19,36 @@ const {
19
19
  readPackageJson
20
20
  } = require('../lib/fs-utils');
21
21
 
22
+ // The published package name, read from the package's own manifest so the paths
23
+ // written into a consumer repo stay correct if the package is ever renamed.
24
+ const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
25
+ const PACKAGE_NAME = JSON.parse(
26
+ fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')
27
+ ).name;
28
+
22
29
  /**
23
30
  * Read a wireframe brand file as a template
24
31
  */
25
32
  function readBrandTemplate(filename) {
26
- const templatePath = path.join(__dirname, '../../tokens/t2-alias/brand/wireframe', filename);
33
+ const templatePath = path.join(PACKAGE_ROOT, 'tokens/t2-alias/brand/wireframe', filename);
27
34
  return JSON.parse(fs.readFileSync(templatePath, 'utf8'));
28
35
  }
29
36
 
30
37
  /**
31
- * Generate the brand manifest for a consumer repo
38
+ * Generate the brand manifest for a consumer repo.
39
+ *
40
+ * Every layer except the brand's own T2 files is read straight out of
41
+ * node_modules, so the consumer only owns the brand layer and inherits
42
+ * primitives, semantics, and component tokens from the installed package.
32
43
  */
33
44
  function generateManifest(brandName) {
34
- const t1 = 'node_modules/muka-ui/tokens/t1-primitives/**/*.json';
35
- const base = 'node_modules/muka-ui/tokens/t2-alias/base.json';
45
+ const pkgTokens = `node_modules/${PACKAGE_NAME}/tokens`;
46
+ const t1 = `${pkgTokens}/t1-primitives/**/*.json`;
47
+ const base = `${pkgTokens}/t2-alias/base.json`;
36
48
  const fonts = `brand/fonts.json`;
37
- const layout = 'node_modules/muka-ui/tokens/t2-alias/layout/mobile.json';
38
- const semantics = 'node_modules/muka-ui/tokens/t3-semantics/ui.json';
39
- const components = 'node_modules/muka-ui/tokens/t4-components/**/*.json';
49
+ const layout = `${pkgTokens}/t2-alias/layout/mobile.json`;
50
+ const semantics = `${pkgTokens}/t3-semantics/ui.json`;
51
+ const components = `${pkgTokens}/t4-components/**/*.json`;
40
52
 
41
53
  return {
42
54
  themes: {
@@ -50,8 +62,9 @@ function generateManifest(brandName) {
50
62
  ]
51
63
  },
52
64
  breakpoints: {
53
- md: 'node_modules/muka-ui/tokens/t2-alias/layout/tablet.json',
54
- lg: 'node_modules/muka-ui/tokens/t2-alias/layout/desktop.json'
65
+ md: `${pkgTokens}/t2-alias/layout/tablet.json`,
66
+ lg: `${pkgTokens}/t2-alias/layout/desktop.json`,
67
+ xl: `${pkgTokens}/t2-alias/layout/wide.json`
55
68
  }
56
69
  };
57
70
  }
@@ -61,7 +74,7 @@ function generateManifest(brandName) {
61
74
  */
62
75
  function generateBuildScript() {
63
76
  return `const path = require('path');
64
- const TokenBuilder = require('muka-ui/build');
77
+ const TokenBuilder = require('${PACKAGE_NAME}/build');
65
78
  const manifest = require('./muka.brand.json');
66
79
 
67
80
  const builder = new TokenBuilder({ rootDir: path.resolve(__dirname, '..') });
@@ -183,13 +196,18 @@ async function brand(args) {
183
196
  console.log('');
184
197
  console.log('2. Build your brand CSS:');
185
198
  console.log(' npm run build:tokens');
199
+ console.log(` → styles/tokens-${brandName}-light.css and -dark.css`);
186
200
  console.log('');
187
- console.log(`3. Link the generated CSS in your HTML:`);
188
- console.log(` <link rel="stylesheet" href="/styles/tokens-${brandName}-light.css" />`);
201
+ console.log('3. Import your brand CSS AFTER the Muka base styles, so your brand');
202
+ console.log(' layer wins the cascade:');
203
+ console.log(` import '${PACKAGE_NAME}/styles/base.css';`);
204
+ console.log(` import './styles/tokens-${brandName}-light.css';`);
205
+ console.log(' Both files target :root, so the one imported last is the active');
206
+ console.log(' theme. To switch brand or mode at runtime, swap the stylesheet.');
189
207
  console.log('');
190
208
  console.log('4. Fonts: the family names in brand/fonts.json must be loaded somewhere.');
191
209
  console.log(' - Reusing a font Muka already ships? Import its fonts file, e.g.');
192
- console.log(" import '@revikornmann/muka-ui/styles/fonts-muka.css';");
210
+ console.log(` import '${PACKAGE_NAME}/styles/fonts-muka.css';`);
193
211
  console.log(' - Introducing your own font? Self-host it with your own @font-face');
194
212
  console.log(' under the exact family name you put in fonts.json (do NOT use a');
195
213
  console.log(' Google Fonts <link> in production — it breaks offline installs).');
@@ -198,7 +216,8 @@ async function brand(args) {
198
216
  console.log(' Colors use T1 primitives like {color.gray.9}, {color.indigo.11}');
199
217
  console.log(' Available palettes: gray, mauve, sand, indigo, iris, mint, jade,');
200
218
  console.log(' tomato, red, amber, green, blue, and more.');
201
- console.log(' See node_modules/muka-ui/tokens/t1-primitives/color.json for all values.');
219
+ console.log(` See node_modules/${PACKAGE_NAME}/tokens/t1-primitives/color.json`);
220
+ console.log(' for all values.');
202
221
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
203
222
  }
204
223
 
@@ -2,7 +2,8 @@
2
2
  * `muka-ui init` command
3
3
  *
4
4
  * Sets up a project for Muka UI usage:
5
- * - Creates CLAUDE.md with AI development guidelines
5
+ * - Creates AGENTS.md with the development guidelines every agent reads
6
+ * - Creates CLAUDE.md pointing at AGENTS.md, for Claude Code
6
7
  * - Creates docs/muka-ui-guidelines.md with usage documentation
7
8
  * - Checks for conflicting dependencies and warns
8
9
  */
@@ -95,21 +96,24 @@ async function init(args) {
95
96
  // Get template replacements
96
97
  const replacements = getReplacements();
97
98
 
98
- // --- CLAUDE.md ---
99
- const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
100
- let createClaudeMd = true;
101
-
102
- if (fileExists(claudeMdPath)) {
103
- console.log('CLAUDE.md already exists.');
104
- createClaudeMd = await confirm('Overwrite with Muka UI template?');
105
- }
106
-
107
- if (createClaudeMd) {
108
- const claudeContent = loadTemplate('CLAUDE.md', replacements);
109
- writeFile(claudeMdPath, claudeContent);
110
- console.log('✓ Created CLAUDE.md\n');
111
- } else {
112
- console.log('⏭ Skipped CLAUDE.md\n');
99
+ // --- Agent briefs ---
100
+ // AGENTS.md holds the rules and is read by most agents; CLAUDE.md is a
101
+ // pointer to it so Claude Code finds them without a second copy to maintain.
102
+ for (const name of ['AGENTS.md', 'CLAUDE.md']) {
103
+ const target = path.join(projectRoot, name);
104
+ let write = true;
105
+
106
+ if (fileExists(target)) {
107
+ console.log(`${name} already exists.`);
108
+ write = await confirm('Overwrite with Muka UI template?');
109
+ }
110
+
111
+ if (write) {
112
+ writeFile(target, loadTemplate(name, replacements));
113
+ console.log(`✓ Created ${name}\n`);
114
+ } else {
115
+ console.log(`⏭ Skipped ${name}\n`);
116
+ }
113
117
  }
114
118
 
115
119
  // --- docs/muka-ui-guidelines.md ---
@@ -163,7 +167,7 @@ async function init(args) {
163
167
  console.log(`3. Browse components: ${manifest.storybook_url}`);
164
168
  console.log('');
165
169
  console.log('4. Stay current: run `npx muka-ui install-skill` then `/setup-muka`');
166
- console.log(' in Claude Code — it adds the auto-update workflow and registers');
170
+ console.log(' in your agent — it adds the auto-update workflow and registers');
167
171
  console.log(' this repo as a consumer. (Or copy templates/update-muka.yml into');
168
172
  console.log(' .github/workflows/ by hand.)');
169
173
  console.log(` See node_modules/${manifest.package_name}/docs/consumers/setup-instructions.md`);
@@ -2,15 +2,16 @@
2
2
  * `muka-ui install-skill` command
3
3
  *
4
4
  * Copies the consumer-facing skills shipped inside the package (under
5
- * `skills/`) into the consuming repo's `.claude/skills/` so Claude Code can
6
- * discover them — most importantly `/setup-muka`.
5
+ * `skills/`) into the consuming repo's `.claude/skills/`, the directory Claude
6
+ * Code and Cursor both scan for skills.
7
7
  *
8
- * Claude Code only discovers skills under `.claude/skills/`, never inside
9
- * `node_modules/`, so a skill shipped in the package is present but not
10
- * discoverable until it is copied in. This command is that bridge.
8
+ * Agents discover skills under `.claude/skills/`, never inside `node_modules/`,
9
+ * so a skill shipped in the package is present but not discoverable until it is
10
+ * copied in. This command is that bridge.
11
11
  *
12
12
  * npx muka-ui install-skill # install all shipped skills
13
- * npx muka-ui install-skill setup-muka # install a specific skill
13
+ * npx muka-ui install-skill setup-muka # install specific skills
14
+ * npx muka-ui install-skill --list # show what is available
14
15
  */
15
16
 
16
17
  const path = require('path');
@@ -39,28 +40,63 @@ function listShippedSkills() {
39
40
  return fs
40
41
  .readdirSync(SHIPPED_SKILLS_DIR, { withFileTypes: true })
41
42
  .filter((d) => d.isDirectory() && fileExists(path.join(SHIPPED_SKILLS_DIR, d.name, 'SKILL.md')))
42
- .map((d) => d.name);
43
+ .map((d) => d.name)
44
+ .sort();
45
+ }
46
+
47
+ /**
48
+ * Pull the `description:` line out of a skill's YAML frontmatter so `--list`
49
+ * can explain what each skill does without the caller opening the files.
50
+ */
51
+ function describeSkill(skillName) {
52
+ const content = readFile(path.join(SHIPPED_SKILLS_DIR, skillName, 'SKILL.md'));
53
+ const match = content.match(/^description:\s*(.+)$/m);
54
+ return match ? match[1].trim() : '';
55
+ }
56
+
57
+ /**
58
+ * Every file in a skill directory, as paths relative to that directory. Skills
59
+ * may ship reference files alongside SKILL.md, and dropping them would leave
60
+ * the skill pointing at documentation that never arrived.
61
+ */
62
+ function skillFiles(skillDir, prefix = '') {
63
+ const files = [];
64
+ for (const entry of fs.readdirSync(path.join(skillDir, prefix), { withFileTypes: true })) {
65
+ const relative = path.join(prefix, entry.name);
66
+ if (entry.isDirectory()) {
67
+ files.push(...skillFiles(skillDir, relative));
68
+ } else if (entry.isFile()) {
69
+ files.push(relative);
70
+ }
71
+ }
72
+ return files;
43
73
  }
44
74
 
45
75
  /**
46
76
  * Copy one shipped skill into the project's .claude/skills directory.
47
- * Returns true if written, false if skipped.
77
+ * Returns true if anything was written, false if skipped.
48
78
  */
49
79
  async function installOne(skillName, projectRoot) {
50
- const src = path.join(SHIPPED_SKILLS_DIR, skillName, 'SKILL.md');
51
- if (!fileExists(src)) {
80
+ const srcDir = path.join(SHIPPED_SKILLS_DIR, skillName);
81
+ if (!fileExists(path.join(srcDir, 'SKILL.md'))) {
52
82
  console.log(`⚠️ No shipped skill named "${skillName}".`);
53
83
  return false;
54
84
  }
55
85
 
56
86
  const destDir = path.join(projectRoot, '.claude', 'skills', skillName);
57
- const dest = path.join(destDir, 'SKILL.md');
87
+ const files = skillFiles(srcDir);
58
88
 
59
- if (fileExists(dest)) {
60
- if (readFile(dest) === readFile(src)) {
61
- console.log(`✓ /${skillName} already up to date`);
62
- return false;
63
- }
89
+ const identical = files.every((file) => {
90
+ const dest = path.join(destDir, file);
91
+ return fileExists(dest) && readFile(dest) === readFile(path.join(srcDir, file));
92
+ });
93
+
94
+ if (identical) {
95
+ console.log(`✓ /${skillName} already up to date`);
96
+ return false;
97
+ }
98
+
99
+ if (dirExists(destDir)) {
64
100
  const overwrite = await confirm(`/${skillName} already exists. Overwrite?`);
65
101
  if (!overwrite) {
66
102
  console.log(`⏭ Skipped /${skillName}`);
@@ -68,20 +104,20 @@ async function installOne(skillName, projectRoot) {
68
104
  }
69
105
  }
70
106
 
71
- ensureDir(destDir);
72
- writeFile(dest, readFile(src));
73
- console.log(`✓ Installed /${skillName} → .claude/skills/${skillName}/SKILL.md`);
107
+ for (const file of files) {
108
+ const dest = path.join(destDir, file);
109
+ ensureDir(path.dirname(dest));
110
+ writeFile(dest, readFile(path.join(srcDir, file)));
111
+ }
112
+
113
+ const extra = files.length > 1 ? ` (+${files.length - 1} reference file(s))` : '';
114
+ console.log(`✓ Installed /${skillName} → .claude/skills/${skillName}/${extra}`);
74
115
  return true;
75
116
  }
76
117
 
77
118
  async function installSkill(args) {
78
119
  console.log('\n🎨 Muka UI — install skills\n');
79
120
 
80
- const projectRoot = findProjectRoot();
81
- if (!projectRoot) {
82
- throw new Error('Could not find package.json. Are you in a Node.js project?');
83
- }
84
-
85
121
  const available = listShippedSkills();
86
122
  if (available.length === 0) {
87
123
  throw new Error(
@@ -90,8 +126,26 @@ async function installSkill(args) {
90
126
  );
91
127
  }
92
128
 
129
+ if (args && (args.includes('--list') || args.includes('-l'))) {
130
+ console.log('Shipped skills:\n');
131
+ for (const name of available) {
132
+ console.log(` /${name}`);
133
+ const description = describeSkill(name);
134
+ if (description) console.log(` ${description}`);
135
+ }
136
+ console.log('\nInstall all of them with: npx muka-ui install-skill');
137
+ console.log('Or just some: npx muka-ui install-skill setup-muka add-brand\n');
138
+ return;
139
+ }
140
+
141
+ const projectRoot = findProjectRoot();
142
+ if (!projectRoot) {
143
+ throw new Error('Could not find package.json. Are you in a Node.js project?');
144
+ }
145
+
93
146
  const requested = args && args.length > 0 ? args : available;
94
147
  let installed = 0;
148
+ const present = [];
95
149
  for (const name of requested) {
96
150
  if (!available.includes(name)) {
97
151
  console.log(`⚠️ "${name}" is not a shipped skill (available: ${available.join(', ')})`);
@@ -100,12 +154,16 @@ async function installSkill(args) {
100
154
  if (await installOne(name, projectRoot)) {
101
155
  installed += 1;
102
156
  }
157
+ present.push(name);
103
158
  }
104
159
 
105
160
  console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
106
161
  if (installed > 0) {
107
- console.log('Done. Restart Claude Code if it is open, then run:');
108
- console.log(' /setup-muka [brand]');
162
+ // Suggest a skill that is actually there — a partial install may not
163
+ // include /setup-muka.
164
+ const next = present.includes('setup-muka') ? '/setup-muka [brand]' : `/${present[0]}`;
165
+ console.log('Done. Restart your agent if it is open, then run:');
166
+ console.log(` ${next}`);
109
167
  } else {
110
168
  console.log('Nothing to install — skills already present.');
111
169
  }