@tpitre/story-ui 1.2.0 → 1.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/dist/cli/index.js +0 -0
- package/dist/mcp-server/routes/generateStory.js +48 -11
- package/dist/story-generator/configLoader.js +11 -5
- package/dist/story-generator/validateStory.js +262 -0
- package/package.json +5 -5
- package/templates/StoryUI/StoryUIPanel.tsx +37 -2
- package/dist/test-storybooks/chakra-test/src/components/index.js +0 -3
- package/dist/test-storybooks/custom-design-test/src/components/index.js +0 -3
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/cli/index.js
CHANGED
|
File without changes
|
|
@@ -6,6 +6,7 @@ import { buildClaudePrompt as buildFlexiblePrompt } from '../../story-generator/
|
|
|
6
6
|
import { loadUserConfig, validateConfig } from '../../story-generator/configLoader.js';
|
|
7
7
|
import { setupProductionGitignore } from '../../story-generator/productionGitignoreManager.js';
|
|
8
8
|
import { getInMemoryStoryService } from '../../story-generator/inMemoryStoryService.js';
|
|
9
|
+
import { extractAndValidateCodeBlock, createFallbackStory } from '../../story-generator/validateStory.js';
|
|
9
10
|
const CLAUDE_API_URL = 'https://api.anthropic.com/v1/messages';
|
|
10
11
|
const CLAUDE_MODEL = process.env.CLAUDE_MODEL || 'claude-sonnet-4-20250514';
|
|
11
12
|
// Legacy constants - now using dynamic discovery
|
|
@@ -185,17 +186,43 @@ export async function generateStoryFromPrompt(req, res) {
|
|
|
185
186
|
console.log('Claude prompt:', fullPrompt);
|
|
186
187
|
const aiText = await callClaude(fullPrompt);
|
|
187
188
|
console.log('Claude raw response:', aiText);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
// Use the new robust validation system
|
|
190
|
+
const validationResult = extractAndValidateCodeBlock(aiText);
|
|
191
|
+
let fileContents;
|
|
192
|
+
let hasValidationWarnings = false;
|
|
193
|
+
if (!validationResult.isValid) {
|
|
194
|
+
console.error('Generated code validation failed:', validationResult.errors);
|
|
195
|
+
// If we have fixedCode, use it
|
|
196
|
+
if (validationResult.fixedCode) {
|
|
197
|
+
fileContents = validationResult.fixedCode;
|
|
198
|
+
hasValidationWarnings = true;
|
|
199
|
+
console.log('Using auto-fixed code with warnings:', validationResult.warnings);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// Create fallback story
|
|
203
|
+
console.log('Creating fallback story due to validation failure');
|
|
204
|
+
fileContents = createFallbackStory(prompt, config);
|
|
205
|
+
hasValidationWarnings = true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Extract the validated code
|
|
210
|
+
const codeMatch = aiText.match(/```(?:tsx|jsx|typescript|ts|js|javascript)?\s*([\s\S]*?)\s*```/i);
|
|
211
|
+
if (codeMatch) {
|
|
212
|
+
fileContents = codeMatch[1].trim();
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const importIdx = aiText.indexOf('import');
|
|
216
|
+
fileContents = importIdx !== -1 ? aiText.slice(importIdx).trim() : aiText.trim();
|
|
217
|
+
}
|
|
218
|
+
if (validationResult.warnings.length > 0) {
|
|
219
|
+
hasValidationWarnings = true;
|
|
220
|
+
console.log('Validation warnings:', validationResult.warnings);
|
|
194
221
|
}
|
|
195
222
|
}
|
|
196
|
-
if (!fileContents
|
|
197
|
-
console.error('No valid code
|
|
198
|
-
return res.status(500).json({ error: '
|
|
223
|
+
if (!fileContents) {
|
|
224
|
+
console.error('No valid code could be extracted or generated.');
|
|
225
|
+
return res.status(500).json({ error: 'Failed to generate valid TypeScript code.' });
|
|
199
226
|
}
|
|
200
227
|
// Generate title based on conversation context
|
|
201
228
|
let aiTitle;
|
|
@@ -255,7 +282,12 @@ export async function generateStoryFromPrompt(req, res) {
|
|
|
255
282
|
story: fileContents,
|
|
256
283
|
environment: 'production',
|
|
257
284
|
storage: 'in-memory',
|
|
258
|
-
isUpdate
|
|
285
|
+
isUpdate,
|
|
286
|
+
validation: {
|
|
287
|
+
hasWarnings: hasValidationWarnings,
|
|
288
|
+
errors: validationResult.errors || [],
|
|
289
|
+
warnings: validationResult.warnings || []
|
|
290
|
+
}
|
|
259
291
|
});
|
|
260
292
|
}
|
|
261
293
|
else {
|
|
@@ -270,7 +302,12 @@ export async function generateStoryFromPrompt(req, res) {
|
|
|
270
302
|
story: fileContents,
|
|
271
303
|
environment: 'development',
|
|
272
304
|
storage: 'file-system',
|
|
273
|
-
isUpdate
|
|
305
|
+
isUpdate,
|
|
306
|
+
validation: {
|
|
307
|
+
hasWarnings: hasValidationWarnings,
|
|
308
|
+
errors: validationResult.errors || [],
|
|
309
|
+
warnings: validationResult.warnings || []
|
|
310
|
+
}
|
|
274
311
|
});
|
|
275
312
|
}
|
|
276
313
|
}
|
|
@@ -28,13 +28,18 @@ export function loadUserConfig() {
|
|
|
28
28
|
console.log(`Loading Story UI config from: ${configPath}`);
|
|
29
29
|
// Read and evaluate the config file
|
|
30
30
|
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
31
|
-
//
|
|
32
|
-
if (configContent.includes('module.exports')) {
|
|
31
|
+
// Handle both CommonJS and ES modules
|
|
32
|
+
if (configContent.includes('module.exports') || configContent.includes('export default')) {
|
|
33
33
|
// Create a temporary module context
|
|
34
34
|
const module = { exports: {} };
|
|
35
35
|
const exports = module.exports;
|
|
36
|
+
// For ES modules, convert to CommonJS for evaluation
|
|
37
|
+
let evalContent = configContent;
|
|
38
|
+
if (configContent.includes('export default')) {
|
|
39
|
+
evalContent = configContent.replace(/export\s+default\s+/, 'module.exports = ');
|
|
40
|
+
}
|
|
36
41
|
// Evaluate the config file content
|
|
37
|
-
eval(
|
|
42
|
+
eval(evalContent);
|
|
38
43
|
const userConfig = module.exports;
|
|
39
44
|
const config = createStoryUIConfig(userConfig.default || userConfig);
|
|
40
45
|
// Cache the loaded config
|
|
@@ -82,13 +87,14 @@ export function validateConfig(config) {
|
|
|
82
87
|
if (!config.componentsPath && !config.componentsMetadataPath && (!config.components || config.components.length === 0)) {
|
|
83
88
|
errors.push('Either componentsPath, componentsMetadataPath, or a components array must be specified');
|
|
84
89
|
}
|
|
85
|
-
|
|
90
|
+
// Only validate componentsPath if it's provided (not null/undefined)
|
|
91
|
+
if (config.componentsPath && config.componentsPath !== null && !fs.existsSync(config.componentsPath)) {
|
|
86
92
|
errors.push(`Components path does not exist: ${config.componentsPath}`);
|
|
87
93
|
}
|
|
88
94
|
if (config.componentsMetadataPath && !fs.existsSync(config.componentsMetadataPath)) {
|
|
89
95
|
errors.push(`Components metadata path does not exist: ${config.componentsMetadataPath}`);
|
|
90
96
|
}
|
|
91
|
-
// Check import path
|
|
97
|
+
// Check import path - but allow actual library names like 'antd'
|
|
92
98
|
if (!config.importPath || config.importPath === 'your-component-library' || config.importPath.trim() === '') {
|
|
93
99
|
errors.push('importPath must be configured to point to your component library');
|
|
94
100
|
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Validates TypeScript code syntax and attempts to fix common issues
|
|
4
|
+
*/
|
|
5
|
+
export function validateStoryCode(code, fileName = 'story.tsx') {
|
|
6
|
+
const result = {
|
|
7
|
+
isValid: true,
|
|
8
|
+
errors: [],
|
|
9
|
+
warnings: []
|
|
10
|
+
};
|
|
11
|
+
try {
|
|
12
|
+
// Create a TypeScript source file
|
|
13
|
+
const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
14
|
+
// Check for syntax errors using the program API
|
|
15
|
+
const compilerOptions = {
|
|
16
|
+
jsx: ts.JsxEmit.ReactJSX,
|
|
17
|
+
target: ts.ScriptTarget.Latest,
|
|
18
|
+
module: ts.ModuleKind.ESNext,
|
|
19
|
+
allowJs: true,
|
|
20
|
+
skipLibCheck: true
|
|
21
|
+
};
|
|
22
|
+
// Create a program to get diagnostics
|
|
23
|
+
const program = ts.createProgram([fileName], compilerOptions, {
|
|
24
|
+
getSourceFile: (name) => name === fileName ? sourceFile : undefined,
|
|
25
|
+
writeFile: () => { },
|
|
26
|
+
getCurrentDirectory: () => '',
|
|
27
|
+
getDirectories: () => [],
|
|
28
|
+
fileExists: (name) => name === fileName,
|
|
29
|
+
readFile: () => '',
|
|
30
|
+
getCanonicalFileName: (name) => name,
|
|
31
|
+
useCaseSensitiveFileNames: () => true,
|
|
32
|
+
getNewLine: () => '\n',
|
|
33
|
+
getDefaultLibFileName: () => 'lib.d.ts'
|
|
34
|
+
});
|
|
35
|
+
const syntaxErrors = program.getSyntacticDiagnostics(sourceFile);
|
|
36
|
+
if (syntaxErrors.length > 0) {
|
|
37
|
+
result.isValid = false;
|
|
38
|
+
for (const diagnostic of syntaxErrors) {
|
|
39
|
+
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
40
|
+
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
41
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
42
|
+
result.errors.push(`Line ${position.line + 1}, Column ${position.character + 1}: ${message}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
result.errors.push(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Additional semantic checks
|
|
50
|
+
const semanticErrors = performSemanticChecks(sourceFile);
|
|
51
|
+
result.errors.push(...semanticErrors);
|
|
52
|
+
if (result.errors.length > 0) {
|
|
53
|
+
result.isValid = false;
|
|
54
|
+
// Attempt to fix common issues
|
|
55
|
+
const fixedCode = attemptAutoFix(code, result.errors);
|
|
56
|
+
if (fixedCode && fixedCode !== code) {
|
|
57
|
+
result.fixedCode = fixedCode;
|
|
58
|
+
// Re-validate the fixed code
|
|
59
|
+
const fixedValidation = validateStoryCode(fixedCode, fileName);
|
|
60
|
+
if (fixedValidation.isValid) {
|
|
61
|
+
result.isValid = true;
|
|
62
|
+
result.warnings.push('Code was automatically fixed for syntax errors');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
result.isValid = false;
|
|
69
|
+
result.errors.push(`Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Performs additional semantic checks on the AST
|
|
75
|
+
*/
|
|
76
|
+
function performSemanticChecks(sourceFile) {
|
|
77
|
+
const errors = [];
|
|
78
|
+
function visit(node) {
|
|
79
|
+
// Check for unclosed JSX elements
|
|
80
|
+
if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
81
|
+
// Additional JSX-specific checks could go here
|
|
82
|
+
}
|
|
83
|
+
// Check for missing imports
|
|
84
|
+
if (ts.isIdentifier(node) && node.text && /^[A-Z]/.test(node.text)) {
|
|
85
|
+
// This is a potential component reference - would need more context to validate
|
|
86
|
+
}
|
|
87
|
+
ts.forEachChild(node, visit);
|
|
88
|
+
}
|
|
89
|
+
visit(sourceFile);
|
|
90
|
+
return errors;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Attempts to automatically fix common syntax errors
|
|
94
|
+
*/
|
|
95
|
+
function attemptAutoFix(code, errors) {
|
|
96
|
+
let fixedCode = code;
|
|
97
|
+
// Fix common issues based on error patterns
|
|
98
|
+
for (const error of errors) {
|
|
99
|
+
if (error.includes('expected ","')) {
|
|
100
|
+
// Try to fix missing commas in object literals
|
|
101
|
+
fixedCode = fixMissingCommas(fixedCode);
|
|
102
|
+
}
|
|
103
|
+
if (error.includes('Unexpected token')) {
|
|
104
|
+
// Try to fix unexpected tokens
|
|
105
|
+
fixedCode = fixUnexpectedTokens(fixedCode);
|
|
106
|
+
}
|
|
107
|
+
if (error.includes('Unterminated string literal')) {
|
|
108
|
+
// Try to fix unterminated strings
|
|
109
|
+
fixedCode = fixUnterminatedStrings(fixedCode);
|
|
110
|
+
}
|
|
111
|
+
if (error.includes('JSX element') && error.includes('has no corresponding closing tag')) {
|
|
112
|
+
// Try to fix unclosed JSX elements
|
|
113
|
+
fixedCode = fixUnclosedJSX(fixedCode);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return fixedCode;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Fixes missing commas in object literals and function parameters
|
|
120
|
+
*/
|
|
121
|
+
function fixMissingCommas(code) {
|
|
122
|
+
// Common patterns where commas might be missing
|
|
123
|
+
const fixes = [
|
|
124
|
+
// Fix object property definitions
|
|
125
|
+
{ pattern: /(\w+):\s*([^,}\n]+)\s*\n\s*(\w+):/g, replacement: '$1: $2,\n $3:' },
|
|
126
|
+
// Fix array elements
|
|
127
|
+
{ pattern: /(\w+)\s*\n\s*(\w+)/g, replacement: '$1,\n $2' },
|
|
128
|
+
// Fix function parameters
|
|
129
|
+
{ pattern: /(\w+:\s*\w+)\s*\n\s*(\w+:)/g, replacement: '$1,\n $2' }
|
|
130
|
+
];
|
|
131
|
+
let fixedCode = code;
|
|
132
|
+
for (const fix of fixes) {
|
|
133
|
+
fixedCode = fixedCode.replace(fix.pattern, fix.replacement);
|
|
134
|
+
}
|
|
135
|
+
return fixedCode;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Fixes unexpected token issues
|
|
139
|
+
*/
|
|
140
|
+
function fixUnexpectedTokens(code) {
|
|
141
|
+
let fixedCode = code;
|
|
142
|
+
// Fix common unexpected token issues
|
|
143
|
+
const fixes = [
|
|
144
|
+
// Fix missing semicolons
|
|
145
|
+
{ pattern: /^(\s*)(export\s+\w+.*[^;])\s*$/gm, replacement: '$1$2;' },
|
|
146
|
+
// Fix missing quotes around strings
|
|
147
|
+
{ pattern: /:\s*([^"'\s,}]+)\s*(,|\})/g, replacement: ': "$1"$2' },
|
|
148
|
+
// Fix trailing commas in objects
|
|
149
|
+
{ pattern: /,(\s*\})/g, replacement: '$1' }
|
|
150
|
+
];
|
|
151
|
+
for (const fix of fixes) {
|
|
152
|
+
fixedCode = fixedCode.replace(fix.pattern, fix.replacement);
|
|
153
|
+
}
|
|
154
|
+
return fixedCode;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Fixes unterminated string literals
|
|
158
|
+
*/
|
|
159
|
+
function fixUnterminatedStrings(code) {
|
|
160
|
+
let fixedCode = code;
|
|
161
|
+
// Find lines with unterminated strings and try to fix them
|
|
162
|
+
const lines = fixedCode.split('\n');
|
|
163
|
+
for (let i = 0; i < lines.length; i++) {
|
|
164
|
+
const line = lines[i];
|
|
165
|
+
// Check for unterminated quotes
|
|
166
|
+
const singleQuoteCount = (line.match(/'/g) || []).length;
|
|
167
|
+
const doubleQuoteCount = (line.match(/"/g) || []).length;
|
|
168
|
+
if (singleQuoteCount % 2 !== 0) {
|
|
169
|
+
lines[i] = line + "'";
|
|
170
|
+
}
|
|
171
|
+
else if (doubleQuoteCount % 2 !== 0) {
|
|
172
|
+
lines[i] = line + '"';
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return lines.join('\n');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Fixes unclosed JSX elements
|
|
179
|
+
*/
|
|
180
|
+
function fixUnclosedJSX(code) {
|
|
181
|
+
let fixedCode = code;
|
|
182
|
+
// Simple heuristic to fix common JSX issues
|
|
183
|
+
const jsxOpenTags = fixedCode.match(/<[A-Z]\w*[^>]*>/g) || [];
|
|
184
|
+
const jsxCloseTags = fixedCode.match(/<\/[A-Z]\w*>/g) || [];
|
|
185
|
+
// If we have more opening tags than closing tags, try to balance them
|
|
186
|
+
if (jsxOpenTags.length > jsxCloseTags.length) {
|
|
187
|
+
// This is a very basic fix - in practice, you'd need more sophisticated parsing
|
|
188
|
+
// For now, we'll just add a warning
|
|
189
|
+
}
|
|
190
|
+
return fixedCode;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Extracts and validates code blocks from AI responses
|
|
194
|
+
*/
|
|
195
|
+
export function extractAndValidateCodeBlock(aiResponse) {
|
|
196
|
+
// Try multiple extraction methods
|
|
197
|
+
const extractionMethods = [
|
|
198
|
+
// Standard code blocks
|
|
199
|
+
(text) => {
|
|
200
|
+
const match = text.match(/```(?:tsx|jsx|typescript|ts|js|javascript)?\s*([\s\S]*?)\s*```/i);
|
|
201
|
+
return match ? match[1].trim() : null;
|
|
202
|
+
},
|
|
203
|
+
// Code starting with import
|
|
204
|
+
(text) => {
|
|
205
|
+
const importIndex = text.indexOf('import');
|
|
206
|
+
return importIndex !== -1 ? text.slice(importIndex).trim() : null;
|
|
207
|
+
},
|
|
208
|
+
// Code starting with export
|
|
209
|
+
(text) => {
|
|
210
|
+
const exportIndex = text.indexOf('export');
|
|
211
|
+
return exportIndex !== -1 ? text.slice(exportIndex).trim() : null;
|
|
212
|
+
}
|
|
213
|
+
];
|
|
214
|
+
let extractedCode = null;
|
|
215
|
+
for (const method of extractionMethods) {
|
|
216
|
+
extractedCode = method(aiResponse);
|
|
217
|
+
if (extractedCode)
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
if (!extractedCode) {
|
|
221
|
+
return {
|
|
222
|
+
isValid: false,
|
|
223
|
+
errors: ['No valid TypeScript code found in AI response'],
|
|
224
|
+
warnings: []
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// Validate the extracted code
|
|
228
|
+
return validateStoryCode(extractedCode);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Creates a fallback story template when generation fails
|
|
232
|
+
*/
|
|
233
|
+
export function createFallbackStory(prompt, config) {
|
|
234
|
+
const title = prompt.length > 50 ? prompt.substring(0, 50) + '...' : prompt;
|
|
235
|
+
const escapedTitle = title.replace(/"/g, '\\"');
|
|
236
|
+
return `import React from 'react';
|
|
237
|
+
import type { StoryObj } from '@storybook/react';
|
|
238
|
+
|
|
239
|
+
// Fallback story generated due to AI generation error
|
|
240
|
+
export default {
|
|
241
|
+
title: '${config.storyPrefix || 'Generated/'}${escapedTitle}',
|
|
242
|
+
component: () => (
|
|
243
|
+
<div style={{ padding: '2rem', textAlign: 'center', border: '2px dashed #ccc', borderRadius: '8px' }}>
|
|
244
|
+
<h2>Story Generation Error</h2>
|
|
245
|
+
<p>The AI-generated story contained syntax errors and could not be created.</p>
|
|
246
|
+
<p><strong>Original prompt:</strong> ${escapedTitle}</p>
|
|
247
|
+
<p>Please try rephrasing your request or contact support.</p>
|
|
248
|
+
</div>
|
|
249
|
+
),
|
|
250
|
+
parameters: {
|
|
251
|
+
docs: {
|
|
252
|
+
description: {
|
|
253
|
+
story: 'This is a fallback story created when the AI generation failed due to syntax errors.'
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export const Default: StoryObj = {
|
|
260
|
+
args: {}
|
|
261
|
+
};`;
|
|
262
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpitre/story-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "AI-powered Storybook story generator for any React component library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
|
44
|
-
"url": "https://github.com/southleft/story-ui.git"
|
|
44
|
+
"url": "git+https://github.com/southleft/story-ui.git"
|
|
45
45
|
},
|
|
46
46
|
"bugs": {
|
|
47
47
|
"url": "https://github.com/southleft/story-ui/issues"
|
|
@@ -62,7 +62,8 @@
|
|
|
62
62
|
"dotenv": "^16.3.1",
|
|
63
63
|
"express": "^4.18.2",
|
|
64
64
|
"inquirer": "^9.2.0",
|
|
65
|
-
"node-fetch": "^2.6.7"
|
|
65
|
+
"node-fetch": "^2.6.7",
|
|
66
|
+
"typescript": "^5.8.3"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@commitlint/cli": "^19.6.1",
|
|
@@ -82,8 +83,7 @@
|
|
|
82
83
|
"cz-conventional-changelog": "^3.3.0",
|
|
83
84
|
"husky": "^9.1.7",
|
|
84
85
|
"semantic-release": "^24.2.0",
|
|
85
|
-
"ts-node": "^10.9.2"
|
|
86
|
-
"typescript": "^5.8.3"
|
|
86
|
+
"ts-node": "^10.9.2"
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"@storybook/react": ">=6.0.0",
|
|
@@ -501,10 +501,45 @@ const StoryUIPanel: React.FC = () => {
|
|
|
501
501
|
|
|
502
502
|
// Create user-friendly response message instead of showing raw markup
|
|
503
503
|
let responseMessage: string;
|
|
504
|
+
let statusIcon = '✅';
|
|
505
|
+
|
|
506
|
+
// Check for validation issues
|
|
507
|
+
if (data.validation && data.validation.hasWarnings) {
|
|
508
|
+
statusIcon = '⚠️';
|
|
509
|
+
const warningCount = data.validation.warnings.length;
|
|
510
|
+
const errorCount = data.validation.errors.length;
|
|
511
|
+
|
|
512
|
+
if (errorCount > 0) {
|
|
513
|
+
statusIcon = '🔧';
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
504
517
|
if (data.isUpdate) {
|
|
505
|
-
responseMessage =
|
|
518
|
+
responseMessage = `${statusIcon} Updated your story: "${data.title}"\n\nI've made the requested changes while keeping the same layout structure. You can view the updated component in Storybook.`;
|
|
506
519
|
} else {
|
|
507
|
-
responseMessage =
|
|
520
|
+
responseMessage = `${statusIcon} Created new story: "${data.title}"\n\nI've generated the component with the requested features. You can view it in Storybook where you'll see both the rendered component and its markup in the Docs tab.`;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Add validation information if there are issues
|
|
524
|
+
if (data.validation && data.validation.hasWarnings) {
|
|
525
|
+
responseMessage += '\n\n';
|
|
526
|
+
|
|
527
|
+
if (data.validation.errors.length > 0) {
|
|
528
|
+
responseMessage += `🔧 **Auto-fixed ${data.validation.errors.length} syntax error(s):**\n`;
|
|
529
|
+
responseMessage += data.validation.errors.slice(0, 3).map(error => ` • ${error}`).join('\n');
|
|
530
|
+
if (data.validation.errors.length > 3) {
|
|
531
|
+
responseMessage += `\n • ... and ${data.validation.errors.length - 3} more`;
|
|
532
|
+
}
|
|
533
|
+
responseMessage += '\n';
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (data.validation.warnings.length > 0) {
|
|
537
|
+
responseMessage += `⚠️ **Warnings:**\n`;
|
|
538
|
+
responseMessage += data.validation.warnings.slice(0, 2).map(warning => ` • ${warning}`).join('\n');
|
|
539
|
+
if (data.validation.warnings.length > 2) {
|
|
540
|
+
responseMessage += `\n • ... and ${data.validation.warnings.length - 2} more`;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
508
543
|
}
|
|
509
544
|
|
|
510
545
|
const aiMsg = { role: 'ai' as const, content: responseMessage };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["../index.ts","../story-ui.config.loader.ts","../story-ui.config.ts","../cli/index.ts","../cli/setup.ts","../mcp-server/index.ts","../mcp-server/routes/claude.ts","../mcp-server/routes/components.ts","../mcp-server/routes/generatestory.ts","../mcp-server/routes/memorystories.ts","../mcp-server/routes/storysync.ts","../story-generator/componentdiscovery.ts","../story-generator/configloader.ts","../story-generator/generatestory.ts","../story-generator/gitignoremanager.ts","../story-generator/inmemorystoryservice.ts","../story-generator/productiongitignoremanager.ts","../story-generator/promptgenerator.ts","../story-generator/storysync.ts"],"version":"5.8.3"}
|