atabey 0.0.12 → 0.0.13
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/ATABEY.md +45 -499
- package/PRIVACY.md +161 -0
- package/README.md +353 -88
- package/bin/validate-al-registry.js +4 -4
- package/dist/framework-mcp/src/tools/definitions.js +23 -1
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/gateway/llm_gateway_query.d.ts +19 -0
- package/dist/framework-mcp/src/tools/gateway/llm_gateway_query.js +138 -0
- package/dist/framework-mcp/src/tools/gateway/llm_gateway_query.js.map +1 -0
- package/dist/framework-mcp/src/tools/gateway/llm_gateway_status.d.ts +8 -0
- package/dist/framework-mcp/src/tools/gateway/llm_gateway_status.js +91 -0
- package/dist/framework-mcp/src/tools/gateway/llm_gateway_status.js.map +1 -0
- package/dist/framework-mcp/src/tools/index.d.ts +1 -1
- package/dist/framework-mcp/src/tools/index.js +35 -20
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.d.ts +11 -0
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +166 -0
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js.map +1 -0
- package/dist/framework-mcp/src/tools/quality/check_architecture_compliance.d.ts +11 -0
- package/dist/framework-mcp/src/tools/quality/check_architecture_compliance.js +135 -0
- package/dist/framework-mcp/src/tools/quality/check_architecture_compliance.js.map +1 -0
- package/dist/framework-mcp/src/tools/schemas.d.ts +88 -8
- package/dist/framework-mcp/src/tools/schemas.js +29 -0
- package/dist/framework-mcp/src/tools/schemas.js.map +1 -1
- package/dist/framework-mcp/src/tools/shell/run_command.js +2 -2
- package/dist/framework-mcp/src/tools/shell/run_command.js.map +1 -1
- package/dist/src/cli/commands/check.js +2 -2
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/dashboard.d.ts +1 -1
- package/dist/src/cli/commands/dashboard.js +264 -41
- package/dist/src/cli/commands/dashboard.js.map +1 -1
- package/dist/src/cli/commands/gateway.d.ts +1 -0
- package/dist/src/cli/commands/gateway.js +172 -0
- package/dist/src/cli/commands/gateway.js.map +1 -0
- package/dist/src/cli/commands/init/create-agent.js +3 -3
- package/dist/src/cli/commands/init/create-agent.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-core.d.ts +1 -1
- package/dist/src/cli/commands/init/scaffold-core.js +1 -1
- package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +2 -0
- package/dist/src/cli/commands/init.js +105 -23
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/mcp.d.ts +7 -0
- package/dist/src/cli/commands/mcp.js +45 -22
- package/dist/src/cli/commands/mcp.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.d.ts +8 -7
- package/dist/src/cli/commands/orchestrate.js +2 -1
- package/dist/src/cli/commands/orchestrate.js.map +1 -1
- package/dist/src/cli/commands/quickstart.d.ts +5 -5
- package/dist/src/cli/commands/quickstart.js +36 -36
- package/dist/src/cli/commands/quickstart.js.map +1 -1
- package/dist/src/cli/index.js +230 -320
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/platforms/core.d.ts +12 -0
- package/dist/src/cli/platforms/core.js +73 -0
- package/dist/src/cli/platforms/core.js.map +1 -0
- package/dist/src/cli/platforms/index.d.ts +5 -0
- package/dist/src/cli/platforms/index.js +6 -0
- package/dist/src/cli/platforms/index.js.map +1 -0
- package/dist/src/cli/platforms/paths.d.ts +15 -0
- package/dist/src/cli/platforms/paths.js +102 -0
- package/dist/src/cli/platforms/paths.js.map +1 -0
- package/dist/src/cli/platforms/scaffold.d.ts +2 -0
- package/dist/src/cli/platforms/scaffold.js +73 -0
- package/dist/src/cli/platforms/scaffold.js.map +1 -0
- package/dist/src/cli/platforms/utils.d.ts +4 -0
- package/dist/src/cli/platforms/utils.js +76 -0
- package/dist/src/cli/platforms/utils.js.map +1 -0
- package/dist/src/cli/shims.js +4 -4
- package/dist/src/cli/utils/fs.d.ts +1 -1
- package/dist/src/cli/utils/fs.js +1 -1
- package/dist/src/cli/utils/fs.js.map +1 -1
- package/dist/src/modules/agents/definitions.d.ts +2 -2
- package/dist/src/modules/agents/definitions.js +59 -23
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/contracts/api.d.ts +178 -0
- package/dist/src/modules/contracts/api.js +56 -0
- package/dist/src/modules/contracts/api.js.map +1 -0
- package/dist/src/modules/contracts/index.d.ts +5 -0
- package/dist/src/modules/contracts/index.js +6 -0
- package/dist/src/modules/contracts/index.js.map +1 -0
- package/dist/src/modules/engines/agent-executor.d.ts +27 -28
- package/dist/src/modules/engines/agent-executor.js +97 -69
- package/dist/src/modules/engines/agent-executor.js.map +1 -1
- package/dist/src/modules/engines/quality-gate.d.ts +7 -7
- package/dist/src/modules/engines/quality-gate.js +7 -7
- package/dist/src/modules/engines/routing-engine.d.ts +18 -27
- package/dist/src/modules/engines/routing-engine.js +70 -44
- package/dist/src/modules/engines/routing-engine.js.map +1 -1
- package/dist/src/modules/gateway/circuit-breaker.d.ts +40 -0
- package/dist/src/modules/gateway/circuit-breaker.js +163 -0
- package/dist/src/modules/gateway/circuit-breaker.js.map +1 -0
- package/dist/src/modules/gateway/cost-tracker.d.ts +55 -0
- package/dist/src/modules/gateway/cost-tracker.js +127 -0
- package/dist/src/modules/gateway/cost-tracker.js.map +1 -0
- package/dist/src/modules/gateway/gateway.d.ts +68 -0
- package/dist/src/modules/gateway/gateway.js +235 -0
- package/dist/src/modules/gateway/gateway.js.map +1 -0
- package/dist/src/modules/gateway/index.d.ts +19 -0
- package/dist/src/modules/gateway/index.js +19 -0
- package/dist/src/modules/gateway/index.js.map +1 -0
- package/dist/src/modules/gateway/load-balancer.d.ts +86 -0
- package/dist/src/modules/gateway/load-balancer.js +230 -0
- package/dist/src/modules/gateway/load-balancer.js.map +1 -0
- package/dist/src/modules/gateway/providers/anthropic.d.ts +14 -0
- package/dist/src/modules/gateway/providers/anthropic.js +169 -0
- package/dist/src/modules/gateway/providers/anthropic.js.map +1 -0
- package/dist/src/modules/gateway/providers/base.d.ts +38 -0
- package/dist/src/modules/gateway/providers/base.js +42 -0
- package/dist/src/modules/gateway/providers/base.js.map +1 -0
- package/dist/src/modules/gateway/providers/google.d.ts +18 -0
- package/dist/src/modules/gateway/providers/google.js +176 -0
- package/dist/src/modules/gateway/providers/google.js.map +1 -0
- package/dist/src/modules/gateway/providers/grok.d.ts +14 -0
- package/dist/src/modules/gateway/providers/grok.js +166 -0
- package/dist/src/modules/gateway/providers/grok.js.map +1 -0
- package/dist/src/modules/gateway/providers/index.d.ts +21 -0
- package/dist/src/modules/gateway/providers/index.js +38 -0
- package/dist/src/modules/gateway/providers/index.js.map +1 -0
- package/dist/src/modules/gateway/providers/ollama.d.ts +23 -0
- package/dist/src/modules/gateway/providers/ollama.js +187 -0
- package/dist/src/modules/gateway/providers/ollama.js.map +1 -0
- package/dist/src/modules/gateway/providers/openai.d.ts +14 -0
- package/dist/src/modules/gateway/providers/openai.js +170 -0
- package/dist/src/modules/gateway/providers/openai.js.map +1 -0
- package/dist/src/modules/gateway/rate-limiter.d.ts +41 -0
- package/dist/src/modules/gateway/rate-limiter.js +119 -0
- package/dist/src/modules/gateway/rate-limiter.js.map +1 -0
- package/dist/src/modules/gateway/types.d.ts +114 -0
- package/dist/src/modules/gateway/types.js +8 -0
- package/dist/src/modules/gateway/types.js.map +1 -0
- package/dist/src/modules/memory/core.d.ts +4 -12
- package/dist/src/modules/memory/core.js +10 -17
- package/dist/src/modules/memory/core.js.map +1 -1
- package/dist/src/modules/memory/embedding.d.ts +28 -0
- package/dist/src/modules/memory/embedding.js +131 -0
- package/dist/src/modules/memory/embedding.js.map +1 -0
- package/dist/src/modules/providers/definitions.d.ts +9 -0
- package/dist/src/modules/providers/definitions.js +141 -0
- package/dist/src/modules/providers/definitions.js.map +1 -0
- package/dist/src/modules/providers/registry.d.ts +12 -0
- package/dist/src/modules/providers/registry.js +19 -0
- package/dist/src/modules/providers/registry.js.map +1 -0
- package/dist/src/modules/providers/shared.d.ts +1 -0
- package/dist/src/modules/providers/shared.js +105 -0
- package/dist/src/modules/providers/shared.js.map +1 -0
- package/dist/src/modules/providers/types.d.ts +14 -0
- package/dist/src/modules/providers/types.js +2 -0
- package/dist/src/modules/providers/types.js.map +1 -0
- package/dist/src/modules/skills/adapter-skills.d.ts +68 -0
- package/dist/src/modules/skills/adapter-skills.js +450 -0
- package/dist/src/modules/skills/adapter-skills.js.map +1 -0
- package/dist/src/shared/audit.d.ts +105 -0
- package/dist/src/shared/audit.js +220 -0
- package/dist/src/shared/audit.js.map +1 -0
- package/dist/src/shared/fs.js +4 -2
- package/dist/src/shared/fs.js.map +1 -1
- package/dist/src/shared/lock.d.ts +82 -0
- package/dist/src/shared/lock.js +160 -0
- package/dist/src/shared/lock.js.map +1 -0
- package/dist/src/shared/logger.d.ts +2 -0
- package/dist/src/shared/logger.js +15 -5
- package/dist/src/shared/logger.js.map +1 -1
- package/dist/src/shared/pii.d.ts +37 -0
- package/dist/src/shared/pii.js +122 -0
- package/dist/src/shared/pii.js.map +1 -0
- package/dist/src/shared/retention.d.ts +63 -0
- package/dist/src/shared/retention.js +171 -0
- package/dist/src/shared/retention.js.map +1 -0
- package/dist/src/shared/storage.d.ts +3 -1
- package/dist/src/shared/storage.js +3 -1
- package/dist/src/shared/storage.js.map +1 -1
- package/dist/tests/adapter.test.js +1 -1
- package/dist/tests/adapter.test.js.map +1 -1
- package/dist/tests/adapters/paths.test.js +4 -4
- package/dist/tests/adapters/paths.test.js.map +1 -1
- package/dist/tests/cli/commands/dashboard-coverage.test.d.ts +1 -0
- package/dist/tests/cli/commands/dashboard-coverage.test.js +88 -0
- package/dist/tests/cli/commands/dashboard-coverage.test.js.map +1 -0
- package/dist/tests/cli/init/adapter_init.test.js +4 -5
- package/dist/tests/cli/init/adapter_init.test.js.map +1 -1
- package/dist/tests/cli/init/unified_init.test.js +5 -7
- package/dist/tests/cli/init/unified_init.test.js.map +1 -1
- package/dist/tests/integration/agent_flow.test.js +14 -8
- package/dist/tests/integration/agent_flow.test.js.map +1 -1
- package/dist/tests/modules/adapters/adapters.test.js +2 -2
- package/dist/tests/modules/adapters/adapters.test.js.map +1 -1
- package/dist/tests/modules/contracts/contracts.test.d.ts +1 -0
- package/dist/tests/modules/contracts/contracts.test.js +73 -0
- package/dist/tests/modules/contracts/contracts.test.js.map +1 -0
- package/dist/tests/modules/engines/agent-executor.test.js +30 -23
- package/dist/tests/modules/engines/agent-executor.test.js.map +1 -1
- package/dist/tests/modules/gateway/circuit-breaker.test.d.ts +1 -0
- package/dist/tests/modules/gateway/circuit-breaker.test.js +124 -0
- package/dist/tests/modules/gateway/circuit-breaker.test.js.map +1 -0
- package/dist/tests/modules/gateway/cost-tracker.test.d.ts +1 -0
- package/dist/tests/modules/gateway/cost-tracker.test.js +74 -0
- package/dist/tests/modules/gateway/cost-tracker.test.js.map +1 -0
- package/dist/tests/modules/gateway/load-balancer.test.d.ts +1 -0
- package/dist/tests/modules/gateway/load-balancer.test.js +70 -0
- package/dist/tests/modules/gateway/load-balancer.test.js.map +1 -0
- package/dist/tests/modules/gateway/rate-limiter.test.d.ts +1 -0
- package/dist/tests/modules/gateway/rate-limiter.test.js +62 -0
- package/dist/tests/modules/gateway/rate-limiter.test.js.map +1 -0
- package/dist/tests/orchestrator-dependencies.test.js +23 -6
- package/dist/tests/orchestrator-dependencies.test.js.map +1 -1
- package/dist/tests/shared/audit.test.d.ts +1 -0
- package/dist/tests/shared/audit.test.js +53 -0
- package/dist/tests/shared/audit.test.js.map +1 -0
- package/dist/tests/storage-operations.test.d.ts +1 -0
- package/dist/tests/storage-operations.test.js +116 -0
- package/dist/tests/storage-operations.test.js.map +1 -0
- package/framework-mcp/README.md +324 -77
- package/framework-mcp/dist/dashboard/assets/index-BAPGLiWE.js +267 -0
- package/framework-mcp/dist/dashboard/index.html +15 -0
- package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +23 -1
- package/framework-mcp/dist/framework-mcp/src/tools/gateway/llm_gateway_query.js +137 -0
- package/framework-mcp/dist/framework-mcp/src/tools/gateway/llm_gateway_status.js +90 -0
- package/framework-mcp/dist/framework-mcp/src/tools/index.js +35 -20
- package/framework-mcp/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +165 -0
- package/framework-mcp/dist/framework-mcp/src/tools/quality/check_architecture_compliance.js +134 -0
- package/framework-mcp/dist/framework-mcp/src/tools/schemas.js +29 -0
- package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +2 -2
- package/framework-mcp/dist/src/modules/memory/core.js +10 -17
- package/framework-mcp/dist/src/modules/memory/embedding.js +130 -0
- package/framework-mcp/dist/src/shared/fs.js +4 -2
- package/framework-mcp/dist/src/shared/logger.js +15 -5
- package/framework-mcp/dist/src/shared/pii.js +121 -0
- package/framework-mcp/dist/src/shared/storage.js +3 -1
- package/framework-mcp/package.json +1 -1
- package/package.json +10 -4
- package/templates/full/ATABEY_FULL.md +515 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Hermes Control Center | Agent Atabey</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-BAPGLiWE.js"></script>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as schemas from "./schemas.js";
|
|
2
1
|
import { zodToMcpSchema } from "../utils/zod-to-mcp.js";
|
|
2
|
+
import * as schemas from "./schemas.js";
|
|
3
3
|
/**
|
|
4
4
|
* ─── SUPREME TOOL REGISTRY ─────────────────────────────────────────
|
|
5
5
|
* Every tool is dynamically generated from its Zod schema.
|
|
@@ -172,4 +172,26 @@ export const TOOLS = [
|
|
|
172
172
|
description: "Pause execution and ask the human developer a clarifying question via the terminal.",
|
|
173
173
|
inputSchema: zodToMcpSchema(schemas.AskHumanSchema),
|
|
174
174
|
},
|
|
175
|
+
// ─── Code Quality ─────────────────────────────────────────────
|
|
176
|
+
{
|
|
177
|
+
name: "analyze_code_quality",
|
|
178
|
+
description: "Analyze code quality in a given path. Checks TypeScript types, lint rules, and code complexity.",
|
|
179
|
+
inputSchema: zodToMcpSchema(schemas.AnalyzeCodeQualitySchema),
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "check_architecture_compliance",
|
|
183
|
+
description: "Check architecture compliance in a given path. Verifies layer boundaries (Controller→Service→Repository), import direction rules, and strict mode.",
|
|
184
|
+
inputSchema: zodToMcpSchema(schemas.CheckArchitectureComplianceSchema),
|
|
185
|
+
},
|
|
186
|
+
// ─── LLM Gateway ─────────────────────────────────────────
|
|
187
|
+
{
|
|
188
|
+
name: "llm_gateway_query",
|
|
189
|
+
description: "Send a chat completion request through the ATABEY LLM Gateway. The gateway automatically load-balances across providers (OpenAI, Anthropic, Google, Grok, Ollama) using configurable strategies (failover, round-robin, cost-optimized). Allows any MCP-connected AI to route LLM requests through the gateway.",
|
|
190
|
+
inputSchema: zodToMcpSchema(schemas.LLMGatewayQuerySchema),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: "llm_gateway_status",
|
|
194
|
+
description: "Get the current status of the LLM Gateway including provider health, load balancing strategy, usage statistics, and budget information.",
|
|
195
|
+
inputSchema: zodToMcpSchema(schemas.LLMGatewayStatusSchema),
|
|
196
|
+
},
|
|
175
197
|
];
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATABEY MCP Tool — LLM Gateway Query
|
|
3
|
+
*
|
|
4
|
+
* Sends a chat completion request through the ATABEY LLM Gateway.
|
|
5
|
+
* The gateway automatically selects the best provider based on the
|
|
6
|
+
* configured load balancing strategy (failover, round-robin, cost-optimized, etc.)
|
|
7
|
+
*
|
|
8
|
+
* This tool allows ANY MCP-connected AI (Gemini CLI, Claude CLI, Cursor, Grok, etc.)
|
|
9
|
+
* to route LLM requests through the gateway to any supported provider.
|
|
10
|
+
*
|
|
11
|
+
* The gateway module is loaded dynamically from the project root at runtime,
|
|
12
|
+
* not at compile time (since it lives outside the MCP workspace).
|
|
13
|
+
*/
|
|
14
|
+
import path from "path";
|
|
15
|
+
/**
|
|
16
|
+
* Dynamically load the LLM Gateway from the project root.
|
|
17
|
+
* Falls back gracefully if the gateway module is not available.
|
|
18
|
+
*/
|
|
19
|
+
async function loadGateway(projectRoot) {
|
|
20
|
+
try {
|
|
21
|
+
const gatewayPath = path.join(projectRoot, "dist/src/modules/gateway/index.js");
|
|
22
|
+
const mod = await import(gatewayPath);
|
|
23
|
+
return mod.gateway;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
try {
|
|
27
|
+
// Fallback: try tsx resolution for development
|
|
28
|
+
const gatewayPath = path.join(projectRoot, "src/modules/gateway/index.ts");
|
|
29
|
+
const mod = await import(gatewayPath);
|
|
30
|
+
return mod.gateway;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle llm_gateway_query tool call.
|
|
39
|
+
* Routes the request through the LLM Gateway with load balancing.
|
|
40
|
+
*/
|
|
41
|
+
export async function handleLLMGatewayQuery(projectRoot, args) {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
try {
|
|
44
|
+
// Load gateway dynamically
|
|
45
|
+
const gateway = await loadGateway(projectRoot);
|
|
46
|
+
if (!gateway) {
|
|
47
|
+
return {
|
|
48
|
+
isError: true,
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: JSON.stringify({
|
|
53
|
+
success: false,
|
|
54
|
+
error: "LLM Gateway is not initialized. The project may need to be built first. " +
|
|
55
|
+
"Run: npm run build:core",
|
|
56
|
+
solution: "Gateway module not found at dist/src/modules/gateway/index.js. " +
|
|
57
|
+
"Ensure the main package is built and ATABEY_PROJECT_ROOT is set correctly.",
|
|
58
|
+
}, null, 2),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Build gateway request
|
|
64
|
+
const gatewayRequest = {
|
|
65
|
+
messages: args.messages.map(m => ({
|
|
66
|
+
role: m.role,
|
|
67
|
+
content: m.content,
|
|
68
|
+
})),
|
|
69
|
+
system: args.system,
|
|
70
|
+
model: args.model,
|
|
71
|
+
temperature: args.temperature ?? 0.7,
|
|
72
|
+
maxTokens: args.maxTokens ?? 4096,
|
|
73
|
+
traceId: args.traceId || `MCP-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`,
|
|
74
|
+
};
|
|
75
|
+
// Provider override
|
|
76
|
+
if (args.provider) {
|
|
77
|
+
gatewayRequest.provider = args.provider;
|
|
78
|
+
}
|
|
79
|
+
// Strategy override
|
|
80
|
+
if (args.strategy) {
|
|
81
|
+
gatewayRequest.strategy = args.strategy;
|
|
82
|
+
}
|
|
83
|
+
// Send through gateway
|
|
84
|
+
const response = await gateway.chat(gatewayRequest);
|
|
85
|
+
const elapsed = Date.now() - startTime;
|
|
86
|
+
if (response.success) {
|
|
87
|
+
return {
|
|
88
|
+
content: [
|
|
89
|
+
{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: JSON.stringify({
|
|
92
|
+
success: true,
|
|
93
|
+
content: response.content,
|
|
94
|
+
provider: response.provider,
|
|
95
|
+
model: response.model,
|
|
96
|
+
usage: response.usage,
|
|
97
|
+
latencyMs: response.latencyMs,
|
|
98
|
+
cost: response.cost,
|
|
99
|
+
traceId: response.traceId,
|
|
100
|
+
elapsed,
|
|
101
|
+
}, null, 2),
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
isError: true,
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: "text",
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
success: false,
|
|
113
|
+
error: response.content,
|
|
114
|
+
provider: response.provider,
|
|
115
|
+
traceId: response.traceId,
|
|
116
|
+
elapsed,
|
|
117
|
+
}, null, 2),
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
return {
|
|
124
|
+
isError: true,
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: "text",
|
|
128
|
+
text: JSON.stringify({
|
|
129
|
+
success: false,
|
|
130
|
+
error: `Gateway query failed: ${error.message}`,
|
|
131
|
+
elapsed: Date.now() - startTime,
|
|
132
|
+
}, null, 2),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATABEY MCP Tool — LLM Gateway Status
|
|
3
|
+
*
|
|
4
|
+
* Returns the current status of the LLM Gateway, including provider health,
|
|
5
|
+
* current load balancing strategy, usage statistics, and budget info.
|
|
6
|
+
*
|
|
7
|
+
* Useful for monitoring and debugging gateway behavior without CLI access.
|
|
8
|
+
*/
|
|
9
|
+
import path from "path";
|
|
10
|
+
/**
|
|
11
|
+
* Dynamically load the LLM Gateway from the project root.
|
|
12
|
+
*/
|
|
13
|
+
async function loadGateway(projectRoot) {
|
|
14
|
+
try {
|
|
15
|
+
const gatewayPath = path.join(projectRoot, "dist/src/modules/gateway/index.js");
|
|
16
|
+
const mod = await import(gatewayPath);
|
|
17
|
+
return mod.gateway;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
try {
|
|
21
|
+
const gatewayPath = path.join(projectRoot, "src/modules/gateway/index.ts");
|
|
22
|
+
const mod = await import(gatewayPath);
|
|
23
|
+
return mod.gateway;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Handle llm_gateway_status tool call.
|
|
32
|
+
*/
|
|
33
|
+
export async function handleLLMGatewayStatus(projectRoot, args) {
|
|
34
|
+
const detail = args.detail || "overview";
|
|
35
|
+
try {
|
|
36
|
+
const gateway = await loadGateway(projectRoot);
|
|
37
|
+
if (!gateway) {
|
|
38
|
+
return {
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: JSON.stringify({
|
|
43
|
+
status: "unavailable",
|
|
44
|
+
message: "LLM Gateway is not initialized. " +
|
|
45
|
+
"Build the project first with: npm run build:core",
|
|
46
|
+
}, null, 2),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const result = {
|
|
52
|
+
status: "active",
|
|
53
|
+
strategy: gateway.loadBalancer.getStrategy(),
|
|
54
|
+
};
|
|
55
|
+
if (detail === "providers" || detail === "overview") {
|
|
56
|
+
result.providers = gateway.getProviderHealth();
|
|
57
|
+
}
|
|
58
|
+
if (detail === "stats" || detail === "overview") {
|
|
59
|
+
result.stats = gateway.getStats();
|
|
60
|
+
}
|
|
61
|
+
if (detail === "overview" || detail === "stats") {
|
|
62
|
+
const budget = gateway.costTracker.getBudgetStatus();
|
|
63
|
+
if (budget) {
|
|
64
|
+
result.budget = budget;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: JSON.stringify(result, null, 2),
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
isError: true,
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: JSON.stringify({
|
|
83
|
+
status: "error",
|
|
84
|
+
error: `Failed to get gateway status: ${error.message}`,
|
|
85
|
+
}, null, 2),
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -1,35 +1,39 @@
|
|
|
1
|
+
import { handleAcquireLock, handleReleaseLock } from "./control_plane/locking.js";
|
|
2
|
+
import { handleRegisterAgent } from "./control_plane/registry.js";
|
|
1
3
|
import { TOOLS } from "./definitions.js";
|
|
2
|
-
import { handleReadFile } from "./file_system/read_file.js";
|
|
3
|
-
import { handleWriteFile } from "./file_system/write_file.js";
|
|
4
|
-
import { handleReplaceText } from "./file_system/replace_text.js";
|
|
5
4
|
import { handleBatchSurgicalEdit } from "./file_system/batch_surgical_edit.js";
|
|
6
5
|
import { handlePatchFile } from "./file_system/patch_file.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { handleGetProjectMap } from "./search/get_map.js";
|
|
11
|
-
import { handleGetFrameworkStatus } from "./framework/get_status.js";
|
|
12
|
-
import { handleUpdateProjectMemory } from "./framework/update_memory.js";
|
|
6
|
+
import { handleReadFile } from "./file_system/read_file.js";
|
|
7
|
+
import { handleReplaceText } from "./file_system/replace_text.js";
|
|
8
|
+
import { handleWriteFile } from "./file_system/write_file.js";
|
|
13
9
|
import { handleAuditDependencies } from "./framework/audit_deps.js";
|
|
14
|
-
import {
|
|
15
|
-
import { handleGetSystemHealth } from "./observability/get_health.js";
|
|
16
|
-
import { handleCheckPorts } from "./observability/check_ports.js";
|
|
10
|
+
import { handleGetFrameworkStatus } from "./framework/get_status.js";
|
|
17
11
|
import { handleOrchestrateLoop } from "./framework/orchestrate.js";
|
|
12
|
+
import { handleRunTests } from "./framework/run_tests.js";
|
|
18
13
|
import { handleSubmitPlan } from "./framework/submit_plan.js";
|
|
19
14
|
import { handleUpdateContractHash } from "./framework/update_contract_hash.js";
|
|
20
|
-
import {
|
|
15
|
+
import { handleUpdateProjectMemory } from "./framework/update_memory.js";
|
|
16
|
+
import { handleLLMGatewayQuery } from "./gateway/llm_gateway_query.js";
|
|
17
|
+
import { handleLLMGatewayStatus } from "./gateway/llm_gateway_status.js";
|
|
18
|
+
import { handleDeleteKnowledge } from "./memory/delete_knowledge.js";
|
|
21
19
|
import { handleGetMemoryInsights } from "./memory/get_insights.js";
|
|
22
|
-
import {
|
|
20
|
+
import { handleReadProjectMemory } from "./memory/read_memory.js";
|
|
23
21
|
import { handleSearchKnowledge } from "./memory/search_knowledge.js";
|
|
24
|
-
import {
|
|
25
|
-
import { handleSendAgentMessage } from "./messaging/send_message.js";
|
|
26
|
-
import { handleLogAgentAction } from "./messaging/log_action.js";
|
|
22
|
+
import { handleStoreKnowledge } from "./memory/store_knowledge.js";
|
|
27
23
|
import { handleAskHuman } from "./messaging/ask_human.js";
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
24
|
+
import { handleLogAgentAction } from "./messaging/log_action.js";
|
|
25
|
+
import { handleSendAgentMessage } from "./messaging/send_message.js";
|
|
26
|
+
import { handleCheckPorts } from "./observability/check_ports.js";
|
|
27
|
+
import { handleGetSystemHealth } from "./observability/get_health.js";
|
|
28
|
+
import { handleAnalyzeCodeQuality } from "./quality/analyze_code_quality.js";
|
|
29
|
+
import { handleCheckArchitectureCompliance } from "./quality/check_architecture_compliance.js";
|
|
31
30
|
import { handleCheckLint } from "./quality/check_lint.js";
|
|
32
31
|
import * as schemas from "./schemas.js";
|
|
32
|
+
import { handleGetProjectGaps } from "./search/get_gaps.js";
|
|
33
|
+
import { handleGetProjectMap } from "./search/get_map.js";
|
|
34
|
+
import { handleGrepSearch } from "./search/grep_search.js";
|
|
35
|
+
import { handleListDir } from "./search/list_dir.js";
|
|
36
|
+
import { handleRunCommand } from "./shell/run_command.js";
|
|
33
37
|
// Map of tool names to their handler functions
|
|
34
38
|
const bind = (fn) => {
|
|
35
39
|
return (root, args) => fn(root, args);
|
|
@@ -67,6 +71,11 @@ export const toolHandlers = {
|
|
|
67
71
|
register_agent: bind(handleRegisterAgent),
|
|
68
72
|
run_shell_command: bind(handleRunCommand),
|
|
69
73
|
check_lint: bind(handleCheckLint),
|
|
74
|
+
analyze_code_quality: bind(handleAnalyzeCodeQuality),
|
|
75
|
+
check_architecture_compliance: bind(handleCheckArchitectureCompliance),
|
|
76
|
+
// LLM Gateway
|
|
77
|
+
llm_gateway_query: bind(handleLLMGatewayQuery),
|
|
78
|
+
llm_gateway_status: bind(handleLLMGatewayStatus),
|
|
70
79
|
};
|
|
71
80
|
// Map of tool names to their Zod validation schemas
|
|
72
81
|
export const toolSchemas = {
|
|
@@ -107,5 +116,11 @@ export const toolSchemas = {
|
|
|
107
116
|
send_agent_message: schemas.SendAgentMessageSchema,
|
|
108
117
|
log_agent_action: schemas.LogAgentActionSchema,
|
|
109
118
|
ask_human: schemas.AskHumanSchema,
|
|
119
|
+
// Code Quality
|
|
120
|
+
analyze_code_quality: schemas.AnalyzeCodeQualitySchema,
|
|
121
|
+
check_architecture_compliance: schemas.CheckArchitectureComplianceSchema,
|
|
122
|
+
// LLM Gateway
|
|
123
|
+
llm_gateway_query: schemas.LLMGatewayQuerySchema,
|
|
124
|
+
llm_gateway_status: schemas.LLMGatewayStatusSchema,
|
|
110
125
|
};
|
|
111
126
|
export { TOOLS };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Code quality analysis tool for Atabey MCP.
|
|
6
|
+
*
|
|
7
|
+
* Performs three checks on the provided source code:
|
|
8
|
+
* - TypeScript type checking (checkTypes)
|
|
9
|
+
* - Lint checking (checkLint)
|
|
10
|
+
* - Code complexity analysis (checkComplexity)
|
|
11
|
+
*/
|
|
12
|
+
export function handleAnalyzeCodeQuality(projectRoot, args) {
|
|
13
|
+
const targetPath = path.resolve(projectRoot, args.path);
|
|
14
|
+
if (!fs.existsSync(targetPath)) {
|
|
15
|
+
return {
|
|
16
|
+
isError: true,
|
|
17
|
+
content: [{ type: "text", text: `[ERROR] Path does not exist: ${args.path}` }]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const results = ["# Code Quality Analysis Report", "", `**Target:** ${args.path}`, `**Timestamp:** ${new Date().toISOString()}`, ""];
|
|
21
|
+
let hasErrors = false;
|
|
22
|
+
// 1. TypeScript Type Check
|
|
23
|
+
if (args.checkTypes !== false) {
|
|
24
|
+
try {
|
|
25
|
+
execSync("npx tsc --noEmit", {
|
|
26
|
+
cwd: projectRoot,
|
|
27
|
+
stdio: "pipe",
|
|
28
|
+
timeout: 30000,
|
|
29
|
+
encoding: "utf8"
|
|
30
|
+
});
|
|
31
|
+
results.push("## ✅ TypeScript Check: PASSED");
|
|
32
|
+
results.push("No type errors found.");
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
hasErrors = true;
|
|
36
|
+
const error = err;
|
|
37
|
+
const stderr = error.stderr || error.stdout || error.message || "Unknown error";
|
|
38
|
+
results.push("## ❌ TypeScript Check: FAILED");
|
|
39
|
+
results.push("```");
|
|
40
|
+
results.push(stderr.substring(0, 2000));
|
|
41
|
+
results.push("```");
|
|
42
|
+
}
|
|
43
|
+
results.push("");
|
|
44
|
+
}
|
|
45
|
+
// 2. Lint Check
|
|
46
|
+
if (args.checkLint !== false) {
|
|
47
|
+
try {
|
|
48
|
+
const lintOutput = execSync("npx eslint --format compact " + args.path, {
|
|
49
|
+
cwd: projectRoot,
|
|
50
|
+
stdio: "pipe",
|
|
51
|
+
timeout: 30000,
|
|
52
|
+
encoding: "utf8"
|
|
53
|
+
});
|
|
54
|
+
const lintStr = lintOutput.trim();
|
|
55
|
+
if (lintStr) {
|
|
56
|
+
results.push("## ⚠️ Lint Check: ISSUES FOUND");
|
|
57
|
+
results.push("```");
|
|
58
|
+
results.push(lintStr.substring(0, 2000));
|
|
59
|
+
results.push("```");
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
results.push("## ✅ Lint Check: PASSED");
|
|
63
|
+
results.push("No lint issues found.");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const error = err;
|
|
68
|
+
const stderr = error.stderr || error.stdout || error.message || "Unknown error";
|
|
69
|
+
// ESLint returns non-zero exit code when issues are found
|
|
70
|
+
if (stderr.includes("ESLint")) {
|
|
71
|
+
results.push("## ❌ Lint Check: FAILED");
|
|
72
|
+
results.push("```");
|
|
73
|
+
results.push(stderr.substring(0, 2000));
|
|
74
|
+
results.push("```");
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
results.push("## ✅ Lint Check: PASSED (no ESLint config)");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
results.push("");
|
|
81
|
+
}
|
|
82
|
+
// 3. Code Complexity Check (basic heuristic)
|
|
83
|
+
if (args.checkComplexity !== false) {
|
|
84
|
+
const complexityIssues = [];
|
|
85
|
+
function scanDirectory(dir) {
|
|
86
|
+
if (!fs.existsSync(dir))
|
|
87
|
+
return;
|
|
88
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
const fullPath = path.join(dir, entry.name);
|
|
91
|
+
if (entry.isDirectory() && !entry.name.startsWith("node_modules") && !entry.name.startsWith(".")) {
|
|
92
|
+
scanDirectory(fullPath);
|
|
93
|
+
}
|
|
94
|
+
else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
|
|
95
|
+
try {
|
|
96
|
+
const content = fs.readFileSync(fullPath, "utf8");
|
|
97
|
+
const lines = content.split("\n");
|
|
98
|
+
// Check for long functions (>50 lines)
|
|
99
|
+
let inFunction = false;
|
|
100
|
+
let funcLines = 0;
|
|
101
|
+
let funcName = "";
|
|
102
|
+
const relativePath = path.relative(projectRoot, fullPath);
|
|
103
|
+
for (let i = 0; i < lines.length; i++) {
|
|
104
|
+
const line = lines[i];
|
|
105
|
+
// Detect function start
|
|
106
|
+
const funcMatch = line.match(/(?:public|private|protected|static\s+)?(?:async\s+)?(?:function\s+)?(\w+)\s*\([^)]*\)\s*{/);
|
|
107
|
+
if (funcMatch) {
|
|
108
|
+
inFunction = true;
|
|
109
|
+
funcLines = 1;
|
|
110
|
+
funcName = funcMatch[1];
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Detect method in class
|
|
114
|
+
const methodMatch = line.match(/^\s*(?:public|private|protected|static\s+)?(\w+)\s*\([^)]*\)\s*{/);
|
|
115
|
+
if (methodMatch && !line.includes("function")) {
|
|
116
|
+
inFunction = true;
|
|
117
|
+
funcLines = 1;
|
|
118
|
+
funcName = methodMatch[1];
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (inFunction) {
|
|
122
|
+
if (line.includes("}")) {
|
|
123
|
+
if (funcLines > 50) {
|
|
124
|
+
complexityIssues.push(`- ${relativePath}:${i + 1} — Function \`${funcName}\` is ${funcLines} lines long (max: 50)`);
|
|
125
|
+
}
|
|
126
|
+
inFunction = false;
|
|
127
|
+
}
|
|
128
|
+
funcLines++;
|
|
129
|
+
}
|
|
130
|
+
// Check nesting depth (>4 levels)
|
|
131
|
+
const indentMatch = line.match(/^(?:\s{2}){5,}/);
|
|
132
|
+
if (indentMatch && !line.trim().startsWith("//") && !line.trim().startsWith("*")) {
|
|
133
|
+
const depth = Math.floor(indentMatch[0].length / 2);
|
|
134
|
+
if (depth > 4) {
|
|
135
|
+
complexityIssues.push(`- ${relativePath}:${i + 1} — Nesting depth ${depth} (max: 4)`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Skip files that can't be read
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
scanDirectory(targetPath);
|
|
147
|
+
if (complexityIssues.length > 0) {
|
|
148
|
+
hasErrors = true;
|
|
149
|
+
results.push(`## ⚠️ Code Complexity Issues (${complexityIssues.length})`);
|
|
150
|
+
results.push(...complexityIssues);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
results.push("## ✅ Code Complexity: OK");
|
|
154
|
+
results.push("No complexity issues found.");
|
|
155
|
+
}
|
|
156
|
+
results.push("");
|
|
157
|
+
}
|
|
158
|
+
// Summary
|
|
159
|
+
results.push("---");
|
|
160
|
+
results.push(`**Overall Status:** ${hasErrors ? "⚠️ Issues Found" : "✅ All Checks Passed"}`);
|
|
161
|
+
return {
|
|
162
|
+
content: [{ type: "text", text: results.join("\n") }],
|
|
163
|
+
isError: hasErrors
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
/**
|
|
4
|
+
* [TOOL] check_architecture_compliance
|
|
5
|
+
*
|
|
6
|
+
* Checks architectural compliance for code at the specified path:
|
|
7
|
+
* - Controller/Service/Repository layer separation
|
|
8
|
+
* - Import rules (controller → service → repository)
|
|
9
|
+
* - Circular dependencies
|
|
10
|
+
*/
|
|
11
|
+
export function handleCheckArchitectureCompliance(projectRoot, args) {
|
|
12
|
+
const targetPath = path.resolve(projectRoot, args.path);
|
|
13
|
+
if (!fs.existsSync(targetPath)) {
|
|
14
|
+
return {
|
|
15
|
+
isError: true,
|
|
16
|
+
content: [{ type: "text", text: `[ERROR] Path does not exist: ${args.path}` }]
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const results = [
|
|
20
|
+
"# Architecture Compliance Report",
|
|
21
|
+
"",
|
|
22
|
+
`**Target:** ${args.path}`,
|
|
23
|
+
`**Timestamp:** ${new Date().toISOString()}`,
|
|
24
|
+
""
|
|
25
|
+
];
|
|
26
|
+
const violations = [];
|
|
27
|
+
const allFiles = [];
|
|
28
|
+
// Collect all relevant files
|
|
29
|
+
function collectFiles(dir) {
|
|
30
|
+
if (!fs.existsSync(dir))
|
|
31
|
+
return;
|
|
32
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const fullPath = path.join(dir, entry.name);
|
|
35
|
+
if (entry.isDirectory() && !entry.name.startsWith("node_modules") && !entry.name.startsWith(".")) {
|
|
36
|
+
collectFiles(fullPath);
|
|
37
|
+
}
|
|
38
|
+
else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx"))) {
|
|
39
|
+
allFiles.push(fullPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
collectFiles(targetPath);
|
|
44
|
+
// Analyze each file for architectural violations
|
|
45
|
+
for (const file of allFiles) {
|
|
46
|
+
const relativePath = path.relative(projectRoot, file);
|
|
47
|
+
const content = fs.readFileSync(file, "utf8");
|
|
48
|
+
const lines = content.split("\n");
|
|
49
|
+
const fileName = path.basename(file, path.extname(file));
|
|
50
|
+
const fileDir = path.dirname(file);
|
|
51
|
+
// 1. Layer naming convention check
|
|
52
|
+
const isController = fileName.endsWith(".controller") || fileName.endsWith("Controller");
|
|
53
|
+
const isService = fileName.endsWith(".service") || fileName.endsWith("Service");
|
|
54
|
+
const isRepository = fileName.endsWith(".repository") || fileName.endsWith("Repository");
|
|
55
|
+
const isModel = fileName.endsWith(".model") || fileName.endsWith("Model");
|
|
56
|
+
// 2. Controller → Service → Repository dependency direction
|
|
57
|
+
for (const line of lines) {
|
|
58
|
+
const importMatch = line.match(/import\s+.*\s+from\s+['"](.+)['"]/);
|
|
59
|
+
if (!importMatch)
|
|
60
|
+
continue;
|
|
61
|
+
const importPath = importMatch[1];
|
|
62
|
+
const importedFileName = path.basename(importPath, path.extname(importPath));
|
|
63
|
+
// Controller importing Repository directly (should go through Service)
|
|
64
|
+
if (isController && (importedFileName.endsWith(".repository") || importedFileName.endsWith("Repository"))) {
|
|
65
|
+
violations.push(`- ${relativePath}: Controller \`${fileName}\` directly imports Repository \`${importedFileName}\`. ` +
|
|
66
|
+
"Use Service layer instead.");
|
|
67
|
+
}
|
|
68
|
+
// Repository importing Controller
|
|
69
|
+
if (isRepository && (importedFileName.endsWith(".controller") || importedFileName.endsWith("Controller"))) {
|
|
70
|
+
violations.push(`- ${relativePath}: Repository \`${fileName}\` imports Controller \`${importedFileName}\`. ` +
|
|
71
|
+
"Reverse dependency detected.");
|
|
72
|
+
}
|
|
73
|
+
// Service importing Controller
|
|
74
|
+
if (isService && (importedFileName.endsWith(".controller") || importedFileName.endsWith("Controller"))) {
|
|
75
|
+
violations.push(`- ${relativePath}: Service \`${fileName}\` imports Controller \`${importedFileName}\`. ` +
|
|
76
|
+
"Service should not depend on Controller.");
|
|
77
|
+
}
|
|
78
|
+
// Model importing Controller/Service/Repository
|
|
79
|
+
if (isModel && (importedFileName.endsWith("Controller") || importedFileName.endsWith("Service") || importedFileName.endsWith("Repository"))) {
|
|
80
|
+
violations.push(`- ${relativePath}: Model \`${fileName}\` imports \`${importedFileName}\`. ` +
|
|
81
|
+
"Models should not depend on other layers.");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 3. Check for barrel index imports that might cause circular dependencies
|
|
85
|
+
if (fileName === "index" && fileDir.includes("modules")) {
|
|
86
|
+
const indexContent = fs.readFileSync(file, "utf8");
|
|
87
|
+
const exports = indexContent.match(/export\s+\*?\s*from\s+['"].+['"]/g) || [];
|
|
88
|
+
if (exports.length > 10) {
|
|
89
|
+
violations.push(`- ${relativePath}: Barrel file exports ${exports.length} modules. ` +
|
|
90
|
+
"Consider splitting into smaller barrels to prevent circular dependencies.");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 4. Strict mode check
|
|
95
|
+
let hasStrictMode = false;
|
|
96
|
+
const tsConfigPath = path.join(projectRoot, "tsconfig.json");
|
|
97
|
+
if (fs.existsSync(tsConfigPath)) {
|
|
98
|
+
try {
|
|
99
|
+
const tsConfig = JSON.parse(fs.readFileSync(tsConfigPath, "utf8"));
|
|
100
|
+
if (tsConfig.compilerOptions?.strict) {
|
|
101
|
+
hasStrictMode = true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Ignore parse errors
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!hasStrictMode) {
|
|
109
|
+
violations.push("- tsconfig.json: `strict` mode is not enabled. Atabey requires strict type checking.");
|
|
110
|
+
}
|
|
111
|
+
// Report
|
|
112
|
+
if (violations.length > 0) {
|
|
113
|
+
results.push(`## ❌ Architecture Violations (${violations.length})`);
|
|
114
|
+
results.push("");
|
|
115
|
+
results.push(...violations);
|
|
116
|
+
results.push("");
|
|
117
|
+
results.push("---");
|
|
118
|
+
results.push(`**Status:** ❌ FAILED — ${violations.length} architectural violations found.`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
results.push("## ✅ Architecture Compliance: PASSED");
|
|
122
|
+
results.push("");
|
|
123
|
+
results.push("- All layer dependencies are correctly oriented.");
|
|
124
|
+
results.push("- No circular dependencies detected.");
|
|
125
|
+
results.push("- Strict mode is enabled.");
|
|
126
|
+
results.push("");
|
|
127
|
+
results.push("---");
|
|
128
|
+
results.push("**Status:** ✅ All architecture checks passed.");
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: "text", text: results.join("\n") }],
|
|
132
|
+
isError: violations.length > 0
|
|
133
|
+
};
|
|
134
|
+
}
|