@fr0mpy/component-system 2.2.0 → 3.1.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 (51) hide show
  1. package/README.md +86 -27
  2. package/bin/cli.js +155 -62
  3. package/bin/validate-compliance.js +447 -0
  4. package/bin/validate-config.js +175 -0
  5. package/index.js +15 -0
  6. package/package.json +6 -4
  7. package/templates/agents/component-auditor.md +77 -0
  8. package/templates/agents/design-token-validator.md +72 -0
  9. package/templates/agents/harness-scaffolder.md +146 -0
  10. package/templates/agents/playwright-tester.md +437 -0
  11. package/templates/agents/style-inspector.md +81 -0
  12. package/templates/commands/component-harness.md +104 -10
  13. package/templates/commands/retheme.md +142 -0
  14. package/templates/commands/save-theme.md +50 -0
  15. package/templates/commands/setup-styling.md +386 -57
  16. package/templates/component-recipes/accordion.md +9 -9
  17. package/templates/component-recipes/alert.md +36 -23
  18. package/templates/component-recipes/avatar.md +14 -12
  19. package/templates/component-recipes/badge.md +9 -6
  20. package/templates/component-recipes/breadcrumb.md +4 -4
  21. package/templates/component-recipes/button.md +2 -2
  22. package/templates/component-recipes/checkbox.md +5 -5
  23. package/templates/component-recipes/collapsible.md +13 -13
  24. package/templates/component-recipes/combobox.md +2 -2
  25. package/templates/component-recipes/context-menu.md +11 -11
  26. package/templates/component-recipes/dialog.md +16 -16
  27. package/templates/component-recipes/drawer.md +18 -18
  28. package/templates/component-recipes/dropdown-menu.md +12 -12
  29. package/templates/component-recipes/hover-card.md +11 -11
  30. package/templates/component-recipes/label.md +4 -4
  31. package/templates/component-recipes/modal.md +9 -9
  32. package/templates/component-recipes/navigation-menu.md +19 -19
  33. package/templates/component-recipes/popover.md +10 -10
  34. package/templates/component-recipes/progress.md +10 -8
  35. package/templates/component-recipes/radio.md +6 -6
  36. package/templates/component-recipes/select.md +5 -5
  37. package/templates/component-recipes/separator.md +2 -2
  38. package/templates/component-recipes/slider.md +2 -2
  39. package/templates/component-recipes/switch.md +6 -6
  40. package/templates/component-recipes/table.md +1 -1
  41. package/templates/component-recipes/tabs.md +6 -6
  42. package/templates/component-recipes/toast.md +56 -42
  43. package/templates/component-recipes/toggle-group.md +4 -4
  44. package/templates/component-recipes/tooltip.md +5 -5
  45. package/templates/mcp/mcp.json +8 -0
  46. package/templates/playwright/playwright.config.ts +31 -0
  47. package/templates/playwright/tests/components.spec.ts +104 -0
  48. package/templates/skills/react-patterns.md +4 -0
  49. package/templates/skills/styling.md +141 -52
  50. package/templates/hooks/triggers.d/react-patterns.json +0 -18
  51. package/templates/hooks/triggers.d/styling.json +0 -23
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @fr0mpy/component-system
2
2
 
3
- Claude Code UI styling system with design tokens, 36 component recipes, and visual preview harness.
3
+ Claude Code UI styling system with multi-theme support, design tokens, component agents, 40 Base UI recipes, and Playwright testing.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,36 +10,92 @@ npx @fr0mpy/component-system
10
10
 
11
11
  ## What's Included
12
12
 
