@tpitre/story-ui 2.1.5 → 2.3.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 (203) hide show
  1. package/.env.sample +82 -11
  2. package/README.md +130 -4
  3. package/dist/cli/deploy.d.ts +17 -0
  4. package/dist/cli/deploy.d.ts.map +1 -0
  5. package/dist/cli/deploy.js +696 -0
  6. package/dist/cli/index.d.ts +3 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +55 -2
  9. package/dist/cli/setup.d.ts +11 -0
  10. package/dist/cli/setup.d.ts.map +1 -0
  11. package/dist/cli/setup.js +437 -110
  12. package/dist/mcp-server/index.d.ts +2 -0
  13. package/dist/mcp-server/index.d.ts.map +1 -0
  14. package/dist/mcp-server/index.js +138 -6
  15. package/dist/mcp-server/mcp-stdio-server.d.ts +3 -0
  16. package/dist/mcp-server/mcp-stdio-server.d.ts.map +1 -0
  17. package/dist/mcp-server/mcp-stdio-server.js +638 -0
  18. package/dist/mcp-server/routes/claude.d.ts +3 -0
  19. package/dist/mcp-server/routes/claude.d.ts.map +1 -0
  20. package/dist/mcp-server/routes/claude.js +60 -23
  21. package/dist/mcp-server/routes/components.d.ts +4 -0
  22. package/dist/mcp-server/routes/components.d.ts.map +1 -0
  23. package/dist/mcp-server/routes/frameworks.d.ts +38 -0
  24. package/dist/mcp-server/routes/frameworks.d.ts.map +1 -0
  25. package/dist/mcp-server/routes/frameworks.js +183 -0
  26. package/dist/mcp-server/routes/generateStory.d.ts +3 -0
  27. package/dist/mcp-server/routes/generateStory.d.ts.map +1 -0
  28. package/dist/mcp-server/routes/generateStory.js +274 -115
  29. package/dist/mcp-server/routes/generateStoryStream.d.ts +12 -0
  30. package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -0
  31. package/dist/mcp-server/routes/generateStoryStream.js +947 -0
  32. package/dist/mcp-server/routes/hybridStories.d.ts +18 -0
  33. package/dist/mcp-server/routes/hybridStories.d.ts.map +1 -0
  34. package/dist/mcp-server/routes/hybridStories.js +214 -0
  35. package/dist/mcp-server/routes/mcpRemote.d.ts +14 -0
  36. package/dist/mcp-server/routes/mcpRemote.d.ts.map +1 -0
  37. package/dist/mcp-server/routes/mcpRemote.js +489 -0
  38. package/dist/mcp-server/routes/memoryStories.d.ts +26 -0
  39. package/dist/mcp-server/routes/memoryStories.d.ts.map +1 -0
  40. package/dist/mcp-server/routes/memoryStories.js +13 -7
  41. package/dist/mcp-server/routes/providers.d.ts +89 -0
  42. package/dist/mcp-server/routes/providers.d.ts.map +1 -0
  43. package/dist/mcp-server/routes/providers.js +369 -0
  44. package/dist/mcp-server/routes/storySync.d.ts +26 -0
  45. package/dist/mcp-server/routes/storySync.d.ts.map +1 -0
  46. package/dist/mcp-server/routes/streamTypes.d.ts +110 -0
  47. package/dist/mcp-server/routes/streamTypes.d.ts.map +1 -0
  48. package/dist/mcp-server/routes/streamTypes.js +18 -0
  49. package/dist/mcp-server/sessionManager.d.ts +50 -0
  50. package/dist/mcp-server/sessionManager.d.ts.map +1 -0
  51. package/dist/mcp-server/sessionManager.js +125 -0
  52. package/dist/story-generator/componentBlacklist.d.ts +21 -0
  53. package/dist/story-generator/componentBlacklist.d.ts.map +1 -0
  54. package/dist/story-generator/componentBlacklist.js +4 -0
  55. package/dist/story-generator/componentDiscovery.d.ts +28 -0
  56. package/dist/story-generator/componentDiscovery.d.ts.map +1 -0
  57. package/dist/story-generator/componentRegistryGenerator.d.ts +49 -0
  58. package/dist/story-generator/componentRegistryGenerator.d.ts.map +1 -0
  59. package/dist/story-generator/componentRegistryGenerator.js +205 -0
  60. package/dist/story-generator/configLoader.d.ts +33 -0
  61. package/dist/story-generator/configLoader.d.ts.map +1 -0
  62. package/dist/story-generator/configLoader.js +8 -1
  63. package/dist/story-generator/considerationsLoader.d.ts +32 -0
  64. package/dist/story-generator/considerationsLoader.d.ts.map +1 -0
  65. package/dist/story-generator/considerationsLoader.js +2 -1
  66. package/dist/story-generator/documentation-sources.d.ts +28 -0
  67. package/dist/story-generator/documentation-sources.d.ts.map +1 -0
  68. package/dist/story-generator/documentationLoader.d.ts +64 -0
  69. package/dist/story-generator/documentationLoader.d.ts.map +1 -0
  70. package/dist/story-generator/documentationLoader.js +4 -3
  71. package/dist/story-generator/dynamicPackageDiscovery.d.ts +97 -0
  72. package/dist/story-generator/dynamicPackageDiscovery.d.ts.map +1 -0
  73. package/dist/story-generator/dynamicPackageDiscovery.js +31 -22
  74. package/dist/story-generator/enhancedComponentDiscovery.d.ts +125 -0
  75. package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -0
  76. package/dist/story-generator/enhancedComponentDiscovery.js +162 -21
  77. package/dist/story-generator/framework-adapters/angular-adapter.d.ts +40 -0
  78. package/dist/story-generator/framework-adapters/angular-adapter.d.ts.map +1 -0
  79. package/dist/story-generator/framework-adapters/angular-adapter.js +427 -0
  80. package/dist/story-generator/framework-adapters/base-adapter.d.ts +75 -0
  81. package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -0
  82. package/dist/story-generator/framework-adapters/base-adapter.js +147 -0
  83. package/dist/story-generator/framework-adapters/framework-detector.d.ts +55 -0
  84. package/dist/story-generator/framework-adapters/framework-detector.d.ts.map +1 -0
  85. package/dist/story-generator/framework-adapters/framework-detector.js +323 -0
  86. package/dist/story-generator/framework-adapters/index.d.ts +97 -0
  87. package/dist/story-generator/framework-adapters/index.d.ts.map +1 -0
  88. package/dist/story-generator/framework-adapters/index.js +198 -0
  89. package/dist/story-generator/framework-adapters/react-adapter.d.ts +40 -0
  90. package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -0
  91. package/dist/story-generator/framework-adapters/react-adapter.js +316 -0
  92. package/dist/story-generator/framework-adapters/svelte-adapter.d.ts +40 -0
  93. package/dist/story-generator/framework-adapters/svelte-adapter.d.ts.map +1 -0
  94. package/dist/story-generator/framework-adapters/svelte-adapter.js +372 -0
  95. package/dist/story-generator/framework-adapters/types.d.ts +182 -0
  96. package/dist/story-generator/framework-adapters/types.d.ts.map +1 -0
  97. package/dist/story-generator/framework-adapters/types.js +8 -0
  98. package/dist/story-generator/framework-adapters/vue-adapter.d.ts +36 -0
  99. package/dist/story-generator/framework-adapters/vue-adapter.d.ts.map +1 -0
  100. package/dist/story-generator/framework-adapters/vue-adapter.js +336 -0
  101. package/dist/story-generator/framework-adapters/web-components-adapter.d.ts +54 -0
  102. package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -0
  103. package/dist/story-generator/framework-adapters/web-components-adapter.js +387 -0
  104. package/dist/story-generator/generateStory.d.ts +7 -0
  105. package/dist/story-generator/generateStory.d.ts.map +1 -0
  106. package/dist/story-generator/gitignoreManager.d.ts +50 -0
  107. package/dist/story-generator/gitignoreManager.d.ts.map +1 -0
  108. package/dist/story-generator/gitignoreManager.js +7 -6
  109. package/dist/story-generator/imageProcessor.d.ts +80 -0
  110. package/dist/story-generator/imageProcessor.d.ts.map +1 -0
  111. package/dist/story-generator/imageProcessor.js +391 -0
  112. package/dist/story-generator/inMemoryStoryService.d.ts +89 -0
  113. package/dist/story-generator/inMemoryStoryService.d.ts.map +1 -0
  114. package/dist/story-generator/llm-providers/base-provider.d.ts +36 -0
  115. package/dist/story-generator/llm-providers/base-provider.d.ts.map +1 -0
  116. package/dist/story-generator/llm-providers/base-provider.js +135 -0
  117. package/dist/story-generator/llm-providers/claude-provider.d.ts +23 -0
  118. package/dist/story-generator/llm-providers/claude-provider.d.ts.map +1 -0
  119. package/dist/story-generator/llm-providers/claude-provider.js +414 -0
  120. package/dist/story-generator/llm-providers/gemini-provider.d.ts +24 -0
  121. package/dist/story-generator/llm-providers/gemini-provider.d.ts.map +1 -0
  122. package/dist/story-generator/llm-providers/gemini-provider.js +406 -0
  123. package/dist/story-generator/llm-providers/index.d.ts +63 -0
  124. package/dist/story-generator/llm-providers/index.d.ts.map +1 -0
  125. package/dist/story-generator/llm-providers/index.js +169 -0
  126. package/dist/story-generator/llm-providers/openai-provider.d.ts +24 -0
  127. package/dist/story-generator/llm-providers/openai-provider.d.ts.map +1 -0
  128. package/dist/story-generator/llm-providers/openai-provider.js +458 -0
  129. package/dist/story-generator/llm-providers/settings-manager.d.ts +75 -0
  130. package/dist/story-generator/llm-providers/settings-manager.d.ts.map +1 -0
  131. package/dist/story-generator/llm-providers/settings-manager.js +173 -0
  132. package/dist/story-generator/llm-providers/story-llm-service.d.ts +79 -0
  133. package/dist/story-generator/llm-providers/story-llm-service.d.ts.map +1 -0
  134. package/dist/story-generator/llm-providers/story-llm-service.js +240 -0
  135. package/dist/story-generator/llm-providers/types.d.ts +153 -0
  136. package/dist/story-generator/llm-providers/types.d.ts.map +1 -0
  137. package/dist/story-generator/llm-providers/types.js +8 -0
  138. package/dist/story-generator/logger.d.ts +14 -0
  139. package/dist/story-generator/logger.d.ts.map +1 -0
  140. package/dist/story-generator/logger.js +119 -0
  141. package/dist/story-generator/postProcessStory.d.ts +6 -0
  142. package/dist/story-generator/postProcessStory.d.ts.map +1 -0
  143. package/dist/story-generator/postProcessStory.js +8 -7
  144. package/dist/story-generator/productionGitignoreManager.d.ts +91 -0
  145. package/dist/story-generator/productionGitignoreManager.d.ts.map +1 -0
  146. package/dist/story-generator/productionGitignoreManager.js +11 -10
  147. package/dist/story-generator/promptGenerator.d.ts +48 -0
  148. package/dist/story-generator/promptGenerator.d.ts.map +1 -0
  149. package/dist/story-generator/promptGenerator.js +186 -1
  150. package/dist/story-generator/storyHistory.d.ts +44 -0
  151. package/dist/story-generator/storyHistory.d.ts.map +1 -0
  152. package/dist/story-generator/storySync.d.ts +68 -0
  153. package/dist/story-generator/storySync.d.ts.map +1 -0
  154. package/dist/story-generator/storyTracker.d.ts +48 -0
  155. package/dist/story-generator/storyTracker.d.ts.map +1 -0
  156. package/dist/story-generator/storyTracker.js +2 -1
  157. package/dist/story-generator/storyValidator.d.ts +6 -0
  158. package/dist/story-generator/storyValidator.d.ts.map +1 -0
  159. package/dist/story-generator/universalDesignSystemAdapter.d.ts +68 -0
  160. package/dist/story-generator/universalDesignSystemAdapter.d.ts.map +1 -0
  161. package/dist/story-generator/universalDesignSystemAdapter.js +141 -3
  162. package/dist/story-generator/urlRedirectService.d.ts +21 -0
  163. package/dist/story-generator/urlRedirectService.d.ts.map +1 -0
  164. package/dist/story-generator/urlRedirectService.js +140 -0
  165. package/dist/story-generator/validateStory.d.ts +19 -0
  166. package/dist/story-generator/validateStory.d.ts.map +1 -0
  167. package/dist/story-generator/validateStory.js +6 -2
  168. package/dist/story-generator/visionPrompts.d.ts +88 -0
  169. package/dist/story-generator/visionPrompts.d.ts.map +1 -0
  170. package/dist/story-generator/visionPrompts.js +462 -0
  171. package/dist/story-ui.config.d.ts +78 -0
  172. package/dist/story-ui.config.d.ts.map +1 -0
  173. package/dist/templates/StoryUI/StoryUIPanel.d.ts +4 -0
  174. package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -0
  175. package/dist/templates/StoryUI/StoryUIPanel.js +1874 -0
  176. package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts +18 -0
  177. package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts.map +1 -0
  178. package/dist/templates/StoryUI/StoryUIPanel.stories.js +37 -0
  179. package/dist/templates/StoryUI/index.d.ts +3 -0
  180. package/dist/templates/StoryUI/index.d.ts.map +1 -0
  181. package/dist/templates/StoryUI/index.js +2 -0
  182. package/package.json +35 -4
  183. package/templates/StoryUI/StoryUIPanel.tsx +1973 -388
  184. package/templates/StoryUI/index.tsx +1 -1
  185. package/templates/StoryUI/manager.tsx +264 -0
  186. package/templates/mcp-config-claude.json +11 -0
  187. package/templates/mcp-example.md +76 -0
  188. package/templates/production-app/.env.example +11 -0
  189. package/templates/production-app/index.html +66 -0
  190. package/templates/production-app/package.json +30 -0
  191. package/templates/production-app/public/favicon.svg +5 -0
  192. package/templates/production-app/src/App.tsx +1157 -0
  193. package/templates/production-app/src/LivePreviewRenderer.tsx +420 -0
  194. package/templates/production-app/src/componentRegistry.ts +315 -0
  195. package/templates/production-app/src/considerations.ts +16 -0
  196. package/templates/production-app/src/index.css +284 -0
  197. package/templates/production-app/src/main.tsx +25 -0
  198. package/templates/production-app/tsconfig.json +32 -0
  199. package/templates/production-app/tsconfig.node.json +11 -0
  200. package/templates/production-app/vite.config.ts +83 -0
  201. package/templates/react-import-rule.json +2 -2
  202. package/dist/index.js +0 -12
  203. package/dist/story-ui.config.loader.js +0 -205
