@zvoove/unity-ui 2.23.1 → 2.25.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.
@@ -1,453 +1,468 @@
1
- /**
2
- * Unity UI — Agent Skills Generator
3
- *
4
- * Generates individual SKILL.md files for each Unity UI component
5
- * following the Agent Skills standard (https://agentskills.io).
6
- *
7
- * Run from a project that has @zvoove/unity-ui installed:
8
- *
9
- * npx unity-ui-skills → outputs to .claude/skills/
10
- * npx unity-ui-skills --output .cursor → outputs to .cursor/skills/
11
- * npx unity-ui-skills --output ./my-skills → outputs to ./my-skills/
12
- *
13
- * Skills enable progressive disclosure — AI agents scan skill metadata
14
- * initially but load full content only when relevant to the current task.
15
- */
16
- import fs from 'fs';
17
- import path from 'path';
18
- import { fileURLToPath } from 'url';
19
-
20
- const __filename = fileURLToPath(import.meta.url);
21
- const __dirname = path.dirname(__filename);
22
-
23
- // ─── Resolve llms.txt from the installed package ────────────────────────────
24
-
25
- const packageRoot = path.resolve(__dirname, '..', '..');
26
-
27
- export function findLlmsTxt() {
28
- // 1. Co-located with this bin (inside the published package)
29
- const fromDist = path.resolve(packageRoot, 'dist', 'llms.txt');
30
- if (fs.existsSync(fromDist)) return fromDist;
31
-
32
- // 2. Fallback: llms.txt at the package root (dev / pre-build)
33
- const fromRoot = path.resolve(packageRoot, 'llms.txt');
34
- if (fs.existsSync(fromRoot)) return fromRoot;
1
+ #!/usr/bin/env node
2
+ #!/usr/bin/env node
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __esm = (fn, res) => function __init() {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ };
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
35
12
 
36
- return null;
13
+ // bin/commands/config.mjs
14
+ var config_exports = {};
15
+ __export(config_exports, {
16
+ DEFAULTS: () => DEFAULTS,
17
+ loadConfig: () => loadConfig
18
+ });
19
+ import fs from "fs";
20
+ import path from "path";
21
+ import { pathToFileURL } from "url";
22
+ function deepMerge(target, source) {
23
+ const result = { ...target };
24
+ for (const key of Object.keys(source)) {
25
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key]) && target[key] && typeof target[key] === "object" && !Array.isArray(target[key])) {
26
+ result[key] = deepMerge(target[key], source[key]);
27
+ } else {
28
+ result[key] = source[key];
29
+ }
30
+ }
31
+ return result;
37
32
  }
33
+ async function loadConfig() {
34
+ const configPath = path.resolve(process.cwd(), "unity-ui.config.mjs");
35
+ if (!fs.existsSync(configPath)) {
36
+ return DEFAULTS;
37
+ }
38
+ try {
39
+ const configUrl = pathToFileURL(configPath).href;
40
+ const mod = await import(configUrl);
41
+ const userConfig = mod.default || {};
42
+ return deepMerge(DEFAULTS, userConfig);
43
+ } catch (err) {
44
+ console.warn(
45
+ `\x1B[33m\u26A0\uFE0F Failed to load unity-ui.config.mjs: ${err.message}\x1B[0m`
46
+ );
47
+ return DEFAULTS;
48
+ }
49
+ }
50
+ var DEFAULTS;
51
+ var init_config = __esm({
52
+ "bin/commands/config.mjs"() {
53
+ "use strict";
54
+ DEFAULTS = {
55
+ components: {
56
+ directory: "src/components",
57
+ indexFile: "src/index.ts"
58
+ },
59
+ ai: {
60
+ skills: {
61
+ output: ".claude"
62
+ },
63
+ rules: {
64
+ output: ".",
65
+ targets: ["cursorrules", "claude"]
66
+ }
67
+ }
68
+ };
69
+ }
70
+ });
38
71
 
