ebade 0.4.5 โ†’ 0.4.6

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.
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: ebade Prompt-to-Product Workflow
3
+ ---
4
+
5
+ # ๐Ÿฃ ebade Prompt-to-Product Workflow
6
+
7
+ This workflow describes how an AI Agent should use the ebade framework to transform a user's natural language intent into a production-ready codebase.
8
+
9
+ ## 1. Initial Project Scaffolding
10
+ When a user asks to "build", "create", or "start" a new web application:
11
+
12
+ // turbo
13
+ 1. Use the `ebade build` command with the user's prompt.
14
+ ```bash
15
+ node cli/scaffold.js build "[User's Prompt]"
16
+ ```
17
+ *This tool will automatically choose the project type, color palette, and initial components.*
18
+
19
+ 2. Navigate into the generated project directory.
20
+
21
+ ## 2. Understanding the Architecture
22
+ ebade generates a `project.ebade.yaml` file in the project root. This is your **Source of Truth**.
23
+ 1. Read `project.ebade.yaml` to understand the pages, components, and data models.
24
+ 2. Respect the design system tokens in `app/globals.css`.
25
+
26
+ ## 3. Iterative Development
27
+ Once the scaffold is ready, move from "Architect" to "Engineer":
28
+
29
+ 1. **Refine Components**: Locate generated components in `components/`. They are high-quality visual placeholders. Add the specific business logic, API calls, or complex state management requested by the user.
30
+ 2. **Implement API Logic**: Fill the `app/api/` route handlers with real backend logic (database queries, external service integrations).
31
+ 3. **Data Schemas**: Use the generated SQL in `database/schema.sql` to set up the actual database.
32
+
33
+ ## 4. Expanding the Project
34
+ To add new features:
35
+ 1. Update `project.ebade.yaml` with the new intent.
36
+ 2. Run `node cli/scaffold.js scaffold project.ebade.yaml .` to generate the new files while preserving your logic.
37
+ 3. Apply the specific implementation details to the new files.
38
+
39
+ ---
40
+ *Built for the Agent-First Era. ebade empowers you to focus on logic, while we handle the architecture.*
package/CHANGELOG.md CHANGED
@@ -5,20 +5,44 @@ All notable changes to **ebade** will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.6] - 2025-01-10
9
+
10
+ ### Added
11
+
12
+ - **EbadeArchitect (The Brain)**: New core engine that translates natural language prompts into structured `ebade` configurations.
13
+ - **`ebade build <prompt>`**: A "one-shot" project creation command. Designs, scaffolds, and prepares a project in seconds.
14
+ - **Architect Intelligence**: Projects now gain context-aware page structures (E-commerce get cart/products, Blog get posts, etc.) and smarter component selection via Regex.
15
+ - **Auto-Environment**: Automatically generates `.gitignore` and `.env.example` for professional project starts.
16
+ - **Agent Workflow Documentation**: Added `.agent/workflows/prompt-to-product.md` to guide AI agents on using the new tools.
17
+ - **MCP Server v0.4.6**: Integrated `ebade_build` as a tool for otonomous agent usage.
18
+ - **Testing Layer**: Added internal testing suites for both the framework logic and CLI integration.
19
+ - **CLI Branding**: Updated to `v0.4.6` with improved help menus and creative briefs.
20
+
21
+ ### Fixed
22
+
23
+ - Fixed CLI entry point to allow safe imports of `scaffold.js` without triggering help output.
24
+ - Improved project naming logic to filter out filler words (e.g., "Can you make a...").
25
+ - Fixed component integrity check to correctly locate test files in `tests/components/`.
26
+
27
+ ## [0.4.5] - 2025-01-10
28
+ ...
8
29
  ## [0.4.5] - 2025-01-10
9
30
 
10
31
  ### Added
32
+
11
33
  - UI/UX Overhaul: Premium dark-mode aesthetic with ambient glow and glassmorphism by default.
12
34
  - Dynamic Color Support: Real-time Hex-to-HSL conversion to apply user's primary color choice to CSS variables.
13
35
  - Component "Intents": Placeholders are now high-quality "Glass Cards" that look like part of a finished UI.
14
36
  - Test Organization: All unit tests are now generated in a centralized `tests/` directory instead of being cluttered with components.
15
37
 
16
38
  ### Fixed
39
+
17
40
  - API Pathing: Fixed a bug that caused double-nesting (e.g., `/api/api/...`) in generated routes.
18
41
  - Removed debug information (headers, route labels) from generated pages for a "turnkey" production feel.
19
42
 
20
43
  ## [0.4.4] - 2025-01-10
21
44
 