13
- - **skills/** - Styling skill for consistent UI generation
14
- - **component-recipes/** - 36 pre-built component templates (button, card, modal, toast, etc.)
15
- - **commands/** - `/setup-styling` and `/component-harness`
13
+ | Directory | Purpose |
14
+ |-----------|---------|
15
+ | `skills/` | Styling + React patterns skills |
16
+ | `agents/` | 5 component system agents |
17
+ | `component-recipes/` | 40 Base UI component templates |
18
+ | `playwright-templates/` | Playwright test config + component specs |
19
+ | `commands/` | `/setup-styling`, `/component-harness`, `/save-theme`, `/retheme` |
20
+ | `.mcp.json` | Playwright MCP server configuration |
16
21
 
17
- ## Features
22
+ ## Multi-Theme System
18
23
 
19
- ### Design Tokens
24
+ Create and switch between multiple themes in real-time:
20
25
 
21
- Run `/setup-styling` to configure your design system interactively. Generates `styling-config.json` with:
26
+ ```
27
+ .claude/
28
+ ├── styling-config.json # Active theme config
29
+ ├── themes/ # Saved themes
30
+ │ ├── stripe-inspired.json
31
+ │ ├── matrix.json
32
+ │ └── vercel-dark.json
33
+ └── component-recipes/ # Component templates
34
+ ```
35
+
36
+ ### Workflow
37
+
38
+ 1. **Create themes** via `/setup-styling`:
39
+ - Extract from URL (analyzes any website's design system)
40
+ - Manual configuration (answer questions about colors, typography)
41
+ - Saves to both `styling-config.json` and `themes/{name}.json`
42
+
43
+ 2. **Switch themes** in the component harness:
44
+ - ThemeSwitcher dropdown loads all `.claude/themes/*.json`
45
+ - Live switching via CSS variable injection
46
+ - No page reload required
47
+
48
+ 3. **Quick commands**:
49
+ - `/save-theme [name]` - Save current config as a named theme
50
+ - `/retheme` - Regenerate CSS from current config
51
+
52
+ ## Commands
53
+
54
+ | Command | Purpose |
55
+ |---------|---------|
56
+ | `/setup-styling` | Configure design tokens, creates theme |
57
+ | `/component-harness` | Launch visual preview with theme switcher |
58
+ | `/save-theme` | Save current config as named theme |
59
+ | `/retheme` | Regenerate harness CSS from config |
60
+
61
+ ## Agents (5)
62
+
63
+ | Agent | Purpose |
64
+ |-------|---------|
65
+ | style-inspector | Reverse-engineers website design systems from URLs |
66
+ | design-token-validator | Audits components for token compliance |
67
+ | component-auditor | Validates recipe compliance, a11y, React patterns |
68
+ | harness-scaffolder | Scaffolds Vite preview gallery from recipes |
69
+ | playwright-tester | Tests components via Playwright MCP with Axe a11y |
70
+
71
+ ## Skills (2)
72
+
73
+ | Skill | Purpose |
74
+ |-------|---------|
75
+ | styling | Enforces design token usage, mobile-first patterns, recipe compliance |
76
+ | react-patterns | Enforces Rules of Hooks and correct state/effect patterns |
22
77
 
23
- - Colors (primary, secondary, destructive, muted, etc.)
24
- - Border radius
25
- - Shadows
26
- - Spacing
27
- - Typography
78
+ ## Component Recipes (40)
28
79
 
29
- ### Component Recipes
80
+ | Category | Components |
81
+ |----------|------------|
82
+ | **Form (10)** | button, input, textarea, select, combobox, checkbox, radio, switch, slider, label |
83
+ | **Layout (6)** | card, separator, collapsible, accordion, tabs, table |
84
+ | **Navigation (5)** | navigation-menu, breadcrumb, pagination, dropdown-menu, context-menu |
85
+ | **Overlay (6)** | modal, dialog, drawer, popover, hover-card, tooltip |
86
+ | **Feedback (5)** | alert, toast, progress, skeleton, spinner |
87
+ | **Display (4)** | badge, avatar, carousel, toggle-group |
30
88
 
31
- 36 component recipes organized by category:
89
+ All recipes use [Base UI](https://base-ui.com) headless primitives for accessibility with Tailwind CSS styling.
32
90
 
33
- - **Form** (10): button, input, textarea, select, combobox, checkbox, radio, switch, slider, label
34
- - **Layout** (6): card, separator, collapsible, accordion, tabs, table
35
- - **Navigation** (5): navigation-menu, breadcrumb, pagination, dropdown-menu, context-menu
36
- - **Overlay** (6): modal, dialog, drawer, popover, hover-card, tooltip
37
- - **Feedback** (5): alert, toast, progress, skeleton, spinner
38
- - **Display** (4): badge, avatar, carousel, toggle-group
91
+ ## Component Harness
39
92
 
40
- ### Component Harness
93
+ Run `/component-harness` to scaffold a Vite + React preview environment:
41
94
 
42
- Run `/component-harness` to scaffold a Vite + React development environment for visual component preview.
95
+ - **Theme Switcher** - Dropdown to switch between saved themes
96
+ - **Live Preview** - All 40 components with variants
97
+ - **Instant Updates** - CSS variable injection, no page reload
98
+ - **Playwright Testing** - Visual + accessibility testing via MCP
43
99
 
44
100
  ## Usage
45
101
 
@@ -47,13 +103,14 @@ Run `/component-harness` to scaffold a Vite + React development environment for
47
103
  # Initialize
48
104
  npx @fr0mpy/component-system
49
105
 
50
- # With options
106
+ # Options
51
107
  npx @fr0mpy/component-system --force # Overwrite existing
52
108
  npx @fr0mpy/component-system --merge # Add to existing .claude
53
109
  npx @fr0mpy/component-system --remove # Remove installation
54
110
 
55
111
  # Selective updates
56
112
  npx @fr0mpy/component-system --update-skills
113
+ npx @fr0mpy/component-system --update-agents
57
114
  npx @fr0mpy/component-system --update-recipes
58
115
  npx @fr0mpy/component-system --update-commands
59
116
  ```
@@ -61,18 +118,20 @@ npx @fr0mpy/component-system --update-commands
61
118
  ## Getting Started
62
119
 
63
120
  1. Install: `npx @fr0mpy/component-system`
64
- 2. Configure: Use `/setup-styling` to set up your design tokens
65
- 3. Preview: Use `/component-harness` to launch visual preview
121
+ 2. Configure: `/setup-styling` to create your first theme
122
+ 3. Preview: `/component-harness` to launch visual gallery
123
+ 4. Add themes: Run `/setup-styling` again to create more themes
124
+ 5. Switch: Use the ThemeSwitcher dropdown in the harness
66
125
 
67
126
  ## Integration with Prompt System
68
127
 
69
- For auto-triggering styling rules when you mention UI/styling keywords, also install:
128
+ For additional agents and context management:
70
129
 
71
130
  ```bash
72
131
  npx @fr0mpy/prompt-system
73
132
  ```
74
133
 
75
- When both packages are installed, the component system injects a `styling.json` trigger into the prompt system's `triggers.d/` directory.
134
+ Skills are automatically discovered via their `USE WHEN` descriptions in YAML frontmatter.
76
135
 
77
136
  ## License
78
137
 
package/bin/cli.js CHANGED
@@ -5,6 +5,7 @@ const path = require('path');
5
5
 
6
6
  const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
7
7
  const TARGET_DIR = path.join(process.cwd(), '.claude');
8
+ const PROJECT_ROOT = process.cwd();
8
9
  const args = process.argv.slice(2);
9
10
 
10
11
  // Parse flags
@@ -16,7 +17,8 @@ const helpMode = hasFlag('--help', '-h');
16
17
  const updateSkills = hasFlag('--update-skills');
17
18
  const updateRecipes = hasFlag('--update-recipes');
18
19
  const updateCommands = hasFlag('--update-commands');
19
- const updateMode = updateSkills || updateRecipes || updateCommands;
20
+ const updateAgents = hasFlag('--update-agents');
21
+ const updateMode = updateSkills || updateRecipes || updateCommands || updateAgents;
20
22
 
21
23
  function copyDir(src, dest) {
22
24
  fs.mkdirSync(dest, { recursive: true });
@@ -52,37 +54,20 @@ function copySubdir(subdir) {
52
54
  return true;
53
55
  }
54
56
 
55
- function injectTriggers() {
56
- const triggersDDir = path.join(TARGET_DIR, 'hooks', 'triggers.d');
57
- if (!fs.existsSync(triggersDDir)) return false;
58
-
59
- const triggers = ['styling.json', 'react-patterns.json'];
60
- let injected = false;
61
-
62
- for (const trigger of triggers) {
63
- const src = path.join(TEMPLATES_DIR, 'hooks', 'triggers.d', trigger);
64
- const dest = path.join(triggersDDir, trigger);
65
- if (fs.existsSync(src)) {
66
- fs.copyFileSync(src, dest);
67
- injected = true;
68
- }
57
+ function mergeJsonFile(src, dest) {
58
+ if (!fs.existsSync(src)) return false;
59
+ const srcData = JSON.parse(fs.readFileSync(src, 'utf8'));
60
+ let destData = {};
61
+ if (fs.existsSync(dest)) {
62
+ try { destData = JSON.parse(fs.readFileSync(dest, 'utf8')); } catch (e) { /* invalid JSON */ }
69
63
  }
