agent-enderun 0.9.4 → 1.0.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/ENDERUN.md +1 -1
- package/.enderun/PROJECT_MEMORY.md +2 -21
- package/.enderun/STATUS.md +11 -7
- package/.enderun/agents/analyst.md +28 -0
- package/.enderun/agents/backend.md +33 -367
- package/.enderun/agents/database.md +27 -45
- package/.enderun/agents/devops.md +27 -187
- package/.enderun/agents/explorer.md +23 -124
- package/.enderun/agents/frontend.md +32 -345
- package/.enderun/agents/git.md +26 -110
- package/.enderun/agents/manager.md +30 -299
- package/.enderun/agents/mobile.md +28 -91
- package/.enderun/agents/native.md +27 -96
- package/.enderun/agents/quality.md +26 -114
- package/.enderun/agents/security.md +28 -0
- package/.enderun/config.json +1 -1
- package/.enderun/knowledge/analyst_reference_guide.md +31 -0
- package/.enderun/knowledge/backend_reference_guide.md +165 -0
- package/.enderun/knowledge/database_reference_guide.md +38 -0
- package/.enderun/knowledge/devops_reference_guide.md +43 -0
- package/.enderun/knowledge/explorer_reference_guide.md +34 -0
- package/.enderun/knowledge/frontend_reference_guide.md +64 -0
- package/.enderun/knowledge/git_reference_guide.md +51 -0
- package/.enderun/knowledge/manager_reference_guide.md +55 -0
- package/.enderun/knowledge/mobile_reference_guide.md +35 -0
- package/.enderun/knowledge/native_reference_guide.md +34 -0
- package/.enderun/knowledge/quality_reference_guide.md +42 -0
- package/.enderun/knowledge/security_reference_guide.md +35 -0
- package/.enderun/logs/manager.json +1 -17
- package/.enderun/memory-graph/agent-contexts/analyst.json +1 -0
- package/.enderun/memory-graph/agent-contexts/backend.json +1 -1
- package/.enderun/memory-graph/agent-contexts/devops.json +1 -1
- package/.enderun/memory-graph/agent-contexts/explorer.json +1 -1
- package/.enderun/memory-graph/agent-contexts/frontend.json +1 -1
- package/.enderun/memory-graph/agent-contexts/git.json +1 -1
- package/.enderun/memory-graph/agent-contexts/manager.json +1 -1
- package/.enderun/memory-graph/agent-contexts/mobile.json +1 -1
- package/.enderun/memory-graph/agent-contexts/native.json +1 -1
- package/.enderun/memory-graph/agent-contexts/quality.json +1 -1
- package/.enderun/memory-graph/agent-contexts/security.json +1 -0
- package/.enderun/memory-graph/shared-facts.json +1 -1
- package/README.md +95 -21
- package/agent.md +1 -1
- package/bin/cli.js +2 -1
- package/bin/init-check.js +1 -1
- package/bin/update-contract.js +1 -1
- package/claude.md +1 -1
- package/dist/.keep +1 -0
- package/docs/README.md +11 -1
- package/docs/getting-started.md +1 -1
- package/eslint.config.js +1 -1
- package/framework-mcp/dist/index.js +44 -242
- package/framework-mcp/dist/tools/definitions.js +109 -0
- package/framework-mcp/dist/tools/file_system/patch_file.js +18 -0
- package/framework-mcp/dist/tools/file_system/read_file.js +7 -0
- package/framework-mcp/dist/tools/file_system/replace_text.js +14 -0
- package/framework-mcp/dist/tools/file_system/write_file.js +9 -0
- package/framework-mcp/dist/tools/framework/get_status.js +5 -0
- package/framework-mcp/dist/tools/framework/orchestrate.js +5 -0
- package/framework-mcp/dist/tools/framework/update_contract_hash.js +5 -0
- package/framework-mcp/dist/tools/framework/update_memory.js +8 -0
- package/framework-mcp/dist/tools/index.js +25 -0
- package/framework-mcp/dist/tools/messaging/log_action.js +22 -0
- package/framework-mcp/dist/tools/messaging/send_message.js +21 -0
- package/framework-mcp/dist/tools/types.js +1 -0
- package/framework-mcp/dist/utils/cli.js +20 -0
- package/framework-mcp/dist/utils/security.js +35 -0
- package/framework-mcp/package.json +1 -1
- package/framework-mcp/src/declarations.d.ts +17 -3
- package/framework-mcp/src/index.ts +51 -279
- package/framework-mcp/src/tools/definitions.ts +111 -0
- package/framework-mcp/src/tools/file_system/patch_file.ts +23 -0
- package/framework-mcp/src/tools/file_system/read_file.ts +9 -0
- package/framework-mcp/src/tools/file_system/replace_text.ts +18 -0
- package/framework-mcp/src/tools/file_system/write_file.ts +11 -0
- package/framework-mcp/src/tools/framework/get_status.ts +7 -0
- package/framework-mcp/src/tools/framework/orchestrate.ts +7 -0
- package/framework-mcp/src/tools/framework/update_contract_hash.ts +7 -0
- package/framework-mcp/src/tools/framework/update_memory.ts +10 -0
- package/framework-mcp/src/tools/index.ts +31 -0
- package/framework-mcp/src/tools/messaging/log_action.ts +28 -0
- package/framework-mcp/src/tools/messaging/send_message.ts +26 -0
- package/framework-mcp/src/tools/types.ts +40 -0
- package/framework-mcp/src/utils/cli.ts +20 -0
- package/framework-mcp/src/utils/security.ts +41 -0
- package/gemini.md +7 -1
- package/grok.md +1 -1
- package/package.json +6 -5
- package/src/cli/adapters.ts +29 -8
- package/src/cli/commands/check.ts +7 -1
- package/src/cli/commands/init.ts +80 -27
- package/src/cli/commands/orchestrate.ts +98 -92
- package/src/cli/index.ts +5 -2
- package/src/cli/utils/app.ts +1 -1
- package/src/cli/utils/fs.ts +47 -13
- package/src/cli/utils/memory.ts +11 -4
- package/src/cli/utils/pkg.ts +5 -4
- package/docs/architecture/README.md +0 -9
- package/docs/user/README.md +0 -35
|
@@ -1,111 +1,117 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { execSync } from "child_process";
|
|
4
3
|
import { getFrameworkDir } from "../utils/memory.js";
|
|
5
4
|
|
|
6
5
|
interface HermesMessage {
|
|
7
6
|
timestamp: string;
|
|
8
7
|
from: string;
|
|
9
8
|
to: string;
|
|
10
|
-
category:
|
|
11
|
-
traceId: string;
|
|
9
|
+
category: string;
|
|
12
10
|
content: string;
|
|
11
|
+
traceId: string;
|
|
13
12
|
status: "PENDING" | "PROCESSED";
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
lines.forEach((line, index) => {
|
|
45
|
-
if (!line.trim()) return;
|
|
46
|
-
const msg = JSON.parse(line) as HermesMessage;
|
|
47
|
-
if (msg.status === "PENDING") {
|
|
48
|
-
pendingMessages.push(msg);
|
|
15
|
+
export async function orchestrateCommand() {
|
|
16
|
+
const frameworkDir = getFrameworkDir();
|
|
17
|
+
const messagesDir = path.join(process.cwd(), frameworkDir, "messages");
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(messagesDir)) {
|
|
20
|
+
console.log("ℹ️ Henüz işlenecek bir mesaj yok (.messages dizini bulunamadı).");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const messageFiles = fs.readdirSync(messagesDir).filter((f) => f.endsWith(".json"));
|
|
25
|
+
const pendingMessages: HermesMessage[] = [];
|
|
26
|
+
|
|
27
|
+
for (const file of messageFiles) {
|
|
28
|
+
const filePath = path.join(messagesDir, file);
|
|
29
|
+
try {
|
|
30
|
+
const content = fs.readFileSync(filePath, "utf8").trim();
|
|
31
|
+
if (!content) continue;
|
|
32
|
+
// Messages are stored as newline-delimited JSON
|
|
33
|
+
const lines = content.split("\n");
|
|
34
|
+
lines.forEach((line) => {
|
|
35
|
+
if (!line.trim()) return;
|
|
36
|
+
const msg = JSON.parse(line) as HermesMessage;
|
|
37
|
+
if (msg.status === "PENDING") {
|
|
38
|
+
pendingMessages.push(msg);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
console.error(`❌ ${file} mesajı okunurken hata oluştu.`);
|
|
49
43
|
}
|
|
50
|
-
});
|
|
51
|
-
} catch (e) {
|
|
52
|
-
// ignore malformed lines
|
|
53
44
|
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (pendingMessages.length === 0) {
|
|
57
|
-
console.log(`\n🟢 Kuyruk Temiz: İşlenecek aktif Hermes mesajı bulunamadı.`);
|
|
58
|
-
console.log(`💡 İpucu: Bir uzman ajanı tetiklemek için send_agent_message aracını kullanın.`);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
console.log(`\n📥 Kuyrukta ${pendingMessages.length} adet bekleyen Hermes mesajı tespit edildi:\n`);
|
|
63
|
-
|
|
64
|
-
// Process the first pending message
|
|
65
|
-
const activeMessage = pendingMessages[0];
|
|
66
|
-
const toAgent = activeMessage.to;
|
|
67
|
-
const fromAgent = activeMessage.from;
|
|
68
|
-
|
|
69
|
-
console.log(`✉️ [GÖNDEREN] : ${fromAgent}`);
|
|
70
|
-
console.log(`📥 [ALICI] : ${toAgent}`);
|
|
71
|
-
console.log(`🆔 [TRACE ID] : ${activeMessage.traceId}`);
|
|
72
|
-
console.log(`🏷️ [KATEGORİ] : ${activeMessage.category}`);
|
|
73
|
-
console.log(`💬 [MESAJ] : "${activeMessage.content}"`);
|
|
74
|
-
console.log(`----------------------------------------------------------------`);
|
|
75
|
-
|
|
76
|
-
// 1. Transition the target agent state to EXECUTING in STATUS.md
|
|
77
|
-
console.log(`⏳ Ajan Durum Geçişi: ${toAgent} durumu EXECUTING olarak kilitleniyor...`);
|
|
78
|
-
transitionAgentState(statusPath, toAgent, "EXECUTING", activeMessage.content);
|
|
79
|
-
|
|
80
|
-
console.log(`\n🤖 Görev Devredildi!`);
|
|
81
|
-
console.log(`👉 Lütfen ${toAgent} agent talimatlarını (${frameworkDir}/agents/${toAgent.replace("@", "")}.md) okuyun ve görevi yerine getirin.`);
|
|
82
|
-
console.log(`💡 Görev tamamlandığında, mesajı PROCESSED olarak işaretlemek ve ajanı boşa çıkarmak için:`);
|
|
83
|
-
console.log(` npx agent-enderun status komutuyla kontrol edin.`);
|
|
84
|
-
}
|
|
85
45
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
for (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
46
|
+
if (pendingMessages.length === 0) {
|
|
47
|
+
console.log("✅ Tüm mesajlar işlenmiş, bekleyen görev yok.");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(`📡 ${pendingMessages.length} adet bekleyen görev bulundu. İşleniyor...\n`);
|
|
52
|
+
|
|
53
|
+
for (const msg of pendingMessages) {
|
|
54
|
+
const { to, content, traceId } = msg;
|
|
55
|
+
|
|
56
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
57
|
+
console.log(`🔹 HEDEF: ${to}`);
|
|
58
|
+
console.log(`🔹 TRACE: ${traceId}`);
|
|
59
|
+
console.log(`🔹 GÖREV: ${content}`);
|
|
60
|
+
|
|
61
|
+
// Determine agent folder based on adapter (detection or default)
|
|
62
|
+
let agentFolder = "agents";
|
|
63
|
+
if (frameworkDir === ".agent") {
|
|
64
|
+
agentFolder = "skills";
|
|
65
|
+
} else if (frameworkDir === ".grok") {
|
|
66
|
+
agentFolder = "plugins";
|
|
102
67
|
}
|
|
103
|
-
|
|
68
|
+
|
|
69
|
+
// 1. Transition the target agent state to EXECUTING in STATUS.md
|
|
70
|
+
transitionAgentState(to, "EXECUTING", content);
|
|
71
|
+
|
|
72
|
+
console.log("\n🤖 Görev Devredildi!");
|
|
73
|
+
console.log(`👉 Lütfen ${to} agent talimatlarını (${frameworkDir}/${agentFolder}/${to.replace("@", "")}.md) okuyun ve görevi yerine getirin.`);
|
|
74
|
+
console.log("\n💡 İpucu: İş bittiğinde, mesajı PROCESSED olarak işaretlemek ve ajanı boşa çıkarmak için:");
|
|
75
|
+
console.log(" npx agent-enderun status komutuyla kontrol edin.");
|
|
104
76
|
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function transitionAgentState(agent: string, state: string, task: string) {
|
|
80
|
+
const frameworkDir = getFrameworkDir();
|
|
81
|
+
const statusPath = path.join(process.cwd(), frameworkDir, "STATUS.md");
|
|
82
|
+
|
|
83
|
+
if (!fs.existsSync(statusPath)) return;
|
|
105
84
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
85
|
+
try {
|
|
86
|
+
const content = fs.readFileSync(statusPath, "utf8");
|
|
87
|
+
const lines = content.split("\n");
|
|
88
|
+
const targetName = agent.startsWith("@") ? agent : `@${agent}`;
|
|
89
|
+
|
|
90
|
+
const newLines: string[] = [];
|
|
91
|
+
let found = false;
|
|
92
|
+
|
|
93
|
+
lines.forEach((line) => {
|
|
94
|
+
if (line.includes(`| ${targetName} |`)) {
|
|
95
|
+
found = true;
|
|
96
|
+
// Example: | @backend | IDLE | — | — | 9.2/10 | — |
|
|
97
|
+
const parts = line.split("|");
|
|
98
|
+
if (parts.length >= 7) {
|
|
99
|
+
parts[2] = ` ${state} `;
|
|
100
|
+
parts[3] = ` ${task.slice(0, 20)}... `;
|
|
101
|
+
newLines.push(parts.join("|"));
|
|
102
|
+
} else {
|
|
103
|
+
newLines.push(line);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
newLines.push(line);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (found) {
|
|
111
|
+
fs.writeFileSync(statusPath, newLines.join("\n"));
|
|
112
|
+
console.log(`✅ STATUS.md üzerinde ${agent} durumu başarıyla '${state}' yapıldı.`);
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
console.error("❌ STATUS.md güncellenirken hata oluştu.");
|
|
116
|
+
}
|
|
111
117
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -18,9 +18,12 @@ async function main() {
|
|
|
18
18
|
const command = args[0];
|
|
19
19
|
|
|
20
20
|
switch (command) {
|
|
21
|
-
case "init":
|
|
22
|
-
|
|
21
|
+
case "init": {
|
|
22
|
+
const dryRun = args.includes("--dry-run");
|
|
23
|
+
const adapter = args.find(a => !a.startsWith("-") && a !== "init");
|
|
24
|
+
await initCommand(adapter, dryRun);
|
|
23
25
|
break;
|
|
26
|
+
}
|
|
24
27
|
|
|
25
28
|
case "check":
|
|
26
29
|
checkCommand();
|
package/src/cli/utils/app.ts
CHANGED
|
@@ -4,7 +4,7 @@ import crypto from "crypto";
|
|
|
4
4
|
import { ensureDir, writeTextFile, writeJsonFile } from "../utils/fs.js";
|
|
5
5
|
import { updateProjectMemoryCommand } from "../commands/memory.js";
|
|
6
6
|
import { slugifyName, titleCase } from "../utils/string.js";
|
|
7
|
-
import { getConfiguredPaths,
|
|
7
|
+
import { getConfiguredPaths, getMemoryPath } from "./memory.js";
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
const targetDir = process.cwd(); // Assuming targetDir is process.cwd() in the CLI context
|
package/src/cli/utils/fs.ts
CHANGED
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
import { remapFrameworkContent } from "../adapters.js"; // Import from the new adapters.js
|
|
5
5
|
import type { AdapterId } from "../adapters.js";
|
|
6
6
|
|
|
7
|
-
export function updateGitIgnore(targetPath: string, frameworkDir = ".gemini"): void {
|
|
7
|
+
export function updateGitIgnore(targetPath: string, frameworkDir = ".gemini", dryRun = false): void {
|
|
8
8
|
const IGNORE_LINES = [
|
|
9
9
|
"# AI-Enderun",
|
|
10
10
|
`${frameworkDir}/logs/*.json`,
|
|
@@ -29,29 +29,41 @@ export function updateGitIgnore(targetPath: string, frameworkDir = ".gemini"): v
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
if (added) {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
if (dryRun) {
|
|
33
|
+
console.warn(`[DRY RUN] Would update .gitignore at ${targetPath}`);
|
|
34
|
+
} else {
|
|
35
|
+
fs.writeFileSync(targetPath, content);
|
|
36
|
+
console.warn("✅ .gitignore updated.");
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
export function ensureDir(dirPath: string): void {
|
|
41
|
+
export function ensureDir(dirPath: string, dryRun = false): void {
|
|
38
42
|
if (!fs.existsSync(dirPath)) {
|
|
39
|
-
|
|
43
|
+
if (dryRun) {
|
|
44
|
+
console.warn(`[DRY RUN] Would create directory: ${dirPath}`);
|
|
45
|
+
} else {
|
|
46
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
47
|
+
}
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
|
|
43
|
-
export function writeTextFile(filePath: string, content: string): void {
|
|
51
|
+
export function writeTextFile(filePath: string, content: string, dryRun = false): void {
|
|
52
|
+
if (dryRun) {
|
|
53
|
+
console.warn(`[DRY RUN] Would write file: ${filePath}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
44
56
|
ensureDir(path.dirname(filePath));
|
|
45
57
|
// Use template literal for content handling to avoid issues with raw newlines
|
|
46
58
|
fs.writeFileSync(filePath, content.endsWith("\n") ? content : `${content}\n`);
|
|
47
59
|
}
|
|
48
60
|
|
|
49
|
-
export function writeJsonFile(filePath: string, value: unknown): void {
|
|
50
|
-
writeTextFile(filePath, JSON.stringify(value, null, 2));
|
|
61
|
+
export function writeJsonFile(filePath: string, value: unknown, dryRun = false): void {
|
|
62
|
+
writeTextFile(filePath, JSON.stringify(value, null, 2), dryRun);
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
interface SanitizeJsonFunction {
|
|
54
|
-
(obj:
|
|
66
|
+
(obj: unknown, targetScope?: string): unknown;
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
export function copyDir(
|
|
@@ -63,11 +75,12 @@ export function copyDir(
|
|
|
63
75
|
targetScope = "",
|
|
64
76
|
sanitizeJson: SanitizeJsonFunction,
|
|
65
77
|
adapterId: AdapterId = "gemini",
|
|
78
|
+
dryRun = false,
|
|
66
79
|
): void {
|
|
67
80
|
const DEFAULT_SKIP = new Set(["node_modules", ".git", ".DS_Store", "package-lock.json"]);
|
|
68
81
|
const actualSkip = new Set([...DEFAULT_SKIP, ...skipSet]);
|
|
69
82
|
|
|
70
|
-
if (!fs.existsSync(dest)) {
|
|
83
|
+
if (!fs.existsSync(dest) && !dryRun) {
|
|
71
84
|
fs.mkdirSync(dest, { recursive: true });
|
|
72
85
|
}
|
|
73
86
|
|
|
@@ -75,7 +88,19 @@ export function copyDir(
|
|
|
75
88
|
if (actualSkip.has(entry.name)) return;
|
|
76
89
|
|
|
77
90
|
const srcPath = path.join(src, entry.name);
|
|
78
|
-
|
|
91
|
+
|
|
92
|
+
// Physical folder remapping during copy
|
|
93
|
+
let effectiveEntryName = entry.name;
|
|
94
|
+
if (entry.isDirectory()) {
|
|
95
|
+
if (entry.name === "agents") {
|
|
96
|
+
if (adapterId === "antigravity") effectiveEntryName = "skills";
|
|
97
|
+
else if (adapterId === "grok") effectiveEntryName = "plugins";
|
|
98
|
+
} else if (entry.name === "knowledge") {
|
|
99
|
+
if (adapterId === "antigravity") effectiveEntryName = "rules";
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const destPath = path.join(dest, effectiveEntryName);
|
|
79
104
|
|
|
80
105
|
if (entry.isDirectory()) {
|
|
81
106
|
copyDir(
|
|
@@ -87,6 +112,7 @@ export function copyDir(
|
|
|
87
112
|
targetScope,
|
|
88
113
|
sanitizeJson,
|
|
89
114
|
adapterId,
|
|
115
|
+
dryRun,
|
|
90
116
|
);
|
|
91
117
|
} else {
|
|
92
118
|
if (nonDestructive && fs.existsSync(destPath)) {
|
|
@@ -112,9 +138,17 @@ export function copyDir(
|
|
|
112
138
|
content = content.replace(/workspace:[^"'\s]*/g, "*");
|
|
113
139
|
}
|
|
114
140
|
|
|
115
|
-
|
|
141
|
+
if (dryRun) {
|
|
142
|
+
console.warn(`[DRY RUN] Would process and write: ${destPath}`);
|
|
143
|
+
} else {
|
|
144
|
+
fs.writeFileSync(destPath, content);
|
|
145
|
+
}
|
|
116
146
|
} else {
|
|
117
|
-
|
|
147
|
+
if (dryRun) {
|
|
148
|
+
console.warn(`[DRY RUN] Would copy binary file: ${destPath}`);
|
|
149
|
+
} else {
|
|
150
|
+
fs.copyFileSync(srcPath, destPath);
|
|
151
|
+
}
|
|
118
152
|
}
|
|
119
153
|
}
|
|
120
154
|
});
|
package/src/cli/utils/memory.ts
CHANGED
|
@@ -11,7 +11,9 @@ export function getFrameworkDir(): string {
|
|
|
11
11
|
const dirPath = path.join(targetDir, dir);
|
|
12
12
|
if (!fs.existsSync(dirPath)) continue;
|
|
13
13
|
const hasMemory = fs.existsSync(path.join(dirPath, "PROJECT_MEMORY.md"));
|
|
14
|
-
const hasAgents = fs.existsSync(path.join(dirPath, "agents"))
|
|
14
|
+
const hasAgents = fs.existsSync(path.join(dirPath, "agents")) ||
|
|
15
|
+
fs.existsSync(path.join(dirPath, "skills")) ||
|
|
16
|
+
fs.existsSync(path.join(dirPath, "plugins"));
|
|
15
17
|
if (hasMemory || hasAgents) {
|
|
16
18
|
return dir;
|
|
17
19
|
}
|
|
@@ -74,7 +76,7 @@ export function releaseMemoryLock(lockPath: string): void {
|
|
|
74
76
|
/**
|
|
75
77
|
* Create initial PROJECT_MEMORY.md if missing.
|
|
76
78
|
*/
|
|
77
|
-
export function initializeMemory(memoryPath: string, targetBase: string): void {
|
|
79
|
+
export function initializeMemory(memoryPath: string, targetBase: string, dryRun = false): void {
|
|
78
80
|
if (fs.existsSync(memoryPath)) return;
|
|
79
81
|
|
|
80
82
|
const traceId = generateULID();
|
|
@@ -136,6 +138,11 @@ This file is the Single Source of Truth (SSOT) and the persistent memory of the
|
|
|
136
138
|
`;
|
|
137
139
|
|
|
138
140
|
const finalTemplate = template.replace(/\{\{FRAMEWORK_DIR\}\}/g, targetBase);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
|
|
142
|
+
if (dryRun) {
|
|
143
|
+
console.warn(`[DRY RUN] Would initialize PROJECT_MEMORY.md at ${memoryPath}`);
|
|
144
|
+
} else {
|
|
145
|
+
fs.writeFileSync(memoryPath, finalTemplate);
|
|
146
|
+
console.warn(`✅ PROJECT_MEMORY.md initialized in ${targetBase}`);
|
|
147
|
+
}
|
|
141
148
|
}
|
package/src/cli/utils/pkg.ts
CHANGED
|
@@ -136,11 +136,12 @@ export function mergePackageJson(targetPath: string, sourcePath: string): void {
|
|
|
136
136
|
console.warn("✅ package.json updated with Enderun scripts and dependencies.");
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
export function sanitizeJson(obj:
|
|
139
|
+
export function sanitizeJson(obj: unknown, targetScope = ""): unknown {
|
|
140
140
|
if (typeof obj !== "object" || obj === null) return obj;
|
|
141
|
-
if (Array.isArray(obj)) return obj.map(item => sanitizeJson(item
|
|
141
|
+
if (Array.isArray(obj)) return obj.map(item => sanitizeJson(item, targetScope));
|
|
142
142
|
const cleaned: Record<string, unknown> = {};
|
|
143
|
-
|
|
143
|
+
const record = obj as Record<string, unknown>;
|
|
144
|
+
for (const [key, value] of Object.entries(record)) {
|
|
144
145
|
let finalKey = key;
|
|
145
146
|
let finalValue = value;
|
|
146
147
|
|
|
@@ -185,7 +186,7 @@ export function sanitizeJson(obj: Record<string, unknown>, targetScope = ""): Re
|
|
|
185
186
|
finalValue = "*";
|
|
186
187
|
}
|
|
187
188
|
|
|
188
|
-
cleaned[finalKey] = (typeof finalValue === "object" && finalValue !== null) ? sanitizeJson(finalValue
|
|
189
|
+
cleaned[finalKey] = (typeof finalValue === "object" && finalValue !== null) ? sanitizeJson(finalValue, targetScope) : finalValue;
|
|
189
190
|
}
|
|
190
191
|
return cleaned;
|
|
191
192
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Architecture Patterns — Agent Enderun
|
|
2
|
-
|
|
3
|
-
This directory contains the non-negotiable technical standards and architectural patterns for the Agent Enderun framework.
|
|
4
|
-
|
|
5
|
-
## Directory Structure
|
|
6
|
-
- `standards/`: Technical SOPs, design systems, and compliance mandates.
|
|
7
|
-
|
|
8
|
-
## Core Mandate
|
|
9
|
-
All agents MUST read and adhere to these documents before initiating any implementation task.
|
package/docs/user/README.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# Agent Enderun — Governance and Architecture Portal
|
|
2
|
-
|
|
3
|
-
This portal is the **Central Knowledge Source** for enterprise projects developed under the Agent Enderun framework. The project's architectural decisions, standards, and governance protocols are sealed here.
|
|
4
|
-
|
|
5
|
-
Unlike ordinary projects, Agent Enderun projects are built on a structure where AI agents operate autonomously but are bound by a rigid, human-authored constitution. This documentation is the **Immutable Guide** for both AI agents (Army) and human developers.
|
|
6
|
-
|
|
7
|
-
### 📋 Documentation Guide
|
|
8
|
-
|
|
9
|
-
#### [1. Architecture & Governance](architecture/)
|
|
10
|
-
* **[Architecture Decision Records (ADRs)](architecture/decisions/)**: Answers to "Why" and "How" questions at critical project milestones.
|
|
11
|
-
* **[Approval & High-Risk Workflows](architecture/approval-flows.md)**: Explains how tokens are generated, audited, and how high-risk actions (e.g., database deletion, privilege escalation) are sealed.
|
|
12
|
-
* **[Notification Strategy](architecture/notification-strategy.md)**: Dynamic and corporate notification patterns that do not disrupt the user experience.
|
|
13
|
-
|
|
14
|
-
#### [2. Frontend Standards](frontend/)
|
|
15
|
-
* **[Component Patterns](frontend/component-patterns.md)**: Zero-UI-Library policy, guide on how all components are hand-crafted and type-safe using Panda CSS.
|
|
16
|
-
* **[Form Validations](frontend/forms.md)**: Zero-error form management systems managed with Zod and React hooks.
|
|
17
|
-
* **[Toaster Configuration](frontend/notifications.md)**: Integration of tools like Sonner with the corporate theme.
|
|
18
|
-
|
|
19
|
-
#### [3. Backend Standards](backend/)
|
|
20
|
-
* **[Error Handling](backend/error-handling.md)**: Professional error management hierarchy that does not leak to the front-end and is traceable in logs.
|
|
21
|
-
* **[Audit Logging](backend/audit-logging.md)**: Contracts for how every operation is permanently processed into the database with a Trace ID.
|
|
22
|
-
|
|
23
|
-
## 🛰️ Phase-Based Development Life Cycle
|
|
24
|
-
All projects must pass the following 5 phases sequentially and completely:
|
|
25
|
-
|
|
26
|
-
1. **PHASE_0 (Discovery):** Tech-stack (`tech-stack.md`) sealed, risk analysis performed.
|
|
27
|
-
2. **PHASE_1 (Architecture & Contract):** First, types and API contracts are written. Contracts must be approved before a single line of application code is written.
|
|
28
|
-
3. **PHASE_2 (Core Development):** Backend and Frontend are built in parallel. Branded Types usage is mandatory.
|
|
29
|
-
4. **PHASE_3 (Integration & Test):** @quality agent takes over. 80% Test Coverage threshold must be met before proceeding to the next phase.
|
|
30
|
-
5. **PHASE_4 (Optimization & Deployment):** Security scans and performance tests are completed.
|
|
31
|
-
|
|
32
|
-
> **Agent Directive:** The documents under this folder define the operational boundaries of the agents. An agent cannot deviate from a rule defined here. If a rule needs to be updated, this can only be done with @manager approval and ADR registration.
|
|
33
|
-
|
|
34
|
-
**Version:** v0.9.0
|
|
35
|
-
**Status:** Active Governance
|