@fragments-sdk/cli 0.5.0 → 0.5.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 (33) hide show
  1. package/dist/bin.js +7 -7
  2. package/dist/{chunk-UXRGD3DM.js → chunk-U4GQ2JTD.js} +2 -2
  3. package/dist/{chunk-B2TQKOLW.js → chunk-V7YLRR4C.js} +2 -238
  4. package/dist/chunk-V7YLRR4C.js.map +1 -0
  5. package/dist/{core-NJVKKLJ4.js → core-DKHB7FYV.js} +2 -2
  6. package/dist/{generate-OVGMDKCJ.js → generate-KL24VZVD.js} +2 -2
  7. package/dist/index.d.ts +2 -285
  8. package/dist/index.js +2 -2
  9. package/dist/{init-EOA7TTOR.js → init-NION5S3M.js} +5 -5
  10. package/dist/init-NION5S3M.js.map +1 -0
  11. package/dist/mcp-bin.js +26 -3
  12. package/dist/mcp-bin.js.map +1 -1
  13. package/dist/{scan-YN4LUDKY.js → scan-ESEXV7LF.js} +2 -2
  14. package/dist/{service-2T26CBWE.js → service-RWUMZ3EW.js} +2 -2
  15. package/dist/{static-viewer-CLJJRYHK.js → static-viewer-O37MJ5B6.js} +2 -2
  16. package/dist/{tokens-FHA2DO22.js → tokens-ITADYVPF.js} +2 -2
  17. package/dist/{viewer-XDPD52L7.js → viewer-YDGFDTK5.js} +11 -11
  18. package/package.json +3 -2
  19. package/src/commands/init.ts +2 -2
  20. package/src/core/context.ts +2 -380
  21. package/src/core/types.ts +11 -101
  22. package/src/mcp/__tests__/findFragmentsJson.test.ts +30 -0
  23. package/src/mcp/server.ts +40 -1
  24. package/dist/chunk-B2TQKOLW.js.map +0 -1
  25. package/dist/init-EOA7TTOR.js.map +0 -1
  26. /package/dist/{chunk-UXRGD3DM.js.map → chunk-U4GQ2JTD.js.map} +0 -0
  27. /package/dist/{core-NJVKKLJ4.js.map → core-DKHB7FYV.js.map} +0 -0
  28. /package/dist/{generate-OVGMDKCJ.js.map → generate-KL24VZVD.js.map} +0 -0
  29. /package/dist/{scan-YN4LUDKY.js.map → scan-ESEXV7LF.js.map} +0 -0
  30. /package/dist/{service-2T26CBWE.js.map → service-RWUMZ3EW.js.map} +0 -0
  31. /package/dist/{static-viewer-CLJJRYHK.js.map → static-viewer-O37MJ5B6.js.map} +0 -0
  32. /package/dist/{tokens-FHA2DO22.js.map → tokens-ITADYVPF.js.map} +0 -0
  33. /package/dist/{viewer-XDPD52L7.js.map → viewer-YDGFDTK5.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,205 +1,5 @@
1
- /**
2
- * Metadata about the component
3
- */
4
- interface SegmentMeta {
5
- /** Component display name */
6
- name: string;
7
- /** Brief description of the component's purpose */
8
- description: string;
9
- /** Category for organizing components (e.g., "actions", "forms", "layout") */
10
- category: string;
11
- /** Optional tags for additional categorization */
12
- tags?: string[];
13
- /** Component status */
14
- status?: "stable" | "beta" | "deprecated" | "experimental";
15
- /** Version when component was introduced */
16
- since?: string;
17
- /** Figma frame URL for design verification */
18
- figma?: string;
19
- /** Figma property mappings (how Figma props map to code props) */
20
- figmaProps?: Record<string, FigmaPropMapping>;
21
- }
22
- /**
23
- * Figma property mapping types - describes how a Figma property maps to code
24
- */
25
- type FigmaPropMapping = FigmaStringMapping | FigmaBooleanMapping | FigmaEnumMapping | FigmaInstanceMapping | FigmaChildrenMapping | FigmaTextContentMapping;
26
- /** Maps a Figma text property to a string prop */
27
- interface FigmaStringMapping {
28
- __type: 'figma-string';
29
- figmaProperty: string;
30
- }
31
- /** Maps a Figma boolean property to a boolean prop (with optional value mapping) */
32
- interface FigmaBooleanMapping {
33
- __type: 'figma-boolean';
34
- figmaProperty: string;
35
- valueMapping?: {
36
- true: unknown;
37
- false: unknown;
38
- };
39
- }
40
- /** Maps a Figma variant property to an enum prop */
41
- interface FigmaEnumMapping {
42
- __type: 'figma-enum';
43
- figmaProperty: string;
44
- valueMapping: Record<string, unknown>;
45
- }
46
- /** References a nested Figma component instance */
47
- interface FigmaInstanceMapping {
48
- __type: 'figma-instance';
49
- figmaProperty: string;
50
- }
51
- /** Renders children from Figma layer names */
52
- interface FigmaChildrenMapping {
53
- __type: 'figma-children';
54
- layers: string[];
55
- }
56
- /** Extracts text content from a Figma text layer */
57
- interface FigmaTextContentMapping {
58
- __type: 'figma-text-content';
59
- layer: string;
60
- }
61
- /**
62
- * Usage guidelines for AI agents and developers
63
- */
64
- interface SegmentUsage {
65
- /** When to use this component */
66
- when: string[];
67
- /** When NOT to use this component (with alternatives) */
68
- whenNot: string[];
69
- /** Additional usage guidelines and best practices */
70
- guidelines?: string[];
71
- /** Accessibility considerations */
72
- accessibility?: string[];
73
- }
74
- /**
75
- * Prop type definitions
76
- */
77
- type PropType = {
78
- type: "string";
79
- pattern?: string;
80
- } | {
81
- type: "number";
82
- min?: number;
83
- max?: number;
84
- } | {
85
- type: "boolean";
86
- } | {
87
- type: "enum";
88
- values: readonly string[];
89
- } | {
90
- type: "function";
91
- signature?: string;
92
- } | {
93
- type: "node";
94
- } | {
95
- type: "element";
96
- } | {
97
- type: "object";
98
- shape?: Record<string, PropDefinition>;
99
- } | {
100
- type: "array";
101
- items?: PropType;
102
- } | {
103
- type: "union";
104
- types: PropType[];
105
- } | {
106
- type: "custom";
107
- typescript: string;
108
- };
109
- /**
110
- * Storybook control types for UI rendering
111
- */
112
- type ControlType = "text" | "number" | "range" | "boolean" | "select" | "multi-select" | "radio" | "inline-radio" | "check" | "inline-check" | "object" | "file" | "color" | "date";
113
- /**
114
- * Definition for a single prop
115
- */
116
- interface PropDefinition {
117
- /** The prop type */
118
- type: PropType["type"];
119
- /** For enum types, the allowed values */
120
- values?: readonly string[];
121
- /** Default value if not provided */
122
- default?: unknown;
123
- /** Description of what this prop does */
124
- description: string;
125
- /** Whether this prop is required */
126
- required?: boolean;
127
- /** Usage constraints for AI agents */
128
- constraints?: string[];
129
- /** Additional type details for complex types */
130
- typeDetails?: Omit<PropType, "type">;
131
- /** Original Storybook control type for UI rendering (e.g., "color", "date", "range") */
132
- controlType?: ControlType;
133
- /** Control options (e.g., min/max for range, presetColors for color) */
134
- controlOptions?: {
135
- min?: number;
136
- max?: number;
137
- step?: number;
138
- presetColors?: string[];
139
- };
140
- }
141
- /**
142
- * Relationship types between components
143
- */
144
- type RelationshipType = "alternative" | "sibling" | "parent" | "child" | "composition";
145
- /**
146
- * Relationship to another component
147
- */
148
- interface ComponentRelation {
149
- /** Name of the related component */
150
- component: string;
151
- /** Type of relationship */
152
- relationship: RelationshipType;
153
- /** Explanation of the relationship */
154
- note: string;
155
- }
156
- /**
157
- * Agent-optimized contract metadata
158
- * Provides compact, structured data for AI code generation
159
- */
160
- interface SegmentContract {
161
- /** Short prop descriptions for agents (e.g., "variant: primary|secondary (required)") */
162
- propsSummary?: string[];
163
- /** Accessibility rule IDs for lookup in glossary (e.g., "A11Y_BTN_LABEL") */
164
- a11yRules?: string[];
165
- /** Banned patterns in codebase - triggers warnings during code review */
166
- bans?: Array<{
167
- /** Pattern to match (regex string or literal) */
168
- pattern: string;
169
- /** Message explaining why this pattern is banned and what to use instead */
170
- message: string;
171
- }>;
172
- /** Scenario tags for use-case matching (e.g., "form.submit", "navigation.primary") */
173
- scenarioTags?: string[];
174
- }
175
- /**
176
- * Provenance tracking for generated segments
177
- * Helps distinguish human-authored from machine-generated content
178
- */
179
- interface SegmentGenerated {
180
- /** Source of this segment definition */
181
- source: "storybook" | "manual" | "ai";
182
- /** Original source file (e.g., "Button.stories.tsx") */
183
- sourceFile?: string;
184
- /** Confidence score from 0-1 (how reliable the extraction was) */
185
- confidence?: number;
186
- /** ISO timestamp when this was generated */
187
- timestamp?: string;
188
- }
189
- /**
190
- * AI-specific metadata for playground context generation
191
- * Provides hints for AI code generation about component composition
192
- */
193
- interface AIMetadata {
194
- /** How this component is composed with others */
195
- compositionPattern?: "compound" | "simple" | "controlled";
196
- /** Sub-component names (without parent prefix, e.g., "Header" not "Card.Header") */
197
- subComponents?: string[];
198
- /** Sub-components that must be present for valid composition */
199
- requiredChildren?: string[];
200
- /** Common usage patterns as JSX strings for AI reference */
201
- commonPatterns?: string[];
202
- }
1
+ import { CompiledSegmentsFile } from '@fragments-sdk/context/types';
2
+
203
3
  /**
204
4
  * Registry generation options
205
5
  */
@@ -345,89 +145,6 @@ interface BoundingBox {
345
145
  width: number;
346
146
  height: number;
347
147
  }
348
- /**
349
- * Compiled segment data (JSON-serializable for AI consumption)
350
- */
351
- interface CompiledSegment {
352
- /** File path relative to project root */
353
- filePath: string;
354
- /** Component metadata */
355
- meta: SegmentMeta;
356
- /** Usage guidelines */
357
- usage: SegmentUsage;
358
- /** Props documentation (without render functions) */
359
- props: Record<string, PropDefinition>;
360
- /** Component relationships */
361
- relations?: ComponentRelation[];
362
- /** Variant names and descriptions (without render functions) */
363
- variants: Array<{
364
- name: string;
365
- description: string;
366
- code?: string;
367
- figma?: string;
368
- /** Args/props used to render this variant (for code generation) */
369
- args?: Record<string, unknown>;
370
- }>;
371
- /** Agent-optimized contract metadata */
372
- contract?: SegmentContract;
373
- /** AI-specific metadata for playground context generation */
374
- ai?: AIMetadata;
375
- /** Provenance tracking (for generated segments) */
376
- _generated?: SegmentGenerated;
377
- }
378
- /**
379
- * Compiled block data (JSON-serializable for AI consumption)
380
- */
381
- interface CompiledBlock {
382
- filePath: string;
383
- name: string;
384
- description: string;
385
- category: string;
386
- components: string[];
387
- code: string;
388
- tags?: string[];
389
- }
390
- /**
391
- * A single token entry in the compiled output
392
- */
393
- interface CompiledTokenEntry {
394
- /** CSS variable name (e.g., "--fui-color-accent") */
395
- name: string;
396
- /** Description from inline comment */
397
- description?: string;
398
- }
399
- /**
400
- * Compiled token data stored in fragments.json
401
- */
402
- interface CompiledTokenData {
403
- /** Detected variable prefix (e.g., "--fui-") */
404
- prefix: string;
405
- /** Total number of tokens */
406
- total: number;
407
- /** Tokens grouped by category */
408
- categories: Record<string, CompiledTokenEntry[]>;
409
- }
410
- /**
411
- * The compiled segments.json structure
412
- */
413
- interface CompiledSegmentsFile {
414
- /** Version of the schema */
415
- version: string;
416
- /** When this file was generated */
417
- generatedAt: string;
418
- /** Package name for import statements (read from package.json at build time) */
419
- packageName?: string;
420
- /** All compiled segments indexed by component name */
421
- segments: Record<string, CompiledSegment>;
422
- /** All compiled blocks indexed by block name */
423
- blocks?: Record<string, CompiledBlock>;
424
- /** Design tokens (CSS custom properties) extracted from style files */
425
- tokens?: CompiledTokenData;
426
- /**
427
- * @deprecated Use blocks instead
428
- */
429
- recipes?: Record<string, CompiledBlock>;
430
- }
431
148
 
432
149
  /**
433
150
  * Find the config file in the current directory or parent directories.
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  validateAll,
8
8
  validateCoverage,
9
9
  validateSchema
10
- } from "./chunk-UXRGD3DM.js";
10
+ } from "./chunk-U4GQ2JTD.js";
11
11
  import "./chunk-IOJE35DZ.js";
12
12
  import {
13
13
  discoverComponentFiles,
@@ -20,7 +20,7 @@ import {
20
20
  generateStaticViewer,
21
21
  generateViewerFromJson
22
22
  } from "./chunk-2DJH4F4P.js";
23
- import "./chunk-B2TQKOLW.js";
23
+ import "./chunk-V7YLRR4C.js";
24
24
  import "./chunk-ICAIQ57V.js";
25
25
  export {
26
26
  buildSegments,
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
- import "./chunk-B2TQKOLW.js";
2
+ import "./chunk-V7YLRR4C.js";
3
3
  import {
4
4
  BRAND
5
5
  } from "./chunk-ICAIQ57V.js";
@@ -79,7 +79,7 @@ async function detectProject(projectRoot) {
79
79
  function generateConfig(options) {
80
80
  const includeStr = options.includePaths.map((p) => ` '${p}'`).join(",\n");
81
81
  const componentStr = options.componentPaths.map((p) => ` '${p}'`).join(",\n");
82
- return `import type { FragmentsConfig } from '@fragments/core';
82
+ return `import type { FragmentsConfig } from '@fragments-sdk/cli';
83
83
 
84
84
  const config: FragmentsConfig = {
85
85
  // Glob patterns for finding fragment/story files
@@ -153,7 +153,7 @@ export function Button({
153
153
  }
154
154
  function generateExampleFragment() {
155
155
  return `import React from 'react';
156
- import { defineFragment } from '@fragments/core';
156
+ import { defineFragment } from '@fragments-sdk/cli';
157
157
  import { Button } from './Button';
158
158
 
159
159
  export default defineFragment({
@@ -375,7 +375,7 @@ Keeping existing configuration. Run \`${BRAND.cliCommand} dev\` to start.
375
375
  if (scenario === "components" && runScan) {
376
376
  console.log(pc.dim("\nGenerating documentation from source code...\n"));
377
377
  try {
378
- const { scan } = await import("./scan-YN4LUDKY.js");
378
+ const { scan } = await import("./scan-ESEXV7LF.js");
379
379
  await scan({
380
380
  config: configPath,
381
381
  verbose: false
@@ -413,4 +413,4 @@ Keeping existing configuration. Run \`${BRAND.cliCommand} dev\` to start.
413
413
  export {
414
414
  init
415
415
  };
416
- //# sourceMappingURL=init-EOA7TTOR.js.map
416
+ //# sourceMappingURL=init-NION5S3M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["/**\n * fragments init - Smart interactive initialization\n *\n * Handles three scenarios:\n * 1. Stories found → Configure and load existing stories\n * 2. Components found (no stories) → Auto-generate documentation\n * 3. Fresh project → Guided setup with example component\n */\n\nimport { readFile, writeFile, mkdir, access } from \"node:fs/promises\";\nimport { resolve, join, relative } from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport fg from \"fast-glob\";\nimport { input, confirm, select } from \"@inquirer/prompts\";\n\nexport interface InitOptions {\n /** Project root directory */\n projectRoot?: string;\n /** Force overwrite existing config */\n force?: boolean;\n /** Non-interactive mode - auto-detect and use defaults */\n yes?: boolean;\n}\n\nexport interface InitResult {\n success: boolean;\n configPath?: string;\n scenario: \"stories\" | \"components\" | \"fresh\";\n storiesFound: number;\n componentsFound: number;\n errors: string[];\n}\n\ninterface DetectionResult {\n storyFiles: string[];\n componentFiles: string[];\n hasConfig: boolean;\n configPath: string | null;\n suggestedComponentPath: string;\n}\n\n/**\n * Detect what exists in the project\n */\nasync function detectProject(projectRoot: string): Promise<DetectionResult> {\n console.log(pc.dim(\"\\nScanning project...\\n\"));\n\n // Check for existing config\n const configPath = join(projectRoot, BRAND.configFile);\n const legacyConfigPath = join(projectRoot, BRAND.legacyConfigFile);\n let hasConfig = false;\n let foundConfigPath: string | null = null;\n\n try {\n await access(configPath);\n hasConfig = true;\n foundConfigPath = configPath;\n } catch {\n try {\n await access(legacyConfigPath);\n hasConfig = true;\n foundConfigPath = legacyConfigPath;\n } catch {\n // No config\n }\n }\n\n // Scan for story files\n const storyFiles = await fg(\n [\"**/*.stories.tsx\", \"**/*.stories.ts\", \"**/*.stories.jsx\", \"**/*.stories.js\"],\n {\n cwd: projectRoot,\n ignore: [\"**/node_modules/**\", \"**/dist/**\", \"**/build/**\", \"**/.storybook/**\"],\n }\n );\n\n // Scan for component files (React components)\n const componentFiles = await fg(\n [\"**/components/**/*.tsx\", \"**/Components/**/*.tsx\", \"src/**/*.tsx\"],\n {\n cwd: projectRoot,\n ignore: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/*.stories.*\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/*.d.ts\",\n \"**/index.tsx\", // Skip barrel files\n ],\n }\n );\n\n // Filter to likely component files (capitalized names, not utility files)\n const likelyComponents = componentFiles.filter((f) => {\n const fileName = f.split(\"/\").pop() || \"\";\n return /^[A-Z]/.test(fileName) && !fileName.includes(\".styles\");\n });\n\n // Suggest component path based on what we found\n let suggestedComponentPath = \"src/components\";\n if (likelyComponents.length > 0) {\n const firstComponent = likelyComponents[0];\n const parts = firstComponent.split(\"/\");\n const componentsIndex = parts.findIndex(\n (p) => p.toLowerCase() === \"components\"\n );\n if (componentsIndex !== -1) {\n suggestedComponentPath = parts.slice(0, componentsIndex + 1).join(\"/\");\n }\n }\n\n return {\n storyFiles,\n componentFiles: likelyComponents,\n hasConfig,\n configPath: foundConfigPath,\n suggestedComponentPath,\n };\n}\n\n/**\n * Generate config file content\n */\nfunction generateConfig(options: {\n includePaths: string[];\n componentPaths: string[];\n framework: string;\n}): string {\n const includeStr = options.includePaths.map((p) => ` '${p}'`).join(\",\\n\");\n const componentStr = options.componentPaths.map((p) => ` '${p}'`).join(\",\\n\");\n\n return `import type { FragmentsConfig } from '@fragments-sdk/cli';\n\nconst config: FragmentsConfig = {\n // Glob patterns for finding fragment/story files\n include: [\n${includeStr}\n ],\n\n // Glob patterns to exclude\n exclude: ['**/node_modules/**'],\n\n // Glob patterns for finding component files (for auto-documentation)\n components: [\n${componentStr}\n ],\n\n // Framework (react, vue, svelte)\n framework: '${options.framework}',\n};\n\nexport default config;\n`;\n}\n\n/**\n * Generate example Button component\n */\nfunction generateExampleComponent(): string {\n return `import React from 'react';\n\nexport interface ButtonProps {\n /** Button label */\n children: React.ReactNode;\n /** Visual style variant */\n variant?: 'primary' | 'secondary' | 'ghost';\n /** Button size */\n size?: 'sm' | 'md' | 'lg';\n /** Disabled state */\n disabled?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport function Button({\n children,\n variant = 'primary',\n size = 'md',\n disabled = false,\n onClick,\n}: ButtonProps) {\n const baseStyles = 'inline-flex items-center justify-center font-medium rounded-md transition-colors';\n\n const variantStyles = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700',\n secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',\n ghost: 'bg-transparent text-gray-700 hover:bg-gray-100',\n };\n\n const sizeStyles = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n };\n\n return (\n <button\n className={\\`\\${baseStyles} \\${variantStyles[variant]} \\${sizeStyles[size]}\\`}\n disabled={disabled}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n`;\n}\n\n/**\n * Generate example Button fragment file\n */\nfunction generateExampleFragment(): string {\n return `import React from 'react';\nimport { defineFragment } from '@fragments-sdk/cli';\nimport { Button } from './Button';\n\nexport default defineFragment({\n component: Button,\n\n meta: {\n name: 'Button',\n description: 'Interactive button for triggering actions',\n category: 'Actions',\n status: 'stable',\n },\n\n usage: {\n when: [\n 'Triggering an action (save, submit, delete)',\n 'Form submission',\n 'Opening dialogs or menus',\n ],\n whenNot: [\n 'Simple navigation (use Link)',\n 'Toggling state (use Switch)',\n ],\n guidelines: [\n 'Use Primary for the main action in a context',\n 'Only one Primary button per section',\n ],\n },\n\n props: {\n children: {\n type: 'node',\n required: true,\n description: 'Button label content',\n },\n variant: {\n type: 'enum',\n values: ['primary', 'secondary', 'ghost'],\n default: 'primary',\n description: 'Visual style variant',\n },\n size: {\n type: 'enum',\n values: ['sm', 'md', 'lg'],\n default: 'md',\n description: 'Button size',\n },\n },\n\n variants: [\n {\n name: 'Primary',\n description: 'Default action button',\n render: () => <Button variant=\"primary\">Save Changes</Button>,\n },\n {\n name: 'Secondary',\n description: 'Less prominent action',\n render: () => <Button variant=\"secondary\">Cancel</Button>,\n },\n {\n name: 'Ghost',\n description: 'Minimal visual weight',\n render: () => <Button variant=\"ghost\">Learn More</Button>,\n },\n {\n name: 'Sizes',\n description: 'Available size options',\n render: () => (\n <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>\n <Button size=\"sm\">Small</Button>\n <Button size=\"md\">Medium</Button>\n <Button size=\"lg\">Large</Button>\n </div>\n ),\n },\n ],\n});\n`;\n}\n\n/**\n * Start the dev server\n */\nfunction startDevServer(projectRoot: string): void {\n console.log(pc.dim(\"\\nStarting development server...\\n\"));\n\n // Use process.platform to determine the correct command\n const isWindows = process.platform === \"win32\";\n const cmd = isWindows ? \"npx.cmd\" : \"npx\";\n\n const child = spawn(cmd, [BRAND.cliCommand, \"dev\"], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n\n child.on(\"error\", (err) => {\n console.error(pc.red(\"Failed to start dev server:\"), err.message);\n });\n}\n\n/**\n * Main init function - smart and interactive by default\n */\nexport async function init(options: InitOptions = {}): Promise<InitResult> {\n const projectRoot = resolve(options.projectRoot || process.cwd());\n const errors: string[] = [];\n\n console.log(pc.cyan(`\\n✨ Welcome to ${BRAND.name}!\\n`));\n\n // Step 1: Detect what exists\n const detection = await detectProject(projectRoot);\n\n // Check for existing config\n if (detection.hasConfig && !options.force) {\n console.log(pc.yellow(`⚠ Config already exists: ${BRAND.configFile}`));\n\n if (!options.yes) {\n const overwrite = await confirm({\n message: \"Do you want to reinitialize? (This will overwrite your config)\",\n default: false,\n });\n\n if (!overwrite) {\n console.log(pc.dim(`\\nKeeping existing configuration. Run \\`${BRAND.cliCommand} dev\\` to start.\\n`));\n return {\n success: true,\n scenario: \"stories\",\n storiesFound: detection.storyFiles.length,\n componentsFound: detection.componentFiles.length,\n errors: [],\n };\n }\n }\n }\n\n // Step 2: Determine scenario and show what we found\n let scenario: \"stories\" | \"components\" | \"fresh\";\n\n if (detection.storyFiles.length > 0) {\n scenario = \"stories\";\n console.log(pc.green(`✓ Found ${detection.storyFiles.length} Storybook story file(s)`));\n console.log(pc.dim(` ${detection.storyFiles.slice(0, 3).join(\"\\n \")}`));\n if (detection.storyFiles.length > 3) {\n console.log(pc.dim(` ... and ${detection.storyFiles.length - 3} more`));\n }\n console.log();\n console.log(\n pc.cyan(\"Great news! \") +\n \"Fragments can load your existing stories automatically.\"\n );\n } else if (detection.componentFiles.length > 0) {\n scenario = \"components\";\n console.log(pc.green(`✓ Found ${detection.componentFiles.length} component file(s)`));\n console.log(pc.dim(` ${detection.componentFiles.slice(0, 3).join(\"\\n \")}`));\n if (detection.componentFiles.length > 3) {\n console.log(pc.dim(` ... and ${detection.componentFiles.length - 3} more`));\n }\n console.log();\n console.log(\n pc.cyan(\"No stories found, but that's fine! \") +\n \"Fragments can auto-generate documentation from your TypeScript.\"\n );\n } else {\n scenario = \"fresh\";\n console.log(pc.yellow(\"No components or stories found.\"));\n console.log();\n console.log(pc.cyan(\"Let's create your first fragment!\"));\n }\n\n console.log();\n\n // Step 3: Gather configuration (interactive unless --yes)\n let componentPath = detection.suggestedComponentPath;\n let runScan = scenario === \"components\";\n let createExample = scenario === \"fresh\";\n let startServer = true;\n\n if (!options.yes) {\n // Ask about component location\n componentPath = await input({\n message: \"Where are your components located?\",\n default: detection.suggestedComponentPath,\n });\n\n if (scenario === \"components\") {\n // For component-only projects, ask about scanning\n runScan = await confirm({\n message: \"Auto-generate documentation from TypeScript?\",\n default: true,\n });\n } else {\n // Fresh project - ask about example\n createExample = await confirm({\n message: \"Create an example Button component to get started?\",\n default: true,\n });\n }\n\n // Ask about starting the server\n startServer = await confirm({\n message: \"Start the viewer now?\",\n default: true,\n });\n }\n\n // Step 4: Create configuration\n console.log(pc.dim(\"\\nCreating configuration...\\n\"));\n\n // Build include patterns\n // Note: Stories are loaded separately by the viewer, not via include patterns\n const includePaths: string[] = [\n `${componentPath}/**/*.fragment.tsx`,\n `${componentPath}/**/*.segment.tsx`, // Legacy support\n ];\n\n // Create config file\n const configPath = join(projectRoot, BRAND.configFile);\n const configContent = generateConfig({\n includePaths,\n componentPaths: [`${componentPath}/**/*.tsx`],\n framework: \"react\",\n });\n\n try {\n await writeFile(configPath, configContent, \"utf-8\");\n console.log(pc.green(`✓ Created ${BRAND.configFile}`));\n } catch (e) {\n errors.push(`Failed to create config: ${e}`);\n }\n\n // Step 5: Handle scenario-specific setup\n if (scenario === \"fresh\" && createExample) {\n // Create example component\n const exampleDir = join(projectRoot, componentPath, \"Button\");\n\n try {\n await mkdir(exampleDir, { recursive: true });\n\n // Write Button.tsx\n await writeFile(\n join(exampleDir, \"Button.tsx\"),\n generateExampleComponent(),\n \"utf-8\"\n );\n console.log(\n pc.green(`✓ Created ${relative(projectRoot, join(exampleDir, \"Button.tsx\"))}`)\n );\n\n // Write Button.fragment.tsx\n await writeFile(\n join(exampleDir, \"Button.fragment.tsx\"),\n generateExampleFragment(),\n \"utf-8\"\n );\n console.log(\n pc.green(\n `✓ Created ${relative(projectRoot, join(exampleDir, \"Button.fragment.tsx\"))}`\n )\n );\n } catch (e) {\n errors.push(`Failed to create example component: ${e}`);\n }\n }\n\n if (scenario === \"components\" && runScan) {\n // Run scan to generate fragments.json\n console.log(pc.dim(\"\\nGenerating documentation from source code...\\n\"));\n try {\n const { scan } = await import(\"./scan.js\");\n await scan({\n config: configPath,\n verbose: false,\n });\n } catch (e) {\n console.log(\n pc.yellow(`Note: Auto-documentation will run when you start the dev server.`)\n );\n }\n }\n\n // Step 6: Show next steps or start server\n if (errors.length === 0) {\n console.log(pc.green(\"\\n✓ Setup complete!\\n\"));\n\n if (startServer) {\n const serverMessage =\n scenario === \"stories\"\n ? `Your ${detection.storyFiles.length} stories are loading...`\n : scenario === \"components\"\n ? `Your ${detection.componentFiles.length} components are being documented...`\n : `Your first component is ready!`;\n\n console.log(pc.cyan(serverMessage));\n startDevServer(projectRoot);\n } else {\n console.log(pc.cyan(\"Next steps:\"));\n console.log(` 1. Run ${pc.bold(`${BRAND.cliCommand} dev`)} to start the viewer`);\n if (scenario === \"fresh\") {\n console.log(` 2. Edit ${pc.bold(`${componentPath}/Button/Button.fragment.tsx`)}`);\n }\n console.log();\n }\n }\n\n return {\n success: errors.length === 0,\n configPath: errors.length === 0 ? configPath : undefined,\n scenario,\n storiesFound: detection.storyFiles.length,\n componentsFound: detection.componentFiles.length,\n errors,\n };\n}\n"],"mappings":"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","names":[]}
package/dist/mcp-bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'module'; const require = createRequire(import.meta.url);
3
3
  import {
4
4
  generateContext
5
- } from "./chunk-B2TQKOLW.js";
5
+ } from "./chunk-V7YLRR4C.js";
6
6
  import {
7
7
  BRAND,
8
8
  DEFAULTS
@@ -57,7 +57,7 @@ var _service = null;
57
57
  async function getService() {
58
58
  if (!_service) {
59
59
  try {
60
- _service = await import("./service-2T26CBWE.js");
60
+ _service = await import("./service-RWUMZ3EW.js");
61
61
  } catch {
62
62
  throw new Error(
63
63
  "Visual tools require playwright. Install it with: npm install playwright"
@@ -152,6 +152,28 @@ function getWorkspaceDirs(rootDir) {
152
152
  }
153
153
  return dirs;
154
154
  }
155
+ function resolveDepPackageJson(localRequire, depName) {
156
+ try {
157
+ return localRequire.resolve(`${depName}/package.json`);
158
+ } catch {
159
+ }
160
+ try {
161
+ const mainPath = localRequire.resolve(depName);
162
+ let dir = dirname(mainPath);
163
+ while (true) {
164
+ const candidate = join(dir, "package.json");
165
+ if (existsSync(candidate)) {
166
+ const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
167
+ if (pkg.name === depName) return candidate;
168
+ }
169
+ const parent = dirname(dir);
170
+ if (parent === dir) break;
171
+ dir = parent;
172
+ }
173
+ } catch {
174
+ }
175
+ return null;
176
+ }
155
177
  function findFragmentsInDeps(dir, found) {
156
178
  const pkgJsonPath = join(dir, "package.json");
157
179
  if (!existsSync(pkgJsonPath)) return;
@@ -164,7 +186,8 @@ function findFragmentsInDeps(dir, found) {
164
186
  const localRequire = createRequire(join(dir, "noop.js"));
165
187
  for (const depName of Object.keys(allDeps)) {
166
188
  try {
167
- const depPkgPath = localRequire.resolve(`${depName}/package.json`);
189
+ const depPkgPath = resolveDepPackageJson(localRequire, depName);
190
+ if (!depPkgPath) continue;
168
191
  const depPkg = JSON.parse(readFileSync(depPkgPath, "utf-8"));
169
192
  if (depPkg.fragments) {
170
193
  const fragmentsPath = join(dirname(depPkgPath), depPkg.fragments);