45
+
22
46
  ### Fixed
23
47
  - Added `postcss.config.js` generation to enable Tailwind styling in scaffolded projects.
24
48
  - Fixed double-nesting issues when initializing projects (removed redundant `projectName/projectName` folder creation).
package/cli/scaffold.js CHANGED
@@ -44,7 +44,7 @@ ${colors.magenta} โ–ˆโ–ˆโ•”โ•โ•โ• ${colors.cyan}โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—$
44
44
  ${colors.magenta} โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—${colors.cyan}โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•${colors.magenta}โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘${colors.cyan}โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•${colors.magenta}โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—
45
45
  ${colors.magenta} โ•šโ•โ•โ•โ•โ•โ•โ•${colors.cyan}โ•šโ•โ•โ•โ•โ•โ• ${colors.magenta}โ•šโ•โ• โ•šโ•โ•${colors.cyan}โ•šโ•โ•โ•โ•โ•โ• ${colors.magenta}โ•šโ•โ•โ•โ•โ•โ•โ•${colors.reset}
46
46
 
47
- ${colors.dim}โœจ Agent-First Framework ${colors.yellow}v0.4.5${colors.reset}
47
+ ${colors.dim}โœจ Agent-First Framework ${colors.yellow}v0.4.6${colors.reset}
48
48
  `;
49
49
 
50
50
  const log = {
@@ -58,6 +58,166 @@ const log = {
58
58
  console.log(`\n${colors.bright}${colors.magenta}โ–ธ ${msg}${colors.reset}`),
59
59
  };
60
60
 
61
+ // ============================================
62
+ // ebade Architect (The Brain)
63
+ // ============================================
64
+ export class EbadeArchitect {
65
+ static async plan(prompt) {
66
+ const p = prompt.toLowerCase();
67
+
68
+ // Core App Type Detection
69
+ let type = "saas-dashboard";
70
+ if (p.includes("e-commerce") || p.includes("shop") || p.includes("store"))
71
+ type = "e-commerce";
72
+ if (p.includes("blog") || p.includes("article") || p.includes("news"))
73
+ type = "blog";
74
+ if (p.includes("portfolio") || p.includes("personal") || p.includes("cv"))
75
+ type = "portfolio";
76
+
77
+ // Component Intelligence
78
+ const components = ["navbar", "footer"];
79
+ const features = [];
80
+
81
+ const has = (keyword) => new RegExp(`\\b${keyword}`, "i").test(p);
82
+
83
+ if (has("chart") || has("analytics") || has("graph") || has("metric")) {
84
+ components.push("activity-chart", "stats-grid");
85
+ features.push("Advanced Analytics");
86
+ }
87
+ if (has("saas") || has("dashboard") || has("admin")) {
88
+ components.push("sidebar-navigation", "metrics-cards");
89
+ features.push("Admin Dashboard");
90
+ }
91
+ if (has("login") || has("auth") || has("sign") || has("user")) {
92
+ components.push("login-form", "signup-form");
93
+ features.push("Authentication");
94
+ }
95
+ if (has("price") || has("plan") || has("subscribe") || has("billing")) {
96
+ components.push("pricing-table", "cta-banner");
97
+ features.push("Subscription Tiers");
98
+ }
99
+ if (has("testim") || has("review") || has("social proof"))
100
+ components.push("testimonials-grid");
101
+ if (has("contact") || has("form") || has("help") || has("support"))
102
+ components.push("contact-form");
103
+ if (has("faq") || has("question")) components.push("faq-accordion");
104
+
105
+ // Dynamic Color Palette (Order matters - specific colors should win over vibes)
106
+ let primary = "#6366f1"; // Indigo default
107
+ if (has("gold") || has("luxury") || has("premium") || has("exclusive"))
108
+ primary = "#fbbf24";
109
+ if (has("green") || has("eco") || has("emerald") || has("nature"))
110
+ primary = "#10b981";
111
+ if (
112
+ has("blue") ||
113
+ has("ocean") ||
114
+ has("sky") ||
115
+ has("trust") ||
116
+ has("corp")
117
+ )
118
+ primary = "#3b82f6";
119
+ if (has("violet") || has("purple") || has("creative") || has("design"))
120
+ primary = "#8b5cf6";
121
+ if (has("orange") || has("fire") || has("warm") || has("brand"))
122
+ primary = "#f59e0b";
123
+ if (has("red") || has("danger") || has("hot") || has("love"))
124
+ primary = "#ef4444";
125
+
126
+ // Smart Pages based on Type
127
+ const pages = [
128
+ {
129
+ path: "/",
130
+ intent: "landing-page",
131
+ components: components.filter((c) =>
132
+ [
133
+ "navbar",
134
+ "hero-section",
135
+ "pricing-table",
136
+ "testimonials-grid",
137
+ "cta-banner",
138
+ "footer",
139
+ ].includes(c)
140
+ ),
141
+ },
142
+ ];
143
+
144
+ if (type === "saas-dashboard") {
145
+ pages.push({
146
+ path: "/dashboard",
147
+ intent: "main-dashboard",
148
+ components: components.filter((c) =>
149
+ [
150
+ "sidebar-navigation",
151
+ "stats-grid",
152
+ "activity-chart",
153
+ "metrics-cards",
154
+ ].includes(c)
155
+ ),
156
+ });
157
+ } else if (type === "e-commerce") {
158
+ pages.push(
159
+ {
160
+ path: "/products",
161
+ intent: "product-list",
162
+ components: ["product-grid"],
163
+ },
164
+ { path: "/cart", intent: "shopping-cart", components: ["cart-list"] }
165
+ );
166
+ } else if (type === "blog") {
167
+ pages.push(
168
+ { path: "/posts", intent: "blog-index", components: ["post-list"] },
169
+ {
170
+ path: "/posts/[slug]",
171
+ intent: "blog-post",
172
+ components: ["post-body"],
173
+ }
174
+ );
175
+ }
176
+
177
+ // Build Internal Intent
178
+ const config = {
179
+ name:
180
+ p
181
+ .split(" ")
182
+ .filter(
183
+ (w) =>
184
+ ![
185
+ "can",
186
+ "you",
187
+ "make",
188
+ "create",
189
+ "a",
190
+ "an",
191
+ "the",
192
+ "with",
193
+ "please",
194
+ "super",
195
+ "ultra",
196
+ "is",
197
+ "for",
198
+ "me",
199
+ "my",
200
+ "and",
201
+ ].includes(w.toLowerCase())
202
+ )
203
+ .slice(0, 2)
204
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
205
+ .join("") || "EbadeApp",
206
+ type: type,
207
+ description: prompt,
208
+ features: features.length > 0 ? features : ["Turnkey Scaffold"],
209
+ design: {
210
+ colors: { primary },
211
+ style: "glass-modern",
212
+ },
213
+ pages: pages,
214
+ api: [{ path: "/api/data", methods: ["GET"], intent: "fetch-data" }],
215
+ };
216
+
217
+ return config;
218
+ }
219
+ }
220
+
61
221
  // ============================================
62
222
  // ebade Parser
63
223
  // ============================================
@@ -536,6 +696,61 @@ export function cn(...inputs: ClassValue[]) {
536
696
  `;
