agent-enderun 0.9.5 → 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 +2 -2
- package/framework-mcp/dist/utils/cli.js +1 -1
- package/framework-mcp/package.json +1 -1
- package/framework-mcp/src/index.ts +3 -3
- package/framework-mcp/src/utils/cli.ts +1 -1
- package/gemini.md +7 -1
- package/grok.md +1 -1
- package/package.json +5 -4
- 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
|
@@ -15,6 +15,6 @@ export function safeExec(command: string, args: string[], cwd: string): string {
|
|
|
15
15
|
});
|
|
16
16
|
} catch (error: unknown) {
|
|
17
17
|
const err = error as { stderr?: string; message?: string };
|
|
18
|
-
throw new Error(err.stderr || err.message || "Command execution failed");
|
|
18
|
+
throw new Error(err.stderr || err.message || "Command execution failed", { cause: error });
|
|
19
19
|
}
|
|
20
20
|
}
|
package/gemini.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This is the primary entry point when using Agent Enderun within the Gemini CLI ecosystem.
|
|
4
4
|
|
|
5
|
-
The framework operates under a unified governance structure located in the
|
|
5
|
+
The framework operates under a unified governance structure located in the .enderun/ directory.
|
|
6
6
|
|
|
7
7
|
### Primary Constitution
|
|
8
8
|
All governance rules, agent checklists, and project memory live here:
|
|
@@ -17,9 +17,15 @@ At the **start of every session**, before any work:
|
|
|
17
17
|
2. **Load Identity:** Read the relevant agent definition under `.enderun/agents/{agent}.md` (default to `@manager`).
|
|
18
18
|
3. **Internalize Knowledge:** Reference the `.enderun/knowledge/` base for architectural and coding standards.
|
|
19
19
|
|
|
20
|
+
### 💾 Memory Tiers
|
|
21
|
+
- **Project Memory (Shared):** `.enderun/PROJECT_MEMORY.md` is the source of truth for task history, Trace IDs, and architectural decisions. **Update this at the end of every turn.**
|
|
22
|
+
- **Private Memory (User-Specific):** Use the system's temporary directory memory folder for personal workflows or user-specific notes that should not be committed to Git.
|
|
23
|
+
- **Project Instructions:** This `gemini.md` file contains the "Supreme Law" and coding standards.
|
|
24
|
+
|
|
20
25
|
### 🛡️ Core Mandates
|
|
21
26
|
- **Surgical Edits:** Use `replace_text` or `patch_file` via MCP for precise changes.
|
|
22
27
|
- **Traceability:** Every action must inherit the active Trace ID from memory.
|
|
23
28
|
- **Contract First:** No implementation without verified types.
|
|
29
|
+
- **NEVER FORGET:** @manager MUST update `.enderun/PROJECT_MEMORY.md` at the end of EVERY session without exception. This is a non-negotiable process integrity rule.
|
|
24
30
|
|
|
25
31
|
All paths and references inside the project must comply with the Supreme Constitution located at `.enderun/ENDERUN.md`.
|
package/grok.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This is the primary entry point when using Agent Enderun within the Grok / X.ai ecosystem.
|
|
4
4
|
|
|
5
|
-
The framework operates under a unified governance structure located in the
|
|
5
|
+
The framework operates under a unified governance structure located in the .enderun/ directory.
|
|
6
6
|
|
|
7
7
|
### Primary Constitution
|
|
8
8
|
All governance rules, agent checklists, and project memory live here:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-enderun",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "The Supreme AI Governance & Orchestration Framework for Enterprise Development",
|
|
5
5
|
"author": "Yusuf BEKAR",
|
|
6
6
|
"license": "MIT",
|
|
@@ -82,7 +82,8 @@
|
|
|
82
82
|
"zod": "^3.24.2"
|
|
83
83
|
},
|
|
84
84
|
"enderun": {
|
|
85
|
-
"version": "0.
|
|
86
|
-
"initializedAt": "2026-05-
|
|
87
|
-
}
|
|
85
|
+
"version": "1.0.0",
|
|
86
|
+
"initializedAt": "2026-05-31T09:58:25.773Z"
|
|
87
|
+
},
|
|
88
|
+
"dependencies": {}
|
|
88
89
|
}
|
package/src/cli/adapters.ts
CHANGED
|
@@ -25,46 +25,47 @@ export const ADAPTERS: Record<AdapterId, AdapterConfig> = {
|
|
|
25
25
|
frameworkDir: ".gemini",
|
|
26
26
|
shimFile: "gemini.md",
|
|
27
27
|
templateDir: ".enderun",
|
|
28
|
-
nestedDirs: ["
|
|
28
|
+
nestedDirs: ["agents", "skills", "knowledge"],
|
|
29
29
|
},
|
|
30
30
|
claude: {
|
|
31
31
|
id: "claude",
|
|
32
32
|
frameworkDir: ".claude",
|
|
33
33
|
shimFile: "claude.md",
|
|
34
34
|
templateDir: ".enderun",
|
|
35
|
+
nestedDirs: ["agents", "skills", "knowledge"],
|
|
35
36
|
},
|
|
36
37
|
grok: {
|
|
37
38
|
id: "grok",
|
|
38
|
-
frameworkDir: ".grok",
|
|
39
|
+
frameworkDir: ".grok",
|
|
39
40
|
shimFile: "grok.md",
|
|
40
41
|
templateDir: ".enderun",
|
|
42
|
+
nestedDirs: ["plugins", "knowledge"],
|
|
41
43
|
},
|
|
42
44
|
antigravity: {
|
|
43
45
|
id: "antigravity",
|
|
44
|
-
frameworkDir: ".
|
|
46
|
+
frameworkDir: ".agent",
|
|
45
47
|
shimFile: "agent.md",
|
|
46
48
|
templateDir: ".enderun",
|
|
49
|
+
nestedDirs: ["skills", "workflows", "rules", "knowledge"],
|
|
47
50
|
},
|
|
48
51
|
"antigravity-cli": {
|
|
49
52
|
id: "antigravity-cli",
|
|
50
53
|
frameworkDir: ".gemini/antigravity-cli",
|
|
51
54
|
shimFile: "agent.md",
|
|
52
55
|
templateDir: ".enderun",
|
|
56
|
+
nestedDirs: ["agents", "skills"],
|
|
53
57
|
},
|
|
54
58
|
};
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
61
|
* All framework runtime directories (for discovery).
|
|
58
|
-
* Verified against 2026 industry standards
|
|
59
|
-
* and internal standards for Antigravity (.gemini/antigravity/).
|
|
62
|
+
* Verified against 2026 industry standards.
|
|
60
63
|
*/
|
|
61
64
|
export const FRAMEWORK_DIR_CANDIDATES = [
|
|
62
|
-
".
|
|
63
|
-
".gemini/antigravity-cli",
|
|
65
|
+
".agent",
|
|
64
66
|
".gemini",
|
|
65
67
|
".claude",
|
|
66
68
|
".grok",
|
|
67
|
-
".agent",
|
|
68
69
|
".enderun",
|
|
69
70
|
] as const;
|
|
70
71
|
|
|
@@ -89,8 +90,28 @@ export function remapFrameworkContent(
|
|
|
89
90
|
adapterId: AdapterId,
|
|
90
91
|
): string {
|
|
91
92
|
let result = content;
|
|
93
|
+
|
|
94
|
+
// 1. Dynamic Agent Folder Mapping based on adapter
|
|
95
|
+
let agentFolder = "agents";
|
|
96
|
+
let knowledgeFolder = "knowledge";
|
|
97
|
+
|
|
98
|
+
if (adapterId === "antigravity") {
|
|
99
|
+
agentFolder = "skills";
|
|
100
|
+
knowledgeFolder = "rules";
|
|
101
|
+
} else if (adapterId === "grok") {
|
|
102
|
+
agentFolder = "plugins";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 2. Replacements
|
|
92
106
|
result = result.replace(/\{\{FRAMEWORK_DIR\}\}/g, frameworkDir);
|
|
93
107
|
result = result.replace(/\{\{ADAPTER\}\}/g, adapterId);
|
|
108
|
+
|
|
109
|
+
// Replace standard patterns with adapter-specific ones
|
|
110
|
+
const frameworkPattern = ".enderun/";
|
|
111
|
+
result = result.replace(new RegExp(frameworkPattern + "agents/", "g"), `${frameworkDir}/${agentFolder}/`);
|
|
112
|
+
result = result.replace(new RegExp(frameworkPattern + "knowledge/", "g"), `${frameworkDir}/${knowledgeFolder}/`);
|
|
113
|
+
|
|
114
|
+
// Generic fallback for other .enderun/ paths
|
|
94
115
|
result = result.replace(/\.enderun\//g, `${frameworkDir}/`);
|
|
95
116
|
result = result.replace(/`\.enderun`/g, `\`${frameworkDir}\``);
|
|
96
117
|
result = result.replace(/\.enderun(?![\w/-])/g, frameworkDir);
|
|
@@ -16,6 +16,12 @@ export function checkCommand() {
|
|
|
16
16
|
|
|
17
17
|
const frameworkDir = getFrameworkDir();
|
|
18
18
|
const pathsMap = getConfiguredPaths();
|
|
19
|
+
|
|
20
|
+
// Determine folder names based on adapter detection
|
|
21
|
+
let knowledgeDir = "knowledge";
|
|
22
|
+
if (frameworkDir === ".agent") {
|
|
23
|
+
knowledgeDir = "rules";
|
|
24
|
+
}
|
|
19
25
|
|
|
20
26
|
const constitutionPath = fs.existsSync(path.join(process.cwd(), "ENDERUN.md"))
|
|
21
27
|
? "ENDERUN.md"
|
|
@@ -29,7 +35,7 @@ export function checkCommand() {
|
|
|
29
35
|
{ name: "Agent Status (STATUS.md)", path: path.join(frameworkDir, "STATUS.md") },
|
|
30
36
|
{ name: "MCP Config (mcp.json)", path: "mcp.json" },
|
|
31
37
|
{ name: "ESLint Config (eslint.config.js)", path: "eslint.config.js" },
|
|
32
|
-
{ name: "ESLint Standards", path: path.join(frameworkDir,
|
|
38
|
+
{ name: "ESLint Standards", path: path.join(frameworkDir, `${knowledgeDir}/eslint-standards.md`) },
|
|
33
39
|
{ name: "Backend Contract", path: path.join(pathsMap.backend, "contract.version.json") },
|
|
34
40
|
{ name: "MCP Server", path: "framework-mcp/package.json" },
|
|
35
41
|
{ name: "Panda CSS Config", path: "panda.config.ts" },
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type AdapterConfig,
|
|
12
12
|
} from "../adapters.js";
|
|
13
13
|
import { getPackageManager, mergePackageJson, deepCleanProtocols, sanitizeJson, getPackageVersion } from "../utils/pkg.js";
|
|
14
|
-
import { updateGitIgnore, ensureDir, writeJsonFile, copyDir } from "../utils/fs.js";
|
|
14
|
+
import { updateGitIgnore, ensureDir, writeJsonFile, copyDir, writeTextFile } from "../utils/fs.js";
|
|
15
15
|
import { initializeMemory } from "../utils/memory.js";
|
|
16
16
|
import { checkCommand } from "./check.js";
|
|
17
17
|
|
|
@@ -76,23 +76,21 @@ function buildDirsToCreate(adapter: AdapterConfig): string[] {
|
|
|
76
76
|
/**
|
|
77
77
|
* Scaffold the framework for a specific IDE adapter (separate runtime folder per IDE).
|
|
78
78
|
*/
|
|
79
|
-
export async function initCommand(adapterInput?: string) {
|
|
79
|
+
export async function initCommand(adapterInput?: string, dryRun = false) {
|
|
80
80
|
const adapter = resolveAdapter(adapterInput);
|
|
81
81
|
const { frameworkDir, shimFile, templateDir } = adapter;
|
|
82
82
|
const targetFrameworkDir = path.join(targetDir, frameworkDir);
|
|
83
83
|
|
|
84
|
+
if (dryRun) {
|
|
85
|
+
console.warn("\n🔍 DRY RUN MODE ACTIVE - No changes will be made to the filesystem.\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
console.warn(`🚀 Installing Agent Enderun (Adapter: ${adapter.id} → ${frameworkDir}/)...`);
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
fs.mkdirSync(targetFrameworkDir, { recursive: true });
|
|
88
|
-
}
|
|
90
|
+
ensureDir(targetFrameworkDir, dryRun);
|
|
89
91
|
|
|
90
92
|
for (const dir of buildDirsToCreate(adapter)) {
|
|
91
|
-
|
|
92
|
-
if (!fs.existsSync(fullPath)) {
|
|
93
|
-
fs.mkdirSync(fullPath, { recursive: true });
|
|
94
|
-
console.warn(`📂 Created directory: ${dir}`);
|
|
95
|
-
}
|
|
93
|
+
ensureDir(path.join(targetDir, dir), dryRun);
|
|
96
94
|
}
|
|
97
95
|
|
|
98
96
|
const filesToProcess = [
|
|
@@ -105,13 +103,13 @@ export async function initCommand(adapterInput?: string) {
|
|
|
105
103
|
fs.existsSync(path.join(sourceDir, f)),
|
|
106
104
|
);
|
|
107
105
|
|
|
108
|
-
ensureDir(path.join(targetDir, "apps/backend"));
|
|
106
|
+
ensureDir(path.join(targetDir, "apps/backend"), dryRun);
|
|
109
107
|
const initContractPath = path.join(targetDir, "apps/backend/contract.version.json");
|
|
110
108
|
if (!fs.existsSync(initContractPath)) {
|
|
111
109
|
writeJsonFile(initContractPath, {
|
|
112
110
|
contract_hash: "initial_hash_placeholder",
|
|
113
111
|
last_updated: new Date().toISOString(),
|
|
114
|
-
});
|
|
112
|
+
}, dryRun);
|
|
115
113
|
}
|
|
116
114
|
|
|
117
115
|
let targetPkg: Record<string, unknown> = {};
|
|
@@ -135,16 +133,43 @@ export async function initCommand(adapterInput?: string) {
|
|
|
135
133
|
const src = path.join(sourceDir, item);
|
|
136
134
|
let dest = path.join(targetDir, item);
|
|
137
135
|
|
|
138
|
-
if
|
|
136
|
+
// Safeguard: Do not delete or overwrite if we are in the framework's own development directory
|
|
137
|
+
const isDevMode = src === dest;
|
|
138
|
+
|
|
139
|
+
if (item === "framework-mcp" && fs.existsSync(dest) && !isDevMode) {
|
|
139
140
|
try {
|
|
140
|
-
|
|
141
|
+
if (dryRun) {
|
|
142
|
+
console.warn(`[DRY RUN] Would remove existing directory: ${dest}`);
|
|
143
|
+
} else {
|
|
144
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
145
|
+
}
|
|
141
146
|
} catch {
|
|
142
147
|
// ignore
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
if (item === templateDir || item.startsWith(`${templateDir}/`)) {
|
|
147
|
-
|
|
152
|
+
let relativePath = item.replace(templateDir, "").replace(/^\//, "");
|
|
153
|
+
|
|
154
|
+
// Adapter-specific agent/skill folder remapping
|
|
155
|
+
if (relativePath.startsWith("agents")) {
|
|
156
|
+
if (adapter.id === "antigravity") {
|
|
157
|
+
relativePath = relativePath.replace("agents", "skills");
|
|
158
|
+
} else if (adapter.id === "grok") {
|
|
159
|
+
relativePath = relativePath.replace("agents", "plugins");
|
|
160
|
+
}
|
|
161
|
+
} else if (relativePath.startsWith("knowledge")) {
|
|
162
|
+
if (adapter.id === "antigravity") {
|
|
163
|
+
relativePath = relativePath.replace("knowledge", "rules");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
dest = path.join(targetDir, frameworkDir, relativePath);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Skip if src and dest are same and it's not a shim or specific file that needs re-mapping
|
|
171
|
+
if (isDevMode && !isAdapterShimFile(item) && item !== "package.json") {
|
|
172
|
+
continue;
|
|
148
173
|
}
|
|
149
174
|
if (item === "ENDERUN.md") {
|
|
150
175
|
dest = path.join(targetFrameworkDir, "ENDERUN.md");
|
|
@@ -161,6 +186,11 @@ export async function initCommand(adapterInput?: string) {
|
|
|
161
186
|
const skipFiles =
|
|
162
187
|
item === templateDir ? ["logs", "PROJECT_MEMORY.md", "PROJECT_MEMORY.lock"] : [];
|
|
163
188
|
const nonDestructive = ["docs", templateDir].includes(item);
|
|
189
|
+
|
|
190
|
+
if (item === templateDir) {
|
|
191
|
+
// the destination path (dest) is already mapped correctly above.
|
|
192
|
+
}
|
|
193
|
+
|
|
164
194
|
copyDir(
|
|
165
195
|
src,
|
|
166
196
|
dest,
|
|
@@ -170,6 +200,7 @@ export async function initCommand(adapterInput?: string) {
|
|
|
170
200
|
targetScope,
|
|
171
201
|
sanitizeJson,
|
|
172
202
|
adapter.id,
|
|
203
|
+
dryRun,
|
|
173
204
|
);
|
|
174
205
|
} else {
|
|
175
206
|
if (item === "package.json") continue;
|
|
@@ -195,25 +226,38 @@ export async function initCommand(adapterInput?: string) {
|
|
|
195
226
|
}
|
|
196
227
|
}
|
|
197
228
|
|
|
198
|
-
|
|
229
|
+
writeTextFile(dest, content, dryRun);
|
|
199
230
|
} else {
|
|
200
|
-
|
|
231
|
+
if (dryRun) {
|
|
232
|
+
console.warn(`[DRY RUN] Would copy binary file: ${dest}`);
|
|
233
|
+
} else {
|
|
234
|
+
fs.copyFileSync(src, dest);
|
|
235
|
+
}
|
|
201
236
|
}
|
|
202
237
|
}
|
|
203
238
|
console.warn(`✅ ${item} processed -> ${path.relative(targetDir, dest)}`);
|
|
204
239
|
}
|
|
205
240
|
|
|
206
|
-
|
|
207
|
-
|
|
241
|
+
if (!dryRun) {
|
|
242
|
+
mergePackageJson(path.join(targetDir, "package.json"), path.join(sourceDir, "package.json"));
|
|
243
|
+
} else {
|
|
244
|
+
console.warn("[DRY RUN] Would merge package.json content.");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
updateGitIgnore(path.join(targetDir, ".gitignore"), frameworkDir, dryRun);
|
|
208
248
|
|
|
209
249
|
const finalMemoryPath = path.join(targetFrameworkDir, "PROJECT_MEMORY.md");
|
|
210
|
-
initializeMemory(finalMemoryPath, frameworkDir);
|
|
250
|
+
initializeMemory(finalMemoryPath, frameworkDir, dryRun);
|
|
211
251
|
|
|
212
|
-
|
|
252
|
+
if (!dryRun) {
|
|
253
|
+
deepCleanProtocols(targetDir, targetScope);
|
|
254
|
+
} else {
|
|
255
|
+
console.warn("[DRY RUN] Would clean specific workspace protocols.");
|
|
256
|
+
}
|
|
213
257
|
|
|
214
258
|
const sampleTestPath = path.join(targetDir, "tests/initial.test.ts");
|
|
215
259
|
if (!fs.existsSync(sampleTestPath)) {
|
|
216
|
-
|
|
260
|
+
writeTextFile(
|
|
217
261
|
sampleTestPath,
|
|
218
262
|
`import { describe, it, expect } from "vitest";
|
|
219
263
|
|
|
@@ -223,20 +267,29 @@ describe("Initial Setup", () => {
|
|
|
223
267
|
});
|
|
224
268
|
});
|
|
225
269
|
`,
|
|
270
|
+
dryRun,
|
|
226
271
|
);
|
|
227
272
|
}
|
|
228
273
|
|
|
229
274
|
if (!fs.existsSync(path.join(targetDir, ".git"))) {
|
|
230
275
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
276
|
+
if (dryRun) {
|
|
277
|
+
console.warn("[DRY RUN] Would initialize git repository.");
|
|
278
|
+
} else {
|
|
279
|
+
execSync("git init", { cwd: targetDir, stdio: "ignore" });
|
|
280
|
+
console.warn("✅ Git repository initialized.");
|
|
281
|
+
}
|
|
233
282
|
} catch {
|
|
234
283
|
// ignore
|
|
235
284
|
}
|
|
236
285
|
}
|
|
237
286
|
|
|
238
287
|
console.warn(`\n🛠️ Running ${adapter.id} adapter configuration...`);
|
|
239
|
-
|
|
288
|
+
if (!dryRun) {
|
|
289
|
+
runAdapterPostInit(adapter, targetDir);
|
|
290
|
+
} else {
|
|
291
|
+
console.warn(`[DRY RUN] Would run post-init steps for ${adapter.id}`);
|
|
292
|
+
}
|
|
240
293
|
|
|
241
294
|
console.warn(`\n♊ ${adapter.id.toUpperCase()}: Setup complete.`);
|
|
242
295
|
console.warn(` • Framework runtime: ${frameworkDir}/`);
|
|
@@ -251,8 +304,8 @@ describe("Initial Setup", () => {
|
|
|
251
304
|
|
|
252
305
|
console.warn(`\n✨ Framework scaffolded! (v${FRAMEWORK_VERSION})`);
|
|
253
306
|
|
|
254
|
-
if (process.env.ENDERUN_SKIP_INSTALL === "1") {
|
|
255
|
-
console.warn(
|
|
307
|
+
if (dryRun || process.env.ENDERUN_SKIP_INSTALL === "1") {
|
|
308
|
+
console.warn(`\n⏭️ Skipping install steps (${dryRun ? "Dry-Run" : "ENDERUN_SKIP_INSTALL=1"}).`);
|
|
256
309
|
return;
|
|
257
310
|
}
|
|
258
311
|
|
|
@@ -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
|