@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.
- package/.env.sample +82 -11
- package/README.md +130 -4
- package/dist/cli/deploy.d.ts +17 -0
- package/dist/cli/deploy.d.ts.map +1 -0
- package/dist/cli/deploy.js +696 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +55 -2
- package/dist/cli/setup.d.ts +11 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +437 -110
- package/dist/mcp-server/index.d.ts +2 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +138 -6
- package/dist/mcp-server/mcp-stdio-server.d.ts +3 -0
- package/dist/mcp-server/mcp-stdio-server.d.ts.map +1 -0
- package/dist/mcp-server/mcp-stdio-server.js +638 -0
- package/dist/mcp-server/routes/claude.d.ts +3 -0
- package/dist/mcp-server/routes/claude.d.ts.map +1 -0
- package/dist/mcp-server/routes/claude.js +60 -23
- package/dist/mcp-server/routes/components.d.ts +4 -0
- package/dist/mcp-server/routes/components.d.ts.map +1 -0
- package/dist/mcp-server/routes/frameworks.d.ts +38 -0
- package/dist/mcp-server/routes/frameworks.d.ts.map +1 -0
- package/dist/mcp-server/routes/frameworks.js +183 -0
- package/dist/mcp-server/routes/generateStory.d.ts +3 -0
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -0
- package/dist/mcp-server/routes/generateStory.js +274 -115
- package/dist/mcp-server/routes/generateStoryStream.d.ts +12 -0
- package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -0
- package/dist/mcp-server/routes/generateStoryStream.js +947 -0
- package/dist/mcp-server/routes/hybridStories.d.ts +18 -0
- package/dist/mcp-server/routes/hybridStories.d.ts.map +1 -0
- package/dist/mcp-server/routes/hybridStories.js +214 -0
- package/dist/mcp-server/routes/mcpRemote.d.ts +14 -0
- package/dist/mcp-server/routes/mcpRemote.d.ts.map +1 -0
- package/dist/mcp-server/routes/mcpRemote.js +489 -0
- package/dist/mcp-server/routes/memoryStories.d.ts +26 -0
- package/dist/mcp-server/routes/memoryStories.d.ts.map +1 -0
- package/dist/mcp-server/routes/memoryStories.js +13 -7
- package/dist/mcp-server/routes/providers.d.ts +89 -0
- package/dist/mcp-server/routes/providers.d.ts.map +1 -0
- package/dist/mcp-server/routes/providers.js +369 -0
- package/dist/mcp-server/routes/storySync.d.ts +26 -0
- package/dist/mcp-server/routes/storySync.d.ts.map +1 -0
- package/dist/mcp-server/routes/streamTypes.d.ts +110 -0
- package/dist/mcp-server/routes/streamTypes.d.ts.map +1 -0
- package/dist/mcp-server/routes/streamTypes.js +18 -0
- package/dist/mcp-server/sessionManager.d.ts +50 -0
- package/dist/mcp-server/sessionManager.d.ts.map +1 -0
- package/dist/mcp-server/sessionManager.js +125 -0
- package/dist/story-generator/componentBlacklist.d.ts +21 -0
- package/dist/story-generator/componentBlacklist.d.ts.map +1 -0
- package/dist/story-generator/componentBlacklist.js +4 -0
- package/dist/story-generator/componentDiscovery.d.ts +28 -0
- package/dist/story-generator/componentDiscovery.d.ts.map +1 -0
- package/dist/story-generator/componentRegistryGenerator.d.ts +49 -0
- package/dist/story-generator/componentRegistryGenerator.d.ts.map +1 -0
- package/dist/story-generator/componentRegistryGenerator.js +205 -0
- package/dist/story-generator/configLoader.d.ts +33 -0
- package/dist/story-generator/configLoader.d.ts.map +1 -0
- package/dist/story-generator/configLoader.js +8 -1
- package/dist/story-generator/considerationsLoader.d.ts +32 -0
- package/dist/story-generator/considerationsLoader.d.ts.map +1 -0
- package/dist/story-generator/considerationsLoader.js +2 -1
- package/dist/story-generator/documentation-sources.d.ts +28 -0
- package/dist/story-generator/documentation-sources.d.ts.map +1 -0
- package/dist/story-generator/documentationLoader.d.ts +64 -0
- package/dist/story-generator/documentationLoader.d.ts.map +1 -0
- package/dist/story-generator/documentationLoader.js +4 -3
- package/dist/story-generator/dynamicPackageDiscovery.d.ts +97 -0
- package/dist/story-generator/dynamicPackageDiscovery.d.ts.map +1 -0
- package/dist/story-generator/dynamicPackageDiscovery.js +31 -22
- package/dist/story-generator/enhancedComponentDiscovery.d.ts +125 -0
- package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -0
- package/dist/story-generator/enhancedComponentDiscovery.js +162 -21
- package/dist/story-generator/framework-adapters/angular-adapter.d.ts +40 -0
- package/dist/story-generator/framework-adapters/angular-adapter.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/angular-adapter.js +427 -0
- package/dist/story-generator/framework-adapters/base-adapter.d.ts +75 -0
- package/dist/story-generator/framework-adapters/base-adapter.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/base-adapter.js +147 -0
- package/dist/story-generator/framework-adapters/framework-detector.d.ts +55 -0
- package/dist/story-generator/framework-adapters/framework-detector.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/framework-detector.js +323 -0
- package/dist/story-generator/framework-adapters/index.d.ts +97 -0
- package/dist/story-generator/framework-adapters/index.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/index.js +198 -0
- package/dist/story-generator/framework-adapters/react-adapter.d.ts +40 -0
- package/dist/story-generator/framework-adapters/react-adapter.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/react-adapter.js +316 -0
- package/dist/story-generator/framework-adapters/svelte-adapter.d.ts +40 -0
- package/dist/story-generator/framework-adapters/svelte-adapter.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/svelte-adapter.js +372 -0
- package/dist/story-generator/framework-adapters/types.d.ts +182 -0
- package/dist/story-generator/framework-adapters/types.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/types.js +8 -0
- package/dist/story-generator/framework-adapters/vue-adapter.d.ts +36 -0
- package/dist/story-generator/framework-adapters/vue-adapter.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/vue-adapter.js +336 -0
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts +54 -0
- package/dist/story-generator/framework-adapters/web-components-adapter.d.ts.map +1 -0
- package/dist/story-generator/framework-adapters/web-components-adapter.js +387 -0
- package/dist/story-generator/generateStory.d.ts +7 -0
- package/dist/story-generator/generateStory.d.ts.map +1 -0
- package/dist/story-generator/gitignoreManager.d.ts +50 -0
- package/dist/story-generator/gitignoreManager.d.ts.map +1 -0
- package/dist/story-generator/gitignoreManager.js +7 -6
- package/dist/story-generator/imageProcessor.d.ts +80 -0
- package/dist/story-generator/imageProcessor.d.ts.map +1 -0
- package/dist/story-generator/imageProcessor.js +391 -0
- package/dist/story-generator/inMemoryStoryService.d.ts +89 -0
- package/dist/story-generator/inMemoryStoryService.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/base-provider.d.ts +36 -0
- package/dist/story-generator/llm-providers/base-provider.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/base-provider.js +135 -0
- package/dist/story-generator/llm-providers/claude-provider.d.ts +23 -0
- package/dist/story-generator/llm-providers/claude-provider.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/claude-provider.js +414 -0
- package/dist/story-generator/llm-providers/gemini-provider.d.ts +24 -0
- package/dist/story-generator/llm-providers/gemini-provider.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/gemini-provider.js +406 -0
- package/dist/story-generator/llm-providers/index.d.ts +63 -0
- package/dist/story-generator/llm-providers/index.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/index.js +169 -0
- package/dist/story-generator/llm-providers/openai-provider.d.ts +24 -0
- package/dist/story-generator/llm-providers/openai-provider.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/openai-provider.js +458 -0
- package/dist/story-generator/llm-providers/settings-manager.d.ts +75 -0
- package/dist/story-generator/llm-providers/settings-manager.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/settings-manager.js +173 -0
- package/dist/story-generator/llm-providers/story-llm-service.d.ts +79 -0
- package/dist/story-generator/llm-providers/story-llm-service.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/story-llm-service.js +240 -0
- package/dist/story-generator/llm-providers/types.d.ts +153 -0
- package/dist/story-generator/llm-providers/types.d.ts.map +1 -0
- package/dist/story-generator/llm-providers/types.js +8 -0
- package/dist/story-generator/logger.d.ts +14 -0
- package/dist/story-generator/logger.d.ts.map +1 -0
- package/dist/story-generator/logger.js +119 -0
- package/dist/story-generator/postProcessStory.d.ts +6 -0
- package/dist/story-generator/postProcessStory.d.ts.map +1 -0
- package/dist/story-generator/postProcessStory.js +8 -7
- package/dist/story-generator/productionGitignoreManager.d.ts +91 -0
- package/dist/story-generator/productionGitignoreManager.d.ts.map +1 -0
- package/dist/story-generator/productionGitignoreManager.js +11 -10
- package/dist/story-generator/promptGenerator.d.ts +48 -0
- package/dist/story-generator/promptGenerator.d.ts.map +1 -0
- package/dist/story-generator/promptGenerator.js +186 -1
- package/dist/story-generator/storyHistory.d.ts +44 -0
- package/dist/story-generator/storyHistory.d.ts.map +1 -0
- package/dist/story-generator/storySync.d.ts +68 -0
- package/dist/story-generator/storySync.d.ts.map +1 -0
- package/dist/story-generator/storyTracker.d.ts +48 -0
- package/dist/story-generator/storyTracker.d.ts.map +1 -0
- package/dist/story-generator/storyTracker.js +2 -1
- package/dist/story-generator/storyValidator.d.ts +6 -0
- package/dist/story-generator/storyValidator.d.ts.map +1 -0
- package/dist/story-generator/universalDesignSystemAdapter.d.ts +68 -0
- package/dist/story-generator/universalDesignSystemAdapter.d.ts.map +1 -0
- package/dist/story-generator/universalDesignSystemAdapter.js +141 -3
- package/dist/story-generator/urlRedirectService.d.ts +21 -0
- package/dist/story-generator/urlRedirectService.d.ts.map +1 -0
- package/dist/story-generator/urlRedirectService.js +140 -0
- package/dist/story-generator/validateStory.d.ts +19 -0
- package/dist/story-generator/validateStory.d.ts.map +1 -0
- package/dist/story-generator/validateStory.js +6 -2
- package/dist/story-generator/visionPrompts.d.ts +88 -0
- package/dist/story-generator/visionPrompts.d.ts.map +1 -0
- package/dist/story-generator/visionPrompts.js +462 -0
- package/dist/story-ui.config.d.ts +78 -0
- package/dist/story-ui.config.d.ts.map +1 -0
- package/dist/templates/StoryUI/StoryUIPanel.d.ts +4 -0
- package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -0
- package/dist/templates/StoryUI/StoryUIPanel.js +1874 -0
- package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts +18 -0
- package/dist/templates/StoryUI/StoryUIPanel.stories.d.ts.map +1 -0
- package/dist/templates/StoryUI/StoryUIPanel.stories.js +37 -0
- package/dist/templates/StoryUI/index.d.ts +3 -0
- package/dist/templates/StoryUI/index.d.ts.map +1 -0
- package/dist/templates/StoryUI/index.js +2 -0
- package/package.json +35 -4
- package/templates/StoryUI/StoryUIPanel.tsx +1973 -388
- package/templates/StoryUI/index.tsx +1 -1
- package/templates/StoryUI/manager.tsx +264 -0
- package/templates/mcp-config-claude.json +11 -0
- package/templates/mcp-example.md +76 -0
- package/templates/production-app/.env.example +11 -0
- package/templates/production-app/index.html +66 -0
- package/templates/production-app/package.json +30 -0
- package/templates/production-app/public/favicon.svg +5 -0
- package/templates/production-app/src/App.tsx +1157 -0
- package/templates/production-app/src/LivePreviewRenderer.tsx +420 -0
- package/templates/production-app/src/componentRegistry.ts +315 -0
- package/templates/production-app/src/considerations.ts +16 -0
- package/templates/production-app/src/index.css +284 -0
- package/templates/production-app/src/main.tsx +25 -0
- package/templates/production-app/tsconfig.json +32 -0
- package/templates/production-app/tsconfig.node.json +11 -0
- package/templates/production-app/vite.config.ts +83 -0
- package/templates/react-import-rule.json +2 -2
- package/dist/index.js +0 -12
- 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 @@
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|