@amedia/brick-mcp 0.0.1-NEW-PATH-1 → 0.0.1-SNAPSHOT-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +269 -58
  2. package/dist/commands/serve.js +42 -0
  3. package/dist/commands/stdio.js +11 -0
  4. package/dist/extractors/packageScanner.js +150 -0
  5. package/dist/http.js +551 -107
  6. package/dist/http.js.map +4 -4
  7. package/dist/index.js +541 -63
  8. package/dist/index.js.map +4 -4
  9. package/dist/indexer/buildIndex.js +12 -0
  10. package/dist/indexer/search.js +12 -0
  11. package/dist/resources/componentResource.js +24 -0
  12. package/dist/resources/docsResource.js +44 -0
  13. package/dist/resources/index.js +49 -0
  14. package/dist/resources/tokenResource.js +20 -0
  15. package/dist/server.js +198 -0
  16. package/dist/tools/getComponentDocs.js +69 -0
  17. package/dist/tools/getDesignTokens.js +127 -0
  18. package/dist/tools/listComponents.js +16 -0
  19. package/dist/tools/searchComponents.js +66 -0
  20. package/dist/types.js +75 -0
  21. package/dist/utils.js +8 -0
  22. package/package.json +4 -18
  23. package/dist/data/components/brick-actions.json +0 -6
  24. package/dist/data/components/brick-alt-teaser.json +0 -10
  25. package/dist/data/components/brick-avatar.json +0 -11
  26. package/dist/data/components/brick-button.json +0 -12
  27. package/dist/data/components/brick-card.json +0 -10
  28. package/dist/data/components/brick-carousel.json +0 -11
  29. package/dist/data/components/brick-classnames.json +0 -10
  30. package/dist/data/components/brick-countdown.json +0 -7
  31. package/dist/data/components/brick-dialog.json +0 -11
  32. package/dist/data/components/brick-fonts.json +0 -10
  33. package/dist/data/components/brick-helloworld.json +0 -7
  34. package/dist/data/components/brick-icon.json +0 -10
  35. package/dist/data/components/brick-icons.json +0 -11
  36. package/dist/data/components/brick-illustrations.json +0 -7
  37. package/dist/data/components/brick-image.json +0 -10
  38. package/dist/data/components/brick-input.json +0 -12
  39. package/dist/data/components/brick-mcp.json +0 -6
  40. package/dist/data/components/brick-nifs.json +0 -7
  41. package/dist/data/components/brick-pill.json +0 -6
  42. package/dist/data/components/brick-player.json +0 -7
  43. package/dist/data/components/brick-published.json +0 -7
  44. package/dist/data/components/brick-share.json +0 -7
  45. package/dist/data/components/brick-stepper.json +0 -7
  46. package/dist/data/components/brick-tab.json +0 -7
  47. package/dist/data/components/brick-tabs.json +0 -11
  48. package/dist/data/components/brick-tag.json +0 -7
  49. package/dist/data/components/brick-teaser-player.json +0 -11
  50. package/dist/data/components/brick-teaser-reels.json +0 -11
  51. package/dist/data/components/brick-teaser.json +0 -11
  52. package/dist/data/components/brick-template.json +0 -11
  53. package/dist/data/components/brick-textarea.json +0 -7
  54. package/dist/data/components/brick-themes.json +0 -6
  55. package/dist/data/components/brick-toast.json +0 -11
  56. package/dist/data/components/brick-toggle.json +0 -7
  57. package/dist/data/components/brick-tokens.json +0 -10
  58. package/dist/data/components/brick-tooltip.json +0 -7
  59. package/dist/data/components-metadata.json +0 -290
  60. package/dist/data/components.json +0 -321
  61. package/dist/data/tokens.json +0 -256
  62. package/scripts/generate-data.js +0 -245
package/README.md CHANGED
@@ -4,38 +4,6 @@
4
4
 
5
5
  This is a Model Context Protocol (MCP) server for the Brick design system. It enables AI assistants (like Claude Code) to provide accurate, context-aware assistance when developers implement Brick components.
6
6
 