39
- // ─── CLI args ───────────────────────────────────────────────────────────────
40
-
41
- // ─── Name normalization ─────────────────────────────────────────────────────
42
- // Maps llms.txt header names → clean skill identifiers.
43
- const NAME_MAP = {
44
- 'Avatar & AvatarGroup': 'Avatar',
45
- 'Radio (RadioGroup + RadioButton)': 'Radio',
46
- 'Segment (SegmentGroup + SegmentButton)': 'Segment',
47
- 'Common Icons': '__SKIP__',
48
- 'File Type Icons': '__SKIP__',
72
+ // bin/commands/skills.mjs
73
+ import fs2 from "fs";
74
+ import path2 from "path";
75
+ import { fileURLToPath } from "url";
76
+ var __filename = fileURLToPath(import.meta.url);
77
+ var __dirname = path2.dirname(__filename);
78
+ var packageRoot = path2.resolve(__dirname, "..", "..");
79
+ function findLlmsTxt() {
80
+ const fromDist = path2.resolve(packageRoot, "dist", "llms.txt");
81
+ if (fs2.existsSync(fromDist)) return fromDist;
82
+ const fromRoot = path2.resolve(packageRoot, "llms.txt");
83
+ if (fs2.existsSync(fromRoot)) return fromRoot;
84
+ return null;
85
+ }
86
+ var NAME_MAP = {
87
+ "Avatar & AvatarGroup": "Avatar",
88
+ "Radio (RadioGroup + RadioButton)": "Radio",
89
+ "Segment (SegmentGroup + SegmentButton)": "Segment",
90
+ "Common Icons": "__SKIP__",
91
+ "File Type Icons": "__SKIP__"
49
92
  };
50
-
51
- // ─── shadcn/ui equivalence map ──────────────────────────────────────────────
52
- const SHADCN_MAP = {
93
+ var SHADCN_MAP = {
53
94
  Accordion: {
54
- name: 'Accordion',
55
- url: 'https://ui.shadcn.com/docs/components/accordion',
95
+ name: "Accordion",
96
+ url: "https://ui.shadcn.com/docs/components/accordion"
56
97
  },
57
98
  ActionCard: null,
58
99
  Avatar: {
59
- name: 'Avatar',
60
- url: 'https://ui.shadcn.com/docs/components/avatar',
100
+ name: "Avatar",
101
+ url: "https://ui.shadcn.com/docs/components/avatar"
61
102
  },
62
- Badge: { name: 'Badge', url: 'https://ui.shadcn.com/docs/components/badge' },
103
+ Badge: { name: "Badge", url: "https://ui.shadcn.com/docs/components/badge" },
63
104
  Breadcrumbs: {
64
- name: 'Breadcrumb',
65
- url: 'https://ui.shadcn.com/docs/components/breadcrumb',
105
+ name: "Breadcrumb",
106
+ url: "https://ui.shadcn.com/docs/components/breadcrumb"
66
107
  },
67
108
  Button: {
68
- name: 'Button',
69
- url: 'https://ui.shadcn.com/docs/components/button',
109
+ name: "Button",
110
+ url: "https://ui.shadcn.com/docs/components/button"
70
111
  },
71
- Card: { name: 'Card', url: 'https://ui.shadcn.com/docs/components/card' },
112
+ Card: { name: "Card", url: "https://ui.shadcn.com/docs/components/card" },
72
113
  ChatBubble: null,
73
114
  Checkbox: {
74
- name: 'Checkbox',
75
- url: 'https://ui.shadcn.com/docs/components/checkbox',
115
+ name: "Checkbox",
116
+ url: "https://ui.shadcn.com/docs/components/checkbox"
76
117
  },
77
118
  Chip: {
78
- name: 'Badge',
79
- url: 'https://ui.shadcn.com/docs/components/badge',
80
- note: 'shadcn Badge covers simple labels; Unity UI Chip adds interactivity (filter, input, suggestion types).',
119
+ name: "Badge",
120
+ url: "https://ui.shadcn.com/docs/components/badge",
121
+ note: "shadcn Badge covers simple labels; Unity UI Chip adds interactivity (filter, input, suggestion types)."
81
122
  },
82
123
  CodeBlock: null,
83
124
  ConfirmationCard: {
84
- name: 'AlertDialog',
85
- url: 'https://ui.shadcn.com/docs/components/alert-dialog',
86
- note: 'AlertDialog is the closest equivalent for confirmation flows, but ConfirmationCard is an inline card, not a modal.',
125
+ name: "AlertDialog",
126
+ url: "https://ui.shadcn.com/docs/components/alert-dialog",
127
+ note: "AlertDialog is the closest equivalent for confirmation flows, but ConfirmationCard is an inline card, not a modal."
87
128
  },
88
129
  ContentBlock: null,
89
130
  DatePicker: {
90
- name: 'DatePicker',
91
- url: 'https://ui.shadcn.com/docs/components/date-picker',
131
+ name: "DatePicker",
132
+ url: "https://ui.shadcn.com/docs/components/date-picker"
92
133
  },
93
134
  Dialog: {
94
- name: 'Dialog',
95
- url: 'https://ui.shadcn.com/docs/components/dialog',
135
+ name: "Dialog",
136
+ url: "https://ui.shadcn.com/docs/components/dialog"
96
137
  },
97
138
  Divider: {
98
- name: 'Separator',
99
- url: 'https://ui.shadcn.com/docs/components/separator',
139
+ name: "Separator",
140
+ url: "https://ui.shadcn.com/docs/components/separator"
100
141
  },
101
142
  Expandable: {
102
- name: 'Collapsible',
103
- url: 'https://ui.shadcn.com/docs/components/collapsible',
143
+ name: "Collapsible",
144
+ url: "https://ui.shadcn.com/docs/components/collapsible"
104
145
  },
105
146
  FormLabel: {
106
- name: 'Label',
107
- url: 'https://ui.shadcn.com/docs/components/label',
147
+ name: "Label",
148
+ url: "https://ui.shadcn.com/docs/components/label"
108
149
  },
109
150
  Grid: null,
110
151
  Icon: null,
111
152
  InfoBox: {
112
- name: 'Alert',
113
- url: 'https://ui.shadcn.com/docs/components/alert',
153
+ name: "Alert",
154
+ url: "https://ui.shadcn.com/docs/components/alert"
114
155
  },
115
156
  MessageActions: null,
116
157
  Pagination: {
117
- name: 'Pagination',
118
- url: 'https://ui.shadcn.com/docs/components/pagination',
158
+ name: "Pagination",
159
+ url: "https://ui.shadcn.com/docs/components/pagination"
119
160
  },
120
161
  PopUpMenu: {
121
- name: 'DropdownMenu',
122
- url: 'https://ui.shadcn.com/docs/components/dropdown-menu',
123
- note: 'Also comparable to ContextMenu when using trigger="right-click".',
162
+ name: "DropdownMenu",
163
+ url: "https://ui.shadcn.com/docs/components/dropdown-menu",
164
+ note: 'Also comparable to ContextMenu when using trigger="right-click".'
124
165
  },
125
166
  ProgressIndicator: {
126
- name: 'Progress',
127
- url: 'https://ui.shadcn.com/docs/components/progress',
167
+ name: "Progress",
168
+ url: "https://ui.shadcn.com/docs/components/progress"
128
169
  },
129
170
  Radio: {
130
- name: 'RadioGroup',
131
- url: 'https://ui.shadcn.com/docs/components/radio-group',
171
+ name: "RadioGroup",
172
+ url: "https://ui.shadcn.com/docs/components/radio-group"
132
173
  },
133
174
  ScoreCard: null,
134
175
  Segment: {
135
- name: 'ToggleGroup',
136
- url: 'https://ui.shadcn.com/docs/components/toggle-group',
176
+ name: "ToggleGroup",
177
+ url: "https://ui.shadcn.com/docs/components/toggle-group"
137
178
  },
138
179
  Select: {
139
- name: 'Select',
140
- url: 'https://ui.shadcn.com/docs/components/select',
141
- note: 'When searchable=true, comparable to Combobox.',
180
+ name: "Select",
181
+ url: "https://ui.shadcn.com/docs/components/select",
182
+ note: "When searchable=true, comparable to Combobox."
142
183
  },
143
- Sheet: { name: 'Sheet', url: 'https://ui.shadcn.com/docs/components/sheet' },
184
+ Sheet: { name: "Sheet", url: "https://ui.shadcn.com/docs/components/sheet" },
144
185
  SideNavigation: {
145
- name: 'Sidebar',
146
- url: 'https://ui.shadcn.com/docs/components/sidebar',
186
+ name: "Sidebar",
187
+ url: "https://ui.shadcn.com/docs/components/sidebar"
147
188
  },
148
189
  Skeleton: {
149
- name: 'Skeleton',
150
- url: 'https://ui.shadcn.com/docs/components/skeleton',
190
+ name: "Skeleton",
191
+ url: "https://ui.shadcn.com/docs/components/skeleton"
151
192
  },
152
193
  Snackbar: {
153
- name: 'Sonner (Toast)',
154
- url: 'https://ui.shadcn.com/docs/components/sonner',
194
+ name: "Sonner (Toast)",
195
+ url: "https://ui.shadcn.com/docs/components/sonner"
155
196
  },
156
197
  Stack: null,
157
198
  Switch: {
158
- name: 'Switch',
159
- url: 'https://ui.shadcn.com/docs/components/switch',
199
+ name: "Switch",
200
+ url: "https://ui.shadcn.com/docs/components/switch"
160
201
  },
161
202
  Table: {
162
- name: 'Table / DataTable',
163
- url: 'https://ui.shadcn.com/docs/components/data-table',
203
+ name: "Table / DataTable",
204
+ url: "https://ui.shadcn.com/docs/components/data-table"
164
205
  },
165
- Tabs: { name: 'Tabs', url: 'https://ui.shadcn.com/docs/components/tabs' },
206
+ Tabs: { name: "Tabs", url: "https://ui.shadcn.com/docs/components/tabs" },
166
207
  Tag: {
167
- name: 'Badge',
168
- url: 'https://ui.shadcn.com/docs/components/badge',
169
- note: 'shadcn Badge is the closest match. Unity UI Tag offers more color and tone variants.',
208
+ name: "Badge",
209
+ url: "https://ui.shadcn.com/docs/components/badge",
210
+ note: "shadcn Badge is the closest match. Unity UI Tag offers more color and tone variants."
170
211
  },
171
212
  TextField: {
172
- name: 'Input',
173
- url: 'https://ui.shadcn.com/docs/components/input',
213
+ name: "Input",
214
+ url: "https://ui.shadcn.com/docs/components/input"
174
215
  },
175
216
  Textarea: {
176
- name: 'Textarea',
177
- url: 'https://ui.shadcn.com/docs/components/textarea',
217
+ name: "Textarea",
218
+ url: "https://ui.shadcn.com/docs/components/textarea"
178
219
  },
179
220
  Tooltip: {
180
- name: 'Tooltip',
181
- url: 'https://ui.shadcn.com/docs/components/tooltip',
221
+ name: "Tooltip",
222
+ url: "https://ui.shadcn.com/docs/components/tooltip"
182
223
  },
183
224
  TopBar: null,
184
225
  Typography: null,
185
226
  Uploader: null,
186
227
  useBreakpoint: null,
187
- useClickOutside: null,
228
+ useClickOutside: null
188
229
  };
189
-
190
- // ─── MUI equivalence map ─────────────────────────────────────────────────────
191
- const MUI_BASE = 'https://mui.com/material-ui/react-';
192
- const MUI_X_BASE = 'https://mui.com/x/react-';
193
-
194
- const MUI_MAP = {
195
- Accordion: { name: 'Accordion', url: `${MUI_BASE}accordion/` },
230
+ var MUI_BASE = "https://mui.com/material-ui/react-";
231
+ var MUI_X_BASE = "https://mui.com/x/react-";
232
+ var MUI_MAP = {
233
+ Accordion: { name: "Accordion", url: `${MUI_BASE}accordion/` },
196
234
  ActionCard: null,
197
- Avatar: { name: 'Avatar', url: `${MUI_BASE}avatar/` },
198
- Badge: { name: 'Badge', url: `${MUI_BASE}badge/` },
199
- Breadcrumbs: { name: 'Breadcrumbs', url: `${MUI_BASE}breadcrumbs/` },
200
- Button: { name: 'Button', url: `${MUI_BASE}button/` },
201
- Card: { name: 'Card', url: `${MUI_BASE}card/` },
235
+ Avatar: { name: "Avatar", url: `${MUI_BASE}avatar/` },
236
+ Badge: { name: "Badge", url: `${MUI_BASE}badge/` },
237
+ Breadcrumbs: { name: "Breadcrumbs", url: `${MUI_BASE}breadcrumbs/` },
238
+ Button: { name: "Button", url: `${MUI_BASE}button/` },
239
+ Card: { name: "Card", url: `${MUI_BASE}card/` },
202
240
  ChatBubble: null,
203
- Checkbox: { name: 'Checkbox', url: `${MUI_BASE}checkbox/` },
204
- Chip: { name: 'Chip', url: `${MUI_BASE}chip/` },
241
+ Checkbox: { name: "Checkbox", url: `${MUI_BASE}checkbox/` },
242
+ Chip: { name: "Chip", url: `${MUI_BASE}chip/` },
205
243
  CodeBlock: null,
206
244
  ConfirmationCard: {
207
- name: 'Dialog',
245
+ name: "Dialog",
208
246
  url: `${MUI_BASE}dialog/`,
209
- note: 'Use a Dialog with confirmation actions. ConfirmationCard is an inline card, not a modal.',
247
+ note: "Use a Dialog with confirmation actions. ConfirmationCard is an inline card, not a modal."
210
248
  },
211
249
  ContentBlock: null,
212
250
  DatePicker: {
213
- name: 'DatePicker',
251
+ name: "DatePicker",
214
252
  url: `${MUI_X_BASE}date-picker/`,
215
- note: 'MUI X component requires @mui/x-date-pickers.',
253
+ note: "MUI X component \u2014 requires @mui/x-date-pickers."
216
254
  },
217
- Dialog: { name: 'Dialog', url: `${MUI_BASE}dialog/` },
218
- Divider: { name: 'Divider', url: `${MUI_BASE}divider/` },
219
- Expandable: { name: 'Collapse', url: `${MUI_BASE}collapse/` },
220
- FormLabel: { name: 'FormLabel', url: `${MUI_BASE}text-field/` },
221
- Grid: { name: 'Grid', url: `${MUI_BASE}grid/` },
222
- Icon: { name: 'SvgIcon', url: `${MUI_BASE}icons/` },
223
- InfoBox: { name: 'Alert', url: `${MUI_BASE}alert/` },
255
+ Dialog: { name: "Dialog", url: `${MUI_BASE}dialog/` },
256
+ Divider: { name: "Divider", url: `${MUI_BASE}divider/` },
257
+ Expandable: { name: "Collapse", url: `${MUI_BASE}collapse/` },
258
+ FormLabel: { name: "FormLabel", url: `${MUI_BASE}text-field/` },
259
+ Grid: { name: "Grid", url: `${MUI_BASE}grid/` },
260
+ Icon: { name: "SvgIcon", url: `${MUI_BASE}icons/` },
261
+ InfoBox: { name: "Alert", url: `${MUI_BASE}alert/` },
224
262
  MessageActions: null,
225
- Pagination: { name: 'Pagination', url: `${MUI_BASE}pagination/` },
226
- PopUpMenu: { name: 'Menu', url: `${MUI_BASE}menu/` },
263
+ Pagination: { name: "Pagination", url: `${MUI_BASE}pagination/` },
264
+ PopUpMenu: { name: "Menu", url: `${MUI_BASE}menu/` },
227
265
  ProgressIndicator: {
228
- name: 'LinearProgress / CircularProgress',
229
- url: `${MUI_BASE}progress/`,
266
+ name: "LinearProgress / CircularProgress",
267
+ url: `${MUI_BASE}progress/`
230
268
  },
231
- Radio: { name: 'RadioGroup', url: `${MUI_BASE}radio-button/` },
269
+ Radio: { name: "RadioGroup", url: `${MUI_BASE}radio-button/` },
232
270
  ScoreCard: null,
233
271
  Segment: {
234
- name: 'ToggleButtonGroup',
235
- url: `${MUI_BASE}toggle-button/`,
272
+ name: "ToggleButtonGroup",
273
+ url: `${MUI_BASE}toggle-button/`
236
274
  },
237
- Select: { name: 'Select', url: `${MUI_BASE}select/` },
275
+ Select: { name: "Select", url: `${MUI_BASE}select/` },
238
276
  Sheet: {
239
- name: 'Drawer',
277
+ name: "Drawer",
240
278
  url: `${MUI_BASE}drawer/`,
241
- note: 'Use a temporary or persistent Drawer.',
279
+ note: "Use a temporary or persistent Drawer."
242
280
  },
243
281
  SideNavigation: {
244
- name: 'Drawer (persistent)',
245
- url: `${MUI_BASE}drawer/`,
282
+ name: "Drawer (persistent)",
283
+ url: `${MUI_BASE}drawer/`
246
284
  },
247
- Skeleton: { name: 'Skeleton', url: `${MUI_BASE}skeleton/` },
248
- Snackbar: { name: 'Snackbar', url: `${MUI_BASE}snackbar/` },
249
- Stack: { name: 'Stack', url: `${MUI_BASE}stack/` },
250
- Switch: { name: 'Switch', url: `${MUI_BASE}switch/` },
285
+ Skeleton: { name: "Skeleton", url: `${MUI_BASE}skeleton/` },
286
+ Snackbar: { name: "Snackbar", url: `${MUI_BASE}snackbar/` },
287
+ Stack: { name: "Stack", url: `${MUI_BASE}stack/` },
288
+ Switch: { name: "Switch", url: `${MUI_BASE}switch/` },
251
289
  Table: {
252
- name: 'Table / DataGrid',
290
+ name: "Table / DataGrid",
253
291
  url: `${MUI_BASE}table/`,
254
- note: 'For advanced features use MUI X DataGrid (@mui/x-data-grid).',
292
+ note: "For advanced features use MUI X DataGrid (@mui/x-data-grid)."
255
293
  },
256
- Tabs: { name: 'Tabs', url: `${MUI_BASE}tabs/` },
294
+ Tabs: { name: "Tabs", url: `${MUI_BASE}tabs/` },
257
295
  Tag: {
258
- name: 'Chip',
296
+ name: "Chip",
259
297
  url: `${MUI_BASE}chip/`,
260
- note: 'MUI Chip covers static labels; Unity UI Tag is display-only with more color/tone variants.',
298
+ note: "MUI Chip covers static labels; Unity UI Tag is display-only with more color/tone variants."
261
299
  },
262
- TextField: { name: 'TextField', url: `${MUI_BASE}text-field/` },
300
+ TextField: { name: "TextField", url: `${MUI_BASE}text-field/` },
263
301
  Textarea: {
264
- name: 'TextField (multiline)',
302
+ name: "TextField (multiline)",
265
303
  url: `${MUI_BASE}text-field/`,
266
- note: 'Use TextField with multiline and rows props.',
304
+ note: "Use TextField with multiline and rows props."
267
305
  },
268
- Tooltip: { name: 'Tooltip', url: `${MUI_BASE}tooltip/` },
269
- TopBar: { name: 'AppBar', url: `${MUI_BASE}app-bar/` },
270
- Typography: { name: 'Typography', url: `${MUI_BASE}typography/` },
306
+ Tooltip: { name: "Tooltip", url: `${MUI_BASE}tooltip/` },
307
+ TopBar: { name: "AppBar", url: `${MUI_BASE}app-bar/` },
308
+ Typography: { name: "Typography", url: `${MUI_BASE}typography/` },
271
309
  Uploader: null,
272
310
  useBreakpoint: {
273
- name: 'useMediaQuery',
274
- url: 'https://mui.com/material-ui/react-use-media-query/',
311
+ name: "useMediaQuery",
312
+ url: "https://mui.com/material-ui/react-use-media-query/"
275
313
  },
276
314
  useClickOutside: {
277
- name: 'ClickAwayListener',
278
- url: `${MUI_BASE}click-away-listener/`,
279
- },
315
+ name: "ClickAwayListener",
316
+ url: `${MUI_BASE}click-away-listener/`
317
+ }
280
318
  };
281
-
282
- // ─── Storybook documentation links ───────────────────────────────────────────
283
- // Maps component name → Storybook title path (as defined in *.stories.tsx).
284
- // URL: https://main--67c03f013fea08bb2f926e5f.chromatic.com/?path=/docs/<path>--docs
285
- const STORYBOOK_BASE =
286
- 'https://main--67c03f013fea08bb2f926e5f.chromatic.com/?path=/docs/';
287
-
288
- const STORYBOOK_MAP = {
289
- Accordion: 'Components/Accordion',
290
- ActionCard: 'Chat/ActionCard',
291
- Avatar: 'Components/Avatar/Avatar',
292
- Badge: 'Components/Badge',
293
- Breadcrumbs: 'Navigation/Breadcrumbs',
294
- Button: 'Components/Buttons/Button',
295
- Card: 'Components/Card',
296
- ChatBubble: 'Chat/ChatBubble',
297
- Checkbox: 'Forms/Checkbox',
298
- Chip: 'Components/Chip',
299
- CodeBlock: 'Components/CodeBlock',
300
- ConfirmationCard: 'Components/ConfirmationCard',
301
- ContentBlock: 'Components/ContentBlock',
302
- DatePicker: 'Forms/DatePicker',
303
- Dialog: 'Components/Dialog',
304
- Divider: 'Components/Divider',
305
- Expandable: 'Components/Expandable',
306
- FormLabel: 'Forms/FormLabel',
307
- Grid: 'Layout/Grid',
308
- Icon: 'Components/Icon',
309
- InfoBox: 'Components/InfoBox',
310
- MessageActions: 'Chat/MessageActions',
311
- Pagination: 'Components/Pagination',
312
- PopUpMenu: 'Components/PopUpMenu',
313
- ProgressIndicator: 'Components/ProgressIndicator',
314
- Radio: 'Forms/Radio/RadioGroup',
315
- ScoreCard: 'Components/ScoreCard',
316
- Segment: 'Components/Buttons/Segment/SegmentGroup',
317
- Select: 'Forms/Select',
318
- Sheet: 'Components/Sheet',
319
- SideNavigation: 'Navigation/SideNavigation',
320
- Skeleton: 'Components/Skeleton',
321
- Snackbar: 'Components/Snackbar',
322
- Stack: 'Layout/Stack',
323
- Switch: 'Forms/Switch',
324
- Table: 'Components/Table',
325
- Tabs: 'Navigation/Tabs',
326
- Tag: 'Components/Tag',
327
- TextField: 'Forms/TextField',
328
- Textarea: 'Forms/Textarea',
329
- Tooltip: 'Components/Tooltip',
330
- TopBar: 'Components/TopBar',
331
- Typography: 'Components/Typography',
332
- Uploader: 'Forms/Uploader',
319
+ var STORYBOOK_BASE = "https://main--67c03f013fea08bb2f926e5f.chromatic.com/?path=/docs/";
320
+ var STORYBOOK_MAP = {
321
+ Accordion: "Components/Accordion",
322
+ ActionCard: "Chat/ActionCard",
323
+ Avatar: "Components/Avatar/Avatar",
324
+ Badge: "Components/Badge",
325
+ Breadcrumbs: "Navigation/Breadcrumbs",
326
+ Button: "Components/Buttons/Button",
327
+ Card: "Components/Card",
328
+ ChatBubble: "Chat/ChatBubble",
329
+ Checkbox: "Forms/Checkbox",
330
+ Chip: "Components/Chip",
331
+ CodeBlock: "Components/CodeBlock",
332
+ ConfirmationCard: "Components/ConfirmationCard",
333
+ ContentBlock: "Components/ContentBlock",
334
+ DatePicker: "Forms/DatePicker",
335
+ Dialog: "Components/Dialog",
336
+ Divider: "Components/Divider",
337
+ Expandable: "Components/Expandable",
338
+ FormLabel: "Forms/FormLabel",
339
+ Grid: "Layout/Grid",
340
+ Icon: "Components/Icon",
341
+ InfoBox: "Components/InfoBox",
342
+ MessageActions: "Chat/MessageActions",
343
+ Pagination: "Components/Pagination",
344
+ PopUpMenu: "Components/PopUpMenu",
345
+ ProgressIndicator: "Components/ProgressIndicator",
346
+ Radio: "Forms/Radio/RadioGroup",
347
+ ScoreCard: "Components/ScoreCard",
348
+ Segment: "Components/Buttons/Segment/SegmentGroup",
349
+ Select: "Forms/Select",
350
+ Sheet: "Components/Sheet",
351
+ SideNavigation: "Navigation/SideNavigation",
352
+ Skeleton: "Components/Skeleton",
353
+ Snackbar: "Components/Snackbar",
354
+ Stack: "Layout/Stack",
355
+ Switch: "Forms/Switch",
356
+ Table: "Components/Table",
357
+ Tabs: "Navigation/Tabs",
358
+ Tag: "Components/Tag",
359
+ TextField: "Forms/TextField",
360
+ Textarea: "Forms/Textarea",
361
+ Tooltip: "Components/Tooltip",
362
+ TopBar: "Components/TopBar",
363
+ Typography: "Components/Typography",
364
+ Uploader: "Forms/Uploader"
333
365
  };
334
-
335
366
  function storybookUrl(name) {
336
367
  const title = STORYBOOK_MAP[name];
337
368
  if (!title) return null;
338
- const slug = title.toLowerCase().replaceAll('/', '-');
369
+ const slug = title.toLowerCase().replaceAll("/", "-");
339
370
  return `${STORYBOOK_BASE}${slug}--docs`;
340
371
  }
341
-
342
- // ─── Component categories ───────────────────────────────────────────────────
343
- const CATEGORIES = {
344
- Stack: 'layout',
345
- Grid: 'layout',
346
- Card: 'layout',
347
- Divider: 'layout',
348
- Expandable: 'layout',
349
- ContentBlock: 'layout',
350
- Typography: 'typography',
351
- TextField: 'form',
352
- Textarea: 'form',
353
- Select: 'form',
354
- Checkbox: 'form',
355
- Radio: 'form',
356
- Switch: 'form',
357
- DatePicker: 'form',
358
- Uploader: 'form',
359
- FormLabel: 'form',
360
- Button: 'action',
361
- Segment: 'action',
362
- PopUpMenu: 'action',
363
- Table: 'data-display',
364
- Tag: 'data-display',
365
- Chip: 'data-display',
366
- Avatar: 'data-display',
367
- Badge: 'data-display',
368
- Icon: 'data-display',
369
- Skeleton: 'data-display',
370
- ProgressIndicator: 'data-display',
371
- CodeBlock: 'data-display',
372
- Tabs: 'navigation',
373
- Breadcrumbs: 'navigation',
374
- SideNavigation: 'navigation',
375
- Pagination: 'navigation',
376
- TopBar: 'navigation',
377
- Dialog: 'feedback',
378
- Sheet: 'feedback',
379
- Snackbar: 'feedback',
380
- InfoBox: 'feedback',
381
- ConfirmationCard: 'feedback',
382
- Tooltip: 'feedback',
383
- Accordion: 'compound',
384
- ActionCard: 'compound',
385
- ChatBubble: 'compound',
386
- MessageActions: 'compound',
387
- ScoreCard: 'compound',
388
- useBreakpoint: 'hook',
389
- useClickOutside: 'hook',
372
+ var CATEGORIES = {
373
+ Stack: "layout",
374
+ Grid: "layout",
375
+ Card: "layout",
376
+ Divider: "layout",
377
+ Expandable: "layout",
378
+ ContentBlock: "layout",
379
+ Typography: "typography",
380
+ TextField: "form",
381
+ Textarea: "form",
382
+ Select: "form",
383
+ Checkbox: "form",
384
+ Radio: "form",
385
+ Switch: "form",
386
+ DatePicker: "form",
387
+ Uploader: "form",
388
+ FormLabel: "form",
389
+ Button: "action",
390
+ Segment: "action",
391
+ PopUpMenu: "action",
392
+ Table: "data-display",
393
+ Tag: "data-display",
394
+ Chip: "data-display",
395
+ Avatar: "data-display",
396
+ Badge: "data-display",
397
+ Icon: "data-display",
398
+ Skeleton: "data-display",
399
+ ProgressIndicator: "data-display",
400
+ CodeBlock: "data-display",
401
+ Tabs: "navigation",
402
+ Breadcrumbs: "navigation",
403
+ SideNavigation: "navigation",
404
+ Pagination: "navigation",
405
+ TopBar: "navigation",
406
+ Dialog: "feedback",
407
+ Sheet: "feedback",
408
+ Snackbar: "feedback",
409
+ InfoBox: "feedback",
410
+ ConfirmationCard: "feedback",
411
+ Tooltip: "feedback",
412
+ Accordion: "compound",
413
+ ActionCard: "compound",
414
+ ChatBubble: "compound",
415
+ MessageActions: "compound",
416
+ ScoreCard: "compound",
417
+ useBreakpoint: "hook",
418
+ useClickOutside: "hook"
390
419
  };
391
-
392
- // Category-specific rules appended to each skill
393
- const CATEGORY_RULES = {
420
+ var CATEGORY_RULES = {
394
421
  layout: [
395
- '- Use Stack and Grid for layout instead of raw div + CSS',
396
- '- Use the spacing scale for gap/padding/margin never use arbitrary pixel values',
422
+ "- Use Stack and Grid for layout instead of raw div + CSS",
423
+ "- Use the spacing scale for gap/padding/margin \u2014 never use arbitrary pixel values"
397
424
  ],
398
425
  form: [
399
- '- Never create custom form inputs when this component exists',
400
- '- Use responsive `density` prop when available for compact layouts',
426
+ "- Never create custom form inputs when this component exists",
427
+ "- Use responsive `density` prop when available for compact layouts"
401
428
  ],
402
429
  feedback: [
403
- '- Never create custom overlays or toast systems when this component exists',
430
+ "- Never create custom overlays or toast systems when this component exists"
404
431
  ],
405
432
  typography: [
406
- '- Use Typography for all text never use raw `<p>`, `<h1>`, `<span>` etc.',
433
+ "- Use Typography for all text \u2014 never use raw `<p>`, `<h1>`, `<span>` etc."
407
434
  ],
408
- hook: ['- Import hooks directly from `@zvoove/unity-ui`'],
435
+ hook: ["- Import hooks directly from `@zvoove/unity-ui`"]
409
436
  };
410
-
411
- // ─── Parse llms.txt ─────────────────────────────────────────────────────────
412
-
413
437
  function detectSection(line) {
414
438
  const sectionHeaders = {
415
- '## Setup': 'setup',
416
- '## Responsive Props': 'responsive',
417
- '## RULES FOR AI AGENTS': 'rules',
418
- '## SPACING SCALE': 'spacing',
419
- '## ICON NAMES': 'icons',
420
- '## STYLING': 'styling',
421
- '## CUSTOM COMPONENT': 'customComponent',
439
+ "## Setup": "setup",
440
+ "## Responsive Props": "responsive",
441
+ "## RULES FOR AI AGENTS": "rules",
442
+ "## SPACING SCALE": "spacing",
443
+ "## ICON NAMES": "icons",
444
+ "## STYLING": "styling",
445
+ "## CUSTOM COMPONENT": "customComponent"
422
446
  };
423
-
424
447
  for (const [prefix, key] of Object.entries(sectionHeaders)) {
425
448
  if (line.startsWith(prefix)) return key;
426
449
  }
427
- if (line.startsWith('## EXAMPLE:')) return 'example';
428
- if (
429
- /^## [A-Z]+ COMPONENTS?$/.test(line) ||
430
- /^## (HOOKS|COMPOUND COMPONENTS|TYPOGRAPHY)$/.test(line)
431
- ) {
432
- return 'category-header';
450
+ if (line.startsWith("## EXAMPLE:")) return "example";
451
+ if (/^## [A-Z]+ COMPONENTS?$/.test(line) || /^## (HOOKS|COMPOUND COMPONENTS|TYPOGRAPHY)$/.test(line)) {
452
+ return "category-header";
433
453
  }
434
454
  return null;
435
455
  }
436
-
437
456
  function mergeComponent(components, buckets, name, lines) {
438
457
  if (!name || lines.length === 0) return;
439
458
  const normalizedName = NAME_MAP[name] ?? name;
440
-
441
- if (normalizedName === '__SKIP__') {
442
- buckets.icons.push('', `### ${name}`, ...lines);
459
+ if (normalizedName === "__SKIP__") {
460
+ buckets.icons.push("", `### ${name}`, ...lines);
443
461
  return;
444
462
  }
445
- const text = lines.join('\n').trim();
446
- components[normalizedName] = components[normalizedName]
447
- ? components[normalizedName] + '\n\n' + text
448
- : text;
463
+ const text = lines.join("\n").trim();
464
+ components[normalizedName] = components[normalizedName] ? components[normalizedName] + "\n\n" + text : text;
449
465
  }
450
-
451
466
  function parseLlmsTxt(content) {
452
467
  const components = {};
453
468
  const buckets = {
@@ -458,36 +473,30 @@ function parseLlmsTxt(content) {
458
473
  styling: [],
459
474
  customComponent: [],
460
475
  icons: [],
461
- example: [],
476
+ example: []
462
477
  };
463
-
464
478
  let activeSection = null;
465
479
  let currentComponent = null;
466
480
  let currentLines = [];
467
-
468
481
  function flush() {
469
482
  mergeComponent(components, buckets, currentComponent, currentLines);
470
483
  currentComponent = null;
471
484
  currentLines = [];
472
485
  }
473
-
474
486
  function handleSectionHeader(line) {
475
487
  flush();
476
488
  const section = detectSection(line);
477
- activeSection = section === 'category-header' ? null : section;
489
+ activeSection = section === "category-header" ? null : section;
478
490
  }
479
-
480
491
  function handleComponentHeader(line) {
481
- // In prose sections, ### sub-headings are content, not component names
482
- if (activeSection === 'styling' || activeSection === 'customComponent') {
492
+ if (activeSection === "styling" || activeSection === "customComponent") {
483
493
  handleContentLine(line);
484
494
  return;
485
495
  }
486
496
  flush();
487
497
  currentComponent = line.slice(4).trim();
488
- if (activeSection !== 'icons') activeSection = null;
498
+ if (activeSection !== "icons") activeSection = null;
489
499
  }
490
-
491
500
  function handleContentLine(line) {
492
501
  if (currentComponent) {
493
502
  currentLines.push(line);
@@ -497,99 +506,80 @@ function parseLlmsTxt(content) {
497
506
  buckets[activeSection].push(line);
498
507
  }
499
508
  }
500
-
501
- for (const line of content.split('\n')) {
502
- if (line === '---') continue;
503
- if (line.startsWith('## ')) handleSectionHeader(line);
504
- else if (line.startsWith('### ')) handleComponentHeader(line);
509
+ for (const line of content.split("\n")) {
510
+ if (line === "---") continue;
511
+ if (line.startsWith("## ")) handleSectionHeader(line);
512
+ else if (line.startsWith("### ")) handleComponentHeader(line);
505
513
  else handleContentLine(line);
506
514
  }
507
-
508
515
  flush();
509
-
510
- const trimBucket = (key) => buckets[key].join('\n').trim();
516
+ const trimBucket = (key) => buckets[key].join("\n").trim();
511
517
  return {
512
- setup: trimBucket('setup'),
513
- responsive: trimBucket('responsive'),
514
- rules: trimBucket('rules'),
515
- spacing: trimBucket('spacing'),
516
- styling: trimBucket('styling'),
517
- customComponent: trimBucket('customComponent'),
518
- icons: trimBucket('icons'),
519
- example: trimBucket('example'),
520
- components,
518
+ setup: trimBucket("setup"),
519
+ responsive: trimBucket("responsive"),
520
+ rules: trimBucket("rules"),
521
+ spacing: trimBucket("spacing"),
522
+ styling: trimBucket("styling"),
523
+ customComponent: trimBucket("customComponent"),
524
+ icons: trimBucket("icons"),
525
+ example: trimBucket("example"),
526
+ components
521
527
  };
522
528
  }
523
-
524
- // ─── Skill generators ───────────────────────────────────────────────────────
525
-
526
529
  function kebabCase(str) {
527
- return str
528
- .replace(/([a-z])([A-Z])/g, '$1-$2')
529
- .toLowerCase()
530
- .replace(/[^a-z0-9]+/g, '-')
531
- .replace(/^-|-$/g, '');
530
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
532
531
  }
533
-
534
532
  function generateComponentSkill(name, content) {
535
533
  const shadcn = SHADCN_MAP[name];
536
- const category = CATEGORIES[name] || 'component';
534
+ const category = CATEGORIES[name] || "component";
537
535
  const slug = kebabCase(name);
538
536
  const docsUrl = storybookUrl(name);
539
-
540
537
  let description = `${name} component from Unity UI (@zvoove/unity-ui). Category: ${category}.`;
541
538
  if (shadcn) {
542
539
  description += ` Comparable to shadcn/ui ${shadcn.name}.`;
543
540
  }
544
541
  description += String.raw`\nTRIGGER when: user needs ${name} in a project using @zvoove/unity-ui.\nDO NOT read dist/ or source files — all API docs are in this skill.`;
545
-
546
542
  const frontmatter = [
547
- '---',
543
+ "---",
548
544
  `name: unity-ui-${slug}`,
549
545
  `description: "${description}"`,
550
- `category: ${category}`,
546
+ `category: ${category}`
551
547
  ];
552
548
  if (shadcn) frontmatter.push(`shadcn_equivalent: ${shadcn.name}`);
553
549
  if (docsUrl) frontmatter.push(`docs: ${docsUrl}`);
554
- frontmatter.push('---');
555
-
556
- const body = [`# Unity UI — ${name}\n`];
557
-
550
+ frontmatter.push("---");
551
+ const body = [`# Unity UI \u2014 ${name}
552
+ `];
558
553
  const links = [];
559
554
  if (docsUrl) links.push(`[Storybook docs](${docsUrl})`);
560
555
  if (shadcn) links.push(`[shadcn/ui ${shadcn.name}](${shadcn.url})`);
561
556
  if (links.length > 0) {
562
- body.push(`> ${links.join(' | ')}`);
557
+ body.push(`> ${links.join(" | ")}`);
563
558
  if (shadcn?.note) body.push(`> ${shadcn.note}`);
564
- body.push('');
559
+ body.push("");
565
560
  }
566
-
567
561
  body.push(content);
568
- body.push('\n## Rules\n');
569
- body.push('- Always import from `@zvoove/unity-ui`');
570
- body.push('- Never recreate components that exist in this library');
571
-
562
+ body.push("\n## Rules\n");
563
+ body.push("- Always import from `@zvoove/unity-ui`");
564
+ body.push("- Never recreate components that exist in this library");
572
565
  const extraRules = CATEGORY_RULES[category] || [];
573
566
  body.push(...extraRules);
574
567
  body.push(
575
- '- Use responsive props where applicable (single value or breakpoint object)'
568
+ "- Use responsive props where applicable (single value or breakpoint object)"
576
569
  );
577
-
578
- return frontmatter.join('\n') + '\n\n' + body.join('\n') + '\n';
570
+ return frontmatter.join("\n") + "\n\n" + body.join("\n") + "\n";
579
571
  }
580
-
581
572
  function generateSetupSkill(parsed) {
582
573
  const frontmatter = [
583
- '---',
584
- 'name: unity-ui-setup',
574
+ "---",
575
+ "name: unity-ui-setup",
585
576
  'description: "Setup and installation for Unity UI (@zvoove/unity-ui). React component library with 40+ components, Tailwind CSS 4, dark mode, responsive props."',
586
- 'category: setup',
587
- '---',
588
- ].join('\n');
577
+ "category: setup",
578
+ "---"
579
+ ].join("\n");
580
+ return frontmatter + `
589
581
 
590
- return (
591
- frontmatter +
592
- `\n\n# Unity UI — Setup & Overview
582
+ # Unity UI \u2014 Setup & Overview
593
583
 
594
584
  > Unity UI (\`@zvoove/unity-ui\`) is a React component library with 40+ accessible, themeable components built with TypeScript and Tailwind CSS 4.
595
585
 
@@ -610,22 +600,19 @@ ${parsed.example}
610
600
  ## Rules
611
601
 
612
602
  ${parsed.rules}
613
- `
614
- );
603
+ `;
615
604
  }
616
-
617
605
  function generateIconsSkill(parsed) {
618
606
  const frontmatter = [
619
- '---',
620
- 'name: unity-ui-icons',
607
+ "---",
608
+ "name: unity-ui-icons",
621
609
  'description: "Icon names and usage for Unity UI (@zvoove/unity-ui). Semantic icon names based on Phosphor Icons. Use with <Icon name=\\"icon-name\\" /> component."',
622
- 'category: data-display',
623
- '---',
624
- ].join('\n');
610
+ "category: data-display",
611
+ "---"
612
+ ].join("\n");
613
+ return frontmatter + `
625
614
 
626
- return (
627
- frontmatter +
628
- `\n\n# Unity UI — Icons
615
+ # Unity UI \u2014 Icons
629
616
 
630
617
  > Unity UI uses its own semantic icon names (not raw Phosphor icon names). Pass them via \`<Icon name="icon-name" />\`.
631
618
 
@@ -634,134 +621,111 @@ ${parsed.icons}
634
621
  ## Rules
635
622
 
636
623
  - Always import Icon from \`@zvoove/unity-ui\`
637
- - Use semantic icon name strings never import Phosphor icon components directly
624
+ - Use semantic icon name strings \u2014 never import Phosphor icon components directly
638
625
  - Use \`getIconForFileExtension(extension)\` to resolve file extensions to icon names automatically
639
- `
640
- );
626
+ `;
641
627
  }
642
-
643
628
  function generateIndexSkill(componentNames) {
644
- const shadcnRows = componentNames
645
- .filter((n) => SHADCN_MAP[n])
646
- .map(
647
- (n) =>
648
- `| ${n} | [${SHADCN_MAP[n].name}](${SHADCN_MAP[n].url}) | \`unity-ui-${kebabCase(n)}\` |`
649
- );
650
-
651
- const muiRows = componentNames
652
- .filter((n) => MUI_MAP[n])
653
- .map(
654
- (n) =>
655
- `| ${n} | [${MUI_MAP[n].name}](${MUI_MAP[n].url}) | \`unity-ui-${kebabCase(n)}\` |`
656
- );
657
-
658
- const uniqueRows = componentNames
659
- .filter((n) => !SHADCN_MAP[n] && !MUI_MAP[n])
660
- .map((n) => `| ${n} | \`unity-ui-${kebabCase(n)}\` |`);
661
-
629
+ const shadcnRows = componentNames.filter((n) => SHADCN_MAP[n]).map(
630
+ (n) => `| ${n} | [${SHADCN_MAP[n].name}](${SHADCN_MAP[n].url}) | \`unity-ui-${kebabCase(n)}\` |`
631
+ );
632
+ const muiRows = componentNames.filter((n) => MUI_MAP[n]).map(
633
+ (n) => `| ${n} | [${MUI_MAP[n].name}](${MUI_MAP[n].url}) | \`unity-ui-${kebabCase(n)}\` |`
634
+ );
635
+ const uniqueRows = componentNames.filter((n) => !SHADCN_MAP[n] && !MUI_MAP[n]).map((n) => `| ${n} | \`unity-ui-${kebabCase(n)}\` |`);
662
636
  const frontmatter = [
663
- '---',
664
- 'name: unity-ui-index',
637
+ "---",
638
+ "name: unity-ui-index",
665
639
  'description: "Component index for Unity UI (@zvoove/unity-ui). Maps all 40+ components to their shadcn/ui and MUI equivalents. Use this to find the right component or migrate from another library."',
666
- 'category: index',
667
- '---',
668
- ].join('\n');
640
+ "category: index",
641
+ "---"
642
+ ].join("\n");
643
+ return frontmatter + `
669
644
 
670
- return (
671
- frontmatter +
672
- `\n\n# Unity UI — Component Index
645
+ # Unity UI \u2014 Component Index
673
646
 
674
647
  > Use this index to find the right Unity UI component. Each component has its own skill with full documentation.
675
648
 
676
- ## shadcn/ui Unity UI
649
+ ## shadcn/ui \u2192 Unity UI
677
650
 
678
651
  | Unity UI | shadcn/ui | Skill |
679
652
  |----------|-----------|-------|
680
- ${shadcnRows.join('\n')}
653
+ ${shadcnRows.join("\n")}
681
654
 
682
- ## MUI Unity UI
655
+ ## MUI \u2192 Unity UI
683
656
 
684
657
  | Unity UI | MUI | Skill |
685
658
  |----------|-----|-------|
686
- ${muiRows.join('\n')}
659
+ ${muiRows.join("\n")}
687
660
 
688
- ## Unity UI–Only Components
661
+ ## Unity UI\u2013Only Components
689
662
 
690
663
  | Unity UI | Skill |
691
664
  |----------|-------|
692
- ${uniqueRows.map((r) => r.replace(' | ', '')).join('\n')}
665
+ ${uniqueRows.map((r) => r.replace(" | \u2014 ", "")).join("\n")}
693
666
 
694
667
  ## How to Use Skills
695
668
 
696
669
  Each skill is a standalone file with full props, usage examples, and rules for one component.
697
670
  AI agents should load the relevant skill when they need to use a specific component.
698
- `
699
- );
671
+ `;
700
672
  }
701
-
702
673
  function generateStylingSkill(parsed) {
703
674
  const description = [
704
- 'Styling guide for Unity UI (@zvoove/unity-ui). Tailwind CSS v4 + design tokens + tailwind-variants.',
705
- 'TRIGGER when: user needs to style a custom element, asks about CSS/styling, or produces inline styles / arbitrary Tailwind values in a @zvoove/unity-ui project.',
706
- 'DO NOT use inline styles, arbitrary Tailwind values, or raw CSS use design tokens and tv() instead.',
675
+ "Styling guide for Unity UI (@zvoove/unity-ui). Tailwind CSS v4 + design tokens + tailwind-variants.",
676
+ "TRIGGER when: user needs to style a custom element, asks about CSS/styling, or produces inline styles / arbitrary Tailwind values in a @zvoove/unity-ui project.",
677
+ "DO NOT use inline styles, arbitrary Tailwind values, or raw CSS \u2014 use design tokens and tv() instead."
707
678
  ].join(String.raw`\n`);
708
-
709
679
  const frontmatter = [
710
- '---',
711
- 'name: unity-ui-styling',
680
+ "---",
681
+ "name: unity-ui-styling",
712
682
  `description: "${description}"`,
713
- 'category: styling',
714
- '---',
715
- ].join('\n');
683
+ "category: styling",
684
+ "---"
685
+ ].join("\n");
686
+ return frontmatter + `
716
687
 
717
- return (
718
- frontmatter + `\n\n# Unity UI — Styling Guide\n\n` + parsed.styling + '\n'
719
- );
720
- }
688
+ # Unity UI \u2014 Styling Guide
721
689
 
690
+ ` + parsed.styling + "\n";
691
+ }
722
692
  function generateCustomComponentSkill(parsed) {
723
693
  const description = [
724
- 'Guide for creating a custom component in a project using @zvoove/unity-ui, following the same conventions as the design system.',
725
- 'TRIGGER when: user needs to create a custom component that does not exist in @zvoove/unity-ui, following Unity UI patterns.',
726
- 'DO NOT TRIGGER when: an existing Unity UI component already covers the use case use that instead.',
694
+ "Guide for creating a custom component in a project using @zvoove/unity-ui, following the same conventions as the design system.",
695
+ "TRIGGER when: user needs to create a custom component that does not exist in @zvoove/unity-ui, following Unity UI patterns.",
696
+ "DO NOT TRIGGER when: an existing Unity UI component already covers the use case \u2014 use that instead."
727
697
  ].join(String.raw`\n`);
728
-
729
698
  const frontmatter = [
730
- '---',
731
- 'name: unity-ui-custom-component',
699
+ "---",
700
+ "name: unity-ui-custom-component",
732
701
  `description: "${description}"`,
733
- 'category: authoring',
734
- '---',
735
- ].join('\n');
702
+ "category: authoring",
703
+ "---"
704
+ ].join("\n");
705
+ return frontmatter + `
736
706
 
737
- return (
738
- frontmatter +
739
- `\n\n# Unity UI — Creating a Custom Component\n\n` +
740
- parsed.customComponent +
741
- '\n'
742
- );
743
- }
707
+ # Unity UI \u2014 Creating a Custom Component
744
708
 
709
+ ` + parsed.customComponent + "\n";
710
+ }
745
711
  function generateFormsSkill() {
746
712
  const description = [
747
- 'Form composition guide for @zvoove/unity-ui with react-hook-form and zod.',
748
- 'TRIGGER when: user is building a form, adding validation, wiring inputs to a form library, or asking how to use Unity UI inputs with react-hook-form.',
749
- 'DO NOT use register() Unity UI inputs are controlled components; always use Controller.',
713
+ "Form composition guide for @zvoove/unity-ui with react-hook-form and zod.",
714
+ "TRIGGER when: user is building a form, adding validation, wiring inputs to a form library, or asking how to use Unity UI inputs with react-hook-form.",
715
+ "DO NOT use register() \u2014 Unity UI inputs are controlled components; always use Controller."
750
716
  ].join(String.raw`\n`);
751
-
752
717
  const frontmatter = [
753
- '---',
754
- 'name: unity-ui-forms',
718
+ "---",
719
+ "name: unity-ui-forms",
755
720
  `description: "${description}"`,
756
- 'category: forms',
757
- '---',
758
- ].join('\n');
721
+ "category: forms",
722
+ "---"
723
+ ].join("\n");
724
+ return frontmatter + `
759
725
 
760
- return (
761
- frontmatter +
762
- `\n\n# Unity UI — Form Composition
726
+ # Unity UI \u2014 Form Composition
763
727
 
764
- > Unity UI inputs are **controlled components**. Use \`Controller\` from react-hook-form never \`register()\`.
728
+ > Unity UI inputs are **controlled components**. Use \`Controller\` from react-hook-form \u2014 never \`register()\`.
765
729
 
766
730
  ## Installing
767
731
 
@@ -778,7 +742,7 @@ import { z } from 'zod';
778
742
  import { Button, Select, Stack, TextField } from '@zvoove/unity-ui';
779
743
 
780
744
  const schema = z.object({
781
- email: z.string().email('Ungültige E-Mail-Adresse'),
745
+ email: z.string().email('Ung\xFCltige E-Mail-Adresse'),
782
746
  role: z.string().min(1, 'Pflichtfeld'),
783
747
  });
784
748
 
@@ -840,7 +804,7 @@ export function ExampleForm() {
840
804
  | Checkbox | \`checked={field.value}\` | use \`checked\`, not \`value\` |
841
805
  | Switch | \`checked={field.value}\` | use \`checked\`, not \`value\` |
842
806
  | DatePicker | \`value={field.value} onChange={field.onChange}\` | pass date value directly |
843
- | Radio (RadioGroup) | \`value={field.value} onChange={field.onChange}\` | |
807
+ | Radio (RadioGroup) | \`value={field.value} onChange={field.onChange}\` | \u2014 |
844
808
 
845
809
  ## Checkbox / Switch Pattern
846
810
 
@@ -885,7 +849,7 @@ import { z } from 'zod';
885
849
  import { Button, Card, Checkbox, Stack, TextField, Typography } from '@zvoove/unity-ui';
886
850
 
887
851
  const loginSchema = z.object({
888
- email: z.string().email('Ungültige E-Mail-Adresse'),
852
+ email: z.string().email('Ung\xFCltige E-Mail-Adresse'),
889
853
  password: z.string().min(8, 'Mindestens 8 Zeichen erforderlich'),
890
854
  rememberMe: z.boolean().optional(),
891
855
  });
@@ -954,7 +918,7 @@ export function LoginForm() {
954
918
 
955
919
  <Stack direction="row" justify="flex-end">
956
920
  <Button type="submit" variant="filled" disabled={isSubmitting}>
957
- {isSubmitting ? 'Wird angemeldet' : 'Anmelden'}
921
+ {isSubmitting ? 'Wird angemeldet\u2026' : 'Anmelden'}
958
922
  </Button>
959
923
  </Stack>
960
924
  </Stack>
@@ -966,34 +930,30 @@ export function LoginForm() {
966
930
 
967
931
  ## Rules
968
932
 
969
- - NEVER use \`register()\` Unity UI inputs are controlled components; always use \`Controller\`
933
+ - NEVER use \`register()\` \u2014 Unity UI inputs are controlled components; always use \`Controller\`
970
934
  - ALWAYS use \`zodResolver\` from \`@hookform/resolvers/zod\` for schema validation
971
- - Checkbox and Switch require \`checked={field.value}\` not \`value\`
935
+ - Checkbox and Switch require \`checked={field.value}\` \u2014 not \`value\`
972
936
  - Display errors with \`error={!!fieldState.error}\` + \`errorMessage={fieldState.error?.message}\`
973
- - Use \`Stack\` for form layout never raw \`<div>\` with flexbox CSS
937
+ - Use \`Stack\` for form layout \u2014 never raw \`<div>\` with flexbox CSS
974
938
  - Default texts, labels, and validation messages must be in German
975
- `
976
- );
939
+ `;
977
940
  }
978
-
979
941
  function generateLayoutsSkill() {
980
942
  const description = [
981
- 'Common app layout patterns for @zvoove/unity-ui: app shells, dashboards, settings pages, master/detail.',
982
- 'TRIGGER when: user is building a page layout, app shell, or multi-section UI in a @zvoove/unity-ui project.',
983
- 'DO NOT use raw div + CSS for layout always use Stack, Grid, TopBar, SideNavigation.',
943
+ "Common app layout patterns for @zvoove/unity-ui: app shells, dashboards, settings pages, master/detail.",
944
+ "TRIGGER when: user is building a page layout, app shell, or multi-section UI in a @zvoove/unity-ui project.",
945
+ "DO NOT use raw div + CSS for layout \u2014 always use Stack, Grid, TopBar, SideNavigation."
984
946
  ].join(String.raw`\n`);
985
-
986
947
  const frontmatter = [
987
- '---',
988
- 'name: unity-ui-layouts',
948
+ "---",
949
+ "name: unity-ui-layouts",
989
950
  `description: "${description}"`,
990
- 'category: layout',
991
- '---',
992
- ].join('\n');
951
+ "category: layout",
952
+ "---"
953
+ ].join("\n");
954
+ return frontmatter + `
993
955
 
994
- return (
995
- frontmatter +
996
- `\n\n# Unity UI — Layout Patterns
956
+ # Unity UI \u2014 Layout Patterns
997
957
 
998
958
  > Use \`Stack\` and \`Grid\` for all layout. Never use raw \`<div style={{ display: 'flex' }}>\`.
999
959
 
@@ -1061,7 +1021,7 @@ export function AppShell({ children }: { children: React.ReactNode }) {
1061
1021
  </Stack>
1062
1022
  <Stack direction="column" gap="md">
1063
1023
  <Card padding="md">
1064
- <Typography variant="title-medium">Aktivität</Typography>
1024
+ <Typography variant="title-medium">Aktivit\xE4t</Typography>
1065
1025
  {/* activity list */}
1066
1026
  </Card>
1067
1027
  </Stack>
@@ -1079,7 +1039,7 @@ export function AppShell({ children }: { children: React.ReactNode }) {
1079
1039
  {/* Left: section label */}
1080
1040
  <Stack direction="column" gap="xs" style={{ minWidth: 200 }}>
1081
1041
  <Typography variant="title-medium">Profil</Typography>
1082
- <Typography variant="body-medium">Persönliche Informationen.</Typography>
1042
+ <Typography variant="body-medium">Pers\xF6nliche Informationen.</Typography>
1083
1043
  </Stack>
1084
1044
 
1085
1045
  {/* Right: fields */}
@@ -1135,7 +1095,7 @@ export function AppShell({ children }: { children: React.ReactNode }) {
1135
1095
  <Card padding="lg">{/* detail content */}</Card>
1136
1096
  ) : (
1137
1097
  <Stack direction="column" align="center" justify="center" style={{ height: '100%' }}>
1138
- <Typography variant="body-medium">Wählen Sie einen Eintrag aus.</Typography>
1098
+ <Typography variant="body-medium">W\xE4hlen Sie einen Eintrag aus.</Typography>
1139
1099
  </Stack>
1140
1100
  )}
1141
1101
  </Stack>
@@ -1188,37 +1148,33 @@ export function AppShell({ children }: { children: React.ReactNode }) {
1188
1148
 
1189
1149
  ## Rules
1190
1150
 
1191
- - Use \`Stack\` and \`Grid\` for ALL layout never \`<div style={{ display: 'flex' }}>\`
1192
- - Use \`TopBar\` + \`SideNavigation\` for app shells never custom nav bars
1193
- - Use \`Card\` for content containers never styled divs
1194
- - Use spacing tokens for gap/padding never arbitrary pixel values (\`gap-lg\` not \`gap-5\`)
1151
+ - Use \`Stack\` and \`Grid\` for ALL layout \u2014 never \`<div style={{ display: 'flex' }}>\`
1152
+ - Use \`TopBar\` + \`SideNavigation\` for app shells \u2014 never custom nav bars
1153
+ - Use \`Card\` for content containers \u2014 never styled divs
1154
+ - Use spacing tokens for gap/padding \u2014 never arbitrary pixel values (\`gap-lg\` not \`gap-5\`)
1195
1155
  - Always make layouts responsive with \`ResponsiveType\` props
1196
- - SideNavigation handles its own responsive collapse do not wrap it in conditional rendering
1197
- `
1198
- );
1156
+ - SideNavigation handles its own responsive collapse \u2014 do not wrap it in conditional rendering
1157
+ `;
1199
1158
  }
1200
-
1201
1159
  function generateDarkModeSkill() {
1202
1160
  const description = [
1203
- 'Dark mode setup and theme toggling for @zvoove/unity-ui projects.',
1204
- 'TRIGGER when: user wants to add dark mode, a theme toggle, or asks how Unity UI dark mode works.',
1205
- 'DO NOT use prefers-color-scheme media queries or className=\\"dark\\" Unity UI uses data-theme=\\"dark\\".',
1161
+ "Dark mode setup and theme toggling for @zvoove/unity-ui projects.",
1162
+ "TRIGGER when: user wants to add dark mode, a theme toggle, or asks how Unity UI dark mode works.",
1163
+ 'DO NOT use prefers-color-scheme media queries or className=\\"dark\\" \u2014 Unity UI uses data-theme=\\"dark\\".'
1206
1164
  ].join(String.raw`\n`);
1207
-
1208
1165
  const frontmatter = [
1209
- '---',
1210
- 'name: unity-ui-dark-mode',
1166
+ "---",
1167
+ "name: unity-ui-dark-mode",
1211
1168
  `description: "${description}"`,
1212
- 'category: theming',
1213
- '---',
1214
- ].join('\n');
1169
+ "category: theming",
1170
+ "---"
1171
+ ].join("\n");
1172
+ return frontmatter + `
1215
1173
 
1216
- return (
1217
- frontmatter +
1218
- `\n\n# Unity UI — Dark Mode
1174
+ # Unity UI \u2014 Dark Mode
1219
1175
 
1220
1176
  > Dark mode is activated by \`data-theme="dark"\` on any ancestor element.
1221
- > All semantic design tokens adapt automatically no per-component changes needed.
1177
+ > All semantic design tokens adapt automatically \u2014 no per-component changes needed.
1222
1178
 
1223
1179
  ## How It Works
1224
1180
 
@@ -1226,7 +1182,7 @@ function generateDarkModeSkill() {
1226
1182
  <!-- Light mode (default) -->
1227
1183
  <div>...</div>
1228
1184
 
1229
- <!-- Dark mode applies to this element and all descendants -->
1185
+ <!-- Dark mode \u2014 applies to this element and all descendants -->
1230
1186
  <div data-theme="dark">...</div>
1231
1187
  \`\`\`
1232
1188
 
@@ -1332,7 +1288,7 @@ Place it in \`TopBar\`'s \`actions\` prop:
1332
1288
 
1333
1289
  ## Token Behaviour in Dark Mode
1334
1290
 
1335
- Semantic tokens adapt automatically no \`dark:\` prefix needed for these:
1291
+ Semantic tokens adapt automatically \u2014 no \`dark:\` prefix needed for these:
1336
1292
 
1337
1293
  | Token | Light | Dark |
1338
1294
  |-------|-------|------|
@@ -1360,68 +1316,57 @@ export const DarkMode: Story = {
1360
1316
  };
1361
1317
  \`\`\`
1362
1318
 
1363
- Or use the Storybook backgrounds addon set the decorator on the global level in \`preview.ts\`.
1319
+ Or use the Storybook backgrounds addon \u2014 set the decorator on the global level in \`preview.ts\`.
1364
1320
 
1365
1321
  ## Rules
1366
1322
 
1367
- - NEVER use \`prefers-color-scheme\` CSS to apply dark mode use \`data-theme="dark"\`
1368
- - NEVER use \`className="dark"\` Unity UI uses the selector strategy, not the class strategy
1369
- - Semantic tokens adapt automatically only add \`dark:\` for custom non-token values
1323
+ - NEVER use \`prefers-color-scheme\` CSS to apply dark mode \u2014 use \`data-theme="dark"\`
1324
+ - NEVER use \`className="dark"\` \u2014 Unity UI uses the selector strategy, not the class strategy
1325
+ - Semantic tokens adapt automatically \u2014 only add \`dark:\` for custom non-token values
1370
1326
  - Persist theme in \`localStorage\` to avoid a flash-of-wrong-theme on reload
1371
1327
  - Do not apply \`data-theme\` to \`<html>\` or \`<body>\` unless your React root is there
1372
- `
1373
- );
1328
+ `;
1374
1329
  }
1375
-
1376
1330
  function generateMigrateShadcnSkill(componentNames) {
1377
1331
  const description = [
1378
- 'Step-by-step guide for migrating a shadcn/ui codebase to @zvoove/unity-ui.',
1379
- 'TRIGGER when: user wants to migrate from shadcn/ui to Unity UI, or is converting shadcn/ui components.',
1380
- 'DO NOT keep shadcn/ui imports alongside Unity UI replace fully.',
1332
+ "Step-by-step guide for migrating a shadcn/ui codebase to @zvoove/unity-ui.",
1333
+ "TRIGGER when: user wants to migrate from shadcn/ui to Unity UI, or is converting shadcn/ui components.",
1334
+ "DO NOT keep shadcn/ui imports alongside Unity UI \u2014 replace fully."
1381
1335
  ].join(String.raw`\n`);
1382
-
1383
1336
  const frontmatter = [
1384
- '---',
1385
- 'name: unity-ui-migrate-shadcn',
1337
+ "---",
1338
+ "name: unity-ui-migrate-shadcn",
1386
1339
  `description: "${description}"`,
1387
- 'category: migration',
1388
- '---',
1389
- ].join('\n');
1390
-
1391
- const componentRows = componentNames
1392
- .filter((n) => SHADCN_MAP[n])
1393
- .map((n) => {
1394
- const s = SHADCN_MAP[n];
1395
- const note = s.note ? ` _(${s.note})_` : '';
1396
- return `| [${s.name}](${s.url}) | \`<${n} />\` | \`unity-ui-${kebabCase(n)}\`${note} |`;
1397
- });
1398
-
1399
- const noEquivalent = componentNames
1400
- .filter((n) => !SHADCN_MAP[n])
1401
- .map(
1402
- (n) => `- **${n}** — load skill \`unity-ui-${kebabCase(n)}\` for usage`
1403
- )
1404
- .join('\n');
1340
+ "category: migration",
1341
+ "---"
1342
+ ].join("\n");
1343
+ const componentRows = componentNames.filter((n) => SHADCN_MAP[n]).map((n) => {
1344
+ const s = SHADCN_MAP[n];
1345
+ const note = s.note ? ` _(${s.note})_` : "";
1346
+ return `| [${s.name}](${s.url}) | \`<${n} />\` | \`unity-ui-${kebabCase(n)}\`${note} |`;
1347
+ });
1348
+ const noEquivalent = componentNames.filter((n) => !SHADCN_MAP[n]).map(
1349
+ (n) => `- **${n}** \u2014 load skill \`unity-ui-${kebabCase(n)}\` for usage`
1350
+ ).join("\n");
1351
+ return frontmatter + `
1405
1352
 
1406
- return (
1407
- frontmatter +
1408
- `\n\n# Migrating from shadcn/ui to Unity UI
1353
+ # Migrating from shadcn/ui to Unity UI
1409
1354
 
1410
1355
  ## Step-by-Step Process
1411
1356
 
1412
- 1. **Install Unity UI** see \`unity-ui-setup\` skill
1413
- 2. **Run a global find** for \`from "@/components/ui/\` and \`from "~/components/ui/\` those are shadcn/ui imports
1414
- 3. **Replace each component** using the table below load the \`unity-ui-<component>\` skill for full props
1415
- 4. **Replace styling** remove Tailwind class-heavy JSX and use Unity UI props instead
1416
- 5. **Remove shadcn/ui** delete the \`components/ui/\` folder and uninstall \`class-variance-authority\`, \`cmdk\`, \`@radix-ui\` etc.
1357
+ 1. **Install Unity UI** \u2014 see \`unity-ui-setup\` skill
1358
+ 2. **Run a global find** for \`from "@/components/ui/\` and \`from "~/components/ui/\` \u2014 those are shadcn/ui imports
1359
+ 3. **Replace each component** using the table below \u2014 load the \`unity-ui-<component>\` skill for full props
1360
+ 4. **Replace styling** \u2014 remove Tailwind class-heavy JSX and use Unity UI props instead
1361
+ 5. **Remove shadcn/ui** \u2014 delete the \`components/ui/\` folder and uninstall \`class-variance-authority\`, \`cmdk\`, \`@radix-ui\` etc.
1417
1362
 
1418
1363
  ## Component Map
1419
1364
 
1420
1365
  | shadcn/ui | Unity UI | Skill |
1421
1366
  |-----------|----------|-------|
1422
- ${componentRows.join('\n')}
1367
+ ${componentRows.join("\n")}
1423
1368
 
1424
- ## Unity UI–Only Components (no shadcn/ui equivalent)
1369
+ ## Unity UI\u2013Only Components (no shadcn/ui equivalent)
1425
1370
 
1426
1371
  ${noEquivalent}
1427
1372
 
@@ -1449,64 +1394,53 @@ rm -rf src/components/ui
1449
1394
 
1450
1395
  ## Rules
1451
1396
 
1452
- - NEVER keep shadcn/ui and Unity UI components side-by-side migrate fully
1397
+ - NEVER keep shadcn/ui and Unity UI components side-by-side \u2014 migrate fully
1453
1398
  - Replace all \`cn()\` usage in component files with \`twMerge()\` from tailwind-merge
1454
- - shadcn/ui uses \`className\` extensively Unity UI uses props (variant, size, etc.); remove the class overrides
1399
+ - shadcn/ui uses \`className\` extensively \u2014 Unity UI uses props (variant, size, etc.); remove the class overrides
1455
1400
  - Import everything from \`@zvoove/unity-ui\`, never from local \`components/ui/\`
1456
- `
1457
- );
1401
+ `;
1458
1402
  }
1459
-
1460
1403
  function generateMigrateMuiSkill(componentNames) {
1461
1404
  const description = [
1462
- 'Step-by-step guide for migrating a Material UI (MUI) codebase to @zvoove/unity-ui.',
1463
- 'TRIGGER when: user wants to migrate from MUI (@mui/material) to Unity UI, or is converting MUI components.',
1464
- 'DO NOT keep MUI imports alongside Unity UI replace fully.',
1405
+ "Step-by-step guide for migrating a Material UI (MUI) codebase to @zvoove/unity-ui.",
1406
+ "TRIGGER when: user wants to migrate from MUI (@mui/material) to Unity UI, or is converting MUI components.",
1407
+ "DO NOT keep MUI imports alongside Unity UI \u2014 replace fully."
1465
1408
  ].join(String.raw`\n`);
1466
-
1467
1409
  const frontmatter = [
1468
- '---',
1469
- 'name: unity-ui-migrate-mui',
1410
+ "---",
1411
+ "name: unity-ui-migrate-mui",
1470
1412
  `description: "${description}"`,
1471
- 'category: migration',
1472
- '---',
1473
- ].join('\n');
1474
-
1475
- const componentRows = componentNames
1476
- .filter((n) => MUI_MAP[n])
1477
- .map((n) => {
1478
- const m = MUI_MAP[n];
1479
- const note = m.note ? ` _(${m.note})_` : '';
1480
- return `| [${m.name}](${m.url}) | \`<${n} />\` | \`unity-ui-${kebabCase(n)}\`${note} |`;
1481
- });
1413
+ "category: migration",
1414
+ "---"
1415
+ ].join("\n");
1416
+ const componentRows = componentNames.filter((n) => MUI_MAP[n]).map((n) => {
1417
+ const m = MUI_MAP[n];
1418
+ const note = m.note ? ` _(${m.note})_` : "";
1419
+ return `| [${m.name}](${m.url}) | \`<${n} />\` | \`unity-ui-${kebabCase(n)}\`${note} |`;
1420
+ });
1421
+ const noEquivalent = componentNames.filter((n) => !MUI_MAP[n]).map(
1422
+ (n) => `- **${n}** \u2014 load skill \`unity-ui-${kebabCase(n)}\` for usage`
1423
+ ).join("\n");
1424
+ return frontmatter + `
1482
1425
 
1483
- const noEquivalent = componentNames
1484
- .filter((n) => !MUI_MAP[n])
1485
- .map(
1486
- (n) => `- **${n}** — load skill \`unity-ui-${kebabCase(n)}\` for usage`
1487
- )
1488
- .join('\n');
1489
-
1490
- return (
1491
- frontmatter +
1492
- `\n\n# Migrating from MUI to Unity UI
1426
+ # Migrating from MUI to Unity UI
1493
1427
 
1494
1428
  ## Step-by-Step Process
1495
1429
 
1496
- 1. **Install Unity UI** see \`unity-ui-setup\` skill
1497
- 2. **Run a global find** for \`from "@mui/material\` and \`from "@mui/x-\` those are MUI imports
1498
- 3. **Replace each component** using the table below load the \`unity-ui-<component>\` skill for full props
1499
- 4. **Replace the sx prop** MUI's \`sx\` system does not exist in Unity UI; use Tailwind tokens instead (load \`unity-ui-styling\`)
1500
- 5. **Remove ThemeProvider** Unity UI uses \`data-theme="dark"\` for dark mode; load \`unity-ui-dark-mode\`
1430
+ 1. **Install Unity UI** \u2014 see \`unity-ui-setup\` skill
1431
+ 2. **Run a global find** for \`from "@mui/material\` and \`from "@mui/x-\` \u2014 those are MUI imports
1432
+ 3. **Replace each component** using the table below \u2014 load the \`unity-ui-<component>\` skill for full props
1433
+ 4. **Replace the sx prop** \u2014 MUI's \`sx\` system does not exist in Unity UI; use Tailwind tokens instead (load \`unity-ui-styling\`)
1434
+ 5. **Remove ThemeProvider** \u2014 Unity UI uses \`data-theme="dark"\` for dark mode; load \`unity-ui-dark-mode\`
1501
1435
  6. **Uninstall MUI** after all components are replaced
1502
1436
 
1503
1437
  ## Component Map
1504
1438
 
1505
1439
  | MUI | Unity UI | Skill |
1506
1440
  |-----|----------|-------|
1507
- ${componentRows.join('\n')}
1441
+ ${componentRows.join("\n")}
1508
1442
 
1509
- ## Unity UI–Only Components (no MUI equivalent)
1443
+ ## Unity UI\u2013Only Components (no MUI equivalent)
1510
1444
 
1511
1445
  ${noEquivalent}
1512
1446
 
@@ -1548,33 +1482,29 @@ npm uninstall @mui/material @mui/x-date-pickers @mui/icons-material @emotion/rea
1548
1482
 
1549
1483
  ## Rules
1550
1484
 
1551
- - NEVER keep MUI and Unity UI components side-by-side migrate fully
1552
- - The \`sx\` prop does not exist in Unity UI use \`className\` with token classes or component props
1553
- - MUI icons do not exist in Unity UI use \`<Icon name="..." />\` (load \`unity-ui-icons\` skill for names)
1485
+ - NEVER keep MUI and Unity UI components side-by-side \u2014 migrate fully
1486
+ - The \`sx\` prop does not exist in Unity UI \u2014 use \`className\` with token classes or component props
1487
+ - MUI icons do not exist in Unity UI \u2014 use \`<Icon name="..." />\` (load \`unity-ui-icons\` skill for names)
1554
1488
  - Remove \`ThemeProvider\` and \`CssBaseline\` from MUI; Unity UI uses CSS custom properties from \`theme.css\`
1555
1489
  - Import everything from \`@zvoove/unity-ui\`
1556
- `
1557
- );
1490
+ `;
1558
1491
  }
1559
-
1560
1492
  function generateFigmaCodeConnectSkill() {
1561
1493
  const description = [
1562
- 'Figma Code Connect setup for @zvoove/unity-ui links Figma components to Unity UI React components.',
1563
- 'TRIGGER when: user wants to set up Figma Code Connect, link design components to code, or improve design-to-code accuracy in a Unity UI project.',
1564
- 'DO NOT use this for general Figma-to-code generation Code Connect is for mapping design components to existing code components.',
1494
+ "Figma Code Connect setup for @zvoove/unity-ui \u2014 links Figma components to Unity UI React components.",
1495
+ "TRIGGER when: user wants to set up Figma Code Connect, link design components to code, or improve design-to-code accuracy in a Unity UI project.",
1496
+ "DO NOT use this for general Figma-to-code generation \u2014 Code Connect is for mapping design components to existing code components."
1565
1497
  ].join(String.raw`\n`);
1566
-
1567
1498
  const frontmatter = [
1568
- '---',
1569
- 'name: unity-ui-figma-code-connect',
1499
+ "---",
1500
+ "name: unity-ui-figma-code-connect",
1570
1501
  `description: "${description}"`,
1571
- 'category: tooling',
1572
- '---',
1573
- ].join('\n');
1502
+ "category: tooling",
1503
+ "---"
1504
+ ].join("\n");
1505
+ return frontmatter + `
1574
1506
 
