@stayicon/drift-guard 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -1
- package/dist/{chunk-27T45SVD.js → chunk-HI6H6PCS.js} +526 -16
- package/dist/chunk-HI6H6PCS.js.map +1 -0
- package/dist/cli/index.js +438 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +118 -1
- package/dist/index.js +17 -3
- package/package.json +1 -1
- package/dist/chunk-27T45SVD.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parsers/structure-parser.ts","../src/types/index.ts","../src/core/snapshot.ts","../src/parsers/css-parser.ts","../src/parsers/html-parser.ts","../src/core/drift.ts","../src/core/rules-generator.ts","../src/core/sync.ts"],"sourcesContent":["import * as cheerio from 'cheerio';\nimport { createHash } from 'node:crypto';\nimport type { StructureFingerprint } from '../types/index.js';\n\n/**\n * Semantic HTML tags to track for structure fingerprinting\n */\nconst SEMANTIC_TAGS = [\n 'header', 'nav', 'main', 'section', 'article',\n 'aside', 'footer', 'form', 'table', 'dialog',\n];\n\n/**\n * Compute a short hash (first 8 chars of sha256)\n */\nfunction shortHash(input: string): string {\n return createHash('sha256').update(input).digest('hex').slice(0, 8);\n}\n\n/**\n * Compute the maximum DOM nesting depth via DFS\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction computeMaxDepth($: cheerio.CheerioAPI, el: cheerio.Cheerio<any>, depth: number): number {\n let maxDepth = depth;\n\n el.children().each((_, child) => {\n if ($(child).prop('nodeType') === 1) { // Element node\n const childDepth = computeMaxDepth($, $(child), depth + 1);\n if (childDepth > maxDepth) {\n maxDepth = childDepth;\n }\n }\n });\n\n return maxDepth;\n}\n\n/**\n * Compute a DOM structure fingerprint from HTML content.\n *\n * Captures:\n * 1. Semantic tag counts (header, nav, main, section, etc.)\n * 2. Maximum nesting depth\n * 3. Layout element hash (elements with display:flex/grid)\n * 4. Body direct child tag sequence hash\n */\nexport function computeStructureFingerprint(htmlContent: string): StructureFingerprint {\n const $ = cheerio.load(htmlContent);\n\n // 1. Semantic tag counts\n const semanticTags: Record<string, number> = {};\n for (const tag of SEMANTIC_TAGS) {\n const count = $(tag).length;\n if (count > 0) {\n semanticTags[tag] = count;\n }\n }\n\n // 2. Max nesting depth\n const body = $('body');\n const maxDepth = body.length > 0\n ? computeMaxDepth($, body, 0)\n : 0;\n\n // 3. Layout element hash — elements with display:flex or display:grid in inline styles\n const layoutElements: string[] = [];\n $('[style]').each((_, el) => {\n const style = $(el).attr('style') ?? '';\n if (/display\\s*:\\s*(flex|grid|inline-flex|inline-grid)/i.test(style)) {\n const tag = ($(el).prop('tagName') ?? 'div').toLowerCase();\n const cls = $(el).attr('class') ?? '';\n layoutElements.push(`${tag}.${cls}`);\n }\n });\n\n // Also capture elements with layout-related class names (Tailwind patterns)\n $('[class*=\"flex\"], [class*=\"grid\"]').each((_, el) => {\n const tag = ($(el).prop('tagName') ?? 'div').toLowerCase();\n const cls = $(el).attr('class') ?? '';\n // Only include if it has actual flex/grid class\n if (/\\b(flex|grid|inline-flex|inline-grid)\\b/.test(cls)) {\n const key = `${tag}.${cls}`;\n if (!layoutElements.includes(key)) {\n layoutElements.push(key);\n }\n }\n });\n\n layoutElements.sort();\n const layoutHash = layoutElements.length > 0\n ? shortHash(layoutElements.join('|'))\n : 'empty';\n\n // 4. Body direct child tag sequence\n const childTags: string[] = [];\n body.children().each((_, child) => {\n if ($(child).prop('nodeType') === 1) { // Element node\n const tag = ($(child).prop('tagName') ?? '').toLowerCase();\n if (tag && tag !== 'script' && tag !== 'link') {\n childTags.push(tag);\n }\n }\n });\n\n const childSequenceHash = childTags.length > 0\n ? shortHash(childTags.join(','))\n : 'empty';\n\n return {\n semanticTags,\n maxDepth,\n layoutHash,\n childSequenceHash,\n };\n}\n\n/**\n * Compare two structure fingerprints and return human-readable differences\n */\nexport function compareStructure(\n original: StructureFingerprint,\n current: StructureFingerprint,\n): string[] {\n const details: string[] = [];\n\n // Compare max depth\n if (original.maxDepth !== current.maxDepth) {\n details.push(`maxDepth: ${original.maxDepth} → ${current.maxDepth}`);\n }\n\n // Compare semantic tag counts\n const allTags = new Set([\n ...Object.keys(original.semanticTags),\n ...Object.keys(current.semanticTags),\n ]);\n\n for (const tag of allTags) {\n const origCount = original.semanticTags[tag] ?? 0;\n const currCount = current.semanticTags[tag] ?? 0;\n if (origCount !== currCount) {\n if (origCount === 0) {\n details.push(`<${tag}> added (${currCount})`);\n } else if (currCount === 0) {\n details.push(`<${tag}> removed (was ${origCount})`);\n } else {\n details.push(`<${tag}> count: ${origCount} → ${currCount}`);\n }\n }\n }\n\n // Compare layout hash\n if (original.layoutHash !== current.layoutHash) {\n details.push(`layout elements changed (hash: ${original.layoutHash} → ${current.layoutHash})`);\n }\n\n // Compare child sequence hash\n if (original.childSequenceHash !== current.childSequenceHash) {\n details.push(`body child sequence changed (hash: ${original.childSequenceHash} → ${current.childSequenceHash})`);\n }\n\n return details;\n}\n","// drift-guard type definitions\n\n/**\n * A single design token extracted from CSS/HTML\n */\nexport interface DesignToken {\n /** Token category: color, font, spacing, shadow, radius, layout */\n category: TokenCategory;\n /** CSS property name (e.g., 'color', 'font-family', 'padding') */\n property: string;\n /** Resolved value (e.g., '#1a73e8', '16px', 'Inter') */\n value: string;\n /** CSS selector where this token was found */\n selector: string;\n /** Source file path */\n file: string;\n /** Line number in source file */\n line?: number;\n}\n\nexport type TokenCategory =\n | 'color'\n | 'font'\n | 'spacing'\n | 'shadow'\n | 'radius'\n | 'layout'\n | 'other';\n\n/**\n * Design snapshot — frozen state of all design tokens\n */\nexport interface DesignSnapshot {\n /** Snapshot version */\n version: string;\n /** ISO timestamp when snapshot was created */\n createdAt: string;\n /** Project root directory */\n projectRoot: string;\n /** Source files that were scanned */\n sourceFiles: string[];\n /** All extracted design tokens */\n tokens: DesignToken[];\n /** Token count by category */\n summary: Record<TokenCategory, number>;\n /** DOM structure fingerprint (v0.2.0+) */\n structure?: StructureFingerprint;\n}\n\n/**\n * A single drift item — one token that changed\n */\nexport interface DriftItem {\n /** The original token from the snapshot */\n original: DesignToken;\n /** The current token value (null if token was deleted) */\n current: DesignToken | null;\n /** Type of change */\n changeType: 'modified' | 'deleted' | 'added';\n}\n\n/**\n * Drift detection report\n */\nexport interface DriftReport {\n /** ISO timestamp of the check */\n checkedAt: string;\n /** Snapshot used as baseline */\n snapshotCreatedAt: string;\n /** Total tokens in snapshot */\n totalTokens: number;\n /** Number of changed tokens */\n changedTokens: number;\n /** Drift score: (changed / total) * 100 */\n driftScore: number;\n /** Threshold used for pass/fail */\n threshold: number;\n /** Whether the check passed */\n passed: boolean;\n /** Individual drift items */\n items: DriftItem[];\n /** Summary by category */\n categorySummary: Record<TokenCategory, {\n total: number;\n changed: number;\n driftPercent: number;\n }>;\n /** DOM structure drift report (v0.2.0+) */\n structureDrift?: StructureDriftReport;\n}\n\n/**\n * DOM structure fingerprint — tracks HTML layout structure\n */\nexport interface StructureFingerprint {\n /** Semantic tag counts: { header: 1, nav: 1, main: 1, section: 3, footer: 1 } */\n semanticTags: Record<string, number>;\n /** Maximum DOM nesting depth */\n maxDepth: number;\n /** Hash of layout elements (display:flex/grid tags+classes) */\n layoutHash: string;\n /** Hash of body's direct child tag sequence */\n childSequenceHash: string;\n}\n\n/**\n * Structure drift detection result\n */\nexport interface StructureDriftReport {\n /** Whether structure changed */\n changed: boolean;\n /** Human-readable change descriptions */\n details: string[];\n}\n\n/**\n * Sync direction for Stitch ↔ Code synchronization\n */\nexport type SyncDirection = 'to-stitch' | 'to-code';\n\n/**\n * A single sync change between Stitch and Code\n */\nexport interface SyncChange {\n /** Token category */\n category: TokenCategory;\n /** CSS property or token name */\n property: string;\n /** Previous value */\n fromValue: string;\n /** New value */\n toValue: string;\n /** Type of change */\n action: 'update' | 'add' | 'remove';\n}\n\n/**\n * Result of a sync operation\n */\nexport interface SyncResult {\n /** Which direction the sync goes */\n direction: SyncDirection;\n /** All changes detected */\n changes: SyncChange[];\n /** Natural language prompt for edit_screens (to-stitch only) */\n prompt?: string;\n /** CSS patch content (to-code only) */\n patchFile?: string;\n /** ISO timestamp */\n timestamp: string;\n}\n\n/**\n * Stitch project/screen configuration\n */\nexport interface StitchConfig {\n /** Stitch project ID */\n projectId?: string;\n /** Stitch screen ID */\n screenId?: string;\n /** Local path to downloaded Stitch HTML */\n htmlPath?: string;\n}\n\n/**\n * Supported AI rule file formats\n */\nexport type RuleFormat =\n | 'cursorrules'\n | 'claude-md'\n | 'agents-md'\n | 'copilot'\n | 'clinerules';\n\n/**\n * Configuration stored in .design-guard/config.json\n */\nexport interface DriftGuardConfig {\n /** Glob patterns for CSS files to scan */\n cssFiles: string[];\n /** Glob patterns for HTML files to scan */\n htmlFiles: string[];\n /** Default drift threshold (percentage) */\n threshold: number;\n /** Token categories to track */\n trackCategories: TokenCategory[];\n /** Files/patterns to ignore */\n ignore: string[];\n /** Stitch project configuration (optional) */\n stitch?: StitchConfig;\n}\n\n/**\n * Default configuration\n */\nexport const DEFAULT_CONFIG: DriftGuardConfig = {\n cssFiles: [\n 'src/**/*.css',\n 'app/**/*.css',\n 'styles/**/*.css',\n '**/*.module.css',\n '**/*.css',\n ],\n htmlFiles: [\n '**/*.html',\n '!node_modules/**',\n '!dist/**',\n '!build/**',\n ],\n threshold: 10,\n trackCategories: ['color', 'font', 'spacing', 'shadow', 'radius', 'layout'],\n ignore: [\n 'node_modules/**',\n 'dist/**',\n 'build/**',\n '.next/**',\n 'coverage/**',\n ],\n};\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport fg from 'fast-glob';\nimport { parseCss, extractCssVariables } from '../parsers/css-parser.js';\nimport { parseHtml, extractStyleBlocks, extractTailwindConfig } from '../parsers/html-parser.js';\nimport { computeStructureFingerprint } from '../parsers/structure-parser.js';\nimport type {\n DesignSnapshot,\n DesignToken,\n TokenCategory,\n DriftGuardConfig,\n StructureFingerprint,\n} from '../types/index.js';\nimport { DEFAULT_CONFIG } from '../types/index.js';\n\nconst SNAPSHOT_DIR = '.design-guard';\nconst SNAPSHOT_FILE = 'snapshot.json';\nconst CONFIG_FILE = 'config.json';\n\n/**\n * Get the full path to the snapshot file\n */\nexport function getSnapshotPath(projectRoot: string): string {\n return path.join(projectRoot, SNAPSHOT_DIR, SNAPSHOT_FILE);\n}\n\n/**\n * Get the config path\n */\nexport function getConfigPath(projectRoot: string): string {\n return path.join(projectRoot, SNAPSHOT_DIR, CONFIG_FILE);\n}\n\n/**\n * Load or create config\n */\nexport function loadConfig(projectRoot: string): DriftGuardConfig {\n const configPath = getConfigPath(projectRoot);\n if (fs.existsSync(configPath)) {\n const raw = fs.readFileSync(configPath, 'utf-8');\n return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };\n }\n return { ...DEFAULT_CONFIG };\n}\n\n/**\n * Save config\n */\nexport function saveConfig(projectRoot: string, config: DriftGuardConfig): void {\n const dir = path.join(projectRoot, SNAPSHOT_DIR);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(getConfigPath(projectRoot), JSON.stringify(config, null, 2), 'utf-8');\n}\n\n/**\n * Scan the project and extract all design tokens\n */\nexport async function scanProject(\n projectRoot: string,\n config: DriftGuardConfig,\n stitchHtmlPath?: string,\n): Promise<{ tokens: DesignToken[]; files: string[] }> {\n const allTokens: DesignToken[] = [];\n const scannedFiles: string[] = [];\n\n // 1. If a Stitch HTML file is provided, parse it first\n if (stitchHtmlPath) {\n const absPath = path.resolve(projectRoot, stitchHtmlPath);\n if (fs.existsSync(absPath)) {\n const htmlContent = fs.readFileSync(absPath, 'utf-8');\n const htmlTokens = parseHtml(htmlContent, stitchHtmlPath);\n allTokens.push(...htmlTokens);\n\n // Also parse <style> blocks within the HTML\n const styleBlocks = extractStyleBlocks(htmlContent);\n for (const block of styleBlocks) {\n const cssTokens = parseCss(block, stitchHtmlPath);\n allTokens.push(...cssTokens);\n const vars = extractCssVariables(block, stitchHtmlPath);\n allTokens.push(...vars);\n }\n scannedFiles.push(stitchHtmlPath);\n\n // Also extract Tailwind config from <script> tags\n const twTokens = extractTailwindConfig(htmlContent, stitchHtmlPath);\n allTokens.push(...twTokens);\n }\n }\n\n // 2. Scan CSS files\n const cssFiles = await fg(config.cssFiles, {\n cwd: projectRoot,\n ignore: config.ignore,\n absolute: false,\n });\n\n for (const file of cssFiles) {\n const absPath = path.join(projectRoot, file);\n const content = fs.readFileSync(absPath, 'utf-8');\n const tokens = parseCss(content, file);\n allTokens.push(...tokens);\n const vars = extractCssVariables(content, file);\n allTokens.push(...vars);\n scannedFiles.push(file);\n }\n\n // 3. Scan HTML files (for inline styles)\n const htmlFiles = await fg(config.htmlFiles, {\n cwd: projectRoot,\n ignore: config.ignore,\n absolute: false,\n });\n\n for (const file of htmlFiles) {\n if (scannedFiles.includes(file)) continue; // Skip if already scanned (e.g., Stitch HTML)\n const absPath = path.join(projectRoot, file);\n const content = fs.readFileSync(absPath, 'utf-8');\n const tokens = parseHtml(content, file);\n allTokens.push(...tokens);\n\n // Parse embedded <style> blocks\n const styleBlocks = extractStyleBlocks(content);\n for (const block of styleBlocks) {\n const cssTokens = parseCss(block, file);\n allTokens.push(...cssTokens);\n }\n\n // Extract Tailwind config from <script> tags\n const twTokens = extractTailwindConfig(content, file);\n allTokens.push(...twTokens);\n\n scannedFiles.push(file);\n }\n\n // Filter by tracked categories\n const filtered = allTokens.filter(t =>\n config.trackCategories.includes(t.category),\n );\n\n // Deduplicate: same property + selector + file = keep first\n const seen = new Set<string>();\n const deduplicated = filtered.filter(t => {\n const key = `${t.file}:${t.selector}:${t.property}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n return { tokens: deduplicated, files: scannedFiles };\n}\n\n/**\n * Build category summary from tokens\n */\nfunction buildSummary(tokens: DesignToken[]): Record<TokenCategory, number> {\n const summary: Record<TokenCategory, number> = {\n color: 0,\n font: 0,\n spacing: 0,\n shadow: 0,\n radius: 0,\n layout: 0,\n other: 0,\n };\n\n for (const token of tokens) {\n summary[token.category]++;\n }\n\n return summary;\n}\n\n/**\n * Create a snapshot from the current project state\n */\nexport async function createSnapshot(\n projectRoot: string,\n stitchHtmlPath?: string,\n): Promise<DesignSnapshot> {\n const config = loadConfig(projectRoot);\n const { tokens, files } = await scanProject(projectRoot, config, stitchHtmlPath);\n\n // Compute structure fingerprint from HTML files\n let structure: StructureFingerprint | undefined;\n try {\n // Use Stitch HTML if provided, otherwise try to find an HTML file\n let htmlForStructure: string | null = null;\n\n if (stitchHtmlPath) {\n const absPath = path.resolve(projectRoot, stitchHtmlPath);\n if (fs.existsSync(absPath)) {\n htmlForStructure = fs.readFileSync(absPath, 'utf-8');\n }\n } else {\n // Try to find any HTML file in the scanned files\n for (const file of files) {\n if (file.endsWith('.html')) {\n const absPath = path.join(projectRoot, file);\n if (fs.existsSync(absPath)) {\n htmlForStructure = fs.readFileSync(absPath, 'utf-8');\n break;\n }\n }\n }\n }\n\n if (htmlForStructure) {\n structure = computeStructureFingerprint(htmlForStructure);\n }\n } catch {\n // Structure fingerprint is optional — don't fail the snapshot\n }\n\n const snapshot: DesignSnapshot = {\n version: '1.0.0',\n createdAt: new Date().toISOString(),\n projectRoot,\n sourceFiles: files,\n tokens,\n summary: buildSummary(tokens),\n structure,\n };\n\n return snapshot;\n}\n\n/**\n * Save a snapshot to disk\n */\nexport function saveSnapshot(projectRoot: string, snapshot: DesignSnapshot): string {\n const dir = path.join(projectRoot, SNAPSHOT_DIR);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n const snapshotPath = getSnapshotPath(projectRoot);\n fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2), 'utf-8');\n return snapshotPath;\n}\n\n/**\n * Load an existing snapshot from disk\n */\nexport function loadSnapshot(projectRoot: string): DesignSnapshot | null {\n const snapshotPath = getSnapshotPath(projectRoot);\n if (!fs.existsSync(snapshotPath)) {\n return null;\n }\n\n const raw = fs.readFileSync(snapshotPath, 'utf-8');\n return JSON.parse(raw) as DesignSnapshot;\n}\n","import * as csstree from 'css-tree';\nimport type { DesignToken, TokenCategory } from '../types/index.js';\n\n/**\n * CSS properties that map to each token category\n */\nconst CATEGORY_MAP: Record<string, TokenCategory> = {\n // Colors\n 'color': 'color',\n 'background-color': 'color',\n 'background': 'color',\n 'border-color': 'color',\n 'outline-color': 'color',\n 'fill': 'color',\n 'stroke': 'color',\n '--color': 'color',\n\n // Fonts\n 'font-family': 'font',\n 'font-size': 'font',\n 'font-weight': 'font',\n 'line-height': 'font',\n 'letter-spacing': 'font',\n\n // Spacing\n 'margin': 'spacing',\n 'margin-top': 'spacing',\n 'margin-right': 'spacing',\n 'margin-bottom': 'spacing',\n 'margin-left': 'spacing',\n 'padding': 'spacing',\n 'padding-top': 'spacing',\n 'padding-right': 'spacing',\n 'padding-bottom': 'spacing',\n 'padding-left': 'spacing',\n 'gap': 'spacing',\n 'row-gap': 'spacing',\n 'column-gap': 'spacing',\n\n // Shadows\n 'box-shadow': 'shadow',\n 'text-shadow': 'shadow',\n\n // Radius\n 'border-radius': 'radius',\n 'border-top-left-radius': 'radius',\n 'border-top-right-radius': 'radius',\n 'border-bottom-left-radius': 'radius',\n 'border-bottom-right-radius': 'radius',\n\n // Layout\n 'display': 'layout',\n 'flex-direction': 'layout',\n 'justify-content': 'layout',\n 'align-items': 'layout',\n 'grid-template-columns': 'layout',\n 'grid-template-rows': 'layout',\n 'position': 'layout',\n\n // Visual effects\n 'backdrop-filter': 'other',\n 'filter': 'other',\n 'animation': 'other',\n 'transition': 'other',\n};\n\n/**\n * Determine the category for a CSS property\n */\nfunction getCategory(property: string, value?: string): TokenCategory | null {\n // Exact match\n if (CATEGORY_MAP[property]) {\n return CATEGORY_MAP[property];\n }\n\n // CSS custom properties (variables)\n if (property.startsWith('--')) {\n const lower = property.toLowerCase();\n\n // Color — keyword-based detection (expanded for Shadcn/Tailwind patterns)\n const colorKeywords = [\n 'color', 'bg', 'text', 'foreground', 'background',\n // Semantic color tokens (Shadcn UI / Tailwind)\n 'primary', 'secondary', 'accent', 'muted', 'destructive',\n 'success', 'warning', 'danger', 'error', 'info',\n // UI component colors\n 'card', 'popover', 'border', 'input', 'ring',\n 'sidebar', 'chart', 'glow',\n // State colors\n 'hover', 'active', 'focus', 'disabled',\n ];\n if (colorKeywords.some(kw => lower.includes(kw))) return 'color';\n\n // Font\n if (lower.includes('font') || lower.includes('size') || lower.includes('weight') || lower.includes('line-height') || lower.includes('letter')) return 'font';\n\n // Spacing\n if (lower.includes('spacing') || lower.includes('margin') || lower.includes('padding') || lower.includes('gap') || lower.includes('inset')) return 'spacing';\n\n // Shadow\n if (lower.includes('shadow')) return 'shadow';\n\n // Radius\n if (lower.includes('radius') || lower.includes('rounded')) return 'radius';\n\n // Layout\n if (lower.includes('width') || lower.includes('height') || lower.includes('sidebar-width')) return 'layout';\n\n // Value-based fallback: detect HSL bare values (e.g., \"217 91% 60%\") or hex/rgb/hsl\n if (value) {\n const trimmed = value.trim();\n // HSL bare format: \"H S% L%\" (common in Tailwind/Shadcn)\n if (/^\\d{1,3}\\s+\\d{1,3}%\\s+\\d{1,3}%$/.test(trimmed)) return 'color';\n // hex, rgb, hsl, oklch, color functions\n if (/^(#|rgb|hsl|oklch|lch|lab|color\\()/.test(trimmed)) return 'color';\n }\n\n return 'other';\n }\n\n return null;\n}\n\n/**\n * Parse CSS content and extract design tokens\n */\nexport function parseCss(\n cssContent: string,\n filePath: string,\n): DesignToken[] {\n const tokens: DesignToken[] = [];\n\n try {\n const ast = csstree.parse(cssContent, {\n filename: filePath,\n positions: true,\n });\n\n csstree.walk(ast, {\n visit: 'Declaration',\n enter(node) {\n const property = node.property;\n const value = csstree.generate(node.value);\n const category = getCategory(property, value);\n\n if (!category) return;\n\n // Skip empty, inherit, initial, unset\n if (!value || ['inherit', 'initial', 'unset', 'revert'].includes(value)) return;\n\n // Find the parent selector\n let selector = ':root';\n let parent = this.atrule ?? this.rule;\n if (parent && parent.type === 'Rule' && parent.prelude) {\n selector = csstree.generate(parent.prelude);\n }\n\n tokens.push({\n category,\n property,\n value: value.trim(),\n selector,\n file: filePath,\n line: node.loc?.start?.line,\n });\n },\n });\n } catch (error) {\n // If parsing fails, return what we have so far\n console.warn(`Warning: Failed to parse CSS in ${filePath}: ${(error as Error).message}`);\n }\n\n return tokens;\n}\n\n/**\n * Extract CSS custom properties (variables) specifically\n */\nexport function extractCssVariables(\n cssContent: string,\n filePath: string,\n): DesignToken[] {\n const tokens: DesignToken[] = [];\n // Match --variable: value patterns\n const varRegex = /--([\\w-]+)\\s*:\\s*([^;]+)/g;\n let match;\n\n while ((match = varRegex.exec(cssContent)) !== null) {\n const property = `--${match[1]}`;\n const value = match[2].trim();\n const category = getCategory(property, value) ?? 'other';\n\n tokens.push({\n category,\n property,\n value,\n selector: ':root',\n file: filePath,\n line: cssContent.substring(0, match.index).split('\\n').length,\n });\n }\n\n return tokens;\n}\n","import * as cheerio from 'cheerio';\nimport type { DesignToken, TokenCategory } from '../types/index.js';\n\n/**\n * Style properties we want to extract from inline styles\n */\nconst TRACKED_PROPERTIES: Record<string, TokenCategory> = {\n 'color': 'color',\n 'background-color': 'color',\n 'background': 'color',\n 'border-color': 'color',\n 'font-family': 'font',\n 'font-size': 'font',\n 'font-weight': 'font',\n 'line-height': 'font',\n 'margin': 'spacing',\n 'margin-top': 'spacing',\n 'margin-right': 'spacing',\n 'margin-bottom': 'spacing',\n 'margin-left': 'spacing',\n 'padding': 'spacing',\n 'padding-top': 'spacing',\n 'padding-right': 'spacing',\n 'padding-bottom': 'spacing',\n 'padding-left': 'spacing',\n 'gap': 'spacing',\n 'box-shadow': 'shadow',\n 'text-shadow': 'shadow',\n 'border-radius': 'radius',\n 'display': 'layout',\n 'flex-direction': 'layout',\n 'justify-content': 'layout',\n 'align-items': 'layout',\n\n // Visual effects\n 'backdrop-filter': 'other',\n 'filter': 'other',\n 'animation': 'other',\n 'transition': 'other',\n};\n\n/**\n * Parse inline styles from a style attribute string\n */\nfunction parseInlineStyle(styleStr: string): Record<string, string> {\n const result: Record<string, string> = {};\n const declarations = styleStr.split(';').filter(Boolean);\n\n for (const decl of declarations) {\n const colonIdx = decl.indexOf(':');\n if (colonIdx === -1) continue;\n\n const prop = decl.substring(0, colonIdx).trim().toLowerCase();\n const val = decl.substring(colonIdx + 1).trim();\n\n if (prop && val) {\n result[prop] = val;\n }\n }\n\n return result;\n}\n\n/**\n * Parse HTML content and extract design tokens from:\n * 1. <style> blocks\n * 2. Inline style attributes\n */\nexport function parseHtml(\n htmlContent: string,\n filePath: string,\n): DesignToken[] {\n const tokens: DesignToken[] = [];\n const $ = cheerio.load(htmlContent);\n\n // 1. Extract from <style> blocks (will be handled by CSS parser upstream)\n // We return them separately as raw CSS strings\n const styleBlocks: string[] = [];\n $('style').each((_, el) => {\n const text = $(el).text();\n if (text) {\n styleBlocks.push(text);\n }\n });\n\n // 2. Extract from inline style attributes\n $('[style]').each((_, el) => {\n const element = $(el);\n const styleStr = element.attr('style');\n if (!styleStr) return;\n\n const selector = buildSelectorPath($, element);\n const styles = parseInlineStyle(styleStr);\n\n for (const [prop, value] of Object.entries(styles)) {\n const category = TRACKED_PROPERTIES[prop];\n if (!category) continue;\n\n tokens.push({\n category,\n property: prop,\n value,\n selector: `[inline] ${selector}`,\n file: filePath,\n });\n }\n });\n\n return tokens;\n}\n\n/**\n * Extract raw CSS from <style> blocks in HTML\n */\nexport function extractStyleBlocks(htmlContent: string): string[] {\n const $ = cheerio.load(htmlContent);\n const blocks: string[] = [];\n\n $('style').each((_, el) => {\n const text = $(el).text();\n if (text) {\n blocks.push(text);\n }\n });\n\n return blocks;\n}\n\n/**\n * Extract design tokens from Tailwind config in <script> tags.\n * Stitch generates HTML with tailwind config like:\n * <script id=\"tailwind-config\">\n * tailwind.config = { theme: { extend: { colors: { \"primary\": \"#256af4\" }, ... } } }\n * </script>\n */\nexport function extractTailwindConfig(\n htmlContent: string,\n filePath: string,\n): DesignToken[] {\n const tokens: DesignToken[] = [];\n const $ = cheerio.load(htmlContent);\n\n // Find script tags that contain tailwind config\n $('script').each((_, el) => {\n const scriptId = $(el).attr('id') ?? '';\n const text = $(el).text();\n if (!text) return;\n\n // Match scripts with id=\"tailwind-config\" or containing \"tailwind.config\"\n const isTailwindConfig =\n scriptId.toLowerCase().includes('tailwind') ||\n text.includes('tailwind.config');\n\n if (!isTailwindConfig) return;\n\n // Extract colors\n const colorsMatch = text.match(/colors\\s*:\\s*\\{([^}]+)\\}/);\n if (colorsMatch) {\n const colorsBlock = colorsMatch[1];\n const colorRegex = /[\"']([^\"']+)[\"']\\s*:\\s*[\"']([^\"']+)[\"']/g;\n let match;\n while ((match = colorRegex.exec(colorsBlock)) !== null) {\n tokens.push({\n category: 'color',\n property: `--tw-${match[1]}`,\n value: match[2],\n selector: '[tailwind.config]',\n file: filePath,\n });\n }\n }\n\n // Extract borderRadius\n const radiusMatch = text.match(/borderRadius\\s*:\\s*\\{([^}]+)\\}/);\n if (radiusMatch) {\n const radiusBlock = radiusMatch[1];\n const radiusRegex = /[\"']([^\"']+)[\"']\\s*:\\s*[\"']([^\"']+)[\"']/g;\n let match;\n while ((match = radiusRegex.exec(radiusBlock)) !== null) {\n tokens.push({\n category: 'radius',\n property: `--tw-radius-${match[1]}`,\n value: match[2],\n selector: '[tailwind.config]',\n file: filePath,\n });\n }\n }\n\n // Extract fontFamily\n const fontMatch = text.match(/fontFamily\\s*:\\s*\\{([^}]+)\\}/);\n if (fontMatch) {\n const fontBlock = fontMatch[1];\n // Match: \"display\": [\"Inter\", \"sans-serif\"] or \"body\": [\"Roboto\"]\n const fontRegex = /[\"']([^\"']+)[\"']\\s*:\\s*\\[([^\\]]+)\\]/g;\n let match;\n while ((match = fontRegex.exec(fontBlock)) !== null) {\n const familyValues = match[2]\n .split(',')\n .map(v => v.trim().replace(/[\"']/g, ''))\n .join(', ');\n tokens.push({\n category: 'font',\n property: `--tw-font-${match[1]}`,\n value: familyValues,\n selector: '[tailwind.config]',\n file: filePath,\n });\n }\n }\n });\n\n return tokens;\n}\n\n/**\n * Build a human-readable selector path for an element\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction buildSelectorPath($: cheerio.CheerioAPI, element: any): string {\n const parts: string[] = [];\n const tagName = element.prop('tagName')?.toLowerCase() ?? 'div';\n const id = element.attr('id');\n const className = element.attr('class');\n\n let sel = tagName;\n if (id) {\n sel += `#${id}`;\n } else if (className) {\n const classList = className.split(/\\s+/).slice(0, 2).join('.');\n sel += `.${classList}`;\n }\n\n parts.push(sel);\n return parts.join(' > ');\n}\n","import type {\n DesignSnapshot,\n DesignToken,\n DriftItem,\n DriftReport,\n TokenCategory,\n StructureDriftReport,\n} from '../types/index.js';\nimport { scanProject, loadConfig } from './snapshot.js';\nimport { computeStructureFingerprint, compareStructure } from '../parsers/structure-parser.js';\n\n/**\n * Compare two tokens by their key (file + selector + property)\n */\nfunction tokenKey(token: DesignToken): string {\n return `${token.file}::${token.selector}::${token.property}`;\n}\n\n/**\n * Detect design drift between a snapshot and the current project state\n */\nexport async function detectDrift(\n projectRoot: string,\n snapshot: DesignSnapshot,\n threshold: number = 10,\n): Promise<DriftReport> {\n const config = loadConfig(projectRoot);\n const { tokens: currentTokens } = await scanProject(projectRoot, config);\n\n // Build lookup maps\n const snapshotMap = new Map<string, DesignToken>();\n for (const token of snapshot.tokens) {\n snapshotMap.set(tokenKey(token), token);\n }\n\n const currentMap = new Map<string, DesignToken>();\n for (const token of currentTokens) {\n currentMap.set(tokenKey(token), token);\n }\n\n const driftItems: DriftItem[] = [];\n\n // Check for modified and deleted tokens\n for (const [key, original] of snapshotMap) {\n const current = currentMap.get(key);\n\n if (!current) {\n // Token was deleted\n driftItems.push({\n original,\n current: null,\n changeType: 'deleted',\n });\n } else if (current.value !== original.value) {\n // Token was modified\n driftItems.push({\n original,\n current,\n changeType: 'modified',\n });\n }\n }\n\n // Check for added tokens (in current but not in snapshot)\n // Note: Added tokens are tracked but don't count as \"drift\" by default\n // because adding new styles is expected behavior during feature development\n\n const totalTokens = snapshot.tokens.length;\n const changedTokens = driftItems.length;\n const driftScore = totalTokens > 0\n ? Math.round((changedTokens / totalTokens) * 100 * 100) / 100\n : 0;\n\n // Build category summary\n const categorySummary: DriftReport['categorySummary'] = {} as DriftReport['categorySummary'];\n const categories: TokenCategory[] = ['color', 'font', 'spacing', 'shadow', 'radius', 'layout', 'other'];\n\n for (const cat of categories) {\n const total = snapshot.tokens.filter(t => t.category === cat).length;\n const changed = driftItems.filter(d => d.original.category === cat).length;\n categorySummary[cat] = {\n total,\n changed,\n driftPercent: total > 0 ? Math.round((changed / total) * 100 * 100) / 100 : 0,\n };\n }\n\n // Structure drift detection (v0.2.0+)\n let structureDrift: StructureDriftReport | undefined;\n\n if (snapshot.structure) {\n try {\n // Find HTML content to compute current structure\n const config = loadConfig(projectRoot);\n const fg = (await import('fast-glob')).default;\n const htmlFiles = await fg(config.htmlFiles, {\n cwd: projectRoot,\n ignore: config.ignore,\n absolute: false,\n });\n\n let htmlContent: string | null = null;\n const fs = await import('node:fs');\n const path = await import('node:path');\n\n for (const file of htmlFiles) {\n const absPath = path.join(projectRoot, file);\n if (fs.existsSync(absPath)) {\n htmlContent = fs.readFileSync(absPath, 'utf-8');\n break;\n }\n }\n\n if (htmlContent) {\n const currentStructure = computeStructureFingerprint(htmlContent);\n const details = compareStructure(snapshot.structure, currentStructure);\n structureDrift = {\n changed: details.length > 0,\n details,\n };\n }\n } catch {\n // Structure comparison is optional — don't fail the check\n }\n }\n\n return {\n checkedAt: new Date().toISOString(),\n snapshotCreatedAt: snapshot.createdAt,\n totalTokens,\n changedTokens,\n driftScore,\n threshold,\n passed: driftScore <= threshold,\n items: driftItems,\n categorySummary,\n structureDrift,\n };\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { DesignSnapshot, RuleFormat } from '../types/index.js';\n\n/**\n * Generate AI agent rules from a design snapshot\n */\nexport function generateRules(\n snapshot: DesignSnapshot,\n format: RuleFormat,\n): string {\n const generators: Record<RuleFormat, () => string> = {\n 'cursorrules': () => generateCursorRules(snapshot),\n 'claude-md': () => generateClaudeMd(snapshot),\n 'agents-md': () => generateAgentsMd(snapshot),\n 'copilot': () => generateCopilotInstructions(snapshot),\n 'clinerules': () => generateClineRules(snapshot),\n };\n\n return generators[format]();\n}\n\n/**\n * Save rules to the appropriate file\n */\nexport function saveRules(\n projectRoot: string,\n format: RuleFormat,\n content: string,\n append: boolean = false,\n): string {\n const fileMap: Record<RuleFormat, string> = {\n 'cursorrules': '.cursorrules',\n 'claude-md': 'CLAUDE.md',\n 'agents-md': 'AGENTS.md',\n 'copilot': '.github/copilot-instructions.md',\n 'clinerules': '.clinerules',\n };\n\n const filePath = path.join(projectRoot, fileMap[format]);\n const dir = path.dirname(filePath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n if (append && fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf-8');\n fs.writeFileSync(filePath, existing + '\\n\\n' + content, 'utf-8');\n } else {\n fs.writeFileSync(filePath, content, 'utf-8');\n }\n\n return filePath;\n}\n\n// ─── Template generators ───────────────────────────────────\n\nfunction buildTokenList(snapshot: DesignSnapshot): string {\n const colorTokens = snapshot.tokens.filter(t => t.category === 'color');\n const fontTokens = snapshot.tokens.filter(t => t.category === 'font');\n const spacingTokens = snapshot.tokens.filter(t => t.category === 'spacing');\n const radiusTokens = snapshot.tokens.filter(t => t.category === 'radius');\n\n const lines: string[] = [];\n\n if (colorTokens.length > 0) {\n lines.push('### Colors (DO NOT CHANGE)');\n const unique = [...new Set(colorTokens.map(t => `${t.property}: ${t.value}`))];\n for (const t of unique.slice(0, 30)) {\n lines.push(`- \\`${t}\\``);\n }\n }\n\n if (fontTokens.length > 0) {\n lines.push('\\n### Fonts (DO NOT CHANGE)');\n const unique = [...new Set(fontTokens.map(t => `${t.property}: ${t.value}`))];\n for (const t of unique.slice(0, 15)) {\n lines.push(`- \\`${t}\\``);\n }\n }\n\n if (spacingTokens.length > 0) {\n lines.push('\\n### Spacing (DO NOT CHANGE)');\n const unique = [...new Set(spacingTokens.map(t => `${t.property}: ${t.value}`))];\n for (const t of unique.slice(0, 20)) {\n lines.push(`- \\`${t}\\``);\n }\n }\n\n if (radiusTokens.length > 0) {\n lines.push('\\n### Border Radius (DO NOT CHANGE)');\n const unique = [...new Set(radiusTokens.map(t => `${t.property}: ${t.value}`))];\n for (const t of unique.slice(0, 10)) {\n lines.push(`- \\`${t}\\``);\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction generateCursorRules(snapshot: DesignSnapshot): string {\n return `# Design Guard — Locked Design Tokens\n# Generated by drift-guard on ${snapshot.createdAt}\n# DO NOT modify these values when adding features or fixing bugs.\n\n## CRITICAL: Design Drift Prevention\n\nWhen modifying this codebase, you MUST preserve the following design tokens exactly as they are.\nDo NOT change colors, fonts, spacing, or border-radius values unless explicitly asked to update the design.\n\nIf you need to add new styles, use the existing design tokens as reference.\nIf a design change is needed, tell the user to run \\`drift-guard snapshot update\\` after making the change.\n\n${buildTokenList(snapshot)}\n\n## Rules\n1. NEVER change existing CSS color values\n2. NEVER change font-family, font-size, or font-weight values\n3. NEVER change margin, padding, or gap values on existing elements\n4. NEVER change border-radius values\n5. When adding new components, use the SAME design tokens listed above\n6. If you must change a design token, warn the user first\n`;\n}\n\nfunction generateClaudeMd(snapshot: DesignSnapshot): string {\n return `# Design Guard — Locked Design Tokens\n\n> Generated by drift-guard on ${snapshot.createdAt}\n> Run \\`npx drift-guard check\\` to verify design consistency\n\n## Design Drift Prevention Rules\n\nWhen working on this codebase, preserve the existing design exactly as-is.\nThe following design tokens are LOCKED and should NOT be modified:\n\n${buildTokenList(snapshot)}\n\n## Important\n- Adding new features should NOT change existing visual styles\n- If a CSS change affects existing components, flag it to the user\n- New components should follow the same design language (colors, fonts, spacing)\n- Run \\`npx drift-guard check\\` before committing to verify no design drift\n`;\n}\n\nfunction generateAgentsMd(snapshot: DesignSnapshot): string {\n return `# AGENTS.md — Design Guard Rules\n\n> Auto-generated by drift-guard. Do not edit manually.\n> Snapshot: ${snapshot.createdAt} | Tokens: ${snapshot.tokens.length}\n\n## Design Token Protection\n\nThis project uses drift-guard to prevent design drift during AI-assisted development.\nThe following design tokens are protected:\n\n${buildTokenList(snapshot)}\n\n## Agent Instructions\n1. Do NOT modify existing CSS values for colors, fonts, spacing, or border-radius\n2. New components MUST use the same design tokens\n3. Run \\`npx drift-guard check\\` before suggesting commits\n4. If design changes are intentional, inform the user to update the snapshot\n`;\n}\n\nfunction generateCopilotInstructions(snapshot: DesignSnapshot): string {\n return `# Copilot Instructions — Design Guard\n\nThis project has locked design tokens. When suggesting code changes:\n\n1. Preserve all existing CSS color, font, spacing, and border-radius values\n2. Use the project's design tokens for new components\n3. Do not override CSS custom properties (variables starting with --)\n\nProtected tokens (${snapshot.tokens.length} total):\n\n${buildTokenList(snapshot)}\n`;\n}\n\nfunction generateClineRules(snapshot: DesignSnapshot): string {\n return `# Design Guard — Protected Design Tokens\n# Generated: ${snapshot.createdAt}\n\nDESIGN_PROTECTION=true\n\n## Rules\n- Do NOT change existing CSS values\n- Preserve colors: ${snapshot.summary.color} tokens locked\n- Preserve fonts: ${snapshot.summary.font} tokens locked\n- Preserve spacing: ${snapshot.summary.spacing} tokens locked\n- Preserve radius: ${snapshot.summary.radius} tokens locked\n\n## Verification\nRun: npx drift-guard check\nThreshold: Changes to more than 10% of design tokens will be flagged\n\n${buildTokenList(snapshot)}\n`;\n}\n","import type {\n DriftItem,\n DesignToken,\n SyncChange,\n SyncResult,\n SyncDirection,\n TokenCategory,\n} from '../types/index.js';\n\n/**\n * Human-readable labels for token categories\n */\nconst CATEGORY_LABELS: Record<TokenCategory, string> = {\n color: 'color',\n font: 'font',\n spacing: 'spacing',\n shadow: 'shadow',\n radius: 'border-radius',\n layout: 'layout',\n other: 'style',\n};\n\n/**\n * Properties that are design tokens (CSS custom properties or Tailwind config).\n * Inline style properties like 'display', 'align-items' are NOT design tokens.\n */\nfunction isDesignTokenProperty(property: string): boolean {\n // CSS custom properties (--*) and Tailwind config tokens (--tw-*)\n if (property.startsWith('--')) return true;\n // font-family is a design token\n if (property === 'font-family') return true;\n return false;\n}\n\n/**\n * Normalize a token key for matching across Stitch HTML and code CSS.\n * Maps between different naming conventions:\n * Stitch Tailwind config: --tw-primary\n * Code CSS variable: --primary\n */\nfunction normalizeTokenKey(property: string): string {\n return property\n .replace(/^--tw-/, '--') // --tw-primary → --primary\n .replace(/^--tw-font-/, '--font-') // --tw-font-display → --font-display\n .toLowerCase();\n}\n\n/**\n * Convert DriftItems into SyncChanges\n */\nexport function driftItemsToSyncChanges(items: DriftItem[]): SyncChange[] {\n return items.map((item) => {\n if (item.changeType === 'deleted') {\n return {\n category: item.original.category,\n property: item.original.property,\n fromValue: item.original.value,\n toValue: '',\n action: 'remove' as const,\n };\n }\n\n if (item.changeType === 'added') {\n return {\n category: (item.current ?? item.original).category,\n property: (item.current ?? item.original).property,\n fromValue: '',\n toValue: (item.current ?? item.original).value,\n action: 'add' as const,\n };\n }\n\n // modified\n return {\n category: item.original.category,\n property: item.original.property,\n fromValue: item.original.value,\n toValue: item.current?.value ?? '',\n action: 'update' as const,\n };\n });\n}\n\n/**\n * Generate a natural language prompt from sync changes.\n * This prompt is designed for Stitch's `edit_screens` API.\n */\nexport function generateSyncPrompt(changes: SyncChange[]): string {\n if (changes.length === 0) {\n return '';\n }\n\n // Group changes by category\n const grouped = new Map<TokenCategory, SyncChange[]>();\n for (const change of changes) {\n const existing = grouped.get(change.category) ?? [];\n existing.push(change);\n grouped.set(change.category, existing);\n }\n\n const lines: string[] = [\n 'Update the following design tokens to match the latest code changes:',\n '',\n ];\n\n for (const [category, categoryChanges] of grouped) {\n const label = CATEGORY_LABELS[category];\n\n for (const change of categoryChanges) {\n const propName = cleanPropertyName(change.property);\n\n if (change.action === 'update') {\n lines.push(\n `- Change ${label} '${propName}' from ${change.fromValue} to ${change.toValue}`,\n );\n } else if (change.action === 'add') {\n lines.push(\n `- Add new ${label} '${propName}' with value ${change.toValue}`,\n );\n } else if (change.action === 'remove') {\n lines.push(\n `- Remove ${label} '${propName}' (was ${change.fromValue})`,\n );\n }\n }\n }\n\n lines.push('');\n lines.push(\n 'Keep all other design elements unchanged. Only modify the specified tokens.',\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Clean up property names for human-readable prompts.\n */\nfunction cleanPropertyName(property: string): string {\n return property\n .replace(/^--tw-/, '')\n .replace(/^--tw-radius-/, '')\n .replace(/^--tw-font-/, '')\n .replace(/^--/, '');\n}\n\n/**\n * Build a SyncResult for pushing code changes to Stitch.\n */\nexport function syncToStitch(driftItems: DriftItem[]): SyncResult {\n const changes = driftItemsToSyncChanges(driftItems);\n const prompt = generateSyncPrompt(changes);\n\n return {\n direction: 'to-stitch' as SyncDirection,\n changes,\n prompt: prompt || undefined,\n timestamp: new Date().toISOString(),\n };\n}\n\n/**\n * Build a SyncResult for pulling Stitch changes to code.\n *\n * ONLY compares design tokens that exist in BOTH Stitch and snapshot.\n * Code-only tokens (e.g., Shadcn --background, --sidebar) are NOT\n * flagged as \"removed\" — Stitch doesn't own them.\n */\nexport function syncFromStitch(\n stitchTokens: DesignToken[],\n snapshotTokens: DesignToken[],\n): SyncResult {\n const changes: SyncChange[] = [];\n\n // Filter to design-token-only properties\n const stitchDesignTokens = stitchTokens.filter(t => isDesignTokenProperty(t.property));\n const snapshotDesignTokens = snapshotTokens.filter(t => isDesignTokenProperty(t.property));\n\n // Build normalized lookup maps\n const snapshotMap = new Map<string, DesignToken>();\n for (const token of snapshotDesignTokens) {\n const key = normalizeTokenKey(token.property);\n if (!snapshotMap.has(key)) {\n snapshotMap.set(key, token);\n }\n }\n\n const stitchMap = new Map<string, DesignToken>();\n for (const token of stitchDesignTokens) {\n const key = normalizeTokenKey(token.property);\n if (!stitchMap.has(key)) {\n stitchMap.set(key, token);\n }\n }\n\n // Find updates and adds: stitch token differs or new\n for (const [key, stitchToken] of stitchMap) {\n const snapshotToken = snapshotMap.get(key);\n\n if (!snapshotToken) {\n changes.push({\n category: stitchToken.category,\n property: stitchToken.property,\n fromValue: '',\n toValue: stitchToken.value,\n action: 'add',\n });\n } else if (stitchToken.value !== snapshotToken.value) {\n changes.push({\n category: stitchToken.category,\n property: snapshotToken.property,\n fromValue: snapshotToken.value,\n toValue: stitchToken.value,\n action: 'update',\n });\n }\n }\n\n // Removals: only flag tokens that are clearly Stitch-origin\n // (i.e., --tw-* prefixed in snapshot AND missing from stitch)\n // This avoids false-flagging code-only tokens like --background\n if (stitchDesignTokens.length > 0) {\n for (const [key, snapshotToken] of snapshotMap) {\n const isStitchOrigin = snapshotToken.property.startsWith('--tw-')\n || snapshotToken.selector === '[tailwind.config]';\n if (isStitchOrigin && !stitchMap.has(key)) {\n changes.push({\n category: snapshotToken.category,\n property: snapshotToken.property,\n fromValue: snapshotToken.value,\n toValue: '',\n action: 'remove',\n });\n }\n }\n }\n\n const patchFile = generateCssPatch(changes);\n\n return {\n direction: 'to-code' as SyncDirection,\n changes,\n patchFile: patchFile || undefined,\n timestamp: new Date().toISOString(),\n };\n}\n\n/**\n * Apply sync changes to actual CSS files in the project.\n */\nexport function applySyncChanges(\n changes: SyncChange[],\n cssFiles: Map<string, string>,\n): { modifiedFiles: Map<string, string>; appliedCount: number } {\n const modifiedFiles = new Map<string, string>();\n let appliedCount = 0;\n\n const updateChanges = changes.filter(c => c.action === 'update');\n\n for (const [filename, content] of cssFiles) {\n let modified = content;\n let fileChanged = false;\n\n for (const change of updateChanges) {\n // Try CSS custom property replacement\n const propName = change.property.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const escapedFrom = change.fromValue.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const cssRegex = new RegExp(\n `(${propName}\\\\s*:\\\\s*)${escapedFrom}(\\\\s*[;\\\\n])`,\n 'g',\n );\n\n let newContent = modified.replace(cssRegex, `$1${change.toValue}$2`);\n\n // Also try Tailwind config format in <script> tags:\n // \"primary\": \"#256af4\" → \"primary\": \"#8b5cf6\"\n if (newContent === modified) {\n const twResult = applySyncToHtml(modified, change);\n if (twResult !== modified) {\n newContent = twResult;\n }\n }\n\n if (newContent !== modified) {\n modified = newContent;\n fileChanged = true;\n appliedCount++;\n }\n }\n\n if (fileChanged) {\n modifiedFiles.set(filename, modified);\n }\n }\n\n return { modifiedFiles, appliedCount };\n}\n\n/**\n * Apply a sync change to HTML content by editing Tailwind config <script> values.\n * Handles format: \"primary\": \"#256af4\" → \"primary\": \"#8b5cf6\"\n */\nfunction applySyncToHtml(html: string, change: SyncChange): string {\n // Extract the token name from --tw-primary → primary\n const tokenName = change.property\n .replace(/^--tw-/, '')\n .replace(/^--/, '');\n\n const escapedFrom = change.fromValue.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Match: \"primary\": \"#256af4\" or \"primary\": \"Inter\"\n const regex = new RegExp(\n `(\"${tokenName}\"\\\\s*:\\\\s*)[\"']${escapedFrom}[\"']`,\n 'g',\n );\n\n return html.replace(regex, `$1\"${change.toValue}\"`);\n}\n\n/**\n * Generate CSS variable patch content from sync changes.\n */\nfunction generateCssPatch(changes: SyncChange[]): string {\n if (changes.length === 0) return '';\n\n const lines: string[] = [\n '/* drift-guard sync patch — apply these changes to your CSS */',\n '/* Generated by: drift-guard sync --direction to-code */',\n '',\n ':root {',\n ];\n\n for (const change of changes) {\n if (change.action === 'remove') {\n lines.push(` /* REMOVED: ${change.property}: ${change.fromValue}; */`);\n } else {\n const comment =\n change.action === 'update'\n ? ` /* was: ${change.fromValue} */`\n : ' /* NEW */';\n lines.push(` ${change.property}: ${change.toValue};${comment}`);\n }\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["cheerio","config","fg","fs","path","fs","path"]}
|