@tpitre/story-ui 2.7.0 → 2.8.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/README.md +76 -46
- package/dist/cli/deploy.d.ts +4 -3
- package/dist/cli/deploy.d.ts.map +1 -1
- package/dist/cli/deploy.js +421 -95
- package/dist/cli/index.js +15 -13
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +7 -113
- package/dist/story-generator/llm-providers/settings-manager.js +4 -4
- package/dist/story-generator/productionGitignoreManager.d.ts.map +1 -1
- package/dist/story-generator/productionGitignoreManager.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Story UI revolutionizes component documentation by automatically generating Stor
|
|
|
10
10
|
## Why Story UI?
|
|
11
11
|
|
|
12
12
|
- **Framework Agnostic**: Works with React, Vue, Angular, Svelte, and Web Components
|
|
13
|
-
- **Multi-Provider AI**: Choose between Claude (Anthropic), GPT-
|
|
13
|
+
- **Multi-Provider AI**: Choose between Claude (Anthropic), GPT-5 (OpenAI), or Gemini (Google)
|
|
14
14
|
- **Design System Aware**: Learns your component library and generates appropriate code
|
|
15
15
|
- **Production Ready**: Deploy as a standalone web app with full MCP integration
|
|
16
16
|
- **Zero Lock-in**: Use any component library - Mantine, Vuetify, Angular Material, Shoelace, or your own
|
|
@@ -51,19 +51,19 @@ Story UI will guide you through:
|
|
|
51
51
|
|
|
52
52
|
| Framework | Design Systems | Status |
|
|
53
53
|
|-----------|---------------|--------|
|
|
54
|
-
| React | Mantine, Chakra UI,
|
|
55
|
-
| Vue | Vuetify,
|
|
56
|
-
| Angular | Angular Material,
|
|
57
|
-
| Svelte | Skeleton, Custom | Fully Supported |
|
|
58
|
-
| Web Components | Shoelace,
|
|
54
|
+
| React | Mantine, Chakra UI, Material UI, Custom | Fully Supported |
|
|
55
|
+
| Vue | Vuetify, Custom | Fully Supported |
|
|
56
|
+
| Angular | Angular Material, Custom | Fully Supported |
|
|
57
|
+
| Svelte | Skeleton UI, Custom | Fully Supported |
|
|
58
|
+
| Web Components | Shoelace, Custom | Fully Supported |
|
|
59
59
|
|
|
60
60
|
### Multi-Provider LLM Support
|
|
61
61
|
|
|
62
62
|
| Provider | Models | Best For |
|
|
63
63
|
|----------|--------|----------|
|
|
64
64
|
| **Claude** (Anthropic) | Opus 4.5, Sonnet 4.5, Haiku 4.5 | Complex reasoning, code quality |
|
|
65
|
-
| **GPT
|
|
66
|
-
| **Gemini** (Google) | Gemini 3 Pro, Gemini 2.
|
|
65
|
+
| **GPT** (OpenAI) | GPT-5.1, GPT-5.1 Thinking, GPT-4o, GPT-4o Mini | Versatility, speed |
|
|
66
|
+
| **Gemini** (Google) | Gemini 3 Pro, Gemini 2.0 Flash, Gemini 1.5 Pro | Fast generation, cost efficiency |
|
|
67
67
|
|
|
68
68
|
### Production Deployment
|
|
69
69
|
- **Cloudflare Workers**: Edge-deployed API proxy
|
|
@@ -97,25 +97,19 @@ The interactive installer will ask:
|
|
|
97
97
|
```
|
|
98
98
|
# For React:
|
|
99
99
|
? Choose a design system:
|
|
100
|
-
>
|
|
101
|
-
Mantine
|
|
100
|
+
> Mantine - Most Popular
|
|
102
101
|
Chakra UI
|
|
103
|
-
|
|
102
|
+
Material UI
|
|
104
103
|
Custom
|
|
105
104
|
|
|
106
105
|
# For Vue:
|
|
107
106
|
? Choose a design system:
|
|
108
|
-
> Vuetify
|
|
109
|
-
Element Plus
|
|
110
|
-
PrimeVue
|
|
111
|
-
Quasar
|
|
107
|
+
> Vuetify - Most Popular
|
|
112
108
|
Custom
|
|
113
109
|
|
|
114
110
|
# For Angular:
|
|
115
111
|
? Choose a design system:
|
|
116
|
-
> Angular Material
|
|
117
|
-
PrimeNG
|
|
118
|
-
NG-ZORRO
|
|
112
|
+
> Angular Material - Most Popular
|
|
119
113
|
Custom
|
|
120
114
|
```
|
|
121
115
|
|
|
@@ -254,11 +248,31 @@ export class DataTableComponent { }
|
|
|
254
248
|
|
|
255
249
|
## MCP Server Integration
|
|
256
250
|
|
|
257
|
-
Story UI includes a Model Context Protocol (MCP) server, allowing direct integration with AI clients like Claude Desktop.
|
|
251
|
+
Story UI includes a Model Context Protocol (MCP) server, allowing direct integration with AI clients like Claude Desktop and Claude Code.
|
|
258
252
|
|
|
259
|
-
###
|
|
253
|
+
### Claude Code Integration (Recommended)
|
|
260
254
|
|
|
261
|
-
|
|
255
|
+
The easiest way to connect is via Claude Code's built-in MCP support:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Add remote HTTP MCP server
|
|
259
|
+
claude mcp add --transport http story-ui https://your-worker.workers.dev/mcp
|
|
260
|
+
|
|
261
|
+
# Or for local development
|
|
262
|
+
claude mcp add --transport http story-ui-local http://localhost:4005/mcp
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Claude Desktop Integration
|
|
266
|
+
|
|
267
|
+
Claude Desktop now supports a connector UI for adding MCP servers. Simply:
|
|
268
|
+
|
|
269
|
+
1. Open Claude Desktop Settings
|
|
270
|
+
2. Navigate to the MCP Servers section
|
|
271
|
+
3. Add a new server with:
|
|
272
|
+
- **Name**: Story UI
|
|
273
|
+
- **URL**: `https://your-worker.workers.dev/mcp` (production) or `http://localhost:4005/mcp` (local)
|
|
274
|
+
|
|
275
|
+
For advanced users who prefer manual configuration, add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
262
276
|
|
|
263
277
|
```json
|
|
264
278
|
{
|
|
@@ -274,28 +288,13 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
|
|
|
274
288
|
}
|
|
275
289
|
```
|
|
276
290
|
|
|
277
|
-
|
|
291
|
+
### Starting the Local MCP Server
|
|
292
|
+
|
|
278
293
|
```bash
|
|
279
294
|
npx story-ui start
|
|
280
295
|
```
|
|
281
296
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
Connect Claude Desktop to your deployed Story UI instance:
|
|
285
|
-
|
|
286
|
-
```json
|
|
287
|
-
{
|
|
288
|
-
"mcpServers": {
|
|
289
|
-
"story-ui-production": {
|
|
290
|
-
"command": "npx",
|
|
291
|
-
"args": ["mcp-remote", "https://your-worker.workers.dev/mcp"],
|
|
292
|
-
"env": {}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
This allows you to generate stories in your production environment directly from Claude Desktop, with all your design system configurations loaded.
|
|
297
|
+
This starts the Story UI HTTP server with MCP endpoint at `http://localhost:4005/mcp`.
|
|
299
298
|
|
|
300
299
|
### Available MCP Commands
|
|
301
300
|
|
|
@@ -365,19 +364,50 @@ wrangler pages deploy dist --project-name=your-app-name
|
|
|
365
364
|
|
|
366
365
|
Update the frontend to point to your worker URL in the configuration.
|
|
367
366
|
|
|
368
|
-
###
|
|
367
|
+
### Railway Deployment (Recommended)
|
|
369
368
|
|
|
370
|
-
|
|
369
|
+
Railway provides the most complete deployment experience with:
|
|
370
|
+
- Full Storybook dev server with HMR
|
|
371
|
+
- Integrated Story UI MCP server
|
|
372
|
+
- Live story generation directly in the sidebar
|
|
373
|
+
- Easy environment variable management
|
|
374
|
+
|
|
375
|
+
**1. Deploy to Railway**
|
|
371
376
|
|
|
372
377
|
```bash
|
|
373
|
-
|
|
378
|
+
# From your Storybook project with Story UI configured
|
|
379
|
+
npx story-ui deploy --live --platform=railway --dry-run
|
|
380
|
+
|
|
381
|
+
# Review the generated configuration, then deploy:
|
|
374
382
|
railway up
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**2. Set Environment Variables in Railway Dashboard:**
|
|
386
|
+
- `ANTHROPIC_API_KEY` - Required for Claude models
|
|
387
|
+
- `OPENAI_API_KEY` - Optional for OpenAI models
|
|
388
|
+
- `GEMINI_API_KEY` - Optional for Gemini models
|
|
389
|
+
- `STORY_UI_DEV_MODE=true` - Enable file-based story storage
|
|
390
|
+
|
|
391
|
+
**3. Connect External MCP Clients**
|
|
392
|
+
|
|
393
|
+
Once deployed, your Railway instance provides an MCP endpoint that AI clients can connect to:
|
|
375
394
|
|
|
376
|
-
# Set environment variables in Railway dashboard:
|
|
377
|
-
# - ANTHROPIC_API_KEY
|
|
378
|
-
# - OPENAI_API_KEY (optional)
|
|
379
|
-
# - GEMINI_API_KEY (optional)
|
|
380
395
|
```
|
|
396
|
+
https://your-app.up.railway.app/story-ui
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**For Claude Desktop/Claude Code:**
|
|
400
|
+
```bash
|
|
401
|
+
# Add your Railway deployment as an MCP server
|
|
402
|
+
claude mcp add --transport http story-ui https://your-app.up.railway.app/story-ui
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**For other MCP clients**, use the full URL:
|
|
406
|
+
```
|
|
407
|
+
https://your-app.up.railway.app/mcp
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
This allows you to generate stories from Claude Desktop, ChatGPT (with MCP support), or any other MCP-compatible AI client, and see them appear in your deployed Storybook instance.
|
|
381
411
|
|
|
382
412
|
---
|
|
383
413
|
|
package/dist/cli/deploy.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
interface DeployOptions {
|
|
2
|
+
live?: boolean;
|
|
3
|
+
platform?: 'railway' | 'fly';
|
|
4
|
+
projectName?: string;
|
|
5
|
+
dryRun?: boolean;
|
|
2
6
|
backend?: boolean;
|
|
3
7
|
frontend?: boolean;
|
|
4
8
|
app?: boolean;
|
|
5
|
-
platform?: 'railway' | 'render' | 'fly';
|
|
6
9
|
backendUrl?: string;
|
|
7
10
|
storybookDir?: string;
|
|
8
|
-
projectName?: string;
|
|
9
|
-
dryRun?: boolean;
|
|
10
11
|
init?: boolean;
|
|
11
12
|
edge?: boolean;
|
|
12
13
|
pages?: boolean;
|
package/dist/cli/deploy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../cli/deploy.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IAErB,
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../cli/deploy.ts"],"names":[],"mappings":"AASA,UAAU,aAAa;IAErB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AA6hCD,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0JzE"}
|
package/dist/cli/deploy.js
CHANGED
|
@@ -34,6 +34,360 @@ function isToolInstalled(tool) {
|
|
|
34
34
|
return false;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate deployment files for live Storybook deployment
|
|
39
|
+
* This creates Dockerfile, start script, and platform configs
|
|
40
|
+
*/
|
|
41
|
+
function generateLiveDeploymentFiles(projectDir, platform) {
|
|
42
|
+
console.log('📝 Generating deployment files...\n');
|
|
43
|
+
// 1. Create Dockerfile for running both servers
|
|
44
|
+
const dockerfilePath = path.join(projectDir, 'Dockerfile');
|
|
45
|
+
const dockerfile = `# Story UI Live Deployment
|
|
46
|
+
# Runs Storybook in dev mode with Story UI MCP server
|
|
47
|
+
|
|
48
|
+
FROM node:20-slim
|
|
49
|
+
|
|
50
|
+
WORKDIR /app
|
|
51
|
+
|
|
52
|
+
# Install dependencies
|
|
53
|
+
COPY package*.json ./
|
|
54
|
+
RUN npm install
|
|
55
|
+
|
|
56
|
+
# Copy project files
|
|
57
|
+
COPY . .
|
|
58
|
+
|
|
59
|
+
# Make start script executable
|
|
60
|
+
RUN chmod +x ./start-production.sh
|
|
61
|
+
|
|
62
|
+
# Expose ports: Storybook (6006) and MCP server (4005)
|
|
63
|
+
EXPOSE 6006 4005
|
|
64
|
+
|
|
65
|
+
# Start both servers
|
|
66
|
+
CMD ["./start-production.sh"]
|
|
67
|
+
`;
|
|
68
|
+
fs.writeFileSync(dockerfilePath, dockerfile);
|
|
69
|
+
console.log('✅ Created Dockerfile');
|
|
70
|
+
// 2. Create start script that runs both servers
|
|
71
|
+
const startScriptPath = path.join(projectDir, 'start-production.sh');
|
|
72
|
+
const startScript = `#!/bin/bash
|
|
73
|
+
|
|
74
|
+
# Story UI Live Production Start Script
|
|
75
|
+
# Runs Storybook in dev mode with Story UI MCP server
|
|
76
|
+
|
|
77
|
+
echo "🚀 Starting Story UI Live Environment..."
|
|
78
|
+
|
|
79
|
+
# Start Storybook dev server in background
|
|
80
|
+
echo "📖 Starting Storybook dev server on port 6006..."
|
|
81
|
+
npm run storybook -- --port 6006 --host 0.0.0.0 --ci --no-open &
|
|
82
|
+
STORYBOOK_PID=$!
|
|
83
|
+
|
|
84
|
+
# Wait a moment for Storybook to initialize
|
|
85
|
+
sleep 5
|
|
86
|
+
|
|
87
|
+
# Start Story UI MCP server in background
|
|
88
|
+
echo "🤖 Starting Story UI MCP server on port 4005..."
|
|
89
|
+
npx story-ui start --port 4005 &
|
|
90
|
+
MCP_PID=$!
|
|
91
|
+
|
|
92
|
+
echo ""
|
|
93
|
+
echo "✅ Story UI Live Environment is running!"
|
|
94
|
+
echo " 📖 Storybook: http://localhost:6006"
|
|
95
|
+
echo " 🤖 MCP Server: http://localhost:4005"
|
|
96
|
+
echo " 📡 MCP Endpoint: http://localhost:4005/mcp"
|
|
97
|
+
echo ""
|
|
98
|
+
|
|
99
|
+
# Wait for either process to exit
|
|
100
|
+
wait $STORYBOOK_PID $MCP_PID
|
|
101
|
+
`;
|
|
102
|
+
fs.writeFileSync(startScriptPath, startScript);
|
|
103
|
+
fs.chmodSync(startScriptPath, '755');
|
|
104
|
+
console.log('✅ Created start-production.sh');
|
|
105
|
+
// 3. Create platform-specific config
|
|
106
|
+
switch (platform) {
|
|
107
|
+
case 'railway':
|
|
108
|
+
createRailwayConfig(projectDir);
|
|
109
|
+
break;
|
|
110
|
+
case 'fly':
|
|
111
|
+
createFlyConfig(projectDir);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
// 4. Create .dockerignore if it doesn't exist
|
|
115
|
+
const dockerignorePath = path.join(projectDir, '.dockerignore');
|
|
116
|
+
if (!fs.existsSync(dockerignorePath)) {
|
|
117
|
+
const dockerignore = `node_modules
|
|
118
|
+
.git
|
|
119
|
+
.gitignore
|
|
120
|
+
*.md
|
|
121
|
+
.DS_Store
|
|
122
|
+
storybook-static
|
|
123
|
+
dist
|
|
124
|
+
.env.local
|
|
125
|
+
`;
|
|
126
|
+
fs.writeFileSync(dockerignorePath, dockerignore);
|
|
127
|
+
console.log('✅ Created .dockerignore');
|
|
128
|
+
}
|
|
129
|
+
// 5. Update package.json to ensure story-ui is a dependency
|
|
130
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
131
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
132
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
133
|
+
// Add story-ui as a dependency if not present
|
|
134
|
+
if (!packageJson.dependencies?.['@tpitre/story-ui'] && !packageJson.devDependencies?.['@tpitre/story-ui']) {
|
|
135
|
+
packageJson.devDependencies = packageJson.devDependencies || {};
|
|
136
|
+
packageJson.devDependencies['@tpitre/story-ui'] = 'latest';
|
|
137
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
138
|
+
console.log('✅ Added @tpitre/story-ui to package.json');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function createRailwayConfig(projectDir) {
|
|
143
|
+
const railwayJsonPath = path.join(projectDir, 'railway.json');
|
|
144
|
+
const railwayJson = {
|
|
145
|
+
"$schema": "https://railway.app/railway.schema.json",
|
|
146
|
+
"build": {
|
|
147
|
+
"builder": "DOCKERFILE"
|
|
148
|
+
},
|
|
149
|
+
"deploy": {
|
|
150
|
+
"numReplicas": 1,
|
|
151
|
+
"restartPolicyType": "ON_FAILURE"
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
fs.writeFileSync(railwayJsonPath, JSON.stringify(railwayJson, null, 2));
|
|
155
|
+
console.log('✅ Created railway.json');
|
|
156
|
+
// Also create nixpacks.toml as alternative
|
|
157
|
+
const nixpacksPath = path.join(projectDir, 'nixpacks.toml');
|
|
158
|
+
const nixpacks = `[start]
|
|
159
|
+
cmd = "./start-production.sh"
|
|
160
|
+
|
|
161
|
+
[phases.install]
|
|
162
|
+
cmds = ["npm install"]
|
|
163
|
+
|
|
164
|
+
[phases.build]
|
|
165
|
+
cmds = []
|
|
166
|
+
`;
|
|
167
|
+
fs.writeFileSync(nixpacksPath, nixpacks);
|
|
168
|
+
console.log('✅ Created nixpacks.toml (Railway alternative)');
|
|
169
|
+
}
|
|
170
|
+
function createFlyConfig(projectDir) {
|
|
171
|
+
const flyTomlPath = path.join(projectDir, 'fly.toml');
|
|
172
|
+
const projectName = path.basename(projectDir).toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
173
|
+
const flyToml = `app = "${projectName}-story-ui"
|
|
174
|
+
primary_region = "sjc"
|
|
175
|
+
|
|
176
|
+
[build]
|
|
177
|
+
dockerfile = "Dockerfile"
|
|
178
|
+
|
|
179
|
+
[[services]]
|
|
180
|
+
internal_port = 6006
|
|
181
|
+
protocol = "tcp"
|
|
182
|
+
|
|
183
|
+
[[services.ports]]
|
|
184
|
+
handlers = ["http"]
|
|
185
|
+
port = 80
|
|
186
|
+
|
|
187
|
+
[[services.ports]]
|
|
188
|
+
handlers = ["tls", "http"]
|
|
189
|
+
port = 443
|
|
190
|
+
|
|
191
|
+
[[services]]
|
|
192
|
+
internal_port = 4005
|
|
193
|
+
protocol = "tcp"
|
|
194
|
+
|
|
195
|
+
[[services.ports]]
|
|
196
|
+
handlers = ["http"]
|
|
197
|
+
port = 4005
|
|
198
|
+
|
|
199
|
+
[env]
|
|
200
|
+
NODE_ENV = "production"
|
|
201
|
+
`;
|
|
202
|
+
fs.writeFileSync(flyTomlPath, flyToml);
|
|
203
|
+
console.log('✅ Created fly.toml');
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Deploy live Storybook (dev mode) with MCP server to a cloud platform
|
|
207
|
+
* This is the RECOMMENDED approach for production Story UI deployment
|
|
208
|
+
*/
|
|
209
|
+
async function deployLiveStorybook(options) {
|
|
210
|
+
console.log('\n🚀 Story UI Live Deployment');
|
|
211
|
+
console.log('═'.repeat(50));
|
|
212
|
+
console.log('This deploys your Storybook in DEV MODE with the MCP server.');
|
|
213
|
+
console.log('Works with ANY components - exactly like your local environment!\n');
|
|
214
|
+
const projectDir = process.cwd();
|
|
215
|
+
const platform = options.platform || 'railway';
|
|
216
|
+
// Validate project has Storybook
|
|
217
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
218
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
219
|
+
console.error('❌ No package.json found. Run this from your Storybook project root.');
|
|
220
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
221
|
+
}
|
|
222
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
223
|
+
const hasStorybook = packageJson.devDependencies?.storybook ||
|
|
224
|
+
packageJson.dependencies?.storybook ||
|
|
225
|
+
packageJson.devDependencies?.['@storybook/react'] ||
|
|
226
|
+
packageJson.dependencies?.['@storybook/react'];
|
|
227
|
+
if (!hasStorybook) {
|
|
228
|
+
console.error('❌ No Storybook found in package.json.');
|
|
229
|
+
console.log(' Make sure you have Storybook installed: npx storybook@latest init');
|
|
230
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
231
|
+
}
|
|
232
|
+
// Generate deployment files
|
|
233
|
+
generateLiveDeploymentFiles(projectDir, platform);
|
|
234
|
+
if (options.dryRun) {
|
|
235
|
+
console.log('\n[DRY RUN] Deployment files generated. Would deploy to', platform);
|
|
236
|
+
console.log('[DRY RUN] To deploy manually:');
|
|
237
|
+
switch (platform) {
|
|
238
|
+
case 'railway':
|
|
239
|
+
console.log(' 1. railway login');
|
|
240
|
+
console.log(' 2. railway init');
|
|
241
|
+
console.log(' 3. railway up');
|
|
242
|
+
console.log(' 4. railway domain (to get URL)');
|
|
243
|
+
break;
|
|
244
|
+
case 'fly':
|
|
245
|
+
console.log(' 1. fly auth login');
|
|
246
|
+
console.log(' 2. fly launch');
|
|
247
|
+
console.log(' 3. fly secrets set ANTHROPIC_API_KEY=...');
|
|
248
|
+
console.log(' 4. fly deploy');
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
return { storybookUrl: 'https://dry-run.example.com', mcpUrl: 'https://dry-run.example.com:4005/mcp' };
|
|
252
|
+
}
|
|
253
|
+
// Actually deploy based on platform
|
|
254
|
+
console.log(`\n☁️ Deploying to ${platform}...`);
|
|
255
|
+
switch (platform) {
|
|
256
|
+
case 'railway':
|
|
257
|
+
return await deployLiveToRailway(projectDir);
|
|
258
|
+
case 'fly':
|
|
259
|
+
return await deployLiveToFly(projectDir);
|
|
260
|
+
default:
|
|
261
|
+
console.error(`❌ Unknown platform: ${platform}`);
|
|
262
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async function deployLiveToRailway(projectDir) {
|
|
266
|
+
console.log('\n🚂 Deploying to Railway...\n');
|
|
267
|
+
if (!isToolInstalled('railway')) {
|
|
268
|
+
console.log('📦 Railway CLI not found. Installing...');
|
|
269
|
+
try {
|
|
270
|
+
execSync('npm install -g @railway/cli', { stdio: 'inherit' });
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
console.error('❌ Failed to install Railway CLI');
|
|
274
|
+
console.log(' Install manually: npm install -g @railway/cli');
|
|
275
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Check if logged in
|
|
279
|
+
try {
|
|
280
|
+
execSync('railway whoami', { stdio: 'pipe' });
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
console.log('🔐 Not logged into Railway. Please login:');
|
|
284
|
+
execSync('railway login', { stdio: 'inherit' });
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
// Check if project is linked
|
|
288
|
+
try {
|
|
289
|
+
execSync('railway status', { cwd: projectDir, stdio: 'pipe' });
|
|
290
|
+
console.log('✅ Railway project already linked');
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
console.log('📁 Creating new Railway project...');
|
|
294
|
+
execSync('railway init', { cwd: projectDir, stdio: 'inherit' });
|
|
295
|
+
}
|
|
296
|
+
// Set environment variables reminder
|
|
297
|
+
console.log('\n⚠️ Remember to set your API keys in Railway dashboard:');
|
|
298
|
+
console.log(' railway variables set ANTHROPIC_API_KEY=your-key');
|
|
299
|
+
console.log(' (or OPENAI_API_KEY, GEMINI_API_KEY)\n');
|
|
300
|
+
// Deploy
|
|
301
|
+
console.log('🚀 Deploying to Railway...');
|
|
302
|
+
const result = execSync('railway up --detach 2>&1', {
|
|
303
|
+
cwd: projectDir,
|
|
304
|
+
encoding: 'utf-8'
|
|
305
|
+
});
|
|
306
|
+
console.log(result);
|
|
307
|
+
// Get the deployment URL
|
|
308
|
+
console.log('\n📋 Getting deployment URL...');
|
|
309
|
+
try {
|
|
310
|
+
const urlResult = execSync('railway domain 2>&1', {
|
|
311
|
+
cwd: projectDir,
|
|
312
|
+
encoding: 'utf-8'
|
|
313
|
+
}).trim();
|
|
314
|
+
if (urlResult && !urlResult.includes('No domain')) {
|
|
315
|
+
const storybookUrl = `https://${urlResult}`;
|
|
316
|
+
const mcpUrl = `https://${urlResult}:4005/mcp`;
|
|
317
|
+
console.log(`\n✅ Deployment successful!`);
|
|
318
|
+
console.log(` 📖 Storybook: ${storybookUrl}`);
|
|
319
|
+
console.log(` 🤖 MCP Server: ${mcpUrl}`);
|
|
320
|
+
return { storybookUrl, mcpUrl };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
console.log('⚠️ Could not get domain automatically.');
|
|
325
|
+
}
|
|
326
|
+
// Try to generate a domain
|
|
327
|
+
console.log('🌐 Generating Railway domain...');
|
|
328
|
+
execSync('railway domain', { cwd: projectDir, stdio: 'inherit' });
|
|
329
|
+
console.log('\n✅ Deployment submitted!');
|
|
330
|
+
console.log(' Run "railway domain" to get your deployment URL.');
|
|
331
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
console.error('❌ Railway deployment failed:', error.message);
|
|
335
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async function deployLiveToFly(projectDir) {
|
|
339
|
+
console.log('\n🪁 Deploying to Fly.io...\n');
|
|
340
|
+
const flyCmd = isToolInstalled('flyctl') ? 'flyctl' : (isToolInstalled('fly') ? 'fly' : null);
|
|
341
|
+
if (!flyCmd) {
|
|
342
|
+
console.log('📦 Fly CLI not found. Installing...');
|
|
343
|
+
try {
|
|
344
|
+
execSync('curl -L https://fly.io/install.sh | sh', { stdio: 'inherit' });
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
console.error('❌ Failed to install Fly CLI');
|
|
348
|
+
console.log(' Install manually: https://fly.io/docs/hands-on/install-flyctl/');
|
|
349
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const cmd = flyCmd || 'fly';
|
|
353
|
+
try {
|
|
354
|
+
// Check if logged in
|
|
355
|
+
try {
|
|
356
|
+
execSync(`${cmd} auth whoami`, { stdio: 'pipe' });
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
console.log('🔐 Not logged into Fly.io. Please login:');
|
|
360
|
+
execSync(`${cmd} auth login`, { stdio: 'inherit' });
|
|
361
|
+
}
|
|
362
|
+
// Launch or deploy
|
|
363
|
+
try {
|
|
364
|
+
execSync(`${cmd} status`, { cwd: projectDir, stdio: 'pipe' });
|
|
365
|
+
console.log('🚀 Deploying to existing Fly app...');
|
|
366
|
+
execSync(`${cmd} deploy`, { cwd: projectDir, stdio: 'inherit' });
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
console.log('📁 Creating new Fly app...');
|
|
370
|
+
execSync(`${cmd} launch --no-deploy`, { cwd: projectDir, stdio: 'inherit' });
|
|
371
|
+
console.log('\n⚠️ Before deploying, set your secrets:');
|
|
372
|
+
console.log(` ${cmd} secrets set ANTHROPIC_API_KEY=your-key`);
|
|
373
|
+
console.log('\n Then run:');
|
|
374
|
+
console.log(` ${cmd} deploy`);
|
|
375
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
376
|
+
}
|
|
377
|
+
// Get URL
|
|
378
|
+
const appName = path.basename(projectDir).toLowerCase().replace(/[^a-z0-9-]/g, '-') + '-story-ui';
|
|
379
|
+
const storybookUrl = `https://${appName}.fly.dev`;
|
|
380
|
+
const mcpUrl = `https://${appName}.fly.dev:4005/mcp`;
|
|
381
|
+
console.log(`\n✅ Deployment successful!`);
|
|
382
|
+
console.log(` 📖 Storybook: ${storybookUrl}`);
|
|
383
|
+
console.log(` 🤖 MCP Server: ${mcpUrl}`);
|
|
384
|
+
return { storybookUrl, mcpUrl };
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
console.error('❌ Fly.io deployment failed:', error.message);
|
|
388
|
+
return { storybookUrl: null, mcpUrl: null };
|
|
389
|
+
}
|
|
390
|
+
}
|
|
37
391
|
/**
|
|
38
392
|
* Deploy backend to Railway
|
|
39
393
|
*/
|
|
@@ -116,61 +470,6 @@ async function deployToRailway(dryRun) {
|
|
|
116
470
|
return null;
|
|
117
471
|
}
|
|
118
472
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Deploy backend to Render
|
|
121
|
-
*/
|
|
122
|
-
async function deployToRender(dryRun) {
|
|
123
|
-
console.log('\n🎨 Deploying backend to Render...\n');
|
|
124
|
-
const pkgRoot = getPackageRoot();
|
|
125
|
-
// Create render.yaml if it doesn't exist
|
|
126
|
-
const renderYamlPath = path.join(pkgRoot, 'render.yaml');
|
|
127
|
-
if (!fs.existsSync(renderYamlPath)) {
|
|
128
|
-
console.log('📝 Creating render.yaml...');
|
|
129
|
-
const renderYaml = `services:
|
|
130
|
-
- type: web
|
|
131
|
-
name: story-ui-backend
|
|
132
|
-
env: node
|
|
133
|
-
buildCommand: npm install && npm run build
|
|
134
|
-
startCommand: node dist/mcp-server/index.js
|
|
135
|
-
healthCheckPath: /story-ui/providers
|
|
136
|
-
envVars:
|
|
137
|
-
- key: NODE_ENV
|
|
138
|
-
value: production
|
|
139
|
-
- key: PORT
|
|
140
|
-
value: 4001
|
|
141
|
-
- key: CLAUDE_API_KEY
|
|
142
|
-
sync: false
|
|
143
|
-
- key: OPENAI_API_KEY
|
|
144
|
-
sync: false
|
|
145
|
-
- key: GEMINI_API_KEY
|
|
146
|
-
sync: false
|
|
147
|
-
`;
|
|
148
|
-
fs.writeFileSync(renderYamlPath, renderYaml);
|
|
149
|
-
console.log('✅ Created render.yaml');
|
|
150
|
-
}
|
|
151
|
-
if (dryRun) {
|
|
152
|
-
console.log('[DRY RUN] render.yaml created at:', renderYamlPath);
|
|
153
|
-
console.log('[DRY RUN] To deploy:');
|
|
154
|
-
console.log(' 1. Push this repo to GitHub');
|
|
155
|
-
console.log(' 2. Go to https://render.com');
|
|
156
|
-
console.log(' 3. Create new Web Service from your repo');
|
|
157
|
-
console.log(' 4. Set environment variables');
|
|
158
|
-
return 'https://dry-run.onrender.com';
|
|
159
|
-
}
|
|
160
|
-
console.log('\n📋 Render deployment is Git-based.');
|
|
161
|
-
console.log(' To deploy to Render:\n');
|
|
162
|
-
console.log(' 1. Push your code to GitHub/GitLab');
|
|
163
|
-
console.log(' 2. Go to https://dashboard.render.com');
|
|
164
|
-
console.log(' 3. Click "New" → "Web Service"');
|
|
165
|
-
console.log(' 4. Connect your repository');
|
|
166
|
-
console.log(' 5. Render will auto-detect the render.yaml config');
|
|
167
|
-
console.log(' 6. Add your API keys as environment variables:');
|
|
168
|
-
console.log(' - CLAUDE_API_KEY');
|
|
169
|
-
console.log(' - OPENAI_API_KEY');
|
|
170
|
-
console.log(' - GEMINI_API_KEY');
|
|
171
|
-
console.log('\n render.yaml has been created in your project root.');
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
473
|
/**
|
|
175
474
|
* Deploy backend to Fly.io
|
|
176
475
|
*/
|
|
@@ -334,12 +633,12 @@ async function deployStorybook(backendUrl, storybookDir, projectName, dryRun) {
|
|
|
334
633
|
}
|
|
335
634
|
}
|
|
336
635
|
/**
|
|
337
|
-
* Build and deploy standalone production app
|
|
636
|
+
* Build and deploy standalone production app
|
|
338
637
|
* This builds a React app with the user's component library bundled in
|
|
339
638
|
*/
|
|
340
639
|
async function deployProductionApp(backendUrl, projectName, dryRun) {
|
|
341
640
|
console.log('\n🚀 Building Standalone Production App...\n');
|
|
342
|
-
console.log(' This creates a
|
|
641
|
+
console.log(' This creates a standalone web app with your component library\n');
|
|
343
642
|
const pkgRoot = getPackageRoot();
|
|
344
643
|
const userCwd = process.cwd();
|
|
345
644
|
const templateDir = path.join(pkgRoot, 'templates/production-app');
|
|
@@ -616,7 +915,7 @@ function printSummary(backendUrl, frontendUrl, appUrl) {
|
|
|
616
915
|
}
|
|
617
916
|
if (appUrl) {
|
|
618
917
|
console.log(`\n🚀 Production App: ${appUrl}`);
|
|
619
|
-
console.log(' This is your
|
|
918
|
+
console.log(' This is your standalone web app with your component library');
|
|
620
919
|
console.log(' Users can prompt and see live-rendered components!');
|
|
621
920
|
}
|
|
622
921
|
if (frontendUrl) {
|
|
@@ -660,7 +959,32 @@ export async function deployCommand(options) {
|
|
|
660
959
|
await legacyEdgeDeployment(options);
|
|
661
960
|
return;
|
|
662
961
|
}
|
|
663
|
-
//
|
|
962
|
+
// NEW RECOMMENDED: Live Storybook deployment
|
|
963
|
+
// Runs Storybook in dev mode with MCP server - works with ANY components
|
|
964
|
+
if (options.live) {
|
|
965
|
+
const result = await deployLiveStorybook(options);
|
|
966
|
+
if (result.storybookUrl || result.mcpUrl) {
|
|
967
|
+
console.log('\n' + '═'.repeat(60));
|
|
968
|
+
console.log('📋 LIVE DEPLOYMENT SUMMARY');
|
|
969
|
+
console.log('═'.repeat(60));
|
|
970
|
+
if (result.storybookUrl) {
|
|
971
|
+
console.log(`\n📖 Storybook (Live Dev Mode): ${result.storybookUrl}`);
|
|
972
|
+
console.log(' This runs in dev mode - Story UI can generate & hot-reload stories!');
|
|
973
|
+
}
|
|
974
|
+
if (result.mcpUrl) {
|
|
975
|
+
console.log(`\n🤖 MCP Server: ${result.mcpUrl}`);
|
|
976
|
+
console.log(' Connect Claude Desktop with:');
|
|
977
|
+
console.log(` claude mcp add --transport http story-ui ${result.mcpUrl}`);
|
|
978
|
+
}
|
|
979
|
+
console.log('\n✅ This is the EXACT same experience as local development!');
|
|
980
|
+
console.log(' - Works with ANY components (custom, Tailwind, multiple libraries)');
|
|
981
|
+
console.log(' - Generated stories are hot-reloaded instantly');
|
|
982
|
+
console.log(' - MCP server accessible from anywhere');
|
|
983
|
+
console.log('\n' + '═'.repeat(60));
|
|
984
|
+
}
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
// Legacy deployment flows
|
|
664
988
|
let backendUrl = options.backendUrl || null;
|
|
665
989
|
let frontendUrl = null;
|
|
666
990
|
let appUrl = null;
|
|
@@ -671,15 +995,12 @@ export async function deployCommand(options) {
|
|
|
671
995
|
case 'railway':
|
|
672
996
|
backendUrl = await deployToRailway(options.dryRun || false);
|
|
673
997
|
break;
|
|
674
|
-
case 'render':
|
|
675
|
-
backendUrl = await deployToRender(options.dryRun || false);
|
|
676
|
-
break;
|
|
677
998
|
case 'fly':
|
|
678
999
|
backendUrl = await deployToFly(options.dryRun || false);
|
|
679
1000
|
break;
|
|
680
1001
|
default:
|
|
681
1002
|
console.error(`❌ Unknown platform: ${platform}`);
|
|
682
|
-
console.log(' Supported platforms: railway,
|
|
1003
|
+
console.log(' Supported platforms: railway, fly');
|
|
683
1004
|
return;
|
|
684
1005
|
}
|
|
685
1006
|
if (!backendUrl && !options.dryRun) {
|
|
@@ -717,40 +1038,45 @@ export async function deployCommand(options) {
|
|
|
717
1038
|
printSummary(backendUrl, frontendUrl, appUrl);
|
|
718
1039
|
}
|
|
719
1040
|
// Show help if no flags provided
|
|
720
|
-
if (!options.backend && !options.frontend && !options.app && !options.edge && !options.pages && !options.all && !options.init) {
|
|
721
|
-
console.log('Story UI Deployment - Deploy your
|
|
722
|
-
console.log('
|
|
723
|
-
console.log('
|
|
724
|
-
console.log('
|
|
725
|
-
console.log(' --
|
|
726
|
-
console.log('
|
|
727
|
-
console.log(' --platform <name>
|
|
728
|
-
console.log(' --
|
|
729
|
-
console.log(' --project-name <name> Project name prefix (default: story-ui)');
|
|
730
|
-
console.log(' --dry-run Show what would be deployed\n');
|
|
1041
|
+
if (!options.backend && !options.frontend && !options.app && !options.live && !options.edge && !options.pages && !options.all && !options.init) {
|
|
1042
|
+
console.log('Story UI Deployment - Deploy your Storybook with AI story generation\n');
|
|
1043
|
+
console.log('═'.repeat(60));
|
|
1044
|
+
console.log(' RECOMMENDED: Live Storybook Deployment');
|
|
1045
|
+
console.log('═'.repeat(60));
|
|
1046
|
+
console.log(' --live Deploy Storybook in DEV MODE with MCP server');
|
|
1047
|
+
console.log(' Works with ANY components - exactly like local dev!');
|
|
1048
|
+
console.log(' --platform <name> Platform: railway (default), fly');
|
|
1049
|
+
console.log(' --dry-run Generate deployment files only\n');
|
|
731
1050
|
console.log('EXAMPLES:');
|
|
732
|
-
console.log('─'.repeat(
|
|
733
|
-
console.log(' # Deploy
|
|
734
|
-
console.log(' npx story-ui deploy --
|
|
735
|
-
console.log(' # Deploy
|
|
736
|
-
console.log(' npx story-ui deploy --
|
|
737
|
-
console.log(' #
|
|
738
|
-
console.log(' npx story-ui deploy --
|
|
739
|
-
console.log('
|
|
740
|
-
console.log('
|
|
741
|
-
console.log('
|
|
742
|
-
console.log('
|
|
743
|
-
console.log('
|
|
744
|
-
console.log('
|
|
745
|
-
console.log('
|
|
1051
|
+
console.log('─'.repeat(60));
|
|
1052
|
+
console.log(' # Deploy your Storybook to Railway (recommended)');
|
|
1053
|
+
console.log(' npx story-ui deploy --live\n');
|
|
1054
|
+
console.log(' # Deploy to Fly.io');
|
|
1055
|
+
console.log(' npx story-ui deploy --live --platform=fly\n');
|
|
1056
|
+
console.log(' # Just generate deployment files (no actual deploy)');
|
|
1057
|
+
console.log(' npx story-ui deploy --live --dry-run\n');
|
|
1058
|
+
console.log('WHY --live IS RECOMMENDED:');
|
|
1059
|
+
console.log('─'.repeat(60));
|
|
1060
|
+
console.log(' - Works with ANY components (custom, Tailwind, multiple libraries)');
|
|
1061
|
+
console.log(' - Exactly the same experience as local development');
|
|
1062
|
+
console.log(' - Story UI writes stories to disk, Storybook hot-reloads them');
|
|
1063
|
+
console.log(' - MCP server accessible from Claude Desktop anywhere');
|
|
1064
|
+
console.log(' - No design system lock-in - completely agnostic\n');
|
|
1065
|
+
console.log('ENVIRONMENT VARIABLES (set on your platform):');
|
|
1066
|
+
console.log('─'.repeat(60));
|
|
1067
|
+
console.log(' ANTHROPIC_API_KEY - Claude API key (recommended)');
|
|
1068
|
+
console.log(' OPENAI_API_KEY - OpenAI API key (optional)');
|
|
1069
|
+
console.log(' GEMINI_API_KEY - Google Gemini API key (optional)');
|
|
746
1070
|
console.log(' (Set at least one of these)\n');
|
|
747
|
-
console.log('
|
|
748
|
-
console.log('─'.repeat(
|
|
749
|
-
console.log(' --
|
|
750
|
-
console.log(' --
|
|
751
|
-
console.log('
|
|
752
|
-
console.log('
|
|
1071
|
+
console.log('ALTERNATIVE APPROACHES (for specific use cases):');
|
|
1072
|
+
console.log('─'.repeat(60));
|
|
1073
|
+
console.log(' --backend Deploy only the MCP server backend');
|
|
1074
|
+
console.log(' --app Deploy standalone production app (static)');
|
|
1075
|
+
console.log(' --frontend Deploy Storybook static build');
|
|
1076
|
+
console.log(' --backend-url <url> Use existing backend URL\n');
|
|
1077
|
+
console.log('DEPRECATED:');
|
|
1078
|
+
console.log('─'.repeat(60));
|
|
753
1079
|
console.log(' --init, --edge, --pages, --all');
|
|
754
|
-
console.log(' These are deprecated. Use --
|
|
1080
|
+
console.log(' These Cloudflare Edge options are deprecated. Use --live instead.\n');
|
|
755
1081
|
}
|
|
756
1082
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -264,21 +264,23 @@ program
|
|
|
264
264
|
});
|
|
265
265
|
program
|
|
266
266
|
.command('deploy')
|
|
267
|
-
.description('Deploy Story UI to production
|
|
268
|
-
//
|
|
269
|
-
.option('--
|
|
270
|
-
.option('--
|
|
271
|
-
.option('--
|
|
272
|
-
|
|
273
|
-
.option('--backend
|
|
274
|
-
.option('--
|
|
267
|
+
.description('Deploy Story UI to production')
|
|
268
|
+
// RECOMMENDED: Live Storybook deployment
|
|
269
|
+
.option('--live', 'Deploy Storybook in DEV MODE with MCP server (RECOMMENDED)')
|
|
270
|
+
.option('--platform <platform>', 'Platform: railway (default), render, fly', 'railway')
|
|
271
|
+
.option('--dry-run', 'Generate deployment files only, don\'t deploy')
|
|
272
|
+
// Alternative approaches
|
|
273
|
+
.option('--backend', 'Deploy only the MCP server backend')
|
|
274
|
+
.option('--app', 'Deploy standalone production app (static build)')
|
|
275
|
+
.option('--frontend', 'Deploy Storybook static build (legacy)')
|
|
276
|
+
.option('--backend-url <url>', 'Use existing backend URL for app/frontend')
|
|
277
|
+
.option('--storybook-dir <dir>', 'Path to Storybook project')
|
|
275
278
|
.option('--project-name <name>', 'Project name prefix', 'story-ui')
|
|
276
|
-
.option('--dry-run', 'Show what would be deployed without deploying')
|
|
277
279
|
// Legacy flags (deprecated)
|
|
278
|
-
.option('--init', '[DEPRECATED]
|
|
279
|
-
.option('--edge', '[DEPRECATED]
|
|
280
|
-
.option('--pages', '[DEPRECATED]
|
|
281
|
-
.option('--all', '[DEPRECATED]
|
|
280
|
+
.option('--init', '[DEPRECATED] Use --live instead')
|
|
281
|
+
.option('--edge', '[DEPRECATED] Use --live instead')
|
|
282
|
+
.option('--pages', '[DEPRECATED] Use --live instead')
|
|
283
|
+
.option('--all', '[DEPRECATED] Use --live instead')
|
|
282
284
|
.action(async (options) => {
|
|
283
285
|
await deployCommand(options);
|
|
284
286
|
});
|
package/dist/cli/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../cli/setup.ts"],"names":[],"mappings":"AAkCA;;GAEG;AACH,wBAAgB,iCAAiC,SA8ChD;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../cli/setup.ts"],"names":[],"mappings":"AAkCA;;GAEG;AACH,wBAAgB,iCAAiC,SA8ChD;AA2VD,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC7C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,YAAiB,iBAwsB5D"}
|
package/dist/cli/setup.js
CHANGED
|
@@ -87,7 +87,7 @@ function setupStorybookPreview(designSystem) {
|
|
|
87
87
|
return;
|
|
88
88
|
}
|
|
89
89
|
// Verify required packages are installed before creating preview
|
|
90
|
-
if (['
|
|
90
|
+
if (['mantine', 'chakra'].includes(designSystem)) {
|
|
91
91
|
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
92
92
|
if (fs.existsSync(packageJsonPath)) {
|
|
93
93
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
@@ -119,18 +119,6 @@ function setupStorybookPreview(designSystem) {
|
|
|
119
119
|
<ChakraProvider value={defaultSystem}>
|
|
120
120
|
<Story />
|
|
121
121
|
</ChakraProvider>
|
|
122
|
-
)`
|
|
123
|
-
},
|
|
124
|
-
antd: {
|
|
125
|
-
imports: [
|
|
126
|
-
"import type { Preview } from '@storybook/react-vite'",
|
|
127
|
-
"import { ConfigProvider } from 'antd'",
|
|
128
|
-
"import React from 'react'"
|
|
129
|
-
],
|
|
130
|
-
decorator: `(Story) => (
|
|
131
|
-
<ConfigProvider>
|
|
132
|
-
<Story />
|
|
133
|
-
</ConfigProvider>
|
|
134
122
|
)`
|
|
135
123
|
},
|
|
136
124
|
mantine: {
|
|
@@ -144,18 +132,6 @@ function setupStorybookPreview(designSystem) {
|
|
|
144
132
|
<MantineProvider>
|
|
145
133
|
<Story />
|
|
146
134
|
</MantineProvider>
|
|
147
|
-
)`
|
|
148
|
-
},
|
|
149
|
-
shadcn: {
|
|
150
|
-
imports: [
|
|
151
|
-
"import type { Preview } from '@storybook/react-vite'",
|
|
152
|
-
"import '../src/index.css'", // or globals.css for Tailwind styles
|
|
153
|
-
"import React from 'react'"
|
|
154
|
-
],
|
|
155
|
-
decorator: `(Story) => (
|
|
156
|
-
<div className="min-h-screen bg-background text-foreground">
|
|
157
|
-
<Story />
|
|
158
|
-
</div>
|
|
159
135
|
)`
|
|
160
136
|
}
|
|
161
137
|
};
|
|
@@ -199,16 +175,16 @@ const LLM_PROVIDERS = {
|
|
|
199
175
|
description: 'Recommended - Best for complex reasoning and code quality'
|
|
200
176
|
},
|
|
201
177
|
openai: {
|
|
202
|
-
name: 'OpenAI (GPT
|
|
178
|
+
name: 'OpenAI (GPT)',
|
|
203
179
|
envKey: 'OPENAI_API_KEY',
|
|
204
|
-
models: ['gpt-5.1', 'gpt-5-
|
|
180
|
+
models: ['gpt-5.1', 'gpt-5.1-thinking', 'gpt-4o', 'gpt-4o-mini'],
|
|
205
181
|
docsUrl: 'https://platform.openai.com/api-keys',
|
|
206
182
|
description: 'Versatile and fast'
|
|
207
183
|
},
|
|
208
184
|
gemini: {
|
|
209
185
|
name: 'Google Gemini',
|
|
210
186
|
envKey: 'GEMINI_API_KEY',
|
|
211
|
-
models: ['gemini-3-pro
|
|
187
|
+
models: ['gemini-3-pro', 'gemini-2.0-flash-exp', 'gemini-2.0-flash', 'gemini-1.5-pro'],
|
|
212
188
|
docsUrl: 'https://aistudio.google.com/app/apikey',
|
|
213
189
|
description: 'Cost-effective with good performance'
|
|
214
190
|
}
|
|
@@ -216,13 +192,6 @@ const LLM_PROVIDERS = {
|
|
|
216
192
|
// Design system installation configurations (organized by framework)
|
|
217
193
|
const DESIGN_SYSTEM_CONFIGS = {
|
|
218
194
|
// React design systems
|
|
219
|
-
antd: {
|
|
220
|
-
packages: ['antd'],
|
|
221
|
-
name: 'Ant Design',
|
|
222
|
-
importPath: 'antd',
|
|
223
|
-
additionalSetup: 'import "antd/dist/reset.css";',
|
|
224
|
-
framework: 'react'
|
|
225
|
-
},
|
|
226
195
|
mantine: {
|
|
227
196
|
packages: ['@mantine/core', '@mantine/hooks', '@mantine/notifications'],
|
|
228
197
|
name: 'Mantine',
|
|
@@ -244,13 +213,6 @@ const DESIGN_SYSTEM_CONFIGS = {
|
|
|
244
213
|
additionalSetup: 'import { ThemeProvider } from "@mui/material/styles";',
|
|
245
214
|
framework: 'react'
|
|
246
215
|
},
|
|
247
|
-
shadcn: {
|
|
248
|
-
packages: ['class-variance-authority', 'clsx', 'tailwind-merge', '@radix-ui/react-slot', 'lucide-react'],
|
|
249
|
-
name: 'shadcn/ui',
|
|
250
|
-
importPath: '@/components/ui',
|
|
251
|
-
additionalSetup: '// shadcn/ui components are locally installed. Run: npx shadcn@latest init',
|
|
252
|
-
framework: 'react'
|
|
253
|
-
},
|
|
254
216
|
// Angular design systems
|
|
255
217
|
'angular-material': {
|
|
256
218
|
packages: ['@angular/material', '@angular/cdk'],
|
|
@@ -541,10 +503,13 @@ export async function setupCommand(options = {}) {
|
|
|
541
503
|
return [
|
|
542
504
|
baseChoice,
|
|
543
505
|
{ name: '🎯 Mantine (@mantine/core) - Most Popular', value: 'mantine' },
|
|
506
|
+
{ name: '⚡ Chakra UI (@chakra-ui/react)', value: 'chakra' },
|
|
507
|
+
{ name: '🎨 Material UI (@mui/material)', value: 'mui' },
|
|
544
508
|
customChoice
|
|
545
509
|
];
|
|
546
510
|
}
|
|
547
511
|
};
|
|
512
|
+
;
|
|
548
513
|
// Non-interactive mode: build answers from CLI options
|
|
549
514
|
let answers;
|
|
550
515
|
if (options.yes || options.designSystem) {
|
|
@@ -767,31 +732,6 @@ export async function setupCommand(options = {}) {
|
|
|
767
732
|
}
|
|
768
733
|
};
|
|
769
734
|
}
|
|
770
|
-
else if (answers.designSystem === 'antd') {
|
|
771
|
-
config = {
|
|
772
|
-
importPath: 'antd',
|
|
773
|
-
componentPrefix: '',
|
|
774
|
-
layoutRules: {
|
|
775
|
-
multiColumnWrapper: 'Row',
|
|
776
|
-
columnComponent: 'Col',
|
|
777
|
-
containerComponent: 'div',
|
|
778
|
-
layoutExamples: {
|
|
779
|
-
twoColumn: `<Row gutter={16}>
|
|
780
|
-
<Col span={12}>
|
|
781
|
-
<Card title="Left Card" bordered={false}>
|
|
782
|
-
<p>Left content goes here</p>
|
|
783
|
-
</Card>
|
|
784
|
-
</Col>
|
|
785
|
-
<Col span={12}>
|
|
786
|
-
<Card title="Right Card" bordered={false}>
|
|
787
|
-
<p>Right content goes here</p>
|
|
788
|
-
</Card>
|
|
789
|
-
</Col>
|
|
790
|
-
</Row>`
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
735
|
else if (answers.designSystem === 'mantine') {
|
|
796
736
|
config = {
|
|
797
737
|
importPath: '@mantine/core',
|
|
@@ -823,52 +763,6 @@ export async function setupCommand(options = {}) {
|
|
|
823
763
|
}
|
|
824
764
|
};
|
|
825
765
|
}
|
|
826
|
-
else if (answers.designSystem === 'shadcn') {
|
|
827
|
-
config = {
|
|
828
|
-
importPath: '@/components/ui',
|
|
829
|
-
componentPrefix: '',
|
|
830
|
-
layoutRules: {
|
|
831
|
-
multiColumnWrapper: 'div',
|
|
832
|
-
columnComponent: 'div',
|
|
833
|
-
containerComponent: 'div',
|
|
834
|
-
layoutExamples: {
|
|
835
|
-
twoColumn: `<div className="grid grid-cols-2 gap-4">
|
|
836
|
-
<Card>
|
|
837
|
-
<CardHeader>
|
|
838
|
-
<CardTitle>Left Card</CardTitle>
|
|
839
|
-
</CardHeader>
|
|
840
|
-
<CardContent>
|
|
841
|
-
<p className="text-sm text-muted-foreground">
|
|
842
|
-
Left content goes here
|
|
843
|
-
</p>
|
|
844
|
-
</CardContent>
|
|
845
|
-
</Card>
|
|
846
|
-
<Card>
|
|
847
|
-
<CardHeader>
|
|
848
|
-
<CardTitle>Right Card</CardTitle>
|
|
849
|
-
</CardHeader>
|
|
850
|
-
<CardContent>
|
|
851
|
-
<p className="text-sm text-muted-foreground">
|
|
852
|
-
Right content goes here
|
|
853
|
-
</p>
|
|
854
|
-
</CardContent>
|
|
855
|
-
</Card>
|
|
856
|
-
</div>`
|
|
857
|
-
}
|
|
858
|
-
},
|
|
859
|
-
designSystemGuidelines: {
|
|
860
|
-
name: 'shadcn/ui',
|
|
861
|
-
additionalNotes: `
|
|
862
|
-
shadcn/ui components are locally installed in the project.
|
|
863
|
-
- Import components from "@/components/ui" (e.g., import { Button } from "@/components/ui/button")
|
|
864
|
-
- Use the cn() utility from "@/lib/utils" for conditional classes
|
|
865
|
-
- Components use Tailwind CSS for styling
|
|
866
|
-
- Use CSS variables for theming (--primary, --secondary, --muted, etc.)
|
|
867
|
-
- Prefer composition over configuration
|
|
868
|
-
`.trim()
|
|
869
|
-
}
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
766
|
else if (answers.designSystem === 'mui') {
|
|
873
767
|
config = {
|
|
874
768
|
importPath: '@mui/material',
|
|
@@ -18,7 +18,7 @@ import { logger } from '../logger.js';
|
|
|
18
18
|
*/
|
|
19
19
|
export function loadSettingsConfig() {
|
|
20
20
|
const defaultProvider = process.env.DEFAULT_PROVIDER || 'claude';
|
|
21
|
-
const defaultModel = process.env.DEFAULT_MODEL || 'claude-
|
|
21
|
+
const defaultModel = process.env.DEFAULT_MODEL || 'claude-opus-4-5-20251101';
|
|
22
22
|
// Parse allowed providers
|
|
23
23
|
const allowedProvidersEnv = process.env.ALLOWED_PROVIDERS;
|
|
24
24
|
const allowedProviders = allowedProvidersEnv
|
|
@@ -79,14 +79,14 @@ export function getAvailableModels(provider, config) {
|
|
|
79
79
|
// Mark recommended models based on capabilities
|
|
80
80
|
const recommendedModels = [
|
|
81
81
|
// Claude
|
|
82
|
+
'claude-opus-4-5-20251101', // Claude Opus 4.5 - flagship
|
|
82
83
|
'claude-sonnet-4-5-20250929',
|
|
83
|
-
'claude-opus-4-5-20251101',
|
|
84
84
|
// OpenAI
|
|
85
|
-
'gpt-5.1',
|
|
85
|
+
'gpt-5.1', // GPT-5.1 - flagship
|
|
86
86
|
'gpt-4o',
|
|
87
87
|
// Gemini
|
|
88
|
+
'gemini-3-pro-preview', // Gemini 3 Pro Preview - flagship
|
|
88
89
|
'gemini-3-pro',
|
|
89
|
-
'gemini-2.0-flash',
|
|
90
90
|
];
|
|
91
91
|
return filteredModels.map((model) => ({
|
|
92
92
|
id: model.id,
|
|
@@ -1 +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;
|
|
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;IAuBnC;;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"}
|
|
@@ -14,6 +14,12 @@ export class ProductionGitignoreManager {
|
|
|
14
14
|
* Detects if we're running in a production/read-only environment
|
|
15
15
|
*/
|
|
16
16
|
detectProductionEnvironment() {
|
|
17
|
+
// Explicit override: Force development mode for file-based story generation
|
|
18
|
+
// Use this on Railway/Render when running Storybook dev mode
|
|
19
|
+
if (process.env.STORY_UI_DEV_MODE === 'true') {
|
|
20
|
+
logger.log('📁 STORY_UI_DEV_MODE=true - forcing file-based story generation');
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
17
23
|
// Check common production environment indicators
|
|
18
24
|
const prodIndicators = [
|
|
19
25
|
process.env.NODE_ENV === 'production',
|