@fragments-sdk/cli 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/LICENSE +77 -14
  2. package/dist/bin.js +247 -247
  3. package/dist/bin.js.map +1 -1
  4. package/dist/{chunk-CVXKXVOY.js → chunk-3T6QL7IY.js} +47 -29
  5. package/dist/chunk-3T6QL7IY.js.map +1 -0
  6. package/dist/{chunk-7OPWMLOE.js → chunk-7KUSBMI4.js} +114 -112
  7. package/dist/chunk-7KUSBMI4.js.map +1 -0
  8. package/dist/{chunk-XHUDJNN3.js → chunk-DH4ETVSM.js} +18 -18
  9. package/dist/chunk-DH4ETVSM.js.map +1 -0
  10. package/dist/{chunk-RVRTRESS.js → chunk-DQHWLAUV.js} +29 -29
  11. package/dist/chunk-DQHWLAUV.js.map +1 -0
  12. package/dist/{chunk-6JBGU74P.js → chunk-GHYYFAQN.js} +23 -23
  13. package/dist/chunk-GHYYFAQN.js.map +1 -0
  14. package/dist/{chunk-NWQ4CJOQ.js → chunk-GKX2HPZ6.js} +40 -40
  15. package/dist/chunk-GKX2HPZ6.js.map +1 -0
  16. package/dist/{chunk-TJ34N7C7.js → chunk-OOGTG5FM.js} +34 -33
  17. package/dist/chunk-OOGTG5FM.js.map +1 -0
  18. package/dist/{core-W2HYIQW6.js → core-UQXZTBFZ.js} +24 -26
  19. package/dist/{generate-LMTISDIJ.js → generate-GP6ZLAQB.js} +5 -5
  20. package/dist/generate-GP6ZLAQB.js.map +1 -0
  21. package/dist/index.d.ts +23 -27
  22. package/dist/index.js +10 -10
  23. package/dist/{init-7CHRKQ7P.js → init-W72WBSU2.js} +5 -5
  24. package/dist/{init-7CHRKQ7P.js.map → init-W72WBSU2.js.map} +1 -1
  25. package/dist/mcp-bin.js +73 -73
  26. package/dist/mcp-bin.js.map +1 -1
  27. package/dist/scan-V54HWRDY.js +12 -0
  28. package/dist/{service-T2L7VLTE.js → service-PVGTYUKX.js} +6 -6
  29. package/dist/{static-viewer-GBR7YNF3.js → static-viewer-KILKIVN7.js} +4 -4
  30. package/dist/{test-OJRXNDO2.js → test-3YRYQRGV.js} +19 -19
  31. package/dist/test-3YRYQRGV.js.map +1 -0
  32. package/dist/{tokens-3BWDESVM.js → tokens-IXSQHPQK.js} +5 -5
  33. package/dist/{viewer-SUFOISZM.js → viewer-K42REJU2.js} +199 -199
  34. package/dist/viewer-K42REJU2.js.map +1 -0
  35. package/package.json +13 -2
  36. package/src/ai.ts +5 -5
  37. package/src/analyze.ts +11 -11
  38. package/src/bin.ts +1 -1
  39. package/src/build.ts +37 -35
  40. package/src/commands/a11y.ts +6 -6
  41. package/src/commands/add.ts +11 -11
  42. package/src/commands/audit.ts +4 -4
  43. package/src/commands/baseline.ts +3 -3
  44. package/src/commands/build.ts +8 -8
  45. package/src/commands/compare.ts +20 -20
  46. package/src/commands/context.ts +16 -16
  47. package/src/commands/enhance.ts +36 -36
  48. package/src/commands/generate.ts +1 -1
  49. package/src/commands/graph.ts +5 -5
  50. package/src/commands/init.ts +1 -1
  51. package/src/commands/link/figma.ts +82 -82
  52. package/src/commands/link/index.ts +3 -3
  53. package/src/commands/link/storybook.ts +9 -9
  54. package/src/commands/list.ts +2 -2
  55. package/src/commands/reset.ts +15 -15
  56. package/src/commands/scan.ts +27 -27
  57. package/src/commands/storygen.ts +24 -24
  58. package/src/commands/validate.ts +2 -2
  59. package/src/commands/verify.ts +8 -8
  60. package/src/core/auto-props.ts +4 -4
  61. package/src/core/composition.test.ts +36 -36
  62. package/src/core/composition.ts +19 -19
  63. package/src/core/config.ts +6 -6
  64. package/src/core/{defineSegment.ts → defineFragment.ts} +16 -22
  65. package/src/core/discovery.ts +6 -6
  66. package/src/core/figma.ts +2 -2
  67. package/src/core/graph-extractor.test.ts +77 -77
  68. package/src/core/graph-extractor.ts +32 -32
  69. package/src/core/importAnalyzer.ts +1 -1
  70. package/src/core/index.ts +22 -23
  71. package/src/core/loader.ts +21 -24
  72. package/src/core/node.ts +5 -5
  73. package/src/core/parser.ts +71 -31
  74. package/src/core/previewLoader.ts +1 -1
  75. package/src/core/schema.ts +16 -16
  76. package/src/core/storyAdapter.test.ts +87 -87
  77. package/src/core/storyAdapter.ts +16 -16
  78. package/src/core/token-parser.ts +9 -1
  79. package/src/core/types.ts +21 -26
  80. package/src/diff.ts +22 -22
  81. package/src/index.ts +2 -2
  82. package/src/mcp/server.ts +80 -80
  83. package/src/migrate/__tests__/utils/utils.test.ts +3 -3
  84. package/src/migrate/bin.ts +4 -4
  85. package/src/migrate/converter.ts +16 -16
  86. package/src/migrate/index.ts +3 -3
  87. package/src/migrate/migrate.ts +3 -3
  88. package/src/migrate/parser.ts +8 -8
  89. package/src/migrate/report.ts +2 -2
  90. package/src/migrate/types.ts +4 -4
  91. package/src/screenshot.ts +22 -22
  92. package/src/service/__tests__/props-extractor.test.ts +15 -15
  93. package/src/service/analytics.ts +39 -39
  94. package/src/service/enhance/codebase-scanner.ts +1 -1
  95. package/src/service/enhance/index.ts +1 -1
  96. package/src/service/enhance/props-extractor.ts +2 -2
  97. package/src/service/enhance/types.ts +2 -2
  98. package/src/service/index.ts +2 -2
  99. package/src/service/metrics-store.ts +1 -1
  100. package/src/service/patch-generator.ts +1 -1
  101. package/src/setup.ts +52 -52
  102. package/src/shared/dev-server-client.ts +7 -7
  103. package/src/shared/fragment-loader.ts +59 -0
  104. package/src/shared/index.ts +1 -1
  105. package/src/shared/types.ts +4 -4
  106. package/src/static-viewer.ts +35 -35
  107. package/src/test/discovery.ts +6 -6
  108. package/src/test/index.ts +5 -5
  109. package/src/test/reporters/console.ts +1 -1
  110. package/src/test/reporters/junit.ts +1 -1
  111. package/src/test/runner.ts +7 -7
  112. package/src/test/types.ts +3 -3
  113. package/src/test/watch.ts +9 -9
  114. package/src/validators.ts +26 -26
  115. package/src/viewer/__tests__/render-utils.test.ts +28 -28
  116. package/src/viewer/__tests__/viewer-integration.test.ts +4 -4
  117. package/src/viewer/cli/health.ts +26 -26
  118. package/src/viewer/components/App.tsx +79 -79
  119. package/src/viewer/components/BottomPanel.tsx +17 -17
  120. package/src/viewer/components/CodePanel.tsx +3 -3
  121. package/src/viewer/components/CommandPalette.tsx +11 -11
  122. package/src/viewer/components/ComponentGraph.tsx +28 -28
  123. package/src/viewer/components/ComponentHeader.tsx +2 -2
  124. package/src/viewer/components/ContractPanel.tsx +6 -6
  125. package/src/viewer/components/FigmaEmbed.tsx +9 -9
  126. package/src/viewer/components/HealthDashboard.tsx +17 -17
  127. package/src/viewer/components/InteractionsPanel.tsx +2 -2
  128. package/src/viewer/components/IsolatedPreviewFrame.tsx +6 -6
  129. package/src/viewer/components/IsolatedRender.tsx +10 -10
  130. package/src/viewer/components/LeftSidebar.tsx +28 -28
  131. package/src/viewer/components/MultiViewportPreview.tsx +14 -14
  132. package/src/viewer/components/PreviewArea.tsx +11 -11
  133. package/src/viewer/components/PreviewFrameHost.tsx +51 -51
  134. package/src/viewer/components/RightSidebar.tsx +9 -9
  135. package/src/viewer/components/Sidebar.tsx +17 -17
  136. package/src/viewer/components/StoryRenderer.tsx +2 -2
  137. package/src/viewer/components/TokenStylePanel.tsx +1 -1
  138. package/src/viewer/components/UsageSection.tsx +2 -2
  139. package/src/viewer/components/VariantMatrix.tsx +11 -11
  140. package/src/viewer/components/VariantRenderer.tsx +3 -3
  141. package/src/viewer/components/VariantTabs.tsx +2 -2
  142. package/src/viewer/components/_future/CreatePage.tsx +6 -6
  143. package/src/viewer/composition-renderer.ts +11 -11
  144. package/src/viewer/entry.tsx +40 -40
  145. package/src/viewer/hooks/useFigmaIntegration.ts +1 -1
  146. package/src/viewer/hooks/usePreviewBridge.ts +5 -5
  147. package/src/viewer/hooks/useUrlState.ts +6 -6
  148. package/src/viewer/index.ts +2 -2
  149. package/src/viewer/intelligence/healthReport.ts +17 -17
  150. package/src/viewer/intelligence/styleDrift.ts +1 -1
  151. package/src/viewer/intelligence/usageScanner.ts +1 -1
  152. package/src/viewer/render-template.html +1 -1
  153. package/src/viewer/render-utils.ts +21 -21
  154. package/src/viewer/server.ts +18 -18
  155. package/src/viewer/utils/detectRelationships.ts +22 -22
  156. package/src/viewer/vite-plugin.ts +213 -213
  157. package/dist/chunk-6JBGU74P.js.map +0 -1
  158. package/dist/chunk-7OPWMLOE.js.map +0 -1
  159. package/dist/chunk-CVXKXVOY.js.map +0 -1
  160. package/dist/chunk-NWQ4CJOQ.js.map +0 -1
  161. package/dist/chunk-RVRTRESS.js.map +0 -1
  162. package/dist/chunk-TJ34N7C7.js.map +0 -1
  163. package/dist/chunk-XHUDJNN3.js.map +0 -1
  164. package/dist/generate-LMTISDIJ.js.map +0 -1
  165. package/dist/scan-WY23TJCP.js +0 -12
  166. package/dist/test-OJRXNDO2.js.map +0 -1
  167. package/dist/viewer-SUFOISZM.js.map +0 -1
  168. package/src/shared/segment-loader.ts +0 -59
  169. /package/dist/{core-W2HYIQW6.js.map → core-UQXZTBFZ.js.map} +0 -0
  170. /package/dist/{scan-WY23TJCP.js.map → scan-V54HWRDY.js.map} +0 -0
  171. /package/dist/{service-T2L7VLTE.js.map → service-PVGTYUKX.js.map} +0 -0
  172. /package/dist/{static-viewer-GBR7YNF3.js.map → static-viewer-KILKIVN7.js.map} +0 -0
  173. /package/dist/{tokens-3BWDESVM.js.map → tokens-IXSQHPQK.js.map} +0 -0
