@fragments-sdk/cli 0.5.1 → 0.6.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 (120) hide show
  1. package/dist/bin.js +712 -39
  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-U4GQ2JTD.js → chunk-D35RGPAG.js} +412 -35
  6. package/dist/chunk-D35RGPAG.js.map +1 -0
  7. package/dist/{chunk-XNWDI6UT.js → chunk-F7ITZPDJ.js} +5 -5
  8. package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
  9. package/dist/{chunk-V7YLRR4C.js → chunk-Q7GOHVOK.js} +3 -3
  10. package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
  11. package/dist/{chunk-2H2JAA3U.js → chunk-SSLQXHNX.js} +3 -3
  12. package/dist/{core-DKHB7FYV.js → core-SKRPJQZG.js} +4 -4
  13. package/dist/{generate-KL24VZVD.js → generate-7AF7WRVK.js} +5 -5
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +15 -7
  16. package/dist/index.js.map +1 -1
  17. package/dist/{init-NZB55B5O.js → init-WKGDPYI4.js} +7 -7
  18. package/dist/init-WKGDPYI4.js.map +1 -0
  19. package/dist/mcp-bin.js +8 -220
  20. package/dist/mcp-bin.js.map +1 -1
  21. package/dist/scan-K6JNMCGM.js +12 -0
  22. package/dist/{service-RWUMZ3EW.js → service-F3E4JJM7.js} +5 -5
  23. package/dist/static-viewer-4LQZ5AGA.js +12 -0
  24. package/dist/{test-ECPEXFDN.js → test-CJDNJTPZ.js} +4 -4
  25. package/dist/{tokens-ITADYVPF.js → tokens-JAJABYXP.js} +6 -6
  26. package/dist/viewer-R3Q6WAMJ.js +1822 -0
  27. package/dist/viewer-R3Q6WAMJ.js.map +1 -0
  28. package/package.json +5 -4
  29. package/src/bin.ts +8 -0
  30. package/src/build.ts +104 -13
  31. package/src/cli-commands.ts +18 -0
  32. package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
  33. package/src/commands/a11y-report.ts +625 -0
  34. package/src/commands/a11y.ts +168 -14
  35. package/src/commands/build.ts +16 -0
  36. package/src/commands/init.ts +2 -2
  37. package/src/core/auto-props.ts +464 -0
  38. package/src/core/schema.ts +2 -0
  39. package/src/core/types.ts +3 -1
  40. package/src/index.ts +4 -0
  41. package/src/mcp/server.ts +13 -220
  42. package/src/theme/__tests__/component-contrast.test.ts +338 -0
  43. package/src/theme/__tests__/contrast-validation.test.ts +326 -0
  44. package/src/theme/contrast.test.ts +331 -0
  45. package/src/theme/contrast.ts +246 -0
  46. package/src/theme/generator.ts +213 -1
  47. package/src/theme/index.ts +16 -0
  48. package/src/theme/types.ts +51 -0
  49. package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
  50. package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
  51. package/src/viewer/components/AccessibilityPanel.tsx +493 -433
  52. package/src/viewer/components/ActionCapture.tsx +1 -1
  53. package/src/viewer/components/ActionsPanel.tsx +142 -183
  54. package/src/viewer/components/App.tsx +159 -164
  55. package/src/viewer/components/BottomPanel.tsx +40 -80
  56. package/src/viewer/components/CodePanel.tsx +9 -87
  57. package/src/viewer/components/CommandPalette.tsx +117 -74
  58. package/src/viewer/components/ComponentGraph.tsx +143 -126
  59. package/src/viewer/components/ComponentHeader.tsx +46 -43
  60. package/src/viewer/components/ContractPanel.tsx +124 -117
  61. package/src/viewer/components/ErrorBoundary.tsx +47 -35
  62. package/src/viewer/components/FigmaEmbed.tsx +18 -13
  63. package/src/viewer/components/FragmentEditor.tsx +126 -63
  64. package/src/viewer/components/HealthDashboard.tsx +146 -171
  65. package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
  66. package/src/viewer/components/Icons.tsx +99 -98
  67. package/src/viewer/components/InteractionsPanel.tsx +317 -264
  68. package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
  69. package/src/viewer/components/IsolatedRender.tsx +12 -6
  70. package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
  71. package/src/viewer/components/LandingPage.tsx +285 -305
  72. package/src/viewer/components/Layout.tsx +7 -9
  73. package/src/viewer/components/LeftSidebar.tsx +78 -108
  74. package/src/viewer/components/MultiViewportPreview.tsx +254 -63
  75. package/src/viewer/components/PreviewArea.tsx +113 -44
  76. package/src/viewer/components/PreviewFrameHost.tsx +6 -5
  77. package/src/viewer/components/PreviewPane.tsx +2 -3
  78. package/src/viewer/components/PreviewToolbar.tsx +61 -104
  79. package/src/viewer/components/PropsEditor.tsx +154 -74
  80. package/src/viewer/components/PropsTable.tsx +95 -82
  81. package/src/viewer/components/RelationsSection.tsx +71 -40
  82. package/src/viewer/components/ResizablePanel.tsx +158 -55
  83. package/src/viewer/components/RightSidebar.tsx +46 -56
  84. package/src/viewer/components/ScreenshotButton.tsx +12 -12
  85. package/src/viewer/components/SkeletonLoader.tsx +99 -83
  86. package/src/viewer/components/StoryRenderer.tsx +4 -11
  87. package/src/viewer/components/Toast.tsx +3 -67
  88. package/src/viewer/components/TokenStylePanel.tsx +136 -118
  89. package/src/viewer/components/UsageSection.tsx +26 -26
  90. package/src/viewer/components/VariantMatrix.tsx +140 -47
  91. package/src/viewer/components/VariantTabs.tsx +24 -68
  92. package/src/viewer/components/ViewportSelector.tsx +106 -110
  93. package/src/viewer/constants/ui.ts +19 -18
  94. package/src/viewer/entry.tsx +8 -3
  95. package/src/viewer/index.ts +3 -6
  96. package/src/viewer/preview-frame.html +21 -5
  97. package/src/viewer/server.ts +7 -16
  98. package/src/viewer/styles/globals.css +4 -4
  99. package/src/viewer/utils/a11y-fixes.ts +53 -30
  100. package/dist/chunk-ICAIQ57V.js.map +0 -1
  101. package/dist/chunk-U4GQ2JTD.js.map +0 -1
  102. package/dist/init-NZB55B5O.js.map +0 -1
  103. package/dist/scan-ESEXV7LF.js +0 -12
  104. package/dist/static-viewer-O37MJ5B6.js +0 -12
  105. package/dist/viewer-YDGFDTK5.js +0 -11104
  106. package/dist/viewer-YDGFDTK5.js.map +0 -1
  107. package/src/viewer/postcss.config.js +0 -6
  108. package/src/viewer/tailwind.config.js +0 -37
  109. /package/dist/{chunk-XNWDI6UT.js.map → chunk-F7ITZPDJ.js.map} +0 -0
  110. /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
  111. /package/dist/{chunk-V7YLRR4C.js.map → chunk-Q7GOHVOK.js.map} +0 -0
  112. /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
  113. /package/dist/{chunk-2H2JAA3U.js.map → chunk-SSLQXHNX.js.map} +0 -0
  114. /package/dist/{core-DKHB7FYV.js.map → core-SKRPJQZG.js.map} +0 -0
  115. /package/dist/{generate-KL24VZVD.js.map → generate-7AF7WRVK.js.map} +0 -0
  116. /package/dist/{scan-ESEXV7LF.js.map → scan-K6JNMCGM.js.map} +0 -0
  117. /package/dist/{service-RWUMZ3EW.js.map → service-F3E4JJM7.js.map} +0 -0
  118. /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-4LQZ5AGA.js.map} +0 -0
  119. /package/dist/{test-ECPEXFDN.js.map → test-CJDNJTPZ.js.map} +0 -0
  120. /package/dist/{tokens-ITADYVPF.js.map → tokens-JAJABYXP.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-D35RGPAG.js";
13
13
  import {
14
14
  scan
15
- } from "./chunk-XNWDI6UT.js";
15
+ } from "./chunk-F7ITZPDJ.js";
16
16
  import {
17
17
  FigmaClient,
18
18
  StorageManager,
@@ -28,18 +28,18 @@ 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-SSLQXHNX.js";
37
37
  import {
38
38
  generateContext
39
- } from "./chunk-V7YLRR4C.js";
39
+ } from "./chunk-Q7GOHVOK.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";
@@ -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-R3Q6WAMJ.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
  });
