agent-enderun 0.1.10 → 0.2.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/.enderun/BRAIN_DASHBOARD.md +43 -0
- package/.enderun/ENDERUN.md +203 -0
- package/.enderun/PROJECT_MEMORY.md +137 -36
- package/.enderun/agents/analyst.md +21 -10
- package/.enderun/agents/backend.md +12 -11
- package/.enderun/agents/explorer.md +10 -7
- package/.enderun/agents/frontend.md +9 -20
- package/.enderun/agents/git.md +16 -12
- package/.enderun/agents/manager.md +14 -15
- package/.enderun/agents/mobile.md +5 -5
- package/.enderun/agents/native.md +5 -5
- package/.enderun/benchmarks/.gitkeep +0 -0
- package/.enderun/cli-commands.json +13 -1
- package/.enderun/config.json +1 -1
- package/.enderun/docs/api/README.md +10 -9
- package/.enderun/docs/api/auth.md +11 -0
- package/.enderun/docs/api/errors.md +7 -0
- package/.enderun/docs/error-handling.md +12 -0
- package/.enderun/docs/privacy.md +3 -0
- package/.enderun/docs/security.md +12 -0
- package/.enderun/docs/tech-stack.md +1 -0
- package/.enderun/docs/troubleshooting.md +7 -0
- package/.enderun/knowledge/api_design_rules.md +6 -0
- package/.enderun/knowledge/async_error_handling.md +18 -0
- package/.enderun/knowledge/branded_types_pattern.md +1 -0
- package/.enderun/knowledge/code_review_checklist.md +7 -0
- package/.enderun/knowledge/contract_versioning.md +7 -0
- package/.enderun/knowledge/database_migration.md +6 -0
- package/.enderun/knowledge/deployment_checklist.md +7 -0
- package/.enderun/knowledge/git_commit_strategy.md +10 -0
- package/.enderun/knowledge/legacy_onboarding.md +7 -0
- package/.enderun/knowledge/monitoring_setup.md +5 -0
- package/.enderun/knowledge/performance_guidelines.md +11 -0
- package/.enderun/knowledge/repository_patterns.md +9 -0
- package/.enderun/knowledge/security_scanning.md +6 -0
- package/.enderun/knowledge/testing_standards.md +7 -0
- package/.enderun/knowledge/troubleshooting_guide.md +5 -0
- package/.enderun/knowledge/zero_ui_library_policy.md +1 -0
- package/.enderun/logs/analyst.json +1 -0
- package/.enderun/logs/backend.json +1 -0
- package/.enderun/logs/explorer.json +1 -0
- package/.enderun/logs/frontend.json +1 -0
- package/.enderun/logs/git.json +1 -0
- package/.enderun/logs/manager.json +363 -0
- package/.enderun/logs/mobile.json +1 -0
- package/.enderun/logs/native.json +1 -0
- package/.enderun/monitoring/.gitkeep +0 -0
- package/ENDERUN.md +8 -8
- package/LICENSE +21 -0
- package/README.md +595 -195
- package/bin/cli.js +306 -79
- package/package.json +35 -2
- package/packages/framework-mcp/README.md +47 -81
- package/packages/framework-mcp/dist/index.js +13 -971
- package/packages/framework-mcp/dist/schemas.js +84 -0
- package/packages/framework-mcp/dist/tools/academy.js +184 -0
- package/packages/framework-mcp/dist/tools/codebase.js +294 -0
- package/packages/framework-mcp/dist/tools/contract.js +95 -0
- package/packages/framework-mcp/dist/tools/database.js +52 -0
- package/packages/framework-mcp/dist/tools/framework.js +161 -0
- package/packages/framework-mcp/dist/tools/git.js +53 -0
- package/packages/framework-mcp/dist/tools/index.js +42 -0
- package/packages/framework-mcp/dist/tools/knowledge.js +69 -0
- package/packages/framework-mcp/dist/tools/memory.js +94 -0
- package/packages/framework-mcp/dist/tools/messages.js +71 -0
- package/packages/framework-mcp/dist/tools/repository.js +76 -0
- package/packages/framework-mcp/dist/tools/security.js +122 -0
- package/packages/framework-mcp/dist/utils.js +82 -0
- package/packages/framework-mcp/package-lock.json +1836 -0
- package/packages/framework-mcp/package.json +1 -1
- package/packages/framework-mcp/src/index.ts +20 -970
- package/packages/framework-mcp/src/schemas.ts +106 -0
- package/packages/framework-mcp/src/tools/academy.ts +178 -0
- package/packages/framework-mcp/src/tools/codebase.ts +284 -0
- package/packages/framework-mcp/src/tools/contract.ts +91 -0
- package/packages/framework-mcp/src/tools/database.ts +49 -0
- package/packages/framework-mcp/src/tools/framework.ts +157 -0
- package/packages/framework-mcp/src/tools/git.ts +43 -0
- package/packages/framework-mcp/src/tools/index.ts +45 -0
- package/packages/framework-mcp/src/tools/knowledge.ts +68 -0
- package/packages/framework-mcp/src/tools/memory.ts +88 -0
- package/packages/framework-mcp/src/tools/messages.ts +70 -0
- package/packages/framework-mcp/src/tools/repository.ts +76 -0
- package/packages/framework-mcp/src/tools/security.ts +122 -0
- package/packages/framework-mcp/src/utils.ts +90 -0
- package/packages/framework-mcp/tests/mcp-server.test.ts +6 -0
- package/packages/shared-types/README.md +28 -51
- package/packages/shared-types/contract.version.json +4 -4
- package/packages/shared-types/dist/index.d.ts +80 -48
- package/packages/shared-types/dist/index.d.ts.map +1 -1
- package/packages/shared-types/dist/index.js +5 -8
- package/packages/shared-types/dist/index.js.map +1 -1
- package/packages/shared-types/package.json +1 -1
- package/packages/shared-types/src/index.ts +79 -51
- package/CHANGELOG.md +0 -97
- package/CLAUDE.md +0 -7
- package/CODEX.md +0 -7
- package/CURSOR.md +0 -7
- package/GEMINI.md +0 -7
- package/docs/tech-stack.md +0 -10
- package/gemini-extension.json +0 -5
- package/panda.config.ts +0 -20
- /package/{docs → .enderun/docs}/project-docs.md +0 -0
package/bin/cli.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
console.log("🤖 Agent Enderun CLI — Initializing...");
|
|
3
2
|
|
|
4
3
|
import fs from "fs";
|
|
5
4
|
import path from "path";
|
|
@@ -177,12 +176,12 @@ function mergePackageJson(targetPath, sourcePath) {
|
|
|
177
176
|
function updateGitIgnore(targetPath, frameworkDir = ".enderun") {
|
|
178
177
|
const IGNORE_LINES = [
|
|
179
178
|
"# AI-Enderun",
|
|
180
|
-
".
|
|
179
|
+
".enderun/logs/*.json",
|
|
181
180
|
".claude/logs/*.json",
|
|
182
181
|
".cursor/logs/*.json",
|
|
183
182
|
".codex/logs/*.json",
|
|
184
183
|
".enderun/logs/*.json",
|
|
185
|
-
".
|
|
184
|
+
".enderun/*.lock",
|
|
186
185
|
".claude/*.lock",
|
|
187
186
|
".cursor/*.lock",
|
|
188
187
|
".codex/*.lock",
|
|
@@ -312,35 +311,37 @@ async function initCommand(selectedAdapter) {
|
|
|
312
311
|
};
|
|
313
312
|
|
|
314
313
|
const targetBase = selectedAdapter ? `.${selectedAdapter}` : ".enderun";
|
|
314
|
+
|
|
315
315
|
const targetFrameworkDir = path.join(targetDir, targetBase);
|
|
316
316
|
|
|
317
317
|
const CORE_FILES = [
|
|
318
318
|
".enderun",
|
|
319
|
-
|
|
319
|
+
|
|
320
320
|
"mcp.json",
|
|
321
321
|
".env.example",
|
|
322
322
|
"ENDERUN.md",
|
|
323
|
-
".
|
|
324
|
-
".enderun/config.json",
|
|
325
|
-
".enderun/STATUS.md",
|
|
323
|
+
"package.json",
|
|
326
324
|
"packages/framework-mcp",
|
|
327
325
|
"packages/shared-types",
|
|
328
|
-
"panda.config.ts",
|
|
329
326
|
];
|
|
330
327
|
|
|
331
328
|
const DIRS_TO_CREATE = [
|
|
329
|
+
targetBase,
|
|
332
330
|
`${targetBase}/agents`,
|
|
333
331
|
`${targetBase}/docs/api`,
|
|
332
|
+
`${targetBase}/knowledge`,
|
|
333
|
+
`${targetBase}/benchmarks`,
|
|
334
|
+
`${targetBase}/monitoring`,
|
|
334
335
|
`${targetBase}/logs`,
|
|
335
336
|
`${targetBase}/messages`,
|
|
336
337
|
"apps/web",
|
|
337
338
|
"apps/backend",
|
|
338
|
-
|
|
339
|
+
|
|
339
340
|
"packages/shared-types",
|
|
340
341
|
"packages/framework-mcp",
|
|
341
342
|
];
|
|
342
343
|
|
|
343
|
-
console.log(
|
|
344
|
+
console.log(`🚀 Installing Agent Enderun (Adapter: ${selectedAdapter || "all"})...`);
|
|
344
345
|
|
|
345
346
|
// Ensure target framework base exists
|
|
346
347
|
if (!fs.existsSync(targetFrameworkDir)) {
|
|
@@ -357,13 +358,12 @@ async function initCommand(selectedAdapter) {
|
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
let filesToProcess = [...CORE_FILES];
|
|
360
|
-
|
|
361
361
|
if (selectedAdapter) {
|
|
362
362
|
if (!ADAPTERS[selectedAdapter]) {
|
|
363
363
|
console.error(`❌ Invalid adapter: ${selectedAdapter}. Available: gemini, claude, cursor, codex`);
|
|
364
364
|
process.exit(1);
|
|
365
365
|
}
|
|
366
|
-
filesToProcess
|
|
366
|
+
filesToProcess.push(...ADAPTERS[selectedAdapter]);
|
|
367
367
|
} else {
|
|
368
368
|
Object.values(ADAPTERS).forEach(list => filesToProcess.push(...list));
|
|
369
369
|
}
|
|
@@ -387,7 +387,7 @@ async function initCommand(selectedAdapter) {
|
|
|
387
387
|
let dest = path.join(targetDir, item);
|
|
388
388
|
|
|
389
389
|
// FORCED CLEANUP: Delete existing framework directories in target before copying
|
|
390
|
-
if (["packages/framework-mcp", "packages/shared-types", ".enderun", ".
|
|
390
|
+
if (["packages/framework-mcp", "packages/shared-types", ".enderun", ".enderun", ".claude", ".cursor", ".codex"].includes(item)) {
|
|
391
391
|
if (fs.existsSync(dest)) {
|
|
392
392
|
try {
|
|
393
393
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
@@ -397,38 +397,27 @@ async function initCommand(selectedAdapter) {
|
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
-
// Clean up existing lockfiles in target
|
|
401
|
-
if (fs.existsSync(dest)) {
|
|
402
|
-
const lockFile = path.join(dest, "package-lock.json");
|
|
403
|
-
if (fs.existsSync(lockFile)) {
|
|
404
|
-
fs.unlinkSync(lockFile);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
400
|
// Remap core framework files to targetBase
|
|
409
401
|
if (item === ".enderun" || item.startsWith(".enderun/")) {
|
|
410
402
|
dest = path.join(targetDir, item.replace(".enderun", targetBase));
|
|
411
403
|
}
|
|
412
404
|
if (item === "ENDERUN.md") dest = path.join(targetFrameworkDir, "ENDERUN.md");
|
|
413
|
-
|
|
414
|
-
|
|
405
|
+
|
|
406
|
+
// Check if item is an adapter pointer file
|
|
407
|
+
const isAdapterPointer = Object.values(ADAPTERS).flat().includes(item);
|
|
408
|
+
if (isAdapterPointer) {
|
|
409
|
+
dest = path.join(targetDir, item);
|
|
415
410
|
}
|
|
416
411
|
|
|
417
412
|
if (fs.existsSync(src)) {
|
|
418
413
|
if (fs.lstatSync(src).isDirectory()) {
|
|
419
|
-
|
|
420
|
-
const skipFiles = (item === ".enderun") ? ["logs", "PROJECT_MEMORY.md", "BRAIN_DASHBOARD.md", "PROJECT_MEMORY.lock"] : [];
|
|
414
|
+
const skipFiles = (item === ".enderun") ? ["logs", "PROJECT_MEMORY.md", "PROJECT_MEMORY.lock"] : [];
|
|
421
415
|
const isDocs = item === "docs";
|
|
422
416
|
copyDir(src, dest, new Set(skipFiles), isDocs, targetBase, targetScope);
|
|
423
417
|
} else {
|
|
424
|
-
//
|
|
425
|
-
if (item === "package.json") continue;
|
|
426
|
-
if (item === "ENDERUN.md" && fs.existsSync(dest)) {
|
|
427
|
-
console.log(`ℹ️ Skipping ENDERUN.md (already exists in ${targetBase}).`);
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
418
|
+
if (item === "package.json") continue; // We merge it later
|
|
430
419
|
|
|
431
|
-
if (fs.existsSync(dest)) {
|
|
420
|
+
if (fs.existsSync(dest) && !isAdapterPointer) {
|
|
432
421
|
console.log(`ℹ️ Skipping existing file: ${item}`);
|
|
433
422
|
continue;
|
|
434
423
|
}
|
|
@@ -440,16 +429,16 @@ async function initCommand(selectedAdapter) {
|
|
|
440
429
|
content = content.replace(/\{\{FRAMEWORK_DIR\}\}/g, targetBase);
|
|
441
430
|
content = content.replace(/\{\{ADAPTER\}\}/g, selectedAdapter || "enderun");
|
|
442
431
|
|
|
443
|
-
// Sanitize workspace: protocol in all text files
|
|
444
432
|
if (ext === ".json") {
|
|
445
433
|
try {
|
|
446
434
|
const json = JSON.parse(content);
|
|
447
435
|
content = JSON.stringify(sanitizeJson(json, targetScope), null, 2);
|
|
436
|
+
// Ensure variable replacement even inside JSON strings if any
|
|
437
|
+
content = content.replace(/\{\{FRAMEWORK_DIR\}\}/g, targetBase);
|
|
438
|
+
content = content.replace(/\{\{ADAPTER\}\}/g, selectedAdapter || "enderun");
|
|
448
439
|
} catch (e) {
|
|
449
440
|
content = content.replace(/workspace:[^"'\s]*/g, "*");
|
|
450
441
|
}
|
|
451
|
-
} else {
|
|
452
|
-
content = content.replace(/workspace:[^"'\s]*/g, "*");
|
|
453
442
|
}
|
|
454
443
|
|
|
455
444
|
fs.writeFileSync(dest, content);
|
|
@@ -461,84 +450,78 @@ async function initCommand(selectedAdapter) {
|
|
|
461
450
|
}
|
|
462
451
|
}
|
|
463
452
|
|
|
464
|
-
//
|
|
453
|
+
// Merge Package JSON
|
|
465
454
|
mergePackageJson(path.join(targetDir, "package.json"), path.join(sourceDir, "package.json"));
|
|
466
455
|
updateGitIgnore(path.join(targetDir, ".gitignore"), targetBase);
|
|
467
456
|
|
|
468
457
|
const finalMemoryPath = path.join(targetDir, targetBase, "PROJECT_MEMORY.md");
|
|
469
458
|
initializeMemory(finalMemoryPath, targetBase);
|
|
470
459
|
|
|
471
|
-
// Deep clean ALL package.json files in target directory (removes workspace: and unocss)
|
|
472
460
|
deepCleanProtocols(targetDir, targetScope);
|
|
473
461
|
|
|
474
|
-
// Initialize git if missing
|
|
475
462
|
if (!fs.existsSync(path.join(targetDir, ".git"))) {
|
|
476
463
|
try {
|
|
477
464
|
const { execSync } = await import("child_process");
|
|
478
465
|
execSync("git init", { cwd: targetDir, stdio: "ignore" });
|
|
479
466
|
console.log("✅ Git repository initialized.");
|
|
480
|
-
} catch (e) {
|
|
481
|
-
console.warn("⚠️ Could not initialize git automatically. Please run 'git init' manually.");
|
|
482
|
-
}
|
|
467
|
+
} catch (e) {}
|
|
483
468
|
}
|
|
484
469
|
|
|
485
|
-
// --- Post-Install Hooks (Smart Setup) ---
|
|
486
|
-
|
|
487
470
|
console.log("\n🛠️ Running smart configuration for adapters...");
|
|
488
471
|
|
|
489
|
-
// Universal Gemini
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
472
|
+
// Universal Symlink for Gemini compatibility
|
|
473
|
+
if (targetBase !== ".enderun") {
|
|
474
|
+
try {
|
|
475
|
+
const geminiDir = path.join(targetDir, ".enderun");
|
|
476
|
+
if (!fs.existsSync(geminiDir)) fs.mkdirSync(geminiDir, { recursive: true });
|
|
477
|
+
|
|
478
|
+
const geminiAgentsDir = path.join(geminiDir, "agents");
|
|
479
|
+
const frameworkAgentsDir = path.join(targetDir, targetBase, "agents");
|
|
480
|
+
if (!fs.existsSync(geminiAgentsDir)) {
|
|
481
|
+
const relativePath = path.relative(geminiDir, frameworkAgentsDir);
|
|
482
|
+
fs.symlinkSync(relativePath, geminiAgentsDir, "dir");
|
|
483
|
+
console.log(`🔗 Created symlink: .enderun/agents -> ${targetBase}/agents`);
|
|
484
|
+
}
|
|
485
|
+
} catch (e) {}
|
|
486
|
+
}
|
|
498
487
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
fs.symlinkSync(relativePath, geminiAgentsDir, "dir");
|
|
502
|
-
console.log(`🔗 Omni-Agent: Created symlink from .gemini/agents to ${targetBase}/agents`);
|
|
503
|
-
}
|
|
504
|
-
} catch (err) {
|
|
505
|
-
// Silently ignore if symlink fails (e.g. on non-compatible OS)
|
|
488
|
+
if (selectedAdapter === "gemini") {
|
|
489
|
+
console.log(`💎 Gemini: Adapter GEMINI.md and ${targetBase}/ folder are ready.`);
|
|
506
490
|
}
|
|
507
491
|
|
|
508
|
-
if (selectedAdapter === "claude"
|
|
492
|
+
if (selectedAdapter === "claude") {
|
|
509
493
|
const mcpPath = path.join(targetDir, "packages/framework-mcp/src/index.ts");
|
|
510
494
|
console.log("\n📝 Claude Code Setup:");
|
|
511
495
|
console.log("To enable Agent Enderun tools in Claude Code, run this command:");
|
|
512
496
|
console.log(`\x1b[36mclaude config add framework-mcp npx tsx ${mcpPath}\x1b[0m`);
|
|
513
497
|
}
|
|
514
498
|
|
|
515
|
-
if (selectedAdapter === "cursor"
|
|
516
|
-
|
|
499
|
+
if (selectedAdapter === "cursor") {
|
|
500
|
+
const cursorRulesPath = path.join(targetDir, ".cursorrules");
|
|
501
|
+
const cursorMdPath = path.join(targetDir, "CURSOR.md");
|
|
502
|
+
if (fs.existsSync(cursorMdPath) && !fs.existsSync(cursorRulesPath)) {
|
|
503
|
+
fs.copyFileSync(cursorMdPath, cursorRulesPath);
|
|
504
|
+
console.log("🔗 Cursor: Synchronized CURSOR.md to .cursorrules");
|
|
505
|
+
}
|
|
517
506
|
}
|
|
518
507
|
|
|
519
508
|
const pkgMgr = getPackageManager();
|
|
520
|
-
console.log(`\nℹ️ Detected package manager: ${pkgMgr}`);
|
|
521
509
|
const installCmd = pkgMgr === "npm" ? "npm install" : `${pkgMgr} install`;
|
|
522
510
|
const buildCmd = pkgMgr === "npm" ? "npm run enderun:build" : `${pkgMgr} run enderun:build`;
|
|
523
511
|
|
|
524
|
-
console.log(
|
|
512
|
+
console.log(`\n✨ Framework scaffolded! (v${FRAMEWORK_VERSION})`);
|
|
525
513
|
|
|
526
514
|
try {
|
|
527
515
|
const { execSync } = await import("child_process");
|
|
528
|
-
|
|
529
516
|
console.log(`\n📦 Step 1/3: Running '${installCmd}'...`);
|
|
530
517
|
execSync(installCmd, { stdio: "inherit" });
|
|
531
|
-
|
|
532
518
|
console.log(`\n🏗️ Step 2/3: Running '${buildCmd}'...`);
|
|
533
519
|
execSync(buildCmd, { stdio: "inherit" });
|
|
534
|
-
|
|
535
520
|
console.log(`\n🔍 Step 3/3: Running 'agent-enderun check'...`);
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
console.log("\n🚀 Agent Enderun is fully installed, built and verified!");
|
|
521
|
+
checkCommand();
|
|
522
|
+
console.log("\n🚀 Agent Enderun is fully installed and verified!");
|
|
540
523
|
} catch (error) {
|
|
541
|
-
console.error("\n❌ Automatic installation failed.
|
|
524
|
+
console.error("\n❌ Automatic installation failed. Run manually:");
|
|
542
525
|
console.log(`👉 ${installCmd} && ${buildCmd}`);
|
|
543
526
|
}
|
|
544
527
|
}
|
|
@@ -593,8 +576,12 @@ function checkCommand() {
|
|
|
593
576
|
{ name: "Shared Types", path: "packages/shared-types/package.json" },
|
|
594
577
|
{ name: "MCP Server", path: "packages/framework-mcp/package.json" },
|
|
595
578
|
{ name: "Tech Stack", path: path.join(frameworkDir, "docs/tech-stack.md") },
|
|
596
|
-
{ name: "
|
|
579
|
+
{ name: "Panda CSS Config", path: "panda.config.ts" },
|
|
580
|
+
{ name: "Requirements", path: path.join(frameworkDir, "docs/project-docs.md") },
|
|
597
581
|
{ name: "API Registry", path: path.join(frameworkDir, "docs/api/README.md") },
|
|
582
|
+
{ name: "Security Policy", path: path.join(frameworkDir, "docs/security.md") },
|
|
583
|
+
{ name: "Privacy Policy", path: path.join(frameworkDir, "docs/privacy.md") },
|
|
584
|
+
{ name: "Brain Dashboard", path: path.join(frameworkDir, "BRAIN_DASHBOARD.md") },
|
|
598
585
|
];
|
|
599
586
|
|
|
600
587
|
for (const check of checks) {
|
|
@@ -835,6 +822,156 @@ function verifyContractCommand() {
|
|
|
835
822
|
}
|
|
836
823
|
}
|
|
837
824
|
|
|
825
|
+
function securityAuditCommand(targetPath) {
|
|
826
|
+
console.log(`🔍 Running Advanced Security Audit on: ${targetPath}...`);
|
|
827
|
+
const scanRules = [
|
|
828
|
+
{ pattern: /sql`/, message: "Potential Raw SQL usage detected", severity: "HIGH" },
|
|
829
|
+
{ pattern: /(password|secret|api_?key)\s*[:=]\s*['"][^'"]+['"]/i, message: "Potential hardcoded secret detected", severity: "CRITICAL" },
|
|
830
|
+
{ pattern: /:\s*any(?!\w)/, message: "Usage of 'any' type detected", severity: "MEDIUM" },
|
|
831
|
+
{ pattern: /\.innerHTML\s*=/, message: "Unsafe innerHTML assignment detected", severity: "MEDIUM" },
|
|
832
|
+
];
|
|
833
|
+
const issues = [];
|
|
834
|
+
const files = collectFiles(path.join(targetDir, targetPath), [".ts", ".tsx", ".js", ".jsx"]);
|
|
835
|
+
files.forEach(f => {
|
|
836
|
+
const content = fs.readFileSync(f, "utf8");
|
|
837
|
+
const lines = content.split("\n");
|
|
838
|
+
lines.forEach((line, i) => {
|
|
839
|
+
scanRules.forEach(rule => {
|
|
840
|
+
if (rule.pattern.test(line)) {
|
|
841
|
+
issues.push(`[${rule.severity}] ${rule.message} in ${path.relative(targetDir, f)}:${i+1}`);
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
});
|
|
845
|
+
});
|
|
846
|
+
if (issues.length === 0) {
|
|
847
|
+
console.log("✅ No security issues detected.");
|
|
848
|
+
} else {
|
|
849
|
+
issues.forEach(issue => console.log(`⚠️ ${issue}`));
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function complianceCheckCommand(targetPath) {
|
|
854
|
+
console.log(`📜 Checking Constitution Compliance: ${targetPath}...`);
|
|
855
|
+
const violations = [];
|
|
856
|
+
const forbidden = ["@shadcn", "mui", "@chakra-ui", "tailwindcss"];
|
|
857
|
+
const files = collectFiles(path.join(targetDir, targetPath), [".ts", ".tsx", ".js", ".jsx", ".md"]);
|
|
858
|
+
files.forEach(f => {
|
|
859
|
+
const content = fs.readFileSync(f, "utf8");
|
|
860
|
+
forbidden.forEach(lib => {
|
|
861
|
+
if (content.includes(lib)) violations.push(`${path.relative(targetDir, f)}: Forbidden library '${lib}' found.`);
|
|
862
|
+
});
|
|
863
|
+
if (f.endsWith(".ts") && content.includes("interface") && content.match(/ID\s*:\s*string/)) {
|
|
864
|
+
violations.push(`${path.relative(targetDir, f)}: Potential Branded Types violation (ID typed as string).`);
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
if (violations.length === 0) {
|
|
868
|
+
console.log("✅ All systems compliant with ENDERUN.md.");
|
|
869
|
+
} else {
|
|
870
|
+
violations.forEach(v => console.log(`❌ ${v}`));
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
function gitCommitCommand(traceId) {
|
|
875
|
+
try {
|
|
876
|
+
const diff = cp.execSync("git diff --staged", { encoding: "utf8" });
|
|
877
|
+
if (!diff) {
|
|
878
|
+
console.log("ℹ️ No staged changes found. Use 'git add' first.");
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
const files = cp.execSync("git diff --staged --name-only", { encoding: "utf8" }).split("\n").filter(Boolean);
|
|
882
|
+
let type = "feat", scope = "code";
|
|
883
|
+
if (files.some(f => f.includes(".md"))) type = "docs";
|
|
884
|
+
else if (files.some(f => f.includes("shared-types"))) type = "arch";
|
|
885
|
+
else if (files.some(f => f.includes("bin/cli.js"))) type = "fix";
|
|
886
|
+
|
|
887
|
+
const summary = files.length === 1 ? `update ${path.basename(files[0])}` : `update ${files.length} files`;
|
|
888
|
+
console.log(`\n### SUGGESTED COMMIT MESSAGE ###\n\n[${traceId}] ${type}(${scope}): ${summary}\n`);
|
|
889
|
+
} catch (e) {
|
|
890
|
+
console.log("❌ Git command failed.");
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
function explorerGraphCommand(targetPath) {
|
|
895
|
+
console.log(`🗺️ Generating Dependency Graph for: ${targetPath}...`);
|
|
896
|
+
const files = collectFiles(path.join(targetDir, targetPath), [".ts", ".tsx"]);
|
|
897
|
+
const edges = [];
|
|
898
|
+
files.forEach(f => {
|
|
899
|
+
const content = fs.readFileSync(f, "utf8");
|
|
900
|
+
const name = path.basename(f, path.extname(f));
|
|
901
|
+
const imports = content.match(/from\s+['"]\.\.?\/[^'"]+['"]/g) || [];
|
|
902
|
+
imports.forEach(imp => {
|
|
903
|
+
const target = path.basename(imp.split(/['"]/)[1]);
|
|
904
|
+
edges.push(`${name} --> ${target}`);
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
if (edges.length === 0) {
|
|
908
|
+
console.log("ℹ️ No internal dependencies found.");
|
|
909
|
+
} else {
|
|
910
|
+
console.log("\n```mermaid\ngraph TD\n" + Array.from(new Set(edges)).join("\n") + "\n```\n");
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
function explorerAuditCommand(targetPath) {
|
|
915
|
+
console.log(`🧠 Codebase Intelligence Scan: ${targetPath}...`);
|
|
916
|
+
const files = collectFiles(path.join(targetDir, targetPath), [".ts", ".tsx"]);
|
|
917
|
+
const complexity = [];
|
|
918
|
+
files.forEach(f => {
|
|
919
|
+
const content = fs.readFileSync(f, "utf8");
|
|
920
|
+
const lines = content.split("\n").length;
|
|
921
|
+
if (lines > 300) complexity.push(`${path.relative(targetDir, f)} (${lines} lines)`);
|
|
922
|
+
});
|
|
923
|
+
if (complexity.length > 0) {
|
|
924
|
+
console.log("\n⚠️ Complexity Spikes:");
|
|
925
|
+
complexity.forEach(c => console.log(`- ${c}`));
|
|
926
|
+
} else {
|
|
927
|
+
console.log("✅ Codebase structure looks clean.");
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function collectFiles(dir, extensions) {
|
|
932
|
+
let results = [];
|
|
933
|
+
if (!fs.existsSync(dir)) return results;
|
|
934
|
+
const list = fs.readdirSync(dir);
|
|
935
|
+
list.forEach(file => {
|
|
936
|
+
file = path.join(dir, file);
|
|
937
|
+
const stat = fs.statSync(file);
|
|
938
|
+
if (stat && stat.isDirectory()) {
|
|
939
|
+
if (!file.includes("node_modules") && !file.includes(".git")) {
|
|
940
|
+
results = results.concat(collectFiles(file, extensions));
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
if (extensions.includes(path.extname(file))) {
|
|
944
|
+
results.push(file);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
return results;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function runScriptCommand(script, projectPath) {
|
|
952
|
+
const fullPath = path.join(targetDir, projectPath);
|
|
953
|
+
if (!fs.existsSync(fullPath)) {
|
|
954
|
+
console.log(`❌ Project path not found: ${projectPath}`);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
console.log(`🚀 Running 'npm run ${script}' in ${projectPath}...`);
|
|
958
|
+
try {
|
|
959
|
+
cp.spawnSync("npm", ["run", script], { cwd: fullPath, stdio: "inherit", shell: true });
|
|
960
|
+
} catch (e) {
|
|
961
|
+
console.log(`❌ Failed to run script: ${e.message}`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function gitSyncCommand() {
|
|
966
|
+
console.log("🔄 Syncing with remote repository...");
|
|
967
|
+
try {
|
|
968
|
+
cp.execSync("git pull origin main --rebase", { stdio: "inherit" });
|
|
969
|
+
console.log("✅ Successfully synced and rebased.");
|
|
970
|
+
} catch (e) {
|
|
971
|
+
console.log("❌ Sync failed. Please resolve conflicts manually.");
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
838
975
|
function logAgentActionCommand(data) {
|
|
839
976
|
const frameworkDir = getFrameworkDir();
|
|
840
977
|
const logsDir = path.join(targetDir, frameworkDir, "logs");
|
|
@@ -921,6 +1058,11 @@ function updateProjectMemoryCommand(section, content) {
|
|
|
921
1058
|
async function main() {
|
|
922
1059
|
const [command, ...args] = process.argv.slice(2);
|
|
923
1060
|
|
|
1061
|
+
// Skip header for version and mcp commands to keep output clean
|
|
1062
|
+
if (command !== "version" && command !== "-v" && command !== "--version" && command !== "mcp") {
|
|
1063
|
+
console.log("🤖 Agent Enderun CLI — Initializing...");
|
|
1064
|
+
}
|
|
1065
|
+
|
|
924
1066
|
switch (command) {
|
|
925
1067
|
case "init":
|
|
926
1068
|
await initCommand(args[0]);
|
|
@@ -938,6 +1080,19 @@ async function main() {
|
|
|
938
1080
|
case "verify-contract":
|
|
939
1081
|
verifyContractCommand();
|
|
940
1082
|
break;
|
|
1083
|
+
case "mcp": {
|
|
1084
|
+
const mcpServerPath = path.join(sourceDir, "packages/framework-mcp/dist/index.js");
|
|
1085
|
+
if (fs.existsSync(mcpServerPath)) {
|
|
1086
|
+
const { spawn } = await import("child_process");
|
|
1087
|
+
// Use node to execute the built MCP server
|
|
1088
|
+
const child = spawn("node", [mcpServerPath], { stdio: "inherit" });
|
|
1089
|
+
child.on("exit", (code) => process.exit(code || 0));
|
|
1090
|
+
} else {
|
|
1091
|
+
console.error("❌ MCP Server not built. Run 'npm run enderun:build' first.");
|
|
1092
|
+
process.exit(1);
|
|
1093
|
+
}
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
941
1096
|
case "log_agent_action": {
|
|
942
1097
|
// Handle both structured JSON and positional args
|
|
943
1098
|
let data = {};
|
|
@@ -978,9 +1133,75 @@ async function main() {
|
|
|
978
1133
|
updateProjectMemoryCommand(section, content);
|
|
979
1134
|
break;
|
|
980
1135
|
}
|
|
1136
|
+
case "update_knowledge_base": {
|
|
1137
|
+
const topic = args[0];
|
|
1138
|
+
const content = args.slice(1).join(" ");
|
|
1139
|
+
if (!topic || !content) {
|
|
1140
|
+
console.error("❌ Usage: agent-enderun update_knowledge_base <topic> <content>");
|
|
1141
|
+
process.exit(1);
|
|
1142
|
+
}
|
|
1143
|
+
const frameworkDir = getFrameworkDir();
|
|
1144
|
+
const kbDir = path.join(targetDir, frameworkDir, "knowledge");
|
|
1145
|
+
if (!fs.existsSync(kbDir)) fs.mkdirSync(kbDir, { recursive: true });
|
|
1146
|
+
const fileName = topic.replace(/[^a-z0-9]/gi, "_").toLowerCase() + ".md";
|
|
1147
|
+
fs.writeFileSync(path.join(kbDir, fileName), content);
|
|
1148
|
+
console.log(`✅ Knowledge base updated: ${topic}`);
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
case "search_knowledge_base": {
|
|
1152
|
+
const query = args[0];
|
|
1153
|
+
if (!query) {
|
|
1154
|
+
console.error("❌ Usage: agent-enderun search_knowledge_base <query>");
|
|
1155
|
+
process.exit(1);
|
|
1156
|
+
}
|
|
1157
|
+
const frameworkDir = getFrameworkDir();
|
|
1158
|
+
const kbDir = path.join(targetDir, frameworkDir, "knowledge");
|
|
1159
|
+
if (!fs.existsSync(kbDir)) {
|
|
1160
|
+
console.log("ℹ️ Knowledge base is empty.");
|
|
1161
|
+
break;
|
|
1162
|
+
}
|
|
1163
|
+
const files = fs.readdirSync(kbDir).filter(f => f.endsWith(".md"));
|
|
1164
|
+
let found = false;
|
|
1165
|
+
for (const file of files) {
|
|
1166
|
+
const content = fs.readFileSync(path.join(kbDir, file), "utf-8");
|
|
1167
|
+
if (content.toLowerCase().includes(query.toLowerCase()) || file.toLowerCase().includes(query.toLowerCase())) {
|
|
1168
|
+
console.log(`\n### ${file.replace(".md", "")}\n${content.slice(0, 300)}...`);
|
|
1169
|
+
found = true;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
if (!found) console.log("ℹ️ No matching entries found.");
|
|
1173
|
+
break;
|
|
1174
|
+
}
|
|
981
1175
|
case "check":
|
|
982
1176
|
checkCommand();
|
|
983
1177
|
break;
|
|
1178
|
+
case "check:security":
|
|
1179
|
+
securityAuditCommand(args[0] || ".");
|
|
1180
|
+
break;
|
|
1181
|
+
case "check:compliance":
|
|
1182
|
+
complianceCheckCommand(args[0] || ".");
|
|
1183
|
+
break;
|
|
1184
|
+
case "git:commit":
|
|
1185
|
+
gitCommitCommand(args[0] || "TRACE-ID-MISSING");
|
|
1186
|
+
break;
|
|
1187
|
+
case "explorer:graph":
|
|
1188
|
+
explorerGraphCommand(args[0] || ".");
|
|
1189
|
+
break;
|
|
1190
|
+
case "explorer:audit":
|
|
1191
|
+
explorerAuditCommand(args[0] || ".");
|
|
1192
|
+
break;
|
|
1193
|
+
case "frontend:dev":
|
|
1194
|
+
runScriptCommand("dev", "apps/web");
|
|
1195
|
+
break;
|
|
1196
|
+
case "frontend:build":
|
|
1197
|
+
runScriptCommand("build", "apps/web");
|
|
1198
|
+
break;
|
|
1199
|
+
case "mobile:dev":
|
|
1200
|
+
runScriptCommand("start", "apps/mobile");
|
|
1201
|
+
break;
|
|
1202
|
+
case "git:sync":
|
|
1203
|
+
gitSyncCommand();
|
|
1204
|
+
break;
|
|
984
1205
|
case "version":
|
|
985
1206
|
case "-v":
|
|
986
1207
|
case "--version":
|
|
@@ -991,12 +1212,18 @@ async function main() {
|
|
|
991
1212
|
🤖 Agent Enderun CLI (v${FRAMEWORK_VERSION})
|
|
992
1213
|
|
|
993
1214
|
Available Commands:
|
|
994
|
-
init [adapter]
|
|
995
|
-
check
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1215
|
+
init [adapter] Initialize the framework (gemini, claude, cursor, codex)
|
|
1216
|
+
check Full health check
|
|
1217
|
+
check:security Run security audit scan
|
|
1218
|
+
check:compliance Run constitution compliance check
|
|
1219
|
+
status Show current phase and task status
|
|
1220
|
+
trace:new <desc> Generate a new Trace ID
|
|
1221
|
+
verify-contract Check shared types integrity
|
|
1222
|
+
explorer:graph Generate dependency graph
|
|
1223
|
+
explorer:audit Codebase intelligence scan
|
|
1224
|
+
git:commit <id> Suggest semantic commit message
|
|
1225
|
+
mcp Start the MCP server
|
|
1226
|
+
version Show version information
|
|
1000
1227
|
|
|
1001
1228
|
Example:
|
|
1002
1229
|
agent-enderun trace:new "Auth module design" backend P1
|
package/package.json
CHANGED
|
@@ -1,23 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-enderun",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The Supreme AI Governance & Orchestration Framework for Enterprise Development",
|
|
5
|
+
"author": "Yusuf BEKAR",
|
|
6
|
+
"license": "MIT",
|
|
4
7
|
"type": "module",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/ysf-bkr/Agent-Enderun.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/ysf-bkr/Agent-Enderun#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ysf-bkr/Agent-Enderun/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"governance",
|
|
19
|
+
"orchestration",
|
|
20
|
+
"agents",
|
|
21
|
+
"mcp",
|
|
22
|
+
"typescript",
|
|
23
|
+
"framework"
|
|
24
|
+
],
|
|
5
25
|
"workspaces": [
|
|
6
26
|
"packages/*"
|
|
7
27
|
],
|
|
8
28
|
"bin": {
|
|
9
29
|
"agent-enderun": "bin/cli.js"
|
|
10
30
|
},
|
|
31
|
+
"files": [
|
|
32
|
+
"bin",
|
|
33
|
+
"packages",
|
|
34
|
+
".enderun",
|
|
35
|
+
"ENDERUN.md",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"mcp.json",
|
|
39
|
+
".env.example"
|
|
40
|
+
],
|
|
11
41
|
"scripts": {
|
|
12
42
|
"enderun:build": "npm run build --prefix packages/shared-types && npm run build --prefix packages/framework-mcp",
|
|
13
43
|
"enderun:status": "agent-enderun status",
|
|
14
44
|
"enderun:trace": "agent-enderun trace:new",
|
|
15
45
|
"enderun:verify": "agent-enderun verify-contract"
|
|
16
46
|
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
17
50
|
"dependencies": {},
|
|
18
51
|
"devDependencies": {},
|
|
19
52
|
"enderun": {
|
|
20
|
-
"version": "0.
|
|
53
|
+
"version": "0.2.0",
|
|
21
54
|
"initializedAt": "2026-05-09T13:24:27.472Z"
|
|
22
55
|
}
|
|
23
56
|
}
|