537
697
  }
538
698
 
699
+ function generateGitignore() {
700
+ return `# dependencies
701
+ /node_modules
702
+ /.pnp
703
+ .pnp.js
704
+
705
+ # testing
706
+ /coverage
707
+
708
+ # next.js
709
+ /.next/
710
+ /out/
711
+
712
+ # production
713
+ /build
714
+
715
+ # misc
716
+ .DS_Store
717
+ *.pem
718
+
719
+ # debug
720
+ npm-debug.log*
721
+ yarn-debug.log*
722
+ yarn-error.log*
723
+
724
+ # local env files
725
+ .env*.local
726
+ .env
727
+
728
+ # vercel
729
+ .vercel
730
+
731
+ # typescript
732
+ *.tsbuildinfo
733
+ next-env.d.ts
734
+ `;
735
+ }
736
+
737
+ function generateEnvExample(config) {
738
+ return `# ebade Generated Environment Variables
739
+ # Project: ${config.name}
740
+
741
+ # Database (Supabase / Postgres)
742
+ DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
743
+
744
+ # Authentication (NextAuth / Clerk)
745
+ NEXTAUTH_SECRET="your-secret-here"
746
+ NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=""
747
+
748
+ # API Keys
749
+ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=""
750
+ STRIPE_SECRET_KEY=""
751
+ `;
752
+ }
753
+
539
754
  // ============================================
540
755
  // Design System CSS Generator
541
756
  // ============================================
@@ -621,21 +836,22 @@ Built with ebade - The Agent-First Framework for the next era of development.
621
836
  // ============================================
622
837
  // Utility Functions
623
838
  // ============================================