@@ -4535,14 +5204,18 @@ program.command("audit").description("Scan all fragments and show compliance met
4535
5204
  process.exit(1);
4536
5205
  }
4537
5206
  });
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) => {
5207
+ 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
5208
  try {
4540
5209
  await a11y({
4541
5210
  config: options.config,
4542
5211
  json: options.json,
4543
5212
  ci: options.ci,
4544
5213
  component: options.component,
4545
- port: options.port
5214
+ port: options.port,
5215
+ format: options.format,
5216
+ standard: options.standard,
5217
+ report: options.report,
5218
+ output: options.output
4546
5219
  });
4547
5220
  } catch (error) {
4548
5221
  if (options.json) {
@@ -4641,8 +5314,8 @@ Make sure the dev server is running: ${BRAND.cliCommand} dev`));
4641
5314
  });
4642
5315
  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
5316
  try {
4644
- const { generateViewerFromJson } = await import("./static-viewer-O37MJ5B6.js");
4645
- const fs = await import("fs/promises");
5317
+ const { generateViewerFromJson } = await import("./static-viewer-4LQZ5AGA.js");
5318
+ const fs2 = await import("fs/promises");
4646
5319
  const path = await import("path");
4647
5320
  const inputPath = path.resolve(process.cwd(), options.input);
4648
5321
  const outputPath = path.resolve(process.cwd(), options.output);
@@ -4650,7 +5323,7 @@ program.command("view").description(`Generate a static HTML viewer for ${BRAND.o
4650
5323
  ${BRAND.name} Viewer Generator
4651
5324
  `));
4652
5325
  try {
4653
- await fs.access(inputPath);
5326
+ await fs2.access(inputPath);
4654
5327
  } catch {
4655
5328
  console.log(pc20.red(`Error: ${options.input} not found.`));
4656
5329
  console.log(pc20.dim(`
@@ -4660,7 +5333,7 @@ Run ${pc20.cyan(`${BRAND.cliCommand} build`)} first to generate ${BRAND.outFile}
4660
5333
  }
4661
5334
  console.log(pc20.dim(`Reading: ${options.input}`));
4662
5335
  const html = await generateViewerFromJson(inputPath);
4663
- await fs.writeFile(outputPath, html);
5336
+ await fs2.writeFile(outputPath, html);
4664
5337
  console.log(pc20.green(`
4665
5338
  \u2713 Generated: ${options.output}
4666
5339
  `));
@@ -4689,7 +5362,7 @@ program.command("add").argument("[name]", 'Component name (e.g., "Button", "Text
4689
5362
  });
4690
5363
  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
5364
  try {
4692
- const { init } = await import("./init-NZB55B5O.js");
5365
+ const { init } = await import("./init-WKGDPYI4.js");
4693
5366
  const result = await init({
4694
5367
  projectRoot: process.cwd(),
4695
5368
  force: options.force,
@@ -4709,7 +5382,7 @@ program.command("init").description("Initialize fragments in a project (interact
4709
5382
  });
4710
5383
  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
5384
  try {
4712
- const { tokens } = await import("./tokens-ITADYVPF.js");
5385
+ const { tokens } = await import("./tokens-JAJABYXP.js");
4713
5386
  const result = await tokens({
4714
5387
  config: options.config,
4715
5388
  json: options.json,
@@ -4728,7 +5401,7 @@ program.command("tokens").description("Discover and list design tokens from CSS/
4728
5401
  });
4729
5402
  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
5403
  try {
4731
- const { generate } = await import("./generate-KL24VZVD.js");
5404
+ const { generate } = await import("./generate-7AF7WRVK.js");
4732
5405
  const result = await generate({
4733
5406
  projectRoot: process.cwd(),
4734
5407
  component,
@@ -4747,7 +5420,7 @@ program.command("generate").description("Generate fragment files from component
4747
5420
  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
5421
  try {
4749
5422
  const { config, configDir } = await loadConfig(options.config);
4750
- const { runTestCommand, listTests } = await import("./test-ECPEXFDN.js");
5423
+ const { runTestCommand, listTests } = await import("./test-CJDNJTPZ.js");
4751
5424
  if (options.list) {
4752
5425
  await listTests(config, configDir, {
4753
5426
  component: options.component,