ebade 0.4.5 → 0.4.7

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/cli/utils.js ADDED
@@ -0,0 +1,98 @@
1
+ import fs from "fs";
2
+
3
+ export function toPascalCase(str) {
4
+ return str
5
+ .split(/[-_]/)
6
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
7
+ .join("");
8
+ }
9
+
10
+ export function toSnakeCase(str) {
11
+ return str
12
+ .replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
13
+ .replace(/-/g, "_")
14
+ .toLowerCase()
15
+ .replace(/^_/, "");
16
+ }
17
+
18
+ export function hexToHsl(hex) {
19
+ let r = 0,
20
+ g = 0,
21
+ b = 0;
22
+ if (hex.length === 4) {
23
+ r = parseInt(hex[1] + hex[1], 16);
24
+ g = parseInt(hex[2] + hex[2], 16);
25
+ b = parseInt(hex[3] + hex[3], 16);
26
+ } else if (hex.length === 7) {
27
+ r = parseInt(hex.slice(1, 3), 16);
28
+ g = parseInt(hex.slice(3, 5), 16);
29
+ b = parseInt(hex.slice(5, 7), 16);
30
+ }
31
+ r /= 255;
32
+ g /= 255;
33
+ b /= 255;
34
+ let max = Math.max(r, g, b),
35
+ min = Math.min(r, g, b);
36
+ let h,
37
+ s,
38
+ l = (max + min) / 2;
39
+ if (max === min) h = s = 0;
40
+ else {
41
+ let d = max - min;
42
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
43
+ switch (max) {
44
+ case r:
45
+ h = (g - b) / d + (g < b ? 6 : 0);
46
+ break;
47
+ case g:
48
+ h = (b - r) / d + 2;
49
+ break;
50
+ case b:
51
+ h = (r - g) / d + 4;
52
+ break;
53
+ }
54
+ h /= 6;
55
+ }
56
+ return `${Math.round(h * 360)} ${Math.round(s * 100)}% ${Math.round(
57
+ l * 100
58
+ )}%`;
59
+ }
60
+
61
+ export function mapToSqlType(type) {
62
+ const typeMap = {
63
+ uuid: "UUID PRIMARY KEY DEFAULT gen_random_uuid()",
64
+ string: "VARCHAR(255)",
65
+ text: "TEXT",
66
+ integer: "INTEGER",
67
+ decimal: "DECIMAL(10,2)",
68
+ boolean: "BOOLEAN",
69
+ timestamp: "TIMESTAMP WITH TIME ZONE DEFAULT NOW()",
70
+ json: "JSONB",
71
+ array: "JSONB",
72
+ enum: "VARCHAR(50)",
73
+ };
74
+ return typeMap[type] || "VARCHAR(255)";
75
+ }
76
+
77
+ export function ensureDir(dir) {
78
+ if (!fs.existsSync(dir)) {
79
+ fs.mkdirSync(dir, { recursive: true });
80
+ }
81
+ }
82
+
83
+ import { execSync } from "child_process";
84
+
85
+ export function formatProject(projectDir) {
86
+ try {
87
+ // Try to use local prettier if it exists, otherwise npx
88
+ execSync(
89
+ `npx prettier --write "${projectDir}/**/*.{ts,tsx,js,jsx,html,css,json,yaml,md}" --ignore-path .gitignore`,
90
+ {
91
+ stdio: "ignore",
92
+ }
93
+ );
94
+ return true;
95
+ } catch (e) {
96
+ return false;
97
+ }
98
+ }
package/docs/GREEN-AI.md CHANGED
@@ -41,11 +41,11 @@ Based on our benchmarks, switching to **ebade** for AI agent workflows saves:
41
41
 
42
42
  ## 🧠 The Efficiency Philosophy
43
43
 
44
- Traditional frameworks are human-centric. They require the AI to write huge amounts of "how" code (boilerplate, imports, setup). **ebade** is agent-centric. It only needs the "what" (intent).
44
+ Traditional frameworks are human-centric. They require the AI to write huge amounts of "how" code (boilerplate, imports, setup). **ebade** uses a hybrid approach to eliminate this waste.
45
45
 
46
46
  ```text
47
- Human-Centric (Next.js): AI writes IMPLEMENTATION → Bloated Context → High Carbon
48
- Agent-Centric (ebade): AI writes ESSENCE (ebade) → Lean Context → Low Carbon
47
+ 1. Offline Architect (Local): 0 Tokens → Handles all boilerplate & structure.
48
+ 2. Online Engineer (Agent): Low Tokens → Handles only specific business logic.
49
49
  ```
50
50
 
51
51
  **Same result. Fraction of the energy.**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ebade",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
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",
@@ -42,5 +42,8 @@
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=18.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "prettier": "^3.7.4"
45
48
  }
46
49
  }
