@fragments-sdk/cli 0.4.1 → 0.4.2

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.
package/dist/mcp-bin.js CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  import { readFile } from "fs/promises";
19
19
  import { existsSync, readFileSync } from "fs";
20
20
  import { join, dirname, resolve } from "path";
21
+ import { createRequire } from "module";
21
22
 
22
23
  // src/mcp/utils.ts
23
24
  function projectFields(obj, fields) {
@@ -83,6 +84,47 @@ function filterPlaceholders(items) {
83
84
  (item) => !PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(item.trim()))
84
85
  );
85
86
  }
87
+ function findFragmentsJson(startDir) {
88
+ const found = [];
89
+ const resolvedStart = resolve(startDir);
90
+ let dir = resolvedStart;
91
+ while (true) {
92
+ const candidate = join(dir, BRAND.outFile);
93
+ if (existsSync(candidate)) {
94
+ found.push(candidate);
95
+ break;
96
+ }
97
+ const parent = dirname(dir);
98
+ if (parent === dir) break;
99
+ dir = parent;
100
+ }
101
+ const pkgJsonPath = join(resolvedStart, "package.json");
102
+ if (existsSync(pkgJsonPath)) {
103
+ try {
104
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
105
+ const allDeps = {
106
+ ...pkgJson.dependencies,
107
+ ...pkgJson.devDependencies
108
+ };
109
+ const localRequire = createRequire(join(resolvedStart, "noop.js"));
110
+ for (const depName of Object.keys(allDeps)) {
111
+ try {
112
+ const depPkgPath = localRequire.resolve(`${depName}/package.json`);
113
+ const depPkg = JSON.parse(readFileSync(depPkgPath, "utf-8"));
114
+ if (depPkg.fragments) {
115
+ const fragmentsPath = join(dirname(depPkgPath), depPkg.fragments);
116
+ if (existsSync(fragmentsPath) && !found.includes(fragmentsPath)) {
117
+ found.push(fragmentsPath);
118
+ }
119
+ }
120
+ } catch {
121
+ }
122
+ }
123
+ } catch {
124
+ }
125
+ }
126
+ return found;
127
+ }
86
128
  var TOOLS = [
87
129
  {
88
130
  name: TOOL_NAMES.discover,
@@ -272,47 +314,6 @@ function createMcpServer(config) {
272
314
  let storageManager = null;
273
315
  let diffEngine = null;
274
316
  let isPoolWarming = false;
275
- function findFragmentsJson(startDir) {
276
- const found = [];
277
- const resolvedStart = resolve(startDir);
278
- let dir = resolvedStart;
279
- while (true) {
280
- const candidate = join(dir, BRAND.outFile);
281
- if (existsSync(candidate)) {
282
- found.push(candidate);
283
- break;
284
- }
285
- const parent = dirname(dir);
286
- if (parent === dir) break;
287
- dir = parent;
288
- }
289
- const pkgJsonPath = join(resolvedStart, "package.json");
290
- if (existsSync(pkgJsonPath)) {
291
- try {
292
- const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
293
- const allDeps = {
294
- ...pkgJson.dependencies,
295
- ...pkgJson.devDependencies
296
- };
297
- for (const depName of Object.keys(allDeps)) {
298
- const depPkgPath = join(resolvedStart, "node_modules", depName, "package.json");
299
- if (!existsSync(depPkgPath)) continue;
300
- try {
301
- const depPkg = JSON.parse(readFileSync(depPkgPath, "utf-8"));
302
- if (depPkg.fragments) {
303
- const fragmentsPath = join(resolvedStart, "node_modules", depName, depPkg.fragments);
304
- if (existsSync(fragmentsPath) && !found.includes(fragmentsPath)) {
305
- found.push(fragmentsPath);
306
- }
307
- }
308
- } catch {
309
- }
310
- }
311
- } catch {
312
- }
313
- }
314
- return found;
315
- }
316
317
  async function loadSegments() {
317
318
  if (segmentsData) {
318
319
  return segmentsData;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcp/server.ts","../src/mcp/utils.ts","../src/mcp-bin.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n BRAND,\n DEFAULTS,\n generateContext,\n type CompiledSegmentsFile,\n type VerifyResult,\n type Theme,\n} from '../core/index.js';\n// ../service is lazy-imported to avoid requiring playwright at startup.\n// Visual tools (render, fix) load it on first use.\ntype ServiceModule = typeof import('../service/index.js');\nlet _service: ServiceModule | null = null;\nasync function getService(): Promise<ServiceModule> {\n if (!_service) {\n try {\n _service = await import('../service/index.js');\n } catch {\n throw new Error(\n 'Visual tools require playwright. Install it with: npm install playwright'\n );\n }\n }\n return _service;\n}\nimport { readFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join, dirname, resolve } from 'node:path';\nimport { projectFields } from './utils.js';\n\n/**\n * MCP Tool names - derived from BRAND constants\n */\nconst TOOL_NAMES = {\n discover: `${BRAND.nameLower}_discover`,\n inspect: `${BRAND.nameLower}_inspect`,\n recipe: `${BRAND.nameLower}_recipe`,\n render: `${BRAND.nameLower}_render`,\n fix: `${BRAND.nameLower}_fix`,\n} as const;\n\n/**\n * Placeholder patterns to filter out from usage text.\n * These are auto-generated and provide no value to AI agents.\n */\nconst PLACEHOLDER_PATTERNS = [\n /^\\w+ component is needed$/i,\n /^Alternative component is more appropriate$/i,\n /^Use \\w+ when you need/i,\n];\n\n/**\n * Filter out placeholder text from usage arrays\n */\nfunction filterPlaceholders(items: string[] | undefined): string[] {\n if (!items) return [];\n return items.filter(item =>\n !PLACEHOLDER_PATTERNS.some(pattern => pattern.test(item.trim()))\n );\n}\n\n/**\n * MCP Server configuration\n */\nexport interface McpServerConfig {\n /** Project root directory */\n projectRoot: string;\n\n /** Viewer base URL */\n viewerUrl?: string;\n\n /** Default theme for verification */\n theme?: Theme;\n\n /** Diff threshold percentage */\n threshold?: number;\n}\n\n/**\n * Tool definitions for the MCP server — 5 consolidated tools\n */\nconst TOOLS: Tool[] = [\n {\n name: TOOL_NAMES.discover,\n description: `Discover components in the design system. Use with no params to list all components. Use 'useCase' for AI-powered suggestions. Use 'component' to find alternatives. Use 'compact' for a token-efficient overview.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n useCase: {\n type: 'string',\n description: 'Description of what you want to build — returns ranked suggestions (e.g., \"form for user email input\", \"button to submit data\")',\n },\n component: {\n type: 'string',\n description: 'Component name to find alternatives for (e.g., \"Button\")',\n },\n category: {\n type: 'string',\n description: 'Filter by category (e.g., \"actions\", \"forms\", \"layout\")',\n },\n search: {\n type: 'string',\n description: 'Search term to filter by name, description, or tags',\n },\n status: {\n type: 'string',\n enum: ['stable', 'beta', 'deprecated', 'experimental'],\n description: 'Filter by component status',\n },\n format: {\n type: 'string',\n enum: ['markdown', 'json'],\n description: 'Output format for context mode (default: markdown)',\n },\n compact: {\n type: 'boolean',\n description: 'If true, returns minimal output (just component names and categories)',\n },\n includeCode: {\n type: 'boolean',\n description: 'If true, includes code examples for each variant',\n },\n includeRelations: {\n type: 'boolean',\n description: 'If true, includes component relationships',\n },\n },\n },\n },\n {\n name: TOOL_NAMES.inspect,\n description: `Get detailed information about a specific component: props, usage guidelines, code examples, accessibility — all in one call. Use 'fields' to request only specific data for token efficiency.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n component: {\n type: 'string',\n description: 'Component name (e.g., \"Button\", \"Input\")',\n },\n fields: {\n type: 'array',\n items: { type: 'string' },\n description: 'Specific fields to return (e.g., [\"meta\", \"usage.when\", \"contract.propsSummary\", \"props\", \"examples\", \"guidelines\"]). If omitted, returns everything. Supports dot notation.',\n },\n variant: {\n type: 'string',\n description: 'Filter examples to a specific variant name (e.g., \"Default\", \"Primary\")',\n },\n maxExamples: {\n type: 'number',\n description: 'Maximum number of code examples to return (default: all)',\n },\n maxLines: {\n type: 'number',\n description: 'Maximum lines per code example (truncates longer examples)',\n },\n },\n required: ['component'],\n },\n },\n {\n name: TOOL_NAMES.recipe,\n description: `Search and retrieve composition recipes — named patterns showing how design system components wire together for common use cases (e.g., \"Login Form\", \"Settings Page\"). Returns the recipe with its code pattern.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n name: {\n type: 'string',\n description: 'Exact recipe name to retrieve (e.g., \"Login Form\")',\n },\n search: {\n type: 'string',\n description: 'Free-text search across recipe names, descriptions, tags, and components',\n },\n component: {\n type: 'string',\n description: 'Filter recipes that use a specific component (e.g., \"Button\")',\n },\n },\n },\n },\n {\n name: TOOL_NAMES.render,\n description: `Render a component and return a screenshot. Optionally compare against a stored baseline ('baseline: true') or against a Figma design ('figmaUrl'). Use this to verify your implementation looks correct.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n component: {\n type: 'string',\n description: 'Component name (e.g., \"Button\", \"Card\", \"Input\")',\n },\n variant: {\n type: 'string',\n description: 'Variant name for baseline/compare modes',\n },\n props: {\n type: 'object',\n description: 'Props to pass to the component (e.g., { \"variant\": \"primary\", \"children\": \"Click me\" })',\n },\n viewport: {\n type: 'object',\n properties: {\n width: { type: 'number', description: 'Viewport width (default: 800)' },\n height: { type: 'number', description: 'Viewport height (default: 600)' },\n },\n description: 'Optional viewport size for the render',\n },\n baseline: {\n type: 'boolean',\n description: 'If true, compares the render against the stored baseline screenshot (requires variant)',\n },\n figmaUrl: {\n type: 'string',\n description: 'Figma frame URL — if provided, compares the render against the Figma design',\n },\n theme: {\n type: 'string',\n enum: ['light', 'dark'],\n description: 'Theme for baseline verification (default: light)',\n },\n threshold: {\n type: 'number',\n description: 'Diff threshold percentage (default: 5 for baseline, 1 for Figma)',\n },\n },\n required: ['component'],\n },\n },\n {\n name: TOOL_NAMES.fix,\n description: `Generate patches to fix token compliance issues in a component. Returns unified diff patches that replace hardcoded CSS values with design token references. Use this after fragments_render identifies issues to automatically fix them.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n component: {\n type: 'string',\n description: 'Component name to generate fixes for (e.g., \"Button\", \"Card\")',\n },\n variant: {\n type: 'string',\n description: 'Specific variant to fix (optional, fixes all variants if omitted)',\n },\n fixType: {\n type: 'string',\n enum: ['token', 'all'],\n description: 'Type of fixes to generate: \"token\" for hardcoded→token replacements, \"all\" for all available fixes (default: \"all\")',\n },\n },\n required: ['component'],\n },\n },\n];\n\n/**\n * Create and configure the MCP server\n */\nexport function createMcpServer(config: McpServerConfig): Server {\n const server = new Server(\n {\n name: `${BRAND.nameLower}-mcp`,\n version: '0.0.1',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Lazy-loaded resources\n let segmentsData: CompiledSegmentsFile | null = null;\n let packageName: string | null = null;\n \n let browserPool: any = null;\n let storageManager: any = null;\n let diffEngine: any = null;\n let isPoolWarming = false;\n\n /**\n * Find fragments.json files:\n * 1. Walk up from projectRoot (for library authors with a local build)\n * 2. Read package.json deps and resolve packages with a \"fragments\" field\n */\n function findFragmentsJson(startDir: string): string[] {\n const found: string[] = [];\n const resolvedStart = resolve(startDir);\n\n // 1. Walk upward from startDir (library author flow)\n let dir = resolvedStart;\n while (true) {\n const candidate = join(dir, BRAND.outFile);\n if (existsSync(candidate)) {\n found.push(candidate);\n break;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n // 2. Read package.json and resolve deps with \"fragments\" field\n const pkgJsonPath = join(resolvedStart, 'package.json');\n if (existsSync(pkgJsonPath)) {\n try {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n const allDeps = {\n ...pkgJson.dependencies,\n ...pkgJson.devDependencies,\n };\n for (const depName of Object.keys(allDeps)) {\n const depPkgPath = join(resolvedStart, 'node_modules', depName, 'package.json');\n if (!existsSync(depPkgPath)) continue;\n try {\n const depPkg = JSON.parse(readFileSync(depPkgPath, 'utf-8'));\n if (depPkg.fragments) {\n const fragmentsPath = join(resolvedStart, 'node_modules', depName, depPkg.fragments);\n if (existsSync(fragmentsPath) && !found.includes(fragmentsPath)) {\n found.push(fragmentsPath);\n }\n }\n } catch {\n // Skip unreadable package\n }\n }\n } catch {\n // No package.json or unreadable\n }\n }\n\n return found;\n }\n\n async function loadSegments(): Promise<CompiledSegmentsFile> {\n if (segmentsData) {\n return segmentsData;\n }\n\n const paths = findFragmentsJson(config.projectRoot);\n\n if (paths.length === 0) {\n throw new Error(\n `No ${BRAND.outFile} found. Searched ${config.projectRoot} and package.json dependencies. ` +\n `Either run \\`${BRAND.cliCommand} build\\` or install a package with a \"fragments\" field in its package.json.`\n );\n }\n\n // Load and merge all found fragments files\n const content = await readFile(paths[0], 'utf-8');\n segmentsData = JSON.parse(content) as CompiledSegmentsFile;\n\n for (let i = 1; i < paths.length; i++) {\n const extra = JSON.parse(await readFile(paths[i], 'utf-8')) as CompiledSegmentsFile;\n Object.assign(segmentsData.segments, extra.segments);\n if (extra.recipes) {\n segmentsData.recipes = { ...segmentsData.recipes, ...extra.recipes };\n }\n }\n\n return segmentsData;\n }\n\n /**\n * Get the package name for import statements.\n * Prefers packageName from fragments.json (set at build time),\n * falls back to the project's package.json name.\n */\n async function getPackageName(): Promise<string> {\n if (packageName) {\n return packageName;\n }\n\n // Prefer packageName from compiled fragments.json\n const data = await loadSegments();\n if (data.packageName) {\n packageName = data.packageName;\n return packageName;\n }\n\n // Fallback to project package.json\n const packageJsonPath = join(config.projectRoot, 'package.json');\n if (existsSync(packageJsonPath)) {\n try {\n const content = await readFile(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(content) as { name?: string };\n if (pkg.name) {\n packageName = pkg.name;\n return packageName;\n }\n } catch {\n // Fall through to default\n }\n }\n\n // Default fallback\n packageName = 'your-component-library';\n return packageName;\n }\n\n /**\n * Get or create browser pool with extended idle timeout for MCP\n */\n async function getBrowserPool() {\n if (!browserPool) {\n const { BrowserPool } = await getService();\n browserPool = new BrowserPool({\n viewport: DEFAULTS.viewport,\n // 30 minute idle timeout for MCP - server runs continuously\n idleTimeoutMs: 30 * 60 * 1000,\n poolSize: 2, // Keep 2 contexts warm for faster captures\n });\n }\n return browserPool;\n }\n\n /**\n * Pre-warm browser pool in background (non-blocking)\n */\n function warmBrowserPool(): void {\n if (isPoolWarming || browserPool?.isReady) {\n return;\n }\n isPoolWarming = true;\n\n // Warm in background - don't await\n getBrowserPool().then((pool) => {\n pool.warmup().then(() => {\n isPoolWarming = false;\n }).catch(() => {\n isPoolWarming = false;\n });\n }).catch(() => {\n isPoolWarming = false;\n });\n }\n\n /**\n * Get or create storage manager\n */\n async function getStorageManager() {\n if (!storageManager) {\n const { StorageManager } = await getService();\n storageManager = new StorageManager({\n projectRoot: config.projectRoot,\n });\n await storageManager.initialize();\n }\n return storageManager;\n }\n\n /**\n * Get or create diff engine\n */\n async function getDiffEngine() {\n if (!diffEngine) {\n const { DiffEngine } = await getService();\n diffEngine = new DiffEngine(config.threshold ?? DEFAULTS.diffThreshold);\n }\n return diffEngine;\n }\n\n // Register tool listing\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: TOOLS };\n });\n\n // Register tool execution\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n // ================================================================\n // DISCOVER — list, suggest, context, alternatives\n // ================================================================\n case TOOL_NAMES.discover: {\n const data = await loadSegments();\n const useCase = (args?.useCase as string) ?? undefined;\n const componentForAlts = (args?.component as string) ?? undefined;\n const category = (args?.category as string) ?? undefined;\n const search = (args?.search as string)?.toLowerCase() ?? undefined;\n const status = (args?.status as string) ?? undefined;\n const format = (args?.format as 'markdown' | 'json') ?? 'markdown';\n const compact = (args?.compact as boolean) ?? false;\n const includeCode = (args?.includeCode as boolean) ?? false;\n const includeRelations = (args?.includeRelations as boolean) ?? false;\n\n // --- Context mode: compact or format specified with no specific query ---\n if (compact || (args?.format && !useCase && !componentForAlts && !category && !search && !status)) {\n const segments = Object.values(data.segments);\n const recipes = Object.values(data.recipes ?? {});\n\n const { content: ctxContent, tokenEstimate } = generateContext(segments, {\n format,\n compact,\n include: {\n code: includeCode,\n relations: includeRelations,\n },\n }, recipes);\n\n return {\n content: [{\n type: 'text' as const,\n text: ctxContent,\n }],\n _meta: { tokenEstimate },\n };\n }\n\n // --- Suggest mode: useCase provided ---\n if (useCase) {\n const useCaseLower = useCase.toLowerCase();\n const context = ((args as Record<string, unknown>)?.context as string)?.toLowerCase() ?? '';\n const searchTerms = `${useCaseLower} ${context}`.split(/\\s+/).filter(Boolean);\n\n const synonymMap: Record<string, string[]> = {\n 'form': ['input', 'field', 'submit', 'validation'],\n 'input': ['form', 'field', 'text', 'entry'],\n 'button': ['action', 'click', 'submit', 'trigger'],\n 'action': ['button', 'click', 'trigger'],\n 'alert': ['notification', 'message', 'warning', 'error', 'feedback'],\n 'notification': ['alert', 'message', 'toast'],\n 'card': ['container', 'panel', 'box', 'content'],\n 'toggle': ['switch', 'checkbox', 'boolean', 'on/off'],\n 'switch': ['toggle', 'checkbox', 'boolean'],\n 'badge': ['tag', 'label', 'status', 'indicator'],\n 'status': ['badge', 'indicator', 'state'],\n 'login': ['auth', 'signin', 'authentication', 'form'],\n 'auth': ['login', 'signin', 'authentication'],\n };\n\n const expandedTerms = new Set(searchTerms);\n searchTerms.forEach(term => {\n const synonyms = synonymMap[term];\n if (synonyms) {\n synonyms.forEach(syn => expandedTerms.add(syn));\n }\n });\n\n const scored = Object.values(data.segments).map((s) => {\n let score = 0;\n const reasons: string[] = [];\n\n const nameLower = s.meta.name.toLowerCase();\n if (searchTerms.some((term) => nameLower.includes(term))) {\n score += 15;\n reasons.push(`Name matches search`);\n } else if (Array.from(expandedTerms).some((term) => nameLower.includes(term))) {\n score += 8;\n reasons.push(`Name matches related term`);\n }\n\n const desc = s.meta.description?.toLowerCase() ?? '';\n const descMatches = searchTerms.filter((term) => desc.includes(term));\n if (descMatches.length > 0) {\n score += descMatches.length * 6;\n reasons.push(`Description matches: ${descMatches.join(', ')}`);\n }\n\n const tags = s.meta.tags?.map((t) => t.toLowerCase()) ?? [];\n const tagMatches = searchTerms.filter((term) =>\n tags.some((tag) => tag.includes(term))\n );\n if (tagMatches.length > 0) {\n score += tagMatches.length * 4;\n reasons.push(`Tags match: ${tagMatches.join(', ')}`);\n }\n\n const whenUsed = s.usage?.when?.join(' ').toLowerCase() ?? '';\n const whenMatches = searchTerms.filter((term) => whenUsed.includes(term));\n if (whenMatches.length > 0) {\n score += whenMatches.length * 10;\n reasons.push(`Use cases match: \"${whenMatches.join(', ')}\"`);\n }\n\n const expandedWhenMatches = Array.from(expandedTerms).filter(\n (term) => !searchTerms.includes(term) && whenUsed.includes(term)\n );\n if (expandedWhenMatches.length > 0) {\n score += expandedWhenMatches.length * 5;\n reasons.push(`Related use cases: \"${expandedWhenMatches.join(', ')}\"`);\n }\n\n const cat = s.meta.category?.toLowerCase() ?? '';\n if (searchTerms.some((term) => cat.includes(term))) {\n score += 8;\n reasons.push(`Category: ${s.meta.category}`);\n }\n\n const variantText = s.variants\n .map(v => `${v.name} ${v.description || ''}`.toLowerCase())\n .join(' ');\n const variantMatches = searchTerms.filter(term => variantText.includes(term));\n if (variantMatches.length > 0) {\n score += variantMatches.length * 3;\n reasons.push(`Variants match: ${variantMatches.join(', ')}`);\n }\n\n if (s.meta.status === 'stable') {\n score += 5;\n reasons.push('Stable component');\n } else if (s.meta.status === 'beta') {\n score += 2;\n }\n\n if (s.meta.status === 'deprecated') {\n score -= 25;\n reasons.push('Deprecated - consider alternatives');\n }\n\n const filteredWhen = filterPlaceholders(s.usage?.when).slice(0, 3);\n const filteredWhenNot = filterPlaceholders(s.usage?.whenNot).slice(0, 2);\n\n let confidence: 'high' | 'medium' | 'low';\n if (score >= 25) confidence = 'high';\n else if (score >= 15) confidence = 'medium';\n else confidence = 'low';\n\n return {\n component: s.meta.name,\n category: s.meta.category,\n description: s.meta.description,\n score,\n confidence,\n reasons,\n usage: { when: filteredWhen, whenNot: filteredWhenNot },\n variantCount: s.variants.length,\n status: s.meta.status,\n };\n });\n\n const MIN_SCORE = 8;\n const filtered = scored\n .filter((s) => s.score >= MIN_SCORE)\n .sort((a, b) => b.score - a.score);\n\n const suggestions: typeof filtered = [];\n const categoryCount: Record<string, number> = {};\n for (const item of filtered) {\n const cat = item.category || 'uncategorized';\n const count = categoryCount[cat] || 0;\n if (count < 2 || suggestions.length < 3) {\n suggestions.push(item);\n categoryCount[cat] = count + 1;\n if (suggestions.length >= 5) break;\n }\n }\n\n const compositionHint = suggestions.length >= 2\n ? `These components work well together. For example, ${suggestions[0].component} can be combined with ${suggestions.slice(1, 3).map(s => s.component).join(' and ')}.`\n : undefined;\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n useCase,\n context: context || undefined,\n suggestions: suggestions.map(({ score, ...rest }) => rest),\n recommendation: suggestions.length > 0\n ? `Best match: ${suggestions[0].component} (${suggestions[0].confidence} confidence) - ${suggestions[0].description}`\n : 'No matching components found. Try different keywords or browse with fragments_discover.',\n compositionHint,\n nextStep: suggestions.length > 0\n ? `Use fragments_inspect(\"${suggestions[0].component}\") for full details.`\n : undefined,\n }, null, 2),\n }],\n };\n }\n\n // --- Alternatives mode: component provided (no useCase) ---\n if (componentForAlts) {\n const segment = Object.values(data.segments).find(\n (s) => s.meta.name.toLowerCase() === componentForAlts.toLowerCase()\n );\n\n if (!segment) {\n throw new Error(`Component \"${componentForAlts}\" not found. Use fragments_discover to see available components.`);\n }\n\n const relations = segment.relations ?? [];\n\n const referencedBy = Object.values(data.segments)\n .filter((s) =>\n s.relations?.some((r) => r.component.toLowerCase() === componentForAlts.toLowerCase())\n )\n .map((s) => ({\n component: s.meta.name,\n relationship: s.relations?.find(\n (r) => r.component.toLowerCase() === componentForAlts.toLowerCase()\n )?.relationship,\n note: s.relations?.find(\n (r) => r.component.toLowerCase() === componentForAlts.toLowerCase()\n )?.note,\n }));\n\n const sameCategory = Object.values(data.segments)\n .filter(\n (s) =>\n s.meta.category === segment.meta.category &&\n s.meta.name.toLowerCase() !== componentForAlts.toLowerCase()\n )\n .map((s) => ({\n component: s.meta.name,\n description: s.meta.description,\n }));\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n component: segment.meta.name,\n category: segment.meta.category,\n directRelations: relations,\n referencedBy,\n sameCategory,\n suggestion: relations.find((r) => r.relationship === 'alternative')\n ? `Consider ${relations.find((r) => r.relationship === 'alternative')?.component}: ${relations.find((r) => r.relationship === 'alternative')?.note}`\n : undefined,\n }, null, 2),\n }],\n };\n }\n\n // --- Default: list mode ---\n const segments = Object.values(data.segments)\n .filter((s) => {\n if (category && s.meta.category !== category) return false;\n if (status && (s.meta.status ?? 'stable') !== status) return false;\n if (search) {\n const nameMatch = s.meta.name.toLowerCase().includes(search);\n const descMatch = s.meta.description?.toLowerCase().includes(search);\n const tagMatch = s.meta.tags?.some((t) => t.toLowerCase().includes(search));\n if (!nameMatch && !descMatch && !tagMatch) return false;\n }\n return true;\n })\n .map((s) => ({\n name: s.meta.name,\n category: s.meta.category,\n description: s.meta.description,\n status: s.meta.status ?? 'stable',\n variantCount: s.variants.length,\n tags: s.meta.tags ?? [],\n }));\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n total: segments.length,\n segments,\n categories: [...new Set(segments.map((s) => s.category))],\n hint: segments.length === 0\n ? 'No components found. Try broader search terms or check available categories.'\n : segments.length > 5\n ? 'Use fragments_discover with useCase for recommendations, or fragments_inspect for details on a specific component.'\n : undefined,\n }, null, 2),\n }],\n };\n }\n\n // ================================================================\n // INSPECT — get + guidelines + example in one call\n // ================================================================\n case TOOL_NAMES.inspect: {\n const data = await loadSegments();\n const componentName = args?.component as string;\n const fields = args?.fields as string[] | undefined;\n const variantName = (args?.variant as string) ?? undefined;\n const maxExamples = args?.maxExamples as number | undefined;\n const maxLines = args?.maxLines as number | undefined;\n\n if (!componentName) {\n throw new Error('component is required');\n }\n\n const segment = Object.values(data.segments).find(\n (s) => s.meta.name.toLowerCase() === componentName.toLowerCase()\n );\n\n if (!segment) {\n throw new Error(`Component \"${componentName}\" not found. Use fragments_discover to see available components.`);\n }\n\n // Build the full inspect result combining get + guidelines + example\n const pkgName = await getPackageName();\n\n // Filter variants for examples\n let variants = segment.variants;\n if (variantName) {\n const filtered = variants.filter(\n (v) => v.name.toLowerCase() === variantName.toLowerCase()\n );\n if (filtered.length > 0) {\n variants = filtered;\n }\n }\n if (maxExamples && maxExamples > 0) {\n variants = variants.slice(0, maxExamples);\n }\n\n const truncateCode = (code: string): string => {\n if (!maxLines || maxLines <= 0) return code;\n const lines = code.split('\\n');\n if (lines.length <= maxLines) return code;\n return lines.slice(0, maxLines).join('\\n') + '\\n// ... truncated';\n };\n\n const examples = variants.map((variant) => {\n if (variant.code) {\n return {\n variant: variant.name,\n description: variant.description,\n code: truncateCode(variant.code),\n };\n }\n return {\n variant: variant.name,\n description: variant.description,\n code: `<${segment.meta.name} />`,\n note: 'No code example provided in fragment. Refer to props for customization.',\n };\n });\n\n const propsReference = Object.entries(segment.props ?? {}).map(([propName, prop]) => ({\n name: propName,\n type: prop.type,\n required: prop.required,\n default: prop.default,\n description: prop.description,\n }));\n\n const propConstraints = Object.entries(segment.props ?? {})\n .filter(([, prop]) => prop.constraints && prop.constraints.length > 0)\n .map(([pName, prop]) => ({\n prop: pName,\n constraints: prop.constraints,\n }));\n\n const fullResult = {\n // Component data (from old \"get\")\n meta: segment.meta,\n props: segment.props,\n variants: segment.variants,\n relations: segment.relations,\n contract: segment.contract,\n generated: segment._generated,\n // Guidelines (from old \"guidelines\")\n guidelines: {\n when: filterPlaceholders(segment.usage?.when),\n whenNot: filterPlaceholders(segment.usage?.whenNot),\n guidelines: segment.usage?.guidelines ?? [],\n accessibility: segment.usage?.accessibility ?? [],\n propConstraints,\n alternatives: segment.relations\n ?.filter((r) => r.relationship === 'alternative')\n .map((r) => ({\n component: r.component,\n note: r.note,\n })) ?? [],\n },\n // Examples (from old \"example\")\n examples: {\n import: `import { ${segment.meta.name} } from '${pkgName}';`,\n code: examples,\n propsReference,\n },\n };\n\n // Apply field projection if specified\n const result = fields && fields.length > 0\n ? projectFields(fullResult as unknown as Record<string, unknown>, fields)\n : fullResult;\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n }],\n };\n }\n\n // ================================================================\n // RECIPE — unchanged\n // ================================================================\n case TOOL_NAMES.recipe: {\n const data = await loadSegments();\n const recipeName = args?.name as string | undefined;\n const search = (args?.search as string)?.toLowerCase() ?? undefined;\n const component = (args?.component as string)?.toLowerCase() ?? undefined;\n\n const allRecipes = Object.values(data.recipes ?? {});\n\n if (allRecipes.length === 0) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n total: 0,\n recipes: [],\n hint: `No recipes found. Run \\`${BRAND.cliCommand} build\\` after adding .recipe.ts files.`,\n }, null, 2),\n }],\n };\n }\n\n let filtered = allRecipes;\n\n if (recipeName) {\n filtered = filtered.filter(\n r => r.name.toLowerCase() === recipeName.toLowerCase()\n );\n }\n\n if (search) {\n filtered = filtered.filter(r => {\n const haystack = [\n r.name,\n r.description,\n ...(r.tags ?? []),\n ...r.components,\n r.category,\n ].join(' ').toLowerCase();\n return haystack.includes(search);\n });\n }\n\n if (component) {\n filtered = filtered.filter(r =>\n r.components.some(c => c.toLowerCase() === component)\n );\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n total: filtered.length,\n recipes: filtered,\n }, null, 2),\n }],\n };\n }\n\n // ================================================================\n // RENDER — render + verify + compare\n // ================================================================\n case TOOL_NAMES.render: {\n const componentName = args?.component as string;\n const variantName = args?.variant as string | undefined;\n const props = (args?.props as Record<string, unknown>) ?? {};\n const viewport = args?.viewport as { width?: number; height?: number } | undefined;\n const useBaseline = (args?.baseline as boolean) ?? false;\n const figmaUrl = args?.figmaUrl as string | undefined;\n const theme = (args?.theme as Theme) ?? config.theme ?? DEFAULTS.theme;\n const threshold = (args?.threshold as number) ?? (figmaUrl ? 1.0 : config.threshold ?? DEFAULTS.diffThreshold);\n\n if (!componentName) {\n return {\n content: [{\n type: 'text' as const,\n text: 'Error: component name is required',\n }],\n isError: true,\n };\n }\n\n // --- Baseline verify mode ---\n if (useBaseline) {\n if (!variantName) {\n throw new Error('variant is required when baseline is true');\n }\n\n const { Timer, CaptureEngine: CE, bufferToBase64Url: toBase64 } = await getService();\n const timer = new Timer();\n\n const storage = await getStorageManager();\n const pool = await getBrowserPool();\n const diff = await getDiffEngine();\n\n const baseline = await storage.loadBaseline(componentName, variantName, theme);\n\n if (!baseline) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n verdict: 'error',\n matches: false,\n diffPercentage: 0,\n screenshot: '',\n baseline: '',\n notes: [],\n error: `No baseline found for ${componentName}/${variantName}. Run \\`${BRAND.cliCommand} screenshot\\` first.`,\n timing: { renderMs: 0, captureMs: 0, diffMs: 0, totalMs: timer.elapsed() },\n } satisfies VerifyResult, null, 2),\n }],\n };\n }\n\n const viewerUrl = config.viewerUrl ?? `http://localhost:${DEFAULTS.port}`;\n const captureEngine = new CE(pool, viewerUrl);\n\n const current = await captureEngine.captureVariant(componentName, variantName, {\n theme,\n delay: DEFAULTS.captureDelayMs,\n });\n\n let diffResult;\n let matches = false;\n\n if (diff.areIdentical(current, baseline)) {\n matches = true;\n diffResult = {\n matches: true,\n diffPercentage: 0,\n diffPixelCount: 0,\n totalPixels: current.viewport.width * current.viewport.height,\n changedRegions: [],\n diffTimeMs: 0,\n };\n } else {\n diffResult = diff.compare(current, baseline, { threshold });\n matches = diffResult.matches;\n }\n\n const result: VerifyResult = {\n verdict: matches ? 'pass' : 'fail',\n matches,\n diffPercentage: diffResult.diffPercentage,\n screenshot: toBase64(current.data),\n baseline: toBase64(baseline.data),\n diffImage: diffResult.diffImage\n ? toBase64(diffResult.diffImage)\n : undefined,\n notes: matches\n ? ['Screenshot matches baseline within threshold']\n : [\n `Diff percentage (${diffResult.diffPercentage}%) exceeds threshold (${threshold}%)`,\n `${diffResult.changedRegions.length} changed region(s) detected`,\n ],\n timing: {\n renderMs: current.metadata.renderTimeMs,\n captureMs: current.metadata.captureTimeMs,\n diffMs: diffResult.diffTimeMs,\n totalMs: timer.elapsed(),\n },\n };\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n }],\n };\n }\n\n // --- Figma compare mode ---\n if (figmaUrl) {\n const baseUrl = config.viewerUrl ?? 'http://localhost:6006';\n const compareUrl = `${baseUrl}/fragments/compare`;\n\n try {\n const response = await fetch(compareUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n component: componentName,\n variant: variantName,\n props,\n figmaUrl,\n threshold,\n }),\n });\n\n interface CompareResult {\n match?: boolean;\n diffPercentage?: number;\n threshold?: number;\n rendered?: string;\n figma?: string;\n diff?: string;\n figmaUrl?: string;\n changedRegions?: Array<{ x: number; y: number; width: number; height: number }>;\n error?: string;\n suggestion?: string;\n }\n\n const result = await response.json() as CompareResult;\n\n if (!response.ok || result.error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Compare error: ${result.error ?? 'Unknown error'}${result.suggestion ? `\\nSuggestion: ${result.suggestion}` : ''}`,\n }],\n isError: true,\n };\n }\n\n const content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> = [];\n\n const summaryText = result.match\n ? `MATCH: ${componentName} matches Figma design (${result.diffPercentage}% diff, threshold: ${result.threshold}%)`\n : `MISMATCH: ${componentName} differs from Figma design by ${result.diffPercentage}% (threshold: ${result.threshold}%)`;\n\n content.push({ type: 'text' as const, text: summaryText });\n\n if (result.diff && !result.match) {\n content.push({\n type: 'image' as const,\n data: result.diff.replace('data:image/png;base64,', ''),\n mimeType: 'image/png',\n });\n content.push({\n type: 'text' as const,\n text: `Diff image above shows visual differences (red highlights). Changed regions: ${result.changedRegions?.length ?? 0}`,\n });\n }\n\n content.push({\n type: 'text' as const,\n text: JSON.stringify({\n match: result.match,\n diffPercentage: result.diffPercentage,\n threshold: result.threshold,\n figmaUrl: result.figmaUrl,\n changedRegions: result.changedRegions,\n }, null, 2),\n });\n\n return { content };\n } catch (error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Failed to compare component: ${error instanceof Error ? error.message : 'Unknown error'}. Make sure the Fragments dev server is running and FIGMA_ACCESS_TOKEN is set.`,\n }],\n isError: true,\n };\n }\n }\n\n // --- Default: pure render mode ---\n const baseUrl = config.viewerUrl ?? 'http://localhost:6006';\n const renderUrl = `${baseUrl}/fragments/render`;\n\n try {\n const response = await fetch(renderUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n component: componentName,\n props,\n viewport: viewport ?? { width: 800, height: 600 },\n }),\n });\n\n const result = await response.json() as { screenshot?: string; error?: string };\n\n if (!response.ok || result.error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Render error: ${result.error ?? 'Unknown error'}`,\n }],\n isError: true,\n };\n }\n\n return {\n content: [\n {\n type: 'image' as const,\n data: result.screenshot!.replace('data:image/png;base64,', ''),\n mimeType: 'image/png',\n },\n {\n type: 'text' as const,\n text: `Successfully rendered ${componentName} with props: ${JSON.stringify(props)}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Failed to render component: ${error instanceof Error ? error.message : 'Unknown error'}. Make sure the Fragments dev server is running.`,\n }],\n isError: true,\n };\n }\n }\n\n // ================================================================\n // FIX — unchanged\n // ================================================================\n case TOOL_NAMES.fix: {\n const data = await loadSegments();\n const componentName = args?.component as string;\n const variantName = (args?.variant as string) ?? undefined;\n const fixType = (args?.fixType as 'token' | 'all') ?? 'all';\n\n if (!componentName) {\n throw new Error('component is required');\n }\n\n const segment = Object.values(data.segments).find(\n (s) => s.meta.name.toLowerCase() === componentName.toLowerCase()\n );\n\n if (!segment) {\n throw new Error(`Component \"${componentName}\" not found. Use fragments_discover to see available components.`);\n }\n\n const baseUrl = config.viewerUrl ?? 'http://localhost:6006';\n const fixUrl = `${baseUrl}/fragments/fix`;\n\n try {\n const response = await fetch(fixUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n component: componentName,\n variant: variantName,\n fixType,\n }),\n });\n\n interface FixResult {\n patches: Array<{ file: string; diff: string }>;\n summary: string;\n error?: string;\n }\n\n const result = await response.json() as FixResult;\n\n if (!response.ok || result.error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Fix generation error: ${result.error ?? 'Unknown error'}`,\n }],\n isError: true,\n };\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n component: componentName,\n variant: variantName ?? 'all',\n fixType,\n patches: result.patches,\n summary: result.summary,\n patchCount: result.patches.length,\n nextStep: result.patches.length > 0\n ? 'Apply patches using your editor or `patch` command, then run fragments_render with baseline:true to confirm fixes.'\n : undefined,\n }, null, 2),\n }],\n };\n } catch (error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Failed to generate fixes: ${error instanceof Error ? error.message : 'Unknown error'}. Make sure the Fragments dev server is running.`,\n }],\n isError: true,\n };\n }\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n }),\n },\n ],\n isError: true,\n };\n }\n });\n\n // Cleanup on close\n server.onclose = async () => {\n if (browserPool) {\n await browserPool.shutdown();\n }\n };\n\n return server;\n}\n\n/**\n * Start the MCP server with stdio transport\n */\nexport async function startMcpServer(config: McpServerConfig): Promise<void> {\n const server = createMcpServer(config);\n const transport = new StdioServerTransport();\n\n await server.connect(transport);\n}\n","/**\n * Utility functions for the MCP server\n */\n\n/**\n * Extract specific fields from an object using dot notation paths.\n * E.g., projectFields(obj, ['meta.name', 'usage.when']) returns { meta: { name: ... }, usage: { when: ... } }\n *\n * @param obj - The source object to extract fields from\n * @param fields - Array of field paths (supports dot notation for nested fields)\n * @returns A new object containing only the requested fields\n */\nexport function projectFields<T extends Record<string, unknown>>(\n obj: T,\n fields: string[]\n): Partial<T> {\n if (!fields || fields.length === 0) {\n return obj;\n }\n\n const result: Record<string, unknown> = {};\n\n for (const field of fields) {\n const parts = field.split('.');\n let source: unknown = obj;\n let target = result;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const isLast = i === parts.length - 1;\n\n if (source === null || source === undefined || typeof source !== 'object') {\n break;\n }\n\n const sourceObj = source as Record<string, unknown>;\n const value = sourceObj[part];\n\n if (isLast) {\n // Set the final value\n target[part] = value;\n } else {\n // Create nested object if needed\n if (!(part in target)) {\n target[part] = {};\n }\n target = target[part] as Record<string, unknown>;\n source = value;\n }\n }\n }\n\n return result as Partial<T>;\n}\n","#!/usr/bin/env node\nimport { startMcpServer } from './mcp/server.js';\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nlet projectRoot = process.cwd();\nlet viewerUrl: string | undefined;\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--project-root' || arg === '-p') {\n projectRoot = args[++i] ?? projectRoot;\n } else if (arg === '--viewer-url' || arg === '-u') {\n viewerUrl = args[++i];\n } else if (arg === '--help' || arg === '-h') {\n console.log(`\nUsage: fragments-mcp [options]\n\nOptions:\n -p, --project-root <path> Project root directory (default: cwd)\n -u, --viewer-url <url> Viewer URL (default: http://localhost:6006)\n -h, --help Show this help message\n`);\n process.exit(0);\n }\n}\n\n// Start server\nstartMcpServer({\n projectRoot,\n viewerUrl,\n}).catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"mappings":"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","names":["args","segments","viewerUrl","baseUrl"]}
1
+ {"version":3,"sources":["../src/mcp/server.ts","../src/mcp/utils.ts","../src/mcp-bin.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n BRAND,\n DEFAULTS,\n generateContext,\n type CompiledSegmentsFile,\n type VerifyResult,\n type Theme,\n} from '../core/index.js';\n// ../service is lazy-imported to avoid requiring playwright at startup.\n// Visual tools (render, fix) load it on first use.\ntype ServiceModule = typeof import('../service/index.js');\nlet _service: ServiceModule | null = null;\nasync function getService(): Promise<ServiceModule> {\n if (!_service) {\n try {\n _service = await import('../service/index.js');\n } catch {\n throw new Error(\n 'Visual tools require playwright. Install it with: npm install playwright'\n );\n }\n }\n return _service;\n}\nimport { readFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join, dirname, resolve } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { projectFields } from './utils.js';\n\n/**\n * MCP Tool names - derived from BRAND constants\n */\nconst TOOL_NAMES = {\n discover: `${BRAND.nameLower}_discover`,\n inspect: `${BRAND.nameLower}_inspect`,\n recipe: `${BRAND.nameLower}_recipe`,\n render: `${BRAND.nameLower}_render`,\n fix: `${BRAND.nameLower}_fix`,\n} as const;\n\n/**\n * Placeholder patterns to filter out from usage text.\n * These are auto-generated and provide no value to AI agents.\n */\nconst PLACEHOLDER_PATTERNS = [\n /^\\w+ component is needed$/i,\n /^Alternative component is more appropriate$/i,\n /^Use \\w+ when you need/i,\n];\n\n/**\n * Filter out placeholder text from usage arrays\n */\nfunction filterPlaceholders(items: string[] | undefined): string[] {\n if (!items) return [];\n return items.filter(item =>\n !PLACEHOLDER_PATTERNS.some(pattern => pattern.test(item.trim()))\n );\n}\n\n/**\n * Find fragments.json files:\n * 1. Walk up from startDir (for library authors with a local build)\n * 2. Read package.json deps and resolve packages with a \"fragments\" field\n *\n * Uses Node.js module resolution (createRequire) to handle all package\n * managers: pnpm symlinks, yarn PnP, monorepo hoisting, etc.\n */\nexport function findFragmentsJson(startDir: string): string[] {\n const found: string[] = [];\n const resolvedStart = resolve(startDir);\n\n // 1. Walk upward from startDir (library author flow)\n let dir = resolvedStart;\n while (true) {\n const candidate = join(dir, BRAND.outFile);\n if (existsSync(candidate)) {\n found.push(candidate);\n break;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n // 2. Read package.json and resolve deps with \"fragments\" field\n const pkgJsonPath = join(resolvedStart, 'package.json');\n if (existsSync(pkgJsonPath)) {\n try {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));\n const allDeps = {\n ...pkgJson.dependencies,\n ...pkgJson.devDependencies,\n };\n const localRequire = createRequire(join(resolvedStart, 'noop.js'));\n for (const depName of Object.keys(allDeps)) {\n try {\n const depPkgPath = localRequire.resolve(`${depName}/package.json`);\n const depPkg = JSON.parse(readFileSync(depPkgPath, 'utf-8'));\n if (depPkg.fragments) {\n const fragmentsPath = join(dirname(depPkgPath), depPkg.fragments);\n if (existsSync(fragmentsPath) && !found.includes(fragmentsPath)) {\n found.push(fragmentsPath);\n }\n }\n } catch {\n // Package not resolvable or unreadable, skip\n }\n }\n } catch {\n // No package.json or unreadable\n }\n }\n\n return found;\n}\n\n/**\n * MCP Server configuration\n */\nexport interface McpServerConfig {\n /** Project root directory */\n projectRoot: string;\n\n /** Viewer base URL */\n viewerUrl?: string;\n\n /** Default theme for verification */\n theme?: Theme;\n\n /** Diff threshold percentage */\n threshold?: number;\n}\n\n/**\n * Tool definitions for the MCP server — 5 consolidated tools\n */\nconst TOOLS: Tool[] = [\n {\n name: TOOL_NAMES.discover,\n description: `Discover components in the design system. Use with no params to list all components. Use 'useCase' for AI-powered suggestions. Use 'component' to find alternatives. Use 'compact' for a token-efficient overview.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n useCase: {\n type: 'string',\n description: 'Description of what you want to build — returns ranked suggestions (e.g., \"form for user email input\", \"button to submit data\")',\n },\n component: {\n type: 'string',\n description: 'Component name to find alternatives for (e.g., \"Button\")',\n },\n category: {\n type: 'string',\n description: 'Filter by category (e.g., \"actions\", \"forms\", \"layout\")',\n },\n search: {\n type: 'string',\n description: 'Search term to filter by name, description, or tags',\n },\n status: {\n type: 'string',\n enum: ['stable', 'beta', 'deprecated', 'experimental'],\n description: 'Filter by component status',\n },\n format: {\n type: 'string',\n enum: ['markdown', 'json'],\n description: 'Output format for context mode (default: markdown)',\n },\n compact: {\n type: 'boolean',\n description: 'If true, returns minimal output (just component names and categories)',\n },\n includeCode: {\n type: 'boolean',\n description: 'If true, includes code examples for each variant',\n },\n includeRelations: {\n type: 'boolean',\n description: 'If true, includes component relationships',\n },\n },\n },\n },\n {\n name: TOOL_NAMES.inspect,\n description: `Get detailed information about a specific component: props, usage guidelines, code examples, accessibility — all in one call. Use 'fields' to request only specific data for token efficiency.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n component: {\n type: 'string',\n description: 'Component name (e.g., \"Button\", \"Input\")',\n },\n fields: {\n type: 'array',\n items: { type: 'string' },\n description: 'Specific fields to return (e.g., [\"meta\", \"usage.when\", \"contract.propsSummary\", \"props\", \"examples\", \"guidelines\"]). If omitted, returns everything. Supports dot notation.',\n },\n variant: {\n type: 'string',\n description: 'Filter examples to a specific variant name (e.g., \"Default\", \"Primary\")',\n },\n maxExamples: {\n type: 'number',\n description: 'Maximum number of code examples to return (default: all)',\n },\n maxLines: {\n type: 'number',\n description: 'Maximum lines per code example (truncates longer examples)',\n },\n },\n required: ['component'],\n },\n },\n {\n name: TOOL_NAMES.recipe,\n description: `Search and retrieve composition recipes — named patterns showing how design system components wire together for common use cases (e.g., \"Login Form\", \"Settings Page\"). Returns the recipe with its code pattern.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n name: {\n type: 'string',\n description: 'Exact recipe name to retrieve (e.g., \"Login Form\")',\n },\n search: {\n type: 'string',\n description: 'Free-text search across recipe names, descriptions, tags, and components',\n },\n component: {\n type: 'string',\n description: 'Filter recipes that use a specific component (e.g., \"Button\")',\n },\n },\n },\n },\n {\n name: TOOL_NAMES.render,\n description: `Render a component and return a screenshot. Optionally compare against a stored baseline ('baseline: true') or against a Figma design ('figmaUrl'). Use this to verify your implementation looks correct.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n component: {\n type: 'string',\n description: 'Component name (e.g., \"Button\", \"Card\", \"Input\")',\n },\n variant: {\n type: 'string',\n description: 'Variant name for baseline/compare modes',\n },\n props: {\n type: 'object',\n description: 'Props to pass to the component (e.g., { \"variant\": \"primary\", \"children\": \"Click me\" })',\n },\n viewport: {\n type: 'object',\n properties: {\n width: { type: 'number', description: 'Viewport width (default: 800)' },\n height: { type: 'number', description: 'Viewport height (default: 600)' },\n },\n description: 'Optional viewport size for the render',\n },\n baseline: {\n type: 'boolean',\n description: 'If true, compares the render against the stored baseline screenshot (requires variant)',\n },\n figmaUrl: {\n type: 'string',\n description: 'Figma frame URL — if provided, compares the render against the Figma design',\n },\n theme: {\n type: 'string',\n enum: ['light', 'dark'],\n description: 'Theme for baseline verification (default: light)',\n },\n threshold: {\n type: 'number',\n description: 'Diff threshold percentage (default: 5 for baseline, 1 for Figma)',\n },\n },\n required: ['component'],\n },\n },\n {\n name: TOOL_NAMES.fix,\n description: `Generate patches to fix token compliance issues in a component. Returns unified diff patches that replace hardcoded CSS values with design token references. Use this after fragments_render identifies issues to automatically fix them.`,\n inputSchema: {\n type: 'object' as const,\n properties: {\n component: {\n type: 'string',\n description: 'Component name to generate fixes for (e.g., \"Button\", \"Card\")',\n },\n variant: {\n type: 'string',\n description: 'Specific variant to fix (optional, fixes all variants if omitted)',\n },\n fixType: {\n type: 'string',\n enum: ['token', 'all'],\n description: 'Type of fixes to generate: \"token\" for hardcoded→token replacements, \"all\" for all available fixes (default: \"all\")',\n },\n },\n required: ['component'],\n },\n },\n];\n\n/**\n * Create and configure the MCP server\n */\nexport function createMcpServer(config: McpServerConfig): Server {\n const server = new Server(\n {\n name: `${BRAND.nameLower}-mcp`,\n version: '0.0.1',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Lazy-loaded resources\n let segmentsData: CompiledSegmentsFile | null = null;\n let packageName: string | null = null;\n \n let browserPool: any = null;\n let storageManager: any = null;\n let diffEngine: any = null;\n let isPoolWarming = false;\n\n async function loadSegments(): Promise<CompiledSegmentsFile> {\n if (segmentsData) {\n return segmentsData;\n }\n\n const paths = findFragmentsJson(config.projectRoot);\n\n if (paths.length === 0) {\n throw new Error(\n `No ${BRAND.outFile} found. Searched ${config.projectRoot} and package.json dependencies. ` +\n `Either run \\`${BRAND.cliCommand} build\\` or install a package with a \"fragments\" field in its package.json.`\n );\n }\n\n // Load and merge all found fragments files\n const content = await readFile(paths[0], 'utf-8');\n segmentsData = JSON.parse(content) as CompiledSegmentsFile;\n\n for (let i = 1; i < paths.length; i++) {\n const extra = JSON.parse(await readFile(paths[i], 'utf-8')) as CompiledSegmentsFile;\n Object.assign(segmentsData.segments, extra.segments);\n if (extra.recipes) {\n segmentsData.recipes = { ...segmentsData.recipes, ...extra.recipes };\n }\n }\n\n return segmentsData;\n }\n\n /**\n * Get the package name for import statements.\n * Prefers packageName from fragments.json (set at build time),\n * falls back to the project's package.json name.\n */\n async function getPackageName(): Promise<string> {\n if (packageName) {\n return packageName;\n }\n\n // Prefer packageName from compiled fragments.json\n const data = await loadSegments();\n if (data.packageName) {\n packageName = data.packageName;\n return packageName;\n }\n\n // Fallback to project package.json\n const packageJsonPath = join(config.projectRoot, 'package.json');\n if (existsSync(packageJsonPath)) {\n try {\n const content = await readFile(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(content) as { name?: string };\n if (pkg.name) {\n packageName = pkg.name;\n return packageName;\n }\n } catch {\n // Fall through to default\n }\n }\n\n // Default fallback\n packageName = 'your-component-library';\n return packageName;\n }\n\n /**\n * Get or create browser pool with extended idle timeout for MCP\n */\n async function getBrowserPool() {\n if (!browserPool) {\n const { BrowserPool } = await getService();\n browserPool = new BrowserPool({\n viewport: DEFAULTS.viewport,\n // 30 minute idle timeout for MCP - server runs continuously\n idleTimeoutMs: 30 * 60 * 1000,\n poolSize: 2, // Keep 2 contexts warm for faster captures\n });\n }\n return browserPool;\n }\n\n /**\n * Pre-warm browser pool in background (non-blocking)\n */\n function warmBrowserPool(): void {\n if (isPoolWarming || browserPool?.isReady) {\n return;\n }\n isPoolWarming = true;\n\n // Warm in background - don't await\n getBrowserPool().then((pool) => {\n pool.warmup().then(() => {\n isPoolWarming = false;\n }).catch(() => {\n isPoolWarming = false;\n });\n }).catch(() => {\n isPoolWarming = false;\n });\n }\n\n /**\n * Get or create storage manager\n */\n async function getStorageManager() {\n if (!storageManager) {\n const { StorageManager } = await getService();\n storageManager = new StorageManager({\n projectRoot: config.projectRoot,\n });\n await storageManager.initialize();\n }\n return storageManager;\n }\n\n /**\n * Get or create diff engine\n */\n async function getDiffEngine() {\n if (!diffEngine) {\n const { DiffEngine } = await getService();\n diffEngine = new DiffEngine(config.threshold ?? DEFAULTS.diffThreshold);\n }\n return diffEngine;\n }\n\n // Register tool listing\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: TOOLS };\n });\n\n // Register tool execution\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n // ================================================================\n // DISCOVER — list, suggest, context, alternatives\n // ================================================================\n case TOOL_NAMES.discover: {\n const data = await loadSegments();\n const useCase = (args?.useCase as string) ?? undefined;\n const componentForAlts = (args?.component as string) ?? undefined;\n const category = (args?.category as string) ?? undefined;\n const search = (args?.search as string)?.toLowerCase() ?? undefined;\n const status = (args?.status as string) ?? undefined;\n const format = (args?.format as 'markdown' | 'json') ?? 'markdown';\n const compact = (args?.compact as boolean) ?? false;\n const includeCode = (args?.includeCode as boolean) ?? false;\n const includeRelations = (args?.includeRelations as boolean) ?? false;\n\n // --- Context mode: compact or format specified with no specific query ---\n if (compact || (args?.format && !useCase && !componentForAlts && !category && !search && !status)) {\n const segments = Object.values(data.segments);\n const recipes = Object.values(data.recipes ?? {});\n\n const { content: ctxContent, tokenEstimate } = generateContext(segments, {\n format,\n compact,\n include: {\n code: includeCode,\n relations: includeRelations,\n },\n }, recipes);\n\n return {\n content: [{\n type: 'text' as const,\n text: ctxContent,\n }],\n _meta: { tokenEstimate },\n };\n }\n\n // --- Suggest mode: useCase provided ---\n if (useCase) {\n const useCaseLower = useCase.toLowerCase();\n const context = ((args as Record<string, unknown>)?.context as string)?.toLowerCase() ?? '';\n const searchTerms = `${useCaseLower} ${context}`.split(/\\s+/).filter(Boolean);\n\n const synonymMap: Record<string, string[]> = {\n 'form': ['input', 'field', 'submit', 'validation'],\n 'input': ['form', 'field', 'text', 'entry'],\n 'button': ['action', 'click', 'submit', 'trigger'],\n 'action': ['button', 'click', 'trigger'],\n 'alert': ['notification', 'message', 'warning', 'error', 'feedback'],\n 'notification': ['alert', 'message', 'toast'],\n 'card': ['container', 'panel', 'box', 'content'],\n 'toggle': ['switch', 'checkbox', 'boolean', 'on/off'],\n 'switch': ['toggle', 'checkbox', 'boolean'],\n 'badge': ['tag', 'label', 'status', 'indicator'],\n 'status': ['badge', 'indicator', 'state'],\n 'login': ['auth', 'signin', 'authentication', 'form'],\n 'auth': ['login', 'signin', 'authentication'],\n };\n\n const expandedTerms = new Set(searchTerms);\n searchTerms.forEach(term => {\n const synonyms = synonymMap[term];\n if (synonyms) {\n synonyms.forEach(syn => expandedTerms.add(syn));\n }\n });\n\n const scored = Object.values(data.segments).map((s) => {\n let score = 0;\n const reasons: string[] = [];\n\n const nameLower = s.meta.name.toLowerCase();\n if (searchTerms.some((term) => nameLower.includes(term))) {\n score += 15;\n reasons.push(`Name matches search`);\n } else if (Array.from(expandedTerms).some((term) => nameLower.includes(term))) {\n score += 8;\n reasons.push(`Name matches related term`);\n }\n\n const desc = s.meta.description?.toLowerCase() ?? '';\n const descMatches = searchTerms.filter((term) => desc.includes(term));\n if (descMatches.length > 0) {\n score += descMatches.length * 6;\n reasons.push(`Description matches: ${descMatches.join(', ')}`);\n }\n\n const tags = s.meta.tags?.map((t) => t.toLowerCase()) ?? [];\n const tagMatches = searchTerms.filter((term) =>\n tags.some((tag) => tag.includes(term))\n );\n if (tagMatches.length > 0) {\n score += tagMatches.length * 4;\n reasons.push(`Tags match: ${tagMatches.join(', ')}`);\n }\n\n const whenUsed = s.usage?.when?.join(' ').toLowerCase() ?? '';\n const whenMatches = searchTerms.filter((term) => whenUsed.includes(term));\n if (whenMatches.length > 0) {\n score += whenMatches.length * 10;\n reasons.push(`Use cases match: \"${whenMatches.join(', ')}\"`);\n }\n\n const expandedWhenMatches = Array.from(expandedTerms).filter(\n (term) => !searchTerms.includes(term) && whenUsed.includes(term)\n );\n if (expandedWhenMatches.length > 0) {\n score += expandedWhenMatches.length * 5;\n reasons.push(`Related use cases: \"${expandedWhenMatches.join(', ')}\"`);\n }\n\n const cat = s.meta.category?.toLowerCase() ?? '';\n if (searchTerms.some((term) => cat.includes(term))) {\n score += 8;\n reasons.push(`Category: ${s.meta.category}`);\n }\n\n const variantText = s.variants\n .map(v => `${v.name} ${v.description || ''}`.toLowerCase())\n .join(' ');\n const variantMatches = searchTerms.filter(term => variantText.includes(term));\n if (variantMatches.length > 0) {\n score += variantMatches.length * 3;\n reasons.push(`Variants match: ${variantMatches.join(', ')}`);\n }\n\n if (s.meta.status === 'stable') {\n score += 5;\n reasons.push('Stable component');\n } else if (s.meta.status === 'beta') {\n score += 2;\n }\n\n if (s.meta.status === 'deprecated') {\n score -= 25;\n reasons.push('Deprecated - consider alternatives');\n }\n\n const filteredWhen = filterPlaceholders(s.usage?.when).slice(0, 3);\n const filteredWhenNot = filterPlaceholders(s.usage?.whenNot).slice(0, 2);\n\n let confidence: 'high' | 'medium' | 'low';\n if (score >= 25) confidence = 'high';\n else if (score >= 15) confidence = 'medium';\n else confidence = 'low';\n\n return {\n component: s.meta.name,\n category: s.meta.category,\n description: s.meta.description,\n score,\n confidence,\n reasons,\n usage: { when: filteredWhen, whenNot: filteredWhenNot },\n variantCount: s.variants.length,\n status: s.meta.status,\n };\n });\n\n const MIN_SCORE = 8;\n const filtered = scored\n .filter((s) => s.score >= MIN_SCORE)\n .sort((a, b) => b.score - a.score);\n\n const suggestions: typeof filtered = [];\n const categoryCount: Record<string, number> = {};\n for (const item of filtered) {\n const cat = item.category || 'uncategorized';\n const count = categoryCount[cat] || 0;\n if (count < 2 || suggestions.length < 3) {\n suggestions.push(item);\n categoryCount[cat] = count + 1;\n if (suggestions.length >= 5) break;\n }\n }\n\n const compositionHint = suggestions.length >= 2\n ? `These components work well together. For example, ${suggestions[0].component} can be combined with ${suggestions.slice(1, 3).map(s => s.component).join(' and ')}.`\n : undefined;\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n useCase,\n context: context || undefined,\n suggestions: suggestions.map(({ score, ...rest }) => rest),\n recommendation: suggestions.length > 0\n ? `Best match: ${suggestions[0].component} (${suggestions[0].confidence} confidence) - ${suggestions[0].description}`\n : 'No matching components found. Try different keywords or browse with fragments_discover.',\n compositionHint,\n nextStep: suggestions.length > 0\n ? `Use fragments_inspect(\"${suggestions[0].component}\") for full details.`\n : undefined,\n }, null, 2),\n }],\n };\n }\n\n // --- Alternatives mode: component provided (no useCase) ---\n if (componentForAlts) {\n const segment = Object.values(data.segments).find(\n (s) => s.meta.name.toLowerCase() === componentForAlts.toLowerCase()\n );\n\n if (!segment) {\n throw new Error(`Component \"${componentForAlts}\" not found. Use fragments_discover to see available components.`);\n }\n\n const relations = segment.relations ?? [];\n\n const referencedBy = Object.values(data.segments)\n .filter((s) =>\n s.relations?.some((r) => r.component.toLowerCase() === componentForAlts.toLowerCase())\n )\n .map((s) => ({\n component: s.meta.name,\n relationship: s.relations?.find(\n (r) => r.component.toLowerCase() === componentForAlts.toLowerCase()\n )?.relationship,\n note: s.relations?.find(\n (r) => r.component.toLowerCase() === componentForAlts.toLowerCase()\n )?.note,\n }));\n\n const sameCategory = Object.values(data.segments)\n .filter(\n (s) =>\n s.meta.category === segment.meta.category &&\n s.meta.name.toLowerCase() !== componentForAlts.toLowerCase()\n )\n .map((s) => ({\n component: s.meta.name,\n description: s.meta.description,\n }));\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n component: segment.meta.name,\n category: segment.meta.category,\n directRelations: relations,\n referencedBy,\n sameCategory,\n suggestion: relations.find((r) => r.relationship === 'alternative')\n ? `Consider ${relations.find((r) => r.relationship === 'alternative')?.component}: ${relations.find((r) => r.relationship === 'alternative')?.note}`\n : undefined,\n }, null, 2),\n }],\n };\n }\n\n // --- Default: list mode ---\n const segments = Object.values(data.segments)\n .filter((s) => {\n if (category && s.meta.category !== category) return false;\n if (status && (s.meta.status ?? 'stable') !== status) return false;\n if (search) {\n const nameMatch = s.meta.name.toLowerCase().includes(search);\n const descMatch = s.meta.description?.toLowerCase().includes(search);\n const tagMatch = s.meta.tags?.some((t) => t.toLowerCase().includes(search));\n if (!nameMatch && !descMatch && !tagMatch) return false;\n }\n return true;\n })\n .map((s) => ({\n name: s.meta.name,\n category: s.meta.category,\n description: s.meta.description,\n status: s.meta.status ?? 'stable',\n variantCount: s.variants.length,\n tags: s.meta.tags ?? [],\n }));\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n total: segments.length,\n segments,\n categories: [...new Set(segments.map((s) => s.category))],\n hint: segments.length === 0\n ? 'No components found. Try broader search terms or check available categories.'\n : segments.length > 5\n ? 'Use fragments_discover with useCase for recommendations, or fragments_inspect for details on a specific component.'\n : undefined,\n }, null, 2),\n }],\n };\n }\n\n // ================================================================\n // INSPECT — get + guidelines + example in one call\n // ================================================================\n case TOOL_NAMES.inspect: {\n const data = await loadSegments();\n const componentName = args?.component as string;\n const fields = args?.fields as string[] | undefined;\n const variantName = (args?.variant as string) ?? undefined;\n const maxExamples = args?.maxExamples as number | undefined;\n const maxLines = args?.maxLines as number | undefined;\n\n if (!componentName) {\n throw new Error('component is required');\n }\n\n const segment = Object.values(data.segments).find(\n (s) => s.meta.name.toLowerCase() === componentName.toLowerCase()\n );\n\n if (!segment) {\n throw new Error(`Component \"${componentName}\" not found. Use fragments_discover to see available components.`);\n }\n\n // Build the full inspect result combining get + guidelines + example\n const pkgName = await getPackageName();\n\n // Filter variants for examples\n let variants = segment.variants;\n if (variantName) {\n const filtered = variants.filter(\n (v) => v.name.toLowerCase() === variantName.toLowerCase()\n );\n if (filtered.length > 0) {\n variants = filtered;\n }\n }\n if (maxExamples && maxExamples > 0) {\n variants = variants.slice(0, maxExamples);\n }\n\n const truncateCode = (code: string): string => {\n if (!maxLines || maxLines <= 0) return code;\n const lines = code.split('\\n');\n if (lines.length <= maxLines) return code;\n return lines.slice(0, maxLines).join('\\n') + '\\n// ... truncated';\n };\n\n const examples = variants.map((variant) => {\n if (variant.code) {\n return {\n variant: variant.name,\n description: variant.description,\n code: truncateCode(variant.code),\n };\n }\n return {\n variant: variant.name,\n description: variant.description,\n code: `<${segment.meta.name} />`,\n note: 'No code example provided in fragment. Refer to props for customization.',\n };\n });\n\n const propsReference = Object.entries(segment.props ?? {}).map(([propName, prop]) => ({\n name: propName,\n type: prop.type,\n required: prop.required,\n default: prop.default,\n description: prop.description,\n }));\n\n const propConstraints = Object.entries(segment.props ?? {})\n .filter(([, prop]) => prop.constraints && prop.constraints.length > 0)\n .map(([pName, prop]) => ({\n prop: pName,\n constraints: prop.constraints,\n }));\n\n const fullResult = {\n // Component data (from old \"get\")\n meta: segment.meta,\n props: segment.props,\n variants: segment.variants,\n relations: segment.relations,\n contract: segment.contract,\n generated: segment._generated,\n // Guidelines (from old \"guidelines\")\n guidelines: {\n when: filterPlaceholders(segment.usage?.when),\n whenNot: filterPlaceholders(segment.usage?.whenNot),\n guidelines: segment.usage?.guidelines ?? [],\n accessibility: segment.usage?.accessibility ?? [],\n propConstraints,\n alternatives: segment.relations\n ?.filter((r) => r.relationship === 'alternative')\n .map((r) => ({\n component: r.component,\n note: r.note,\n })) ?? [],\n },\n // Examples (from old \"example\")\n examples: {\n import: `import { ${segment.meta.name} } from '${pkgName}';`,\n code: examples,\n propsReference,\n },\n };\n\n // Apply field projection if specified\n const result = fields && fields.length > 0\n ? projectFields(fullResult as unknown as Record<string, unknown>, fields)\n : fullResult;\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n }],\n };\n }\n\n // ================================================================\n // RECIPE — unchanged\n // ================================================================\n case TOOL_NAMES.recipe: {\n const data = await loadSegments();\n const recipeName = args?.name as string | undefined;\n const search = (args?.search as string)?.toLowerCase() ?? undefined;\n const component = (args?.component as string)?.toLowerCase() ?? undefined;\n\n const allRecipes = Object.values(data.recipes ?? {});\n\n if (allRecipes.length === 0) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n total: 0,\n recipes: [],\n hint: `No recipes found. Run \\`${BRAND.cliCommand} build\\` after adding .recipe.ts files.`,\n }, null, 2),\n }],\n };\n }\n\n let filtered = allRecipes;\n\n if (recipeName) {\n filtered = filtered.filter(\n r => r.name.toLowerCase() === recipeName.toLowerCase()\n );\n }\n\n if (search) {\n filtered = filtered.filter(r => {\n const haystack = [\n r.name,\n r.description,\n ...(r.tags ?? []),\n ...r.components,\n r.category,\n ].join(' ').toLowerCase();\n return haystack.includes(search);\n });\n }\n\n if (component) {\n filtered = filtered.filter(r =>\n r.components.some(c => c.toLowerCase() === component)\n );\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n total: filtered.length,\n recipes: filtered,\n }, null, 2),\n }],\n };\n }\n\n // ================================================================\n // RENDER — render + verify + compare\n // ================================================================\n case TOOL_NAMES.render: {\n const componentName = args?.component as string;\n const variantName = args?.variant as string | undefined;\n const props = (args?.props as Record<string, unknown>) ?? {};\n const viewport = args?.viewport as { width?: number; height?: number } | undefined;\n const useBaseline = (args?.baseline as boolean) ?? false;\n const figmaUrl = args?.figmaUrl as string | undefined;\n const theme = (args?.theme as Theme) ?? config.theme ?? DEFAULTS.theme;\n const threshold = (args?.threshold as number) ?? (figmaUrl ? 1.0 : config.threshold ?? DEFAULTS.diffThreshold);\n\n if (!componentName) {\n return {\n content: [{\n type: 'text' as const,\n text: 'Error: component name is required',\n }],\n isError: true,\n };\n }\n\n // --- Baseline verify mode ---\n if (useBaseline) {\n if (!variantName) {\n throw new Error('variant is required when baseline is true');\n }\n\n const { Timer, CaptureEngine: CE, bufferToBase64Url: toBase64 } = await getService();\n const timer = new Timer();\n\n const storage = await getStorageManager();\n const pool = await getBrowserPool();\n const diff = await getDiffEngine();\n\n const baseline = await storage.loadBaseline(componentName, variantName, theme);\n\n if (!baseline) {\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n verdict: 'error',\n matches: false,\n diffPercentage: 0,\n screenshot: '',\n baseline: '',\n notes: [],\n error: `No baseline found for ${componentName}/${variantName}. Run \\`${BRAND.cliCommand} screenshot\\` first.`,\n timing: { renderMs: 0, captureMs: 0, diffMs: 0, totalMs: timer.elapsed() },\n } satisfies VerifyResult, null, 2),\n }],\n };\n }\n\n const viewerUrl = config.viewerUrl ?? `http://localhost:${DEFAULTS.port}`;\n const captureEngine = new CE(pool, viewerUrl);\n\n const current = await captureEngine.captureVariant(componentName, variantName, {\n theme,\n delay: DEFAULTS.captureDelayMs,\n });\n\n let diffResult;\n let matches = false;\n\n if (diff.areIdentical(current, baseline)) {\n matches = true;\n diffResult = {\n matches: true,\n diffPercentage: 0,\n diffPixelCount: 0,\n totalPixels: current.viewport.width * current.viewport.height,\n changedRegions: [],\n diffTimeMs: 0,\n };\n } else {\n diffResult = diff.compare(current, baseline, { threshold });\n matches = diffResult.matches;\n }\n\n const result: VerifyResult = {\n verdict: matches ? 'pass' : 'fail',\n matches,\n diffPercentage: diffResult.diffPercentage,\n screenshot: toBase64(current.data),\n baseline: toBase64(baseline.data),\n diffImage: diffResult.diffImage\n ? toBase64(diffResult.diffImage)\n : undefined,\n notes: matches\n ? ['Screenshot matches baseline within threshold']\n : [\n `Diff percentage (${diffResult.diffPercentage}%) exceeds threshold (${threshold}%)`,\n `${diffResult.changedRegions.length} changed region(s) detected`,\n ],\n timing: {\n renderMs: current.metadata.renderTimeMs,\n captureMs: current.metadata.captureTimeMs,\n diffMs: diffResult.diffTimeMs,\n totalMs: timer.elapsed(),\n },\n };\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n }],\n };\n }\n\n // --- Figma compare mode ---\n if (figmaUrl) {\n const baseUrl = config.viewerUrl ?? 'http://localhost:6006';\n const compareUrl = `${baseUrl}/fragments/compare`;\n\n try {\n const response = await fetch(compareUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n component: componentName,\n variant: variantName,\n props,\n figmaUrl,\n threshold,\n }),\n });\n\n interface CompareResult {\n match?: boolean;\n diffPercentage?: number;\n threshold?: number;\n rendered?: string;\n figma?: string;\n diff?: string;\n figmaUrl?: string;\n changedRegions?: Array<{ x: number; y: number; width: number; height: number }>;\n error?: string;\n suggestion?: string;\n }\n\n const result = await response.json() as CompareResult;\n\n if (!response.ok || result.error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Compare error: ${result.error ?? 'Unknown error'}${result.suggestion ? `\\nSuggestion: ${result.suggestion}` : ''}`,\n }],\n isError: true,\n };\n }\n\n const content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> = [];\n\n const summaryText = result.match\n ? `MATCH: ${componentName} matches Figma design (${result.diffPercentage}% diff, threshold: ${result.threshold}%)`\n : `MISMATCH: ${componentName} differs from Figma design by ${result.diffPercentage}% (threshold: ${result.threshold}%)`;\n\n content.push({ type: 'text' as const, text: summaryText });\n\n if (result.diff && !result.match) {\n content.push({\n type: 'image' as const,\n data: result.diff.replace('data:image/png;base64,', ''),\n mimeType: 'image/png',\n });\n content.push({\n type: 'text' as const,\n text: `Diff image above shows visual differences (red highlights). Changed regions: ${result.changedRegions?.length ?? 0}`,\n });\n }\n\n content.push({\n type: 'text' as const,\n text: JSON.stringify({\n match: result.match,\n diffPercentage: result.diffPercentage,\n threshold: result.threshold,\n figmaUrl: result.figmaUrl,\n changedRegions: result.changedRegions,\n }, null, 2),\n });\n\n return { content };\n } catch (error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Failed to compare component: ${error instanceof Error ? error.message : 'Unknown error'}. Make sure the Fragments dev server is running and FIGMA_ACCESS_TOKEN is set.`,\n }],\n isError: true,\n };\n }\n }\n\n // --- Default: pure render mode ---\n const baseUrl = config.viewerUrl ?? 'http://localhost:6006';\n const renderUrl = `${baseUrl}/fragments/render`;\n\n try {\n const response = await fetch(renderUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n component: componentName,\n props,\n viewport: viewport ?? { width: 800, height: 600 },\n }),\n });\n\n const result = await response.json() as { screenshot?: string; error?: string };\n\n if (!response.ok || result.error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Render error: ${result.error ?? 'Unknown error'}`,\n }],\n isError: true,\n };\n }\n\n return {\n content: [\n {\n type: 'image' as const,\n data: result.screenshot!.replace('data:image/png;base64,', ''),\n mimeType: 'image/png',\n },\n {\n type: 'text' as const,\n text: `Successfully rendered ${componentName} with props: ${JSON.stringify(props)}`,\n },\n ],\n };\n } catch (error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Failed to render component: ${error instanceof Error ? error.message : 'Unknown error'}. Make sure the Fragments dev server is running.`,\n }],\n isError: true,\n };\n }\n }\n\n // ================================================================\n // FIX — unchanged\n // ================================================================\n case TOOL_NAMES.fix: {\n const data = await loadSegments();\n const componentName = args?.component as string;\n const variantName = (args?.variant as string) ?? undefined;\n const fixType = (args?.fixType as 'token' | 'all') ?? 'all';\n\n if (!componentName) {\n throw new Error('component is required');\n }\n\n const segment = Object.values(data.segments).find(\n (s) => s.meta.name.toLowerCase() === componentName.toLowerCase()\n );\n\n if (!segment) {\n throw new Error(`Component \"${componentName}\" not found. Use fragments_discover to see available components.`);\n }\n\n const baseUrl = config.viewerUrl ?? 'http://localhost:6006';\n const fixUrl = `${baseUrl}/fragments/fix`;\n\n try {\n const response = await fetch(fixUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n component: componentName,\n variant: variantName,\n fixType,\n }),\n });\n\n interface FixResult {\n patches: Array<{ file: string; diff: string }>;\n summary: string;\n error?: string;\n }\n\n const result = await response.json() as FixResult;\n\n if (!response.ok || result.error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Fix generation error: ${result.error ?? 'Unknown error'}`,\n }],\n isError: true,\n };\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: JSON.stringify({\n component: componentName,\n variant: variantName ?? 'all',\n fixType,\n patches: result.patches,\n summary: result.summary,\n patchCount: result.patches.length,\n nextStep: result.patches.length > 0\n ? 'Apply patches using your editor or `patch` command, then run fragments_render with baseline:true to confirm fixes.'\n : undefined,\n }, null, 2),\n }],\n };\n } catch (error) {\n return {\n content: [{\n type: 'text' as const,\n text: `Failed to generate fixes: ${error instanceof Error ? error.message : 'Unknown error'}. Make sure the Fragments dev server is running.`,\n }],\n isError: true,\n };\n }\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n }),\n },\n ],\n isError: true,\n };\n }\n });\n\n // Cleanup on close\n server.onclose = async () => {\n if (browserPool) {\n await browserPool.shutdown();\n }\n };\n\n return server;\n}\n\n/**\n * Start the MCP server with stdio transport\n */\nexport async function startMcpServer(config: McpServerConfig): Promise<void> {\n const server = createMcpServer(config);\n const transport = new StdioServerTransport();\n\n await server.connect(transport);\n}\n","/**\n * Utility functions for the MCP server\n */\n\n/**\n * Extract specific fields from an object using dot notation paths.\n * E.g., projectFields(obj, ['meta.name', 'usage.when']) returns { meta: { name: ... }, usage: { when: ... } }\n *\n * @param obj - The source object to extract fields from\n * @param fields - Array of field paths (supports dot notation for nested fields)\n * @returns A new object containing only the requested fields\n */\nexport function projectFields<T extends Record<string, unknown>>(\n obj: T,\n fields: string[]\n): Partial<T> {\n if (!fields || fields.length === 0) {\n return obj;\n }\n\n const result: Record<string, unknown> = {};\n\n for (const field of fields) {\n const parts = field.split('.');\n let source: unknown = obj;\n let target = result;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const isLast = i === parts.length - 1;\n\n if (source === null || source === undefined || typeof source !== 'object') {\n break;\n }\n\n const sourceObj = source as Record<string, unknown>;\n const value = sourceObj[part];\n\n if (isLast) {\n // Set the final value\n target[part] = value;\n } else {\n // Create nested object if needed\n if (!(part in target)) {\n target[part] = {};\n }\n target = target[part] as Record<string, unknown>;\n source = value;\n }\n }\n }\n\n return result as Partial<T>;\n}\n","#!/usr/bin/env node\nimport { startMcpServer } from './mcp/server.js';\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nlet projectRoot = process.cwd();\nlet viewerUrl: string | undefined;\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--project-root' || arg === '-p') {\n projectRoot = args[++i] ?? projectRoot;\n } else if (arg === '--viewer-url' || arg === '-u') {\n viewerUrl = args[++i];\n } else if (arg === '--help' || arg === '-h') {\n console.log(`\nUsage: fragments-mcp [options]\n\nOptions:\n -p, --project-root <path> Project root directory (default: cwd)\n -u, --viewer-url <url> Viewer URL (default: http://localhost:6006)\n -h, --help Show this help message\n`);\n process.exit(0);\n }\n}\n\n// Start server\nstartMcpServer({\n projectRoot,\n viewerUrl,\n}).catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n});\n"],"mappings":"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","names":["args","segments","viewerUrl","baseUrl"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fragments-sdk/cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "CLI, MCP server, and dev tools for Fragments design system",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,308 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdirSync, writeFileSync, rmSync, realpathSync, symlinkSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { findFragmentsJson } from '../server.js';
6
+
7
+ /**
8
+ * Creates a temporary directory tree for testing findFragmentsJson.
9
+ * Uses realpathSync to normalize macOS /var -> /private/var symlinks,
10
+ * ensuring path comparisons work reliably.
11
+ */
12
+ function createTmpDir(): string {
13
+ const raw = join(tmpdir(), `fragments-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
14
+ mkdirSync(raw, { recursive: true });
15
+ return realpathSync(raw);
16
+ }
17
+
18
+ function writeJson(path: string, data: unknown): void {
19
+ writeFileSync(path, JSON.stringify(data));
20
+ }
21
+
22
+ describe('findFragmentsJson', () => {
23
+ let root: string;
24
+
25
+ beforeEach(() => {
26
+ root = createTmpDir();
27
+ });
28
+
29
+ afterEach(() => {
30
+ rmSync(root, { recursive: true, force: true });
31
+ });
32
+
33
+ describe('Phase 1: walk upward (library author flow)', () => {
34
+ it('finds fragments.json in the start directory', () => {
35
+ writeFileSync(join(root, 'fragments.json'), '{}');
36
+
37
+ const result = findFragmentsJson(root);
38
+ expect(result).toEqual([join(root, 'fragments.json')]);
39
+ });
40
+
41
+ it('finds fragments.json in a parent directory', () => {
42
+ const sub = join(root, 'packages', 'app');
43
+ mkdirSync(sub, { recursive: true });
44
+ writeFileSync(join(root, 'fragments.json'), '{}');
45
+
46
+ const result = findFragmentsJson(sub);
47
+ expect(result).toEqual([join(root, 'fragments.json')]);
48
+ });
49
+
50
+ it('returns empty array when no fragments.json exists anywhere', () => {
51
+ const sub = join(root, 'some', 'deep', 'path');
52
+ mkdirSync(sub, { recursive: true });
53
+
54
+ const result = findFragmentsJson(sub);
55
+ expect(result).toEqual([]);
56
+ });
57
+ });
58
+
59
+ describe('Phase 2: resolve deps with "fragments" field', () => {
60
+ it('finds fragments.json via dependency with "fragments" field', () => {
61
+ const depDir = join(root, 'node_modules', 'my-ui-lib');
62
+ mkdirSync(depDir, { recursive: true });
63
+
64
+ writeJson(join(root, 'package.json'), {
65
+ dependencies: { 'my-ui-lib': '^1.0.0' },
66
+ });
67
+ writeJson(join(depDir, 'package.json'), {
68
+ name: 'my-ui-lib',
69
+ fragments: 'fragments.json',
70
+ });
71
+ writeFileSync(join(depDir, 'fragments.json'), '{}');
72
+
73
+ const result = findFragmentsJson(root);
74
+ expect(result.length).toBe(1);
75
+ expect(result[0]).toBe(join(depDir, 'fragments.json'));
76
+ });
77
+
78
+ it('resolves custom fragments path from dependency', () => {
79
+ const depDir = join(root, 'node_modules', 'my-ui-lib');
80
+ mkdirSync(join(depDir, 'dist'), { recursive: true });
81
+
82
+ writeJson(join(root, 'package.json'), {
83
+ dependencies: { 'my-ui-lib': '^1.0.0' },
84
+ });
85
+ writeJson(join(depDir, 'package.json'), {
86
+ name: 'my-ui-lib',
87
+ fragments: 'dist/fragments.json',
88
+ });
89
+ writeFileSync(join(depDir, 'dist', 'fragments.json'), '{}');
90
+
91
+ const result = findFragmentsJson(root);
92
+ expect(result.length).toBe(1);
93
+ expect(result[0]).toBe(join(depDir, 'dist', 'fragments.json'));
94
+ });
95
+
96
+ it('finds fragments.json from devDependencies', () => {
97
+ const depDir = join(root, 'node_modules', 'my-ui-lib');
98
+ mkdirSync(depDir, { recursive: true });
99
+
100
+ writeJson(join(root, 'package.json'), {
101
+ devDependencies: { 'my-ui-lib': '^1.0.0' },
102
+ });
103
+ writeJson(join(depDir, 'package.json'), {
104
+ name: 'my-ui-lib',
105
+ fragments: 'fragments.json',
106
+ });
107
+ writeFileSync(join(depDir, 'fragments.json'), '{}');
108
+
109
+ const result = findFragmentsJson(root);
110
+ expect(result.length).toBe(1);
111
+ expect(result[0]).toBe(join(depDir, 'fragments.json'));
112
+ });
113
+
114
+ it('skips dependencies without "fragments" field', () => {
115
+ const depDir = join(root, 'node_modules', 'react');
116
+ mkdirSync(depDir, { recursive: true });
117
+
118
+ writeJson(join(root, 'package.json'), {
119
+ dependencies: { react: '^18.0.0' },
120
+ });
121
+ writeJson(join(depDir, 'package.json'), {
122
+ name: 'react',
123
+ });
124
+
125
+ const result = findFragmentsJson(root);
126
+ expect(result).toEqual([]);
127
+ });
128
+
129
+ it('skips dependency when fragments file does not exist', () => {
130
+ const depDir = join(root, 'node_modules', 'my-ui-lib');
131
+ mkdirSync(depDir, { recursive: true });
132
+
133
+ writeJson(join(root, 'package.json'), {
134
+ dependencies: { 'my-ui-lib': '^1.0.0' },
135
+ });
136
+ writeJson(join(depDir, 'package.json'), {
137
+ name: 'my-ui-lib',
138
+ fragments: 'fragments.json',
139
+ });
140
+ // Note: fragments.json not created
141
+
142
+ const result = findFragmentsJson(root);
143
+ expect(result).toEqual([]);
144
+ });
145
+
146
+ it('skips unresolvable dependencies gracefully', () => {
147
+ writeJson(join(root, 'package.json'), {
148
+ dependencies: { 'nonexistent-package': '^1.0.0' },
149
+ });
150
+
151
+ const result = findFragmentsJson(root);
152
+ expect(result).toEqual([]);
153
+ });
154
+
155
+ it('handles project with no package.json', () => {
156
+ const result = findFragmentsJson(root);
157
+ expect(result).toEqual([]);
158
+ });
159
+ });
160
+
161
+ describe('symlink resolution (pnpm-style)', () => {
162
+ it('follows symlinks to find fragments.json', () => {
163
+ // Simulate pnpm layout: real package in .pnpm, symlink in node_modules
164
+ const realDir = join(root, '.pnpm', 'my-ui-lib@1.0.0', 'node_modules', 'my-ui-lib');
165
+ const symlinkDir = join(root, 'node_modules', 'my-ui-lib');
166
+
167
+ mkdirSync(realDir, { recursive: true });
168
+ mkdirSync(join(root, 'node_modules'), { recursive: true });
169
+
170
+ writeJson(join(realDir, 'package.json'), {
171
+ name: 'my-ui-lib',
172
+ fragments: 'fragments.json',
173
+ });
174
+ writeFileSync(join(realDir, 'fragments.json'), '{}');
175
+
176
+ // Create symlink: node_modules/my-ui-lib -> .pnpm/.../my-ui-lib
177
+ symlinkSync(realDir, symlinkDir, 'dir');
178
+
179
+ writeJson(join(root, 'package.json'), {
180
+ dependencies: { 'my-ui-lib': '^1.0.0' },
181
+ });
182
+
183
+ const result = findFragmentsJson(root);
184
+ expect(result.length).toBe(1);
185
+ // require.resolve follows the symlink to the real path
186
+ expect(result[0]).toBe(join(realDir, 'fragments.json'));
187
+ });
188
+ });
189
+
190
+ describe('hoisted dependencies', () => {
191
+ it('finds fragments.json from a hoisted parent node_modules', () => {
192
+ // Monorepo layout: deps hoisted to root, app is in packages/app
193
+ const appDir = join(root, 'packages', 'app');
194
+ const hoistedDep = join(root, 'node_modules', 'my-ui-lib');
195
+
196
+ mkdirSync(appDir, { recursive: true });
197
+ mkdirSync(hoistedDep, { recursive: true });
198
+
199
+ writeJson(join(appDir, 'package.json'), {
200
+ dependencies: { 'my-ui-lib': '^1.0.0' },
201
+ });
202
+ writeJson(join(hoistedDep, 'package.json'), {
203
+ name: 'my-ui-lib',
204
+ fragments: 'fragments.json',
205
+ });
206
+ writeFileSync(join(hoistedDep, 'fragments.json'), '{}');
207
+
208
+ // createRequire resolves up the directory tree, so this should work
209
+ const result = findFragmentsJson(appDir);
210
+ expect(result.length).toBe(1);
211
+ expect(result[0]).toBe(join(hoistedDep, 'fragments.json'));
212
+ });
213
+ });
214
+
215
+ describe('deduplication', () => {
216
+ it('returns both local and dep fragments when they are different files', () => {
217
+ // fragments.json in root (found by walk-up) AND dep has its own
218
+ writeFileSync(join(root, 'fragments.json'), '{}');
219
+
220
+ const depDir = join(root, 'node_modules', 'my-ui-lib');
221
+ mkdirSync(depDir, { recursive: true });
222
+ writeJson(join(root, 'package.json'), {
223
+ dependencies: { 'my-ui-lib': '^1.0.0' },
224
+ });
225
+ writeJson(join(depDir, 'package.json'), {
226
+ name: 'my-ui-lib',
227
+ fragments: 'fragments.json',
228
+ });
229
+ writeFileSync(join(depDir, 'fragments.json'), '{}');
230
+
231
+ const result = findFragmentsJson(root);
232
+ // Walk-up finds root/fragments.json, dep resolution finds dep/fragments.json
233
+ expect(result.length).toBe(2);
234
+ expect(result).toContain(join(root, 'fragments.json'));
235
+ expect(result).toContain(join(depDir, 'fragments.json'));
236
+ });
237
+ });
238
+
239
+ describe('multiple dependencies', () => {
240
+ it('finds fragments.json from multiple dependencies', () => {
241
+ const dep1 = join(root, 'node_modules', 'ui-lib-a');
242
+ const dep2 = join(root, 'node_modules', 'ui-lib-b');
243
+ mkdirSync(dep1, { recursive: true });
244
+ mkdirSync(dep2, { recursive: true });
245
+
246
+ writeJson(join(root, 'package.json'), {
247
+ dependencies: { 'ui-lib-a': '^1.0.0' },
248
+ devDependencies: { 'ui-lib-b': '^2.0.0' },
249
+ });
250
+ writeJson(join(dep1, 'package.json'), {
251
+ name: 'ui-lib-a',
252
+ fragments: 'fragments.json',
253
+ });
254
+ writeFileSync(join(dep1, 'fragments.json'), '{}');
255
+ writeJson(join(dep2, 'package.json'), {
256
+ name: 'ui-lib-b',
257
+ fragments: 'fragments.json',
258
+ });
259
+ writeFileSync(join(dep2, 'fragments.json'), '{}');
260
+
261
+ const result = findFragmentsJson(root);
262
+ expect(result.length).toBe(2);
263
+ expect(result).toContain(join(dep1, 'fragments.json'));
264
+ expect(result).toContain(join(dep2, 'fragments.json'));
265
+ });
266
+
267
+ it('only includes deps that have "fragments" field', () => {
268
+ const uiLib = join(root, 'node_modules', 'ui-lib');
269
+ const react = join(root, 'node_modules', 'react');
270
+ mkdirSync(uiLib, { recursive: true });
271
+ mkdirSync(react, { recursive: true });
272
+
273
+ writeJson(join(root, 'package.json'), {
274
+ dependencies: { react: '^18.0.0', 'ui-lib': '^1.0.0' },
275
+ });
276
+ writeJson(join(react, 'package.json'), { name: 'react' });
277
+ writeJson(join(uiLib, 'package.json'), {
278
+ name: 'ui-lib',
279
+ fragments: 'fragments.json',
280
+ });
281
+ writeFileSync(join(uiLib, 'fragments.json'), '{}');
282
+
283
+ const result = findFragmentsJson(root);
284
+ expect(result.length).toBe(1);
285
+ expect(result[0]).toBe(join(uiLib, 'fragments.json'));
286
+ });
287
+ });
288
+
289
+ describe('scoped packages', () => {
290
+ it('resolves scoped package names like @scope/ui', () => {
291
+ const depDir = join(root, 'node_modules', '@my-scope', 'ui');
292
+ mkdirSync(depDir, { recursive: true });
293
+
294
+ writeJson(join(root, 'package.json'), {
295
+ dependencies: { '@my-scope/ui': '^1.0.0' },
296
+ });
297
+ writeJson(join(depDir, 'package.json'), {
298
+ name: '@my-scope/ui',
299
+ fragments: 'fragments.json',
300
+ });
301
+ writeFileSync(join(depDir, 'fragments.json'), '{}');
302
+
303
+ const result = findFragmentsJson(root);
304
+ expect(result.length).toBe(1);
305
+ expect(result[0]).toBe(join(depDir, 'fragments.json'));
306
+ });
307
+ });
308
+ });
package/src/mcp/server.ts CHANGED
@@ -32,6 +32,7 @@ async function getService(): Promise<ServiceModule> {
32
32
  import { readFile } from 'node:fs/promises';
33
33
  import { existsSync, readFileSync } from 'node:fs';
34
34
  import { join, dirname, resolve } from 'node:path';
35
+ import { createRequire } from 'node:module';
35
36
  import { projectFields } from './utils.js';
36
37
 
37
38
  /**
@@ -65,6 +66,63 @@ function filterPlaceholders(items: string[] | undefined): string[] {
65
66
  );
66
67
  }
67
68
 
69
+ /**
70
+ * Find fragments.json files:
71
+ * 1. Walk up from startDir (for library authors with a local build)
72
+ * 2. Read package.json deps and resolve packages with a "fragments" field
73
+ *
74
+ * Uses Node.js module resolution (createRequire) to handle all package
75
+ * managers: pnpm symlinks, yarn PnP, monorepo hoisting, etc.
76
+ */
77
+ export function findFragmentsJson(startDir: string): string[] {
78
+ const found: string[] = [];
79
+ const resolvedStart = resolve(startDir);
80
+
81
+ // 1. Walk upward from startDir (library author flow)
82
+ let dir = resolvedStart;
83
+ while (true) {
84
+ const candidate = join(dir, BRAND.outFile);
85
+ if (existsSync(candidate)) {
86
+ found.push(candidate);
87
+ break;
88
+ }
89
+ const parent = dirname(dir);
90
+ if (parent === dir) break;
91
+ dir = parent;
92
+ }
93
+
94
+ // 2. Read package.json and resolve deps with "fragments" field
95
+ const pkgJsonPath = join(resolvedStart, 'package.json');
96
+ if (existsSync(pkgJsonPath)) {
97
+ try {
98
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
99
+ const allDeps = {
100
+ ...pkgJson.dependencies,
101
+ ...pkgJson.devDependencies,
102
+ };
103
+ const localRequire = createRequire(join(resolvedStart, 'noop.js'));
104
+ for (const depName of Object.keys(allDeps)) {
105
+ try {
106
+ const depPkgPath = localRequire.resolve(`${depName}/package.json`);
107
+ const depPkg = JSON.parse(readFileSync(depPkgPath, 'utf-8'));
108
+ if (depPkg.fragments) {
109
+ const fragmentsPath = join(dirname(depPkgPath), depPkg.fragments);
110
+ if (existsSync(fragmentsPath) && !found.includes(fragmentsPath)) {
111
+ found.push(fragmentsPath);
112
+ }
113
+ }
114
+ } catch {
115
+ // Package not resolvable or unreadable, skip
116
+ }
117
+ }
118
+ } catch {
119
+ // No package.json or unreadable
120
+ }
121
+ }
122
+
123
+ return found;
124
+ }
125
+
68
126
  /**
69
127
  * MCP Server configuration
70
128
  */
@@ -282,60 +340,6 @@ export function createMcpServer(config: McpServerConfig): Server {
282
340
  let diffEngine: any = null;
283
341
  let isPoolWarming = false;
284
342
 
285
- /**
286
- * Find fragments.json files:
287
- * 1. Walk up from projectRoot (for library authors with a local build)
288
- * 2. Read package.json deps and resolve packages with a "fragments" field
289
- */
290
- function findFragmentsJson(startDir: string): string[] {
291
- const found: string[] = [];
292
- const resolvedStart = resolve(startDir);
293
-
294
- // 1. Walk upward from startDir (library author flow)
295
- let dir = resolvedStart;
296
- while (true) {
297
- const candidate = join(dir, BRAND.outFile);
298
- if (existsSync(candidate)) {
299
- found.push(candidate);
300
- break;
301
- }
302
- const parent = dirname(dir);
303
- if (parent === dir) break;
304
- dir = parent;
305
- }
306
-
307
- // 2. Read package.json and resolve deps with "fragments" field
308
- const pkgJsonPath = join(resolvedStart, 'package.json');
309
- if (existsSync(pkgJsonPath)) {
310
- try {
311
- const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
312
- const allDeps = {
313
- ...pkgJson.dependencies,
314
- ...pkgJson.devDependencies,
315
- };
316
- for (const depName of Object.keys(allDeps)) {
317
- const depPkgPath = join(resolvedStart, 'node_modules', depName, 'package.json');
318
- if (!existsSync(depPkgPath)) continue;
319
- try {
320
- const depPkg = JSON.parse(readFileSync(depPkgPath, 'utf-8'));
321
- if (depPkg.fragments) {
322
- const fragmentsPath = join(resolvedStart, 'node_modules', depName, depPkg.fragments);
323
- if (existsSync(fragmentsPath) && !found.includes(fragmentsPath)) {
324
- found.push(fragmentsPath);
325
- }
326
- }
327
- } catch {
328
- // Skip unreadable package
329
- }
330
- }
331
- } catch {
332
- // No package.json or unreadable
333
- }
334
- }
335
-
336
- return found;
337
- }
338
-
339
343
  async function loadSegments(): Promise<CompiledSegmentsFile> {
340
344
  if (segmentsData) {
341
345
  return segmentsData;