ebade 0.1.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/ROADMAP.md ADDED
@@ -0,0 +1,119 @@
1
+ # ebade Roadmap πŸ—ΊοΈ
2
+
3
+ > Building the first framework designed FOR AI agents - The Essence of Code.
4
+
5
+ ---
6
+
7
+ ## 🎯 Vision
8
+
9
+ **ebade** becomes the native language for AI agents to build web applications.
10
+ When a user asks an AI to "build me an e-commerce site", the AI speaks ebade.
11
+ It's more efficient, deterministic, and KIND TO EARTH. 🌱
12
+
13
+ ---
14
+
15
+ ## Phase 1: Foundation (Week 1-2) βœ… IN PROGRESS
16
+
17
+ ### 1.1 MCP Server
18
+
19
+ Make ebade usable by AI agents RIGHT NOW.
20
+
21
+ - [x] Create MCP server package
22
+ - [x] `ebade_scaffold` tool - generate project from ebade
23
+ - [x] `ebade_validate` tool - validate ebade file
24
+ - [x] `ebade_compile` tool - compile single ebade to code
25
+ - [x] `ebade_generate` tool - infer ebade from natural language
26
+
27
+ ### 1.2 Real Compiler
28
+
29
+ Replace string templates with actual AST-based compilation.
30
+
31
+ - [ ] ebade parser (YAML/TS β†’ AST)
32
+ - [ ] Code generator (AST β†’ React/Next.js)
33
+ - [ ] Support for multiple framework targets
34
+
35
+ ### 1.3 CLI Improvements
36
+
37
+ - [ ] `ebade init` - interactive project setup
38
+ - [ ] `ebade dev` - watch mode with local agent sync
39
+
40
+ ---
41
+
42
+ ## Phase 2: Developer Experience (Week 3-4)
43
+
44
+ ### 2.1 VS Code Extension
45
+
46
+ - [ ] Syntax highlighting for ebade decorators
47
+ - [ ] Autocomplete for inferred patterns
48
+ - [ ] Inline token usage counter (Carbon counter! 🌱)
49
+
50
+ ### 2.2 Playground Website
51
+
52
+ - [ ] Live editor (Monaco)
53
+ - [ ] Real-time compilation preview
54
+ - [ ] Share ebade via URL
55
+
56
+ ### 2.3 Documentation Site
57
+
58
+ - [ ] "The Turkish Story" - The meaning of ebade
59
+ - [ ] Getting started for Agents
60
+ - [ ] Getting started for Humans
61
+
62
+ ---
63
+
64
+ ## Phase 3: Ecosystem (Month 2)
65
+
66
+ ### 3.1 ebade Registry
67
+
68
+ - [ ] npm-like registry for reusable intents
69
+ - [ ] `ebade add auth/clerk`
70
+ - [ ] `ebade add blog/minimal`
71
+
72
+ ### 3.2 Framework Targets
73
+
74
+ - [ ] Next.js App Router βœ… (v0.1)
75
+ - [ ] Vue 3 + Nuxt
76
+ - [ ] Svelte + SvelteKit
77
+ - [ ] Mobile (React Native / Flutter)
78
+
79
+ ### 3.3 The "Badik" Mascot 🐣
80
+
81
+ - [ ] Community names
82
+ - [ ] Logo design
83
+ - [ ] Swag / Stickers
84
+
85
+ ---
86
+
87
+ ## Phase 4: AI Native Features (Month 3)
88
+
89
+ ### 4.1 Green AI Optimization
90
+
91
+ - [ ] Auto-optimize ebade definitions for minimum token count.
92
+ - [ ] Carbon offset calculations per line of code.
93
+
94
+ ### 4.2 Multi-Agent Orchestration
95
+
96
+ - [ ] System for multiple agents to collaborate on a single ebade file synchronously.
97
+
98
+ ---
99
+
100
+ ## Success Metrics (3 Months)
101
+
102
+ | Metric | Target | Mission |
103
+ | :--- | :--- | :--- |
104
+ | Token Savings | >70% | Efficiency |
105
+ | Carbon Saved | >100kg | Sustainability |
106
+ | Framework Targets | 3 | Accessibility |
107
+ | Community Size | 1,000 "Badiks" | Impact |
108
+
109
+ ---
110
+
111
+ ## Current Status
112
+
113
+ **Phase 1.1 - MCP Server** ← WE ARE HERE
114
+
115
+ The MCP server is live. AI agents can now use ebade to scaffold full Next.js apps with 65% fewer tokens.
116
+
117
+ ---
118
+
119
+ *Last updated: 2026-01-07*
package/SYNTAX.md ADDED
@@ -0,0 +1,515 @@
1
+ # ebade Syntax Specification πŸ“–
2
+
3
+ > **Code is a function of ebade.**
4
+ > `Code = f(ebade)`
5
+
6
+ This document defines the syntax and decorators used in ebade to define application intents.
7
+
8
+ ## Core Principle: ebb-and-flow of intent
9
+
10
+ In ebade, you don't write implementation details. You define the **intent** of a component, page, or API. The ebade compiler then transforms this intent into framework-specific code (e.g., Next.js, Vue, Svelte).
11
+
12
+ ---
13
+
14
+ ## File Extensions
15
+
16
+ - `.intent.js` / `.intent.ts` β€” ebade definitions
17
+ - `.intent.yaml` β€” Declarative ebade configs
18
+ - `ebade.config.js` β€” Project-level ebade configuration
19
+
20
+ ---
21
+
22
+ ## πŸ—οΈ Project Intent (`project.intent.yaml`)
23
+
24
+ The project-level ebade defines the overall structure and features of the application.
25
+
26
+ ```yaml
27
+ name: my-app
28
+ type: saas-dashboard | e-commerce | blog | landing-page | portfolio
29
+ features:
30
+ - user-auth
31
+ - payments
32
+ - analytics
33
+ - search
34
+ - database
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Decorators
40
+
41
+ ### @page(path)
42
+
43
+ Defines a page/route.
44
+
45
+ ```typescript
46
+ @page('/products')
47
+ @page('/products/[id]')
48
+ @page('/users/[userId]/orders/[orderId]')
49
+ ```
50
+
51
+ ### @intent(name)
52
+
53
+ Declares the purpose of this component/page.
54
+
55
+ ```typescript
56
+ @intent('product-listing')
57
+ @intent('user-authentication')
58
+ @intent('checkout-flow')
59
+ ```
60
+
61
+ ### @requires(dependencies)
62
+
63
+ Specifies what this ebade needs to function.
64
+
65
+ ```typescript
66
+ @requires({
67
+ data: ['products', 'categories'], // Data dependencies
68
+ auth: 'required' | 'optional' | 'none',
69
+ permissions: ['admin', 'editor'],
70
+ features: ['dark-mode', 'analytics']
71
+ })
72
+ ```
73
+
74
+ ### @outcomes(results)
75
+
76
+ Defines possible outcomes and their handlers.
77
+
78
+ ```typescript
79
+ @outcomes({
80
+ success: '/success-page',
81
+ success: { redirect: '/dashboard', toast: 'Welcome!' },
82
+ error: { show: 'inline', retry: true },
83
+ loading: { skeleton: true },
84
+ empty: { message: 'No items found', action: 'create-first' }
85
+ })
86
+ ```
87
+
88
+ ### @data(fetcher)
89
+
90
+ Defines how to fetch data for this ebade.
91
+
92
+ ```typescript
93
+ @data(async ({ params, query }) => {
94
+ return db.products.findMany({
95
+ where: { category: params.category },
96
+ limit: query.limit || 20
97
+ });
98
+ })
99
+ ```
100
+
101
+ ### @validate(rules)
102
+
103
+ Input validation rules.
104
+
105
+ ```typescript
106
+ @validate({
107
+ email: ['required', 'email'],
108
+ password: ['required', 'min:8', 'has-uppercase', 'has-number'],
109
+ age: ['required', 'number', 'min:18']
110
+ })
111
+ ```
112
+
113
+ ### @style(design)
114
+
115
+ Visual styling from design system.
116
+
117
+ ```typescript
118
+ @style('card/elevated')
119
+ @style({ variant: 'primary', size: 'lg', rounded: true })
120
+ ```
121
+
122
+ ### @compose(intents)
123
+
124
+ Combines multiple ebade definitions.
125
+
126
+ ```typescript
127
+ @compose(['header', 'sidebar', 'main-content', 'footer'])
128
+ ```
129
+
130
+ ### @on(event, handler)
131
+
132
+ Event handlers.
133
+
134
+ ```typescript
135
+ @on('submit', async (data) => createOrder(data))
136
+ @on('error', (e) => logError(e))
137
+ ```
138
+
139
+ ### @expects(scenarios)
140
+
141
+ Defines expected behaviors for testing. **Tests become part of the ebade.**
142
+
143
+ ```typescript
144
+ @expects([
145
+ {
146
+ scenario: 'happy-path',
147
+ given: { productId: 1, quantity: 2 },
148
+ when: 'add-to-cart',
149
+ then: 'cart-updated',
150
+ assert: { cartCount: 2 }
151
+ },
152
+ {
153
+ scenario: 'out-of-stock',
154
+ given: { productId: 1, stock: 0 },
155
+ when: 'add-to-cart',
156
+ then: 'error',
157
+ error: 'Product is out of stock'
158
+ },
159
+ {
160
+ scenario: 'invalid-quantity',
161
+ given: { productId: 1, quantity: -1 },
162
+ when: 'add-to-cart',
163
+ then: 'error',
164
+ error: 'Quantity must be positive'
165
+ }
166
+ ])
167
+ ```
168
+
169
+ This automatically generates test files during compilation:
170
+
171
+ ```typescript
172
+ // Generated: add-to-cart.test.ts
173
+
174
+ describe('add-to-cart', () => {
175
+ it('happy-path: should update cart', async () => {
176
+ const result = await addToCart({ productId: 1, quantity: 2 });
177
+ expect(result.outcome).toBe('cart-updated');
178
+ expect(result.cartCount).toBe(2);
179
+ });
180
+
181
+ it('out-of-stock: should show error', async () => {
182
+ const result = await addToCart({ productId: 1, stock: 0 });
183
+ expect(result.outcome).toBe('error');
184
+ expect(result.error).toBe('Product is out of stock');
185
+ });
186
+
187
+ it('invalid-quantity: should reject negative', async () => {
188
+ const result = await addToCart({ productId: 1, quantity: -1 });
189
+ expect(result.outcome).toBe('error');
190
+ expect(result.error).toBe('Quantity must be positive');
191
+ });
192
+ });
193
+ ```
194
+
195
+ #### Full Example with @expects
196
+
197
+ ```typescript
198
+ // auth/login.intent.ts
199
+
200
+ @intent('user-login')
201
+ @inputs({
202
+ email: { type: 'email', required: true },
203
+ password: { type: 'password', required: true }
204
+ })
205
+ @validate({
206
+ email: ['required', 'email'],
207
+ password: ['required', 'min:8']
208
+ })
209
+ @expects([
210
+ {
211
+ scenario: 'valid-credentials',
212
+ given: { email: 'user@test.com', password: 'ValidPass123' },
213
+ mocks: { db: { user: { id: 1, verified: true } } },
214
+ then: 'success',
215
+ assert: { redirect: '/dashboard' }
216
+ },
217
+ {
218
+ scenario: 'invalid-password',
219
+ given: { email: 'user@test.com', password: 'wrong' },
220
+ mocks: { db: { user: null } },
221
+ then: 'error',
222
+ error: 'Invalid email or password'
223
+ },
224
+ {
225
+ scenario: 'unverified-email',
226
+ given: { email: 'new@test.com', password: 'ValidPass123' },
227
+ mocks: { db: { user: { id: 2, verified: false } } },
228
+ then: 'redirect',
229
+ assert: { redirect: '/verify-email' }
230
+ },
231
+ {
232
+ scenario: 'rate-limited',
233
+ given: { email: 'user@test.com', password: 'wrong' },
234
+ context: { failedAttempts: 5 },
235
+ then: 'error',
236
+ error: 'Too many attempts. Try again later.'
237
+ }
238
+ ])
239
+ @outcomes({
240
+ success: { redirect: '/dashboard', toast: 'Welcome back!' },
241
+ error: { show: 'inline' },
242
+ redirect: { to: 'context.redirect' }
243
+ })
244
+ export function LoginForm({ onSubmit }) {
245
+ // Business logic only
246
+ }
247
+ ```
248
+
249
+ #### Why Tests in ebade?
250
+
251
+ | Traditional | ebade |
252
+ |-------------|----------|
253
+ | Write code, then write tests | Define expectations upfront |
254
+ | Tests in separate files | Tests in same definition |
255
+ | Easy to forget edge cases | Edge cases are first-class |
256
+ | Tests as afterthought | Tests as specification |
257
+
258
+ > **ebade-Driven Testing**: You're not testing code, you're testing ebade.
259
+
260
+ ---
261
+
262
+ ## Component Definition
263
+
264
+ ### Basic Component
265
+
266
+ ```typescript
267
+ // product-card.intent.ts
268
+
269
+ @intent('display-product')
270
+ @displays(['image', 'title', 'price', 'rating'])
271
+ @actions(['add-to-cart', 'add-to-wishlist', 'quick-view'])
272
+ @style('e-commerce/product-card')
273
+ export function ProductCard({ product }) {
274
+ // Only business logic, no boilerplate
275
+ }
276
+ ```
277
+
278
+ ### Page Definition
279
+
280
+ ```typescript
281
+ // checkout.intent.ts
282
+
283
+ @page('/checkout')
284
+ @intent('complete-purchase')
285
+ @requires({
286
+ data: ['cart', 'user'],
287
+ auth: 'required'
288
+ })
289
+ @outcomes({
290
+ success: '/orders/[orderId]',
291
+ paymentFailed: { show: 'error', retry: true },
292
+ cartEmpty: { redirect: '/products', message: 'Your cart is empty' }
293
+ })
294
+ @compose([
295
+ 'order-summary',
296
+ 'shipping-form',
297
+ 'payment-form',
298
+ 'place-order-button'
299
+ ])
300
+ export function CheckoutPage({ cart, user }) {
301
+ return <CheckoutFlow cart={cart} user={user} />;
302
+ }
303
+ ```
304
+
305
+ ### Form Definition
306
+
307
+ ```typescript
308
+ // contact-form.intent.ts
309
+
310
+ @intent('collect-contact-info')
311
+ @fields({
312
+ name: { type: 'text', required: true, label: 'Full Name' },
313
+ email: { type: 'email', required: true },
314
+ message: { type: 'textarea', required: true, rows: 5 },
315
+ category: {
316
+ type: 'select',
317
+ options: ['support', 'sales', 'feedback'],
318
+ default: 'support'
319
+ }
320
+ })
321
+ @validate({
322
+ name: ['required', 'min:2'],
323
+ email: ['required', 'email'],
324
+ message: ['required', 'min:10']
325
+ })
326
+ @on('submit', async (data) => sendContactForm(data))
327
+ @outcomes({
328
+ success: { show: 'toast', message: 'Message sent!' },
329
+ error: { show: 'inline' }
330
+ })
331
+ export function ContactForm() {}
332
+ ```
333
+
334
+ ---
335
+
336
+ ## Data Intents
337
+
338
+ ```typescript
339
+ // data/products.intent.ts
340
+
341
+ @dataSource('products')
342
+ @provider('supabase')
343
+ @table('products')
344
+ @schema({
345
+ id: 'uuid',
346
+ name: 'string',
347
+ price: 'decimal',
348
+ category: 'string',
349
+ stock: 'integer',
350
+ images: 'array<string>',
351
+ createdAt: 'timestamp'
352
+ })
353
+ @queries({
354
+ list: { orderBy: 'createdAt', limit: 20 },
355
+ byCategory: (category) => ({ where: { category } }),
356
+ search: (term) => ({ where: { name: { contains: term } } })
357
+ })
358
+ export const ProductsData = defineData();
359
+ ```
360
+
361
+ ---
362
+
363
+ ## API Intents
364
+
365
+ ```typescript
366
+ // api/orders.intent.ts
367
+
368
+ @api('/api/orders')
369
+ @intent('order-management')
370
+ @auth('required')
371
+
372
+ @get('/')
373
+ @returns('Order[]')
374
+ async function listOrders({ user }) {
375
+ return db.orders.findMany({ where: { userId: user.id } });
376
+ }
377
+
378
+ @post('/')
379
+ @validate({ items: 'required', shippingAddress: 'required' })
380
+ @returns('Order')
381
+ async function createOrder({ body, user }) {
382
+ return db.orders.create({ ...body, userId: user.id });
383
+ }
384
+
385
+ @get('/[id]')
386
+ @returns('Order')
387
+ async function getOrder({ params, user }) {
388
+ return db.orders.findOne({ id: params.id, userId: user.id });
389
+ }
390
+ ```
391
+
392
+ ---
393
+
394
+ ## Layout Intents
395
+
396
+ ```typescript
397
+ // layouts/main.intent.ts
398
+
399
+ @layout('main')
400
+ @compose([
401
+ { slot: 'header', intent: 'navigation-header' },
402
+ { slot: 'sidebar', intent: 'main-sidebar', show: 'desktop-only' },
403
+ { slot: 'main', intent: 'page-content' },
404
+ { slot: 'footer', intent: 'site-footer' }
405
+ ])
406
+ @style('layout/dashboard')
407
+ export function MainLayout({ children }) {
408
+ return children;
409
+ }
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Full Example: E-commerce Product Page
415
+
416
+ ```typescript
417
+ // products/[id].intent.ts
418
+
419
+ @page('/products/[id]')
420
+ @intent('view-product-details')
421
+ @data(async ({ params }) => ({
422
+ product: await db.products.findUnique({ id: params.id }),
423
+ reviews: await db.reviews.findMany({ productId: params.id }),
424
+ related: await db.products.findRelated(params.id, { limit: 4 })
425
+ }))
426
+ @outcomes({
427
+ notFound: '/404',
428
+ success: 'render'
429
+ })
430
+ @seo(({ product }) => ({
431
+ title: product.name,
432
+ description: product.description,
433
+ image: product.images[0]
434
+ }))
435
+ @compose([
436
+ 'product-gallery',
437
+ 'product-info',
438
+ 'add-to-cart-section',
439
+ 'product-tabs', // description, specs, reviews
440
+ 'related-products'
441
+ ])
442
+ export function ProductPage({ product, reviews, related }) {
443
+ return (
444
+ <ProductPageLayout>
445
+ <ProductGallery images={product.images} />
446
+ <ProductInfo product={product} />
447
+ <AddToCart product={product} />
448
+ <ProductTabs description={product.description} reviews={reviews} />
449
+ <RelatedProducts products={related} />
450
+ </ProductPageLayout>
451
+ );
452
+ }
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Compiler Output
458
+
459
+ The above intent compiles to standard Next.js/React:
460
+
461
+ ```typescript
462
+ // Compiled: app/products/[id]/page.tsx
463
+
464
+ import { notFound } from 'next/navigation';
465
+ import { Metadata } from 'next';
466
+ // ... 50+ lines of imports
467
+
468
+ export async function generateMetadata({ params }): Promise<Metadata> {
469
+ const product = await db.products.findUnique({ id: params.id });
470
+ if (!product) return {};
471
+ return {
472
+ title: product.name,
473
+ description: product.description,
474
+ openGraph: { images: [product.images[0]] }
475
+ };
476
+ }
477
+
478
+ export default async function ProductPage({ params }) {
479
+ const product = await db.products.findUnique({ id: params.id });
480
+ if (!product) notFound();
481
+
482
+ const reviews = await db.reviews.findMany({ productId: params.id });
483
+ const related = await db.products.findRelated(params.id, { limit: 4 });
484
+
485
+ return (
486
+ <ProductPageLayout>
487
+ {/* ... full implementation */}
488
+ </ProductPageLayout>
489
+ );
490
+ }
491
+ ```
492
+
493
+ ---
494
+
495
+ ## Design Tokens (from intent)
496
+
497
+ ```typescript
498
+ @style({
499
+ variant: 'primary',
500
+ size: 'lg',
501
+ rounded: true,
502
+ elevation: 'md'
503
+ })
504
+ ```
505
+
506
+ Resolves to:
507
+
508
+ ```css
509
+ .component {
510
+ background-color: var(--color-primary);
511
+ padding: var(--spacing-lg);
512
+ border-radius: var(--radius-lg);
513
+ box-shadow: var(--shadow-md);
514
+ }
515
+ ```