ebade 0.4.0 → 0.4.1
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/ARCHITECTURE.md +109 -0
- package/CHANGELOG.md +3 -1
- package/README.md +61 -199
- package/cli/scaffold.js +150 -9
- package/package.json +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/vscode-extension/package.json +1 -1
- package/www/app/globals.css +301 -38
- package/www/app/page.tsx +118 -86
- package/www/app/playground/page.tsx +13 -30
- package/www/components/Navbar.tsx +67 -0
- package/www/package.json +1 -1
- package/www/public/assets/demo.mp4 +0 -0
package/cli/scaffold.js
CHANGED
|
@@ -13,6 +13,7 @@ import yaml from "yaml";
|
|
|
13
13
|
import ora from "ora";
|
|
14
14
|
import prompts from "prompts";
|
|
15
15
|
import chokidar from "chokidar";
|
|
16
|
+
import { execSync } from "child_process";
|
|
16
17
|
|
|
17
18
|
// ============================================
|
|
18
19
|
// ANSI Renk Kodları (Terminal çıktısı için)
|
|
@@ -39,7 +40,7 @@ ${colors.magenta} ██╔══╝ ${colors.cyan}██╔══██╗$
|
|
|
39
40
|
${colors.magenta} ███████╗${colors.cyan}██████╔╝${colors.magenta}██║ ██║${colors.cyan}██████╔╝${colors.magenta}███████╗
|
|
40
41
|
${colors.magenta} ╚══════╝${colors.cyan}╚═════╝ ${colors.magenta}╚═╝ ╚═╝${colors.cyan}╚═════╝ ${colors.magenta}╚══════╝${colors.reset}
|
|
41
42
|
|
|
42
|
-
${colors.dim}✨ Agent-First Framework ${colors.yellow}v0.1
|
|
43
|
+
${colors.dim}✨ Agent-First Framework ${colors.yellow}v0.4.1${colors.reset}
|
|
43
44
|
`;
|
|
44
45
|
|
|
45
46
|
const log = {
|
|
@@ -47,6 +48,8 @@ const log = {
|
|
|
47
48
|
success: (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`),
|
|
48
49
|
warn: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
|
|
49
50
|
file: (msg) => console.log(`${colors.cyan} →${colors.reset} ${msg}`),
|
|
51
|
+
verify: (msg) => console.log(`${colors.yellow} 🔍${colors.reset} ${msg}`),
|
|
52
|
+
error: (msg) => console.log(`${colors.red} ✘${colors.reset} ${msg}`),
|
|
50
53
|
section: (msg) =>
|
|
51
54
|
console.log(`\n${colors.bright}${colors.magenta}▸ ${msg}${colors.reset}`),
|
|
52
55
|
};
|
|
@@ -657,7 +660,7 @@ function ensureDir(dir) {
|
|
|
657
660
|
// ============================================
|
|
658
661
|
// Main Scaffold Function
|
|
659
662
|
// ============================================
|
|
660
|
-
function scaffold(ebadePath, outputDir) {
|
|
663
|
+
async function scaffold(ebadePath, outputDir) {
|
|
661
664
|
const startTime = Date.now();
|
|
662
665
|
const stats = {
|
|
663
666
|
pages: 0,
|
|
@@ -872,6 +875,10 @@ function scaffold(ebadePath, outputDir) {
|
|
|
872
875
|
fs.copyFileSync(ebadePath, path.join(projectDir, "project.ebade.yaml"));
|
|
873
876
|
log.file("project.ebade.yaml (for agent reference)");
|
|
874
877
|
|
|
878
|
+
// ========== Summary ==========
|
|
879
|
+
// ========== Verify Output ==========
|
|
880
|
+
const verificationResult = await verifyOutput(projectDir, config);
|
|
881
|
+
|
|
875
882
|
// ========== Summary ==========
|
|
876
883
|
const duration = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
877
884
|
|
|
@@ -897,8 +904,16 @@ ${colors.green} │${colors.reset} ${colors.cyan}📊 Token Savings:${
|
|
|
897
904
|
${colors.green} │${colors.reset} ${colors.cyan}⏱ Completed in:${
|
|
898
905
|
colors.reset
|
|
899
906
|
} ${String(duration + "s").padEnd(18)} ${colors.green}│${colors.reset}
|
|
907
|
+
${colors.green} ├${"─".repeat(41)}┤${colors.reset}
|
|
908
|
+
${colors.green} │${colors.reset} ${colors.yellow}🔍 Integrity:${
|
|
909
|
+
colors.reset
|
|
910
|
+
} ${(verificationResult.passed ? "PASSED" : "ISSUES FOUND").padEnd(
|
|
911
|
+
18
|
|
912
|
+
)} ${colors.green}│${colors.reset}
|
|
900
913
|
${colors.green} └${"─".repeat(41)}┘${colors.reset}
|
|
901
914
|
|
|
915
|
+
${verificationResult.report}
|
|
916
|
+
|
|
902
917
|
${colors.dim}Next steps:${colors.reset}
|
|
903
918
|
${colors.gray}1.${colors.reset} cd ${colors.cyan}${projectDir}${colors.reset}
|
|
904
919
|
${colors.gray}2.${colors.reset} npm install
|
|
@@ -911,6 +926,117 @@ ${colors.yellow}💡 Tip:${colors.reset} AI Agents can read ${
|
|
|
911
926
|
`);
|
|
912
927
|
}
|
|
913
928
|
|
|
929
|
+
/**
|
|
930
|
+
* ebade Output Verifier
|
|
931
|
+
* Performs a sanity check on the generated codebase.
|
|
932
|
+
*/
|
|
933
|
+
async function verifyOutput(projectDir, config) {
|
|
934
|
+
log.section("Verifying output integrity");
|
|
935
|
+
const spinner = ora("Running ebade verification protocols...").start();
|
|
936
|
+
|
|
937
|
+
const results = {
|
|
938
|
+
structure: true,
|
|
939
|
+
syntax: true,
|
|
940
|
+
tests: true,
|
|
941
|
+
issues: [],
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
// 1. Structure Check
|
|
945
|
+
const requiredFiles = [
|
|
946
|
+
"package.json",
|
|
947
|
+
"tsconfig.json",
|
|
948
|
+
"app/layout.tsx",
|
|
949
|
+
"app/page.tsx",
|
|
950
|
+
"lib/utils.ts",
|
|
951
|
+
];
|
|
952
|
+
|
|
953
|
+
for (const file of requiredFiles) {
|
|
954
|
+
if (!fs.existsSync(path.join(projectDir, file))) {
|
|
955
|
+
results.structure = false;
|
|
956
|
+
results.issues.push(`Missing core file: ${file}`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// 2. Syntax Check (Lightweight)
|
|
961
|
+
// We check if exports match the intent in some key files
|
|
962
|
+
if (config.pages) {
|
|
963
|
+
config.pages.forEach((page) => {
|
|
964
|
+
const pagePath =
|
|
965
|
+
page.path === "/"
|
|
966
|
+
? "app/page.tsx"
|
|
967
|
+
: `app${page.path.replace("[", "(").replace("]", ")")}/page.tsx`;
|
|
968
|
+
const fullPath = path.join(projectDir, pagePath);
|
|
969
|
+
if (fs.existsSync(fullPath)) {
|
|
970
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
971
|
+
const expectedExport = `export default function ${toPascalCase(
|
|
972
|
+
page.intent
|
|
973
|
+
)}Page()`;
|
|
974
|
+
if (!content.includes(expectedExport)) {
|
|
975
|
+
results.syntax = false;
|
|
976
|
+
results.issues.push(
|
|
977
|
+
`Syntax mismatch in ${pagePath}: Export name should be ${toPascalCase(
|
|
978
|
+
page.intent
|
|
979
|
+
)}Page`
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// 3. Test Coverage Check
|
|
987
|
+
// Ensure every component has a matching test file
|
|
988
|
+
const components = fs
|
|
989
|
+
.readdirSync(path.join(projectDir, "components"))
|
|
990
|
+
.filter((f) => f.endsWith(".tsx") && !f.endsWith(".test.tsx"));
|
|
991
|
+
components.forEach((comp) => {
|
|
992
|
+
const testFile = comp.replace(".tsx", ".test.tsx");
|
|
993
|
+
if (!fs.existsSync(path.join(projectDir, "components", testFile))) {
|
|
994
|
+
results.tests = false;
|
|
995
|
+
results.issues.push(`Missing test for component: ${comp}`);
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
// 4. Semantic Integrity Check
|
|
1000
|
+
// Check if layout imports globals.css
|
|
1001
|
+
const layoutPath = path.join(projectDir, "app/layout.tsx");
|
|
1002
|
+
if (fs.existsSync(layoutPath)) {
|
|
1003
|
+
const content = fs.readFileSync(layoutPath, "utf-8");
|
|
1004
|
+
if (!content.includes('import "./globals.css"')) {
|
|
1005
|
+
results.issues.push(
|
|
1006
|
+
"Semantic Error: Root layout missing global styles import"
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Check if home page has at least one intent-defined component
|
|
1012
|
+
const homePath = path.join(projectDir, "app/page.tsx");
|
|
1013
|
+
if (fs.existsSync(homePath) && config.pages?.[0]?.components?.length > 0) {
|
|
1014
|
+
const content = fs.readFileSync(homePath, "utf-8");
|
|
1015
|
+
const firstComp = toPascalCase(config.pages[0].components[0]);
|
|
1016
|
+
if (!content.includes(`<${firstComp} />`)) {
|
|
1017
|
+
results.issues.push(
|
|
1018
|
+
`Semantic Warning: Home page might be missing the ${firstComp} component`
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
spinner.stop();
|
|
1024
|
+
|
|
1025
|
+
const passed = results.issues.length === 0;
|
|
1026
|
+
|
|
1027
|
+
let report = "";
|
|
1028
|
+
if (passed) {
|
|
1029
|
+
report = `${colors.green} ✓ All integrity checks passed! Code is production-ready.${colors.reset}`;
|
|
1030
|
+
} else {
|
|
1031
|
+
report = `${colors.red} ⚠ Verification found ${results.issues.length} issue(s):${colors.reset}\n`;
|
|
1032
|
+
results.issues.forEach((issue) => {
|
|
1033
|
+
report += ` ${colors.red}•${colors.reset} ${issue}\n`;
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
return { passed, report };
|
|
1038
|
+
}
|
|
1039
|
+
|
|
914
1040
|
// ============================================
|
|
915
1041
|
// CLI Entry Point
|
|
916
1042
|
// ============================================
|
|
@@ -928,6 +1054,7 @@ ${colors.dim}Commands:${colors.reset}
|
|
|
928
1054
|
init Create a new ebade project interactively
|
|
929
1055
|
scaffold <file> [output] Scaffold a project from ebade file
|
|
930
1056
|
dev <file> [output] Watch ebade file and re-scaffold on changes
|
|
1057
|
+
playground Open the ebade playground
|
|
931
1058
|
|
|
932
1059
|
${colors.dim}Examples:${colors.reset}
|
|
933
1060
|
npx ebade init
|
|
@@ -1047,7 +1174,7 @@ ${colors.green}✓${colors.reset} Created ${colors.cyan}${ebadeFilePath}${colors
|
|
|
1047
1174
|
`);
|
|
1048
1175
|
|
|
1049
1176
|
if (response.autoScaffold) {
|
|
1050
|
-
scaffold(ebadeFilePath, outputDir);
|
|
1177
|
+
await scaffold(ebadeFilePath, outputDir);
|
|
1051
1178
|
} else {
|
|
1052
1179
|
console.log(`
|
|
1053
1180
|
${colors.dim}Next steps:${colors.reset}
|
|
@@ -1060,7 +1187,7 @@ ${colors.dim}Next steps:${colors.reset}
|
|
|
1060
1187
|
// ============================================
|
|
1061
1188
|
// Dev Command (Watch Mode)
|
|
1062
1189
|
// ============================================
|
|
1063
|
-
function dev(ebadeFile, outputDir) {
|
|
1190
|
+
async function dev(ebadeFile, outputDir) {
|
|
1064
1191
|
console.log(`
|
|
1065
1192
|
${LOGO}
|
|
1066
1193
|
`);
|
|
@@ -1071,7 +1198,7 @@ ${LOGO}
|
|
|
1071
1198
|
console.log(`${colors.dim}Press Ctrl+C to stop.${colors.reset}\n`);
|
|
1072
1199
|
|
|
1073
1200
|
// Initial scaffold
|
|
1074
|
-
scaffold(ebadeFile, outputDir);
|
|
1201
|
+
await scaffold(ebadeFile, outputDir);
|
|
1075
1202
|
|
|
1076
1203
|
// Watch for changes
|
|
1077
1204
|
const watcher = chokidar.watch(ebadeFile, {
|
|
@@ -1079,11 +1206,11 @@ ${LOGO}
|
|
|
1079
1206
|
ignoreInitial: true,
|
|
1080
1207
|
});
|
|
1081
1208
|
|
|
1082
|
-
watcher.on("change", () => {
|
|
1209
|
+
watcher.on("change", async () => {
|
|
1083
1210
|
console.log(
|
|
1084
1211
|
`\n${colors.yellow}⚡ Change detected!${colors.reset} Re-scaffolding...\n`
|
|
1085
1212
|
);
|
|
1086
|
-
scaffold(ebadeFile, outputDir);
|
|
1213
|
+
await scaffold(ebadeFile, outputDir);
|
|
1087
1214
|
});
|
|
1088
1215
|
|
|
1089
1216
|
watcher.on("error", (error) => {
|
|
@@ -1127,7 +1254,21 @@ if (command === "init") {
|
|
|
1127
1254
|
process.exit(1);
|
|
1128
1255
|
}
|
|
1129
1256
|
|
|
1130
|
-
scaffold(ebadeFile, outputDir);
|
|
1257
|
+
await scaffold(ebadeFile, outputDir);
|
|
1258
|
+
} else if (command === "playground") {
|
|
1259
|
+
console.log(`\n${colors.cyan}🌐 Opening ebade playground...${colors.reset}`);
|
|
1260
|
+
const url = "https://ebade.dev/playground";
|
|
1261
|
+
const start =
|
|
1262
|
+
process.platform === "darwin"
|
|
1263
|
+
? "open"
|
|
1264
|
+
: process.platform === "win32"
|
|
1265
|
+
? "start"
|
|
1266
|
+
: "xdg-open";
|
|
1267
|
+
try {
|
|
1268
|
+
execSync(`${start} ${url}`);
|
|
1269
|
+
} catch (e) {
|
|
1270
|
+
console.log(`\n${colors.yellow}Please open:${colors.reset} ${url}`);
|
|
1271
|
+
}
|
|
1131
1272
|
} else if (command === "dev") {
|
|
1132
1273
|
const ebadeFile = args[1];
|
|
1133
1274
|
const outputDir = args[2] || "./output";
|
|
@@ -1149,7 +1290,7 @@ if (command === "init") {
|
|
|
1149
1290
|
process.exit(1);
|
|
1150
1291
|
}
|
|
1151
1292
|
|
|
1152
|
-
dev(ebadeFile, outputDir);
|
|
1293
|
+
await dev(ebadeFile, outputDir);
|
|
1153
1294
|
} else {
|
|
1154
1295
|
console.error(
|
|
1155
1296
|
`${colors.red}Error:${colors.reset} Unknown command: ${command}`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ebade/mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "MCP Server for ebade v0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "MCP Server for ebade v0.4.1 - The Agent-First Framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ebade",
|
|
3
3
|
"displayName": "ebade - Agent-First Framework",
|
|
4
4
|
"description": "Syntax highlighting and snippets for ebade (.ebade.yaml) files",
|
|
5
|
-
"version": "0.4.
|
|
5
|
+
"version": "0.4.1",
|
|
6
6
|
"publisher": "hasankemaldemirci",
|
|
7
7
|
"icon": "images/icon.png",
|
|
8
8
|
"engines": {
|