@fragments-sdk/cli 0.15.0 → 0.15.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/{ai-client-I6MDWNYA.js → ai-client-LSLQGOMM.js} +1 -2
- package/dist/bin.js +565 -548
- package/dist/bin.js.map +1 -1
- package/dist/chunk-5JF26E55.js +1255 -0
- package/dist/chunk-5JF26E55.js.map +1 -0
- package/dist/{chunk-XJQ5BIWI.js → chunk-6SQPP47U.js} +30 -314
- package/dist/chunk-6SQPP47U.js.map +1 -0
- package/dist/{chunk-65WSVDV5.js → chunk-HQ6A6DTV.js} +1386 -1097
- package/dist/chunk-HQ6A6DTV.js.map +1 -0
- package/dist/chunk-MHIBEEW4.js +511 -0
- package/dist/chunk-MHIBEEW4.js.map +1 -0
- package/dist/{chunk-CZD3AD4Q.js → chunk-ONUP6Z4W.js} +17 -6
- package/dist/chunk-ONUP6Z4W.js.map +1 -0
- package/dist/{codebase-scanner-VOTPXRYW.js → codebase-scanner-MQHUZC2G.js} +1 -2
- package/dist/{converter-JLINP7CJ.js → converter-7XM3Y6NJ.js} +1 -2
- package/dist/{converter-JLINP7CJ.js.map → converter-7XM3Y6NJ.js.map} +1 -1
- package/dist/core/index.js +0 -1
- package/dist/create-JVAU3YKN.js +852 -0
- package/dist/create-JVAU3YKN.js.map +1 -0
- package/dist/doctor-BDPMYYE6.js +385 -0
- package/dist/doctor-BDPMYYE6.js.map +1 -0
- package/dist/{generate-A4FP5426.js → generate-PVOLUAAC.js} +3 -4
- package/dist/{generate-A4FP5426.js.map → generate-PVOLUAAC.js.map} +1 -1
- package/dist/{govern-scan-UCBZR6D6.js → govern-scan-OYFZYOQW.js} +142 -9
- package/dist/govern-scan-OYFZYOQW.js.map +1 -0
- package/dist/index.d.ts +2 -22
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-HGSM35XA.js → init-SSGUSP7Z.js} +3 -4
- package/dist/{init-HGSM35XA.js.map → init-SSGUSP7Z.js.map} +1 -1
- package/dist/{init-cloud-MQ6GRJAZ.js → init-cloud-3DNKPWFB.js} +29 -4
- package/dist/{init-cloud-MQ6GRJAZ.js.map → init-cloud-3DNKPWFB.js.map} +1 -1
- package/dist/mcp-bin.js +1 -2
- package/dist/mcp-bin.js.map +1 -1
- package/dist/node-37AUE74M.js +65 -0
- package/dist/push-contracts-WY32TFP6.js +84 -0
- package/dist/push-contracts-WY32TFP6.js.map +1 -0
- package/dist/{scan-VNNKACG2.js → scan-PKSYSTRR.js} +5 -5
- package/dist/{scan-generate-TWRHNU5M.js → scan-generate-VY27PIOX.js} +8 -9
- package/dist/scan-generate-VY27PIOX.js.map +1 -0
- package/dist/{scanner-7LAZYPWZ.js → scanner-4KZNOXAK.js} +1 -2
- package/dist/{service-FHQU7YS7.js → service-QJGWUIVL.js} +16 -9
- package/dist/{snapshot-KQEQ6XHL.js → snapshot-WIJMEIFT.js} +1 -2
- package/dist/{snapshot-KQEQ6XHL.js.map → snapshot-WIJMEIFT.js.map} +1 -1
- package/dist/{static-viewer-63PG6FWY.js → static-viewer-7QIBQZRC.js} +1 -2
- package/dist/{test-UQYUCZIS.js → test-64Z5BKBA.js} +2 -3
- package/dist/{test-UQYUCZIS.js.map → test-64Z5BKBA.js.map} +1 -1
- package/dist/token-normalizer-TEPOVBPV.js +312 -0
- package/dist/token-normalizer-TEPOVBPV.js.map +1 -0
- package/dist/token-parser-32KOIOFN.js +22 -0
- package/dist/token-parser-32KOIOFN.js.map +1 -0
- package/dist/{tokens-6GYKDV6U.js → tokens-NZWFQIAB.js} +7 -7
- package/dist/{tokens-generate-VTZV5EEW.js → tokens-generate-5JQSJ27E.js} +1 -2
- package/dist/{tokens-generate-VTZV5EEW.js.map → tokens-generate-5JQSJ27E.js.map} +1 -1
- package/dist/tokens-push-HY3KO36V.js +148 -0
- package/dist/tokens-push-HY3KO36V.js.map +1 -0
- package/package.json +18 -16
- package/src/bin.ts +94 -1
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +1 -1
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +1 -1
- package/src/commands/__tests__/build-freshness.test.ts +231 -0
- package/src/commands/__tests__/create.test.ts +71 -0
- package/src/commands/__tests__/drift-sync.test.ts +1 -1
- package/src/commands/__tests__/govern.test.ts +258 -0
- package/src/commands/__tests__/init.test.ts +9 -1
- package/src/commands/__tests__/scan-generate.test.ts +1 -1
- package/src/commands/build.ts +54 -1
- package/src/commands/context.ts +1 -1
- package/src/commands/create.ts +590 -0
- package/src/commands/doctor.ts +3 -2
- package/src/commands/govern-scan.ts +187 -8
- package/src/commands/govern.ts +65 -2
- package/src/commands/init-cloud.ts +32 -4
- package/src/commands/push-contracts.ts +112 -0
- package/src/commands/scan-generate.ts +1 -1
- package/src/commands/scan.ts +13 -0
- package/src/commands/sync.ts +2 -2
- package/src/commands/tokens-push.ts +199 -0
- package/src/core/__tests__/token-resolver.test.ts +1 -1
- package/src/core/component-extractor.test.ts +1 -1
- package/src/core/drift-verifier.ts +1 -1
- package/src/core/extractor-adapter.ts +1 -1
- package/src/index.ts +3 -3
- package/src/migrate/fragment-to-contract.ts +2 -2
- package/src/service/index.ts +8 -0
- package/src/service/tailwind-v4-parser.ts +314 -0
- package/src/service/token-parser.ts +56 -0
- package/src/setup.ts +10 -39
- package/src/theme/__tests__/component-contrast.test.ts +2 -2
- package/src/theme/__tests__/serializer.test.ts +1 -1
- package/src/theme/generator.ts +30 -1
- package/src/theme/schema.ts +8 -0
- package/src/theme/serializer.ts +13 -9
- package/src/theme/types.ts +8 -0
- package/src/validators.ts +1 -2
- package/dist/chunk-65WSVDV5.js.map +0 -1
- package/dist/chunk-7WHVW72L.js +0 -2664
- package/dist/chunk-7WHVW72L.js.map +0 -1
- package/dist/chunk-CZD3AD4Q.js.map +0 -1
- package/dist/chunk-MN3TJ3D5.js +0 -695
- package/dist/chunk-MN3TJ3D5.js.map +0 -1
- package/dist/chunk-XJQ5BIWI.js.map +0 -1
- package/dist/chunk-Z7EY4VHE.js +0 -50
- package/dist/govern-scan-UCBZR6D6.js.map +0 -1
- package/dist/sass.node-4XJK6YBF.js +0 -130708
- package/dist/sass.node-4XJK6YBF.js.map +0 -1
- package/dist/scan-generate-TWRHNU5M.js.map +0 -1
- package/src/build.ts +0 -736
- package/src/core/auto-props.ts +0 -464
- package/src/core/component-extractor.ts +0 -1121
- package/src/core/token-resolver.ts +0 -155
- package/src/viewer/preview-adapter.ts +0 -116
- /package/dist/{ai-client-I6MDWNYA.js.map → ai-client-LSLQGOMM.js.map} +0 -0
- /package/dist/{chunk-Z7EY4VHE.js.map → codebase-scanner-MQHUZC2G.js.map} +0 -0
- /package/dist/{codebase-scanner-VOTPXRYW.js.map → node-37AUE74M.js.map} +0 -0
- /package/dist/{scan-VNNKACG2.js.map → scan-PKSYSTRR.js.map} +0 -0
- /package/dist/{scanner-7LAZYPWZ.js.map → scanner-4KZNOXAK.js.map} +0 -0
- /package/dist/{service-FHQU7YS7.js.map → service-QJGWUIVL.js.map} +0 -0
- /package/dist/{static-viewer-63PG6FWY.js.map → static-viewer-7QIBQZRC.js.map} +0 -0
- /package/dist/{tokens-6GYKDV6U.js.map → tokens-NZWFQIAB.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/create.ts","../src/theme/serializer.ts","../src/theme/schema.ts","../src/theme/generator.ts"],"sourcesContent":["/**\n * fragments create - Scaffold a new project with Fragments UI and a custom theme\n *\n * Mirrors the shadcn model: configure on the web (usefragments.com/create),\n * then `npx @fragments-sdk/cli create` bootstraps a project with that config.\n */\n\nimport { execSync } from 'node:child_process';\nimport { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport pc from 'picocolors';\nimport { BRAND } from '../core/index.js';\nimport { decompressTheme } from '../theme/serializer.js';\nimport { generateCssTokens, generateScssTokens } from '../theme/generator.js';\nimport type { ThemeConfig } from '../theme/types.js';\n\n// ============================================\n// Font Helpers\n// ============================================\n\n/**\n * Extract the primary font family name from a CSS font-stack string.\n * e.g. '\"Space Grotesk\", sans-serif' → 'Space Grotesk'\n */\nfunction extractFontFamily(cssFontStack: string): string | null {\n const match = cssFontStack.match(/^[\"']?([^\"',]+)[\"']?/);\n if (!match) return null;\n const name = match[1].trim();\n const generics = [\"sans-serif\", \"serif\", \"monospace\", \"cursive\", \"fantasy\", \"system-ui\"];\n if (generics.includes(name.toLowerCase())) return null;\n if (name.toLowerCase() === \"inter\") return null; // Inter is the default, no need to load\n return name;\n}\n\nfunction googleFontsUrl(familyName: string): string {\n return `https://fonts.googleapis.com/css2?family=${encodeURIComponent(familyName)}:wght@400;500;600;700&display=swap`;\n}\n\n// ============================================\n// Types\n// ============================================\n\nexport interface CreateOptions {\n name?: string;\n template?: 'nextjs' | 'vite';\n packageManager?: 'npm' | 'pnpm' | 'yarn' | 'bun';\n theme?: string;\n preset?: string;\n brand?: string;\n scss?: boolean;\n mcp?: boolean;\n yes?: boolean;\n noGit?: boolean;\n}\n\nexport interface CreateResult {\n success: boolean;\n projectDir?: string;\n error?: string;\n}\n\n// ============================================\n// Package Manager Detection\n// ============================================\n\nfunction detectPackageManager(): 'npm' | 'pnpm' | 'yarn' | 'bun' {\n const agent = process.env.npm_config_user_agent || '';\n if (agent.startsWith('pnpm')) return 'pnpm';\n if (agent.startsWith('yarn')) return 'yarn';\n if (agent.startsWith('bun')) return 'bun';\n return 'npm';\n}\n\nfunction getInstallCommand(pm: string): string {\n return pm === 'yarn' ? 'yarn add' : `${pm} add`;\n}\n\nfunction getDevInstallCommand(pm: string): string {\n return pm === 'yarn' ? 'yarn add -D' : `${pm} add -D`;\n}\n\nfunction getRunCommand(pm: string): string {\n return pm === 'npm' ? 'npm run' : pm;\n}\n\n// ============================================\n// Validation\n// ============================================\n\nfunction isValidProjectName(name: string): boolean {\n return /^[a-z0-9][a-z0-9._-]*$/.test(name);\n}\n\n// ============================================\n// Theme Resolution\n// ============================================\n\nconst PRESET_API_URL = 'https://canny-otter-874.convex.site/api/theme-presets';\n\nasync function fetchPreset(presetId: string): Promise<ThemeConfig | null> {\n try {\n const res = await fetch(`${PRESET_API_URL}?id=${encodeURIComponent(presetId)}`);\n if (!res.ok) return null;\n const theme = await res.json();\n if (!theme || !theme.name) return null;\n return theme as ThemeConfig;\n } catch {\n return null;\n }\n}\n\nasync function resolveTheme(options: CreateOptions): Promise<ThemeConfig | null> {\n if (options.preset) {\n console.log(pc.dim(` Fetching theme preset ${options.preset}...`));\n const theme = await fetchPreset(options.preset);\n if (!theme) {\n console.error(pc.red(`Error: Could not fetch preset \"${options.preset}\". It may have expired or the ID is invalid.`));\n return null;\n }\n return theme;\n }\n\n if (options.theme) {\n const decoded = decompressTheme(options.theme);\n if (!decoded) {\n console.error(pc.red('Error: Could not decode theme string. Make sure you copied it from usefragments.com/create'));\n return null;\n }\n return decoded;\n }\n\n if (options.brand) {\n return {\n name: 'custom',\n colors: {\n accent: options.brand,\n },\n };\n }\n\n return {\n name: 'default',\n colors: {\n accent: '#6366f1',\n },\n };\n}\n\n// ============================================\n// Templates\n// ============================================\n\nexport function generateNextjsLayout(themePath: string, theme?: ThemeConfig): string {\n const fontName = theme?.typography?.fontSans ? extractFontFamily(theme.typography.fontSans) : null;\n const fontUrl = fontName ? googleFontsUrl(fontName) : null;\n\n const htmlOpen = fontUrl\n ? ` <html lang=\"en\" suppressHydrationWarning>\n <head>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossOrigin=\"\" />\n <link href=\"${fontUrl}\" rel=\"stylesheet\" />\n </head>\n <body>`\n : ` <html lang=\"en\" suppressHydrationWarning>\n <body>`;\n\n return `import type { Metadata } from 'next';\nimport '@fragments-sdk/ui/styles';\nimport '${themePath}';\nimport { Providers } from './providers';\n\nexport const metadata: Metadata = {\n title: 'My App',\n description: 'Built with Fragments UI',\n};\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n${htmlOpen}\n <Providers>{children}</Providers>\n </body>\n </html>\n );\n}\n`;\n}\n\nexport function generateNextjsProviders(): string {\n return `'use client';\n\nimport type { ReactNode } from 'react';\nimport { ThemeProvider, TooltipProvider, ToastProvider } from '@fragments-sdk/ui';\n\nexport function Providers({ children }: { children: ReactNode }) {\n return (\n <ThemeProvider defaultMode=\"system\">\n <TooltipProvider>\n <ToastProvider>{children}</ToastProvider>\n </TooltipProvider>\n </ThemeProvider>\n );\n}\n`;\n}\n\nexport function generateNextjsPage(): string {\n return `'use client';\n\nimport { Button, Card, Stack, Text, Input } from '@fragments-sdk/ui';\n\nexport default function Home() {\n return (\n <main style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n <Card style={{ maxWidth: 480, width: '100%' }}>\n <Card.Header>\n <Card.Title>Welcome to Fragments</Card.Title>\n <Card.Description>Your app is ready. Start building something great.</Card.Description>\n </Card.Header>\n <Card.Body>\n <Stack gap={3}>\n <Input placeholder=\"Enter something...\" />\n <Stack direction=\"row\" gap={2}>\n <Button>Get Started</Button>\n <Button variant=\"secondary\">Learn More</Button>\n </Stack>\n </Stack>\n </Card.Body>\n </Card>\n </main>\n );\n}\n`;\n}\n\nfunction generateViteMain(themePath: string): string {\n return `import { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { ThemeProvider, TooltipProvider, ToastProvider } from '@fragments-sdk/ui';\nimport '@fragments-sdk/ui/styles';\nimport '${themePath}';\nimport App from './App';\n\ncreateRoot(document.getElementById('root')!).render(\n <StrictMode>\n <ThemeProvider defaultMode=\"system\">\n <TooltipProvider>\n <ToastProvider>\n <App />\n </ToastProvider>\n </TooltipProvider>\n </ThemeProvider>\n </StrictMode>,\n);\n`;\n}\n\nfunction generateViteApp(): string {\n return `import { Button, Card, Stack, Text, Input } from '@fragments-sdk/ui';\n\nfunction App() {\n return (\n <main style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n <Card style={{ maxWidth: 480, width: '100%' }}>\n <Card.Header>\n <Card.Title>Welcome to Fragments</Card.Title>\n <Card.Description>Your app is ready. Start building something great.</Card.Description>\n </Card.Header>\n <Card.Body>\n <Stack gap={3}>\n <Input placeholder=\"Enter something...\" />\n <Stack direction=\"row\" gap={2}>\n <Button>Get Started</Button>\n <Button variant=\"secondary\">Learn More</Button>\n </Stack>\n </Stack>\n </Card.Body>\n </Card>\n </main>\n );\n}\n\nexport default App;\n`;\n}\n\nfunction injectFontIntoViteHtml(projectDir: string, theme: ThemeConfig): void {\n const fontName = theme.typography?.fontSans ? extractFontFamily(theme.typography.fontSans) : null;\n if (!fontName) return;\n\n const indexPath = join(projectDir, \"index.html\");\n if (!existsSync(indexPath)) return;\n\n let html = readFileSync(indexPath, \"utf-8\");\n const fontLinks = [\n ' <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />',\n ' <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />',\n ` <link href=\"${googleFontsUrl(fontName)}\" rel=\"stylesheet\" />`,\n ].join(\"\\n\");\n html = html.replace(\"</head>\", `${fontLinks}\\n </head>`);\n writeFileSync(indexPath, html, \"utf-8\");\n}\n\n// ============================================\n// Scaffolding\n// ============================================\n\nasync function promptIfMissing(options: CreateOptions): Promise<CreateOptions> {\n const resolved = { ...options };\n\n if (!resolved.name) {\n if (resolved.yes) {\n resolved.name = 'my-app';\n } else {\n try {\n const { input } = await import('@inquirer/prompts');\n resolved.name = await input({\n message: 'Project name:',\n default: 'my-app',\n validate: (val) => isValidProjectName(val) || 'Use lowercase letters, numbers, hyphens, dots, underscores',\n });\n } catch {\n resolved.name = 'my-app';\n }\n }\n }\n\n if (!resolved.template && !resolved.yes) {\n try {\n const { select } = await import('@inquirer/prompts');\n resolved.template = await select({\n message: 'Framework:',\n choices: [\n { name: 'Next.js (App Router)', value: 'nextjs' as const },\n { name: 'Vite + React', value: 'vite' as const },\n ],\n default: 'nextjs',\n });\n } catch {\n resolved.template = 'nextjs';\n }\n }\n\n resolved.template = resolved.template || 'nextjs';\n resolved.packageManager = resolved.packageManager || detectPackageManager();\n\n return resolved;\n}\n\nfunction scaffoldFramework(name: string, template: string, pm: string): void {\n console.log(pc.cyan(`\\nScaffolding ${template === 'nextjs' ? 'Next.js' : 'Vite + React'} project...\\n`));\n\n if (template === 'nextjs') {\n const cmd = `npx create-next-app@latest ${name} --ts --app --src-dir --no-tailwind --no-eslint --import-alias \"@/*\" --yes`;\n execSync(cmd, { stdio: 'inherit' });\n } else {\n // Vite\n if (pm === 'bun') {\n execSync(`bun create vite ${name} --template react-ts`, { stdio: 'inherit' });\n } else {\n execSync(`npm create vite@latest ${name} -- --template react-ts`, { stdio: 'inherit' });\n }\n }\n}\n\nfunction installDeps(projectDir: string, pm: string, scss: boolean): void {\n console.log(pc.cyan('\\nInstalling Fragments UI...\\n'));\n\n const install = getInstallCommand(pm);\n execSync(`${install} @fragments-sdk/ui`, { cwd: projectDir, stdio: 'inherit' });\n\n if (scss) {\n const devInstall = getDevInstallCommand(pm);\n execSync(`${devInstall} sass`, { cwd: projectDir, stdio: 'inherit' });\n }\n}\n\nfunction writeThemeFile(projectDir: string, theme: ThemeConfig, scss: boolean, template: string): string {\n const stylesDir = join(projectDir, 'src', 'styles');\n mkdirSync(stylesDir, { recursive: true });\n\n const ext = scss ? 'scss' : 'css';\n const content = scss ? generateScssTokens(theme) : generateCssTokens(theme);\n const filePath = join(stylesDir, `theme.${ext}`);\n writeFileSync(filePath, content, 'utf-8');\n\n // Next.js layout is at src/app/layout.tsx → relative path is ../styles/theme.ext\n // Vite main is at src/main.tsx → relative path is ./styles/theme.ext\n if (template === 'nextjs') {\n return `../styles/theme.${ext}`;\n }\n return `./styles/theme.${ext}`;\n}\n\nexport function addNextTranspilePackages(projectDir: string): void {\n const configCandidates = ['next.config.ts', 'next.config.mjs', 'next.config.js'];\n\n for (const configFile of configCandidates) {\n const fullPath = join(projectDir, configFile);\n if (!existsSync(fullPath)) continue;\n\n const content = readFileSync(fullPath, 'utf-8');\n\n if (content.includes('transpilePackages') && content.includes('@fragments-sdk/ui')) {\n return;\n }\n\n if (content.includes('transpilePackages')) {\n return;\n }\n\n const patterns = [\n {\n search: /const\\s+\\w+\\s*(?::\\s*\\w+)?\\s*=\\s*\\{/,\n replacement: (match: string) => `${match}\\n transpilePackages: ['@fragments-sdk/ui'],`,\n },\n {\n search: /module\\.exports\\s*=\\s*\\{/,\n replacement: (match: string) => `${match}\\n transpilePackages: ['@fragments-sdk/ui'],`,\n },\n {\n search: /export\\s+default\\s*\\{/,\n replacement: (match: string) => `${match}\\n transpilePackages: ['@fragments-sdk/ui'],`,\n },\n ];\n\n for (const pattern of patterns) {\n if (!pattern.search.test(content)) continue;\n\n writeFileSync(\n fullPath,\n content.replace(pattern.search, pattern.replacement),\n 'utf-8',\n );\n return;\n }\n\n return;\n }\n}\n\nfunction rewriteAppFiles(projectDir: string, template: string, themePath: string, theme: ThemeConfig): void {\n if (template === 'nextjs') {\n // Rewrite layout.tsx\n const layoutPath = join(projectDir, 'src', 'app', 'layout.tsx');\n writeFileSync(layoutPath, generateNextjsLayout(themePath, theme), 'utf-8');\n\n const providersPath = join(projectDir, 'src', 'app', 'providers.tsx');\n writeFileSync(providersPath, generateNextjsProviders(), 'utf-8');\n\n // Rewrite page.tsx\n const pagePath = join(projectDir, 'src', 'app', 'page.tsx');\n writeFileSync(pagePath, generateNextjsPage(), 'utf-8');\n\n // Remove default page.module.css if it exists\n const moduleCssPath = join(projectDir, 'src', 'app', 'page.module.css');\n try {\n unlinkSync(moduleCssPath);\n } catch { /* doesn't exist, that's fine */ }\n\n // Remove globals.css if it exists (we use our own theme)\n const globalsCssPath = join(projectDir, 'src', 'app', 'globals.css');\n try {\n unlinkSync(globalsCssPath);\n } catch { /* doesn't exist */ }\n\n addNextTranspilePackages(projectDir);\n } else {\n // Vite: rewrite main.tsx and App.tsx\n const mainPath = join(projectDir, 'src', 'main.tsx');\n writeFileSync(mainPath, generateViteMain(themePath), 'utf-8');\n\n const appPath = join(projectDir, 'src', 'App.tsx');\n writeFileSync(appPath, generateViteApp(), 'utf-8');\n\n // Clean up default Vite files\n for (const file of ['src/App.css', 'src/index.css']) {\n try {\n unlinkSync(join(projectDir, file));\n } catch { /* doesn't exist */ }\n }\n\n injectFontIntoViteHtml(projectDir, theme);\n }\n}\n\nfunction initGit(projectDir: string): void {\n try {\n // create-next-app already inits git, so check first\n if (!existsSync(join(projectDir, '.git'))) {\n execSync('git init', { cwd: projectDir, stdio: 'ignore' });\n execSync('git add -A', { cwd: projectDir, stdio: 'ignore' });\n execSync('git commit -m \"Initial commit with Fragments UI\"', { cwd: projectDir, stdio: 'ignore' });\n }\n } catch {\n // Git not available — skip silently\n }\n}\n\nfunction configureMcp(projectDir: string): void {\n const mcpConfig = {\n mcpServers: {\n fragments: {\n command: 'npx',\n args: ['-y', '@fragments-sdk/cli', 'mcp'],\n },\n },\n };\n\n const mcpDir = join(projectDir, '.mcp');\n mkdirSync(mcpDir, { recursive: true });\n writeFileSync(join(mcpDir, 'config.json'), JSON.stringify(mcpConfig, null, 2), 'utf-8');\n}\n\n// ============================================\n// Main\n// ============================================\n\nexport async function create(options: CreateOptions): Promise<CreateResult> {\n console.log(pc.cyan(`\\n${BRAND.name} Create\\n`));\n\n // 1. Gather inputs\n const resolved = await promptIfMissing(options);\n const name = resolved.name!;\n const template = resolved.template!;\n const pm = resolved.packageManager!;\n\n // 2. Validate\n if (!isValidProjectName(name)) {\n return { success: false, error: `Invalid project name: ${name}. Use lowercase letters, numbers, hyphens, dots, underscores.` };\n }\n\n const projectDir = resolve(process.cwd(), name);\n if (existsSync(projectDir)) {\n return { success: false, error: `Directory \"${name}\" already exists.` };\n }\n\n // 3. Resolve theme\n const theme = await resolveTheme(resolved);\n if (!theme) {\n return { success: false, error: 'Invalid theme configuration.' };\n }\n\n // 4. Scaffold framework\n scaffoldFramework(name, template, pm);\n\n if (!existsSync(projectDir)) {\n return { success: false, error: 'Framework scaffolding failed — project directory was not created.' };\n }\n\n // 5. Install deps\n installDeps(projectDir, pm, !!resolved.scss);\n\n // 6. Write theme tokens\n const themePath = writeThemeFile(projectDir, theme, !!resolved.scss, template);\n\n // 7. Rewrite app files with providers + theme import\n rewriteAppFiles(projectDir, template, themePath, theme);\n\n // 8. MCP config\n if (resolved.mcp) {\n configureMcp(projectDir);\n console.log(pc.dim(' Configured MCP server for AI tooling'));\n }\n\n // 9. Git init\n if (!resolved.noGit) {\n initGit(projectDir);\n }\n\n // 10. Success message\n const run = getRunCommand(pm);\n console.log('');\n console.log(pc.green(' Project created successfully!'));\n console.log('');\n console.log(` ${pc.cyan('cd')} ${name}`);\n console.log(` ${pc.cyan(run)} dev`);\n console.log('');\n\n if (theme.name !== 'default') {\n console.log(pc.dim(` Theme \"${theme.name}\" applied with full token set.`));\n console.log(pc.dim(` Edit src/styles/theme.${resolved.scss ? 'scss' : 'css'} to customize.\\n`));\n }\n\n return { success: true, projectDir };\n}\n","/**\n * Theme Serialization\n *\n * Encodes/decodes theme configurations to/from URL-safe strings\n * using zlib compression and base64url encoding.\n */\n\nimport { deflateSync, inflateSync } from \"node:zlib\";\nimport { validateThemeConfig } from \"./schema.js\";\nimport type { ThemeConfig } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://usefragments.com/create\";\n\n/**\n * Convert a Buffer to base64url encoding (URL-safe base64)\n */\nfunction toBase64Url(buffer: Buffer): string {\n return buffer\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n}\n\n/**\n * Convert a base64url string to Buffer\n */\nfunction fromBase64Url(str: string): Buffer {\n // Restore standard base64 characters\n let base64 = str.replace(/-/g, \"+\").replace(/_/g, \"/\");\n\n // Add padding if needed\n const pad = base64.length % 4;\n if (pad) {\n base64 += \"=\".repeat(4 - pad);\n }\n\n return Buffer.from(base64, \"base64\");\n}\n\n/**\n * Compress a theme configuration to a URL-safe string\n *\n * Process: JSON → deflate → base64url\n *\n * @param config - Theme configuration to compress\n * @returns URL-safe encoded string\n */\nexport function compressTheme(config: ThemeConfig): string {\n const json = JSON.stringify(config);\n const compressed = deflateSync(Buffer.from(json, \"utf-8\"), { level: 9 });\n return toBase64Url(compressed);\n}\n\n/**\n * Decompress a URL-safe string back to theme configuration\n *\n * Process: base64url → inflate → JSON\n *\n * @param encoded - URL-safe encoded string\n * @returns Theme configuration or null if invalid\n */\nexport function decompressTheme(encoded: string): ThemeConfig | null {\n // Try zlib-compressed first (CLI native encoding)\n try {\n const buffer = fromBase64Url(encoded);\n const decompressed = inflateSync(buffer);\n const json = decompressed.toString(\"utf-8\");\n const parsed = JSON.parse(json);\n const result = validateThemeConfig(parsed);\n if (result.success) return result.data;\n } catch { /* not zlib-compressed */ }\n\n // Fall back to plain base64url JSON (browser/docs encoding)\n try {\n const buffer = fromBase64Url(encoded);\n const json = buffer.toString(\"utf-8\");\n const parsed = JSON.parse(json);\n const result = validateThemeConfig(parsed);\n if (result.success) return result.data;\n } catch { /* invalid */ }\n\n return null;\n}\n\n/**\n * Encode a theme configuration to a full URL with ?preset= parameter\n *\n * @param config - Theme configuration to encode\n * @param baseUrl - Base URL (default: https://fragments.dev/init)\n * @returns Full URL with encoded theme as preset parameter\n */\nexport function encodeThemeToUrl(\n config: ThemeConfig,\n baseUrl: string = DEFAULT_BASE_URL\n): string {\n const encoded = compressTheme(config);\n const url = new URL(baseUrl);\n url.searchParams.set(\"preset\", encoded);\n return url.toString();\n}\n\n/**\n * Decode a theme from a URL or raw encoded string\n *\n * Handles:\n * - Full URLs with ?preset= parameter\n * - Raw encoded strings (compressed theme data)\n *\n * @param input - URL or encoded string\n * @returns Theme configuration or null if invalid\n */\nexport function decodeThemeFromUrl(input: string): ThemeConfig | null {\n // Try to parse as URL first\n try {\n const url = new URL(input);\n const preset = url.searchParams.get(\"preset\");\n if (preset) {\n return decompressTheme(preset);\n }\n // URL parsed but no preset param\n return null;\n } catch {\n // Not a valid URL, try as raw encoded string\n return decompressTheme(input);\n }\n}\n","/**\n * Theme Configuration Zod Schemas\n *\n * Provides validation for theme configuration objects\n */\n\nimport { z } from \"zod\";\nimport type { ThemeConfig } from \"./types.js\";\n\n/**\n * Regex patterns for color validation\n */\nconst HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\nconst RGB_COLOR_REGEX = /^rgba?\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*(,\\s*(0|1|0?\\.\\d+))?\\s*\\)$/;\nconst HSL_COLOR_REGEX = /^hsla?\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}%\\s*,\\s*\\d{1,3}%\\s*(,\\s*(0|1|0?\\.\\d+))?\\s*\\)$/;\n\n/**\n * CSS color string validator\n */\nconst colorSchema = z.string().refine(\n (val) => {\n return (\n HEX_COLOR_REGEX.test(val) ||\n RGB_COLOR_REGEX.test(val) ||\n HSL_COLOR_REGEX.test(val)\n );\n },\n { message: \"Invalid color format. Use hex (#rrggbb), rgb(), rgba(), hsl(), or hsla()\" }\n);\n\n/**\n * CSS size value validator (px, rem, em, etc.)\n */\nconst sizeSchema = z.string().refine(\n (val) => {\n // Match number followed by unit, or just a number (for unitless values like 9999px)\n return /^-?\\d*\\.?\\d+(px|rem|em|%|vw|vh)?$/.test(val);\n },\n { message: \"Invalid size format. Use px, rem, em, %, vw, or vh\" }\n);\n\n/**\n * Shadow value validator (more permissive for complex shadow syntax)\n */\nconst shadowSchema = z.string();\n\n/**\n * Font stack validator\n */\nconst fontStackSchema = z.string();\n\n/**\n * Font weight validator (100-900 in increments of 100)\n */\nconst fontWeightSchema = z.number().int().min(100).max(900);\n\n/**\n * Theme colors schema\n */\nexport const themeColorsSchema = z.object({\n accent: colorSchema.optional(),\n accentHover: colorSchema.optional(),\n accentActive: colorSchema.optional(),\n danger: colorSchema.optional(),\n dangerHover: colorSchema.optional(),\n success: colorSchema.optional(),\n warning: colorSchema.optional(),\n info: colorSchema.optional(),\n dangerBg: colorSchema.optional(),\n successBg: colorSchema.optional(),\n warningBg: colorSchema.optional(),\n infoBg: colorSchema.optional(),\n}).strict();\n\n/**\n * Theme surfaces schema\n */\nexport const themeSurfacesSchema = z.object({\n bgPrimary: colorSchema.optional(),\n bgSecondary: colorSchema.optional(),\n bgTertiary: colorSchema.optional(),\n bgElevated: colorSchema.optional(),\n bgHover: colorSchema.optional(),\n bgActive: colorSchema.optional(),\n}).strict();\n\n/**\n * Theme text schema\n */\nexport const themeTextSchema = z.object({\n primary: colorSchema.optional(),\n secondary: colorSchema.optional(),\n tertiary: colorSchema.optional(),\n inverse: colorSchema.optional(),\n}).strict();\n\n/**\n * Theme borders schema\n */\nexport const themeBordersSchema = z.object({\n default: colorSchema.optional(),\n strong: colorSchema.optional(),\n}).strict();\n\n/**\n * Theme typography schema\n */\nexport const themeTypographySchema = z.object({\n fontSans: fontStackSchema.optional(),\n fontMono: fontStackSchema.optional(),\n fontWeightNormal: fontWeightSchema.optional(),\n fontWeightMedium: fontWeightSchema.optional(),\n fontWeightSemibold: fontWeightSchema.optional(),\n}).strict();\n\n/**\n * Theme radius schema\n */\nexport const themeRadiusSchema = z.object({\n sm: sizeSchema.optional(),\n md: sizeSchema.optional(),\n lg: sizeSchema.optional(),\n full: sizeSchema.optional(),\n}).strict();\n\n/**\n * Theme shadows schema\n */\nexport const themeShadowsSchema = z.object({\n sm: shadowSchema.optional(),\n md: shadowSchema.optional(),\n}).strict();\n\n/**\n * Theme dark mode schema\n */\nexport const themeDarkModeSchema = z.object({\n surfaces: themeSurfacesSchema.optional(),\n text: themeTextSchema.optional(),\n borders: themeBordersSchema.optional(),\n shadows: themeShadowsSchema.optional(),\n accent: colorSchema.optional(),\n accentHover: colorSchema.optional(),\n accentActive: colorSchema.optional(),\n dangerBg: colorSchema.optional(),\n successBg: colorSchema.optional(),\n warningBg: colorSchema.optional(),\n infoBg: colorSchema.optional(),\n backdrop: colorSchema.optional(),\n dangerText: colorSchema.optional(),\n successText: colorSchema.optional(),\n warningText: colorSchema.optional(),\n infoText: colorSchema.optional(),\n}).strict();\n\n/**\n * Complete theme configuration schema\n */\nexport const themeConfigSchema = z.object({\n name: z.string().min(1, \"Theme name is required\"),\n version: z.string().optional(),\n extends: z.string().optional(),\n colors: themeColorsSchema.optional(),\n surfaces: themeSurfacesSchema.optional(),\n text: themeTextSchema.optional(),\n borders: themeBordersSchema.optional(),\n typography: themeTypographySchema.optional(),\n radius: themeRadiusSchema.optional(),\n shadows: themeShadowsSchema.optional(),\n dark: themeDarkModeSchema.optional(),\n density: z.enum(['compact', 'default', 'relaxed']).optional(),\n}).strict();\n\n/**\n * Type for the inferred schema\n */\nexport type ThemeConfigInput = z.input<typeof themeConfigSchema>;\nexport type ThemeConfigOutput = z.output<typeof themeConfigSchema>;\n\n/**\n * Validation result type\n */\nexport type ThemeValidationResult =\n | { success: true; data: ThemeConfig }\n | { success: false; error: z.ZodError };\n\n/**\n * Validate a theme configuration object\n *\n * @param config - The theme configuration to validate\n * @returns Validation result with either the parsed data or error details\n */\nexport function validateThemeConfig(config: unknown): ThemeValidationResult {\n const result = themeConfigSchema.safeParse(config);\n\n if (result.success) {\n return { success: true, data: result.data as ThemeConfig };\n }\n\n return { success: false, error: result.error };\n}\n","/**\n * Theme Token Generator\n *\n * Generates SCSS and CSS token files from theme configurations\n */\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n ThemeConfig,\n TokenGeneratorOptions,\n TokenGeneratorResult,\n ContrastPair,\n ContrastWarning,\n ContrastValidationResult,\n} from \"./types.js\";\nimport {\n parseColor,\n contrastRatio,\n meetsAA as checkAA,\n meetsAAA as checkAAA,\n} from \"./contrast.js\";\n\nconst DEFAULT_FILE_PREFIX = \"_theme-tokens\";\n\n/**\n * Token mapping from ThemeConfig structure to SCSS variable names\n */\nconst TOKEN_MAPPINGS = {\n colors: {\n accent: \"fui-color-accent\",\n accentHover: \"fui-color-accent-hover\",\n accentActive: \"fui-color-accent-active\",\n danger: \"fui-color-danger\",\n dangerHover: \"fui-color-danger-hover\",\n success: \"fui-color-success\",\n warning: \"fui-color-warning\",\n info: \"fui-color-info\",\n dangerBg: \"fui-color-danger-bg\",\n successBg: \"fui-color-success-bg\",\n warningBg: \"fui-color-warning-bg\",\n infoBg: \"fui-color-info-bg\",\n dangerText: \"fui-color-danger-text\",\n successText: \"fui-color-success-text\",\n warningText: \"fui-color-warning-text\",\n infoText: \"fui-color-info-text\",\n },\n surfaces: {\n bgPrimary: \"fui-bg-primary\",\n bgSecondary: \"fui-bg-secondary\",\n bgTertiary: \"fui-bg-tertiary\",\n bgElevated: \"fui-bg-elevated\",\n bgHover: \"fui-bg-hover\",\n bgActive: \"fui-bg-active\",\n },\n text: {\n primary: \"fui-text-primary\",\n secondary: \"fui-text-secondary\",\n tertiary: \"fui-text-tertiary\",\n inverse: \"fui-text-inverse\",\n },\n borders: {\n default: \"fui-border\",\n strong: \"fui-border-strong\",\n },\n typography: {\n fontSans: \"fui-font-sans\",\n fontMono: \"fui-font-mono\",\n fontWeightNormal: \"fui-font-weight-normal\",\n fontWeightMedium: \"fui-font-weight-medium\",\n fontWeightSemibold: \"fui-font-weight-semibold\",\n },\n radius: {\n sm: \"fui-radius-sm\",\n md: \"fui-radius-md\",\n lg: \"fui-radius-lg\",\n full: \"fui-radius-full\",\n },\n shadows: {\n sm: \"fui-shadow-sm\",\n md: \"fui-shadow-md\",\n },\n} as const;\n\n/**\n * Dark mode token mappings\n */\nconst DARK_TOKEN_MAPPINGS = {\n surfaces: {\n bgPrimary: \"fui-dark-bg-primary\",\n bgSecondary: \"fui-dark-bg-secondary\",\n bgTertiary: \"fui-dark-bg-tertiary\",\n bgElevated: \"fui-dark-bg-elevated\",\n bgHover: \"fui-dark-bg-hover\",\n bgActive: \"fui-dark-bg-active\",\n },\n text: {\n primary: \"fui-dark-text-primary\",\n secondary: \"fui-dark-text-secondary\",\n tertiary: \"fui-dark-text-tertiary\",\n inverse: \"fui-dark-text-inverse\",\n },\n borders: {\n default: \"fui-dark-border\",\n strong: \"fui-dark-border-strong\",\n },\n shadows: {\n sm: \"fui-dark-shadow-sm\",\n md: \"fui-dark-shadow-md\",\n },\n // Direct dark mode properties\n accent: \"fui-dark-color-accent\",\n accentHover: \"fui-dark-color-accent-hover\",\n accentActive: \"fui-dark-color-accent-active\",\n dangerBg: \"fui-dark-color-danger-bg\",\n successBg: \"fui-dark-color-success-bg\",\n warningBg: \"fui-dark-color-warning-bg\",\n infoBg: \"fui-dark-color-info-bg\",\n dangerText: \"fui-dark-color-danger-text\",\n successText: \"fui-dark-color-success-text\",\n warningText: \"fui-dark-color-warning-text\",\n infoText: \"fui-dark-color-info-text\",\n backdrop: \"fui-dark-backdrop\",\n} as const;\n\n/**\n * Generate tokens for a category\n */\nfunction generateCategoryTokens(\n config: ThemeConfig,\n categoryKey: keyof typeof TOKEN_MAPPINGS,\n format: \"scss\" | \"css\"\n): string[] {\n const category = config[categoryKey];\n if (!category) return [];\n\n const mappings = TOKEN_MAPPINGS[categoryKey];\n const tokens: string[] = [];\n\n for (const [key, varName] of Object.entries(mappings)) {\n const value = (category as Record<string, unknown>)[key];\n if (value !== undefined) {\n if (format === \"scss\") {\n tokens.push(`$${varName}: ${value} !default;`);\n } else {\n tokens.push(` --${varName}: ${value};`);\n }\n }\n }\n\n return tokens;\n}\n\n/**\n * Generate dark mode tokens\n */\nfunction generateDarkTokens(\n config: ThemeConfig,\n format: \"scss\" | \"css\"\n): string[] {\n if (!config.dark) return [];\n\n const tokens: string[] = [];\n\n // Handle nested categories\n const nestedCategories = [\"surfaces\", \"text\", \"borders\", \"shadows\"] as const;\n for (const category of nestedCategories) {\n const categoryData = config.dark[category];\n if (!categoryData) continue;\n\n const mappings = DARK_TOKEN_MAPPINGS[category];\n for (const [key, varName] of Object.entries(mappings)) {\n const value = (categoryData as Record<string, unknown>)[key];\n if (value !== undefined) {\n if (format === \"scss\") {\n tokens.push(`$${varName}: ${value} !default;`);\n } else {\n tokens.push(` --${varName.replace(\"fui-dark-\", \"fui-\")}: ${value};`);\n }\n }\n }\n }\n\n // Handle direct dark mode properties\n const directProps = [\"accent\", \"accentHover\", \"accentActive\", \"dangerBg\", \"successBg\", \"warningBg\", \"infoBg\", \"dangerText\", \"successText\", \"warningText\", \"infoText\", \"backdrop\"] as const;\n for (const prop of directProps) {\n const value = config.dark[prop];\n if (value !== undefined) {\n const varName = DARK_TOKEN_MAPPINGS[prop];\n if (format === \"scss\") {\n tokens.push(`$${varName}: ${value} !default;`);\n } else {\n // For CSS, use the light mode variable name in dark context\n const cssVarName = varName.replace(\"fui-dark-color-\", \"fui-color-\").replace(\"fui-dark-\", \"fui-\");\n tokens.push(` --${cssVarName}: ${value};`);\n }\n }\n }\n\n return tokens;\n}\n\n/**\n * Validate contrast across all text/surface token pairs in a theme.\n *\n * Returns `ContrastValidationResult` with every evaluated pair plus\n * errors (fails AA) and warnings (passes AA, fails AAA).\n */\nexport function validateContrast(config: ThemeConfig): ContrastValidationResult {\n const pairs: ContrastPair[] = [];\n const warnings: ContrastWarning[] = [];\n const errors: ContrastWarning[] = [];\n\n const textTokens = [\n { key: 'primary', token: 'text.primary' },\n { key: 'secondary', token: 'text.secondary' },\n { key: 'tertiary', token: 'text.tertiary' },\n ] as const;\n\n const surfaceTokens = [\n { key: 'bgPrimary', token: 'surfaces.bgPrimary' },\n { key: 'bgSecondary', token: 'surfaces.bgSecondary' },\n { key: 'bgTertiary', token: 'surfaces.bgTertiary' },\n { key: 'bgElevated', token: 'surfaces.bgElevated' },\n ] as const;\n\n // -- Light mode matrix --\n for (const text of textTokens) {\n const textColor = config.text?.[text.key];\n if (!textColor) continue;\n\n for (const surface of surfaceTokens) {\n const surfaceColor = config.surfaces?.[surface.key];\n if (!surfaceColor) continue;\n\n try {\n const fg = parseColor(textColor);\n const bg = parseColor(surfaceColor);\n const ratio = contrastRatio(fg, bg);\n const aa = checkAA(ratio);\n const aaa = checkAAA(ratio);\n\n const pair: ContrastPair = {\n textToken: text.token,\n surfaceToken: surface.token,\n textColor,\n surfaceColor,\n ratio: Math.round(ratio * 100) / 100,\n meetsAA: aa,\n meetsAAA: aaa,\n mode: 'light',\n };\n pairs.push(pair);\n\n if (!aa) {\n errors.push({\n message: `${text.token} (${textColor}) on ${surface.token} (${surfaceColor}) — ${pair.ratio}:1 — fails AA (need 4.5:1)`,\n pair,\n severity: 'error',\n });\n } else if (!aaa) {\n warnings.push({\n message: `${text.token} (${textColor}) on ${surface.token} (${surfaceColor}) — ${pair.ratio}:1 — passes AA but fails AAA (need 7:1)`,\n pair,\n severity: 'warning',\n });\n }\n } catch {\n // Skip unparseable colors (e.g. rgba with alpha)\n }\n }\n }\n\n // inverse text on accent\n if (config.text?.inverse && config.colors?.accent) {\n try {\n const fg = parseColor(config.text.inverse);\n const bg = parseColor(config.colors.accent);\n const ratio = contrastRatio(fg, bg);\n const aa = checkAA(ratio);\n const aaa = checkAAA(ratio);\n\n const pair: ContrastPair = {\n textToken: 'text.inverse',\n surfaceToken: 'colors.accent',\n textColor: config.text.inverse,\n surfaceColor: config.colors.accent,\n ratio: Math.round(ratio * 100) / 100,\n meetsAA: aa,\n meetsAAA: aaa,\n mode: 'light',\n };\n pairs.push(pair);\n\n if (!aa) {\n errors.push({\n message: `text.inverse (${config.text.inverse}) on colors.accent (${config.colors.accent}) — ${pair.ratio}:1 — fails AA`,\n pair,\n severity: 'error',\n });\n } else if (!aaa) {\n warnings.push({\n message: `text.inverse (${config.text.inverse}) on colors.accent (${config.colors.accent}) — ${pair.ratio}:1 — passes AA but fails AAA`,\n pair,\n severity: 'warning',\n });\n }\n } catch {\n // skip\n }\n }\n\n // -- Dark mode matrix --\n if (config.dark) {\n const darkTextTokens = [\n { key: 'primary' as const, token: 'dark.text.primary' },\n { key: 'secondary' as const, token: 'dark.text.secondary' },\n { key: 'tertiary' as const, token: 'dark.text.tertiary' },\n ];\n\n const darkSurfaceTokens = [\n { key: 'bgPrimary' as const, token: 'dark.surfaces.bgPrimary' },\n { key: 'bgSecondary' as const, token: 'dark.surfaces.bgSecondary' },\n { key: 'bgTertiary' as const, token: 'dark.surfaces.bgTertiary' },\n { key: 'bgElevated' as const, token: 'dark.surfaces.bgElevated' },\n ];\n\n for (const text of darkTextTokens) {\n const textColor = config.dark.text?.[text.key] ?? config.text?.[text.key];\n if (!textColor) continue;\n\n for (const surface of darkSurfaceTokens) {\n const surfaceColor = config.dark.surfaces?.[surface.key] ?? config.surfaces?.[surface.key];\n if (!surfaceColor) continue;\n\n try {\n const fg = parseColor(textColor);\n const bg = parseColor(surfaceColor);\n const ratio = contrastRatio(fg, bg);\n const aa = checkAA(ratio);\n const aaa = checkAAA(ratio);\n\n const pair: ContrastPair = {\n textToken: text.token,\n surfaceToken: surface.token,\n textColor,\n surfaceColor,\n ratio: Math.round(ratio * 100) / 100,\n meetsAA: aa,\n meetsAAA: aaa,\n mode: 'dark',\n };\n pairs.push(pair);\n\n if (!aa) {\n errors.push({\n message: `${text.token} (${textColor}) on ${surface.token} (${surfaceColor}) — ${pair.ratio}:1 — fails AA`,\n pair,\n severity: 'error',\n });\n } else if (!aaa) {\n warnings.push({\n message: `${text.token} (${textColor}) on ${surface.token} (${surfaceColor}) — ${pair.ratio}:1 — passes AA but fails AAA`,\n pair,\n severity: 'warning',\n });\n }\n } catch {\n // skip\n }\n }\n }\n }\n\n return {\n pairs,\n warnings,\n errors,\n passed: errors.length === 0,\n };\n}\n\n/**\n * Generate SCSS tokens from a theme configuration\n *\n * @param config - Theme configuration\n * @returns SCSS content string\n */\nexport function generateScssTokens(config: ThemeConfig): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"// Auto-generated by @fragments-sdk/cli\");\n lines.push(`// Theme: ${config.name}`);\n if (config.version) {\n lines.push(`// Version: ${config.version}`);\n }\n lines.push(\"\");\n\n // Colors\n const colorTokens = generateCategoryTokens(config, \"colors\", \"scss\");\n if (colorTokens.length > 0) {\n lines.push(\"// Colors\");\n lines.push(...colorTokens);\n lines.push(\"\");\n }\n\n // Surfaces\n const surfaceTokens = generateCategoryTokens(config, \"surfaces\", \"scss\");\n if (surfaceTokens.length > 0) {\n lines.push(\"// Surfaces\");\n lines.push(...surfaceTokens);\n lines.push(\"\");\n }\n\n // Text\n const textTokens = generateCategoryTokens(config, \"text\", \"scss\");\n if (textTokens.length > 0) {\n lines.push(\"// Text\");\n lines.push(...textTokens);\n lines.push(\"\");\n }\n\n // Borders\n const borderTokens = generateCategoryTokens(config, \"borders\", \"scss\");\n if (borderTokens.length > 0) {\n lines.push(\"// Borders\");\n lines.push(...borderTokens);\n if (config.borders?.default) {\n lines.push(`$fui-border-default: ${config.borders.default} !default;`);\n }\n lines.push(\"\");\n }\n\n // Typography\n const typographyTokens = generateCategoryTokens(config, \"typography\", \"scss\");\n if (typographyTokens.length > 0) {\n lines.push(\"// Typography\");\n lines.push(...typographyTokens);\n lines.push(\"\");\n }\n\n // Border Radius\n const radiusTokens = generateCategoryTokens(config, \"radius\", \"scss\");\n if (radiusTokens.length > 0) {\n lines.push(\"// Border Radius\");\n lines.push(...radiusTokens);\n lines.push(\"\");\n }\n\n // Shadows\n const shadowTokens = generateCategoryTokens(config, \"shadows\", \"scss\");\n if (shadowTokens.length > 0) {\n lines.push(\"// Shadows\");\n lines.push(...shadowTokens);\n lines.push(\"\");\n }\n\n // Density\n if (config.density) {\n lines.push(\"// Density\");\n lines.push(`$fui-density: \"${config.density}\" !default;`);\n lines.push(\"\");\n }\n\n // Dark mode\n const darkTokens = generateDarkTokens(config, \"scss\");\n if (darkTokens.length > 0) {\n lines.push(\"// Dark Mode\");\n lines.push(...darkTokens);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate CSS custom properties from a theme configuration\n *\n * @param config - Theme configuration\n * @returns CSS content string\n */\nexport function generateCssTokens(config: ThemeConfig): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"/* Auto-generated by @fragments-sdk/cli */\");\n lines.push(`/* Theme: ${config.name} */`);\n if (config.version) {\n lines.push(`/* Version: ${config.version} */`);\n }\n lines.push(\"\");\n\n // Collect all light mode tokens\n const lightTokens: string[] = [];\n\n const categories = [\"colors\", \"surfaces\", \"text\", \"borders\", \"typography\", \"radius\", \"shadows\"] as const;\n for (const category of categories) {\n const tokens = generateCategoryTokens(config, category, \"css\");\n lightTokens.push(...tokens);\n }\n\n // Emit --fui-border-default alias (components reference both names)\n if (config.borders?.default) {\n lightTokens.push(` --fui-border-default: ${config.borders.default};`);\n }\n\n // Density\n if (config.density) {\n lightTokens.push(` --fui-density: ${config.density};`);\n }\n\n if (lightTokens.length > 0) {\n lines.push(\":root {\");\n lines.push(...lightTokens);\n lines.push(\"}\");\n lines.push(\"\");\n }\n\n // Dark mode\n const darkTokens = generateDarkTokens(config, \"css\");\n\n // Border-default alias for dark mode\n if (config.dark?.borders?.default) {\n darkTokens.push(` --fui-border-default: ${config.dark.borders.default};`);\n }\n\n if (darkTokens.length > 0) {\n lines.push(':root.dark,');\n lines.push(':root[data-theme=\"dark\"] {');\n lines.push(...darkTokens);\n lines.push(\"}\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate token files from a theme configuration\n *\n * @param config - Theme configuration\n * @param options - Generator options\n * @returns Result with file paths or error\n */\nexport async function generateTokenFiles(\n config: ThemeConfig,\n options: TokenGeneratorOptions\n): Promise<TokenGeneratorResult> {\n const { format, outputDir, filePrefix = DEFAULT_FILE_PREFIX } = options;\n\n try {\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n const result: TokenGeneratorResult = { success: true };\n\n // Run contrast validation (non-blocking)\n const contrastResult = validateContrast(config);\n result.contrastValidation = contrastResult;\n\n if (contrastResult.errors.length > 0) {\n for (const err of contrastResult.errors) {\n console.warn(`[contrast] ERROR: ${err.message}`);\n }\n }\n if (contrastResult.warnings.length > 0) {\n for (const warn of contrastResult.warnings) {\n console.warn(`[contrast] WARNING: ${warn.message}`);\n }\n }\n\n // Generate SCSS if requested\n if (format === \"scss\" || format === \"both\") {\n const scssContent = generateScssTokens(config);\n const scssPath = join(outputDir, `${filePrefix}.scss`);\n await writeFile(scssPath, scssContent, \"utf-8\");\n result.scssPath = scssPath;\n }\n\n // Generate CSS if requested\n if (format === \"css\" || format === \"both\") {\n const cssContent = generateCssTokens(config);\n const cssPath = join(outputDir, `${filePrefix}.css`);\n await writeFile(cssPath, cssContent, \"utf-8\");\n result.cssPath = cssPath;\n }\n\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n}\n"],"mappings":"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","names":["join","join"]}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-D2CDBRNU.js";
|
|
3
|
+
import {
|
|
4
|
+
BRAND
|
|
5
|
+
} from "./chunk-32LIWN2P.js";
|
|
6
|
+
|
|
7
|
+
// src/commands/doctor.ts
|
|
8
|
+
import { readFile, access } from "fs/promises";
|
|
9
|
+
import { join, resolve } from "path";
|
|
10
|
+
import pc from "picocolors";
|
|
11
|
+
import { NEUTRAL_PALETTES } from "@fragments-sdk/viewer/docs-data";
|
|
12
|
+
var VALID_NEUTRALS = NEUTRAL_PALETTES.map((p) => p.name);
|
|
13
|
+
var VALID_DENSITIES = ["compact", "default", "relaxed"];
|
|
14
|
+
var VALID_RADII = ["sharp", "subtle", "default", "rounded", "pill"];
|
|
15
|
+
async function checkPackageInstalled(root) {
|
|
16
|
+
try {
|
|
17
|
+
const pkgPath = join(root, "package.json");
|
|
18
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
19
|
+
const pkg = JSON.parse(content);
|
|
20
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21
|
+
if (allDeps["@fragments-sdk/ui"]) {
|
|
22
|
+
return {
|
|
23
|
+
name: "Package installed",
|
|
24
|
+
status: "pass",
|
|
25
|
+
message: `@fragments-sdk/ui ${allDeps["@fragments-sdk/ui"]} found in dependencies`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name: "Package installed",
|
|
30
|
+
status: "fail",
|
|
31
|
+
message: "@fragments-sdk/ui not found in package.json",
|
|
32
|
+
fix: "npm install @fragments-sdk/ui"
|
|
33
|
+
};
|
|
34
|
+
} catch {
|
|
35
|
+
return {
|
|
36
|
+
name: "Package installed",
|
|
37
|
+
status: "fail",
|
|
38
|
+
message: "No package.json found"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function checkStylesImport(root) {
|
|
43
|
+
const entryPatterns = [
|
|
44
|
+
"src/main.tsx",
|
|
45
|
+
"src/main.ts",
|
|
46
|
+
"src/index.tsx",
|
|
47
|
+
"src/index.ts",
|
|
48
|
+
"src/App.tsx",
|
|
49
|
+
"src/App.ts",
|
|
50
|
+
"app/layout.tsx",
|
|
51
|
+
"app/layout.ts",
|
|
52
|
+
"src/app/layout.tsx",
|
|
53
|
+
"src/app/layout.ts",
|
|
54
|
+
"app/root.tsx",
|
|
55
|
+
"pages/_app.tsx",
|
|
56
|
+
"pages/_app.ts"
|
|
57
|
+
];
|
|
58
|
+
for (const pattern of entryPatterns) {
|
|
59
|
+
try {
|
|
60
|
+
const content = await readFile(join(root, pattern), "utf-8");
|
|
61
|
+
if (content.includes("@fragments-sdk/ui/styles")) {
|
|
62
|
+
return {
|
|
63
|
+
name: "Styles import",
|
|
64
|
+
status: "pass",
|
|
65
|
+
message: `Found styles import in ${pattern}`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (content.includes("@fragments-sdk/ui/globals")) {
|
|
69
|
+
return {
|
|
70
|
+
name: "Styles import",
|
|
71
|
+
status: "warn",
|
|
72
|
+
message: `${pattern} uses deprecated '@fragments-sdk/ui/globals'. Use '@fragments-sdk/ui/styles' instead`,
|
|
73
|
+
fix: `Replace '@fragments-sdk/ui/globals' with '@fragments-sdk/ui/styles' in ${pattern}`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const scssPatterns = [
|
|
80
|
+
"src/styles/globals.scss",
|
|
81
|
+
"src/globals.scss",
|
|
82
|
+
"styles/globals.scss",
|
|
83
|
+
"app/globals.scss",
|
|
84
|
+
"src/app/globals.scss",
|
|
85
|
+
"app/styles/globals.scss"
|
|
86
|
+
];
|
|
87
|
+
for (const pattern of scssPatterns) {
|
|
88
|
+
try {
|
|
89
|
+
const content = await readFile(join(root, pattern), "utf-8");
|
|
90
|
+
if (content.includes("@fragments-sdk/ui/styles")) {
|
|
91
|
+
return {
|
|
92
|
+
name: "Styles import",
|
|
93
|
+
status: "pass",
|
|
94
|
+
message: `Found SCSS @use import in ${pattern}`
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
name: "Styles import",
|
|
102
|
+
status: "fail",
|
|
103
|
+
message: "No @fragments-sdk/ui/styles import found in entry files",
|
|
104
|
+
fix: "Add `import '@fragments-sdk/ui/styles'` to your app's entry file"
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function checkThemeProvider(root) {
|
|
108
|
+
const providerPatterns = [
|
|
109
|
+
"src/main.tsx",
|
|
110
|
+
"src/App.tsx",
|
|
111
|
+
"src/providers.tsx",
|
|
112
|
+
"app/layout.tsx",
|
|
113
|
+
"app/providers.tsx",
|
|
114
|
+
"src/app/layout.tsx",
|
|
115
|
+
"src/app/providers.tsx",
|
|
116
|
+
"app/root.tsx",
|
|
117
|
+
"pages/_app.tsx"
|
|
118
|
+
];
|
|
119
|
+
for (const pattern of providerPatterns) {
|
|
120
|
+
try {
|
|
121
|
+
const content = await readFile(join(root, pattern), "utf-8");
|
|
122
|
+
if (content.includes("ThemeProvider")) {
|
|
123
|
+
if (content.includes("defaultTheme=") || content.includes("defaultTheme =")) {
|
|
124
|
+
return {
|
|
125
|
+
name: "ThemeProvider",
|
|
126
|
+
status: "warn",
|
|
127
|
+
message: `${pattern} uses deprecated 'defaultTheme' prop. Use 'defaultMode' instead`,
|
|
128
|
+
fix: `Replace 'defaultTheme' with 'defaultMode' in ${pattern}`
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
name: "ThemeProvider",
|
|
133
|
+
status: "pass",
|
|
134
|
+
message: `ThemeProvider found in ${pattern}`
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
name: "ThemeProvider",
|
|
142
|
+
status: "warn",
|
|
143
|
+
message: "ThemeProvider not found in common entry files (optional but recommended)",
|
|
144
|
+
fix: 'Wrap your app with <ThemeProvider defaultMode="system">'
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function checkScssSeeds(root) {
|
|
148
|
+
const checks = [];
|
|
149
|
+
const scssPatterns = [
|
|
150
|
+
"src/styles/globals.scss",
|
|
151
|
+
"src/globals.scss",
|
|
152
|
+
"styles/globals.scss",
|
|
153
|
+
"app/globals.scss",
|
|
154
|
+
"src/app/globals.scss",
|
|
155
|
+
"app/styles/globals.scss"
|
|
156
|
+
];
|
|
157
|
+
for (const pattern of scssPatterns) {
|
|
158
|
+
try {
|
|
159
|
+
const content = await readFile(join(root, pattern), "utf-8");
|
|
160
|
+
if (!content.includes("@fragments-sdk/ui/styles")) continue;
|
|
161
|
+
const standalonePattern = /^\$fui-\w+:\s*.+;$/m;
|
|
162
|
+
if (standalonePattern.test(content) && !content.includes("@use")) {
|
|
163
|
+
checks.push({
|
|
164
|
+
name: "SCSS syntax",
|
|
165
|
+
status: "fail",
|
|
166
|
+
message: `${pattern} uses standalone $fui- variables. Must use @use...with() syntax`,
|
|
167
|
+
fix: "@use '@fragments-sdk/ui/styles' with ($fui-brand: #0066ff);"
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const neutralMatch = content.match(/\$fui-neutral:\s*"([^"]+)"/);
|
|
171
|
+
if (neutralMatch && !VALID_NEUTRALS.includes(neutralMatch[1])) {
|
|
172
|
+
checks.push({
|
|
173
|
+
name: "SCSS seed: neutral",
|
|
174
|
+
status: "fail",
|
|
175
|
+
message: `Invalid $fui-neutral: "${neutralMatch[1]}" in ${pattern}`,
|
|
176
|
+
fix: `Valid neutrals: ${VALID_NEUTRALS.join(", ")}`
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const densityMatch = content.match(/\$fui-density:\s*"([^"]+)"/);
|
|
180
|
+
if (densityMatch && !VALID_DENSITIES.includes(densityMatch[1])) {
|
|
181
|
+
checks.push({
|
|
182
|
+
name: "SCSS seed: density",
|
|
183
|
+
status: "fail",
|
|
184
|
+
message: `Invalid $fui-density: "${densityMatch[1]}" in ${pattern}`,
|
|
185
|
+
fix: `Valid densities: ${VALID_DENSITIES.join(", ")}`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
const radiusMatch = content.match(/\$fui-radius-style:\s*"([^"]+)"/);
|
|
189
|
+
if (radiusMatch && !VALID_RADII.includes(radiusMatch[1])) {
|
|
190
|
+
checks.push({
|
|
191
|
+
name: "SCSS seed: radius-style",
|
|
192
|
+
status: "fail",
|
|
193
|
+
message: `Invalid $fui-radius-style: "${radiusMatch[1]}" in ${pattern}`,
|
|
194
|
+
fix: `Valid radius styles: ${VALID_RADII.join(", ")}`
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
const brandMatch = content.match(/\$fui-brand:\s*(#[0-9a-fA-F]+)/);
|
|
198
|
+
if (brandMatch) {
|
|
199
|
+
const hex = brandMatch[1];
|
|
200
|
+
if (!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(hex)) {
|
|
201
|
+
checks.push({
|
|
202
|
+
name: "SCSS seed: brand",
|
|
203
|
+
status: "fail",
|
|
204
|
+
message: `Invalid $fui-brand color: "${hex}" in ${pattern}`,
|
|
205
|
+
fix: "Must be a valid hex color (e.g., #0066ff)"
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (checks.length === 0) {
|
|
210
|
+
checks.push({
|
|
211
|
+
name: "SCSS seeds",
|
|
212
|
+
status: "pass",
|
|
213
|
+
message: `Seed values in ${pattern} are valid`
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return checks;
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
checks.push({
|
|
221
|
+
name: "SCSS seeds",
|
|
222
|
+
status: "pass",
|
|
223
|
+
message: "No custom SCSS seeds configured (using defaults)"
|
|
224
|
+
});
|
|
225
|
+
return checks;
|
|
226
|
+
}
|
|
227
|
+
async function checkPeerDeps(root) {
|
|
228
|
+
const checks = [];
|
|
229
|
+
try {
|
|
230
|
+
const pkgPath = join(root, "package.json");
|
|
231
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
232
|
+
const pkg = JSON.parse(content);
|
|
233
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
234
|
+
if (!allDeps["react"]) {
|
|
235
|
+
checks.push({
|
|
236
|
+
name: "Peer dep: react",
|
|
237
|
+
status: "fail",
|
|
238
|
+
message: "react not found in dependencies (required)",
|
|
239
|
+
fix: "npm install react react-dom"
|
|
240
|
+
});
|
|
241
|
+
} else {
|
|
242
|
+
checks.push({
|
|
243
|
+
name: "Peer dep: react",
|
|
244
|
+
status: "pass",
|
|
245
|
+
message: `react ${allDeps["react"]} installed`
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
if (!allDeps["sass"]) {
|
|
249
|
+
checks.push({
|
|
250
|
+
name: "Peer dep: sass",
|
|
251
|
+
status: "warn",
|
|
252
|
+
message: "sass not installed (needed for custom SCSS theming)",
|
|
253
|
+
fix: "npm install -D sass"
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
const optionalPeers = [
|
|
257
|
+
{ pkg: "recharts", components: "Chart" },
|
|
258
|
+
{ pkg: "shiki", components: "CodeBlock" },
|
|
259
|
+
{ pkg: "react-day-picker", components: "DatePicker" },
|
|
260
|
+
{ pkg: "@tanstack/react-table", components: "DataTable" }
|
|
261
|
+
];
|
|
262
|
+
for (const peer of optionalPeers) {
|
|
263
|
+
if (allDeps[peer.pkg]) {
|
|
264
|
+
checks.push({
|
|
265
|
+
name: `Optional dep: ${peer.pkg}`,
|
|
266
|
+
status: "pass",
|
|
267
|
+
message: `${peer.pkg} installed (enables ${peer.components})`
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
checks.push({
|
|
273
|
+
name: "Peer dependencies",
|
|
274
|
+
status: "fail",
|
|
275
|
+
message: "Could not read package.json"
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return checks;
|
|
279
|
+
}
|
|
280
|
+
async function checkMcpConfig(root) {
|
|
281
|
+
const mcpConfigPaths = [
|
|
282
|
+
".mcp.json",
|
|
283
|
+
".cursor/mcp.json",
|
|
284
|
+
".vscode/mcp.json"
|
|
285
|
+
];
|
|
286
|
+
for (const configPath of mcpConfigPaths) {
|
|
287
|
+
try {
|
|
288
|
+
const fullPath = join(root, configPath);
|
|
289
|
+
const content = await readFile(fullPath, "utf-8");
|
|
290
|
+
const config = JSON.parse(content);
|
|
291
|
+
const servers = config.mcpServers || config.servers || {};
|
|
292
|
+
const hasFragments = Object.values(servers).some((server) => {
|
|
293
|
+
const s = server;
|
|
294
|
+
return s.args?.some((arg) => arg.includes("@fragments-sdk/mcp")) || s.command?.includes("fragments");
|
|
295
|
+
});
|
|
296
|
+
if (hasFragments) {
|
|
297
|
+
return {
|
|
298
|
+
name: "MCP configuration",
|
|
299
|
+
status: "pass",
|
|
300
|
+
message: `Fragments MCP server configured in ${configPath}`
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
} catch {
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
name: "MCP configuration",
|
|
308
|
+
status: "warn",
|
|
309
|
+
message: "No Fragments MCP server configuration found (optional)",
|
|
310
|
+
fix: "Run `fragments init` or add @fragments-sdk/mcp to your MCP config"
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
async function checkTypeScript(root) {
|
|
314
|
+
try {
|
|
315
|
+
const tsconfigPath = join(root, "tsconfig.json");
|
|
316
|
+
await access(tsconfigPath);
|
|
317
|
+
return {
|
|
318
|
+
name: "TypeScript",
|
|
319
|
+
status: "pass",
|
|
320
|
+
message: "tsconfig.json found"
|
|
321
|
+
};
|
|
322
|
+
} catch {
|
|
323
|
+
return {
|
|
324
|
+
name: "TypeScript",
|
|
325
|
+
status: "warn",
|
|
326
|
+
message: "No tsconfig.json found (TypeScript recommended but not required)"
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async function doctor(options = {}) {
|
|
331
|
+
const root = resolve(options.root ?? process.cwd());
|
|
332
|
+
const checks = [];
|
|
333
|
+
if (!options.json) {
|
|
334
|
+
console.log(pc.cyan(`
|
|
335
|
+
${BRAND.name} Doctor
|
|
336
|
+
`));
|
|
337
|
+
console.log(pc.dim(`Checking project at ${root}
|
|
338
|
+
`));
|
|
339
|
+
}
|
|
340
|
+
checks.push(await checkPackageInstalled(root));
|
|
341
|
+
checks.push(await checkStylesImport(root));
|
|
342
|
+
checks.push(await checkThemeProvider(root));
|
|
343
|
+
checks.push(...await checkScssSeeds(root));
|
|
344
|
+
checks.push(...await checkPeerDeps(root));
|
|
345
|
+
checks.push(await checkMcpConfig(root));
|
|
346
|
+
checks.push(await checkTypeScript(root));
|
|
347
|
+
const passed = checks.filter((c) => c.status === "pass").length;
|
|
348
|
+
const warned = checks.filter((c) => c.status === "warn").length;
|
|
349
|
+
const failed = checks.filter((c) => c.status === "fail").length;
|
|
350
|
+
const result = {
|
|
351
|
+
success: failed === 0,
|
|
352
|
+
checks,
|
|
353
|
+
passed,
|
|
354
|
+
warned,
|
|
355
|
+
failed
|
|
356
|
+
};
|
|
357
|
+
if (options.json) {
|
|
358
|
+
console.log(JSON.stringify(result, null, 2));
|
|
359
|
+
} else {
|
|
360
|
+
for (const check of checks) {
|
|
361
|
+
const icon = check.status === "pass" ? pc.green("\u2713") : check.status === "warn" ? pc.yellow("!") : pc.red("\u2717");
|
|
362
|
+
const msg = check.status === "pass" ? check.message : check.status === "warn" ? pc.yellow(check.message) : pc.red(check.message);
|
|
363
|
+
console.log(` ${icon} ${pc.bold(check.name)}: ${msg}`);
|
|
364
|
+
if (check.fix && check.status !== "pass") {
|
|
365
|
+
console.log(pc.dim(` \u2192 ${check.fix}`));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
console.log();
|
|
369
|
+
if (failed === 0 && warned === 0) {
|
|
370
|
+
console.log(pc.green(`\u2713 All ${passed} checks passed \u2014 your setup looks great!`));
|
|
371
|
+
} else if (failed === 0) {
|
|
372
|
+
console.log(pc.green(`\u2713 ${passed} passed`) + pc.yellow(`, ${warned} warning(s)`));
|
|
373
|
+
} else {
|
|
374
|
+
console.log(
|
|
375
|
+
pc.red(`\u2717 ${failed} failed`) + (warned > 0 ? pc.yellow(`, ${warned} warning(s)`) : "") + pc.dim(`, ${passed} passed`)
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
console.log();
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
export {
|
|
383
|
+
doctor
|
|
384
|
+
};
|
|
385
|
+
//# sourceMappingURL=doctor-BDPMYYE6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["/**\n * fragments doctor - Diagnose design system configuration\n *\n * Checks a consumer project for common setup issues:\n * - Missing styles import\n * - ThemeProvider not found\n * - Invalid SCSS seed values\n * - Missing peer dependencies\n * - MCP configuration\n */\n\nimport { readFile, access } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport pc from 'picocolors';\nimport { BRAND } from '../core/index.js';\nimport { NEUTRAL_PALETTES } from '@fragments-sdk/viewer/docs-data';\n\n// ============================================\n// Types\n// ============================================\n\nexport interface DoctorOptions {\n /** Project root directory (defaults to cwd) */\n root?: string;\n /** Output JSON instead of formatted text */\n json?: boolean;\n /** Auto-fix issues where possible */\n fix?: boolean;\n}\n\nexport interface DoctorCheck {\n name: string;\n status: 'pass' | 'warn' | 'fail';\n message: string;\n fix?: string;\n}\n\nexport interface DoctorResult {\n success: boolean;\n checks: DoctorCheck[];\n passed: number;\n warned: number;\n failed: number;\n}\n\n// ============================================\n// Valid seed values — derived from canonical sources\n// ============================================\n\nconst VALID_NEUTRALS = NEUTRAL_PALETTES.map((p) => p.name);\nconst VALID_DENSITIES = ['compact', 'default', 'relaxed'];\nconst VALID_RADII = ['sharp', 'subtle', 'default', 'rounded', 'pill'];\n\n// ============================================\n// Individual Checks\n// ============================================\n\nasync function checkPackageInstalled(root: string): Promise<DoctorCheck> {\n try {\n const pkgPath = join(root, 'package.json');\n const content = await readFile(pkgPath, 'utf-8');\n const pkg = JSON.parse(content);\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n if (allDeps['@fragments-sdk/ui']) {\n return {\n name: 'Package installed',\n status: 'pass',\n message: `@fragments-sdk/ui ${allDeps['@fragments-sdk/ui']} found in dependencies`,\n };\n }\n\n return {\n name: 'Package installed',\n status: 'fail',\n message: '@fragments-sdk/ui not found in package.json',\n fix: 'npm install @fragments-sdk/ui',\n };\n } catch {\n return {\n name: 'Package installed',\n status: 'fail',\n message: 'No package.json found',\n };\n }\n}\n\nasync function checkStylesImport(root: string): Promise<DoctorCheck> {\n const entryPatterns = [\n 'src/main.tsx', 'src/main.ts', 'src/index.tsx', 'src/index.ts',\n 'src/App.tsx', 'src/App.ts',\n 'app/layout.tsx', 'app/layout.ts',\n 'src/app/layout.tsx', 'src/app/layout.ts',\n 'app/root.tsx',\n 'pages/_app.tsx', 'pages/_app.ts',\n ];\n\n for (const pattern of entryPatterns) {\n try {\n const content = await readFile(join(root, pattern), 'utf-8');\n\n // Check for correct import\n if (content.includes(\"@fragments-sdk/ui/styles\")) {\n return {\n name: 'Styles import',\n status: 'pass',\n message: `Found styles import in ${pattern}`,\n };\n }\n\n // Check for deprecated ./globals import\n if (content.includes(\"@fragments-sdk/ui/globals\")) {\n return {\n name: 'Styles import',\n status: 'warn',\n message: `${pattern} uses deprecated '@fragments-sdk/ui/globals'. Use '@fragments-sdk/ui/styles' instead`,\n fix: `Replace '@fragments-sdk/ui/globals' with '@fragments-sdk/ui/styles' in ${pattern}`,\n };\n }\n } catch {\n // File doesn't exist, continue\n }\n }\n\n // Also check SCSS files for @use import\n const scssPatterns = [\n 'src/styles/globals.scss', 'src/globals.scss',\n 'styles/globals.scss', 'app/globals.scss',\n 'src/app/globals.scss',\n 'app/styles/globals.scss',\n ];\n\n for (const pattern of scssPatterns) {\n try {\n const content = await readFile(join(root, pattern), 'utf-8');\n if (content.includes(\"@fragments-sdk/ui/styles\")) {\n return {\n name: 'Styles import',\n status: 'pass',\n message: `Found SCSS @use import in ${pattern}`,\n };\n }\n } catch {\n // File doesn't exist, continue\n }\n }\n\n return {\n name: 'Styles import',\n status: 'fail',\n message: 'No @fragments-sdk/ui/styles import found in entry files',\n fix: \"Add `import '@fragments-sdk/ui/styles'` to your app's entry file\",\n };\n}\n\nasync function checkThemeProvider(root: string): Promise<DoctorCheck> {\n const providerPatterns = [\n 'src/main.tsx', 'src/App.tsx', 'src/providers.tsx',\n 'app/layout.tsx', 'app/providers.tsx',\n 'src/app/layout.tsx', 'src/app/providers.tsx',\n 'app/root.tsx',\n 'pages/_app.tsx',\n ];\n\n for (const pattern of providerPatterns) {\n try {\n const content = await readFile(join(root, pattern), 'utf-8');\n\n if (content.includes('ThemeProvider')) {\n // Check for deprecated defaultTheme prop\n if (content.includes('defaultTheme=') || content.includes('defaultTheme =')) {\n return {\n name: 'ThemeProvider',\n status: 'warn',\n message: `${pattern} uses deprecated 'defaultTheme' prop. Use 'defaultMode' instead`,\n fix: `Replace 'defaultTheme' with 'defaultMode' in ${pattern}`,\n };\n }\n\n return {\n name: 'ThemeProvider',\n status: 'pass',\n message: `ThemeProvider found in ${pattern}`,\n };\n }\n } catch {\n // File doesn't exist, continue\n }\n }\n\n return {\n name: 'ThemeProvider',\n status: 'warn',\n message: 'ThemeProvider not found in common entry files (optional but recommended)',\n fix: \"Wrap your app with <ThemeProvider defaultMode=\\\"system\\\">\",\n };\n}\n\nasync function checkScssSeeds(root: string): Promise<DoctorCheck[]> {\n const checks: DoctorCheck[] = [];\n\n const scssPatterns = [\n 'src/styles/globals.scss', 'src/globals.scss',\n 'styles/globals.scss', 'app/globals.scss',\n 'src/app/globals.scss',\n 'app/styles/globals.scss',\n ];\n\n for (const pattern of scssPatterns) {\n try {\n const content = await readFile(join(root, pattern), 'utf-8');\n if (!content.includes(\"@fragments-sdk/ui/styles\")) continue;\n\n // Check for standalone variable syntax (wrong)\n const standalonePattern = /^\\$fui-\\w+:\\s*.+;$/m;\n if (standalonePattern.test(content) && !content.includes('@use')) {\n checks.push({\n name: 'SCSS syntax',\n status: 'fail',\n message: `${pattern} uses standalone $fui- variables. Must use @use...with() syntax`,\n fix: \"@use '@fragments-sdk/ui/styles' with ($fui-brand: #0066ff);\",\n });\n }\n\n // Validate neutral value\n const neutralMatch = content.match(/\\$fui-neutral:\\s*\"([^\"]+)\"/);\n if (neutralMatch && !VALID_NEUTRALS.includes(neutralMatch[1])) {\n checks.push({\n name: 'SCSS seed: neutral',\n status: 'fail',\n message: `Invalid $fui-neutral: \"${neutralMatch[1]}\" in ${pattern}`,\n fix: `Valid neutrals: ${VALID_NEUTRALS.join(', ')}`,\n });\n }\n\n // Validate density value\n const densityMatch = content.match(/\\$fui-density:\\s*\"([^\"]+)\"/);\n if (densityMatch && !VALID_DENSITIES.includes(densityMatch[1])) {\n checks.push({\n name: 'SCSS seed: density',\n status: 'fail',\n message: `Invalid $fui-density: \"${densityMatch[1]}\" in ${pattern}`,\n fix: `Valid densities: ${VALID_DENSITIES.join(', ')}`,\n });\n }\n\n // Validate radius-style value\n const radiusMatch = content.match(/\\$fui-radius-style:\\s*\"([^\"]+)\"/);\n if (radiusMatch && !VALID_RADII.includes(radiusMatch[1])) {\n checks.push({\n name: 'SCSS seed: radius-style',\n status: 'fail',\n message: `Invalid $fui-radius-style: \"${radiusMatch[1]}\" in ${pattern}`,\n fix: `Valid radius styles: ${VALID_RADII.join(', ')}`,\n });\n }\n\n // Validate brand is a valid hex color\n const brandMatch = content.match(/\\$fui-brand:\\s*(#[0-9a-fA-F]+)/);\n if (brandMatch) {\n const hex = brandMatch[1];\n if (!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(hex)) {\n checks.push({\n name: 'SCSS seed: brand',\n status: 'fail',\n message: `Invalid $fui-brand color: \"${hex}\" in ${pattern}`,\n fix: 'Must be a valid hex color (e.g., #0066ff)',\n });\n }\n }\n\n // If we found the file and parsed it, and no seed issues, add a pass\n if (checks.length === 0) {\n checks.push({\n name: 'SCSS seeds',\n status: 'pass',\n message: `Seed values in ${pattern} are valid`,\n });\n }\n\n return checks;\n } catch {\n // File doesn't exist, continue\n }\n }\n\n // No SCSS file found — not an error, just informational\n checks.push({\n name: 'SCSS seeds',\n status: 'pass',\n message: 'No custom SCSS seeds configured (using defaults)',\n });\n\n return checks;\n}\n\nasync function checkPeerDeps(root: string): Promise<DoctorCheck[]> {\n const checks: DoctorCheck[] = [];\n\n try {\n const pkgPath = join(root, 'package.json');\n const content = await readFile(pkgPath, 'utf-8');\n const pkg = JSON.parse(content);\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n // React is required\n if (!allDeps['react']) {\n checks.push({\n name: 'Peer dep: react',\n status: 'fail',\n message: 'react not found in dependencies (required)',\n fix: 'npm install react react-dom',\n });\n } else {\n checks.push({\n name: 'Peer dep: react',\n status: 'pass',\n message: `react ${allDeps['react']} installed`,\n });\n }\n\n // sass is needed for custom theming\n if (!allDeps['sass']) {\n checks.push({\n name: 'Peer dep: sass',\n status: 'warn',\n message: 'sass not installed (needed for custom SCSS theming)',\n fix: 'npm install -D sass',\n });\n }\n\n // Check optional peer deps that components might need\n const optionalPeers: Array<{ pkg: string; components: string }> = [\n { pkg: 'recharts', components: 'Chart' },\n { pkg: 'shiki', components: 'CodeBlock' },\n { pkg: 'react-day-picker', components: 'DatePicker' },\n { pkg: '@tanstack/react-table', components: 'DataTable' },\n ];\n\n for (const peer of optionalPeers) {\n if (allDeps[peer.pkg]) {\n checks.push({\n name: `Optional dep: ${peer.pkg}`,\n status: 'pass',\n message: `${peer.pkg} installed (enables ${peer.components})`,\n });\n }\n }\n } catch {\n checks.push({\n name: 'Peer dependencies',\n status: 'fail',\n message: 'Could not read package.json',\n });\n }\n\n return checks;\n}\n\nasync function checkMcpConfig(root: string): Promise<DoctorCheck> {\n const mcpConfigPaths = [\n '.mcp.json',\n '.cursor/mcp.json',\n '.vscode/mcp.json',\n ];\n\n for (const configPath of mcpConfigPaths) {\n try {\n const fullPath = join(root, configPath);\n const content = await readFile(fullPath, 'utf-8');\n const config = JSON.parse(content);\n\n // Check if fragments MCP server is configured\n const servers = config.mcpServers || config.servers || {};\n const hasFragments = Object.values(servers).some((server: unknown) => {\n const s = server as { command?: string; args?: string[] };\n return (\n s.args?.some((arg: string) => arg.includes('@fragments-sdk/mcp')) ||\n s.command?.includes('fragments')\n );\n });\n\n if (hasFragments) {\n return {\n name: 'MCP configuration',\n status: 'pass',\n message: `Fragments MCP server configured in ${configPath}`,\n };\n }\n } catch {\n // File doesn't exist or is invalid, continue\n }\n }\n\n return {\n name: 'MCP configuration',\n status: 'warn',\n message: 'No Fragments MCP server configuration found (optional)',\n fix: 'Run `fragments init` or add @fragments-sdk/mcp to your MCP config',\n };\n}\n\nasync function checkTypeScript(root: string): Promise<DoctorCheck> {\n try {\n const tsconfigPath = join(root, 'tsconfig.json');\n await access(tsconfigPath);\n return {\n name: 'TypeScript',\n status: 'pass',\n message: 'tsconfig.json found',\n };\n } catch {\n return {\n name: 'TypeScript',\n status: 'warn',\n message: 'No tsconfig.json found (TypeScript recommended but not required)',\n };\n }\n}\n\n// ============================================\n// Main Doctor Function\n// ============================================\n\n/**\n * Run diagnostic checks on a consumer project\n */\nexport async function doctor(\n options: DoctorOptions = {}\n): Promise<DoctorResult> {\n const root = resolve(options.root ?? process.cwd());\n const checks: DoctorCheck[] = [];\n\n if (!options.json) {\n console.log(pc.cyan(`\\n${BRAND.name} Doctor\\n`));\n console.log(pc.dim(`Checking project at ${root}\\n`));\n }\n\n // Run all checks\n checks.push(await checkPackageInstalled(root));\n checks.push(await checkStylesImport(root));\n checks.push(await checkThemeProvider(root));\n checks.push(...await checkScssSeeds(root));\n checks.push(...await checkPeerDeps(root));\n checks.push(await checkMcpConfig(root));\n checks.push(await checkTypeScript(root));\n\n const passed = checks.filter(c => c.status === 'pass').length;\n const warned = checks.filter(c => c.status === 'warn').length;\n const failed = checks.filter(c => c.status === 'fail').length;\n\n const result: DoctorResult = {\n success: failed === 0,\n checks,\n passed,\n warned,\n failed,\n };\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n // Print results\n for (const check of checks) {\n const icon =\n check.status === 'pass' ? pc.green('✓') :\n check.status === 'warn' ? pc.yellow('!') :\n pc.red('✗');\n\n const msg =\n check.status === 'pass' ? check.message :\n check.status === 'warn' ? pc.yellow(check.message) :\n pc.red(check.message);\n\n console.log(` ${icon} ${pc.bold(check.name)}: ${msg}`);\n\n if (check.fix && check.status !== 'pass') {\n console.log(pc.dim(` → ${check.fix}`));\n }\n }\n\n // Summary\n console.log();\n if (failed === 0 && warned === 0) {\n console.log(pc.green(`✓ All ${passed} checks passed — your setup looks great!`));\n } else if (failed === 0) {\n console.log(pc.green(`✓ ${passed} passed`) + pc.yellow(`, ${warned} warning(s)`));\n } else {\n console.log(\n pc.red(`✗ ${failed} failed`) +\n (warned > 0 ? pc.yellow(`, ${warned} warning(s)`) : '') +\n pc.dim(`, ${passed} passed`)\n );\n }\n console.log();\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-D2CDBRNU.js";
|
|
2
3
|
import {
|
|
3
4
|
extractPropsFromFile
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-D2CDBRNU.js";
|
|
5
|
+
} from "./chunk-HQ6A6DTV.js";
|
|
6
6
|
import {
|
|
7
7
|
BRAND
|
|
8
8
|
} from "./chunk-32LIWN2P.js";
|
|
9
|
-
import "./chunk-Z7EY4VHE.js";
|
|
10
9
|
|
|
11
10
|
// src/commands/generate.ts
|
|
12
11
|
import { readFile, writeFile, access } from "fs/promises";
|
|
@@ -455,4 +454,4 @@ function inferStatus(filePath) {
|
|
|
455
454
|
export {
|
|
456
455
|
generate
|
|
457
456
|
};
|
|
458
|
-
//# sourceMappingURL=generate-
|
|
457
|
+
//# sourceMappingURL=generate-PVOLUAAC.js.map
|