1575
- return (
1576
- frontmatter +
1577
- `\n\n# Unity UI — Figma Code Connect
1507
+ # Unity UI \u2014 Figma Code Connect
1578
1508
 
1579
1509
  > Code Connect links Figma components to Unity UI React components so that when a designer shares a Figma URL, the AI knows exactly which component and props to use.
1580
1510
 
@@ -1604,8 +1534,8 @@ Create \`figma.config.json\` at the project root:
1604
1534
 
1605
1535
  1. Open the Unity UI Figma design file
1606
1536
  2. Select the component you want to connect
1607
- 3. Copy the URL it contains \`node-id=<nodeId>\`
1608
- 4. Convert \`-\` to \`:\` in the node ID (e.g. \`123-456\` \`123:456\`)
1537
+ 3. Copy the URL \u2014 it contains \`node-id=<nodeId>\`
1538
+ 4. Convert \`-\` to \`:\` in the node ID (e.g. \`123-456\` \u2192 \`123:456\`)
1609
1539
 
1610
1540
  ## Mapping File Structure
1611
1541
 
@@ -1708,42 +1638,35 @@ npx figma connect publish --token $FIGMA_ACCESS_TOKEN
1708
1638
  - Create one \`.figma.tsx\` file per component
1709
1639
  - The Figma URL must point to the **main component** (not an instance or frame)
1710
1640
  - Prop names in \`figma.enum()\` must match Figma's exact property names (case-sensitive)
1711
- - Never commit Figma access tokens use environment variables
1641
+ - Never commit Figma access tokens \u2014 use environment variables
1712
1642
  - After updating, republish with \`npx figma connect publish\`
1713
- `
1714
- );
1643
+ `;
1715
1644
  }
1716
-
1717
1645
  function generateUmbrellaSkill(componentNames) {
1718
1646
  const description = [
1719
- 'Unity UI (@zvoove/unity-ui) component library router. Use this as the entry point when building UI with this package.',
1720
- 'TRIGGER when: user wants to build UI, use a component, or migrate/convert a UI from any source (Lovable, Figma Make, shadcn/ui, MUI, Ant Design, etc.) into this design system.',
1721
- 'DO NOT TRIGGER when: @zvoove/unity-ui is not installed in the project.',
1647
+ "Unity UI (@zvoove/unity-ui) component library router. Use this as the entry point when building UI with this package.",
1648
+ "TRIGGER when: user wants to build UI, use a component, or migrate/convert a UI from any source (Lovable, Figma Make, shadcn/ui, MUI, Ant Design, etc.) into this design system.",
1649
+ "DO NOT TRIGGER when: @zvoove/unity-ui is not installed in the project."
1722
1650
  ].join(String.raw`\n`);
1723
-
1724
- const componentList = componentNames
1725
- .map((n) => `- ${n} → load skill \`unity-ui-${kebabCase(n)}\``)
1726
- .join('\n');
1727
-
1651
+ const componentList = componentNames.map((n) => `- ${n} \u2192 load skill \`unity-ui-${kebabCase(n)}\``).join("\n");
1728
1652
  const frontmatter = [
1729
- '---',
1730
- 'name: unity-ui',
1653
+ "---",
1654
+ "name: unity-ui",
1731
1655
  `description: "${description}"`,
1732
- 'category: routing',
1733
- '---',
1734
- ].join('\n');
1656
+ "category: routing",
1657
+ "---"
1658
+ ].join("\n");
1659
+ return frontmatter + `
1735
1660
 
1736
- return (
1737
- frontmatter +
1738
- `\n\n# Unity UI — Component Router
1661
+ # Unity UI \u2014 Component Router
1739
1662
 