70
- return injected;
71
- }
72
-
73
- function removeTriggers() {
74
- const triggersDDir = path.join(TARGET_DIR, 'hooks', 'triggers.d');
75
- const triggers = ['styling.json', 'react-patterns.json'];
76
- let removed = false;
77
-
78
- for (const trigger of triggers) {
79
- const triggerPath = path.join(triggersDDir, trigger);
80
- if (fs.existsSync(triggerPath)) {
81
- fs.unlinkSync(triggerPath);
82
- removed = true;
83
- }
64
+ const merged = { ...destData, ...srcData };
65
+ // Deep merge mcpServers if both exist
66
+ if (destData.mcpServers && srcData.mcpServers) {
67
+ merged.mcpServers = { ...destData.mcpServers, ...srcData.mcpServers };
84
68
  }
85
- return removed;
69
+ fs.writeFileSync(dest, JSON.stringify(merged, null, 2) + '\n');
70
+ return true;
86
71
  }
87
72
 
88
73
  async function init() {
@@ -95,7 +80,7 @@ async function init() {
95
80
  if (componentSystemExists && !forceMode && !mergeMode) {
96
81
  console.log('⚠️ Component system already exists in .claude/');
97
82
  console.log(' Use --force to overwrite, --merge to update, or use selective updates:');
98
- console.log(' --update-skills, --update-recipes, --update-commands\n');
83
+ console.log(' --update-skills, --update-recipes, --update-commands, --update-agents\n');
99
84
  process.exit(1);
100
85
  }
101
86
 
@@ -108,14 +93,39 @@ async function init() {
108
93
  fs.mkdirSync(TARGET_DIR, { recursive: true });
109
94
 
110
95
  if (forceMode && componentSystemExists) {
111
- // Only remove component-system specific dirs
112
- const componentDirs = ['skills', 'component-recipes'];
113
- for (const dir of componentDirs) {
114
- const dirPath = path.join(TARGET_DIR, dir);
115
- if (fs.existsSync(dirPath)) {
116
- fs.rmSync(dirPath, { recursive: true });
96
+ // Remove component-system specific skill files (preserve prompt-system skills)
97
+ const componentSkills = ['styling.md', 'react-patterns.md', 'style-inspector.md'];
98
+ const skillsDir = path.join(TARGET_DIR, 'skills');
99
+ if (fs.existsSync(skillsDir)) {
100
+ for (const skill of componentSkills) {
101
+ const skillPath = path.join(skillsDir, skill);
102
+ if (fs.existsSync(skillPath)) {
103
+ fs.unlinkSync(skillPath);
104
+ }
105
+ }
106
+ }
107
+
108
+ // Remove component-system specific agent files
109
+ const componentAgents = [
110
+ 'style-inspector.md', 'design-token-validator.md',
111
+ 'component-auditor.md', 'harness-scaffolder.md', 'playwright-tester.md'
112
+ ];
113
+ const agentsDir = path.join(TARGET_DIR, 'agents');
114
+ if (fs.existsSync(agentsDir)) {
115
+ for (const agent of componentAgents) {
116
+ const agentPath = path.join(agentsDir, agent);
117
+ if (fs.existsSync(agentPath)) {
118
+ fs.unlinkSync(agentPath);
119
+ }
117
120
  }
118
121
  }
122
+
123
+ // Remove component-recipes entirely (owned by component-system)
124
+ const recipesDir = path.join(TARGET_DIR, 'component-recipes');
125
+ if (fs.existsSync(recipesDir)) {
126
+ fs.rmSync(recipesDir, { recursive: true });
127
+ }
128
+
119
129
  console.log('🗑️ Removed existing component system files.\n');
120
130
  }
121
131
 
@@ -123,6 +133,20 @@ async function init() {
123
133
  copyDir(path.join(TEMPLATES_DIR, 'skills'), path.join(TARGET_DIR, 'skills'));
124
134
  copyDir(path.join(TEMPLATES_DIR, 'component-recipes'), path.join(TARGET_DIR, 'component-recipes'));
125
135
 
136
+ // Copy agents (merge into existing agents dir if prompt-system is installed)
137
+ const agentsDir = path.join(TARGET_DIR, 'agents');
138
+ fs.mkdirSync(agentsDir, { recursive: true });
139
+ copyDir(path.join(TEMPLATES_DIR, 'agents'), agentsDir);
140
+
141
+ // Migrate: remove style-inspector from skills if it exists (now an agent)
142
+ const oldStyleInspector = path.join(TARGET_DIR, 'skills', 'style-inspector.md');
143
+ if (fs.existsSync(oldStyleInspector)) {
144
+ fs.unlinkSync(oldStyleInspector);
145
+ }
146
+
147
+ // Copy Playwright templates (staged for harness scaffolding)
148
+ copyDir(path.join(TEMPLATES_DIR, 'playwright'), path.join(TARGET_DIR, 'playwright-templates'));
149
+
126
150
  // Copy styling commands
127
151
  const commandsDir = path.join(TARGET_DIR, 'commands');
128
152
  fs.mkdirSync(commandsDir, { recursive: true });
@@ -135,21 +159,24 @@ async function init() {
135
159
  path.join(commandsDir, 'component-harness.md')
136
160
  );
137
161
 
162
+ // Merge MCP configuration into project .mcp.json
163
+ const mcpSrc = path.join(TEMPLATES_DIR, 'mcp', 'mcp.json');
164
+ const mcpDest = path.join(PROJECT_ROOT, '.mcp.json');
165
+ if (mergeJsonFile(mcpSrc, mcpDest)) {
166
+ console.log('✅ Configured Playwright MCP server in .mcp.json');
167
+ }
168
+
138
169
  console.log('✅ Created component system files:');
139
- console.log(' 📁 skills/ - Styling skill for UI generation');
140
- console.log(' 📁 component-recipes/ - 36 component templates');
170
+ console.log(' 📁 skills/ - Styling + React patterns skills');
171
+ console.log(' 📁 agents/ - 5 component system agents');
172
+ console.log(' 📁 component-recipes/ - 38 component templates');
173
+ console.log(' 📁 playwright-templates/ - Playwright test config + specs');
141
174
  console.log(' 📄 commands/setup-styling.md');
142
175
  console.log(' 📄 commands/component-harness.md\n');
143
176
 
144
- // Inject triggers if prompt-system is installed
145
- if (promptSystemExists) {
146
- if (injectTriggers()) {
147
- console.log('✅ Injected triggers into prompt system.');
148
- console.log(' Styling and React patterns will auto-trigger on relevant prompts.\n');
149
- }
150
- } else {
151
- console.log('ℹ️ Prompt system not detected.');
152
- console.log(' For auto-triggering styling rules, also install:');
177
+ // Suggest prompt-system if not installed
178
+ if (!promptSystemExists) {
179
+ console.log('💡 For agents and prompt management, also install:');
153
180
  console.log(' npx @fr0mpy/prompt-system\n');
154
181
  }
155
182
 
@@ -166,8 +193,21 @@ async function update() {
166
193
 
167
194
  const updates = [];
168
195
 
169
- if (updateSkills && copySubdir('skills')) updates.push('skills');
196
+ if (updateSkills && copySubdir('skills')) {
197
+ // Migrate: remove style-inspector from skills if it exists
198
+ const oldStyleInspector = path.join(TARGET_DIR, 'skills', 'style-inspector.md');
199
+ if (fs.existsSync(oldStyleInspector)) {
200
+ fs.unlinkSync(oldStyleInspector);
201
+ }
202
+ updates.push('skills');
203
+ }
170
204
  if (updateRecipes && copySubdir('component-recipes')) updates.push('component-recipes');
205
+ if (updateAgents) {
206
+ const agentsDir = path.join(TARGET_DIR, 'agents');
207
+ fs.mkdirSync(agentsDir, { recursive: true });
208
+ copyDir(path.join(TEMPLATES_DIR, 'agents'), agentsDir);
209
+ updates.push('agents');
210
+ }
171
211
  if (updateCommands) {
172
212
  const commandsDir = path.join(TARGET_DIR, 'commands');
173
213
  fs.mkdirSync(commandsDir, { recursive: true });
@@ -198,16 +238,47 @@ function remove() {
198
238
  // Check if prompt-system exists - if so, only remove component-system files
199
239
  const hasHooks = fs.existsSync(path.join(TARGET_DIR, 'hooks'));
200
240
 
201
- const componentDirs = ['skills', 'component-recipes'];
241
+ const componentSkills = ['styling.md', 'react-patterns.md', 'style-inspector.md'];
242
+ const componentAgents = [
243
+ 'style-inspector.md', 'design-token-validator.md',
244
+ 'component-auditor.md', 'harness-scaffolder.md', 'playwright-tester.md'
245
+ ];
202
246
  const componentCommands = ['setup-styling.md', 'component-harness.md'];
203
247
 
204
- for (const dir of componentDirs) {
205
- const dirPath = path.join(TARGET_DIR, dir);
206
- if (fs.existsSync(dirPath)) {
207
- fs.rmSync(dirPath, { recursive: true });
248
+ // Remove component-system specific skill files (preserve prompt-system skills)
249
+ const skillsDir = path.join(TARGET_DIR, 'skills');
250
+ if (fs.existsSync(skillsDir)) {
251
+ for (const skill of componentSkills) {
252
+ const skillPath = path.join(skillsDir, skill);
253
+ if (fs.existsSync(skillPath)) {
254
+ fs.unlinkSync(skillPath);
255
+ }
208
256
  }
209
257
  }
210
258
 
259
+ // Remove component-system specific agent files (preserve prompt-system agents)
260
+ const agentsDir = path.join(TARGET_DIR, 'agents');
261
+ if (fs.existsSync(agentsDir)) {
262
+ for (const agent of componentAgents) {
263
+ const agentPath = path.join(agentsDir, agent);
264
+ if (fs.existsSync(agentPath)) {
265
+ fs.unlinkSync(agentPath);
266
+ }
267
+ }
268
+ }
269
+
270
+ // Remove component-recipes entirely (owned by component-system)
271
+ const recipesDir = path.join(TARGET_DIR, 'component-recipes');
272
+ if (fs.existsSync(recipesDir)) {
273
+ fs.rmSync(recipesDir, { recursive: true });
274
+ }
275
+
276
+ // Remove playwright-templates (owned by component-system)
277
+ const playwrightDir = path.join(TARGET_DIR, 'playwright-templates');
278
+ if (fs.existsSync(playwrightDir)) {
279
+ fs.rmSync(playwrightDir, { recursive: true });
280
+ }
281
+
211
282
  // Remove styling commands
212
283
  const commandsDir = path.join(TARGET_DIR, 'commands');
213
284
  if (fs.existsSync(commandsDir)) {
@@ -219,15 +290,31 @@ function remove() {
219
290
  }
220
291
  }
221
292
 
222
- // Remove triggers
223
- removeTriggers();
224
-
225
293
  // Remove styling-config.json if it exists
226
294
  const stylingConfig = path.join(TARGET_DIR, 'styling-config.json');
227
295
  if (fs.existsSync(stylingConfig)) {
228
296
  fs.unlinkSync(stylingConfig);
229
297
  }
230
298
 
299
+ // Clean up Playwright MCP config from .mcp.json
300
+ const mcpPath = path.join(PROJECT_ROOT, '.mcp.json');
301
+ if (fs.existsSync(mcpPath)) {
302
+ try {
303
+ const mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
304
+ if (mcpConfig.mcpServers?.playwright) {
305
+ delete mcpConfig.mcpServers.playwright;
306
+ if (Object.keys(mcpConfig.mcpServers).length === 0) {
307
+ delete mcpConfig.mcpServers;
308
+ }
309
+ if (Object.keys(mcpConfig).length === 0) {
310
+ fs.unlinkSync(mcpPath);
311
+ } else {
312
+ fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2) + '\n');
313
+ }
314
+ }
315
+ } catch (e) { /* .mcp.json may not be valid JSON */ }
316
+ }
317
+
231
318
  if (hasHooks) {
232
319
  console.log('✅ Removed component system files. Prompt system preserved.\n');
233
320
  } else {
@@ -256,6 +343,7 @@ Selective updates:
256
343
  --update-skills Update only skills/
257
344
  --update-recipes Update only component-recipes/
258
345
  --update-commands Update only styling commands
346
+ --update-agents Update only agents/
259
347
 
260
348
  Options:
261
349
  -h, --help Show this help message
@@ -264,16 +352,21 @@ Options:
264
352
  -r, --remove Remove component system (alias: --uninstall)
265
353
 
266
354
  What's included:
267
- • skills/ Styling skill for consistent UI generation
268
- component-recipes/ 36 pre-built component templates
269
- • commands/ /setup-styling, /component-harness
355
+ • skills/ Styling + React patterns skills
356
+ agents/ 5 component system agents (style-inspector,
357
+ design-token-validator, component-auditor,
358
+ harness-scaffolder, playwright-tester)
359
+ • component-recipes/ 38 pre-built component templates
360
+ • playwright-templates/ Playwright test config + component specs
361
+ • commands/ /setup-styling, /component-harness
362
+ • .mcp.json Playwright MCP server configuration
270
363
 
271
364
  Getting started:
272
365
  1. Run: npx @fr0mpy/component-system
273
366
  2. Use: /setup-styling to configure your design system
274
- 3. Use: /component-harness to preview components
367
+ 3. Use: /component-harness to preview and test components
275
368
 
276
- For prompt injection and agents:
369
+ For prompt injection and additional agents:
277
370
  npx @fr0mpy/prompt-system
278
371
 
279
372
  Learn more: https://github.com/fr0mpy/claude-base-setup