agent-enderun 1.11.2 → 1.11.4
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/README.md +5 -5
- package/bin/validate-agent-army.js +0 -1
- package/dist/framework-mcp/src/index.js +11 -1
- package/dist/framework-mcp/src/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/definitions.js +0 -10
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/index.js +0 -2
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/utils/compliance.d.ts +1 -1
- package/dist/framework-mcp/src/utils/compliance.js +68 -19
- package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
- package/dist/src/cli/adapters/scaffold.d.ts +1 -1
- package/dist/src/cli/adapters/scaffold.js +8 -8
- package/dist/src/cli/adapters/scaffold.js.map +1 -1
- package/dist/src/cli/commands/check.js +25 -40
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/contract.d.ts +3 -1
- package/dist/src/cli/commands/contract.js +8 -2
- package/dist/src/cli/commands/contract.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-ops.js +0 -2
- package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
- package/dist/src/cli/commands/init.js +4 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.js +10 -3
- package/dist/src/cli/commands/orchestrate.js.map +1 -1
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/index.js +14 -19
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/compliance.d.ts +5 -1
- package/dist/src/cli/utils/compliance.js +90 -42
- package/dist/src/cli/utils/compliance.js.map +1 -1
- package/dist/src/cli/utils/ui.js +11 -11
- package/dist/src/cli/utils/ui.js.map +1 -1
- package/dist/src/modules/adapters/definitions.js +114 -113
- package/dist/src/modules/adapters/definitions.js.map +1 -1
- package/dist/src/modules/adapters/registry.d.ts +12 -0
- package/dist/src/modules/adapters/registry.js +19 -0
- package/dist/src/modules/adapters/registry.js.map +1 -0
- package/dist/src/modules/adapters/shared.js +5 -4
- package/dist/src/modules/adapters/shared.js.map +1 -1
- package/dist/src/modules/agents/definitions.d.ts +6 -6
- package/dist/src/modules/agents/definitions.js +49 -25
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/agents/registry/analyst.js +1 -1
- package/dist/src/modules/agents/registry/analyst.js.map +1 -1
- package/dist/src/modules/agents/registry/architect.js +1 -1
- package/dist/src/modules/agents/registry/architect.js.map +1 -1
- package/dist/src/modules/agents/registry/backend.js +1 -1
- package/dist/src/modules/agents/registry/backend.js.map +1 -1
- package/dist/src/modules/agents/registry/database.js +1 -1
- package/dist/src/modules/agents/registry/database.js.map +1 -1
- package/dist/src/modules/agents/registry/devops.js +1 -1
- package/dist/src/modules/agents/registry/devops.js.map +1 -1
- package/dist/src/modules/agents/registry/explorer.js +1 -1
- package/dist/src/modules/agents/registry/explorer.js.map +1 -1
- package/dist/src/modules/agents/registry/frontend.js +1 -1
- package/dist/src/modules/agents/registry/frontend.js.map +1 -1
- package/dist/src/modules/agents/registry/git.js +1 -1
- package/dist/src/modules/agents/registry/git.js.map +1 -1
- package/dist/src/modules/agents/registry/manager.js +1 -2
- package/dist/src/modules/agents/registry/manager.js.map +1 -1
- package/dist/src/modules/agents/registry/mobile.js +1 -1
- package/dist/src/modules/agents/registry/mobile.js.map +1 -1
- package/dist/src/modules/agents/registry/quality.js +1 -1
- package/dist/src/modules/agents/registry/quality.js.map +1 -1
- package/dist/src/modules/agents/registry/security.js +1 -1
- package/dist/src/modules/agents/registry/security.js.map +1 -1
- package/dist/src/shared/fs.js +4 -3
- package/dist/src/shared/fs.js.map +1 -1
- package/dist/tests/agents-definitions.test.js +2 -1
- package/dist/tests/agents-definitions.test.js.map +1 -1
- package/dist/tests/integration/hermes_locking.test.d.ts +1 -0
- package/dist/tests/integration/hermes_locking.test.js +62 -0
- package/dist/tests/integration/hermes_locking.test.js.map +1 -0
- package/dist/tests/orchestrate.test.js +9 -6
- package/dist/tests/orchestrate.test.js.map +1 -1
- package/framework-mcp/dist/index.js +11 -1
- package/framework-mcp/dist/tools/definitions.js +0 -10
- package/framework-mcp/dist/tools/index.js +0 -2
- package/framework-mcp/dist/utils/compliance.js +68 -19
- package/framework-mcp/node_modules/.package-lock.json +1179 -0
- package/framework-mcp/package-lock.json +1191 -0
- package/framework-mcp/package.json +2 -2
- package/framework-mcp/src/index.ts +13 -1
- package/framework-mcp/src/tools/definitions.ts +0 -10
- package/framework-mcp/src/tools/index.ts +0 -2
- package/framework-mcp/src/utils/compliance.ts +82 -24
- package/package.json +3 -4
- package/src/cli/adapters/scaffold.ts +9 -8
- package/src/cli/commands/check.ts +26 -48
- package/src/cli/commands/contract.ts +5 -2
- package/src/cli/commands/init/scaffold-ops.ts +0 -3
- package/src/cli/commands/init.ts +5 -3
- package/src/cli/commands/orchestrate.ts +12 -3
- package/src/cli/commands/status.ts +3 -2
- package/src/cli/index.ts +14 -20
- package/src/cli/utils/compliance.ts +101 -47
- package/src/cli/utils/ui.ts +11 -11
- package/src/modules/adapters/definitions.ts +82 -57
- package/src/modules/adapters/registry.ts +27 -0
- package/src/modules/adapters/shared.ts +5 -4
- package/src/modules/agents/definitions.ts +53 -24
- package/src/modules/agents/registry/analyst.ts +1 -1
- package/src/modules/agents/registry/architect.ts +1 -1
- package/src/modules/agents/registry/backend.ts +1 -1
- package/src/modules/agents/registry/database.ts +1 -1
- package/src/modules/agents/registry/devops.ts +1 -1
- package/src/modules/agents/registry/explorer.ts +1 -1
- package/src/modules/agents/registry/frontend.ts +1 -1
- package/src/modules/agents/registry/git.ts +1 -1
- package/src/modules/agents/registry/manager.ts +1 -2
- package/src/modules/agents/registry/mobile.ts +1 -1
- package/src/modules/agents/registry/quality.ts +1 -1
- package/src/modules/agents/registry/security.ts +1 -1
- package/src/shared/fs.ts +4 -3
- package/templates/standards/frontend-standards.md +7 -2
- package/templates/standards/governance-standards.md +27 -1
- package/templates/standards/logging-and-secrets.md +1 -1
- package/templates/standards/observability-standards.md +1 -1
- package/templates/standards/quality-standards.md +2 -1
- package/bin/enderun-dashboard.js +0 -25
- package/framework-mcp/src/tools/dashboard/start_dashboard.ts +0 -33
- package/src/cli/commands/dashboard/data-service.ts +0 -167
- package/src/cli/commands/dashboard/html-template.ts +0 -696
- package/src/cli/commands/dashboard/server.ts +0 -43
- package/src/cli/commands/dashboard.ts +0 -11
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-enderun/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.4",
|
|
4
4
|
"description": "Agent Enderun Model Context Protocol (MCP) Server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/node": "^25.9.1",
|
|
17
|
-
"typescript": "^5.
|
|
17
|
+
"typescript": "^5.9.3"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -57,13 +57,25 @@ function validateArgs(toolName: string, args: Record<string, unknown>): string |
|
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
60
|
+
server.setRequestHandler(ListToolsRequestSchema, async (request) => {
|
|
61
|
+
// 2026 Stateless Spec: Log client info from metadata if available
|
|
62
|
+
const meta = (request as any)._meta;
|
|
63
|
+
if (meta) {
|
|
64
|
+
process.stderr.write(`[MCP] Stateless ListTools from ${meta.client?.name || "unknown"} v${meta.client?.version || "?.?"}\n`);
|
|
65
|
+
}
|
|
61
66
|
return { tools: TOOLS };
|
|
62
67
|
});
|
|
63
68
|
|
|
64
69
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
65
70
|
const req = request as { params: { name: string, arguments?: Record<string, unknown> } };
|
|
66
71
|
const { name, arguments: args } = req.params;
|
|
72
|
+
const meta = (request as any)._meta;
|
|
73
|
+
|
|
74
|
+
// 2026 Stateless Spec: Prioritize metadata-driven context
|
|
75
|
+
if (meta) {
|
|
76
|
+
process.stderr.write(`[MCP] Stateless CallTool: ${name} (Client: ${meta.client?.name || "unknown"})\n`);
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
const projectRoot = process.env.ENDERUN_PROJECT_ROOT || process.cwd();
|
|
68
80
|
|
|
69
81
|
try {
|
|
@@ -151,16 +151,6 @@ export const TOOLS: ToolDefinition[] = [
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
},
|
|
154
|
-
{
|
|
155
|
-
name: "start_dashboard",
|
|
156
|
-
description: "Start the Enderun Web Dashboard (Command Center) to visualize real-time agent status, logs, and system metrics in the browser.",
|
|
157
|
-
inputSchema: {
|
|
158
|
-
type: "object",
|
|
159
|
-
properties: {
|
|
160
|
-
port: { type: "number", description: "Optional: Port to run the dashboard on (default: 5858)" }
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
154
|
{
|
|
165
155
|
name: "get_framework_status",
|
|
166
156
|
description: "Get the current project phase, active traces, and agent states.",
|
|
@@ -14,7 +14,6 @@ import { handleAuditDependencies } from "./framework/audit_deps.js";
|
|
|
14
14
|
import { handleRunTests } from "./framework/run_tests.js";
|
|
15
15
|
import { handleGetSystemHealth } from "./observability/get_health.js";
|
|
16
16
|
import { handleCheckPorts } from "./observability/check_ports.js";
|
|
17
|
-
import { handleStartDashboard } from "./dashboard/start_dashboard.js";
|
|
18
17
|
import { handleOrchestrateLoop } from "./framework/orchestrate.js";
|
|
19
18
|
import { handleUpdateContractHash } from "./framework/update_contract_hash.js";
|
|
20
19
|
import { handleReadProjectMemory } from "./memory/read_memory.js";
|
|
@@ -51,7 +50,6 @@ export const toolHandlers: Record<string, ToolHandler> = {
|
|
|
51
50
|
run_tests: bind(handleRunTests),
|
|
52
51
|
get_system_health: bind(handleGetSystemHealth),
|
|
53
52
|
check_active_ports: bind(handleCheckPorts),
|
|
54
|
-
start_dashboard: bind(handleStartDashboard),
|
|
55
53
|
orchestrate_loop: bind(handleOrchestrateLoop),
|
|
56
54
|
send_agent_message: bind(handleSendAgentMessage),
|
|
57
55
|
log_agent_action: bind(handleLogAgentAction),
|
|
@@ -1,37 +1,95 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Enterprise Compliance Guardrail
|
|
3
|
-
* Checks content against corporate standards before allowing file mutations.
|
|
5
|
+
* Checks content against corporate standards using AST analysis before allowing file mutations.
|
|
4
6
|
*/
|
|
5
7
|
export function verifyCorporateCompliance(content: string, filePath: string): void {
|
|
6
|
-
//
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
throw new Error(
|
|
10
|
-
"❌ Corporate Compliance Breach: 'console.log/warn/error' usage is forbidden. " +
|
|
11
|
-
"Use the 'logger' system from '@/shared/logger' instead."
|
|
12
|
-
);
|
|
13
|
-
}
|
|
8
|
+
// Skip compliance checks for non-source files or specific ignored files
|
|
9
|
+
if (filePath.endsWith(".json") || filePath.endsWith(".md") || filePath.endsWith(".env.example")) {
|
|
10
|
+
return;
|
|
14
11
|
}
|
|
15
12
|
|
|
13
|
+
const sourceFile = ts.createSourceFile(
|
|
14
|
+
filePath,
|
|
15
|
+
content,
|
|
16
|
+
ts.ScriptTarget.Latest,
|
|
17
|
+
true
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const errors: string[] = [];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Recursive AST Visitor
|
|
24
|
+
*/
|
|
25
|
+
function visit(node: ts.Node) {
|
|
26
|
+
// 1. Zero Console Policy
|
|
27
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
28
|
+
const expression = node.expression;
|
|
29
|
+
const name = node.name.text;
|
|
30
|
+
if (ts.isIdentifier(expression) && expression.text === "console") {
|
|
31
|
+
if (["log", "warn", "error"].includes(name)) {
|
|
32
|
+
// Check if file is exempt
|
|
33
|
+
if (!filePath.includes("logger.ts") && !filePath.includes("check.ts") && !filePath.includes("cli.ts")) {
|
|
34
|
+
errors.push(`❌ Corporate Compliance Breach: 'console.${name}' usage is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
16
40
|
// 2. No Explicit Any Policy
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
41
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
42
|
+
if (ts.isIdentifier(node.typeName) && node.typeName.text === "any") {
|
|
43
|
+
if (!filePath.includes("definitions.ts") && !filePath.includes("types.ts")) {
|
|
44
|
+
errors.push(`❌ Corporate Compliance Breach: 'any' type is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 3. Zero UI Library Policy (No @chakra-ui, mui, @shadcn)
|
|
50
|
+
if (ts.isImportDeclaration(node)) {
|
|
51
|
+
const moduleSpecifier = node.moduleSpecifier;
|
|
52
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
53
|
+
const forbiddenLibs = ["@chakra-ui", "mui", "@shadcn", "antd", "bootstrap"];
|
|
54
|
+
const lib = forbiddenLibs.find(l => moduleSpecifier.text.includes(l));
|
|
55
|
+
if (lib) {
|
|
56
|
+
errors.push(`❌ Corporate Compliance Breach: External UI library '${lib}' usage is FORBIDDEN at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}. Build atomic components manually instead.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Handle 'any' as a keyword type (e.g., parameter: any)
|
|
62
|
+
if (node.kind === ts.SyntaxKind.AnyKeyword) {
|
|
63
|
+
if (!filePath.includes("definitions.ts") && !filePath.includes("types.ts")) {
|
|
64
|
+
errors.push(`❌ Corporate Compliance Breach: 'any' keyword is forbidden at line ${sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1}.`);
|
|
65
|
+
}
|
|
24
66
|
}
|
|
67
|
+
|
|
68
|
+
ts.forEachChild(node, visit);
|
|
25
69
|
}
|
|
26
70
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
71
|
+
visit(sourceFile);
|
|
72
|
+
|
|
73
|
+
// 3. Hardcoded Secrets & PII Guard
|
|
74
|
+
const piiKeywords = [
|
|
75
|
+
{ regex: /API_KEY\s*=\s*['"][^'"]+['"]/i, msg: "Hardcoded API Key" },
|
|
76
|
+
{ regex: /SECRET\s*=\s*['"][^'"]+['"]/i, msg: "Hardcoded Secret" },
|
|
77
|
+
{ regex: /PASSWORD\s*=\s*['"][^'"]+['"]/i, msg: "Hardcoded Password" },
|
|
78
|
+
{ regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/, msg: "PII Detected: Email Address" },
|
|
79
|
+
{ regex: /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/, msg: "PII Detected: Credit Card Pattern" }
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
for (const { regex, msg } of piiKeywords) {
|
|
83
|
+
if (regex.test(content)) {
|
|
84
|
+
// Allow emails in specific files like README or package.json
|
|
85
|
+
if (msg.includes("Email") && (filePath.endsWith("README.md") || filePath.endsWith("package.json") || filePath.includes("CONTRIBUTING"))) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
errors.push(`❌ Corporate Compliance Breach: ${msg} detected.`);
|
|
35
89
|
}
|
|
36
90
|
}
|
|
91
|
+
|
|
92
|
+
if (errors.length > 0) {
|
|
93
|
+
throw new Error(errors.join("\n"));
|
|
94
|
+
}
|
|
37
95
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-enderun",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.4",
|
|
4
4
|
"description": "The Supreme AI Governance & Autonomous Orchestration Framework for Enterprise Development. Acts as a Corporate AI Management Assistant.",
|
|
5
5
|
"author": "Yusuf BEKAR",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,6 @@
|
|
|
48
48
|
"enderun:verify": "agent-enderun verify-contract",
|
|
49
49
|
"enderun:update-contract": "agent-enderun update-contract",
|
|
50
50
|
"enderun:check": "agent-enderun check",
|
|
51
|
-
"enderun:dashboard": "node bin/enderun-dashboard.js",
|
|
52
51
|
"test:init": "node dist/src/cli/index.js init",
|
|
53
52
|
"enderun:lint": "eslint .",
|
|
54
53
|
"lint": "eslint .",
|
|
@@ -66,12 +65,12 @@
|
|
|
66
65
|
"eslint": "^10.4.0",
|
|
67
66
|
"globals": "^17.6.0",
|
|
68
67
|
"tsx": "^4.22.3",
|
|
69
|
-
"typescript": "^5.
|
|
68
|
+
"typescript": "^5.9.3",
|
|
70
69
|
"typescript-eslint": "^8.0.0",
|
|
71
70
|
"vitest": "^3.0.0"
|
|
72
71
|
},
|
|
73
72
|
"enderun": {
|
|
74
|
-
"version": "1.11.
|
|
73
|
+
"version": "1.11.4",
|
|
75
74
|
"initializedAt": "2026-06-04T18:51:28.970Z",
|
|
76
75
|
"frameworkDir": ".enderun"
|
|
77
76
|
},
|
|
@@ -20,7 +20,8 @@ export function scaffoldAgents(
|
|
|
20
20
|
dryRun: boolean,
|
|
21
21
|
agentsToScaffold?: string[],
|
|
22
22
|
explicitDestDir?: string,
|
|
23
|
-
explicitExt?: string
|
|
23
|
+
explicitExt?: string,
|
|
24
|
+
paths?: Record<string, string>
|
|
24
25
|
): void {
|
|
25
26
|
const adapter = ADAPTERS[adapterId];
|
|
26
27
|
if (!adapter) return;
|
|
@@ -46,27 +47,27 @@ export function scaffoldAgents(
|
|
|
46
47
|
|
|
47
48
|
switch (adapterId) {
|
|
48
49
|
case "gemini":
|
|
49
|
-
content = toGeminiCliMd(agent, baseKnowledgeDir);
|
|
50
|
+
content = toGeminiCliMd(agent, baseKnowledgeDir, paths);
|
|
50
51
|
break;
|
|
51
52
|
case "grok":
|
|
52
53
|
// Grok uses same Gemini-compatible YAML format
|
|
53
|
-
content = toGeminiCliMd(agent, baseKnowledgeDir);
|
|
54
|
+
content = toGeminiCliMd(agent, baseKnowledgeDir, paths);
|
|
54
55
|
break;
|
|
55
56
|
case "claude":
|
|
56
|
-
content = toClaudeCodeMd(agent, baseKnowledgeDir);
|
|
57
|
+
content = toClaudeCodeMd(agent, baseKnowledgeDir, paths);
|
|
57
58
|
break;
|
|
58
59
|
case "cursor":
|
|
59
|
-
content = toCursorMdc(agent, baseKnowledgeDir);
|
|
60
|
+
content = toCursorMdc(agent, baseKnowledgeDir, paths);
|
|
60
61
|
break;
|
|
61
62
|
case "codex":
|
|
62
|
-
content = toCodexMd(agent, baseKnowledgeDir);
|
|
63
|
+
content = toCodexMd(agent, baseKnowledgeDir, paths);
|
|
63
64
|
break;
|
|
64
65
|
case "antigravity-cli": {
|
|
65
66
|
// Antigravity uses nested folders: agents/{name}/agent.json and agents/{name}/agent.md
|
|
66
67
|
const agentDir = path.join(destAgentsDir, agent.name);
|
|
67
68
|
if (!dryRun) fs.mkdirSync(agentDir, { recursive: true });
|
|
68
69
|
|
|
69
|
-
content = toAntigravityJson(agent, baseKnowledgeDir);
|
|
70
|
+
content = toAntigravityJson(agent, baseKnowledgeDir, paths);
|
|
70
71
|
fileName = path.join(agent.name, "agent.json");
|
|
71
72
|
|
|
72
73
|
secondaryContent = `# 🎖️ Agent Enderun — @${agent.name}\n\n${agent.instructions.identity}\n\n${agent.instructions.mission}`;
|
|
@@ -75,7 +76,7 @@ export function scaffoldAgents(
|
|
|
75
76
|
}
|
|
76
77
|
default:
|
|
77
78
|
// Fallback to Gemini format
|
|
78
|
-
content = toGeminiCliMd(agent, baseKnowledgeDir);
|
|
79
|
+
content = toGeminiCliMd(agent, baseKnowledgeDir, paths);
|
|
79
80
|
break;
|
|
80
81
|
}
|
|
81
82
|
|
|
@@ -2,7 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
|
|
5
|
-
import { getFrameworkDir, getMemoryPath, getConfiguredPaths, isFrameworkDevelopmentRepo } from "../utils/memory.js";
|
|
5
|
+
import { getFrameworkDir, getMemoryPath, getConfiguredPaths, isFrameworkDevelopmentRepo, readState } from "../utils/memory.js";
|
|
6
6
|
import { getPackageVersion, getValidatorPath } from "../utils/pkg.js";
|
|
7
7
|
import { UI } from "../utils/ui.js";
|
|
8
8
|
import { logger } from "../../shared/logger.js";
|
|
@@ -10,16 +10,41 @@ import { scanProjectCompliance } from "../utils/compliance.js";
|
|
|
10
10
|
import { ALL_AGENTS } from "../../modules/agents/definitions.js";
|
|
11
11
|
import { detectActiveAgentLayouts, findAgentInstruction } from "../adapters/paths.js";
|
|
12
12
|
|
|
13
|
+
import { verifyApiContractCommand } from "./contract.js";
|
|
14
|
+
|
|
13
15
|
export async function checkCommand() {
|
|
14
16
|
UI.intent("Agent Enderun Health Check", `Checking system health and discipline rules (v${getPackageVersion()})...`);
|
|
15
17
|
let issues = 0;
|
|
16
18
|
|
|
19
|
+
const state = readState();
|
|
20
|
+
if (!state) {
|
|
21
|
+
UI.error("Memory state not found. Run 'init' first.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
const frameworkDir = getFrameworkDir();
|
|
18
26
|
const memoryPath = getMemoryPath();
|
|
19
27
|
const pathsMap = getConfiguredPaths();
|
|
20
28
|
|
|
21
29
|
UI.success(`Using framework dir: ${frameworkDir}`);
|
|
22
30
|
|
|
31
|
+
// --- Contract Gate (Phase 2+ Discipline) ---
|
|
32
|
+
if (["PHASE_2", "PHASE_3", "PHASE_4"].includes(state.phase)) {
|
|
33
|
+
console.warn("\n📝 Validating API Contracts (Phase 2+ Required)...");
|
|
34
|
+
try {
|
|
35
|
+
const contractOk = await verifyApiContractCommand({ silent: true });
|
|
36
|
+
if (!contractOk) {
|
|
37
|
+
UI.error("Contract verification FAILED! You cannot be in Phase 2+ with unverified contracts.");
|
|
38
|
+
issues++;
|
|
39
|
+
} else {
|
|
40
|
+
UI.success("API Contracts verified and sealed.");
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
UI.error("Error during contract verification.");
|
|
44
|
+
issues++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
23
48
|
let knowledgeDir = "knowledge";
|
|
24
49
|
if (frameworkDir === ".github") knowledgeDir = "instructions";
|
|
25
50
|
|
|
@@ -57,7 +82,6 @@ export async function checkCommand() {
|
|
|
57
82
|
{ name: ".env.example", path: ".env.example" },
|
|
58
83
|
...(isFrameworkDevelopment ? [{ name: "MCP Server", path: "framework-mcp/package.json" }] : []),
|
|
59
84
|
{ name: "Panda CSS Config", path: appPandaPath, optional: true },
|
|
60
|
-
{ name: "Brain Dashboard", path: path.join(frameworkDir, "BRAIN_DASHBOARD.md") },
|
|
61
85
|
];
|
|
62
86
|
|
|
63
87
|
for (const check of checks) {
|
|
@@ -135,52 +159,6 @@ export async function checkCommand() {
|
|
|
135
159
|
logger.debug("npx tsc --noEmit check failed", err);
|
|
136
160
|
}
|
|
137
161
|
|
|
138
|
-
interface MetricEntry {
|
|
139
|
-
timestamp: string;
|
|
140
|
-
agent: string;
|
|
141
|
-
action: string;
|
|
142
|
-
estimatedTokens: number;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const metricsPath = path.join(frameworkDir, "observability/metrics.json");
|
|
146
|
-
if (fs.existsSync(metricsPath)) {
|
|
147
|
-
try {
|
|
148
|
-
const raw = fs.readFileSync(metricsPath, "utf8");
|
|
149
|
-
const metrics: MetricEntry[] = JSON.parse(raw);
|
|
150
|
-
if (Array.isArray(metrics) && metrics.length > 0) {
|
|
151
|
-
console.warn("\n📊 Token Consumption Report:");
|
|
152
|
-
let totalTokens = 0;
|
|
153
|
-
const breakdown: Record<string, { count: number; tokens: number }> = {};
|
|
154
|
-
|
|
155
|
-
for (const entry of metrics) {
|
|
156
|
-
const tokens = typeof entry.estimatedTokens === "number" ? entry.estimatedTokens : 0;
|
|
157
|
-
totalTokens += tokens;
|
|
158
|
-
|
|
159
|
-
const actionName = (entry.action || "unknown").split(":")[0].trim();
|
|
160
|
-
if (!breakdown[actionName]) {
|
|
161
|
-
breakdown[actionName] = { count: 0, tokens: 0 };
|
|
162
|
-
}
|
|
163
|
-
breakdown[actionName].count += 1;
|
|
164
|
-
breakdown[actionName].tokens += tokens;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
console.warn(` - Total Operations: ${metrics.length}`);
|
|
168
|
-
console.warn(` - Total Estimated Tokens: ${totalTokens}`);
|
|
169
|
-
console.warn("\n Breakdown by Action:");
|
|
170
|
-
for (const [action, data] of Object.entries(breakdown)) {
|
|
171
|
-
console.warn(` - ${action}: ${data.count} ops (${data.tokens} tokens)`);
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
console.warn("\n📊 Token Consumption Report: No token usage logged yet.");
|
|
175
|
-
}
|
|
176
|
-
} catch (err) {
|
|
177
|
-
console.warn("\n📊 Token Consumption Report: Could not read or parse metrics file.");
|
|
178
|
-
logger.debug("Failed to read or parse metrics.json in checkCommand", err);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
console.warn("\n📊 Token Consumption Report: No token usage logged yet.");
|
|
182
|
-
}
|
|
183
|
-
|
|
184
162
|
if (issues === 0) {
|
|
185
163
|
UI.success("\n🚀 All systems green! Agent Enderun is ready.");
|
|
186
164
|
} else {
|
|
@@ -7,13 +7,14 @@ import { ValidationError } from "../../shared/errors.js";
|
|
|
7
7
|
/**
|
|
8
8
|
* Verify type safety between backend and frontend contracts.
|
|
9
9
|
*/
|
|
10
|
-
export async function verifyApiContractCommand() {
|
|
10
|
+
export async function verifyApiContractCommand(options: { silent?: boolean } = {}): Promise<boolean> {
|
|
11
11
|
const projectRoot = process.cwd();
|
|
12
12
|
const pathsMap = getConfiguredPaths();
|
|
13
13
|
const sharedDir = path.join(projectRoot, pathsMap.backend, "src/types");
|
|
14
14
|
const contractPath = path.join(projectRoot, pathsMap.backend, "contract.version.json");
|
|
15
15
|
|
|
16
16
|
if (!fs.existsSync(sharedDir) || !fs.existsSync(contractPath)) {
|
|
17
|
+
if (options.silent) return false;
|
|
17
18
|
throw new ValidationError(
|
|
18
19
|
"API types or contract version file missing.",
|
|
19
20
|
null,
|
|
@@ -25,8 +26,10 @@ export async function verifyApiContractCommand() {
|
|
|
25
26
|
const contract = JSON.parse(fs.readFileSync(contractPath, "utf8"));
|
|
26
27
|
|
|
27
28
|
if (contract.contract_hash === currentHash) {
|
|
28
|
-
console.warn("✅ Contract is valid and synchronized.");
|
|
29
|
+
if (!options.silent) console.warn("✅ Contract is valid and synchronized.");
|
|
30
|
+
return true;
|
|
29
31
|
} else {
|
|
32
|
+
if (options.silent) return false;
|
|
30
33
|
throw new ValidationError(
|
|
31
34
|
"Contract drift detected!",
|
|
32
35
|
{ stored: contract.contract_hash, actual: currentHash },
|
|
@@ -48,9 +48,6 @@ export function scaffoldOps(frameworkDir: string, dryRun: boolean) {
|
|
|
48
48
|
};
|
|
49
49
|
writeJsonFile(path.join(frameworkDir, "cli-commands.json"), cliCommands, dryRun);
|
|
50
50
|
|
|
51
|
-
// Scaffold BRAIN_DASHBOARD.md
|
|
52
|
-
writeTextFile(path.join(frameworkDir, "BRAIN_DASHBOARD.md"), "# 🧠 Brain Dashboard\n\nActive Trace: T-000\nActive Phase: PHASE_0 (Genesis)\n\n## Agent Statuses\n- @manager: READY\n- @architect: READY\n- @backend: READY\n- @frontend: READY\n- @quality: READY\n");
|
|
53
|
-
|
|
54
51
|
// Scaffold router/routing_rules.md
|
|
55
52
|
const routerDir = path.join(frameworkDir, "router");
|
|
56
53
|
if (!fs.existsSync(routerDir)) fs.mkdirSync(routerDir, { recursive: true });
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type AdapterId,
|
|
12
12
|
} from "../adapters/index.js";
|
|
13
13
|
import { ensureDir } from "../utils/fs.js";
|
|
14
|
-
import { initializeMemory } from "../utils/memory.js";
|
|
14
|
+
import { initializeMemory, getConfiguredPaths } from "../utils/memory.js";
|
|
15
15
|
import { getPackageVersion } from "../utils/pkg.js";
|
|
16
16
|
import { UI } from "../utils/ui.js";
|
|
17
17
|
|
|
@@ -122,18 +122,20 @@ export async function initCommand(adapterName: string, options: { unified?: bool
|
|
|
122
122
|
|
|
123
123
|
scaffoldStandards(path.join(projectRoot, coreDir), dryRun);
|
|
124
124
|
|
|
125
|
+
const pathsMap = getConfiguredPaths();
|
|
126
|
+
|
|
125
127
|
if (isUnified) {
|
|
126
128
|
// Scaffold ALL agents for ALL adapters under unified hub
|
|
127
129
|
for (const id of ADAPTER_IDS) {
|
|
128
130
|
const dest = resolveAgentsDir(id, true, aiToolDir);
|
|
129
|
-
scaffoldAgents(projectRoot, id, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt);
|
|
131
|
+
scaffoldAgents(projectRoot, id, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt, pathsMap);
|
|
130
132
|
if (!dryRun) mirrorUnifiedAgentsToNative(projectRoot, id);
|
|
131
133
|
}
|
|
132
134
|
UI.success(`✅ Scaffolding complete for all adapters under ${aiToolDir}/ with native mirrors.`);
|
|
133
135
|
} else {
|
|
134
136
|
// Standard single-adapter scaffold
|
|
135
137
|
const dest = resolveAgentsDir(adapterId, false);
|
|
136
|
-
scaffoldAgents(projectRoot, adapterId, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt);
|
|
138
|
+
scaffoldAgents(projectRoot, adapterId, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt, pathsMap);
|
|
137
139
|
UI.success(`✅ Generated agent definitions under ${dest.agentsDir}/`);
|
|
138
140
|
}
|
|
139
141
|
|
|
@@ -65,12 +65,21 @@ export async function orchestrateCommand(options?: { maxIterations?: number }) {
|
|
|
65
65
|
const agentStatuses = readStatus();
|
|
66
66
|
let updatedStatus = false;
|
|
67
67
|
for (const [agentName, info] of Object.entries(agentStatuses)) {
|
|
68
|
-
const { state, lastUpdated } = info as { state: string; task: string; lastUpdated?: string };
|
|
68
|
+
const { state, lastUpdated, task } = info as { state: string; task: string; lastUpdated?: string };
|
|
69
69
|
if (state === "EXECUTING" && lastUpdated) {
|
|
70
70
|
const lastUpdatedTime = Date.parse(lastUpdated);
|
|
71
71
|
if (!isNaN(lastUpdatedTime) && Date.now() - lastUpdatedTime > 30 * 60 * 1000) {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const displayAgent = agentName.startsWith("@") ? agentName : `@${agentName}`;
|
|
73
|
+
UI.error(`⚠️ Agent ${displayAgent} has TIMED OUT (in EXECUTING state for >30m). Triggering Self-Healing...`);
|
|
74
|
+
|
|
75
|
+
// SELF-HEALING: Log the failure and reset to READY
|
|
76
|
+
agentStatuses[agentName] = {
|
|
77
|
+
state: "READY",
|
|
78
|
+
task: "Idle (Recovered from Timeout)",
|
|
79
|
+
lastUpdated: new Date().toISOString()
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
UI.success(`✅ Hermes Self-Healing: ${displayAgent} reset to READY state. Task "${task}" aborted for recovery.`);
|
|
74
83
|
updatedStatus = true;
|
|
75
84
|
}
|
|
76
85
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
|
|
3
|
-
import
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { listTasks, readState, readStatus, getFrameworkDir } from "../utils/memory.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Print the current framework status.
|
package/src/cli/index.ts
CHANGED
|
@@ -32,8 +32,8 @@ async function main() {
|
|
|
32
32
|
const to = command;
|
|
33
33
|
const content = args.slice(1).join(" ");
|
|
34
34
|
if (!content) {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
process.stderr.write(`❌ Error: Missing task content for ${to}.\n`);
|
|
36
|
+
process.stderr.write(`Usage: agent-enderun ${to} "Your task description"\n`);
|
|
37
37
|
process.exit(64);
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -54,8 +54,8 @@ async function main() {
|
|
|
54
54
|
traceId
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
process.stdout.write(`✅ Task delegated to ${to} (Trace: ${traceId})\n`);
|
|
58
|
+
process.stdout.write("👉 Run \"agent-enderun orchestrate\" to process.\n");
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -93,19 +93,13 @@ async function main() {
|
|
|
93
93
|
const section = args[1];
|
|
94
94
|
const content = args[2];
|
|
95
95
|
if (!section || !content) {
|
|
96
|
-
|
|
96
|
+
process.stderr.write("❌ Error: section and content are required.\n");
|
|
97
97
|
process.exit(64);
|
|
98
98
|
}
|
|
99
99
|
await updateProjectMemoryCommand(section, content);
|
|
100
100
|
break;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
case "dashboard": {
|
|
104
|
-
const { dashboardCommand } = await import("./commands/dashboard.js");
|
|
105
|
-
await dashboardCommand(args.slice(1));
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
103
|
case "orchestrate":
|
|
110
104
|
case "loop":
|
|
111
105
|
await orchestrateCommand();
|
|
@@ -114,7 +108,7 @@ async function main() {
|
|
|
114
108
|
case "approve": {
|
|
115
109
|
const traceId = args[1];
|
|
116
110
|
if (!traceId) {
|
|
117
|
-
|
|
111
|
+
process.stderr.write("❌ Error: traceId is required.\n");
|
|
118
112
|
process.exit(64);
|
|
119
113
|
}
|
|
120
114
|
await approveCommand(traceId);
|
|
@@ -228,7 +222,7 @@ async function main() {
|
|
|
228
222
|
case "version":
|
|
229
223
|
case "-v":
|
|
230
224
|
case "--version":
|
|
231
|
-
|
|
225
|
+
process.stdout.write(`v${getPackageVersion()}\n`);
|
|
232
226
|
break;
|
|
233
227
|
|
|
234
228
|
case "help":
|
|
@@ -258,8 +252,8 @@ async function main() {
|
|
|
258
252
|
traceId
|
|
259
253
|
});
|
|
260
254
|
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
process.stdout.write(`📡 Request sent to @manager: "${content}" (Trace: ${traceId})\n`);
|
|
256
|
+
process.stdout.write("👉 Run 'agent-enderun orchestrate' to process.\n");
|
|
263
257
|
} else {
|
|
264
258
|
showHelp();
|
|
265
259
|
}
|
|
@@ -268,7 +262,7 @@ async function main() {
|
|
|
268
262
|
}
|
|
269
263
|
|
|
270
264
|
function showHelp() {
|
|
271
|
-
|
|
265
|
+
process.stdout.write(`
|
|
272
266
|
🎖️ Agent Enderun CLI (v${getPackageVersion()}) — The Supreme AI Orchestrator
|
|
273
267
|
|
|
274
268
|
Usage:
|
|
@@ -307,7 +301,7 @@ Natural Language:
|
|
|
307
301
|
Example:
|
|
308
302
|
agent-enderun "Audit my project"
|
|
309
303
|
agent-enderun @backend "Create the login page"
|
|
310
|
-
`);
|
|
304
|
+
\n`);
|
|
311
305
|
}
|
|
312
306
|
|
|
313
307
|
import { EnderunBaseError } from "../shared/errors.js";
|
|
@@ -315,12 +309,12 @@ import { logger } from "../shared/logger.js";
|
|
|
315
309
|
|
|
316
310
|
main().catch((err) => {
|
|
317
311
|
if (err instanceof EnderunBaseError) {
|
|
318
|
-
|
|
312
|
+
process.stderr.write(`\n❌ [${err.code}] Error: ${err.message}\n`);
|
|
319
313
|
if (err.solution) {
|
|
320
|
-
|
|
314
|
+
process.stderr.write(`💡 Solution Tip: ${err.solution}\n\n`);
|
|
321
315
|
}
|
|
322
316
|
} else {
|
|
323
|
-
|
|
317
|
+
process.stderr.write(`\n❌ Fatal Error: ${err.message || String(err)}\n`);
|
|
324
318
|
}
|
|
325
319
|
|
|
326
320
|
logger.fatal("Fatal exception during CLI execution", err);
|