1740
- > **@zvoove/unity-ui** is installed in this project. Use the skills below do NOT read \`dist/\`, \`node_modules/\`, or source files for API documentation.
1663
+ > **@zvoove/unity-ui** is installed in this project. Use the skills below \u2014 do NOT read \`dist/\`, \`node_modules/\`, or source files for API documentation.
1741
1664
 
1742
1665
  ## How to Use
1743
1666
 
1744
1667
  1. Find the component you need in the directory below
1745
1668
  2. Load its \`unity-ui-<component>\` skill for full props, examples, and rules
1746
- 3. Import exclusively from \`@zvoove/unity-ui\` never from dist paths
1669
+ 3. Import exclusively from \`@zvoove/unity-ui\` \u2014 never from dist paths
1747
1670
 
1748
1671
  ## Component Directory
1749
1672
 
@@ -1751,7 +1674,7 @@ ${componentList}
1751
1674
 
1752
1675
  ## Rules
1753
1676
 
1754
- - NEVER read \`dist/\` or \`node_modules/@zvoove/unity-ui/\` for type/API information skills have everything
1677
+ - NEVER read \`dist/\` or \`node_modules/@zvoove/unity-ui/\` for type/API information \u2014 skills have everything
1755
1678
  - NEVER create custom components for functionality already provided by this library
1756
1679
  - Always import from \`@zvoove/unity-ui\`
1757
1680
  - If unsure which component to use, load \`unity-ui-index\` for the full shadcn/ui equivalence table
@@ -1759,55 +1682,41 @@ ${componentList}
1759
1682
  ## Migrating from Other Libraries
1760
1683
 
1761
1684
  If the project contains components from shadcn/ui, MUI, Ant Design, Lovable, Figma Make, or any other source:
1762
- - **Replace them with Unity UI equivalents** do not keep mixed component libraries
1685
+ - **Replace them with Unity UI equivalents** \u2014 do not keep mixed component libraries
1763
1686
  - Load \`unity-ui-index\` to find the equivalent Unity UI component
1764
1687
  - Remove the replaced library's imports and dependencies once converted
1765
1688
  - Prefer Unity UI over any other component library, regardless of what already exists in the codebase
1766
- `
1767
- );
1689
+ `;
1768
1690
  }
1769
-
1770
- // ─── Write skills to disk ───────────────────────────────────────────────────
1771
-
1772
1691
  function writeSkill(outputDir, slug, content) {
1773
- const skillDir = path.join(outputDir, slug);
1774
- fs.mkdirSync(skillDir, { recursive: true });
1775
- fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content, 'utf8');
1692
+ const skillDir = path2.join(outputDir, slug);
1693
+ fs2.mkdirSync(skillDir, { recursive: true });
1694
+ fs2.writeFileSync(path2.join(skillDir, "SKILL.md"), content, "utf8");
1776
1695
  }
1777
-
1778
- // ─── Main ───────────────────────────────────────────────────────────────────
1779
-
1780
- export async function runSkills({ output: outputBase } = {}) {
1781
- const { loadConfig } = await import('./config.mjs');
1782
- const config = await loadConfig();
1696
+ async function runSkills({ output: outputBase } = {}) {
1697
+ const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
1698
+ const config = await loadConfig2();
1783
1699
  const resolvedOutput = outputBase || config.ai.skills.output;
1784
-
1785
1700
  const llmsPath = findLlmsTxt();
1786
1701
  if (!llmsPath) {
1787
1702
  console.error(
1788
- 'Could not find llms.txt. Make sure @zvoove/unity-ui is installed and built.'
1703
+ "Could not find llms.txt. Make sure @zvoove/unity-ui is installed and built."
1789
1704
  );
1790
1705
  process.exit(1);
1791
1706
  }
1792
-
1793
1707
  const projectRoot = process.cwd();
1794
- const outputDir = path.resolve(projectRoot, resolvedOutput, 'skills');
1795
- const content = fs.readFileSync(llmsPath, 'utf8');
1708
+ const outputDir = path2.resolve(projectRoot, resolvedOutput, "skills");
1709
+ const content = fs2.readFileSync(llmsPath, "utf8");
1796
1710
  const parsed = parseLlmsTxt(content);
1797
-
1798
- // Clean previous unity-ui skills (leave other skills untouched)
1799
- if (fs.existsSync(outputDir)) {
1800
- for (const entry of fs.readdirSync(outputDir)) {
1801
- if (entry.startsWith('unity-ui-')) {
1802
- fs.rmSync(path.join(outputDir, entry), { recursive: true });
1711
+ if (fs2.existsSync(outputDir)) {
1712
+ for (const entry of fs2.readdirSync(outputDir)) {
1713
+ if (entry.startsWith("unity-ui-")) {
1714
+ fs2.rmSync(path2.join(outputDir, entry), { recursive: true });
1803
1715
  }
1804
1716
  }
1805
1717
  }
1806
-
1807
1718
  const componentNames = Object.keys(parsed.components).sort();
1808
1719
  let count = 0;
1809
-
1810
- // Component skills
1811
1720
  for (const [name, componentContent] of Object.entries(parsed.components)) {
1812
1721
  writeSkill(
1813
1722
  outputDir,
@@ -1816,41 +1725,41 @@ export async function runSkills({ output: outputBase } = {}) {
1816
1725
  );
1817
1726
  count++;
1818
1727
  }
1819
-
1820
- // Meta skills
1821
- writeSkill(outputDir, 'unity-ui', generateUmbrellaSkill(componentNames));
1822
- writeSkill(outputDir, 'unity-ui-setup', generateSetupSkill(parsed));
1823
- writeSkill(outputDir, 'unity-ui-styling', generateStylingSkill(parsed));
1728
+ writeSkill(outputDir, "unity-ui", generateUmbrellaSkill(componentNames));
1729
+ writeSkill(outputDir, "unity-ui-setup", generateSetupSkill(parsed));
1730
+ writeSkill(outputDir, "unity-ui-styling", generateStylingSkill(parsed));
1824
1731
  writeSkill(
1825
1732
  outputDir,
1826
- 'unity-ui-custom-component',
1733
+ "unity-ui-custom-component",
1827
1734
  generateCustomComponentSkill(parsed)
1828
1735
  );
1829
- writeSkill(outputDir, 'unity-ui-icons', generateIconsSkill(parsed));
1830
- writeSkill(outputDir, 'unity-ui-index', generateIndexSkill(componentNames));
1831
- writeSkill(outputDir, 'unity-ui-forms', generateFormsSkill());
1832
- writeSkill(outputDir, 'unity-ui-layouts', generateLayoutsSkill());
1833
- writeSkill(outputDir, 'unity-ui-dark-mode', generateDarkModeSkill());
1736
+ writeSkill(outputDir, "unity-ui-icons", generateIconsSkill(parsed));
1737
+ writeSkill(outputDir, "unity-ui-index", generateIndexSkill(componentNames));
1738
+ writeSkill(outputDir, "unity-ui-forms", generateFormsSkill());
1739
+ writeSkill(outputDir, "unity-ui-layouts", generateLayoutsSkill());
1740
+ writeSkill(outputDir, "unity-ui-dark-mode", generateDarkModeSkill());
1834
1741
  writeSkill(
1835
1742
  outputDir,
1836
- 'unity-ui-migrate-shadcn',
1743
+ "unity-ui-migrate-shadcn",
1837
1744
  generateMigrateShadcnSkill(componentNames)
1838
1745
  );
1839
1746
  writeSkill(
1840
1747
  outputDir,
1841
- 'unity-ui-migrate-mui',
1748
+ "unity-ui-migrate-mui",
1842
1749
  generateMigrateMuiSkill(componentNames)
1843
1750
  );
1844
1751
  writeSkill(
1845
1752
  outputDir,
1846
- 'unity-ui-figma-code-connect',
1753
+ "unity-ui-figma-code-connect",
1847
1754
  generateFigmaCodeConnectSkill()
1848
1755
  );
1849
1756
  count += 12;
1850
-
1851
- const relOutput = path.relative(projectRoot, outputDir);
1852
- console.log(`\n Unity UI Agent Skills Generator\n`);
1853
- console.log(` ✅ Generated ${count} skills in ${relOutput}/\n`);
1757
+ const relOutput = path2.relative(projectRoot, outputDir);
1758
+ console.log(`
1759
+ Unity UI \u2014 Agent Skills Generator
1760
+ `);
1761
+ console.log(` \u2705 Generated ${count} skills in ${relOutput}/
1762
+ `);
1854
1763
  console.log(` ${componentNames.length} component skills`);
1855
1764
  console.log(` 1 umbrella routing skill (entry point + migration rules)`);
1856
1765
  console.log(` 1 setup skill (installation, spacing, responsive props)`);
@@ -1872,12 +1781,36 @@ export async function runSkills({ output: outputBase } = {}) {
1872
1781
  ` 1 dark mode skill (data-theme, ThemeProvider, token behaviour)`
1873
1782
  );
1874
1783
  console.log(
1875
- ` 1 migrate-shadcn skill (step-by-step shadcn/ui Unity UI)`
1784
+ ` 1 migrate-shadcn skill (step-by-step shadcn/ui \u2192 Unity UI)`
1876
1785
  );
1877
- console.log(` 1 migrate-mui skill (step-by-step MUI Unity UI)`);
1786
+ console.log(` 1 migrate-mui skill (step-by-step MUI \u2192 Unity UI)`);
1878
1787
  console.log(
1879
- ` 1 figma-code-connect skill (Code Connect setup and mappings)\n`
1788
+ ` 1 figma-code-connect skill (Code Connect setup and mappings)
1789
+ `
1880
1790
  );
1881
1791
  console.log(` Your AI agent can now discover and use Unity UI components.`);
1882
- console.log(` Skills are loaded on-demand only relevant ones are read.\n`);
1792
+ console.log(` Skills are loaded on-demand \u2014 only relevant ones are read.
1793
+ `);
1794
+ }
1795
+
1796
+ // bin/generate-skills.mjs
1797
+ console.warn(
1798
+ '\x1B[33m\u26A0\uFE0F "unity-ui-skills" is deprecated. Use "npx unity-ui skills" instead.\x1B[0m\n'
1799
+ );
1800
+ var args = process.argv.slice(2);
1801
+ var output = ".claude";
1802
+ for (let i = 0; i < args.length; i++) {
1803
+ if ((args[i] === "--output" || args[i] === "-o") && args[i + 1]) {
1804
+ output = args[i + 1];
1805
+ i++;
1806
+ }
1807
+ if (args[i] === "--help" || args[i] === "-h") {
1808
+ console.log(`Usage: npx unity-ui skills [options]
1809
+
1810
+ This command has moved. Please use:
1811
+ npx unity-ui skills [-o <dir>]
1812
+ `);
1813
+ process.exit(0);
1814
+ }
1883
1815
  }
1816
+ runSkills({ output });