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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { resolveFrameworkDir } from "../../utils/security.js";
|
|
4
|
+
import { ToolArgs, ToolResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
export function handleSendAgentMessage(projectRoot: string, args: ToolArgs): ToolResult {
|
|
7
|
+
const { to, category, content, traceId } = args as Required<Pick<ToolArgs, "to" | "category" | "content" | "traceId">>;
|
|
8
|
+
const frameworkDir = resolveFrameworkDir(projectRoot);
|
|
9
|
+
const agentName = to.replace("@", "");
|
|
10
|
+
const messagePath = path.join(projectRoot, frameworkDir, "messages", `${agentName}.json`);
|
|
11
|
+
|
|
12
|
+
const message = {
|
|
13
|
+
timestamp: new Date().toISOString(),
|
|
14
|
+
from: "@mcp",
|
|
15
|
+
to,
|
|
16
|
+
category,
|
|
17
|
+
traceId,
|
|
18
|
+
content,
|
|
19
|
+
status: "PENDING"
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
fs.mkdirSync(path.dirname(messagePath), { recursive: true });
|
|
23
|
+
fs.appendFileSync(messagePath, JSON.stringify(message) + "\n");
|
|
24
|
+
|
|
25
|
+
return { content: [{ type: "text", text: `✅ Message sent to ${to}` }] };
|
|
26
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ToolDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: Record<string, { type: string; description?: string; enum?: string[] }>;
|
|
7
|
+
required?: string[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface CallToolRequest {
|
|
12
|
+
params: {
|
|
13
|
+
name: string;
|
|
14
|
+
arguments?: ToolArgs;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ToolArgs {
|
|
19
|
+
path?: string;
|
|
20
|
+
content?: string;
|
|
21
|
+
oldText?: string;
|
|
22
|
+
newText?: string;
|
|
23
|
+
startLine?: number;
|
|
24
|
+
endLine?: number;
|
|
25
|
+
newContent?: string;
|
|
26
|
+
section?: string;
|
|
27
|
+
to?: string;
|
|
28
|
+
category?: "ACTION" | "DELEGATION" | "INFO" | "ALERT";
|
|
29
|
+
traceId?: string;
|
|
30
|
+
agent?: string;
|
|
31
|
+
action?: string;
|
|
32
|
+
status?: "SUCCESS" | "FAILURE";
|
|
33
|
+
summary?: string;
|
|
34
|
+
findings?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ToolResult {
|
|
38
|
+
isError?: boolean;
|
|
39
|
+
content: Array<{ type: "text"; text: string }>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { execFileSync } from "child_process";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Executes a CLI command safely using execFileSync (no shell injection risk).
|
|
5
|
+
* Captures stderr gracefully to prevent stream crashes.
|
|
6
|
+
*/
|
|
7
|
+
export function safeExec(command: string, args: string[], cwd: string): string {
|
|
8
|
+
try {
|
|
9
|
+
return execFileSync(command, args, {
|
|
10
|
+
cwd,
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
timeout: 30000,
|
|
13
|
+
maxBuffer: 1024 * 1024,
|
|
14
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
15
|
+
});
|
|
16
|
+
} catch (error: unknown) {
|
|
17
|
+
const err = error as { stderr?: string; message?: string };
|
|
18
|
+
throw new Error(err.stderr || err.message || "Command execution failed", { cause: error });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validates and resolves a user-provided path to prevent path traversal attacks.
|
|
6
|
+
* Ensures the resolved path stays within the project root boundary.
|
|
7
|
+
*/
|
|
8
|
+
export function safePath(projectRoot: string, userPath: string): string {
|
|
9
|
+
const resolved = path.resolve(projectRoot, userPath);
|
|
10
|
+
const normalizedRoot = path.resolve(projectRoot);
|
|
11
|
+
|
|
12
|
+
if (!resolved.startsWith(normalizedRoot + path.sep) && resolved !== normalizedRoot) {
|
|
13
|
+
throw new Error(`Access denied: path "${userPath}" escapes project root.`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return resolved;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the active framework directory by scanning known candidates.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveFrameworkDir(projectRoot: string): string {
|
|
23
|
+
const candidates = [
|
|
24
|
+
".gemini/antigravity",
|
|
25
|
+
".gemini/antigravity-cli",
|
|
26
|
+
".gemini",
|
|
27
|
+
".claude",
|
|
28
|
+
".grok",
|
|
29
|
+
".agent",
|
|
30
|
+
".enderun",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
for (const candidate of candidates) {
|
|
34
|
+
const candidatePath = path.join(projectRoot, candidate);
|
|
35
|
+
if (fs.existsSync(candidatePath)) {
|
|
36
|
+
return candidate;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return ".enderun";
|
|
41
|
+
}
|
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
|
-
}
|
|
88
|
-
}
|
|
85
|
+
"version": "1.0.0",
|
|
86
|
+
"initializedAt": "2026-05-31T09:58:25.773Z"
|
|
87
|
+
},
|
|
88
|
+
"dependencies": {}
|
|
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
|
|