7
- ## Prerequisites
8
-
9
- Before using the Brick MCP server, you need to set up Claude Code:
10
-
11
- > **Note**: This guide assumes that you have pulled the latest changes and installed all dependencies.
12
-
13
- ### 1. Install Claude CLI
14
-
15
- ```bash
16
- curl -fsSL https://claude.ai/install.sh | bash
17
- ```
18
-
19
- ### 2. Authenticate with Google Cloud
20
-
21
- You'll need to authenticate daily to access Amedia's coding agent project:
22
-
23
- ```bash
24
- gcloud auth application-default login --project amedia-coding-agent
25
- ```
26
-
27
- > **Note**: You will need to re-authenticate once per day.
28
-
29
- ### 3. Install Claude Code VS Code Extension (Optional)
30
-
31
- If you prefer using Claude Code within VS Code:
32
-
33
- 1. Open VS Code
34
- 2. Go to the Extensions marketplace
35
- 3. Search for "Claude Code"
36
- 4. Install the extension (the one from Anthropic)
37
- 5. Restart VS Code if necessary
38
-
39
7
  ## Usage
40
8
 
41
9
  The Brick MCP server can be run in two modes:
@@ -45,7 +13,7 @@ The Brick MCP server can be run in two modes:
45
13
  To add the Brick MCP server to Claude Code using stdio transport:
46
14
 
47
15
  ```bash
48
- claude mcp add --transport stdio Brick -- node /absolute/path/to/brick/packages/brick-mcp/src/index.ts
16
+ claude mcp add --transport stdio Brick -- node /absolute/path/to/brick/mcp-server/src/index.ts
49
17
  ```
50
18
 
51
19
  Replace `/absolute/path/to/brick/` with the actual path to your Brick repository.
@@ -67,7 +35,6 @@ PORT=3001 HOST=localhost npm run start:http
67
35
  ```
68
36
 
69
37
  The HTTP server exposes:
70
-
71
38
  - `http://localhost:3000/health` - Health check endpoint
72
39
  - `http://localhost:3000/sse` - SSE endpoint for MCP protocol communication
73
40
  - `http://localhost:3000/message` - Message endpoint for client-to-server communication
@@ -104,16 +71,13 @@ The Model Context Protocol (MCP) is a standardized way to expose resources, tool
104
71
 
105
72
  MCP servers can be written in TypeScript using the `@modelcontextprotocol/sdk` package.
106
73
 
107
- ## MCP Tools (Actions)
74
+ ## Proposed Architecture
108
75
 
109
- Tools are functions that AI assistants can call to actively query and interact with the Brick design system. When you ask Claude about Brick components, it uses these tools behind the scenes to fetch accurate, up-to-date information directly from the codebase.
76
+ ### MCP Tools (Actions)
110
77
 
111
- These tools make Claude context-aware about the specific Brick setup, ensuring accurate implementation guidance tailored to the components and design tokens available in the project.
78
+ Tools allow AI assistants to actively query and search the Brick design system.
112
79
 
113
- <details>
114
- <summary>
115
- <strong>1. <code>list-components</code></strong>
116
- </summary>
80
+ #### 1. `list-components`
117
81
 
118
82
  **Purpose**: List all available Brick components with metadata
119
83
 
@@ -142,10 +106,9 @@ These tools make Claude context-aware about the specific Brick setup, ensuring a
142
106
 
143
107
  **Use Case**: "What components are available in Brick?"
144
108
 
145
- </details>
109
+ ---
146
110
 
147
- <details>
148
- <summary><strong>2. <code>get-component-docs</code></strong></summary>
111
+ #### 2. `get-component-docs`
149
112
 
150
113
  **Purpose**: Retrieve detailed documentation for specific component(s)
151
114
 
@@ -220,10 +183,9 @@ These tools make Claude context-aware about the specific Brick setup, ensuring a
220
183
 
221
184
  **Use Case**: "How do I use brick-button? What props does it accept?"
222
185
 
223
- </details>
186
+ ---
224
187
 
225
- <details>
226
- <summary><strong>3. <code>get-design-tokens</code></strong></summary>
188
+ #### 3. `get-design-tokens`
227
189
 
228
190
  **Purpose**: Access design tokens from brick-tokens
229
191
 
@@ -252,10 +214,9 @@ These tools make Claude context-aware about the specific Brick setup, ensuring a
252
214
 
253
215
  **Use Case**: "What color tokens are available in Brick?"
254
216
 
255
- </details>
217
+ ---
256
218
 
257
- <details>
258
- <summary><strong>4. <code>search-components</code></strong></summary>
219
+ #### 4. `search-components`
259
220
 
260
221
  **Purpose**: Search components by keyword or functionality
261
222
 
@@ -283,10 +244,9 @@ These tools make Claude context-aware about the specific Brick setup, ensuring a
283
244
 
284
245
  **Use Case**: "Find components related to forms"
285
246
 
286
- </details>
247
+ ---
287
248
 