@@ -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.7",
4
+ "description": "MCP Server for ebade v0.4.7 - 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.7)
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.7",
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.7 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,60 @@
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 runMultiTargetTests() {
7
+ console.log("🧪 Running Multi-Target TDD Tests...\n");
8
+
9
+ const PROJECT_NAME = "SimpleStatic";
10
+ if (fs.existsSync(PROJECT_NAME)) {
11
+ fs.rmSync(PROJECT_NAME, { recursive: true, force: true });
12
+ }
13
+
14
+ try {
15
+ // 1. Test 'ebade build' with --target html
16
+ console.log(`Testing '--target html' for ${PROJECT_NAME}...`);
17
+ // Note: This will fail initially because --target flag and adapter aren't implemented yet.
18
+ // This is the 'RED' phase of TDD.
19
+ const cmd = `node cli/scaffold.js build "A simple static site" --target html`;
20
+
21
+ execSync(cmd, { stdio: "inherit" });
22
+
23
+ const projectDir = path.join(process.cwd(), PROJECT_NAME);
24
+
25
+ assert.ok(
26
+ fs.existsSync(projectDir),
27
+ `Project directory (${PROJECT_NAME}) should exist`
28
+ );
29
+
30
+ // Vanilla HTML expected files
31
+ assert.ok(
32
+ fs.existsSync(path.join(projectDir, "index.html")),
33
+ "index.html should be generated for HTML target"
34
+ );
35
+ assert.ok(
36
+ fs.existsSync(path.join(projectDir, "styles.css")),
37
+ "styles.css should be generated for HTML target"
38
+ );
39
+
40
+ // Ensure Next.js files are NOT generated
41
+ assert.ok(
42
+ !fs.existsSync(path.join(projectDir, "app/page.tsx")),
43
+ "Next.js app directory should NOT exist for HTML target"
44
+ );
45
+
46
+ console.log("āœ… Multi-Target TDD Test OK");
47
+ } catch (err) {
48
+ console.log("\nāŒ TDD Test failed (Expected if not implemented yet):");
49
+ console.error(err.message);
50
+ // In TDD 'Red' phase, we don't necessarily exit(1) if we expect failure,
51
+ // but here we want to see it fail.
52
+ } finally {
53
+ // Cleanup
54
+ if (fs.existsSync(PROJECT_NAME)) {
55
+ fs.rmSync(PROJECT_NAME, { recursive: true, force: true });
56
+ }
57
+ }
58
+ }
59
+
60
+ runMultiTargetTests();
@@ -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.7)...\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
+ });
@@ -0,0 +1,54 @@
1
+ # ebade v0.4.7 Build Demo
2
+ # Run with: vhs vhs/build-demo.tape
3
+
4
+ Output ../assets/build-demo.gif
5
+ Output ../assets/build-demo.mp4
6
+
7
+ Set FontSize 20
8
+ Set Width 1200
9
+ Set Height 800
10
+ Set Theme "Catppuccin Mocha"
11
+ Set Padding 40
12
+ Set TypingSpeed 60ms
13
+
14
+ # Start fresh
15
+ Hide
16
+ Type "rm -rf LuxuryConcierge"
17
+ Enter
18
+ Type "clear"
19
+ Enter
20
+ Sleep 500ms
21
+ Show
22
+
23
+ # Step 1: The Prompt
24
+ Type "# šŸ›”ļø Phase I: The Offline Architect"
25
+ Enter
26
+ Sleep 1s
27
+ Type "# Designing a project with 0 tokens using NPX..."
28
+ Enter
29
+ Sleep 1.5s
30
+
31
+ # The magic command using npx
32
+ Type "npx ebade build 'A luxury concierge service with pricing, testimonials and a gold theme'"
33
+ Sleep 500ms
34
+ Enter
35
+
36
+ # Wait for the Architect to work (Creative Brief output)
37
+ Sleep 15s
38
+
39
+ # Step 2: Show the result
40
+ Type "# āœ… Project designed and scaffolded in seconds."
41
+ Enter
42
+ Sleep 1.5s
43
+ Type "ls -R LuxuryConcierge/app"
44
+ Enter
45
+ Sleep 4s
46
+
47
+ # Final tagline
48
+ Type "# šŸŒ“ ebade: Hybrid Workflow."
49
+ Enter
50
+ Sleep 1s
51
+ Type "# → Get started at ebade.dev"
52
+ Enter
53
+
54
+ Sleep 4s
@@ -1,10 +1,10 @@
1
1
  # ebade Demo Video Script
2
- # Run with: vhs demo.tape
2
+ # Run with: vhs vhs/demo.tape
3
3
  # Outputs: demo.gif + demo.mp4
4
4
 
5
5
  # Outputs - both formats
6
- Output assets/demo.gif
7
- Output assets/demo.mp4
6
+ Output ../assets/demo.gif
7
+ Output ../assets/demo.mp4
8
8
 
9
9
  # Configuration
10
10
  Set FontSize 20
package/www/app/page.tsx CHANGED
@@ -67,7 +67,7 @@ export default function HomePage() {
67
67
  <div className="visual-glow"></div>
68
68
  <div className="video-container">
69
69
  <video className="hero-video" autoPlay loop muted playsInline>
70
- <source src="/assets/demo.mp4" type="video/mp4" />
70
+ <source src="/assets/build-demo.mp4" type="video/mp4" />
71
71
  </video>
72
72
  </div>
73
73
  </div>
package/www/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "www",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "next dev",
Binary file
Binary file