@@ -0,0 +1,119 @@
1
+ // Enhanced logging utility with configurable levels and MCP-safe output
2
+ const LOG_LEVELS = {
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3,
7
+ none: 4,
8
+ };
9
+ // Get log level from environment or default to 'info'
10
+ const getConfiguredLevel = () => {
11
+ const envLevel = process.env.STORY_UI_LOG_LEVEL?.toLowerCase();
12
+ return LOG_LEVELS[envLevel] !== undefined ? envLevel : 'info';
13
+ };
14
+ const isMcpMode = () => {
15
+ return process.argv.includes('mcp') || process.env.STORY_UI_MCP_MODE === 'true';
16
+ };
17
+ // Remove emojis from strings to prevent JSON parsing errors in MCP
18
+ const stripEmojis = (str) => {
19
+ return str.replace(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F000}-\u{1F02F}]|[\u{1F0A0}-\u{1F0FF}]|[\u{1F100}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F900}-\u{1F9FF}]|[\u{2190}-\u{21FF}]|[\u{2300}-\u{23FF}]|[\u{25A0}-\u{25FF}]|[\u{2B00}-\u{2BFF}]|[\u{3000}-\u{303F}]|✅|❌|⚠️|🔍|📦|📋|🔄|📊|⭐|🚀|💡|🎯|🔧|📌|🏃|🎨|💪|🌟|🎉|🎊|👍|👎|📝|📄|🗑️|🗂️|📁|🖥️|💻|📱|🌐|🔒|🔓|🔑|🔨|⚡|🔥|💧|🌈|☀️|🌙|⭐|✨|💫|☁️|🌧️|⛈️|❄️|☃️|⛄|🌬️|💨|🌪️|🌫️|🌊|🎯/gu, '');
20
+ };
21
+ const formatTimestamp = () => {
22
+ const now = new Date();
23
+ return now.toISOString().replace('T', ' ').slice(0, 19);
24
+ };
25
+ const formatMessage = (level, args) => {
26
+ const timestamp = formatTimestamp();
27
+ const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
28
+ const processedArgs = args.map(arg => {
29
+ if (typeof arg === 'string') {
30
+ return isMcpMode() ? stripEmojis(arg) : arg;
31
+ }
32
+ if (typeof arg === 'object') {
33
+ try {
34
+ return JSON.stringify(arg, null, 2);
35
+ }
36
+ catch {
37
+ return String(arg);
38
+ }
39
+ }
40
+ return String(arg);
41
+ });
42
+ return [prefix, ...processedArgs];
43
+ };
44
+ const shouldLog = (level) => {
45
+ const configuredLevel = getConfiguredLevel();
46
+ return LOG_LEVELS[level] >= LOG_LEVELS[configuredLevel];
47
+ };
48
+ class Logger {
49
+ static getInstance() {
50
+ if (!Logger.instance) {
51
+ Logger.instance = new Logger();
52
+ }
53
+ return Logger.instance;
54
+ }
55
+ debug(...args) {
56
+ if (!shouldLog('debug'))
57
+ return;
58
+ const formattedArgs = formatMessage('debug', args);
59
+ if (isMcpMode()) {
60
+ console.error(...formattedArgs);
61
+ }
62
+ else {
63
+ console.debug(...formattedArgs);
64
+ }
65
+ }
66
+ log(...args) {
67
+ // Alias for info for backwards compatibility
68
+ this.info(...args);
69
+ }
70
+ info(...args) {
71
+ if (!shouldLog('info'))
72
+ return;
73
+ const formattedArgs = formatMessage('info', args);
74
+ if (isMcpMode()) {
75
+ console.error(...formattedArgs);
76
+ }
77
+ else {
78
+ console.log(...formattedArgs);
79
+ }
80
+ }
81
+ warn(...args) {
82
+ if (!shouldLog('warn'))
83
+ return;
84
+ const formattedArgs = formatMessage('warn', args);
85
+ if (isMcpMode()) {
86
+ console.error(...formattedArgs);
87
+ }
88
+ else {
89
+ console.warn(...formattedArgs);
90
+ }
91
+ }
92
+ error(...args) {
93
+ if (!shouldLog('error'))
94
+ return;
95
+ const formattedArgs = formatMessage('error', args);
96
+ console.error(...formattedArgs);
97
+ }
98
+ // Utility method for structured logging
99
+ structured(level, message, data) {
100
+ if (!shouldLog(level))
101
+ return;
102
+ const logEntry = {
103
+ timestamp: formatTimestamp(),
104
+ level,
105
+ message,
106
+ ...(data && { data }),
107
+ };
108
+ if (isMcpMode()) {
109
+ console.error(JSON.stringify(logEntry));
110
+ }
111
+ else {
112
+ console.log(JSON.stringify(logEntry, null, 2));
113
+ }
114
+ }
115
+ }
116
+ // Export singleton instance
117
+ export const logger = Logger.getInstance();
118
+ // Export for backwards compatibility with code that imports the object directly
119
+ export default logger;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Post-process generated stories to fix common issues
3
+ * This module is completely design-system agnostic
4
+ */
5
+ export declare function postProcessStory(code: string, libraryPath: string): string;
6
+ //# sourceMappingURL=postProcessStory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postProcessStory.d.ts","sourceRoot":"","sources":["../../story-generator/postProcessStory.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAkB1E"}
@@ -1,19 +1,20 @@
1
+ import { logger } from './logger.js';
1
2
  /**
2
3
  * Post-process generated stories to fix common issues
3
4
  * This module is completely design-system agnostic
4
5
  */
