@fragments-sdk/cli 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/bin.js +996 -79
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-ICAIQ57V.js → chunk-6JBGU74P.js} +5 -3
  4. package/dist/chunk-6JBGU74P.js.map +1 -0
  5. package/dist/chunk-7OPWMLOE.js +1625 -0
  6. package/dist/chunk-7OPWMLOE.js.map +1 -0
  7. package/dist/{chunk-2H2JAA3U.js → chunk-CVXKXVOY.js} +3 -3
  8. package/dist/{chunk-2H2JAA3U.js.map → chunk-CVXKXVOY.js.map} +1 -1
  9. package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
  10. package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
  11. package/dist/{chunk-V7YLRR4C.js → chunk-TJ34N7C7.js} +41 -4
  12. package/dist/{chunk-V7YLRR4C.js.map → chunk-TJ34N7C7.js.map} +1 -1
  13. package/dist/{chunk-XNWDI6UT.js → chunk-XHUDJNN3.js} +5 -5
  14. package/dist/{core-DKHB7FYV.js → core-W2HYIQW6.js} +4 -4
  15. package/dist/{generate-KL24VZVD.js → generate-LMTISDIJ.js} +5 -5
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +15 -7
  18. package/dist/index.js.map +1 -1
  19. package/dist/{init-NION5S3M.js → init-7CHRKQ7P.js} +5 -5
  20. package/dist/mcp-bin.js +8 -220
  21. package/dist/mcp-bin.js.map +1 -1
  22. package/dist/scan-WY23TJCP.js +12 -0
  23. package/dist/{service-RWUMZ3EW.js → service-T2L7VLTE.js} +5 -5
  24. package/dist/static-viewer-GBR7YNF3.js +12 -0
  25. package/dist/{test-ECPEXFDN.js → test-OJRXNDO2.js} +4 -4
  26. package/dist/{tokens-ITADYVPF.js → tokens-3BWDESVM.js} +6 -6
  27. package/dist/viewer-SUFOISZM.js +1822 -0
  28. package/dist/viewer-SUFOISZM.js.map +1 -0
  29. package/package.json +6 -5
  30. package/src/bin.ts +31 -0
  31. package/src/build.ts +147 -13
  32. package/src/cli-commands.ts +18 -0
  33. package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
  34. package/src/commands/a11y-report.ts +625 -0
  35. package/src/commands/a11y.ts +168 -14
  36. package/src/commands/build.ts +16 -0
  37. package/src/commands/graph.ts +274 -0
  38. package/src/core/auto-props.ts +464 -0
  39. package/src/core/composition.ts +64 -1
  40. package/src/core/graph-extractor.test.ts +542 -0
  41. package/src/core/graph-extractor.ts +601 -0
  42. package/src/core/importAnalyzer.ts +5 -0
  43. package/src/core/schema.ts +2 -0
  44. package/src/core/types.ts +3 -1
  45. package/src/index.ts +4 -0
  46. package/src/mcp/server.ts +13 -220
  47. package/src/theme/__tests__/component-contrast.test.ts +338 -0
  48. package/src/theme/__tests__/contrast-validation.test.ts +326 -0
  49. package/src/theme/contrast.test.ts +331 -0
  50. package/src/theme/contrast.ts +246 -0
  51. package/src/theme/generator.ts +213 -1
  52. package/src/theme/index.ts +16 -0
  53. package/src/theme/types.ts +51 -0
  54. package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
  55. package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
  56. package/src/viewer/components/AccessibilityPanel.tsx +493 -433
  57. package/src/viewer/components/ActionCapture.tsx +1 -1
  58. package/src/viewer/components/ActionsPanel.tsx +142 -183
  59. package/src/viewer/components/App.tsx +276 -183
  60. package/src/viewer/components/BottomPanel.tsx +40 -80
  61. package/src/viewer/components/CodePanel.tsx +9 -87
  62. package/src/viewer/components/CommandPalette.tsx +117 -74
  63. package/src/viewer/components/ComponentGraph.tsx +143 -126
  64. package/src/viewer/components/ComponentHeader.tsx +46 -43
  65. package/src/viewer/components/ContractPanel.tsx +124 -117
  66. package/src/viewer/components/ErrorBoundary.tsx +47 -35
  67. package/src/viewer/components/FigmaEmbed.tsx +18 -13
  68. package/src/viewer/components/FragmentEditor.tsx +126 -63
  69. package/src/viewer/components/HealthDashboard.tsx +146 -171
  70. package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
  71. package/src/viewer/components/Icons.tsx +151 -98
  72. package/src/viewer/components/InteractionsPanel.tsx +317 -264
  73. package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
  74. package/src/viewer/components/IsolatedRender.tsx +12 -6
  75. package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
  76. package/src/viewer/components/LandingPage.tsx +285 -305
  77. package/src/viewer/components/Layout.tsx +12 -10
  78. package/src/viewer/components/LeftSidebar.tsx +103 -155
  79. package/src/viewer/components/MultiViewportPreview.tsx +254 -63
  80. package/src/viewer/components/PreviewArea.tsx +113 -44
  81. package/src/viewer/components/PreviewFrameHost.tsx +36 -6
  82. package/src/viewer/components/PreviewPane.tsx +2 -3
  83. package/src/viewer/components/PreviewToolbar.tsx +109 -105
  84. package/src/viewer/components/PropsEditor.tsx +154 -74
  85. package/src/viewer/components/PropsTable.tsx +95 -82
  86. package/src/viewer/components/RelationsSection.tsx +71 -40
  87. package/src/viewer/components/ResizablePanel.tsx +158 -55
  88. package/src/viewer/components/RightSidebar.tsx +46 -56
  89. package/src/viewer/components/ScreenshotButton.tsx +12 -12
  90. package/src/viewer/components/SkeletonLoader.tsx +99 -83
  91. package/src/viewer/components/StoryRenderer.tsx +4 -11
  92. package/src/viewer/components/Toast.tsx +3 -67
  93. package/src/viewer/components/TokenStylePanel.tsx +136 -118
  94. package/src/viewer/components/UsageSection.tsx +26 -26
  95. package/src/viewer/components/VariantMatrix.tsx +140 -47
  96. package/src/viewer/components/VariantTabs.tsx +24 -68
  97. package/src/viewer/components/ViewportSelector.tsx +121 -114
  98. package/src/viewer/constants/ui.ts +23 -22
  99. package/src/viewer/entry.tsx +8 -3
  100. package/src/viewer/index.ts +3 -6
  101. package/src/viewer/preview-frame.html +43 -18
  102. package/src/viewer/server.ts +7 -16
  103. package/src/viewer/styles/globals.css +46 -85
  104. package/src/viewer/utils/a11y-fixes.ts +53 -30
  105. package/dist/chunk-ICAIQ57V.js.map +0 -1
  106. package/dist/chunk-U4GQ2JTD.js +0 -832
  107. package/dist/chunk-U4GQ2JTD.js.map +0 -1
  108. package/dist/scan-ESEXV7LF.js +0 -12
  109. package/dist/static-viewer-O37MJ5B6.js +0 -12
  110. package/dist/viewer-YDGFDTK5.js +0 -11104
  111. package/dist/viewer-YDGFDTK5.js.map +0 -1
  112. package/src/viewer/postcss.config.js +0 -6
  113. package/src/viewer/tailwind.config.js +0 -37
  114. /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
  115. /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
  116. /package/dist/{chunk-XNWDI6UT.js.map → chunk-XHUDJNN3.js.map} +0 -0
  117. /package/dist/{core-DKHB7FYV.js.map → core-W2HYIQW6.js.map} +0 -0
  118. /package/dist/{generate-KL24VZVD.js.map → generate-LMTISDIJ.js.map} +0 -0
  119. /package/dist/{init-NION5S3M.js.map → init-7CHRKQ7P.js.map} +0 -0
  120. /package/dist/{scan-ESEXV7LF.js.map → scan-WY23TJCP.js.map} +0 -0
  121. /package/dist/{service-RWUMZ3EW.js.map → service-T2L7VLTE.js.map} +0 -0
  122. /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-GBR7YNF3.js.map} +0 -0
  123. /package/dist/{test-ECPEXFDN.js.map → test-OJRXNDO2.js.map} +0 -0
  124. /package/dist/{tokens-ITADYVPF.js.map → tokens-3BWDESVM.js.map} +0 -0
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+ import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
3
3
  import {
4
4
  buildFragmentsDir,
5
5
  buildSegments,
@@ -9,10 +9,10 @@ import {
9
9
  validateAll,
10
10
  validateCoverage,
11
11
  validateSchema
12
- } from "./chunk-U4GQ2JTD.js";
12
+ } from "./chunk-7OPWMLOE.js";
13
13
  import {
14
14
  scan
15
- } from "./chunk-XNWDI6UT.js";
15
+ } from "./chunk-XHUDJNN3.js";
16
16
  import {
17
17
  FigmaClient,
18
18
  StorageManager,
@@ -28,22 +28,22 @@ import {
28
28
  renderAllComponentVariants,
29
29
  scanCodebase,
30
30
  shutdownSharedPool
31
- } from "./chunk-IOJE35DZ.js";
31
+ } from "./chunk-NWQ4CJOQ.js";
32
32
  import {
33
33
  discoverSegmentFiles,
34
34
  loadConfig,
35
35
  loadSegmentFile
36
- } from "./chunk-2H2JAA3U.js";
36
+ } from "./chunk-CVXKXVOY.js";
37
37
  import {
38
38
  generateContext
39
- } from "./chunk-V7YLRR4C.js";
39
+ } from "./chunk-TJ34N7C7.js";
40
40
  import {
41
41
  BRAND
42
- } from "./chunk-ICAIQ57V.js";
42
+ } from "./chunk-6JBGU74P.js";
43
43
 