288
- <details>
289
- <summary><strong>5. <code>get-usage-examples</code> (Optional for v1)</strong></summary>
249
+ #### 5. `get-usage-examples` (Optional for v1)
290
250
 
291
251
  **Purpose**: Get real-world code examples from Storybook stories
292
252
 
@@ -314,13 +274,264 @@ These tools make Claude context-aware about the specific Brick setup, ensuring a
314
274
 
315
275
  **Use Case**: "Show me examples of brick-button in different states"
316
276
 
317
- </details>
277
+ ---
278
+
279
+ ### MCP Resources (Static/Dynamic Data)
280
+
281
+ Resources provide direct access to structured data without complex queries.
282
+
283
+ - **`brick://components`**
284
+ - List of all components (similar to list-components tool)
285
+
286
+ - **`brick://component/{name}`**
287
+ - Individual component documentation (e.g., `brick://component/brick-button`)
288
+
289
+ - **`brick://tokens`**
290
+ - All design tokens
291
+
292
+ - **`brick://tokens/{category}`**
293
+ - Tokens by category (e.g., `brick://tokens/colors`)
294
+
295
+ - **`brick://getting-started`**
296
+ - Setup and installation guide
297
+
298
+ - **`brick://architecture`**
299
+ - Architecture overview from CLAUDE.md
300
+
301
+ ---
302
+
303
+ ## Implementation Approach
304
+
305
+ ### Package Structure
306
+
307
+ Create a new package in the monorepo:
308
+
309
+ ```
310
+ packages/brick-mcp-server/
311
+ ├── src/
312
+ │ ├── index.ts # Main MCP server entry point
313
+ │ ├── server.ts # MCP server setup and registration
314
+ │ ├── tools/
315
+ │ │ ├── listComponents.ts
316
+ │ │ ├── getComponentDocs.ts
317
+ │ │ ├── getDesignTokens.ts
318
+ │ │ ├── searchComponents.ts
319
+ │ │ └── getUsageExamples.ts
320
+ │ ├── resources/
321
+ │ │ ├── componentResource.ts
322
+ │ │ ├── tokenResource.ts
323
+ │ │ └── docsResource.ts
324
+ │ ├── extractors/
325
+ │ │ ├── packageScanner.ts # Scan packages/ for components
326
+ │ │ ├── mdxParser.ts # Parse Storybook MDX files
327
+ │ │ ├── typeExtractor.ts # Extract TS types from files
328
+ │ │ ├── tokenExtractor.ts # Extract design tokens
329
+ │ │ └── storyExtractor.ts # Extract examples from stories
330
+ │ ├── indexer/
331
+ │ │ ├── buildIndex.ts # Build searchable index
332
+ │ │ └── search.ts # Search implementation
333
+ │ ├── types.ts # TypeScript types
334
+ │ └── utils.ts # Helper functions
335
+ ├── build.js # Build script
336
+ ├── package.json
337
+ ├── README.md
338
+ └── tsconfig.json
339
+ ```
340
+
341
+ ### Documentation Extraction Strategy
342
+
343
+ The server will extract documentation from various sources in the monorepo:
344
+
345
+ 1. **Component Metadata** (from `package.json`):
346
+ - Name, version, description
347
+ - Dependencies
348
+
349
+ 2. **Type Definitions** (from `src/types.ts` or `src/template.ts`):
350
+ - Props/attributes with types
351
+ - Event types
352
+ - Method signatures
353
+ - Parse TypeScript AST to extract interfaces
354
+
355
+ 3. **Documentation** (from `stories/*.mdx`):
356
+ - Rich descriptions
357
+ - Usage guidelines
358
+ - Accessibility information
359
+ - Parse MDX frontmatter and content
360
+
361
+ 4. **Examples** (from `stories/*.stories.ts`):
362
+ - Real code examples from Storybook
363
+ - Different component states
364
+ - Parse story definitions
365
+
366
+ 5. **Styles** (from `src/styles.js`):
367
+ - CSS custom properties
368
+ - Available variants
369
+ - Parse Stitches configuration
370
+
371
+ 6. **Design Tokens** (from `packages/brick-tokens`):
372
+ - Token definitions
373
+ - Theme variations
374
+ - Parse token JSON/JS files
375
+
376
+ 7. **Repository Metadata** (from `CLAUDE.md`, `README.md`):
377
+ - Getting started guide
378
+ - Architecture overview
379
+ - Common patterns
380
+
381
+ ### Indexing and Search
382
+
383
+ To enable fast search:
384
+
385
+ 1. **Build-time indexing**: Create a JSON index of all components with searchable fields
386
+ 2. **Fuzzy search**: Use libraries like `fuse.js` for fuzzy text matching
387
+ 3. **Semantic categories**: Tag components by purpose (forms, navigation, feedback, etc.)
388
+ 4. **Cache**: Cache extracted documentation to avoid repeated parsing
389
+
390
+ ### Technology Stack
391
+
392
+ - **MCP SDK**: `@modelcontextprotocol/sdk` for server implementation
393
+ - **TypeScript**: Type-safe implementation
394
+ - **AST Parsing**:
395
+ - `typescript` compiler API for TS parsing
396
+ - `@mdx-js/mdx` or custom parser for MDX
397
+ - `@babel/parser` for JS/JSX parsing
398
+ - **Search**: `fuse.js` for fuzzy search
399
+ - **File System**: Node.js `fs` module for scanning packages
400
+
401
+ ### Deployment Options
402
+
403
+ 1. **Local Development** (stdio transport):
404
+ - Users run the server locally via `npx @amedia/brick-mcp-server`
405
+ - Configured in Claude Code settings
406
+
407
+ 2. **HTTP Server** (optional):
408
+ - Deploy as a service for remote access
409
+ - Use `@modelcontextprotocol/sdk/server/streamableHttp.js`
410
+
411
+ 3. **npm Package**:
412
+ - Publish as `@amedia/brick-mcp-server`
413
+ - Users install and configure in their MCP client
414
+
415
+ ### Example Server Setup
416
+
417
+ ```typescript
418
+ import {
419
+ McpServer,
420
+ ResourceTemplate,
421
+ } from '@modelcontextprotocol/sdk/server/mcp.js';
422
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
423
+ import { listComponents } from './tools/listComponents.js';
424
+ import { getComponentDocs } from './tools/getComponentDocs.js';
425
+
426
+ // Create MCP server
427
+ const server = new McpServer({
428
+ name: 'brick-design-system',
429
+ version: '1.0.0',
430
+ });
431
+
432
+ // Register tools
433
+ server.registerTool(
434
+ 'list-components',
435
+ {
436
+ title: 'List Brick Components',
437
+ description: 'List all available Brick components with metadata',
438
+ inputSchema: { filter: z.string().optional() },
439
+ outputSchema: z.object({
440
+ components: z.array(
441
+ z.object({
442
+ name: z.string(),
443
+ version: z.string(),
444
+ selector: z.string(),
445
+ description: z.string(),
446
+ })
447
+ ),
448
+ }),
449
+ },
450
+ async ({ filter }) => {
451
+ const components = await listComponents(filter);
452
+ return {
453
+ content: [{ type: 'text', text: JSON.stringify(components) }],
454
+ structuredContent: { components },
455
+ };
456
+ }
457
+ );
458
+
459
+ // Register resources
460
+ server.registerResource(
461
+ 'components',
462
+ new ResourceTemplate('brick://components', { list: undefined }),
463
+ {
464
+ title: 'Brick Components',
465
+ description: 'List of all Brick components',
466
+ },
467
+ async (uri) => {
468
+ const components = await listComponents();
469
+ return {
470
+ contents: [
471
+ {
472
+ uri: uri.href,
473
+ text: JSON.stringify(components, null, 2),
474
+ mimeType: 'application/json',
475
+ },
476
+ ],
477
+ };
478
+ }
479
+ );
480
+
481
+ // Start server with stdio transport
482
+ const transport = new StdioServerTransport();
483
+ await server.connect(transport);
484
+ ```
485
+
486
+ ---
487
+
488
+ ## Development Workflow
489
+
490
+ ### Phase 1: Foundation
491
+
492
+ 1. Set up package structure in `packages/brick-mcp-server/`
493
+ 2. Install MCP SDK and dependencies
494
+ 3. Create basic server with one tool (list-components)
495
+ 4. Implement package scanner to find all brick-\* packages
496
+
497
+ ### Phase 2: Documentation Extraction
498
+
499
+ 1. Build TypeScript type extractor
500
+ 2. Build MDX documentation parser
501
+ 3. Build Storybook story parser
502
+ 4. Build design token extractor
503
+
504
+ ### Phase 3: Core Tools
505
+
506
+ 1. Implement all MCP tools
507
+ 2. Implement search functionality
508
+ 3. Build documentation index
509
+
510
+ ### Phase 4: Resources
511
+
512
+ 1. Implement MCP resources
513
+ 2. Add caching layer
514
+ 3. Add error handling
515
+
516
+ ### Phase 5: Testing & Documentation
517
+
518
+ 1. Write unit tests for extractors
519
+ 2. Write integration tests for MCP tools
520
+ 3. Create comprehensive README
521
+ 4. Add usage examples
522
+
523
+ ### Phase 6: Publishing
524
+
525
+ 1. Build and bundle for npm
526
+ 2. Publish to npm as `@amedia/brick-mcp-server`
527
+ 3. Document installation in Brick docs
528
+ 4. Create video/guide for users
318
529
 