5
6
  export function postProcessStory(code, libraryPath) {
6
- console.log(`🔧 Post-processing story for library: ${libraryPath}`);
7
+ logger.log(`🔧 Post-processing story for library: ${libraryPath}`);
7
8
  let processedCode = code;
8
9
  // Fix ANY component with children prop - ALWAYS convert to render function
9
10
  if (processedCode.includes('children: (')) {
10
- console.log('🚨 Detected children prop in args - converting to render function');
11
+ logger.log('🚨 Detected children prop in args - converting to render function');
11
12
  processedCode = convertLayoutToRenderFunction(processedCode);
12
13
  }
13
14
  // Leave inline styles as-is - let the AI use the available components naturally
14
15
  // Post-processing should be design-system agnostic
15
16
  if (processedCode.includes('style={{')) {
16
- console.log('ℹ️ Inline styles detected - keeping as-is for design system agnosticism');
17
+ logger.log('ℹ️ Inline styles detected - keeping as-is for design system agnosticism');
17
18
  }
18
19
  return processedCode;
19
20
  }
@@ -36,7 +37,7 @@ function convertLayoutToRenderFunction(code) {
36
37
  // Also fix the satisfies Meta type
37
38
  const metaWithType = `const meta = {${newMetaContent}} satisfies Meta;`;
38
39
  processedCode = code.replace(/const meta = {[^}]+} satisfies Meta(?:<[^>]+>)?;/s, metaWithType);