44
44
  // src/bin.ts
45
45
  import { Command } from "commander";
46
- import pc20 from "picocolors";
46
+ import pc21 from "picocolors";
47
47
  import { readFileSync } from "fs";
48
48
  import { fileURLToPath } from "url";
49
49
  import { dirname as dirname4, join as join10 } from "path";
@@ -145,6 +145,13 @@ ${BRAND.name} Build
145
145
  }
146
146
  console.log();
147
147
  }
148
+ if (result.warnings.length > 0) {
149
+ console.log(pc2.yellow("Build warnings:\n"));
150
+ for (const warning of result.warnings) {
151
+ console.log(` ${pc2.yellow("\u26A0")} ${warning.file}: ${warning.warning}`);
152
+ }
153
+ console.log();
154
+ }
148
155
  segmentCount = result.segmentCount;
149
156
  outputPath = result.outputPath;
150
157
  console.log(pc2.green(`\u2713 Built ${result.segmentCount} fragment(s)`));
@@ -162,6 +169,13 @@ ${BRAND.name} Build
162
169
  }
163
170
  console.log();
164
171
  }
172
+ if (fragmentsResult.warnings.length > 0) {
173
+ console.log(pc2.yellow("Registry warnings:\n"));
174
+ for (const warning of fragmentsResult.warnings) {
175
+ console.log(` ${pc2.yellow("\u26A0")} ${warning.file}: ${warning.warning}`);
176
+ }
177
+ console.log();
178
+ }
165
179
  componentCount = fragmentsResult.componentCount;
166
180
  registryPath = fragmentsResult.registryPath;
167
181
  contextPath = fragmentsResult.contextPath;