624
- function toPascalCase(str) {
839
+ export function toPascalCase(str) {
625
840
  return str
626
- .split("-")
841
+ .split(/[-_]/)
627
842
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
628
843
  .join("");
629
844
  }
630
845
 
631
- function toSnakeCase(str) {
846
+ export function toSnakeCase(str) {
632
847
  return str
633
848
  .replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
849
+ .replace(/-/g, "_")
634
850
  .toLowerCase()
635
851
  .replace(/^_/, "");
636
852
  }
637
853
 
638
- function hexToHsl(hex) {
854
+ export function hexToHsl(hex) {
639
855
  let r = 0,
640
856
  g = 0,
641
857
  b = 0;
@@ -882,6 +1098,17 @@ async function scaffold(ebadePath, outputDir) {
882
1098
  );
883
1099
  log.file("vitest.config.ts");
884
1100
 
1101
+ // .gitignore
1102
+ fs.writeFileSync(path.join(projectDir, ".gitignore"), generateGitignore());
1103
+ log.file(".gitignore");
1104
+
1105
+ // .env.example
1106
+ fs.writeFileSync(
1107
+ path.join(projectDir, ".env.example"),
1108
+ generateEnvExample(config)
1109
+ );
1110
+ log.file(".env.example");
1111
+
885
1112
  // app/layout.tsx
886
1113
  fs.writeFileSync(
887
1114
  path.join(projectDir, "app/layout.tsx"),
@@ -1114,12 +1341,14 @@ ${colors.dim}Usage:${colors.reset}
1114
1341
 
1115
1342
  ${colors.dim}Commands:${colors.reset}
1116
1343
  init Create a new ebade project interactively
1344
+ build <prompt> Generate and scaffold a project from a natural language prompt
1117
1345
  scaffold <file> [output] Scaffold a project from ebade file
1118
1346
  dev <file> [output] Watch ebade file and re-scaffold on changes
1119
1347
  playground Open the ebade playground
1120
1348
 
1121
1349
  ${colors.dim}Examples:${colors.reset}
1122
1350
  npx ebade init
1351
+ npx ebade build "A violet themed crypto dashboard"
1123
1352
  npx ebade scaffold examples/saas-dashboard.ebade.yaml ./output
1124
1353
  npx ebade dev my-project.ebade.yaml ./my-app
1125
1354
 
@@ -1283,80 +1512,134 @@ ${LOGO}
1283
1512
  // ============================================
1284
1513
  // Command Router
1285
1514
  // ============================================
1286
- if (
1287
- args.length === 0 ||
1288
- command === "help" ||
1289
- command === "--help" ||
1290
- command === "-h"
1291
- ) {
1292
- showHelp();
1293
- process.exit(0);
1294
- }
1515
+ const isMain =
1516
+ process.argv[1] &&
1517
+ (process.argv[1].endsWith("scaffold.js") ||
1518
+ process.argv[1].endsWith("ebade"));
1519
+
1520
+ if (isMain) {
1521
+ if (
1522
+ args.length === 0 ||
1523
+ command === "help" ||
1524
+ command === "--help" ||
1525
+ command === "-h"
1526
+ ) {
1527
+ showHelp();
1528
+ process.exit(0);
1529
+ }
1295
1530
 
1296
- if (command === "init") {
1297
- await init();
1298
- } else if (command === "scaffold") {
1299
- const ebadeFile = args[1];
1300
- const outputDir = args[2] || "./output";
1531
+ if (command === "init") {
1532
+ await init();
1533
+ } else if (command === "scaffold") {
1534
+ const ebadeFile = args[1];
1535
+ const outputDir = args[2] || "./output";
1301
1536
 
1302
- if (!ebadeFile) {
1303
- console.error(
1304
- `${colors.red}Error:${colors.reset} Please provide an ebade file path.`
1305
- );
1306
- console.log(
1307
- `\n${colors.dim}Usage:${colors.reset} npx ebade scaffold <file.ebade.yaml> [output-dir]\n`
1308
- );
1309
- process.exit(1);
1310
- }
1537
+ if (!ebadeFile) {
1538
+ console.error(
1539
+ `${colors.red}Error:${colors.reset} Please provide an ebade file path.`
1540
+ );
1541
+ console.log(
1542
+ `\n${colors.dim}Usage:${colors.reset} npx ebade scaffold <file.ebade.yaml> [output-dir]\n`
1543
+ );
1544
+ process.exit(1);
1545
+ }
1311
1546
 
1312
- if (!fs.existsSync(ebadeFile)) {
1313
- console.error(
1314
- `${colors.red}Error:${colors.reset} ebade file not found: ${ebadeFile}`
1315
- );
1316
- process.exit(1);
1317
- }
1547
+ if (!fs.existsSync(ebadeFile)) {
1548
+ console.error(
1549
+ `${colors.red}Error:${colors.reset} ebade file not found: ${ebadeFile}`
1550
+ );
1551
+ process.exit(1);
1552
+ }
1318
1553
 
1319
- await scaffold(ebadeFile, outputDir);
1320
- } else if (command === "playground") {
1321
- console.log(`\n${colors.cyan}๐ŸŒ Opening ebade playground...${colors.reset}`);
1322
- const url = "https://ebade.dev/playground";
1323
- const start =
1324
- process.platform === "darwin"
1325
- ? "open"
1326
- : process.platform === "win32"
1327
- ? "start"
1328
- : "xdg-open";
1329
- try {
1330
- execSync(`${start} ${url}`);
1331
- } catch (e) {
1332
- console.log(`\n${colors.yellow}Please open:${colors.reset} ${url}`);
1333
- }
1334
- } else if (command === "dev") {
1335
- const ebadeFile = args[1];
1336
- const outputDir = args[2] || "./output";
1554
+ await scaffold(ebadeFile, outputDir);
1555
+ } else if (command === "build") {
1556
+ const prompt = args.slice(1).join(" ");
1337
1557
 
1338
- if (!ebadeFile) {
1339
- console.error(
1340
- `${colors.red}Error:${colors.reset} Please provide an ebade file path.`
1558
+ if (!prompt) {
1559
+ console.error(
1560
+ `${colors.red}Error:${colors.reset} Please provide a prompt. e.g. npx ebade build "A blue themed SaaS"`
1561
+ );
1562
+ process.exit(1);
1563
+ }
1564
+
1565
+ const spinner = ora(
1566
+ `${colors.cyan}EbadeArchitect is designing your project...${colors.reset}`
1567
+ ).start();
1568
+ const config = await EbadeArchitect.plan(prompt);
1569
+ spinner.succeed(
1570
+ `Design complete: ${colors.bright}${config.name}${colors.reset}`
1341
1571
  );
1572
+
1573
+ const outputDir = "./" + (config.name || "ebade-app");
1574
+
1575
+ // Create temporary YAML and scaffold
1576
+ const tempDir = path.join(process.cwd(), ".ebade_temp");
1577
+ ensureDir(tempDir);
1578
+ const tempFile = path.join(tempDir, "project.ebade.yaml");
1579
+ fs.writeFileSync(tempFile, yaml.stringify(config));
1580
+
1581
+ await scaffold(tempFile, outputDir);
1582
+
1583
+ // Final Brief
1584
+ console.log(`
1585
+ ${colors.magenta}${colors.bright}๐ŸŽจ Creative Brief from EbadeArchitect:${
1586
+ colors.reset
1587
+ }
1588
+ ${colors.cyan}Project:${colors.reset} ${config.name}
1589
+ ${colors.cyan}Theme:${colors.reset} ${
1590
+ config.design.colors.primary
1591
+ } (Detected from prompt)
1592
+ ${colors.cyan}Pages:${colors.reset} ${config.pages
1593
+ .map((p) => p.path)
1594
+ .join(", ")}
1595
+ ${colors.cyan}Features:${colors.reset} ${config.features.join(", ")}
1596
+ `);
1597
+
1598
+ // Cleanup
1599
+ fs.rmSync(tempDir, { recursive: true, force: true });
1600
+ } else if (command === "playground") {
1342
1601
  console.log(
1343
- `\n${colors.dim}Usage:${colors.reset} npx ebade dev <file.ebade.yaml> [output-dir]\n`
1602
+ `\n${colors.cyan}๐ŸŒ Opening ebade playground...${colors.reset}`
1344
1603
  );
1345
- process.exit(1);
1346
- }
1604
+ const url = "https://ebade.dev/playground";
1605
+ const start =
1606
+ process.platform === "darwin"
1607
+ ? "open"
1608
+ : process.platform === "win32"
1609
+ ? "start"
1610
+ : "xdg-open";
1611
+ try {
1612
+ execSync(`${start} ${url}`);
1613
+ } catch (e) {
1614
+ console.log(`\n${colors.yellow}Please open:${colors.reset} ${url}`);
1615
+ }
1616
+ } else if (command === "dev") {
1617
+ const ebadeFile = args[1];
1618
+ const outputDir = args[2] || "./output";
1347
1619
 
1348
- if (!fs.existsSync(ebadeFile)) {
1620
+ if (!ebadeFile) {
1621
+ console.error(
1622
+ `${colors.red}Error:${colors.reset} Please provide an ebade file path.`
1623
+ );
1624
+ console.log(
1625
+ `\n${colors.dim}Usage:${colors.reset} npx ebade dev <file.ebade.yaml> [output-dir]\n`
1626
+ );
1627
+ process.exit(1);
1628
+ }
1629
+
1630
+ if (!fs.existsSync(ebadeFile)) {
1631
+ console.error(
1632
+ `${colors.red}Error:${colors.reset} ebade file not found: ${ebadeFile}`
1633
+ );
1634
+ process.exit(1);
1635
+ }
1636
+
1637
+ await dev(ebadeFile, outputDir);
1638
+ } else {
1349
1639
  console.error(
1350
- `${colors.red}Error:${colors.reset} ebade file not found: ${ebadeFile}`
1640
+ `${colors.red}Error:${colors.reset} Unknown command: ${command}`
1351
1641
  );
1642
+ showHelp();
1352
1643
  process.exit(1);
1353
1644
  }
1354
-
1355
- await dev(ebadeFile, outputDir);
1356
- } else {
1357
- console.error(
1358
- `${colors.red}Error:${colors.reset} Unknown command: ${command}`
1359
- );
1360
- showHelp();
1361
- process.exit(1);
1362
1645
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ebade",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "ebade - Agent-First Framework. The first framework designed for AI agents, readable by humans.",
5
5
  "type": "module",
6
6
  "main": "cli/scaffold.js",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ebade-mcp-server",
3
- "version": "0.4.5",
4
- "description": "MCP Server for ebade v0.4.4 - The Agent-First Framework",
3
+ "version": "0.4.6",
4
+ "description": "MCP Server for ebade v0.4.6 - The Agent-First Framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -9,6 +9,7 @@
9
9
  * - Validate ebade files
10
10
  * - Compile ebade to framework-specific code
11
11
  * - Generate components from natural language descriptions
12
+ * - Build entire projects from natural language prompts (NEW in v0.4.6)
12
13
  */
13
14
 
14
15
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -24,12 +25,13 @@ import { scaffoldProject } from "./tools/scaffold.js";
24
25
  import { validateIntent } from "./tools/validate.js";
25
26
  import { compileIntent } from "./tools/compile.js";
26
27
  import { generateComponent } from "./tools/generate.js";
28
+ import { buildFromPrompt } from "./tools/build.js";
27
29
 
28
30
  // Create the MCP server
29
31
  const server = new Server(
30
32
  {
31
33
  name: "ebade",
32
- version: "0.3.1",
34
+ version: "0.4.6",
33
35
  },
34
36
  {
35
37
  capabilities: {
@@ -183,6 +185,33 @@ Use this when:
183
185
  required: ["description"],
184
186
  },
185
187
  },
188
+ {
189
+ name: "ebade_build",
190
+ description: `Revolutionary "Prompt-to-Product" tool.
191
+ Generates a complete, production-ready project from a single natural language description.
192
+
193
+ Use this when the user says:
194
+ - "Bana mor temalฤฑ bir kripto borsasฤฑ yap"
195
+ - "Create a red themed SaaS for AI model store"
196
+ - "Make a sleek portfolio for a creative director"
197
+
198
+ This tool handles architecture, component selection, color palette, and scaffolding in one shot.`,
199
+ inputSchema: {
200
+ type: "object",
201
+ properties: {
202
+ prompt: {
203
+ type: "string",
204
+ description: "The natural language instruction for the project",
205
+ },
206
+ outputDir: {
207
+ type: "string",
208
+ description:
209
+ "Base directory path where the project will be created (absolute)",
210
+ },
211
+ },
212
+ required: ["prompt", "outputDir"],
213
+ },
214
+ },
186
215
  ],
187
216
  };
188
217
  });
@@ -229,6 +258,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
229
258
  style: args?.style as any,
230
259
  });
231
260
 
261
+ case "ebade_build":
262
+ return {
263
+ content: [
264
+ {
265
+ type: "text",
266
+ text: await buildFromPrompt(args as any),
267
+ },
268
+ ],
269
+ };
270
+
232
271
  default:
233
272
  throw new Error(`Unknown tool: ${name}`);
234
273
  }
@@ -278,7 +317,7 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
278
317
  const { uri } = request.params;
279
318
 
280
319
  const resources: Record<string, string> = {
281
- "ebade://syntax": `# ebade Syntax Reference\\n\\n@page, @ebade, @requires, @outcomes, @data, @validate, @style, @compose, @on, @expects\\n\\nCode = f(ebade)`,
320
+ "ebade://syntax": `# ebade Syntax Reference\n\n@page, @ebade, @requires, @outcomes, @data, @validate, @style, @compose, @on, @expects\n\nCode = f(ebade)`,
282
321
  "ebade://examples/ecommerce": `# E-commerce ebade\nname: my-store\ntype: e-commerce\nfeatures:\n - product-catalog\n - shopping-cart\n - checkout`,
283
322
  "ebade://examples/saas": `# SaaS ebade\nname: my-saas\ntype: saas-dashboard\nfeatures:\n - user-auth\n - billing\n - analytics`,
284
323
  };
@@ -0,0 +1,57 @@
1
+ import { execSync } from "child_process";
2
+ import path from "path";
3
+ import fs from "fs";
4
+
5
+ interface BuildArgs {
6
+ prompt: string;
7
+ outputDir: string;
8
+ }
9
+
10
+ export async function buildFromPrompt(args: BuildArgs): Promise<string> {
11
+ const { prompt, outputDir } = args;
12
+
13
+ try {
14
+ // Find the CLI script path
15
+ // Assuming we are in packages/mcp-server/dist/tools/ (at runtime)
16
+ // or packages/mcp-server/src/tools/ (at dev time)
17
+ const cliPath = path.resolve(process.cwd(), "../../cli/scaffold.js");
18
+
19
+ if (!fs.existsSync(cliPath)) {
20
+ throw new Error(`CLI not found at ${cliPath}`);
21
+ }
22
+
23
+ console.log(`๐Ÿš€ Executing ebade build from prompt: "${prompt}"`);
24
+
25
+ // Execute the CLI command
26
+ // We pass the prompt as an argument.
27
+ // We need to handle the outputDir carefully.
28
+ // The CLI build command currently uses its own naming logic,
29
+ // but it creates the folder in the current process.cwd().
30
+
31
+ const cmd = `node "${cliPath}" build "${prompt}"`;
32
+
33
+ // Run in the specified outputDir if provided
34
+ const result = execSync(cmd, {
35
+ cwd: outputDir,
36
+ encoding: "utf-8",
37
+ env: { ...process.env, NODE_ENV: "production" },
38
+ });
39
+
40
+ return `โœ… ebade v0.4.6 Build Complete!
41
+
42
+ Prompt: "${prompt}"
43
+ Output: ${outputDir}
44
+
45
+ CLI Output:
46
+ ${result}
47
+
48
+ Next Steps:
49
+ 1. Navigate to the generated folder.
50
+ 2. Run 'npm install && npm run dev'.
51
+ 3. Enjoy your turnkey project!`;
52
+ } catch (error) {
53
+ throw new Error(
54
+ `Build failed: ${error instanceof Error ? error.message : String(error)}`
55
+ );
56
+ }
57
+ }
@@ -0,0 +1,66 @@
1
+ import { execSync } from "child_process";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import assert from "assert";
5
+
6
+ async function runCliTests() {
7
+ console.log("๐Ÿงช Running CLI Integration Tests...\n");
8
+
9
+ const PROJECT_NAME = "ModernBlog";
10
+ if (fs.existsSync(PROJECT_NAME)) {
11
+ fs.rmSync(PROJECT_NAME, { recursive: true, force: true });
12
+ }
13
+
14
+ try {
15
+ // 1. Test 'ebade build' command
16
+ console.log(`Testing 'ebade build' command for ${PROJECT_NAME}...`);
17
+ const cmd = `node cli/scaffold.js build "A Modern Blog with blue theme"`;
18
+
19
+ execSync(cmd, { stdio: "inherit" });
20
+
21
+ const projectDir = path.join(process.cwd(), PROJECT_NAME);
22
+
23
+ assert.ok(
24
+ fs.existsSync(projectDir),
25
+ `Project directory (${PROJECT_NAME}) should exist`
26
+ );
27
+ assert.ok(
28
+ fs.existsSync(path.join(projectDir, "project.ebade.yaml")),
29
+ "project.ebade.yaml should be generated"
30
+ );
31
+ assert.ok(
32
+ fs.existsSync(path.join(projectDir, "app/page.tsx")),
33
+ "Main page should be generated"
34
+ );
35
+ assert.ok(
36
+ fs.existsSync(path.join(projectDir, ".env.example")),
37
+ ".env.example should be generated"
38
+ );
39
+ assert.ok(
40
+ fs.existsSync(path.join(projectDir, ".gitignore")),
41
+ ".gitignore should be generated"
42
+ );
43
+
44
+ // Verify blog pages
45
+ assert.ok(
46
+ fs.existsSync(path.join(projectDir, "app/posts/page.tsx")),
47
+ "Blog index page should be generated"
48
+ );
49
+
50
+ console.log("โœ… 'ebade build' Integration OK");
51
+ } catch (err) {
52
+ console.error("\nโŒ CLI Test failed:");
53
+ console.error(err);
54
+ process.exit(1);
55
+ } finally {
56
+ // Cleanup
57
+ console.log("\n๐Ÿงน Cleaning up test artifacts...");
58
+ if (fs.existsSync(PROJECT_NAME)) {
59
+ fs.rmSync(PROJECT_NAME, { recursive: true, force: true });
60
+ }
61
+ }
62
+
63
+ console.log("\nโœจ CLI integration tests passed!");
64
+ }
65
+
66
+ runCliTests();
@@ -0,0 +1,102 @@
1
+ import {
2
+ EbadeArchitect,
3
+ toPascalCase,
4
+ toSnakeCase,
5
+ hexToHsl,
6
+ } from "../../cli/scaffold.js";
7
+ import assert from "assert";
8
+
9
+ async function runTests() {
10
+ console.log("๐Ÿงช Running Framework Unit Tests (v0.4.6)...\n");
11
+
12
+ // 1. Utility Functions
13
+ console.log("Testing Utility Functions...");
14
+ assert.strictEqual(toPascalCase("hello-world"), "HelloWorld");
15
+ assert.strictEqual(toPascalCase("hello_world"), "HelloWorld");
16
+ assert.strictEqual(toSnakeCase("HelloWorld"), "hello_world");
17
+ assert.strictEqual(toSnakeCase("hello-world"), "hello_world");
18
+
19
+ // hexToHsl Test (Critical for Design System)
20
+ const hsl = hexToHsl("#8b5cf6"); // Violet
21
+ assert.ok(
22
+ hsl.includes("258"),
23
+ `HSL for #8b5cf6 should include hue 258, got ${hsl}`
24
+ );
25
+ console.log("โœ… Utilities OK");
26
+
27
+ // 2. Architect Mapping
28
+ console.log("\nTesting EbadeArchitect (Complex Intent)...");
29
+ const prompt =
30
+ "Can you make a luxury gold themed dashboard with charts and login features?";
31
+ const config = await EbadeArchitect.plan(prompt);
32
+
33
+ // Check intelligence
34
+ assert.strictEqual(
35
+ config.name,
36
+ "LuxuryGold",
37
+ "Should filter filler words like 'Can you make a'"
38
+ );
39
+ assert.strictEqual(
40
+ config.design.colors.primary,
41
+ "#fbbf24",
42
+ "Gold detection failed"
43
+ );
44
+ assert.ok(
45
+ config.features.includes("Advanced Analytics"),
46
+ "Analytics detection failed"
47
+ );
48
+ assert.ok(
49
+ config.features.includes("Authentication"),
50
+ "Auth detection failed"
51
+ );
52
+
53
+ // Check Type-Aware Pages
54
+ assert.strictEqual(
55
+ config.pages.length,
56
+ 2,
57
+ "Should have landing and dashboard"
58
+ );
59
+ assert.ok(
60
+ config.pages.some((p) => p.path === "/dashboard"),
61
+ "Dashboard page missing"
62
+ );
63
+ console.log("โœ… Complex Intent mapping OK");
64
+
65
+ // 3. Project Type Specifics (E-commerce)
66
+ console.log("\nTesting EbadeArchitect (E-commerce)...");
67
+ const shopConfig = await EbadeArchitect.plan(
68
+ "Sleek shoe store with red theme"
69
+ );
70
+ assert.strictEqual(shopConfig.type, "e-commerce");
71
+ assert.ok(
72
+ shopConfig.pages.some((p) => p.path === "/products"),
73
+ "E-commerce missing /products"
74
+ );
75
+ assert.ok(
76
+ shopConfig.pages.some((p) => p.path === "/cart"),
77
+ "E-commerce missing /cart"
78
+ );
79
+ console.log("โœ… E-commerce structure OK");
80
+
81
+ // 4. Project Type Specifics (Blog)
82
+ console.log("\nTesting EbadeArchitect (Blog)...");
83
+ const blogConfig = await EbadeArchitect.plan("Ocean themed news blog");
84
+ assert.strictEqual(blogConfig.type, "blog");
85
+ assert.ok(
86
+ blogConfig.pages.some((p) => p.path === "/posts"),
87
+ "Blog missing /posts index"
88
+ );
89
+ assert.ok(
90
+ blogConfig.pages.some((p) => p.path === "/posts/[slug]"),
91
+ "Blog missing /posts/[slug] dynamic route"
92
+ );
93
+ console.log("โœ… Blog structure OK");
94
+
95
+ console.log("\nโœจ All framework tests passed!");
96
+ }
97
+
98
+ runTests().catch((err) => {
99
+ console.error("\nโŒ Test failed:");
100
+ console.error(err);
101
+ process.exit(1);
102
+ });
package/www/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "www",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "next dev",