39
- console.log('✅ Removed component from meta object');
40
+ logger.log('✅ Removed component from meta object');
40
41
  }
41
42
  }
42
43
  // Extract all stories with children prop
@@ -49,7 +50,7 @@ function convertLayoutToRenderFunction(code) {
49
50
  const newStory = `export const ${storyName}: Story = {\n render: () => (\n${childrenContent}\n )\n};`;
50
51
  // Replace the old story with the new one
51
52
  processedCode = processedCode.replace(match[0], newStory);
52
- console.log(`✅ Converted ${storyName} from children prop to render function`);
53
+ logger.log(`✅ Converted ${storyName} from children prop to render function`);
53
54
  }
54
55
  return processedCode;
55
56
  }
@@ -58,7 +59,7 @@ function convertLayoutToRenderFunction(code) {
58
59
  */
59
60
  function convertAlertChildrenToExports(code) {
60
61
  // For now, return the code as-is
61
- console.log('Alert conversion not yet implemented');
62
+ logger.log('Alert conversion not yet implemented');
62
63
  return code;
63
64
  }
64
65
  /**
@@ -66,6 +67,6 @@ function convertAlertChildrenToExports(code) {
66
67
  */
67
68
  function convertToastChildrenToExports(code) {
68
69
  // For now, return the code as-is
69
- console.log('Toast conversion not yet implemented');
70
+ logger.log('Toast conversion not yet implemented');
70
71
  return code;
71
72
  }
@@ -0,0 +1,91 @@
1
+ import { StoryUIConfig } from '../story-ui.config.js';
2
+ /**
3
+ * Production-ready gitignore manager that handles both development and server environments
4
+ */
5
+ export declare class ProductionGitignoreManager {
6
+ private config;
7
+ private projectRoot;
8
+ private isProduction;
9
+ constructor(config: StoryUIConfig, projectRoot?: string);
10
+ /**
11
+ * Detects if we're running in a production/read-only environment
12
+ */
13
+ private detectProductionEnvironment;
14
+ /**
15
+ * Tests if we can write to the project root
16
+ */
17
+ private canWriteToProjectRoot;
18
+ /**
19
+ * Main setup method that adapts to environment
20
+ */
21
+ setupGitignoreIntegration(): void;
22
+ /**
23
+ * Production environment: Use in-memory story generation
24
+ */
25
+ private handleProductionEnvironment;
26
+ /**
27
+ * Development environment: Full gitignore management
28
+ */
29
+ private handleDevelopmentEnvironment;
30
+ /**
31
+ * Validates that production environment is properly configured
32
+ */
33
+ private validateProductionSetup;
34
+ /**
35
+ * Sets up temporary directory for production story generation
36
+ */
37
+ private setupTemporaryDirectory;
38
+ /**
39
+ * Gets a writable temporary directory for production
40
+ */
41
+ getProductionTempDirectory(): string;
42
+ /**
43
+ * Creates the generated directory if it doesn't exist (development only)
44
+ */
45
+ private ensureGeneratedDirectoryExists;
46
+ /**
47
+ * Ensures the generated stories directory is added to .gitignore (development only)
48
+ */
49
+ private ensureGeneratedDirectoryIgnored;
50
+ /**
51
+ * Gets the relative path from project root to generated stories directory
52
+ */
53
+ private getRelativeGeneratedPath;
54
+ /**
55
+ * Creates a new .gitignore file with Story UI section
56
+ */
57
+ private createGitignore;
58
+ /**
59
+ * Checks if the generated path is already ignored
60
+ */
61
+ private isPathIgnored;
62
+ /**
63
+ * Adds ignore rule to existing .gitignore
64
+ */
65
+ private addIgnoreRule;
66
+ /**
67
+ * Generates the gitignore section for Story UI
68
+ */
69
+ private generateGitignoreSection;
70
+ /**
71
+ * Creates a README in the generated directory explaining its purpose (development only)
72
+ */
73
+ private createGeneratedDirectoryReadme;
74
+ /**
75
+ * Cleans up old generated stories (safe for both environments)
76
+ */
77
+ cleanupOldStories(maxAge?: number): void;
78
+ /**
79
+ * Gets the appropriate directory for story generation based on environment
80
+ */
81
+ getStoryGenerationPath(): string;
82
+ /**
83
+ * Checks if we're in production mode
84
+ */
85
+ isProductionMode(): boolean;
86
+ }
87
+ /**
88
+ * Convenience function to set up gitignore for Story UI (production-ready)
89
+ */
90
+ export declare function setupProductionGitignore(config: StoryUIConfig, projectRoot?: string): ProductionGitignoreManager;
91
+ //# sourceMappingURL=productionGitignoreManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"productionGitignoreManager.d.ts","sourceRoot":"","sources":["../../story-generator/productionGitignoreManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;GAEG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAU;gBAElB,MAAM,EAAE,aAAa,EAAE,WAAW,GAAE,MAAsB;IAMtE;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAgBnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAW7B;;OAEG;IACH,yBAAyB,IAAI,IAAI;IAQjC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAUnC;;OAEG;IACH,OAAO,CAAC,4BAA4B;IAQpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAY/B;;OAEG;IACH,0BAA0B,IAAI,MAAM;IAuBpC;;OAEG;IACH,OAAO,CAAC,8BAA8B;IAStC;;OAEG;IACH,OAAO,CAAC,+BAA+B;IA0BvC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAmBhC;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAOhC;;OAEG;IACH,OAAO,CAAC,8BAA8B;IAyCtC;;OAEG;IACH,iBAAiB,CAAC,MAAM,GAAE,MAAgC,GAAG,IAAI;IAoCjE;;OAEG;IACH,sBAAsB,IAAI,MAAM;IAYhC;;OAEG;IACH,gBAAgB,IAAI,OAAO;CAG5B;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,0BAA0B,CAIhH"}
@@ -1,5 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { logger } from './logger.js';
3
4
  /**
4
5
  * Production-ready gitignore manager that handles both development and server environments
5
6
  */
@@ -55,7 +56,7 @@ export class ProductionGitignoreManager {
55
56
  * Production environment: Use in-memory story generation
56
57
  */
57
58
  handleProductionEnvironment() {
58
- console.log('🌐 Production environment detected - using in-memory story generation');
59
+ logger.log('🌐 Production environment detected - using in-memory story generation');
59
60
  // Validate that gitignore is already set up
60
61
  this.validateProductionSetup();
61
62
  // Set up temporary directory for story generation if needed
@@ -65,7 +66,7 @@ export class ProductionGitignoreManager {
65
66
  * Development environment: Full gitignore management
66
67
  */
67
68
  handleDevelopmentEnvironment() {
68
- console.log('🔧 Development environment - setting up gitignore integration');
69
+ logger.log('🔧 Development environment - setting up gitignore integration');
69
70
  this.ensureGeneratedDirectoryExists();
70
71
  this.ensureGeneratedDirectoryIgnored();
71
72
  this.createGeneratedDirectoryReadme();
@@ -86,7 +87,7 @@ export class ProductionGitignoreManager {
86
87
  console.warn(' Run "npx story-ui setup-gitignore" in development to fix this.');
87
88
  }
88
89
  else {
89
- console.log('✅ Production gitignore configuration validated');
90
+ logger.log('✅ Production gitignore configuration validated');
90
91
  }
91
92
  }
92
93
  /**
@@ -97,7 +98,7 @@ export class ProductionGitignoreManager {
97
98
  const tempDir = this.getProductionTempDirectory();
98
99
  if (!fs.existsSync(tempDir)) {
99
100
  fs.mkdirSync(tempDir, { recursive: true });
100
- console.log(`✅ Created temporary directory: ${tempDir}`);
101
+ logger.log(`✅ Created temporary directory: ${tempDir}`);
101
102
  }
102
103
  }
103
104
  catch (error) {
@@ -135,7 +136,7 @@ export class ProductionGitignoreManager {
135
136
  const generatedDir = this.config.generatedStoriesPath;
136
137
  if (!fs.existsSync(generatedDir)) {
137
138
  fs.mkdirSync(generatedDir, { recursive: true });
138
- console.log(`✅ Created generated stories directory: ${generatedDir}`);
139
+ logger.log(`✅ Created generated stories directory: ${generatedDir}`);
139
140
  }
140
141
  }
141
142
  /**
@@ -156,7 +157,7 @@ export class ProductionGitignoreManager {
156
157
  // Check if the path is already ignored
157
158
  const gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');
158
159
  if (this.isPathIgnored(gitignoreContent, generatedPath)) {
159
- console.log(`✅ Generated stories directory already ignored: ${generatedPath}`);
160
+ logger.log(`✅ Generated stories directory already ignored: ${generatedPath}`);
160
161
  return;
161
162
  }
162
163
  // Add the ignore rule
@@ -187,7 +188,7 @@ export class ProductionGitignoreManager {
187
188
  createGitignore(gitignorePath, generatedPath) {
188
189
  const content = this.generateGitignoreSection(generatedPath);
189
190
  fs.writeFileSync(gitignorePath, content);
190
- console.log(`✅ Created .gitignore with Story UI generated directory: ${generatedPath}`);
191
+ logger.log(`✅ Created .gitignore with Story UI generated directory: ${generatedPath}`);
191
192
  }
192
193
  /**
193
194
  * Checks if the generated path is already ignored
@@ -214,7 +215,7 @@ export class ProductionGitignoreManager {
214
215
  const separator = existingContent.endsWith('\n') ? '\n' : '\n\n';
215
216
  const updatedContent = existingContent + separator + newSection;
216
217
  fs.writeFileSync(gitignorePath, updatedContent);
217
- console.log(`✅ Added Story UI generated directory to .gitignore: ${generatedPath}`);
218
+ logger.log(`✅ Added Story UI generated directory to .gitignore: ${generatedPath}`);
218
219
  }
219
220
  /**
220
221
  * Generates the gitignore section for Story UI
@@ -260,7 +261,7 @@ Generated by [Story UI](https://github.com/your-org/story-ui) - AI-powered Story
260
261
  `;
261
262
  try {
262
263
  fs.writeFileSync(readmePath, readmeContent);
263
- console.log(`✅ Created README in generated directory`);
264
+ logger.log(`✅ Created README in generated directory`);
264
265
  }
265
266
  catch (error) {
266
267
  console.warn('⚠️ Could not create README in generated directory');
@@ -293,7 +294,7 @@ Generated by [Story UI](https://github.com/your-org/story-ui) - AI-powered Story
293
294
  }
294
295
  }
295
296
  if (cleanedCount > 0) {
296
- console.log(`🧹 Cleaned up ${cleanedCount} old generated stories from ${dir}`);
297
+ logger.log(`🧹 Cleaned up ${cleanedCount} old generated stories from ${dir}`);
297
298
  }
298
299
  }
299
300
  catch (error) {
@@ -0,0 +1,48 @@
1
+ import { StoryUIConfig } from '../story-ui.config.js';
2
+ import { DiscoveredComponent } from './componentDiscovery.js';
3
+ import { FrameworkPrompt, StoryGenerationOptions, FrameworkType, FrameworkAdapter } from './framework-adapters/index.js';
4
+ /**
5
+ * Extended prompt interface that includes framework information
6
+ * Uses string[] for layoutInstructions instead of string
7
+ */
8
+ export interface FrameworkAwarePrompt extends Omit<FrameworkPrompt, 'layoutInstructions'> {
9
+ layoutInstructions: string[];
10
+ }
11
+ export interface GeneratedPrompt {
12
+ systemPrompt: string;
13
+ componentReference: string;
14
+ layoutInstructions: string[];
15
+ examples: string[];
16
+ sampleStory: string;
17
+ }
18
+ /**
19
+ * Generates a comprehensive AI prompt based on the configuration and discovered components
20
+ */
21
+ export declare function generatePrompt(config: StoryUIConfig, components: DiscoveredComponent[]): GeneratedPrompt;
22
+ /**
23
+ * Builds the complete Claude prompt
24
+ */
25
+ export declare function buildClaudePrompt(userPrompt: string, config: StoryUIConfig, components: DiscoveredComponent[]): Promise<string>;
26
+ /**
27
+ * Generates a framework-aware prompt using the adapter system
28
+ * This is the new multi-framework entry point
29
+ */
30
+ export declare function generateFrameworkAwarePrompt(config: StoryUIConfig, components: DiscoveredComponent[], options?: StoryGenerationOptions): Promise<FrameworkAwarePrompt>;
31
+ /**
32
+ * Builds a complete LLM prompt with framework awareness
33
+ * This is the new multi-framework entry point for building complete prompts
34
+ */
35
+ export declare function buildFrameworkAwarePrompt(userPrompt: string, config: StoryUIConfig, components: DiscoveredComponent[], options?: StoryGenerationOptions): Promise<string>;
36
+ /**
37
+ * Detect the framework for a given project
38
+ */
39
+ export declare function detectProjectFramework(projectRoot?: string): Promise<FrameworkType>;
40
+ /**
41
+ * Get the adapter for a specific framework
42
+ */
43
+ export declare function getFrameworkAdapter(framework: FrameworkType): FrameworkAdapter;
44
+ /**
45
+ * Get all available framework adapters
46
+ */
47
+ export declare function getAvailableFrameworks(): FrameworkType[];
48
+ //# sourceMappingURL=promptGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptGenerator.d.ts","sourceRoot":"","sources":["../../story-generator/promptGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAEL,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;AAEvC;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC;IACvF,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,eAAe,CAcxG;AAoaD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,OAAO,CAAC,MAAM,CAAC,CA8HjB;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAqB/B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,CA6GjB;AAwDD;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAIzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,aAAa,GAAG,gBAAgB,CAG9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,aAAa,EAAE,CAGxD"}
@@ -1,5 +1,6 @@
1
1
  import { loadConsiderations, considerationsToPrompt } from './considerationsLoader.js';
2
2
  import { DocumentationLoader } from './documentationLoader.js';
3
+ import { getAdapterRegistry, } from './framework-adapters/index.js';
3
4
  /**
4
5
  * Generates a comprehensive AI prompt based on the configuration and discovered components
5
6
  */
@@ -27,7 +28,28 @@ function generateSystemPrompt(config) {
27
28
  const componentSystemName = config.componentPrefix ?
28
29
  `${config.componentPrefix.replace(/^[A-Z]+/, '')} design system` :
29
30
  'component library';
30
- return `🚨 CRITICAL: EVERY STORY MUST START WITH "import React from 'react';" AS THE FIRST LINE 🚨
31
+ // Get the library name for prominent constraint
32
+ const libraryName = config.designSystemGuidelines?.name || config.importPath || 'configured library';
33
+ const importPath = config.importPath || 'your-library';
34
+ return `
35
+ ╔════════════════════════════════════════════════════════════════════╗
36
+ ║ 🚨 MANDATORY LIBRARY CONSTRAINT 🚨 ║
37
+ ╠════════════════════════════════════════════════════════════════════╣
38
+ ║ REQUIRED LIBRARY: ${libraryName.padEnd(46)}║
39
+ ║ IMPORT PATH: ${importPath.padEnd(46)}║
40
+ ╠════════════════════════════════════════════════════════════════════╣
41
+ ║ ALL component imports MUST use: ║
42
+ ║ import { ComponentName } from '${importPath}';${' '.repeat(Math.max(0, 32 - importPath.length))}║
43
+ ╠════════════════════════════════════════════════════════════════════╣
44
+ ║ 🚫 FORBIDDEN LIBRARIES - DO NOT USE: ║
45
+ ║ - tamagui, @tamagui/core (NEVER USE) ║
46
+ ║ - @chakra-ui/react (unless configured) ║
47
+ ║ - @mui/material (unless configured) ║
48
+ ║ - antd (unless configured) ║
49
+ ║ - Any library NOT matching: ${importPath.padEnd(36)}║
50
+ ╚════════════════════════════════════════════════════════════════════╝
51
+
52
+ 🚨 CRITICAL: EVERY STORY MUST START WITH "import React from 'react';" AS THE FIRST LINE 🚨
31
53
 
32
54
  🔴 CRITICAL RULE: NEVER use children in args for ANY component or layout. Always use render functions. 🔴
33
55
 
@@ -448,3 +470,166 @@ export async function buildClaudePrompt(userPrompt, config, components) {
448
470
  promptParts.push(`Output a complete Storybook story file in TypeScript. Import components as shown in the sample template below. Use the following sample as a template. Respond ONLY with a single code block containing the full file, and nothing else.`, '', '<rules>', '🚨 FINAL CRITICAL REMINDERS 🚨', "🔴 FIRST LINE MUST BE: import React from 'react';", '🔴 WITHOUT THIS IMPORT, THE STORY WILL BREAK!', '', 'OTHER CRITICAL RULES:', '- Story title MUST always start with "Generated/" (e.g., title: "Generated/Recipe Card")', '- Do NOT use prefixes like "Content/", "Components/", or any other section name', '- ONLY import components that are listed in the "Available components" section', '- ALWAYS use the exact import path shown in parentheses after each component', '- NEVER use main package imports when specific subpath imports are shown', '- Do NOT import story exports - these are NOT real components', '- Check every import against the Available components list before using it', '- FORBIDDEN: Any component not explicitly listed in the Available components section', '- FORBIDDEN: Theme setup components (providers should be configured at the app level, not in individual stories)', '- All images MUST have a src attribute with placeholder URLs (use https://picsum.photos/)', '- Never create <img> tags without src attributes', '- MUST use ES modules syntax: "export default meta;" NOT "module.exports = meta;"', '- The file MUST have a default export for the meta object', '- Keep the story concise and focused - avoid overly complex layouts that might exceed token limits', '- Ensure all JSX tags are properly closed', '- Story must be complete and syntactically valid', '- CRITICAL: Never put ANY content in args.children - always use render function', '- Use render functions for ALL layouts and component compositions', '- For layouts: DO NOT set component in meta', '- Only set component in meta when showcasing a SINGLE component', '- Use appropriate styling for the component library (design tokens, className, or inline styles as needed)', '</rules>', '', 'Sample story format:', generated.sampleStory, '', 'User request:', userPrompt);
449
471
  return promptParts.join('\n');
450
472
  }
473
+ /**
474
+ * Generates a framework-aware prompt using the adapter system
475
+ * This is the new multi-framework entry point
476
+ */
477
+ export async function generateFrameworkAwarePrompt(config, components, options) {
478
+ const registry = getAdapterRegistry();
479
+ // Get the appropriate adapter (auto-detect or use specified framework)
480
+ let adapter;
481
+ if (options?.framework) {
482
+ adapter = registry.getAdapter(options.framework);
483
+ }
484
+ else {
485
+ adapter = await registry.autoDetect(process.cwd());
486
+ }
487
+ // Generate framework-specific prompt components
488
+ const frameworkPrompt = await registry.generatePrompt(config, components, options);
489
+ // Generate layout instructions (framework-agnostic)
490
+ const layoutInstructions = generateLayoutInstructions(config);
491
+ return {
492
+ ...frameworkPrompt,
493
+ layoutInstructions,
494
+ };
495
+ }
496
+ /**
497
+ * Builds a complete LLM prompt with framework awareness
498
+ * This is the new multi-framework entry point for building complete prompts
499
+ */
500
+ export async function buildFrameworkAwarePrompt(userPrompt, config, components, options) {
501
+ const generated = await generateFrameworkAwarePrompt(config, components, options);
502
+ const promptParts = [
503
+ generated.systemPrompt,
504
+ '',
505
+ ];
506
+ // Load documentation - try new directory-based approach first
507
+ const projectRoot = config.considerationsPath ?
508
+ config.considerationsPath.replace(/\/story-ui-considerations\.(md|json)$/, '') :
509
+ process.cwd();
510
+ const docLoader = new DocumentationLoader(projectRoot);
511
+ let documentationAdded = false;
512
+ if (docLoader.hasDocumentation()) {
513
+ const docs = await docLoader.loadDocumentation();
514
+ if (docs.sources.length > 0) {
515
+ const docPrompt = docLoader.formatForPrompt(docs);
516
+ if (docPrompt) {
517
+ promptParts.push(docPrompt);
518
+ promptParts.push('');
519
+ documentationAdded = true;
520
+ }
521
+ }
522
+ }
523
+ // Fall back to legacy considerations file if no directory-based docs
524
+ if (!documentationAdded) {
525
+ const considerations = loadConsiderations(config.considerationsPath);
526
+ if (considerations) {
527
+ const considerationsPrompt = considerationsToPrompt(considerations);
528
+ if (considerationsPrompt) {
529
+ promptParts.push(considerationsPrompt);
530
+ promptParts.push('');
531
+ }
532
+ }
533
+ }
534
+ promptParts.push(...generated.layoutInstructions, '', 'Available components:', generated.componentReference, '', generated.examples);
535
+ // Add additional imports information if configured
536
+ if (config.additionalImports && config.additionalImports.length > 0) {
537
+ promptParts.push('');
538
+ promptParts.push('ADDITIONAL IMPORT EXAMPLES - COPY THESE EXACTLY:');
539
+ config.additionalImports.forEach(additionalImport => {
540
+ const componentExamples = additionalImport.components.map(componentName => {
541
+ let componentConfig = config.components?.find(c => c.name === componentName);
542
+ if (!componentConfig) {
543
+ componentConfig = config.layoutComponents?.find(c => c.name === componentName);
544
+ }
545
+ if (componentConfig && componentConfig.importType === 'default') {
546
+ return `import ${componentName} from '${additionalImport.path}';`;
547
+ }
548
+ else {
549
+ return `import { ${componentName} } from '${additionalImport.path}';`;
550
+ }
551
+ });
552
+ componentExamples.forEach(example => {
553
+ promptParts.push(`- ${example}`);
554
+ });
555
+ });
556
+ }
557
+ // Add framework-specific rules
558
+ const frameworkType = generated.framework.componentFramework;
559
+ const frameworkRules = getFrameworkSpecificRules(frameworkType);
560
+ if (frameworkRules.length > 0) {
561
+ promptParts.push('');
562
+ promptParts.push(`${frameworkType.toUpperCase()} SPECIFIC RULES:`);
563
+ promptParts.push(...frameworkRules);
564
+ }
565
+ promptParts.push('', `Output a complete Storybook story file in TypeScript. Import components as shown in the sample template below. Use the following sample as a template. Respond ONLY with a single code block containing the full file, and nothing else.`, '', '<rules>', 'CRITICAL REMINDERS:', '- Story title MUST always start with "Generated/" (e.g., title: "Generated/Recipe Card")', '- ONLY import components that are listed in the "Available components" section', '- ALWAYS use the exact import path shown in parentheses after each component', '- NEVER use main package imports when specific subpath imports are shown', '- Do NOT import story exports - these are NOT real components', '- All images MUST have a src attribute with placeholder URLs (use https://picsum.photos/)', '- MUST use ES modules syntax: "export default meta;" NOT "module.exports = meta;"', '- The file MUST have a default export for the meta object', '- Keep the story concise and focused - avoid overly complex layouts', '- Ensure all tags are properly closed and syntax is valid', '- Story must be complete and syntactically valid', '</rules>', '', 'Sample story format:', generated.sampleStory, '', 'User request:', userPrompt);
566
+ return promptParts.join('\n');
567
+ }
568
+ /**
569
+ * Get framework-specific rules to include in the prompt
570
+ */
571
+ function getFrameworkSpecificRules(framework) {
572
+ const rules = [];
573
+ switch (framework) {
574
+ case 'react':
575
+ rules.push("- FIRST LINE MUST BE: import React from 'react';");
576
+ rules.push('- Use JSX syntax for templates');
577
+ rules.push('- NEVER pass children through args - use render functions');
578
+ rules.push('- For layouts with multiple components, DO NOT set component in meta');
579
+ break;
580
+ case 'vue':
581
+ rules.push("- Import from '@storybook/vue3'");
582
+ rules.push('- Use Vue 3 Composition API style');
583
+ rules.push('- Use render functions with template for complex content');
584
+ rules.push('- Event bindings use @event or v-on:event syntax');
585
+ rules.push('- Slots use v-slot directive or # shorthand');
586
+ break;
587
+ case 'angular':
588
+ rules.push("- Import from '@storybook/angular'");
589
+ rules.push('- Use moduleMetadata or applicationConfig decorators');
590
+ rules.push('- Property binding: [property]="value"');
591
+ rules.push('- Event binding: (event)="handler($event)"');
592
+ rules.push('- Use Angular template syntax in render functions');
593
+ break;
594
+ case 'svelte':
595
+ rules.push("- Import from '@storybook/svelte'");
596
+ rules.push('- Import .svelte files directly as default exports');
597
+ rules.push('- Events use on: directive (e.g., on:click)');
598
+ rules.push('- Use bind: for two-way binding');
599
+ break;
600
+ case 'web-components':
601
+ rules.push("- Import { html } from 'lit'");
602
+ rules.push("- Import from '@storybook/web-components'");
603
+ rules.push('- Use html`` template literal, NOT JSX');
604
+ rules.push('- Use kebab-case for tag names (e.g., <my-button>)');
605
+ rules.push('- Property binding: .property=${value}');
606
+ rules.push('- Event binding: @event=${handler}');
607
+ rules.push('- Boolean attributes: ?disabled=${true}');
608
+ break;
609
+ default:
610
+ break;
611
+ }
612
+ return rules;
613
+ }
614
+ /**
615
+ * Detect the framework for a given project
616
+ */
617
+ export async function detectProjectFramework(projectRoot) {
618
+ const registry = getAdapterRegistry();
619
+ const adapter = await registry.autoDetect(projectRoot || process.cwd());
620
+ return adapter.type;
621
+ }
622
+ /**
623
+ * Get the adapter for a specific framework
624
+ */
625
+ export function getFrameworkAdapter(framework) {
626
+ const registry = getAdapterRegistry();
627
+ return registry.getAdapter(framework);
628
+ }
629
+ /**
630
+ * Get all available framework adapters
631
+ */
632
+ export function getAvailableFrameworks() {
633
+ const registry = getAdapterRegistry();
634
+ return registry.getAvailableFrameworks();
635
+ }