@@ -1614,19 +1628,19 @@ async function discoverStoryFiles(projectRoot, patterns) {
1614
1628
 
1615
1629
  // src/setup.ts
1616
1630
  async function isSegmentsJsonStale(configDir, outFile) {
1617
- const fs = await import("fs/promises");
1631
+ const fs2 = await import("fs/promises");
1618
1632
  const path = await import("path");
1619
1633
  const fg4 = await import("fast-glob");
1620
1634
  const segmentsJsonPath = path.join(configDir, outFile);
1621
1635
  try {
1622
- const segmentsJsonStat = await fs.stat(segmentsJsonPath);
1636
+ const segmentsJsonStat = await fs2.stat(segmentsJsonPath);
1623
1637
  const segmentFiles = await fg4.default(`**/*${BRAND.fileExtension}`, {
1624
1638
  cwd: configDir,
1625
1639
  ignore: ["**/node_modules/**"],
1626
1640
  absolute: true
1627
1641
  });
1628
1642
  for (const file of segmentFiles) {
1629
- const stat3 = await fs.stat(file);
1643
+ const stat3 = await fs2.stat(file);
1630
1644
  if (stat3.mtimeMs > segmentsJsonStat.mtimeMs) {
1631
1645
  return { stale: true, missing: false };
1632
1646
  }
@@ -1637,11 +1651,11 @@ async function isSegmentsJsonStale(configDir, outFile) {
1637
1651
  }
1638
1652
  }
1639
1653
  async function loadSegmentInfo(segmentFiles) {
1640
- const fs = await import("fs/promises");
1654
+ const fs2 = await import("fs/promises");
1641
1655
  const segments = [];
1642
1656
  for (const file of segmentFiles) {
1643
1657
  try {
1644
- const content = await fs.readFile(file.absolutePath, "utf-8");
1658
+ const content = await fs2.readFile(file.absolutePath, "utf-8");
1645
1659
  const nameMatch = content.match(/name:\s*['"]([^'"]+)['"]/);
1646
1660
  const hasFigma = /meta:\s*\{[^}]*figma:\s*['"]https?:/.test(content);
1647
1661
  if (nameMatch) {
@@ -1657,7 +1671,7 @@ async function loadSegmentInfo(segmentFiles) {
1657
1671
  return segments;
1658
1672
  }
1659
1673
  async function runSetup(options = {}) {
1660
- const fs = await import("fs/promises");
1674
+ const fs2 = await import("fs/promises");
1661
1675
  const path = await import("path");
1662
1676
  const result = {
1663
1677
  segmentFilesCreated: 0,
@@ -1685,8 +1699,8 @@ async function runSetup(options = {}) {
1685
1699
  try {
1686
1700
  const parsed = await parseStoryFile(storyFile);
1687
1701
  const segmentResult = convertToSegment(parsed);
1688
- await fs.mkdir(path.dirname(segmentResult.outputFile), { recursive: true });
1689
- await fs.writeFile(segmentResult.outputFile, segmentResult.code);
1702
+ await fs2.mkdir(path.dirname(segmentResult.outputFile), { recursive: true });
1703
+ await fs2.writeFile(segmentResult.outputFile, segmentResult.code);
1690
1704
  converted++;
1691
1705
  } catch {
1692
1706
  }
@@ -1771,7 +1785,7 @@ ${BRAND.name} Dev Server
1771
1785
  }
1772
1786
  }
1773
1787
  }
1774
- const { createDevServer } = await import("./viewer-YDGFDTK5.js");
1788
+ const { createDevServer } = await import("./viewer-SUFOISZM.js");
1775
1789
  console.log(pc7.dim("\nStarting dev server..."));
1776
1790
  const parsedPort = typeof port === "string" ? parseInt(port, 10) : port;
1777
1791
  try {
@@ -2402,13 +2416,636 @@ ${BRAND.name} Design System Audit
2402
2416
  }
2403
2417
 
2404
2418
  // src/commands/a11y.ts
2419
+ import fs from "fs";
2405
2420
  import pc12 from "picocolors";
2421
+
2422
+ // src/commands/a11y-report.ts
2423
+ function generateA11yReport(summary) {
2424
+ const score = summary.score ?? calculateA11yScore(summary);
2425
+ return `<!DOCTYPE html>
2426
+ <html lang="en">
2427
+ <head>
2428
+ <meta charset="UTF-8">
2429
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
2430
+ <title>${BRAND.name} Accessibility Report</title>
2431
+ <style>
2432
+ ${getStyles()}
2433
+ </style>
2434
+ </head>
2435
+ <body>
2436
+ <div class="container">
2437
+ ${renderHeader(score)}
2438
+ ${renderSummaryCards(summary, score)}
2439
+ ${renderComponentGrid(summary.components)}
2440
+ ${renderFooter()}
2441
+ </div>
2442
+ <script>
2443
+ ${getScripts()}
2444
+ </script>
2445
+ </body>
2446
+ </html>`;
2447
+ }
2448
+ function getStyles() {
2449
+ return `
2450
+ :root {
2451
+ --bg: #0a0a0a;
2452
+ --bg-card: #141414;
2453
+ --bg-hover: #1a1a1a;
2454
+ --border: #262626;
2455
+ --text: #f2f2f2;
2456
+ --text-secondary: #a1a1aa;
2457
+ --text-muted: #71717a;
2458
+ --accent: #10b981;
2459
+ --accent-light: #34d399;
2460
+ --danger: #ef4444;
2461
+ --warning: #eab308;
2462
+ --success: #22c55e;
2463
+ --radius: 12px;
2464
+ }
2465
+
2466
+ @media (prefers-color-scheme: light) {
2467
+ :root:not(.dark) {
2468
+ --bg: #f8f8f8;
2469
+ --bg-card: #ffffff;
2470
+ --bg-hover: #f0f0f0;
2471
+ --border: #e0e0e0;
2472
+ --text: #171717;
2473
+ --text-secondary: #525252;
2474
+ --text-muted: #737373;
2475
+ }
2476
+ }
2477
+
2478
+ .dark {
2479
+ --bg: #0a0a0a;
2480
+ --bg-card: #141414;
2481
+ --bg-hover: #1a1a1a;
2482
+ --border: #262626;
2483
+ --text: #f2f2f2;
2484
+ --text-secondary: #a1a1aa;
2485
+ --text-muted: #71717a;
2486
+ }
2487
+
2488
+ .light {
2489
+ --bg: #f8f8f8;
2490
+ --bg-card: #ffffff;
2491
+ --bg-hover: #f0f0f0;
2492
+ --border: #e0e0e0;
2493
+ --text: #171717;
2494
+ --text-secondary: #525252;
2495
+ --text-muted: #737373;
2496
+ }
2497
+
2498
+ * {
2499
+ margin: 0;
2500
+ padding: 0;
2501
+ box-sizing: border-box;
2502
+ }
2503
+
2504
+ body {
2505
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
2506
+ background: var(--bg);
2507
+ color: var(--text);
2508
+ line-height: 1.6;
2509
+ -webkit-font-smoothing: antialiased;
2510
+ }
2511
+
2512
+ .container {
2513
+ max-width: 1200px;
2514
+ margin: 0 auto;
2515
+ padding: 48px 24px;
2516
+ }
2517
+
2518
+ /* Header */
2519
+ .header {
2520
+ display: flex;
2521
+ justify-content: space-between;
2522
+ align-items: flex-start;
2523
+ margin-bottom: 48px;
2524
+ padding-bottom: 32px;
2525
+ border-bottom: 1px solid var(--border);
2526
+ }
2527
+
2528
+ .header-left h1 {
2529
+ font-size: 32px;
2530
+ font-weight: 700;
2531
+ margin-bottom: 8px;
2532
+ background: linear-gradient(135deg, var(--text), var(--accent));
2533
+ -webkit-background-clip: text;
2534
+ -webkit-text-fill-color: transparent;
2535
+ }
2536
+
2537
+ .header-left p {
2538
+ color: var(--text-secondary);
2539
+ font-size: 14px;
2540
+ }
2541
+
2542
+ .header-right {
2543
+ display: flex;
2544
+ align-items: flex-start;
2545
+ gap: 16px;
2546
+ }
2547
+
2548
+ .theme-toggle {
2549
+ background: var(--bg-card);
2550
+ border: 1px solid var(--border);
2551
+ border-radius: 8px;
2552
+ color: var(--text-secondary);
2553
+ cursor: pointer;
2554
+ padding: 8px 12px;
2555
+ font-size: 14px;
2556
+ line-height: 1;
2557
+ }
2558
+
2559
+ .theme-toggle:hover {
2560
+ border-color: var(--accent);
2561
+ color: var(--text);
2562
+ }
2563
+
2564
+ .grade-badge {
2565
+ display: flex;
2566
+ flex-direction: column;
2567
+ align-items: center;
2568
+ padding: 24px 32px;
2569
+ background: var(--bg-card);
2570
+ border: 1px solid var(--border);
2571
+ border-radius: var(--radius);
2572
+ }
2573
+
2574
+ .grade-score-large {
2575
+ font-size: 56px;
2576
+ font-weight: 800;
2577
+ line-height: 1;
2578
+ }
2579
+
2580
+ .grade-label {
2581
+ font-size: 14px;
2582
+ color: var(--text-secondary);
2583
+ margin-top: 8px;
2584
+ }
2585
+
2586
+ /* Summary Cards */
2587
+ .summary-grid {
2588
+ display: grid;
2589
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2590
+ gap: 16px;
2591
+ margin-bottom: 48px;
2592
+ }
2593
+
2594
+ .summary-card {
2595
+ background: var(--bg-card);
2596
+ border: 1px solid var(--border);
2597
+ border-radius: var(--radius);
2598
+ padding: 24px;
2599
+ }
2600
+
2601
+ .summary-card-label {
2602
+ font-size: 13px;
2603
+ color: var(--text-muted);
2604
+ text-transform: uppercase;
2605
+ letter-spacing: 0.05em;
2606
+ margin-bottom: 8px;
2607
+ }
2608
+
2609
+ .summary-card-value {
2610
+ font-size: 36px;
2611
+ font-weight: 700;
2612
+ }
2613
+
2614
+ .summary-card-sub {
2615
+ font-size: 13px;
2616
+ color: var(--text-secondary);
2617
+ margin-top: 4px;
2618
+ }
2619
+
2620
+ /* Section */
2621
+ .section {
2622
+ margin-bottom: 48px;
2623
+ }
2624
+
2625
+ .section-title {
2626
+ font-size: 20px;
2627
+ font-weight: 600;
2628
+ margin-bottom: 24px;
2629
+ display: flex;
2630
+ align-items: center;
2631
+ gap: 12px;
2632
+ }
2633
+
2634
+ .section-title::before {
2635
+ content: '';
2636
+ width: 4px;
2637
+ height: 24px;
2638
+ background: var(--accent);
2639
+ border-radius: 2px;
2640
+ }
2641
+
2642
+ /* Component Grid */
2643
+ .component-grid {
2644
+ display: grid;
2645
+ grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
2646
+ gap: 16px;
2647
+ }
2648
+
2649
+ .component-card {
2650
+ background: var(--bg-card);
2651
+ border: 1px solid var(--border);
2652
+ border-radius: var(--radius);
2653
+ padding: 20px;
2654
+ transition: border-color 0.2s;
2655
+ }
2656
+
2657
+ .component-card:hover {
2658
+ border-color: var(--accent);
2659
+ }
2660
+
2661
+ .component-card-header {
2662
+ display: flex;
2663
+ justify-content: space-between;
2664
+ align-items: center;
2665
+ margin-bottom: 12px;
2666
+ }
2667
+
2668
+ .component-name {
2669
+ font-weight: 600;
2670
+ font-size: 16px;
2671
+ }
2672
+
2673
+ .status-badge {
2674
+ font-size: 12px;
2675
+ font-weight: 700;
2676
+ padding: 3px 10px;
2677
+ border-radius: 6px;
2678
+ text-transform: uppercase;
2679
+ letter-spacing: 0.03em;
2680
+ }
2681
+
2682
+ .status-pass { background: rgba(34, 197, 94, 0.15); color: #22c55e; }
2683
+ .status-warn { background: rgba(234, 179, 8, 0.15); color: #eab308; }
2684
+ .status-fail { background: rgba(239, 68, 68, 0.15); color: #ef4444; }
2685
+
2686
+ .component-stats {
2687
+ display: flex;
2688
+ gap: 16px;
2689
+ font-size: 13px;
2690
+ color: var(--text-secondary);
2691
+ margin-bottom: 8px;
2692
+ }
2693
+
2694
+ .severity-bar {
2695
+ display: flex;
2696
+ gap: 8px;
2697
+ flex-wrap: wrap;
2698
+ margin-bottom: 12px;
2699
+ }
2700
+
2701
+ .severity-chip {
2702
+ font-size: 12px;
2703
+ padding: 3px 10px;
2704
+ border-radius: 6px;
2705
+ }
2706
+
2707
+ .severity-critical { background: rgba(239, 68, 68, 0.15); color: #ef4444; }
2708
+ .severity-serious { background: rgba(239, 68, 68, 0.10); color: #f87171; }
2709
+ .severity-moderate { background: rgba(234, 179, 8, 0.15); color: #eab308; }
2710
+ .severity-minor { background: rgba(113, 113, 122, 0.15); color: var(--text-muted); }
2711
+
2712
+ /* Expandable violation details */
2713
+ .violation-details {
2714
+ margin-top: 8px;
2715
+ }
2716
+
2717
+ .violation-details summary {
2718
+ cursor: pointer;
2719
+ font-size: 13px;
2720
+ color: var(--text-secondary);
2721
+ padding: 4px 0;
2722
+ user-select: none;
2723
+ }
2724
+
2725
+ .violation-details summary:hover {
2726
+ color: var(--text);
2727
+ }
2728
+
2729
+ .violation-details[open] summary {
2730
+ margin-bottom: 8px;
2731
+ }
2732
+
2733
+ .violation-list {
2734
+ display: flex;
2735
+ flex-direction: column;
2736
+ gap: 8px;
2737
+ }
2738
+
2739
+ .violation-item {
2740
+ background: var(--bg);
2741
+ border-radius: 8px;
2742
+ padding: 12px;
2743
+ font-size: 13px;
2744
+ }
2745
+
2746
+ .violation-item-header {
2747
+ display: flex;
2748
+ align-items: center;
2749
+ gap: 8px;
2750
+ margin-bottom: 4px;
2751
+ }
2752
+
2753
+ .violation-rule {
2754
+ font-weight: 600;
2755
+ color: var(--text);
2756
+ }
2757
+
2758
+ .violation-impact {
2759
+ font-size: 11px;
2760
+ font-weight: 600;
2761
+ padding: 1px 6px;
2762
+ border-radius: 4px;
2763
+ text-transform: uppercase;
2764
+ }
2765
+
2766
+ .violation-description {
2767
+ color: var(--text-secondary);
2768
+ line-height: 1.5;
2769
+ }
2770
+
2771
+ .violation-help {
2772
+ color: var(--accent);
2773
+ font-size: 12px;
2774
+ margin-top: 4px;
2775
+ }
2776
+
2777
+ /* Footer */
2778
+ .footer {
2779
+ margin-top: 64px;
2780
+ padding-top: 32px;
2781
+ border-top: 1px solid var(--border);
2782
+ text-align: center;
2783
+ color: var(--text-muted);
2784
+ font-size: 13px;
2785
+ }
2786
+
2787
+ .footer a {
2788
+ color: var(--accent);
2789
+ text-decoration: none;
2790
+ }
2791
+
2792
+ /* Responsive */
2793
+ @media (max-width: 768px) {
2794
+ .header {
2795
+ flex-direction: column;
2796
+ gap: 24px;
2797
+ }
2798
+
2799
+ .header-right {
2800
+ align-self: flex-start;
2801
+ }
2802
+
2803
+ .component-grid {
2804
+ grid-template-columns: 1fr;
2805
+ }
2806
+ }
2807
+ `;
2808
+ }
2809
+ function getScoreColor(score) {
2810
+ if (score >= 90) return "#22c55e";
2811
+ if (score >= 70) return "#eab308";
2812
+ return "#ef4444";
2813
+ }
2814
+ function escapeHtml(str) {
2815
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2816
+ }
2817
+ function renderHeader(score) {
2818
+ const color = getScoreColor(score.score);
2819
+ const now = /* @__PURE__ */ new Date();
2820
+ const timestamp = now.toLocaleDateString("en-US", {
2821
+ weekday: "long",
2822
+ year: "numeric",
2823
+ month: "long",
2824
+ day: "numeric",
2825
+ hour: "2-digit",
2826
+ minute: "2-digit"
2827
+ });
2828
+ return `
2829
+ <header class="header">
2830
+ <div class="header-left">
2831
+ <h1>${BRAND.name} Accessibility Report</h1>
2832
+ <p>Generated ${escapeHtml(timestamp)}</p>
2833
+ </div>
2834
+ <div class="header-right">
2835
+ <button class="theme-toggle" id="theme-toggle" aria-label="Toggle light/dark theme">Toggle theme</button>
2836
+ <div class="grade-badge">
2837
+ <div class="grade-score-large" style="color: ${color}">${score.score}</div>
2838
+ <div class="grade-label">/ 100</div>
2839
+ </div>
2840
+ </div>
2841
+ </header>
2842
+ `;
2843
+ }
2844
+ function renderSummaryCards(summary, score) {
2845
+ return `
2846
+ <div class="summary-grid">
2847
+ <div class="summary-card">
2848
+ <div class="summary-card-label">Components</div>
2849
+ <div class="summary-card-value">${summary.totalComponents}</div>
2850
+ <div class="summary-card-sub">${summary.accessibleComponents} accessible (${summary.accessiblePercent}%)</div>
2851
+ </div>
2852
+ <div class="summary-card">
2853
+ <div class="summary-card-label">AA Compliance</div>
2854
+ <div class="summary-card-value" style="color: ${getScoreColor(score.aaPercent)}">${score.aaPercent}%</div>
2855
+ <div class="summary-card-sub">No critical/serious violations</div>
2856
+ </div>
2857
+ <div class="summary-card">
2858
+ <div class="summary-card-label">AAA Compliance</div>
2859
+ <div class="summary-card-value" style="color: ${getScoreColor(score.aaaPercent)}">${score.aaaPercent}%</div>
2860
+ <div class="summary-card-sub">Zero violations</div>
2861
+ </div>
2862
+ <div class="summary-card">
2863
+ <div class="summary-card-label">Total Violations</div>
2864
+ <div class="summary-card-value" style="color: ${summary.totalViolations === 0 ? "#22c55e" : "#ef4444"}">${summary.totalViolations}</div>
2865
+ <div class="summary-card-sub">${summary.totalCritical} critical, ${summary.totalSerious} serious, ${summary.totalModerate} moderate, ${summary.totalMinor} minor</div>
2866
+ </div>
2867
+ </div>
2868
+ `;
2869
+ }
2870
+ function renderComponentCard(comp) {
2871
+ const statusClass = comp.status === "PASS" ? "status-pass" : comp.status === "WARN" ? "status-warn" : "status-fail";
2872
+ const variantCount = comp.results.length || 1;
2873
+ let critical = 0;
2874
+ let serious = 0;
2875
+ let moderate = 0;
2876
+ let minor = 0;
2877
+ for (const r of comp.results) {
2878
+ critical += r.summary.critical;
2879
+ serious += r.summary.serious;
2880
+ moderate += r.summary.moderate;
2881
+ minor += r.summary.minor;
2882
+ }
2883
+ const severityChips = [];
2884
+ if (critical > 0) severityChips.push(`<span class="severity-chip severity-critical">${critical} critical</span>`);
2885
+ if (serious > 0) severityChips.push(`<span class="severity-chip severity-serious">${serious} serious</span>`);
2886
+ if (moderate > 0) severityChips.push(`<span class="severity-chip severity-moderate">${moderate} moderate</span>`);
2887
+ if (minor > 0) severityChips.push(`<span class="severity-chip severity-minor">${minor} minor</span>`);
2888
+ let violationDetailsHtml = "";
2889
+ const variantsWithViolations = comp.results.filter((r) => r.summary.total > 0);
2890
+ if (variantsWithViolations.length > 0) {
2891
+ const variantItems = variantsWithViolations.map((r) => {
2892
+ const counts = [];
2893
+ if (r.summary.critical > 0) counts.push(`${r.summary.critical} critical`);
2894
+ if (r.summary.serious > 0) counts.push(`${r.summary.serious} serious`);
2895
+ if (r.summary.moderate > 0) counts.push(`${r.summary.moderate} moderate`);
2896
+ if (r.summary.minor > 0) counts.push(`${r.summary.minor} minor`);
2897
+ return `
2898
+ <div class="violation-item">
2899
+ <div class="violation-item-header">
2900
+ <span class="violation-rule">${escapeHtml(r.variant)}</span>
2901
+ </div>
2902
+ <div class="violation-description">${counts.join(", ")}</div>
2903
+ </div>
2904
+ `;
2905
+ }).join("");
2906
+ violationDetailsHtml = `
2907
+ <details class="violation-details">
2908
+ <summary>View variant breakdown (${variantsWithViolations.length} variant${variantsWithViolations.length === 1 ? "" : "s"} with issues)</summary>
2909
+ <div class="violation-list">
2910
+ ${variantItems}
2911
+ </div>
2912
+ </details>
2913
+ `;
2914
+ }
2915
+ return `
2916
+ <div class="component-card">
2917
+ <div class="component-card-header">
2918
+ <span class="component-name">${escapeHtml(comp.component)}</span>
2919
+ <span class="status-badge ${statusClass}">${comp.status}</span>
2920
+ </div>
2921
+ <div class="component-stats">
2922
+ <span>${variantCount} variant${variantCount === 1 ? "" : "s"}</span>
2923
+ <span>${comp.totalViolations} violation${comp.totalViolations === 1 ? "" : "s"}</span>
2924
+ </div>
2925
+ ${severityChips.length > 0 ? `<div class="severity-bar">${severityChips.join("")}</div>` : ""}
2926
+ ${violationDetailsHtml}
2927
+ </div>
2928
+ `;
2929
+ }
2930
+ function renderComponentGrid(components) {
2931
+ if (components.length === 0) {
2932
+ return `
2933
+ <section class="section">
2934
+ <h2 class="section-title">Components</h2>
2935
+ <p style="color: var(--text-secondary)">No components found.</p>
2936
+ </section>
2937
+ `;
2938
+ }
2939
+ const order = { FAIL: 0, WARN: 1, PASS: 2 };
2940
+ const sorted = [...components].sort((a, b) => order[a.status] - order[b.status]);
2941
+ return `
2942
+ <section class="section">
2943
+ <h2 class="section-title">Components</h2>
2944
+ <div class="component-grid">
2945
+ ${sorted.map(renderComponentCard).join("")}
2946
+ </div>
2947
+ </section>
2948
+ `;
2949
+ }
2950
+ function renderFooter() {
2951
+ return `
2952
+ <footer class="footer">
2953
+ <p>Generated by <a href="#">${BRAND.name}</a> &mdash; AI-first design system documentation</p>
2954
+ </footer>
2955
+ `;
2956
+ }
2957
+ function getScripts() {
2958
+ return `
2959
+ // Theme toggle
2960
+ (function() {
2961
+ var toggle = document.getElementById('theme-toggle');
2962
+ var root = document.documentElement;
2963
+
2964
+ function setTheme(theme) {
2965
+ root.classList.remove('light', 'dark');
2966
+ root.classList.add(theme);
2967
+ toggle.textContent = theme === 'dark' ? 'Light mode' : 'Dark mode';
2968
+ }
2969
+
2970
+ // Default to dark
2971
+ var preferred = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
2972
+ setTheme(preferred);
2973
+
2974
+ toggle.addEventListener('click', function() {
2975
+ var current = root.classList.contains('dark') ? 'dark' : 'light';
2976
+ setTheme(current === 'dark' ? 'light' : 'dark');
2977
+ });
2978
+ })();
2979
+
2980
+ // Animate bars on load
2981
+ document.querySelectorAll('.bar-fill, .coverage-bar-fill').forEach(function(el) {
2982
+ var width = el.style.width;
2983
+ el.style.width = '0';
2984
+ setTimeout(function() {
2985
+ el.style.width = width;
2986
+ }, 100);
2987
+ });
2988
+ `;
2989
+ }
2990
+
2991
+ // src/commands/a11y.ts
2992
+ function calculateA11yScore(summary) {
2993
+ const deductions = summary.totalCritical * 10 + summary.totalSerious * 5 + summary.totalModerate * 2 + summary.totalMinor * 1;
2994
+ const score = Math.max(0, 100 - deductions);
2995
+ const aaComponents = summary.components.filter(
2996
+ (c) => c.totalCritical === 0 && c.totalSerious === 0
2997
+ ).length;
2998
+ const aaPercent = summary.totalComponents > 0 ? Math.round(aaComponents / summary.totalComponents * 100) : 100;
2999
+ const aaaComponents = summary.components.filter(
3000
+ (c) => c.totalViolations === 0
3001
+ ).length;
3002
+ const aaaPercent = summary.totalComponents > 0 ? Math.round(aaaComponents / summary.totalComponents * 100) : 100;
3003
+ return { score, aaPercent, aaaPercent };
3004
+ }
3005
+ function formatGitHub(summary) {
3006
+ const score = summary.score ?? calculateA11yScore(summary);
3007
+ const badge = summary.passed ? "passing" : "failing";
3008
+ const badgeColor = summary.passed ? "brightgreen" : "red";
3009
+ const lines = [];
3010
+ lines.push(`## ${BRAND.name} Accessibility Report`);
3011
+ lines.push("");
3012
+ lines.push(`![a11y](https://img.shields.io/badge/a11y-${badge}-${badgeColor})`);
3013
+ lines.push(`**Score:** ${score.score}/100 | **AA:** ${score.aaPercent}% | **AAA:** ${score.aaaPercent}%`);
3014
+ lines.push("");
3015
+ lines.push("| Component | Variants | Violations | Critical | Serious | Status |");
3016
+ lines.push("|-----------|----------|------------|----------|---------|--------|");
3017
+ for (const result of summary.components) {
3018
+ const statusIcon = result.status === "PASS" ? "PASS" : result.status === "WARN" ? "WARN" : "FAIL";
3019
+ const variantCount = result.results.length || 1;
3020
+ lines.push(
3021
+ `| ${result.component} | ${variantCount} | ${result.totalViolations} | ${result.totalCritical} | ${result.totalSerious} | ${statusIcon} |`
3022
+ );
3023
+ }
3024
+ lines.push("");
3025
+ lines.push(`**Summary:** ${summary.accessibleComponents}/${summary.totalComponents} components accessible (${summary.accessiblePercent}%)`);
3026
+ lines.push(`**Violations:** ${summary.totalViolations} total (${summary.totalCritical} critical, ${summary.totalSerious} serious, ${summary.totalModerate} moderate, ${summary.totalMinor} minor)`);
3027
+ if (summary.totalCritical + summary.totalSerious > 0) {
3028
+ lines.push("");
3029
+ lines.push(`**Blocking:** ${summary.totalCritical + summary.totalSerious} critical/serious issues must be fixed`);
3030
+ }
3031
+ lines.push("");
3032
+ return lines.join("\n");
3033
+ }
2406
3034
  async function a11y(options = {}) {
2407
- const { config: configPath, json = false, ci = false, component, port = 6006 } = options;
3035
+ const {
3036
+ config: configPath,
3037
+ json = false,
3038
+ ci = false,
3039
+ component,
3040
+ port = 6006,
3041
+ format = json ? "json" : "table",
3042
+ standard = "AA"
3043
+ } = options;
2408
3044
  await loadConfig(configPath);
2409
3045
  const client = createDevServerClient(port);
2410
3046
  const componentResults = [];
2411
- if (!json) {
3047
+ const isJsonOutput = format === "json" || json;
3048
+ if (!isJsonOutput && format !== "github") {
2412
3049
  console.log(pc12.cyan(`
2413
3050
  ${BRAND.name} Accessibility Report
2414
3051
  `));
@@ -2422,7 +3059,7 @@ ${BRAND.name} Accessibility Report
2422
3059
  }
2423
3060
  const segments = await client.getSegments();
2424
3061
  if (segments.length === 0) {
2425
- if (json) {
3062
+ if (isJsonOutput) {
2426
3063
  console.log(JSON.stringify({ error: "No fragments found", components: [] }));
2427
3064
  } else {
2428
3065
  console.log(pc12.yellow("No fragments found.\n"));
@@ -2443,14 +3080,14 @@ ${BRAND.name} Accessibility Report
2443
3080
  const componentsToCheck = component ? segments.filter((s) => s.name.toLowerCase() === component.toLowerCase()) : segments;
2444
3081
  if (component && componentsToCheck.length === 0) {
2445
3082
  const error = `Component '${component}' not found. Available: ${segments.map((s) => s.name).join(", ")}`;
2446
- if (json) {
3083
+ if (isJsonOutput) {
2447
3084
  console.log(JSON.stringify({ error }));
2448
3085
  } else {
2449
3086
  console.log(pc12.red(error));
2450
3087
  }
2451
3088
  throw new Error(error);
2452
3089
  }
2453
- if (!json) {
3090
+ if (!isJsonOutput && format !== "github") {
2454
3091
  console.log(pc12.dim(`Checking ${componentsToCheck.length} component(s) for accessibility issues...
2455
3092
  `));
2456
3093
  }
@@ -2471,6 +3108,9 @@ ${BRAND.name} Accessibility Report
2471
3108
  } else if (totalViolations2 > 0) {
2472
3109
  status = "WARN";
2473
3110
  }
3111
+ if (standard === "AAA" && totalViolations2 > 0) {
3112
+ status = "FAIL";
3113
+ }
2474
3114
  componentResults.push({
2475
3115
  component: seg.name,
2476
3116
  results: a11yResult.results,
@@ -2479,7 +3119,7 @@ ${BRAND.name} Accessibility Report
2479
3119
  totalCritical: totalCritical2,
2480
3120
  totalSerious: totalSerious2
2481
3121
  });
2482
- } catch (error) {
3122
+ } catch {
2483
3123
  componentResults.push({
2484
3124
  component: seg.name,
2485
3125
  results: [],
@@ -2502,6 +3142,7 @@ ${BRAND.name} Accessibility Report
2502
3142
  totalMinor += result.summary.minor;
2503
3143
  }
2504
3144
  }
3145
+ const passed = standard === "AAA" ? totalViolations === 0 : totalCritical === 0 && totalSerious === 0;
2505
3146
  const summary = {
2506
3147
  totalComponents: componentResults.length,
2507
3148
  accessibleComponents,
@@ -2512,9 +3153,12 @@ ${BRAND.name} Accessibility Report
2512
3153
  totalSerious,
2513
3154
  totalModerate,
2514
3155
  totalMinor,
2515
- passed: totalCritical === 0 && totalSerious === 0
3156
+ passed
2516
3157
  };
2517
- if (json) {
3158
+ summary.score = calculateA11yScore(summary);
3159
+ if (format === "github") {
3160
+ console.log(formatGitHub(summary));
3161
+ } else if (isJsonOutput) {
2518
3162
  console.log(JSON.stringify(summary, null, 2));
2519
3163
  } else {
2520
3164
  console.log(pc12.bold(
@@ -2530,21 +3174,46 @@ ${BRAND.name} Accessibility Report
2530
3174
  }
2531
3175
  console.log(pc12.dim("\u2500".repeat(72)));
2532
3176
  console.log();
3177
+ const categories = [
3178
+ { label: "Critical", count: totalCritical, color: pc12.red },
3179
+ { label: "Serious", count: totalSerious, color: pc12.red },
3180
+ { label: "Moderate", count: totalModerate, color: pc12.yellow },
3181
+ { label: "Minor", count: totalMinor, color: pc12.dim }
3182
+ ];
3183
+ for (const cat of categories) {
3184
+ if (cat.count > 0) {
3185
+ const dots = ".".repeat(Math.max(1, 30 - cat.label.length));
3186
+ console.log(` ${cat.label} ${pc12.dim(dots)} ${cat.color(String(cat.count))}`);
3187
+ }
3188
+ }
3189
+ const { score, aaPercent, aaaPercent } = summary.score;
3190
+ console.log();
3191
+ console.log(pc12.bold(` Score: ${score}/100`));
3192
+ console.log(` AA compliance .... ${aaPercent}%`);
3193
+ console.log(` AAA compliance ... ${aaaPercent}%`);
3194
+ console.log(` Standard ......... WCAG ${standard}`);
3195
+ console.log();
2533
3196
  console.log(pc12.bold("Summary:"));
2534
3197
  console.log(` ${accessibleComponents}/${componentResults.length} components accessible (${summary.accessiblePercent}%)`);
2535
3198
  console.log(` Total violations: ${totalViolations} (${totalCritical} critical, ${totalSerious} serious, ${totalModerate} moderate, ${totalMinor} minor)`);
2536
3199
  if (!summary.passed) {
2537
3200
  console.log();
2538
- console.log(pc12.red("\u2717 Accessibility check failed - critical/serious violations found"));
3201
+ console.log(pc12.red("x Accessibility check failed - critical/serious violations found"));
2539
3202
  } else if (totalViolations > 0) {
2540
3203
  console.log();
2541
- console.log(pc12.yellow("\u26A0 Minor/moderate violations found - consider fixing for better accessibility"));
3204
+ console.log(pc12.yellow("! Minor/moderate violations found - consider fixing for better accessibility"));
2542
3205
  } else {
2543
3206
  console.log();
2544
- console.log(pc12.green("\u2713 All components pass accessibility checks"));
3207
+ console.log(pc12.green("v All components pass accessibility checks"));
2545
3208
  }
2546
3209
  console.log();
2547
3210
  }
3211
+ if (options.report) {
3212
+ const outputPath = options.output ?? "a11y-report.html";
3213
+ const html = generateA11yReport(summary);
3214
+ fs.writeFileSync(outputPath, html, "utf-8");
3215
+ console.log(pc12.green("v Report generated: " + outputPath));
3216
+ }
2548
3217
  if (ci && !summary.passed) {
2549
3218
  throw new Error(`Accessibility check failed: ${totalCritical} critical, ${totalSerious} serious violations found`);
2550
3219
  }
@@ -3825,8 +4494,8 @@ ${BRAND.name} AI Enhancement
3825
4494
  ];
3826
4495
  for (const srcPath of possiblePaths) {
3827
4496
  try {
3828
- const fs = await import("fs");
3829
- if (fs.existsSync(srcPath)) {
4497
+ const fs2 = await import("fs");
4498
+ if (fs2.existsSync(srcPath)) {
3830
4499
  const extraction = await extractPropsFromFile(srcPath, {
3831
4500
  propsTypeName: `${compName}Props`
3832
4501
  });
@@ -4275,6 +4944,242 @@ ${whenNotItems}
4275
4944
  }
4276
4945
  }
4277
4946
 
4947
+ // src/commands/graph.ts
4948
+ import pc20 from "picocolors";
4949
+ import { readFile as readFile6 } from "fs/promises";
4950
+ import { resolve as resolve6 } from "path";
4951
+ import {
4952
+ ComponentGraphEngine,
4953
+ deserializeGraph
4954
+ } from "@fragments-sdk/context/graph";
4955
+ async function graph(component, options) {
4956
+ const { config, configDir } = await loadConfig(options.config);
4957
+ const outputPath = resolve6(configDir, config.outFile ?? BRAND.outFile);
4958
+ let data;
4959
+ try {
4960
+ const content = await readFile6(outputPath, "utf-8");
4961
+ data = JSON.parse(content);
4962
+ } catch {
4963
+ console.error(
4964
+ pc20.red(`Error: Could not load ${BRAND.outFile}. Run \`${BRAND.cliCommand} build\` first.`)
4965
+ );
4966
+ process.exit(1);
4967
+ }
4968
+ if (!data.graph) {
4969
+ console.error(
4970
+ pc20.red(`Error: No graph data in ${BRAND.outFile}. Rebuild with the latest CLI.`)
4971
+ );
4972
+ process.exit(1);
4973
+ }
4974
+ const graph2 = deserializeGraph(data.graph);
4975
+ const blocks = data.blocks ? Object.fromEntries(
4976
+ Object.entries(data.blocks).map(([k, v]) => [k, { components: v.components }])
4977
+ ) : void 0;
4978
+ const engine = new ComponentGraphEngine(graph2, blocks);
4979
+ const mode = options.mode ?? (component ? "dependencies" : "health");
4980
+ const format = options.format ?? "table";
4981
+ const edgeTypes = options.edgeTypes ? options.edgeTypes.split(",") : void 0;
4982
+ const needsComponent = ["dependencies", "dependents", "impact", "path", "composition", "alternatives"];
4983
+ if (needsComponent.includes(mode) && !component) {
4984
+ console.error(pc20.red(`Error: "${mode}" mode requires a component name.`));
4985
+ process.exit(1);
4986
+ }
4987
+ if (component && !engine.hasNode(component)) {
4988
+ console.error(pc20.red(`Error: Component "${component}" not found in graph.`));
4989
+ process.exit(1);
4990
+ }
4991
+ switch (mode) {
4992
+ case "health": {
4993
+ const health = engine.getHealth();
4994
+ if (format === "json") {
4995
+ console.log(JSON.stringify(health, null, 2));
4996
+ return;
4997
+ }
4998
+ console.log(pc20.bold("\nComponent Graph Health\n"));
4999
+ console.log(` ${pc20.cyan("Nodes:")} ${health.nodeCount}`);
5000
+ console.log(` ${pc20.cyan("Edges:")} ${health.edgeCount}`);
5001
+ console.log(` ${pc20.cyan("Avg degree:")} ${health.averageDegree}`);
5002
+ console.log(` ${pc20.cyan("Islands:")} ${health.connectedComponents.length}`);
5003
+ console.log(` ${pc20.cyan("Coverage:")} ${health.compositionCoverage}% in blocks`);
5004
+ console.log(` ${pc20.cyan("Orphans:")} ${health.orphans.length > 0 ? health.orphans.join(", ") : pc20.green("none")}`);
5005
+ if (health.hubs.length > 0) {
5006
+ console.log(`
5007
+ ${pc20.bold("Top hubs:")}`);
5008
+ for (const hub of health.hubs.slice(0, 5)) {
5009
+ console.log(` ${pc20.yellow(hub.name)} \u2014 ${hub.degree} connections`);
5010
+ }
5011
+ }
5012
+ console.log();
5013
+ break;
5014
+ }
5015
+ case "dependencies": {
5016
+ const deps = engine.dependencies(component, edgeTypes);
5017
+ if (format === "json") {
5018
+ console.log(JSON.stringify({ component, dependencies: deps }, null, 2));
5019
+ return;
5020
+ }
5021
+ console.log(pc20.bold(`
5022
+ Dependencies of ${component}
5023
+ `));
5024
+ if (deps.length === 0) {
5025
+ console.log(" No outgoing dependencies.");
5026
+ } else {
5027
+ for (const dep of deps) {
5028
+ console.log(` ${pc20.yellow(dep.target)} ${pc20.dim(`(${dep.type})`)}${dep.note ? ` \u2014 ${dep.note}` : ""}`);
5029
+ }
5030
+ }
5031
+ console.log();
5032
+ break;
5033
+ }
5034
+ case "dependents": {
5035
+ const deps = engine.dependents(component, edgeTypes);
5036
+ if (format === "json") {
5037
+ console.log(JSON.stringify({ component, dependents: deps }, null, 2));
5038
+ return;
5039
+ }
5040
+ console.log(pc20.bold(`
5041
+ Dependents of ${component}
5042
+ `));
5043
+ if (deps.length === 0) {
5044
+ console.log(" No incoming dependents.");
5045
+ } else {
5046
+ for (const dep of deps) {
5047
+ console.log(` ${pc20.yellow(dep.source)} ${pc20.dim(`(${dep.type})`)}${dep.note ? ` \u2014 ${dep.note}` : ""}`);
5048
+ }
5049
+ }
5050
+ console.log();
5051
+ break;
5052
+ }
5053
+ case "impact": {
5054
+ const result = engine.impact(component, options.depth ?? 3);
5055
+ if (format === "json") {
5056
+ console.log(JSON.stringify(result, null, 2));
5057
+ return;
5058
+ }
5059
+ console.log(pc20.bold(`
5060
+ Impact analysis: ${component}
5061
+ `));
5062
+ console.log(` ${pc20.red(`${result.totalAffected}`)} affected components, ${pc20.red(`${result.affectedBlocks.length}`)} affected blocks
5063
+ `);
5064
+ if (result.affected.length > 0) {
5065
+ console.log(` ${pc20.bold("Affected components:")}`);
5066
+ for (const entry of result.affected) {
5067
+ const indent = " ".repeat(entry.depth + 1);
5068
+ console.log(`${indent}${pc20.yellow(entry.component)} ${pc20.dim(`(depth ${entry.depth}, via ${entry.edgeType})`)}`);
5069
+ }
5070
+ }
5071
+ if (result.affectedBlocks.length > 0) {
5072
+ console.log(`
5073
+ ${pc20.bold("Affected blocks:")} ${result.affectedBlocks.join(", ")}`);
5074
+ }
5075
+ console.log();
5076
+ break;
5077
+ }
5078
+ case "path": {
5079
+ if (!options.target) {
5080
+ console.error(pc20.red("Error: --target is required for path mode."));
5081
+ process.exit(1);
5082
+ }
5083
+ const result = engine.path(component, options.target);
5084
+ if (format === "json") {
5085
+ console.log(JSON.stringify(result, null, 2));
5086
+ return;
5087
+ }
5088
+ console.log(pc20.bold(`
5089
+ Path: ${component} \u2192 ${options.target}
5090
+ `));
5091
+ if (!result.found) {
5092
+ console.log(` ${pc20.red("No path found.")}`);
5093
+ } else {
5094
+ console.log(` ${result.path.map((n) => pc20.yellow(n)).join(pc20.dim(" \u2192 "))}`);
5095
+ if (result.edges.length > 0) {
5096
+ console.log(` ${pc20.dim(`(${result.edges.map((e) => e.type).join(" \u2192 ")})`)}`);
5097
+ }
5098
+ }
5099
+ console.log();
5100
+ break;
5101
+ }
5102
+ case "composition": {
5103
+ const tree = engine.composition(component);
5104
+ if (format === "json") {
5105
+ console.log(JSON.stringify(tree, null, 2));
5106
+ return;
5107
+ }
5108
+ console.log(pc20.bold(`
5109
+ Composition: ${component}
5110
+ `));
5111
+ console.log(` ${pc20.cyan("Pattern:")} ${tree.compositionPattern ?? "unknown"}`);
5112
+ if (tree.parent) {
5113
+ console.log(` ${pc20.cyan("Parent:")} ${tree.parent}`);
5114
+ }
5115
+ if (tree.subComponents.length > 0) {
5116
+ console.log(` ${pc20.cyan("Sub-components:")}`);
5117
+ for (const sub of tree.subComponents) {
5118
+ const isRequired = tree.requiredChildren.includes(sub);
5119
+ console.log(` ${pc20.yellow(sub)}${isRequired ? pc20.red(" (required)") : ""}`);
5120
+ }
5121
+ }
5122
+ if (tree.siblings.length > 0) {
5123
+ console.log(` ${pc20.cyan("Siblings:")} ${tree.siblings.join(", ")}`);
5124
+ }
5125
+ if (tree.blocks.length > 0) {
5126
+ console.log(` ${pc20.cyan("In blocks:")} ${tree.blocks.join(", ")}`);
5127
+ }
5128
+ console.log();
5129
+ break;
5130
+ }
5131
+ case "alternatives": {
5132
+ const alts = engine.alternatives(component);
5133
+ if (format === "json") {
5134
+ console.log(JSON.stringify({ component, alternatives: alts }, null, 2));
5135
+ return;
5136
+ }
5137
+ console.log(pc20.bold(`
5138
+ Alternatives for ${component}
5139
+ `));
5140
+ if (alts.length === 0) {
5141
+ console.log(" No known alternatives.");
5142
+ } else {
5143
+ for (const alt of alts) {
5144
+ console.log(` ${pc20.yellow(alt.component)}${alt.note ? ` \u2014 ${alt.note}` : ""}`);
5145
+ }
5146
+ }
5147
+ console.log();
5148
+ break;
5149
+ }
5150
+ case "islands": {
5151
+ const islands = engine.islands();
5152
+ if (format === "json") {
5153
+ console.log(JSON.stringify({ islands }, null, 2));
5154
+ return;
5155
+ }
5156
+ console.log(pc20.bold(`
5157
+ Connected Islands (${islands.length})
5158
+ `));
5159
+ for (let i = 0; i < islands.length; i++) {
5160
+ console.log(` ${pc20.cyan(`Island ${i + 1}`)} (${islands[i].length} components): ${islands[i].join(", ")}`);
5161
+ }
5162
+ console.log();
5163
+ break;
5164
+ }
5165
+ default:
5166
+ console.error(pc20.red(`Unknown mode: "${mode}". Valid: health, dependencies, dependents, impact, path, composition, alternatives, islands`));
5167
+ process.exit(1);
5168
+ }
5169
+ if (format === "dot") {
5170
+ const lines = ["digraph ComponentGraph {", " rankdir=LR;", " node [shape=box, style=rounded];"];
5171
+ for (const node of graph2.nodes) {
5172
+ lines.push(` "${node.name}" [label="${node.name}\\n(${node.category})"];`);
5173
+ }
5174
+ for (const edge of graph2.edges) {
5175
+ const style = edge.type === "alternative-to" ? "dashed" : "solid";
5176
+ lines.push(` "${edge.source}" -> "${edge.target}" [label="${edge.type}", style=${style}];`);
5177
+ }
5178
+ lines.push("}");
5179
+ console.log(lines.join("\n"));
5180
+ }
5181
+ }
5182
+
4278
5183
  // src/bin.ts
4279
5184
  var __dirname = dirname4(fileURLToPath(import.meta.url));
4280
5185
  var pkg = JSON.parse(readFileSync(join10(__dirname, "../package.json"), "utf-8"));
@@ -4287,7 +5192,7 @@ program.command("validate").description("Validate fragment files").option("-c, -
4287
5192
  process.exit(1);
4288
5193
  }
4289
5194
  } catch (error) {
4290
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5195
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4291
5196
  process.exit(1);
4292
5197
  }
4293
5198
  });
@@ -4307,7 +5212,7 @@ program.command("build").description(`Build compiled ${BRAND.outFile} and ${BRAN
4307
5212
  process.exit(1);
4308
5213
  }
4309
5214
  } catch (error) {
4310
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5215
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4311
5216
  process.exit(1);
4312
5217
  }
4313
5218
  });
@@ -4326,7 +5231,7 @@ program.command("context").description("Generate AI-ready context for your desig
4326
5231
  process.exit(1);
4327
5232
  }
4328
5233
  } catch (error) {
4329
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5234
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4330
5235
  process.exit(1);
4331
5236
  }
4332
5237
  });
@@ -4353,7 +5258,7 @@ program.command("ai").description("Generate context optimized for AI assistants
4353
5258
  }
4354
5259
  }
4355
5260
  } catch (error) {
4356
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5261
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4357
5262
  process.exit(1);
4358
5263
  }
4359
5264
  });
@@ -4361,7 +5266,7 @@ program.command("list").description("List all discovered fragment files").option
4361
5266
  try {
4362
5267
  await list(options);
4363
5268
  } catch (error) {
4364
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5269
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4365
5270
  process.exit(1);
4366
5271
  }
4367
5272
  });
@@ -4369,7 +5274,7 @@ program.command("reset").description("Reset to initial state (delete all generat
4369
5274
  try {
4370
5275
  await reset(options);
4371
5276
  } catch (error) {
4372
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5277
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4373
5278
  process.exit(1);
4374
5279
  }
4375
5280
  });
@@ -4383,7 +5288,7 @@ linkCommand.command("figma").argument("[figma-url]", "Figma file URL to link com
4383
5288
  variants: options.variants
4384
5289
  });
4385
5290
  } catch (error) {
4386
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5291
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4387
5292
  process.exit(1);
4388
5293
  }
4389
5294
  });
@@ -4398,7 +5303,7 @@ linkCommand.command("storybook").description("Bootstrap fragments from existing
4398
5303
  exclude: options.exclude
4399
5304
  });
4400
5305
  } catch (error) {
4401
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5306
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4402
5307
  process.exit(1);
4403
5308
  }
4404
5309
  });
@@ -4413,9 +5318,9 @@ program.command("dev").description("Start the development server with live compo
4413
5318
  skipBuild: options.skipBuild
4414
5319
  });
4415
5320
  } catch (error) {
4416
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5321
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4417
5322
  if (error instanceof Error && error.stack) {
4418
- console.error(pc20.dim(error.stack));
5323
+ console.error(pc21.dim(error.stack));
4419
5324
  }
4420
5325
  process.exit(1);
4421
5326
  }
@@ -4436,7 +5341,7 @@ program.command("screenshot").description("Capture screenshots of component vari
4436
5341
  process.exit(1);
4437
5342
  }
4438
5343
  } catch (error) {
4439
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5344
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4440
5345
  process.exit(1);
4441
5346
  }
4442
5347
  });
@@ -4455,7 +5360,7 @@ program.command("diff").argument("[component]", "Component name to diff (optiona
4455
5360
  process.exit(1);
4456
5361
  }
4457
5362
  } catch (error) {
4458
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5363
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4459
5364
  process.exit(1);
4460
5365
  }
4461
5366
  });
@@ -4474,8 +5379,8 @@ program.command("compare").argument("[component]", "Component name to compare").
4474
5379
  process.exit(1);
4475
5380
  }
4476
5381
  } catch (error) {
4477
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
4478
- console.log(pc20.dim(`
5382
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
5383
+ console.log(pc21.dim(`
4479
5384
  Make sure the dev server is running: ${BRAND.cliCommand} dev`));
4480
5385
  process.exit(1);
4481
5386
  }
@@ -4494,7 +5399,7 @@ program.command("analyze").description("Analyze design system and generate repor
4494
5399
  process.exit(1);
4495
5400
  }
4496
5401
  } catch (error) {
4497
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5402
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4498
5403
  process.exit(1);
4499
5404
  }
4500
5405
  });
@@ -4513,7 +5418,7 @@ program.command("verify").argument("[component]", "Component name to verify (opt
4513
5418
  if (options.ci) {
4514
5419
  console.log(JSON.stringify({ error: error instanceof Error ? error.message : "Verification failed" }));
4515
5420
  } else {
4516
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5421
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4517
5422
  }
4518
5423
  process.exit(1);
4519
5424
  }
@@ -4530,25 +5435,29 @@ program.command("audit").description("Scan all fragments and show compliance met
4530
5435
  if (options.json) {
4531
5436
  console.log(JSON.stringify({ error: error instanceof Error ? error.message : "Audit failed" }));
4532
5437
  } else {
4533
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5438
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4534
5439
  }
4535
5440
  process.exit(1);
4536
5441
  }
4537
5442
  });
4538
- program.command("a11y").description("Run accessibility checks on all component variants").option("-c, --config <path>", "Path to config file").option("--json", "Output results as JSON").option("--ci", "CI mode (exit code 1 if any critical/serious violations)").option("--component <name>", "Check specific component only").option("-p, --port <port>", "Dev server port", "6006").action(async (options) => {
5443
+ program.command("a11y").description("Run accessibility checks on all component variants").option("-c, --config <path>", "Path to config file").option("--json", "Output results as JSON").option("--ci", "CI mode (exit code 1 if any critical/serious violations)").option("--component <name>", "Check specific component only").option("-p, --port <port>", "Dev server port", "6006").option("--format <format>", "Output format (table, json, github)", "table").option("--standard <level>", "WCAG level (AA or AAA)", "AA").option("--report", "Generate standalone HTML compliance report").option("-o, --output <path>", "Output path for report", "a11y-report.html").action(async (options) => {
4539
5444
  try {
4540
5445
  await a11y({
4541
5446
  config: options.config,
4542
5447
  json: options.json,
4543
5448
  ci: options.ci,
4544
5449
  component: options.component,
4545
- port: options.port
5450
+ port: options.port,
5451
+ format: options.format,
5452
+ standard: options.standard,
5453
+ report: options.report,
5454
+ output: options.output
4546
5455
  });
4547
5456
  } catch (error) {
4548
5457
  if (options.json) {
4549
5458
  console.log(JSON.stringify({ error: error instanceof Error ? error.message : "A11y check failed" }));
4550
5459
  } else {
4551
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5460
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4552
5461
  }
4553
5462
  process.exit(1);
4554
5463
  }
@@ -4571,7 +5480,7 @@ program.command("enhance").description("AI-powered documentation generation from
4571
5480
  if (options.format === "json") {
4572
5481
  console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Enhance failed" }));
4573
5482
  } else {
4574
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5483
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4575
5484
  }
4576
5485
  process.exit(1);
4577
5486
  }
@@ -4592,7 +5501,7 @@ program.command("scan").description(`Zero-config ${BRAND.outFile} generation fro
4592
5501
  process.exit(1);
4593
5502
  }
4594
5503
  } catch (error) {
4595
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5504
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4596
5505
  process.exit(1);
4597
5506
  }
4598
5507
  });
@@ -4605,7 +5514,7 @@ program.command("storygen").description("Generate Storybook stories from fragmen
4605
5514
  format: options.format
4606
5515
  });
4607
5516
  } catch (error) {
4608
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5517
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4609
5518
  process.exit(1);
4610
5519
  }
4611
5520
  });
@@ -4617,7 +5526,7 @@ program.command("metrics").argument("[component]", "Component name (optional, sh
4617
5526
  json: options.json
4618
5527
  });
4619
5528
  } catch (error) {
4620
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5529
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4621
5530
  process.exit(1);
4622
5531
  }
4623
5532
  });
@@ -4631,9 +5540,9 @@ program.command("baseline").description("Manage visual regression baselines").ar
4631
5540
  port: options.port
4632
5541
  });
4633
5542
  } catch (error) {
4634
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5543
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4635
5544
  if (action === "update") {
4636
- console.log(pc20.dim(`
5545
+ console.log(pc21.dim(`
4637
5546
  Make sure the dev server is running: ${BRAND.cliCommand} dev`));
4638
5547
  }
4639
5548
  process.exit(1);
@@ -4641,27 +5550,27 @@ Make sure the dev server is running: ${BRAND.cliCommand} dev`));
4641
5550
  });
4642
5551
  program.command("view").description(`Generate a static HTML viewer for ${BRAND.outFile}`).option("-i, --input <path>", `Path to ${BRAND.outFile}`, BRAND.outFile).option("-o, --output <path>", "Output HTML file path", BRAND.viewerHtmlFile).option("--open", "Open in browser after generation").action(async (options) => {
4643
5552
  try {
4644
- const { generateViewerFromJson } = await import("./static-viewer-O37MJ5B6.js");
4645
- const fs = await import("fs/promises");
5553
+ const { generateViewerFromJson } = await import("./static-viewer-GBR7YNF3.js");
5554
+ const fs2 = await import("fs/promises");
4646
5555
  const path = await import("path");
4647
5556
  const inputPath = path.resolve(process.cwd(), options.input);
4648
5557
  const outputPath = path.resolve(process.cwd(), options.output);
4649
- console.log(pc20.cyan(`
5558
+ console.log(pc21.cyan(`
4650
5559
  ${BRAND.name} Viewer Generator
4651
5560
  `));
4652
5561
  try {
4653
- await fs.access(inputPath);
5562
+ await fs2.access(inputPath);
4654
5563
  } catch {
4655
- console.log(pc20.red(`Error: ${options.input} not found.`));
4656
- console.log(pc20.dim(`
4657
- Run ${pc20.cyan(`${BRAND.cliCommand} build`)} first to generate ${BRAND.outFile}
5564
+ console.log(pc21.red(`Error: ${options.input} not found.`));
5565
+ console.log(pc21.dim(`
5566
+ Run ${pc21.cyan(`${BRAND.cliCommand} build`)} first to generate ${BRAND.outFile}
4658
5567
  `));
4659
5568
  process.exit(1);
4660
5569
  }
4661
- console.log(pc20.dim(`Reading: ${options.input}`));
5570
+ console.log(pc21.dim(`Reading: ${options.input}`));
4662
5571
  const html = await generateViewerFromJson(inputPath);
4663
- await fs.writeFile(outputPath, html);
4664
- console.log(pc20.green(`
5572
+ await fs2.writeFile(outputPath, html);
5573
+ console.log(pc21.green(`
4665
5574
  \u2713 Generated: ${options.output}
4666
5575
  `));
4667
5576
  if (options.open) {
@@ -4670,7 +5579,7 @@ Run ${pc20.cyan(`${BRAND.cliCommand} build`)} first to generate ${BRAND.outFile}
4670
5579
  exec(`${openCmd} "${outputPath}"`);
4671
5580
  }
4672
5581
  } catch (error) {
4673
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5582
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4674
5583
  process.exit(1);
4675
5584
  }
4676
5585
  });
@@ -4683,33 +5592,33 @@ program.command("add").argument("[name]", 'Component name (e.g., "Button", "Text
4683
5592
  component: options.component
4684
5593
  });
4685
5594
  } catch (error) {
4686
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5595
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4687
5596
  process.exit(1);
4688
5597
  }
4689
5598
  });
4690
5599
  program.command("init").description("Initialize fragments in a project (interactive by default)").option("--force", "Overwrite existing config").option("-y, --yes", "Non-interactive mode - auto-detect and use defaults").action(async (options) => {
4691
5600
  try {
4692
- const { init } = await import("./init-NION5S3M.js");
5601
+ const { init } = await import("./init-7CHRKQ7P.js");
4693
5602
  const result = await init({
4694
5603
  projectRoot: process.cwd(),
4695
5604
  force: options.force,
4696
5605
  yes: options.yes
4697
5606
  });
4698
5607
  if (!result.success) {
4699
- console.error(pc20.red("\nInit failed with errors:"));
5608
+ console.error(pc21.red("\nInit failed with errors:"));
4700
5609
  for (const error of result.errors) {
4701
- console.error(pc20.red(` - ${error}`));
5610
+ console.error(pc21.red(` - ${error}`));
4702
5611
  }
4703
5612
  process.exit(1);
4704
5613
  }
4705
5614
  } catch (error) {
4706
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5615
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4707
5616
  process.exit(1);
4708
5617
  }
4709
5618
  });
4710
5619
  program.command("tokens").description("Discover and list design tokens from CSS/SCSS files").option("-c, --config <path>", "Path to config file").option("--json", "Output as JSON").option("--categories", "Group tokens by category").option("--theme <theme>", "Filter by theme name").option("--category <category>", "Filter by category (color, spacing, typography, etc.)").option("--verbose", "Show all tokens (no truncation)").action(async (options) => {
4711
5620
  try {
4712
- const { tokens } = await import("./tokens-ITADYVPF.js");
5621
+ const { tokens } = await import("./tokens-3BWDESVM.js");
4713
5622
  const result = await tokens({
4714
5623
  config: options.config,
4715
5624
  json: options.json,
@@ -4722,13 +5631,13 @@ program.command("tokens").description("Discover and list design tokens from CSS/
4722
5631
  process.exit(1);
4723
5632
  }
4724
5633
  } catch (error) {
4725
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5634
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4726
5635
  process.exit(1);
4727
5636
  }
4728
5637
  });
4729
5638
  program.command("generate").description("Generate fragment files from component source code").argument("[component]", "Specific component name to generate (optional)").option("--force", "Overwrite existing fragment files").option("--pattern <glob>", "Pattern for component files", "src/components/**/*.tsx").action(async (component, options) => {
4730
5639
  try {
4731
- const { generate } = await import("./generate-KL24VZVD.js");
5640
+ const { generate } = await import("./generate-LMTISDIJ.js");
4732
5641
  const result = await generate({
4733
5642
  projectRoot: process.cwd(),
4734
5643
  component,
@@ -4736,18 +5645,26 @@ program.command("generate").description("Generate fragment files from component
4736
5645
  componentPattern: options.pattern
4737
5646
  });
4738
5647
  if (!result.success) {
4739
- console.error(pc20.red("\nGenerate completed with errors"));
5648
+ console.error(pc21.red("\nGenerate completed with errors"));
4740
5649
  process.exit(1);
4741
5650
  }
4742
5651
  } catch (error) {
4743
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5652
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
5653
+ process.exit(1);
5654
+ }
5655
+ });
5656
+ program.command("graph").description("Query the component relationship graph").argument("[component]", "Component name (optional)").option("-c, --config <path>", "Path to config file").option("-m, --mode <mode>", "Query mode: health, dependencies, dependents, impact, path, composition, alternatives, islands").option("-t, --target <component>", "Target component for path mode").option("--edge-types <types>", "Comma-separated edge types to filter by").option("--depth <number>", "Max traversal depth for impact mode", parseInt).option("--format <format>", "Output format: table, json, dot", "table").action(async (component, options) => {
5657
+ try {
5658
+ await graph(component, options);
5659
+ } catch (error) {
5660
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4744
5661
  process.exit(1);
4745
5662
  }
4746
5663
  });
4747
5664
  program.command("test").description("Run interaction tests for fragments with play functions").option("-c, --config <path>", "Path to config file").option("--component <name>", "Filter by component name").option("--tags <tags>", "Filter by tags (comma-separated)").option("--grep <pattern>", "Filter by variant name pattern").option("--exclude <pattern>", "Exclude tests matching pattern").option("--parallel <count>", "Number of parallel browser contexts", parseInt, 4).option("--timeout <ms>", "Timeout per test in milliseconds", parseInt, 3e4).option("--retries <count>", "Number of retries for failed tests", parseInt, 0).option("--bail", "Stop on first failure").option("--browser <name>", "Browser to use (chromium, firefox, webkit)", "chromium").option("--headed", "Run in headed mode (show browser)").option("--a11y", "Run accessibility checks with axe-core").option("--visual", "Capture screenshots for visual regression").option("--update-snapshots", "Update visual snapshots").option("--watch", "Watch mode - re-run on file changes").option("--reporters <names>", "Reporters to use (console, junit, json)", "console").option("-o, --output <dir>", "Output directory for results", "./test-results").option("--server-url <url>", "URL of running dev server (skips starting server)").option("-p, --port <port>", "Port for dev server", parseInt, 6006).option("--ci", "CI mode - non-interactive, exit with code 1 on failure").option("--list", "List available tests without running them").action(async (options) => {
4748
5665
  try {
4749
5666
  const { config, configDir } = await loadConfig(options.config);
4750
- const { runTestCommand, listTests } = await import("./test-ECPEXFDN.js");
5667
+ const { runTestCommand, listTests } = await import("./test-OJRXNDO2.js");
4751
5668
  if (options.list) {
4752
5669
  await listTests(config, configDir, {
4753
5670
  component: options.component,
@@ -4780,7 +5697,7 @@ program.command("test").description("Run interaction tests for fragments with pl
4780
5697
  });
4781
5698
  process.exit(exitCode);
4782
5699
  } catch (error) {
4783
- console.error(pc20.red("Error:"), error instanceof Error ? error.message : error);
5700
+ console.error(pc21.red("Error:"), error instanceof Error ? error.message : error);
4784
5701
  process.exit(1);
4785
5702
  }
4786
5703
  });