@@ -1,12 +1,12 @@
1
1
  /**
2
- * fragments link figma - Link Figma components to segments
2
+ * fragments link figma - Link Figma components to fragments
3
3
  */
4
4
 
5
5
  import { readFile, writeFile } from 'node:fs/promises';
6
6
  import { relative } from 'node:path';
7
7
  import pc from 'picocolors';
8
8
  import { BRAND } from '../../core/index.js';
9
- import { loadConfig, discoverSegmentFiles } from '../../core/node.js';
9
+ import { loadConfig, discoverFragmentFiles } from '../../core/node.js';
10
10
  import { FigmaClient } from '../../service/index.js';
11
11
 
12
12
  /**
@@ -33,29 +33,29 @@ export interface LinkFigmaResult {
33
33
  }
34
34
 
35
35
  /**
36
- * Segment variant info
36
+ * Fragment variant info
37
37
  */
38
- interface SegmentVariantInfo {
38
+ interface FragmentVariantInfo {
39
39
  name: string;
40
40
  hasFigma: boolean;
41
41
  }
42
42
 
43
43
  /**
44
- * Segment info
44
+ * Fragment info
45
45
  */
46
- interface SegmentInfo {
46
+ interface FragmentInfo {
47
47
  name: string;
48
48
  filePath: string;
49
49
  relativePath: string;
50
50
  hasFigma: boolean;
51
- variants: SegmentVariantInfo[];
51
+ variants: FragmentVariantInfo[];
52
52
  }
53
53
 
54
54
  /**
55
55
  * Match result
56
56
  */
57
57
  interface Match {
58
- segment: SegmentInfo;
58
+ fragment: FragmentInfo;
59
59
  figmaComponent: {
60
60
  name: string;
61
61
  description: string;
@@ -145,20 +145,20 @@ export async function linkFigma(
145
145
  console.log();
146
146
  }
147
147
 
148
- // Discover local segments
149
- const segmentFiles = await discoverSegmentFiles(config, configDir);
148
+ // Discover local fragments
149
+ const fragmentFiles = await discoverFragmentFiles(config, configDir);
150
150
 
151
- if (segmentFiles.length === 0) {
152
- console.log(pc.yellow('No segment files found in codebase.'));
151
+ if (fragmentFiles.length === 0) {
152
+ console.log(pc.yellow('No fragment files found in codebase.'));
153
153
  console.log(pc.dim(`Looking for: ${config.include.join(', ')}`));
154
154
  process.exit(0);
155
155
  }
156
156
 
157
- console.log(pc.dim(`Found ${segmentFiles.length} segment file(s)\n`));
157
+ console.log(pc.dim(`Found ${fragmentFiles.length} fragment file(s)\n`));
158
158
 
159
- // Load segments to get names
160
- const segments: SegmentInfo[] = [];
161
- for (const file of segmentFiles) {
159
+ // Load fragments to get names
160
+ const fragments: FragmentInfo[] = [];
161
+ for (const file of fragmentFiles) {
162
162
  try {
163
163
  const content = await readFile(file.absolutePath, 'utf-8');
164
164
  // Extract name from meta.name in the file
@@ -167,15 +167,15 @@ export async function linkFigma(
167
167
  const hasFigma = /meta:\s*\{[^}]*figma:\s*['"]https?:/.test(content);
168
168
 
169
169
  // Extract variant names and their figma status
170
- const segmentVariants = extractVariants(content, nameMatch?.[1]);
170
+ const fragmentVariants = extractVariants(content, nameMatch?.[1]);
171
171
 
172
172
  if (nameMatch) {
173
- segments.push({
173
+ fragments.push({
174
174
  name: nameMatch[1],
175
175
  filePath: file.absolutePath,
176
176
  relativePath: file.relativePath,
177
177
  hasFigma,
178
- variants: segmentVariants,
178
+ variants: fragmentVariants,
179
179
  });
180
180
  }
181
181
  } catch {
@@ -185,15 +185,15 @@ export async function linkFigma(
185
185
 
186
186
  // Find matches
187
187
  const matches: Match[] = [];
188
- const unmatchedSegments: SegmentInfo[] = [];
188
+ const unmatchedFragments: FragmentInfo[] = [];
189
189
 
190
- for (const segment of segments) {
190
+ for (const fragment of fragments) {
191
191
  // Find best matching Figma component
192
192
  let bestMatch: typeof allFigmaComponents[0] | null = null;
193
193
  let bestScore = 0;
194
194
 
195
195
  for (const figmaComp of allFigmaComponents) {
196
- const score = calculateMatchScore(segment.name, figmaComp.name);
196
+ const score = calculateMatchScore(fragment.name, figmaComp.name);
197
197
 
198
198
  if (score > bestScore) {
199
199
  bestMatch = figmaComp;
@@ -206,19 +206,19 @@ export async function linkFigma(
206
206
 
207
207
  // Accept matches with 65%+ score
208
208
  if (bestMatch && bestScore >= 65) {
209
- const alreadyLinked = segment.hasFigma;
209
+ const alreadyLinked = fragment.hasFigma;
210
210
  if (alreadyLinked && !auto) {
211
- console.log(pc.dim(`⏭️ ${segment.name} (already linked)`));
211
+ console.log(pc.dim(`⏭️ ${fragment.name} (already linked)`));
212
212
  }
213
- matches.push({ segment, figmaComponent: bestMatch, score: bestScore, alreadyLinked });
213
+ matches.push({ fragment, figmaComponent: bestMatch, score: bestScore, alreadyLinked });
214
214
  } else {
215
- unmatchedSegments.push(segment);
215
+ unmatchedFragments.push(fragment);
216
216
  }
217
217
  }
218
218
 
219
- if (unmatchedSegments.length > 0) {
220
- console.log(pc.dim('Unmatched segments:'));
221
- for (const seg of unmatchedSegments) {
219
+ if (unmatchedFragments.length > 0) {
220
+ console.log(pc.dim('Unmatched fragments:'));
221
+ for (const seg of unmatchedFragments) {
222
222
  console.log(` ${pc.dim('•')} ${seg.name}`);
223
223
  }
224
224
  console.log();
@@ -230,7 +230,7 @@ export async function linkFigma(
230
230
 
231
231
  if (matches.length === 0) {
232
232
  console.log(pc.yellow('\nNo automatic matches found.'));
233
- console.log(pc.dim('You can manually add figma URLs to your segment definitions.'));
233
+ console.log(pc.dim('You can manually add figma URLs to your fragment definitions.'));
234
234
  process.exit(0);
235
235
  }
236
236
 
@@ -241,7 +241,7 @@ export async function linkFigma(
241
241
  for (const match of newMatches) {
242
242
  const scoreColor = match.score === 100 ? pc.green : pc.yellow;
243
243
  console.log(
244
- ` ${pc.green('✓')} ${pc.bold(match.segment.name)} → ${match.figmaComponent.name} ${scoreColor(`(${Math.round(match.score)}%)`)}`
244
+ ` ${pc.green('✓')} ${pc.bold(match.fragment.name)} → ${match.figmaComponent.name} ${scoreColor(`(${Math.round(match.score)}%)`)}`
245
245
  );
246
246
  }
247
247
  }
@@ -259,7 +259,7 @@ export async function linkFigma(
259
259
  for (const match of newMatches) {
260
260
  const scoreColor = match.score === 100 ? pc.green : pc.yellow;
261
261
  console.log(
262
- ` ${pc.green('✓')} ${pc.bold(match.segment.name)} → ${match.figmaComponent.name} ${scoreColor(`(${Math.round(match.score)}%)`)}`
262
+ ` ${pc.green('✓')} ${pc.bold(match.fragment.name)} → ${match.figmaComponent.name} ${scoreColor(`(${Math.round(match.score)}%)`)}`
263
263
  );
264
264
  }
265
265
  } else {
@@ -272,7 +272,7 @@ export async function linkFigma(
272
272
  const choices = newMatches.map((match) => {
273
273
  const scoreColor = match.score === 100 ? pc.green : pc.yellow;
274
274
  return {
275
- name: `${pc.bold(match.segment.name)} → ${match.figmaComponent.name} ${scoreColor(`(${Math.round(match.score)}%)`)}`,
275
+ name: `${pc.bold(match.fragment.name)} → ${match.figmaComponent.name} ${scoreColor(`(${Math.round(match.score)}%)`)}`,
276
276
  value: match,
277
277
  checked: true,
278
278
  };
@@ -295,13 +295,13 @@ export async function linkFigma(
295
295
  // Include already-linked matches for variant linking
296
296
  const allSelectedMatches = [...selectedMatches, ...alreadyLinkedMatches];
297
297
 
298
- // Update segment files (only for new matches, not already-linked)
298
+ // Update fragment files (only for new matches, not already-linked)
299
299
  let updated = 0;
300
300
  for (const match of selectedMatches) {
301
301
  if (match.alreadyLinked) continue;
302
302
 
303
303
  try {
304
- let content = await readFile(match.segment.filePath, 'utf-8');
304
+ let content = await readFile(match.fragment.filePath, 'utf-8');
305
305
  const figmaUrlToInsert = figmaClient.buildNodeUrl(
306
306
  match.figmaComponent.file_key,
307
307
  match.figmaComponent.node_id,
@@ -323,16 +323,16 @@ export async function linkFigma(
323
323
  );
324
324
  }
325
325
 
326
- await writeFile(match.segment.filePath, content);
326
+ await writeFile(match.fragment.filePath, content);
327
327
  updated++;
328
- console.log(` ${pc.green('✓')} Updated ${match.segment.relativePath}`);
328
+ console.log(` ${pc.green('✓')} Updated ${match.fragment.relativePath}`);
329
329
  } catch (error) {
330
- console.log(` ${pc.red('✗')} Failed to update ${match.segment.relativePath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
330
+ console.log(` ${pc.red('✗')} Failed to update ${match.fragment.relativePath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
331
331
  }
332
332
  }
333
333
 
334
334
  if (updated > 0) {
335
- console.log(pc.green(`\n✓ Updated ${updated} segment file(s)\n`));
335
+ console.log(pc.green(`\n✓ Updated ${updated} fragment file(s)\n`));
336
336
  }
337
337
 
338
338
  // Variant linking
@@ -357,10 +357,10 @@ export async function linkFigma(
357
357
  }
358
358
 
359
359
  /**
360
- * Extract variants from segment file content
360
+ * Extract variants from fragment file content
361
361
  */
362
- function extractVariants(content: string, componentName?: string): SegmentVariantInfo[] {
363
- const variants: SegmentVariantInfo[] = [];
362
+ function extractVariants(content: string, componentName?: string): FragmentVariantInfo[] {
363
+ const variants: FragmentVariantInfo[] = [];
364
364
 
365
365
  // Find variants: [ ... ] section
366
366
  const variantsArrayMatch = content.match(/variants:\s*\[/);
@@ -411,27 +411,27 @@ function extractVariants(content: string, componentName?: string): SegmentVarian
411
411
  /**
412
412
  * Calculate match score between two names
413
413
  */
414
- function calculateMatchScore(segmentName: string, figmaName: string): number {
414
+ function calculateMatchScore(fragmentName: string, figmaName: string): number {
415
415
  const normalizeForMatch = (s: string) =>
416
416
  s.toLowerCase().replace(/[^a-z0-9]/g, '');
417
417
 
418
- const normalizedSegment = normalizeForMatch(segmentName);
418
+ const normalizedFragment = normalizeForMatch(fragmentName);
419
419
  const normalizedFigma = normalizeForMatch(figmaName);
420
420
 
421
421
  // Exact match after normalization
422
- if (normalizedSegment === normalizedFigma) {
422
+ if (normalizedFragment === normalizedFigma) {
423
423
  return 100;
424
424
  }
425
425
 
426
- // Check if segment name appears at the START of figma name
427
- if (normalizedFigma.startsWith(normalizedSegment)) {
428
- const coverage = normalizedSegment.length / normalizedFigma.length;
426
+ // Check if fragment name appears at the START of figma name
427
+ if (normalizedFigma.startsWith(normalizedFragment)) {
428
+ const coverage = normalizedFragment.length / normalizedFigma.length;
429
429
  return Math.max(85, coverage * 100);
430
430
  }
431
431
 
432
- // Check if figma name appears at the START of segment name
433
- if (normalizedSegment.startsWith(normalizedFigma)) {
434
- const coverage = normalizedFigma.length / normalizedSegment.length;
432
+ // Check if figma name appears at the START of fragment name
433
+ if (normalizedFragment.startsWith(normalizedFigma)) {
434
+ const coverage = normalizedFigma.length / normalizedFragment.length;
435
435
  return Math.max(80, coverage * 100);
436
436
  }
437
437
 
@@ -445,24 +445,24 @@ function calculateMatchScore(segmentName: string, figmaName: string): number {
445
445
  .filter((w) => w.length > 0);
446
446
  };
447
447
 
448
- const segmentWords = getWords(segmentName);
448
+ const fragmentWords = getWords(fragmentName);
449
449
  const figmaWords = getWords(figmaName);
450
450
 
451
- // Check if all segment words appear in figma words
452
- const allSegmentWordsInFigma = segmentWords.every((sw) =>
451
+ // Check if all fragment words appear in figma words
452
+ const allFragmentWordsInFigma = fragmentWords.every((sw) =>
453
453
  figmaWords.some((fw) => fw === sw || fw.startsWith(sw) || sw.startsWith(fw))
454
454
  );
455
455
 
456
- if (allSegmentWordsInFigma && segmentWords.length > 0) {
457
- const wordOverlap = segmentWords.length / Math.max(segmentWords.length, figmaWords.length);
456
+ if (allFragmentWordsInFigma && fragmentWords.length > 0) {
457
+ const wordOverlap = fragmentWords.length / Math.max(fragmentWords.length, figmaWords.length);
458
458
  return Math.max(75, wordOverlap * 95);
459
459
  }
460
460
 
461
461
  // Partial containment
462
- if (normalizedFigma.includes(normalizedSegment)) {
462
+ if (normalizedFigma.includes(normalizedFragment)) {
463
463
  return 70;
464
464
  }
465
- if (normalizedSegment.includes(normalizedFigma)) {
465
+ if (normalizedFragment.includes(normalizedFigma)) {
466
466
  return 65;
467
467
  }
468
468
 
@@ -510,16 +510,16 @@ async function linkVariants(
510
510
  continue;
511
511
  }
512
512
 
513
- // Match segment variants to Figma variants
514
- const segmentVariants = match.segment.variants.filter((v) => !v.hasFigma);
515
- if (segmentVariants.length === 0) {
516
- console.log(pc.dim(` ⏭️ ${match.segment.name}: all variants already linked`));
513
+ // Match fragment variants to Figma variants
514
+ const fragmentVariants = match.fragment.variants.filter((v) => !v.hasFigma);
515
+ if (fragmentVariants.length === 0) {
516
+ console.log(pc.dim(` ⏭️ ${match.fragment.name}: all variants already linked`));
517
517
  continue;
518
518
  }
519
519
 
520
- console.log(pc.dim(` ${match.segment.name}: ${csWithVariants.variants.length} Figma variants`));
520
+ console.log(pc.dim(` ${match.fragment.name}: ${csWithVariants.variants.length} Figma variants`));
521
521
 
522
- for (const segmentVariant of segmentVariants) {
522
+ for (const fragmentVariant of fragmentVariants) {
523
523
  // Find matching Figma variants by score
524
524
  const variantMatches: Array<{
525
525
  figmaVariant: typeof csWithVariants.variants[0];
@@ -527,18 +527,18 @@ async function linkVariants(
527
527
  }> = [];
528
528
 
529
529
  for (const fv of csWithVariants.variants) {
530
- // Check if any property value matches the segment variant name
531
- const normalizedSegment = normalizeForMatch(segmentVariant.name);
530
+ // Check if any property value matches the fragment variant name
531
+ const normalizedFragment = normalizeForMatch(fragmentVariant.name);
532
532
 
533
533
  for (const value of fv.values) {
534
534
  const normalizedValue = normalizeForMatch(value);
535
535
 
536
- if (normalizedSegment === normalizedValue) {
536
+ if (normalizedFragment === normalizedValue) {
537
537
  variantMatches.push({ figmaVariant: fv, score: 100 });
538
538
  break;
539
- } else if (normalizedValue.includes(normalizedSegment)) {
539
+ } else if (normalizedValue.includes(normalizedFragment)) {
540
540
  variantMatches.push({ figmaVariant: fv, score: 85 });
541
- } else if (normalizedSegment.includes(normalizedValue)) {
541
+ } else if (normalizedFragment.includes(normalizedValue)) {
542
542
  variantMatches.push({ figmaVariant: fv, score: 75 });
543
543
  }
544
544
  }
@@ -557,11 +557,11 @@ async function linkVariants(
557
557
  );
558
558
 
559
559
  try {
560
- let content = await readFile(match.segment.filePath, 'utf-8');
560
+ let content = await readFile(match.fragment.filePath, 'utf-8');
561
561
 
562
562
  // Add figma URL after the variant's name field
563
563
  const namePattern = new RegExp(
564
- `(name:\\s*['"]${escapeRegExp(segmentVariant.name)}['"],?)`,
564
+ `(name:\\s*['"]${escapeRegExp(fragmentVariant.name)}['"],?)`,
565
565
  'g'
566
566
  );
567
567
 
@@ -572,14 +572,14 @@ async function linkVariants(
572
572
  return `${matchedStr}\n figma: '${variantUrl}',`;
573
573
  });
574
574
 
575
- await writeFile(match.segment.filePath, content);
575
+ await writeFile(match.fragment.filePath, content);
576
576
  variantUpdates++;
577
577
  console.log(
578
- ` ${pc.green('✓')} ${segmentVariant.name} → ${bestMatch.figmaVariant.name}`
578
+ ` ${pc.green('✓')} ${fragmentVariant.name} → ${bestMatch.figmaVariant.name}`
579
579
  );
580
580
  } catch (error) {
581
581
  console.log(
582
- ` ${pc.red('✗')} ${segmentVariant.name}: ${error instanceof Error ? error.message : 'Unknown error'}`
582
+ ` ${pc.red('✗')} ${fragmentVariant.name}: ${error instanceof Error ? error.message : 'Unknown error'}`
583
583
  );
584
584
  }
585
585
  } else if (variantMatches.length > 0) {
@@ -594,7 +594,7 @@ async function linkVariants(
594
594
 
595
595
  try {
596
596
  const selectedVariant = await select({
597
- message: ` Match for "${segmentVariant.name}":`,
597
+ message: ` Match for "${fragmentVariant.name}":`,
598
598
  choices,
599
599
  });
600
600
 
@@ -605,9 +605,9 @@ async function linkVariants(
605
605
  figmaData.fileName
606
606
  );
607
607
 
608
- let content = await readFile(match.segment.filePath, 'utf-8');
608
+ let content = await readFile(match.fragment.filePath, 'utf-8');
609
609
  const namePattern = new RegExp(
610
- `(name:\\s*['"]${escapeRegExp(segmentVariant.name)}['"],?)`,
610
+ `(name:\\s*['"]${escapeRegExp(fragmentVariant.name)}['"],?)`,
611
611
  'g'
612
612
  );
613
613
 
@@ -618,19 +618,19 @@ async function linkVariants(
618
618
  return `${matchedStr}\n figma: '${variantUrl}',`;
619
619
  });
620
620
 
621
- await writeFile(match.segment.filePath, content);
621
+ await writeFile(match.fragment.filePath, content);
622
622
  variantUpdates++;
623
623
  console.log(
624
- ` ${pc.green('✓')} ${segmentVariant.name} → ${selectedVariant.name}`
624
+ ` ${pc.green('✓')} ${fragmentVariant.name} → ${selectedVariant.name}`
625
625
  );
626
626
  } else {
627
- console.log(` ${pc.dim('⏭️')} ${segmentVariant.name} (skipped)`);
627
+ console.log(` ${pc.dim('⏭️')} ${fragmentVariant.name} (skipped)`);
628
628
  }
629
629
  } catch {
630
- console.log(` ${pc.dim('⏭️')} ${segmentVariant.name} (cancelled)`);
630
+ console.log(` ${pc.dim('⏭️')} ${fragmentVariant.name} (cancelled)`);
631
631
  }
632
632
  } else {
633
- console.log(` ${pc.yellow('?')} ${segmentVariant.name}: no matching Figma variant`);
633
+ console.log(` ${pc.yellow('?')} ${fragmentVariant.name}: no matching Figma variant`);
634
634
  }
635
635
  }
636
636
  }
@@ -1,9 +1,9 @@
1
1
  /**
2
- * fragments link - Link external resources to segments
2
+ * fragments link - Link external resources to fragments
3
3
  *
4
4
  * This module provides subcommands for:
5
- * - figma: Link Figma components to segments
6
- * - storybook: Bootstrap segments from Storybook stories
5
+ * - figma: Link Figma components to fragments
6
+ * - storybook: Bootstrap fragments from Storybook stories
7
7
  */
8
8
 
9
9
  export { linkFigma, type LinkFigmaOptions, type LinkFigmaResult } from './figma.js';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * fragments link storybook - Bootstrap segments from Storybook stories
2
+ * fragments link storybook - Bootstrap fragments from Storybook stories
3
3
  */
4
4
 
5
5
  import { writeFile, mkdir } from 'node:fs/promises';
@@ -10,7 +10,7 @@ import {
10
10
  detectStorybookConfig,
11
11
  discoverStoryFiles as discoverStorybookFiles,
12
12
  parseStoryFile,
13
- convertToSegment,
13
+ convertToFragment,
14
14
  } from '../../migrate/index.js';
15
15
 
16
16
  /**
@@ -19,7 +19,7 @@ import {
19
19
  export interface LinkStorybookOptions {
20
20
  /** Path to .storybook/main.* config */
21
21
  config?: string;
22
- /** Output directory for segment files */
22
+ /** Output directory for fragment files */
23
23
  out?: string;
24
24
  /** Skip confirmation prompts */
25
25
  yes?: boolean;
@@ -114,7 +114,7 @@ export async function linkStorybook(
114
114
 
115
115
  try {
116
116
  const parsed = await parseStoryFile(storyFile);
117
- const result = convertToSegment(parsed);
117
+ const result = convertToFragment(parsed);
118
118
 
119
119
  // Determine output path
120
120
  const outputFile = out
@@ -177,7 +177,7 @@ export async function linkStorybook(
177
177
 
178
178
  // Dry run stops here
179
179
  if (dryRun) {
180
- console.log(pc.dim(`\n${previews.length} segment file(s) would be created`));
180
+ console.log(pc.dim(`\n${previews.length} fragment file(s) would be created`));
181
181
  console.log(pc.yellow('\n[Dry run - no files were written]'));
182
182
  return { success: true, generated: 0 };
183
183
  }
@@ -186,7 +186,7 @@ export async function linkStorybook(
186
186
  let selectedPreviews = previews;
187
187
 
188
188
  if (yes) {
189
- console.log(pc.dim(`\n${previews.length} segment file(s) will be created`));
189
+ console.log(pc.dim(`\n${previews.length} fragment file(s) will be created`));
190
190
  } else {
191
191
  const { checkbox } = await import('@inquirer/prompts');
192
192
 
@@ -222,7 +222,7 @@ export async function linkStorybook(
222
222
 
223
223
  // Generate files
224
224
  const genTotal = selectedPreviews.length;
225
- console.log(pc.dim(`\nGenerating ${genTotal} segment file(s)...\n`));
225
+ console.log(pc.dim(`\nGenerating ${genTotal} fragment file(s)...\n`));
226
226
 
227
227
  let generated = 0;
228
228
  let genErrors = 0;
@@ -231,7 +231,7 @@ export async function linkStorybook(
231
231
  const storyFile = join(projectRoot, preview.sourceFile);
232
232
  try {
233
233
  const parsed = await parseStoryFile(storyFile);
234
- const result = convertToSegment(parsed);
234
+ const result = convertToFragment(parsed);
235
235
 
236
236
  // Determine output path
237
237
  const outputFile = out
@@ -252,7 +252,7 @@ export async function linkStorybook(
252
252
  }
253
253
  }
254
254
 
255
- console.log(pc.green(`\n✓ Generated ${generated} segment file(s)\n`));
255
+ console.log(pc.green(`\n✓ Generated ${generated} fragment file(s)\n`));
256
256
 
257
257
  // Next steps
258
258
  console.log(pc.dim('───────────────────────────────────────'));
@@ -4,7 +4,7 @@
4
4
 
5
5
  import pc from 'picocolors';
6
6
  import { BRAND } from '../core/index.js';
7
- import { loadConfig, discoverSegmentFiles } from '../core/node.js';
7
+ import { loadConfig, discoverFragmentFiles } from '../core/node.js';
8
8
 
9
9
  /**
10
10
  * Options for list command
@@ -30,7 +30,7 @@ export interface ListResult {
30
30
  */
31
31
  export async function list(options: ListOptions = {}): Promise<ListResult> {
32
32
  const { config, configDir } = await loadConfig(options.config);
33
- const files = await discoverSegmentFiles(config, configDir);
33
+ const files = await discoverFragmentFiles(config, configDir);
34
34
 
35
35
  console.log(pc.cyan(`\n${BRAND.name} - Discovered Fragments\n`));
36
36
 
@@ -42,7 +42,7 @@ export async function reset(options: ResetOptions = {}): Promise<ResetResult> {
42
42
  const filesToDelete: string[] = [];
43
43
  const dirsToDelete: string[] = [];
44
44
 
45
- // Check data directory (.segments/)
45
+ // Check data directory (.fragments/)
46
46
  const dataDir = join(projectRoot, BRAND.dataDir);
47
47
  try {
48
48
  const dataDirStat = await stat(dataDir);
@@ -53,8 +53,8 @@ export async function reset(options: ResetOptions = {}): Promise<ResetResult> {
53
53
  // Directory doesn't exist
54
54
  }
55
55
 
56
- // Check for segments.json (default output file)
57
- const defaultOutFile = join(projectRoot, 'segments.json');
56
+ // Check for fragments.json (default output file)
57
+ const defaultOutFile = join(projectRoot, 'fragments.json');
58
58
  try {
59
59
  const fileStat = await stat(defaultOutFile);
60
60
  if (fileStat.isFile()) {
@@ -65,10 +65,10 @@ export async function reset(options: ResetOptions = {}): Promise<ResetResult> {
65
65
  }
66
66
 
67
67
  // Try to load config for custom outFile and include patterns
68
- let segmentPatterns = [`**/*${BRAND.fileExtension}`];
68
+ let fragmentPatterns = [`**/*${BRAND.fileExtension}`];
69
69
  try {
70
70
  const { config } = await loadConfig();
71
- if (config.outFile && config.outFile !== 'segments.json') {
71
+ if (config.outFile && config.outFile !== 'fragments.json') {
72
72
  const customOutFile = join(projectRoot, config.outFile);
73
73
  try {
74
74
  const fileStat = await stat(customOutFile);
@@ -81,15 +81,15 @@ export async function reset(options: ResetOptions = {}): Promise<ResetResult> {
81
81
  }
82
82
  // Use config include patterns if available
83
83
  if (config.include && config.include.length > 0) {
84
- segmentPatterns = config.include;
84
+ fragmentPatterns = config.include;
85
85
  }
86
86
  } catch {
87
87
  // No config file, use defaults
88
88
  }
89
89
 
90
- // Find all segment files (*.segment.tsx)
90
+ // Find all fragment files (*.fragment.tsx)
91
91
  console.log(pc.dim('Scanning for generated files...\n'));
92
- for (const pattern of segmentPatterns) {
92
+ for (const pattern of fragmentPatterns) {
93
93
  const matches = await fg(pattern, {
94
94
  cwd: projectRoot,
95
95
  ignore: ['**/node_modules/**'],
@@ -130,23 +130,23 @@ export async function reset(options: ResetOptions = {}): Promise<ResetResult> {
130
130
  }
131
131
 
132
132
  // Group files by type for cleaner output
133
- const segmentFiles = filesToDelete.filter((f) => f.endsWith(BRAND.fileExtension));
133
+ const fragmentFiles = filesToDelete.filter((f) => f.endsWith(BRAND.fileExtension));
134
134
  const mdxFilesFound = filesToDelete.filter((f) => f.endsWith('.mdx'));
135
135
  const otherFiles = filesToDelete.filter(
136
136
  (f) => !f.endsWith(BRAND.fileExtension) && !f.endsWith('.mdx')
137
137
  );
138
138
 
139
- if (segmentFiles.length > 0) {
140
- console.log(` 📄 ${segmentFiles.length} segment file(s) (*${BRAND.fileExtension})`);
141
- if (segmentFiles.length <= 5) {
142
- for (const f of segmentFiles) {
139
+ if (fragmentFiles.length > 0) {
140
+ console.log(` 📄 ${fragmentFiles.length} fragment file(s) (*${BRAND.fileExtension})`);
141
+ if (fragmentFiles.length <= 5) {
142
+ for (const f of fragmentFiles) {
143
143
  console.log(pc.dim(` ${relative(projectRoot, f)}`));
144
144
  }
145
145
  } else {
146
- for (const f of segmentFiles.slice(0, 3)) {
146
+ for (const f of fragmentFiles.slice(0, 3)) {
147
147
  console.log(pc.dim(` ${relative(projectRoot, f)}`));
148
148
  }
149
- console.log(pc.dim(` ... and ${segmentFiles.length - 3} more`));
149
+ console.log(pc.dim(` ... and ${fragmentFiles.length - 3} more`));
150
150
  }
151
151
  }
152
152