319
530
  ---
320
531
 
321
532
  ## Usage Example
322
533
 
323
- You can interact with the Brick MCP server in Claude Code:
534
+ Once configured, you can interact with the Brick MCP server in Claude Code:
324
535
 
325
536
  ```
326
537
  User: "I need to add a button to my app using Brick"
@@ -386,6 +597,6 @@ claude mcp add --transport stdio Brick -- npx @amedia/brick-mcp
386
597
 
387
598
  ## References
388
599
 
389
- - MCP TypeScript SDK: <https://github.com/modelcontextprotocol/typescript-sdk>
390
- - MCP Example Servers: <https://github.com/modelcontextprotocol/servers>
391
- - Brick Designsystem: `www.brick.api.no`
600
+ - MCP TypeScript SDK: https://github.com/modelcontextprotocol/typescript-sdk
601
+ - MCP Example Servers: https://github.com/modelcontextprotocol/servers
602
+ - Brick Monorepo: `/Users/simonsundstrom/dev/amedia/brick`
@@ -0,0 +1,42 @@
1
+ /**
2
+ * HTTP/Fastify transport command
3
+ * Used for running the MCP server as an HTTP service
4
+ */
5
+ import Fastify from 'fastify';
6
+ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
7
+ import { createServer } from '../server.ts';
8
+ export async function runServe(options = {}) {
9
+ const port = options.port ?? 3000;
10
+ const host = options.host ?? '0.0.0.0';
11
+ const fastify = Fastify({
12
+ logger: true,
13
+ });
14
+ // Health check endpoint
15
+ fastify.get('/health', async () => {
16
+ return { status: 'ok' };
17
+ });
18
+ // MCP SSE endpoint
19
+ fastify.get('/sse', async (request, reply) => {
20
+ const server = createServer();
21
+ const transport = new SSEServerTransport('/messages', reply.raw);
22
+ await server.connect(transport);
23
+ // Keep connection alive
24
+ request.raw.on('close', () => {
25
+ server.close();
26
+ });
27
+ });
28
+ // POST endpoint for messages
29
+ fastify.post('/messages', async () => {
30
+ // SSE transport handles this internally
31
+ return { received: true };
32
+ });
33
+ try {
34
+ await fastify.listen({ port, host });
35
+ console.log(`Brick MCP server listening on http://${host}:${port}`);
36
+ console.log(`SSE endpoint: http://${host}:${port}/sse`);
37
+ }
38
+ catch (err) {
39
+ fastify.log.error(err);
40
+ process.exit(1);
41
+ }
42
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * stdio transport command
3
+ * Used by Claude Desktop and other stdio-based MCP clients
4
+ */
5
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
6
+ import { createServer } from '../server.ts';
7
+ export async function runStdio() {
8
+ const server = createServer();
9
+ const transport = new StdioServerTransport();
10
+ await server.connect(transport);
11
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Package scanner for discovering Brick components
3
+ */
4
+ import { readdir, readFile } from 'node:fs/promises';
5
+ import { dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { PackageJsonSchema, } from '../types.ts';
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ /**
11
+ * Get the root directory of the Brick monorepo
12
+ * Assumes mcp-server is in the root of the brick repository
13
+ */
14
+ export function getBrickRoot() {
15
+ // Go up from mcp-server/src to brick root
16
+ return join(__dirname, '..', '..');
17
+ }
18
+ /**
19
+ * Extract component selector from package name
20
+ * e.g., "@amedia/brick-button" -> "brick-button"
21
+ */
22
+ export function extractSelector(packageName, version) {
23
+ const componentName = packageName.replace('@amedia/', '');
24
+ const majorVersion = version.split('.')[0];
25
+ return `${componentName}-v${majorVersion}`;
26
+ }
27
+ /**
28
+ * Categorize component based on name or package.json metadata
29
+ * This is a simple heuristic - can be improved with actual metadata
30
+ */
31
+ export function categorizeComponent(name) {
32
+ const categoryMap = {
33
+ Forms: ['button', 'input', 'checkbox', 'radio', 'select', 'form'],
34
+ Navigation: ['menu', 'nav', 'breadcrumb', 'tabs', 'link'],
35
+ Layout: ['grid', 'card', 'container', 'layout', 'section'],
36
+ Feedback: ['alert', 'toast', 'notification', 'banner', 'dialog', 'modal'],
37
+ Display: ['avatar', 'badge', 'icon', 'image', 'teaser', 'carousel'],
38
+ Utilities: ['tokens', 'classnames', 'template', 'fonts'],
39
+ };
40
+ const componentName = name.toLowerCase();
41
+ for (const [category, keywords] of Object.entries(categoryMap)) {
42
+ if (keywords.some((keyword) => componentName.includes(keyword))) {
43
+ return category;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ /**
49
+ * Extract tags from component name
50
+ */
51
+ export function extractTags(name, category) {
52
+ const tags = [];
53
+ if (category) {
54
+ tags.push(category.toLowerCase());
55
+ }
56
+ // Add interactive tag for form/button components
57
+ if (name.includes('button') ||
58
+ name.includes('input') ||
59
+ name.includes('select')) {
60
+ tags.push('interactive');
61
+ }
62
+ return tags;
63
+ }
64
+ /**
65
+ * Read and parse package.json for a given package path
66
+ */
67
+ export async function readPackageJson(packagePath) {
68
+ try {
69
+ const packageJsonPath = join(packagePath, 'package.json');
70
+ const content = await readFile(packageJsonPath, 'utf-8');
71
+ const data = JSON.parse(content);
72
+ return PackageJsonSchema.parse(data);
73
+ }
74
+ catch (error) {
75
+ console.error(`Error reading package.json at ${packagePath}:`, error);
76
+ return null;
77
+ }
78
+ }
79
+ /**
80
+ * Scan a single package directory and extract component metadata
81
+ */
82
+ export async function scanPackage(packagePath) {
83
+ const packageJson = await readPackageJson(packagePath);
84
+ if (!packageJson) {
85
+ return null;
86
+ }
87
+ // Only include packages that start with @amedia/brick- and exclude utility packages
88
+ if (!packageJson.name.startsWith('@amedia/brick-')) {
89
+ return null;
90
+ }
91
+ const componentName = packageJson.name.replace('@amedia/', '');
92
+ const selector = extractSelector(packageJson.name, packageJson.version);
93
+ const category = categorizeComponent(componentName);
94
+ const tags = extractTags(componentName, category);
95
+ return {
96
+ name: componentName,
97
+ version: packageJson.version,
98
+ selector,
99
+ description: packageJson.description,
100
+ category,
101
+ tags: tags.length > 0 ? tags : undefined,
102
+ packagePath,
103
+ };
104
+ }
105
+ /**
106
+ * Scan all packages in the Brick monorepo
107
+ */
108
+ export async function scanAllPackages() {
109
+ const brickRoot = getBrickRoot();
110
+ const packagesDir = join(brickRoot, 'packages');
111
+ try {
112
+ const entries = await readdir(packagesDir, { withFileTypes: true });
113
+ const packageDirs = entries
114
+ .filter((entry) => entry.isDirectory() && entry.name.startsWith('brick-'))
115
+ .map((entry) => join(packagesDir, entry.name));
116
+ const components = await Promise.all(packageDirs.map((dir) => scanPackage(dir)));
117
+ // Filter out null results and sort by name
118
+ return components
119
+ .filter((component) => component !== null)
120
+ .sort((a, b) => a.name.localeCompare(b.name));
121
+ }
122
+ catch (error) {
123
+ console.error('Error scanning packages:', error);
124
+ return [];
125
+ }
126
+ }
127
+ /**
128
+ * Filter components by category or tag
129
+ */
130
+ export function filterComponents(components, filter) {
131
+ if (!filter) {
132
+ return components;
133
+ }
134
+ const filterLower = filter.toLowerCase();
135
+ return components.filter((component) => {
136
+ // Match against name
137
+ if (component.name.toLowerCase().includes(filterLower)) {
138
+ return true;
139
+ }
140
+ // Match against category
141
+ if (component.category?.toLowerCase().includes(filterLower)) {
142
+ return true;
143
+ }
144
+ // Match against tags
145
+ if (component.tags?.some((tag) => tag.toLowerCase().includes(filterLower))) {
146
+ return true;
147
+ }
148
+ return false;
149
+ });
150
+ }