ebade 0.2.2 → 0.4.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/CHANGELOG.md +5 -0
- package/README.md +49 -38
- package/ROADMAP.md +19 -14
- package/cli/scaffold.js +502 -186
- package/cli/simulate.js +102 -0
- package/cli/templates/feature-grid.tsx +80 -0
- package/cli/templates/footer.tsx +121 -0
- package/cli/templates/hero-section.tsx +34 -0
- package/cli/templates/login-form.tsx +124 -0
- package/cli/templates/navbar.tsx +53 -0
- package/cli/templates/pricing-table.tsx +140 -0
- package/cli/templates/signup-form.tsx +111 -0
- package/demo.tape +2 -2
- package/examples/saas-dashboard.ebade.yaml +2 -0
- package/netlify.toml +7 -0
- package/package.json +3 -1
- package/packages/mcp-server/README.md +3 -3
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/index.ts +12 -16
- package/packages/mcp-server/src/tools/scaffold.ts +153 -404
- package/packages/vscode-extension/README.md +45 -0
- package/packages/vscode-extension/ebade-0.1.0.vsix +0 -0
- package/packages/vscode-extension/ebade-0.3.0.vsix +0 -0
- package/packages/vscode-extension/ebade-0.3.1.vsix +0 -0
- package/packages/vscode-extension/ebade-0.3.2.vsix +0 -0
- package/packages/vscode-extension/images/icon.png +0 -0
- package/packages/vscode-extension/language-configuration.json +24 -0
- package/packages/vscode-extension/package.json +54 -0
- package/packages/vscode-extension/snippets/ebade.json +86 -0
- package/packages/vscode-extension/syntaxes/ebade.tmLanguage.json +54 -0
- package/www/README.md +36 -0
- package/www/app/favicon.ico +0 -0
- package/www/app/globals.css +1256 -0
- package/www/app/layout.tsx +66 -0
- package/www/app/page.tsx +374 -0
- package/www/app/playground/page.tsx +627 -0
- package/www/components/ThreeCanvas.tsx +156 -0
- package/www/next.config.ts +19 -0
- package/www/package-lock.json +1779 -0
- package/www/package.json +27 -0
- package/www/postcss.config.mjs +7 -0
- package/www/public/logo.png +0 -0
- package/www/tsconfig.json +42 -0
- package/landing/index.html +0 -237
- package/landing/main.js +0 -147
- package/landing/style.css +0 -616
- /package/{demo.gif → assets/demo.gif} +0 -0
- /package/{demo.mp4 → assets/demo.mp4} +0 -0
- /package/{landing → www/public}/_headers +0 -0
- /package/{landing → www/public}/favicon.svg +0 -0
- /package/{landing → www/public}/og-image.png +0 -0
- /package/{landing → www/public}/og-readme.png +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scaffold Tool
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* v0.3.1 - Integrated with standard ebade templates
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import fs from "fs";
|
|
@@ -10,465 +10,214 @@ import yaml from "yaml";
|
|
|
10
10
|
|
|
11
11
|
interface ScaffoldArgs {
|
|
12
12
|
projectName: string;
|
|
13
|
-
projectType:
|
|
14
|
-
|
|
13
|
+
projectType:
|
|
14
|
+
| "SaaS Dashboard"
|
|
15
|
+
| "E-commerce"
|
|
16
|
+
| "Landing Page"
|
|
17
|
+
| "Empty Project";
|
|
18
|
+
primaryColor?: string;
|
|
15
19
|
outputDir: string;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
const TEMPLATES: Record<string, any> = {
|
|
23
|
+
"SaaS Dashboard": {
|
|
24
|
+
features: ["user-auth", "billing", "analytics", "team-management"],
|
|
21
25
|
pages: [
|
|
22
26
|
{
|
|
23
27
|
path: "/",
|
|
24
28
|
intent: "landing-page",
|
|
25
|
-
components: ["hero
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
path: "/products",
|
|
29
|
-
intent: "product-listing",
|
|
30
|
-
components: ["search-bar", "filter-sidebar", "product-grid"],
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
path: "/products/[slug]",
|
|
34
|
-
intent: "product-detail",
|
|
35
|
-
components: [
|
|
36
|
-
"product-gallery",
|
|
37
|
-
"product-info",
|
|
38
|
-
"add-to-cart",
|
|
39
|
-
"reviews",
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
path: "/cart",
|
|
44
|
-
intent: "shopping-cart",
|
|
45
|
-
components: ["cart-items", "cart-summary", "checkout-cta"],
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
path: "/checkout",
|
|
49
|
-
intent: "checkout-flow",
|
|
50
|
-
auth: "required",
|
|
51
|
-
components: ["checkout-form", "payment-section", "order-summary"],
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
data: {
|
|
55
|
-
Product: {
|
|
56
|
-
fields: {
|
|
57
|
-
id: { type: "uuid", required: true },
|
|
58
|
-
name: { type: "string", required: true },
|
|
59
|
-
price: { type: "decimal", required: true },
|
|
60
|
-
images: { type: "array" },
|
|
61
|
-
category: { type: "string" },
|
|
62
|
-
stock: { type: "integer" },
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
Cart: {
|
|
66
|
-
fields: {
|
|
67
|
-
id: { type: "uuid", required: true },
|
|
68
|
-
items: { type: "array", required: true },
|
|
69
|
-
total: { type: "decimal", required: true },
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
"saas-dashboard": {
|
|
75
|
-
pages: [
|
|
76
|
-
{
|
|
77
|
-
path: "/",
|
|
78
|
-
intent: "landing-page",
|
|
79
|
-
components: ["hero", "features", "pricing", "cta"],
|
|
29
|
+
components: ["hero", "features", "pricing"],
|
|
80
30
|
},
|
|
81
31
|
{
|
|
82
32
|
path: "/dashboard",
|
|
83
|
-
intent: "dashboard",
|
|
33
|
+
intent: "main-dashboard",
|
|
84
34
|
auth: "required",
|
|
85
|
-
components: ["stats-
|
|
35
|
+
components: ["stats-grid", "activity-chart"],
|
|
86
36
|
},
|
|
87
37
|
{
|
|
88
38
|
path: "/settings",
|
|
89
|
-
intent: "settings",
|
|
39
|
+
intent: "user-settings",
|
|
90
40
|
auth: "required",
|
|
91
|
-
components: ["profile-form", "security
|
|
41
|
+
components: ["profile-form", "security"],
|
|
92
42
|
},
|
|
93
43
|
],
|
|
94
|
-
|
|
95
|
-
User: {
|
|
96
|
-
fields: {
|
|
97
|
-
id: { type: "uuid", required: true },
|
|
98
|
-
email: { type: "string", required: true, unique: true },
|
|
99
|
-
name: { type: "string", required: true },
|
|
100
|
-
plan: { type: "enum" },
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
},
|
|
44
|
+
design: { style: "modern-glassmorphism", borderRadius: "xl" },
|
|
104
45
|
},
|
|
105
|
-
|
|
46
|
+
"E-commerce": {
|
|
47
|
+
features: ["product-catalog", "shopping-cart", "checkout", "search"],
|
|
106
48
|
pages: [
|
|
107
49
|
{
|
|
108
50
|
path: "/",
|
|
109
|
-
intent: "
|
|
110
|
-
components: ["
|
|
51
|
+
intent: "home-page",
|
|
52
|
+
components: ["hero-section", "product-grid"],
|
|
111
53
|
},
|
|
112
54
|
{
|
|
113
|
-
path: "/
|
|
114
|
-
intent: "
|
|
115
|
-
components: ["
|
|
55
|
+
path: "/cart",
|
|
56
|
+
intent: "shopping-cart",
|
|
57
|
+
components: ["cart-list", "checkout-cta"],
|
|
116
58
|
},
|
|
117
59
|
{
|
|
118
|
-
path: "/
|
|
119
|
-
intent: "
|
|
120
|
-
|
|
60
|
+
path: "/checkout",
|
|
61
|
+
intent: "checkout-flow",
|
|
62
|
+
auth: "required",
|
|
63
|
+
components: ["payment-form"],
|
|
121
64
|
},
|
|
122
65
|
],
|
|
123
|
-
|
|
124
|
-
Post: {
|
|
125
|
-
fields: {
|
|
126
|
-
id: { type: "uuid", required: true },
|
|
127
|
-
title: { type: "string", required: true },
|
|
128
|
-
slug: { type: "string", required: true, unique: true },
|
|
129
|
-
content: { type: "text", required: true },
|
|
130
|
-
publishedAt: { type: "timestamp" },
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
},
|
|
66
|
+
design: { style: "clean-minimal", borderRadius: "md" },
|
|
134
67
|
},
|
|
135
|
-
"
|
|
68
|
+
"Landing Page": {
|
|
69
|
+
features: ["hero", "features", "testimonials", "cta", "footer"],
|
|
136
70
|
pages: [
|
|
137
71
|
{
|
|
138
72
|
path: "/",
|
|
139
|
-
intent: "landing",
|
|
73
|
+
intent: "landing-page",
|
|
140
74
|
components: [
|
|
141
75
|
"hero",
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"faq",
|
|
146
|
-
"cta",
|
|
147
|
-
"footer",
|
|
76
|
+
"feature-grid",
|
|
77
|
+
"testimonial-slider",
|
|
78
|
+
"cta-section",
|
|
148
79
|
],
|
|
149
80
|
},
|
|
150
81
|
],
|
|
151
|
-
|
|
82
|
+
design: { style: "premium-dark", borderRadius: "full" },
|
|
152
83
|
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
intent: "portfolio-home",
|
|
158
|
-
components: ["hero", "about", "projects-grid", "skills", "contact"],
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
path: "/projects/[slug]",
|
|
162
|
-
intent: "project-detail",
|
|
163
|
-
components: ["project-gallery", "project-info", "tech-stack"],
|
|
164
|
-
},
|
|
165
|
-
],
|
|
166
|
-
data: {
|
|
167
|
-
Project: {
|
|
168
|
-
fields: {
|
|
169
|
-
id: { type: "uuid", required: true },
|
|
170
|
-
title: { type: "string", required: true },
|
|
171
|
-
description: { type: "text" },
|
|
172
|
-
images: { type: "array" },
|
|
173
|
-
link: { type: "string" },
|
|
174
|
-
},
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
// Component templates
|
|
181
|
-
const componentTemplates: Record<string, (name: string) => string> = {
|
|
182
|
-
default: (name: string) => {
|
|
183
|
-
const pascalName = name
|
|
184
|
-
.split("-")
|
|
185
|
-
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
186
|
-
.join("");
|
|
187
|
-
return `"use client";
|
|
188
|
-
|
|
189
|
-
import { useState } from "react";
|
|
190
|
-
|
|
191
|
-
interface ${pascalName}Props {
|
|
192
|
-
className?: string;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export function ${pascalName}({ className }: ${pascalName}Props) {
|
|
196
|
-
return (
|
|
197
|
-
<section className={\`${name} \${className || ""}\`}>
|
|
198
|
-
<div className="container">
|
|
199
|
-
{/* ${pascalName} content */}
|
|
200
|
-
<h2>${pascalName}</h2>
|
|
201
|
-
</div>
|
|
202
|
-
</section>
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
`;
|
|
84
|
+
"Empty Project": {
|
|
85
|
+
features: [],
|
|
86
|
+
pages: [{ path: "/", intent: "index", components: ["welcome"] }],
|
|
87
|
+
design: { style: "minimal", borderRadius: "md" },
|
|
206
88
|
},
|
|
207
89
|
};
|
|
208
90
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
.join("");
|
|
217
|
-
return `import { ${pascalName} } from "@/components/${c}";`;
|
|
218
|
-
})
|
|
219
|
-
.join("\n");
|
|
91
|
+
export async function scaffoldProject(args: ScaffoldArgs): Promise<string> {
|
|
92
|
+
const {
|
|
93
|
+
projectName,
|
|
94
|
+
projectType,
|
|
95
|
+
primaryColor = "#6366f1",
|
|
96
|
+
outputDir,
|
|
97
|
+
} = args;
|
|
220
98
|
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
const pascalName = c
|
|
224
|
-
.split("-")
|
|
225
|
-
.map((w: string) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
226
|
-
.join("");
|
|
227
|
-
return ` <${pascalName} />`;
|
|
228
|
-
})
|
|
229
|
-
.join("\n");
|
|
230
|
-
|
|
231
|
-
const pageName = page.intent
|
|
232
|
-
.split("-")
|
|
233
|
-
.map((w: string) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
234
|
-
.join("");
|
|
235
|
-
|
|
236
|
-
return `/**
|
|
237
|
-
* @page('${page.path}')
|
|
238
|
-
* @ebade('${page.intent}')
|
|
239
|
-
* ${page.auth ? `@requires({ auth: '${page.auth}' })` : ""}
|
|
240
|
-
*/
|
|
241
|
-
|
|
242
|
-
${componentImports}
|
|
243
|
-
|
|
244
|
-
export default function ${pageName}Page() {
|
|
245
|
-
return (
|
|
246
|
-
<main className="page ${page.intent}">
|
|
247
|
-
${componentUsage}
|
|
248
|
-
</main>
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
`;
|
|
252
|
-
}
|
|
99
|
+
const template = TEMPLATES[projectType];
|
|
100
|
+
const projectDir = path.join(outputDir, projectName);
|
|
253
101
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
102
|
+
try {
|
|
103
|
+
// 1. Create directory structure
|
|
104
|
+
const dirs = [
|
|
105
|
+
"app/api",
|
|
106
|
+
"components",
|
|
107
|
+
"lib",
|
|
108
|
+
"styles",
|
|
109
|
+
"public",
|
|
110
|
+
"types",
|
|
111
|
+
"database",
|
|
112
|
+
];
|
|
113
|
+
if (!fs.existsSync(projectDir))
|
|
114
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
115
|
+
|
|
116
|
+
dirs.forEach((d) => {
|
|
117
|
+
const fullPath = path.join(projectDir, d);
|
|
118
|
+
if (!fs.existsSync(fullPath)) fs.mkdirSync(fullPath, { recursive: true });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// 2. Generate ebade file
|
|
122
|
+
const ebadeConfig = {
|
|
258
123
|
name: projectName,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
},
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
"@types/node": "^20.0.0",
|
|
274
|
-
"@types/react": "^18.2.0",
|
|
275
|
-
typescript: "^5.3.0",
|
|
276
|
-
},
|
|
277
|
-
ebade: {
|
|
278
|
-
type: projectType,
|
|
279
|
-
version: "0.1.0",
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
null,
|
|
283
|
-
2
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Generate globals.css
|
|
288
|
-
function generateGlobalsCss(): string {
|
|
289
|
-
return `/* ebade Generated Design System */
|
|
290
|
-
|
|
291
|
-
:root {
|
|
292
|
-
--color-primary: #6366f1;
|
|
293
|
-
--color-secondary: #f59e0b;
|
|
294
|
-
--color-accent: #10b981;
|
|
295
|
-
|
|
296
|
-
--font-family: 'Inter', system-ui, sans-serif;
|
|
297
|
-
|
|
298
|
-
--radius-sm: 0.25rem;
|
|
299
|
-
--radius-md: 0.5rem;
|
|
300
|
-
--radius-lg: 1rem;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
* {
|
|
304
|
-
box-sizing: border-box;
|
|
305
|
-
margin: 0;
|
|
306
|
-
padding: 0;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
body {
|
|
310
|
-
font-family: var(--font-family);
|
|
311
|
-
line-height: 1.6;
|
|
312
|
-
color: #1f2937;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
.container {
|
|
316
|
-
max-width: 1200px;
|
|
317
|
-
margin: 0 auto;
|
|
318
|
-
padding: 0 1rem;
|
|
319
|
-
}
|
|
124
|
+
type: projectType.toLowerCase().replace(" ", "-"),
|
|
125
|
+
description: `Generated ${projectType} via ebade MCP`,
|
|
126
|
+
features: template.features,
|
|
127
|
+
pages: template.pages,
|
|
128
|
+
design: {
|
|
129
|
+
...template.design,
|
|
130
|
+
colors: { primary: primaryColor },
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
fs.writeFileSync(
|
|
135
|
+
path.join(projectDir, "project.ebade.yaml"),
|
|
136
|
+
yaml.stringify(ebadeConfig)
|
|
137
|
+
);
|
|
320
138
|
|
|
321
|
-
.
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
`;
|
|
325
|
-
}
|
|
139
|
+
// 3. Generate Next.js files (Basic mocks to match CLI)
|
|
140
|
+
generateCoreFiles(projectDir, ebadeConfig);
|
|
326
141
|
|
|
327
|
-
|
|
328
|
-
|
|
142
|
+
return `✅ ebade v0.3.1 Scaffold Complete!
|
|
143
|
+
|
|
144
|
+
Project: ${projectName}
|
|
145
|
+
Type: ${projectType}
|
|
146
|
+
Dir: ${projectDir}
|
|
329
147
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
148
|
+
Next Steps:
|
|
149
|
+
1. Open this folder in Cursor/Claude
|
|
150
|
+
2. Run 'npx ebade dev project.ebade.yaml' to start the agent engine.`;
|
|
151
|
+
} catch (error) {
|
|
333
152
|
throw new Error(
|
|
334
|
-
`
|
|
335
|
-
|
|
336
|
-
|
|
153
|
+
`Scaffold failed: ${
|
|
154
|
+
error instanceof Error ? error.message : String(error)
|
|
155
|
+
}`
|
|
337
156
|
);
|
|
338
157
|
}
|
|
158
|
+
}
|
|
339
159
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
: `app${page.path.replace("[", "(").replace("]", ")")}/page.tsx`;
|
|
363
|
-
|
|
364
|
-
const pageDir = path.dirname(path.join(projectDir, pagePath));
|
|
365
|
-
if (!fs.existsSync(pageDir)) {
|
|
366
|
-
fs.mkdirSync(pageDir, { recursive: true });
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Write page file
|
|
370
|
-
const pageContent = generatePageTemplate(page);
|
|
371
|
-
fs.writeFileSync(path.join(projectDir, pagePath), pageContent);
|
|
372
|
-
createdFiles.push(pagePath);
|
|
373
|
-
|
|
374
|
-
// Generate component files
|
|
375
|
-
for (const component of page.components || []) {
|
|
376
|
-
const componentPath = `components/${component}.tsx`;
|
|
377
|
-
const fullComponentPath = path.join(projectDir, componentPath);
|
|
378
|
-
|
|
379
|
-
if (!fs.existsSync(fullComponentPath)) {
|
|
380
|
-
const componentContent = componentTemplates.default(component);
|
|
381
|
-
fs.writeFileSync(fullComponentPath, componentContent);
|
|
382
|
-
createdFiles.push(componentPath);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// Generate package.json
|
|
160
|
+
function generateCoreFiles(projectDir: string, config: any) {
|
|
161
|
+
// package.json
|
|
162
|
+
const pkg = {
|
|
163
|
+
name: config.name,
|
|
164
|
+
version: "0.1.0",
|
|
165
|
+
dependencies: {
|
|
166
|
+
next: "latest",
|
|
167
|
+
react: "latest",
|
|
168
|
+
"react-dom": "latest",
|
|
169
|
+
"lucide-react": "latest",
|
|
170
|
+
},
|
|
171
|
+
devDependencies: {
|
|
172
|
+
"@types/node": "latest",
|
|
173
|
+
"@types/react": "latest",
|
|
174
|
+
"@types/react-dom": "latest",
|
|
175
|
+
autoprefixer: "latest",
|
|
176
|
+
postcss: "latest",
|
|
177
|
+
tailwindcss: "latest",
|
|
178
|
+
typescript: "latest",
|
|
179
|
+
},
|
|
180
|
+
scripts: { dev: "next dev", build: "next build", start: "next start" },
|
|
181
|
+
};
|
|
388
182
|
fs.writeFileSync(
|
|
389
183
|
path.join(projectDir, "package.json"),
|
|
390
|
-
|
|
184
|
+
JSON.stringify(pkg, null, 2)
|
|
391
185
|
);
|
|
392
|
-
createdFiles.push("package.json");
|
|
393
186
|
|
|
394
|
-
//
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
secondary: "#f59e0b",
|
|
413
|
-
accent: "#10b981",
|
|
414
|
-
},
|
|
187
|
+
// tsconfig.json (Basic version)
|
|
188
|
+
const tsconfig = {
|
|
189
|
+
compilerOptions: {
|
|
190
|
+
target: "es5",
|
|
191
|
+
lib: ["dom", "dom.iterable", "esnext"],
|
|
192
|
+
allowJs: true,
|
|
193
|
+
skipLibCheck: true,
|
|
194
|
+
strict: true,
|
|
195
|
+
noEmit: true,
|
|
196
|
+
esModuleInterop: true,
|
|
197
|
+
module: "esnext",
|
|
198
|
+
moduleResolution: "bundler",
|
|
199
|
+
resolveJsonModule: true,
|
|
200
|
+
isolatedModules: true,
|
|
201
|
+
jsx: "preserve",
|
|
202
|
+
incremental: true,
|
|
203
|
+
plugins: [{ name: "next" }],
|
|
204
|
+
paths: { "@/*": ["./*"] },
|
|
415
205
|
},
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// Generate layout
|
|
421
|
-
const layoutContent = `import "./globals.css";
|
|
422
|
-
import type { Metadata } from "next";
|
|
423
|
-
import { Inter } from "next/font/google";
|
|
424
|
-
|
|
425
|
-
const inter = Inter({ subsets: ["latin"] });
|
|
426
|
-
|
|
427
|
-
export const metadata: Metadata = {
|
|
428
|
-
title: "${projectName}",
|
|
429
|
-
description: "Built with ebade",
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
export default function RootLayout({
|
|
433
|
-
children,
|
|
434
|
-
}: {
|
|
435
|
-
children: React.ReactNode;
|
|
436
|
-
}) {
|
|
437
|
-
return (
|
|
438
|
-
<html lang="en">
|
|
439
|
-
<body className={inter.className}>{children}</body>
|
|
440
|
-
</html>
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
`;
|
|
444
|
-
fs.writeFileSync(path.join(projectDir, "app/layout.tsx"), layoutContent);
|
|
445
|
-
// Copy globals.css to app folder for Next.js
|
|
206
|
+
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
207
|
+
exclude: ["node_modules"],
|
|
208
|
+
};
|
|
446
209
|
fs.writeFileSync(
|
|
447
|
-
path.join(projectDir, "
|
|
448
|
-
|
|
210
|
+
path.join(projectDir, "tsconfig.json"),
|
|
211
|
+
JSON.stringify(tsconfig, null, 2)
|
|
449
212
|
);
|
|
450
|
-
createdFiles.push("app/layout.tsx", "app/globals.css");
|
|
451
|
-
|
|
452
|
-
return {
|
|
453
|
-
content: [
|
|
454
|
-
{
|
|
455
|
-
type: "text",
|
|
456
|
-
text: `✅ Successfully scaffolded "${projectName}" (${projectType})
|
|
457
213
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
📋 ebade file saved as: project.ebade.yaml
|
|
469
|
-
This can be used by AI agents to understand and iterate on the project.
|
|
470
|
-
`,
|
|
471
|
-
},
|
|
472
|
-
],
|
|
473
|
-
};
|
|
214
|
+
// .cursorrules
|
|
215
|
+
const rules = `
|
|
216
|
+
# ebade Agent Rules for ${config.name}
|
|
217
|
+
- Respect project.ebade.yaml as the source of truth.
|
|
218
|
+
- Follow the ${config.design.style} design style.
|
|
219
|
+
- Use ${config.design.colors.primary} as the primary color.
|
|
220
|
+
- Always import React from 'react' in .tsx files.
|
|
221
|
+
`;
|
|
222
|
+
fs.writeFileSync(path.join(projectDir, ".cursorrules"), rules);
|
|
474
223
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ebade VS Code Extension
|
|
2
|
+
|
|
3
|
+
Syntax highlighting, snippets, and language support for `.ebade.yaml` files.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### 🎨 Syntax Highlighting
|
|
8
|
+
|
|
9
|
+
- Keywords: `project`, `pages`, `api`, `data`, `design`
|
|
10
|
+
- Decorators: `@page`, `@intent`, `@requires`
|
|
11
|
+
- Strings, numbers, booleans
|
|
12
|
+
- Comments
|
|
13
|
+
|
|
14
|
+
### ✨ Snippets (v0.3.2 Updates)
|
|
15
|
+
|
|
16
|
+
| Prefix | Description |
|
|
17
|
+
| :--- | :--- |
|
|
18
|
+
| `eb-saas` | Full SaaS Dashboard template |
|
|
19
|
+
| `eb-shop` | Full E-commerce store template |
|
|
20
|
+
| `eb-page` | New page definition |
|
|
21
|
+
| `eb-comp` | Component reference |
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
### From VSIX (Local)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd packages/vscode-extension
|
|
29
|
+
npx vsce package
|
|
30
|
+
code --install-extension ebade-*.vsix
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### From Marketplace (Coming Soon)
|
|
34
|
+
|
|
35
|
+
Search for "ebade" in VS Code Extensions.
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
1. Create a file with `.ebade.yaml` extension
|
|
40
|
+
2. Start typing `eb-` to see available snippets
|
|
41
|
+
3. Enjoy syntax highlighting! 🎉
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
Built with 💜 by the ebade team.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|