atabey-mcp 0.0.26 → 0.0.27
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/dist/atabey/src/modules/engines/risk-engine.js +4 -2
- package/dist/atabey/src/modules/engines/risk-engine.js.map +1 -1
- package/package.json +1 -2
- package/dashboard/index.html +0 -15
- package/dashboard/package.json +0 -29
- package/dashboard/src/App.tsx +0 -352
- package/dashboard/src/components/AdapterSkillsPanel.tsx +0 -100
- package/dashboard/src/components/AgentMonitor.tsx +0 -90
- package/dashboard/src/components/ApprovalCenter.tsx +0 -74
- package/dashboard/src/components/CompliancePanel.tsx +0 -72
- package/dashboard/src/components/DisciplinePanel.tsx +0 -148
- package/dashboard/src/components/ErrorTracker.tsx +0 -97
- package/dashboard/src/components/FinOpsPanel.tsx +0 -236
- package/dashboard/src/components/HermesBrokerView.tsx +0 -59
- package/dashboard/src/components/HermesStats.tsx +0 -108
- package/dashboard/src/components/LicensePanel.tsx +0 -199
- package/dashboard/src/components/LogViewer.tsx +0 -87
- package/dashboard/src/components/LoopDetectorPanel.tsx +0 -203
- package/dashboard/src/components/MCPSetupPanel.tsx +0 -423
- package/dashboard/src/components/MemoryInsights.tsx +0 -107
- package/dashboard/src/components/PlanViewer.tsx +0 -95
- package/dashboard/src/components/PrivacyPanel.tsx +0 -276
- package/dashboard/src/components/QualityPanel.tsx +0 -98
- package/dashboard/src/components/TelemetryPanel.tsx +0 -197
- package/dashboard/src/components/TokenEconomyPanel.tsx +0 -285
- package/dashboard/src/hooks/useApi.ts +0 -39
- package/dashboard/src/hooks/useWS.ts +0 -47
- package/dashboard/src/main.tsx +0 -22
- package/dashboard/src/styles.ts +0 -908
- package/dashboard/tsconfig.json +0 -20
- package/dashboard/vite.config.ts +0 -25
|
@@ -30,10 +30,12 @@ export class RiskEngine {
|
|
|
30
30
|
];
|
|
31
31
|
// ─── Behavioral Signal Patterns ──────────────────────────────────────────
|
|
32
32
|
// Glob / wildcard patterns in paths that indicate bulk/mass-scope operations.
|
|
33
|
+
// NOTE: `/**/` (surrounded by slashes) = recursive glob, but `**text**` = markdown bold.
|
|
34
|
+
// We match `/**` or `**/` (path-context glob) and exclude standalone `**word**`.
|
|
33
35
|
static BULK_SCOPE_PATTERNS = [
|
|
34
|
-
|
|
36
|
+
/\/\*\*\/?/, // recursive glob in path context: /** or /**/
|
|
35
37
|
/\*\.[a-z]{2,4}/, // wildcard extension (*.ts, *.js)
|
|
36
|
-
/\/\*$/, // directory wildcard
|
|
38
|
+
/\/\*$/, // directory wildcard: /dir/*
|
|
37
39
|
];
|
|
38
40
|
/**
|
|
39
41
|
* Assesses the risk of a natural language task or command string.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-engine.js","sourceRoot":"","sources":["../../../../../../atabey/src/modules/engines/risk-engine.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,UAAU;IACX,MAAM,CAAC,kBAAkB,GAAG;QAChC,EAAE,IAAI,EAAE,QAAQ,EAAI,MAAM,EAAE,EAAE,EAAE;QAChC,EAAE,IAAI,EAAE,MAAM,EAAM,MAAM,EAAE,EAAE,EAAE;QAChC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;QAChC,EAAE,IAAI,EAAE,QAAQ,EAAI,MAAM,EAAE,EAAE,EAAE;QAChC,EAAE,IAAI,EAAE,OAAO,EAAK,MAAM,EAAE,EAAE,EAAE;QAChC,EAAE,IAAI,EAAE,QAAQ,EAAI,MAAM,EAAE,EAAE,EAAE;QAChC,EAAE,IAAI,EAAE,OAAO,EAAK,MAAM,EAAE,EAAE,EAAE;KACnC,CAAC;IAEM,MAAM,CAAC,eAAe,GAAG;QAC7B,EAAE,OAAO,EAAE,QAAQ,EAAO,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,OAAO,EAAE,SAAS,EAAM,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,OAAO,EAAE,WAAW,EAAI,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,OAAO,EAAE,WAAW,EAAI,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,OAAO,EAAE,SAAS,EAAM,MAAM,EAAE,EAAE,EAAE,EAAE,4BAA4B;KACvE,CAAC;IAEF,4EAA4E;IAC5E,8EAA8E;
|
|
1
|
+
{"version":3,"file":"risk-engine.js","sourceRoot":"","sources":["../../../../../../atabey/src/modules/engines/risk-engine.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atabey-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"description": "Atabey — AI Governance & Multi-Agent Platform / Orchestrator — MCP Server",
|
|
5
5
|
"author": "Yusuf BEKAR",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"files": [
|
|
39
39
|
"bin",
|
|
40
40
|
"dist",
|
|
41
|
-
"dashboard",
|
|
42
41
|
"README.md",
|
|
43
42
|
"LICENSE"
|
|
44
43
|
],
|
package/dashboard/index.html
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="root"></div>
|
|
13
|
-
<script type="module" src="/src/main.tsx"></script>
|
|
14
|
-
</body>
|
|
15
|
-
</html>
|
package/dashboard/package.json
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@atabey/dashboard-ui",
|
|
3
|
-
"version": "0.0.26",
|
|
4
|
-
"private": false,
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"access": "public"
|
|
7
|
-
},
|
|
8
|
-
"type": "module",
|
|
9
|
-
"scripts": {
|
|
10
|
-
"dev": "vite",
|
|
11
|
-
"build": "vite build",
|
|
12
|
-
"preview": "vite preview",
|
|
13
|
-
"test": "node -e \"process.exit(0)\""
|
|
14
|
-
},
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"react": "^19.0.0",
|
|
17
|
-
"react-dom": "^19.0.0",
|
|
18
|
-
"lucide-react": "^0.471.0",
|
|
19
|
-
"framer-motion": "^12.0.0",
|
|
20
|
-
"@tanstack/react-query": "^5.64.0"
|
|
21
|
-
},
|
|
22
|
-
"devDependencies": {
|
|
23
|
-
"@types/react": "^19.0.0",
|
|
24
|
-
"@types/react-dom": "^19.0.0",
|
|
25
|
-
"@vitejs/plugin-react": "^4.3.4",
|
|
26
|
-
"vite": "^6.0.7",
|
|
27
|
-
"typescript": "^5.9.3"
|
|
28
|
-
}
|
|
29
|
-
}
|
package/dashboard/src/App.tsx
DELETED
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Activity,
|
|
3
|
-
AlertTriangle,
|
|
4
|
-
Ban,
|
|
5
|
-
BarChart3,
|
|
6
|
-
BookOpen,
|
|
7
|
-
Bot,
|
|
8
|
-
Brain,
|
|
9
|
-
CheckCircle,
|
|
10
|
-
Cpu,
|
|
11
|
-
DollarSign,
|
|
12
|
-
ExternalLink,
|
|
13
|
-
GitBranch,
|
|
14
|
-
Github,
|
|
15
|
-
LayoutDashboard,
|
|
16
|
-
Lock,
|
|
17
|
-
Menu,
|
|
18
|
-
MessageSquare,
|
|
19
|
-
Moon,
|
|
20
|
-
Plug,
|
|
21
|
-
ScrollText,
|
|
22
|
-
Server,
|
|
23
|
-
ShieldCheck,
|
|
24
|
-
Sun,
|
|
25
|
-
Unlock,
|
|
26
|
-
Wifi,
|
|
27
|
-
X,
|
|
28
|
-
} from "lucide-react";
|
|
29
|
-
import { useEffect, useState } from "react";
|
|
30
|
-
import { AdapterSkillsPanel } from "./components/AdapterSkillsPanel";
|
|
31
|
-
import { AgentMonitor } from "./components/AgentMonitor";
|
|
32
|
-
import { ApprovalCenter } from "./components/ApprovalCenter";
|
|
33
|
-
import { CompliancePanel } from "./components/CompliancePanel";
|
|
34
|
-
import { DisciplinePanel } from "./components/DisciplinePanel";
|
|
35
|
-
import { ErrorTracker } from "./components/ErrorTracker";
|
|
36
|
-
import { FinOpsPanel } from "./components/FinOpsPanel";
|
|
37
|
-
import { HermesBrokerView } from "./components/HermesBrokerView";
|
|
38
|
-
import { HermesStats } from "./components/HermesStats";
|
|
39
|
-
import { LicensePanel } from "./components/LicensePanel";
|
|
40
|
-
import { LogViewer } from "./components/LogViewer";
|
|
41
|
-
import { LoopDetectorPanel } from "./components/LoopDetectorPanel";
|
|
42
|
-
import { MCPSetupPanel } from "./components/MCPSetupPanel";
|
|
43
|
-
import { MemoryInsights } from "./components/MemoryInsights";
|
|
44
|
-
import { PlanViewer } from "./components/PlanViewer";
|
|
45
|
-
import { PrivacyPanel } from "./components/PrivacyPanel";
|
|
46
|
-
import { QualityPanel } from "./components/QualityPanel";
|
|
47
|
-
import { TelemetryPanel } from "./components/TelemetryPanel";
|
|
48
|
-
import { TokenEconomyPanel } from "./components/TokenEconomyPanel";
|
|
49
|
-
import { useApi } from "./hooks/useApi";
|
|
50
|
-
import { useWS } from "./hooks/useWS";
|
|
51
|
-
import { css } from "./styles";
|
|
52
|
-
|
|
53
|
-
interface AgentInfo {
|
|
54
|
-
name: string;
|
|
55
|
-
state: string;
|
|
56
|
-
task: string;
|
|
57
|
-
last_updated: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
interface HermesStatsInfo {
|
|
61
|
-
total: number;
|
|
62
|
-
pending: number;
|
|
63
|
-
byCategory: Record<string, number>;
|
|
64
|
-
byStatus: Record<string, number>;
|
|
65
|
-
lastMessage: unknown;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface ApprovalInfo {
|
|
69
|
-
id: string;
|
|
70
|
-
traceId: string;
|
|
71
|
-
description: string;
|
|
72
|
-
status: string;
|
|
73
|
-
timestamp: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
interface ComplianceInfo {
|
|
77
|
-
summary: {
|
|
78
|
-
totalFiles: number;
|
|
79
|
-
totalViolations: number;
|
|
80
|
-
byType: Record<string, number>;
|
|
81
|
-
};
|
|
82
|
-
violations: unknown[];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const TABS = [
|
|
86
|
-
{ id: "dashboard", label: "Overview", Component: null, desc: "Governance Overview", icon: LayoutDashboard },
|
|
87
|
-
{ id: "agents", label: "Specialists", Component: AgentMonitor, desc: "13 Governed Specialists", icon: Bot },
|
|
88
|
-
{ id: "hermes", label: "Hermes", Component: HermesStats, desc: "Message Queue Stats", icon: BarChart3 },
|
|
89
|
-
{ id: "messages", label: "Audit Trail", Component: HermesBrokerView, desc: "Hermes Message Queue", icon: MessageSquare },
|
|
90
|
-
{ id: "approvals", label: "HITL Gates", Component: ApprovalCenter, desc: "Human-in-the-Loop Gates", icon: ShieldCheck },
|
|
91
|
-
{ id: "tasks", label: "Tasks", Component: PlanViewer, desc: "Task Planning & DAG", icon: GitBranch },
|
|
92
|
-
{ id: "logs", label: "Execution", Component: LogViewer, desc: "Specialist Execution Logs", icon: ScrollText },
|
|
93
|
-
{ id: "quality", label: "Quality", Component: QualityPanel, desc: "Code Quality Analysis", icon: Activity },
|
|
94
|
-
{ id: "errors", label: "Exceptions", Component: ErrorTracker, desc: "Policy & Audit Exceptions", icon: AlertTriangle },
|
|
95
|
-
{ id: "memory", label: "Memory", Component: MemoryInsights, desc: "Vector Memory Search", icon: Brain },
|
|
96
|
-
{ id: "compliance", label: "Compliance", Component: CompliancePanel, desc: "Quality Gate Status", icon: CheckCircle },
|
|
97
|
-
{ id: "finops", label: "FinOps", Component: FinOpsPanel, desc: "Budget & Cost Management", icon: DollarSign },
|
|
98
|
-
{ id: "loop", label: "Loop Detector", Component: LoopDetectorPanel, desc: "Loop Prevention & Cooldowns", icon: Ban },
|
|
99
|
-
{ id: "license", label: "License", Component: LicensePanel, desc: "SPDX & Copyleft Scanner", icon: BookOpen },
|
|
100
|
-
{ id: "telemetry", label: "Telemetry", Component: TelemetryPanel, desc: "Edge-to-Cloud Streaming", icon: Wifi },
|
|
101
|
-
{ id: "privacy", label: "GDPR / KVKK", Component: PrivacyPanel, desc: "GDPR & KVKK Compliance", icon: ShieldCheck },
|
|
102
|
-
{ id: "discipline", label: "Discipline", Component: DisciplinePanel, desc: "AI Discipline & Rules", icon: Ban },
|
|
103
|
-
{ id: "mcp", label: "MCP Setup", Component: MCPSetupPanel, desc: "MCP Configuration", icon: Server },
|
|
104
|
-
{ id: "adapters", label: "Adapters", Component: AdapterSkillsPanel, desc: "Adapter-Skill Mapping", icon: Plug },
|
|
105
|
-
{ id: "tokens", label: "Token Econ", Component: TokenEconomyPanel, desc: "Token Economy & Cost", icon: Cpu },
|
|
106
|
-
];
|
|
107
|
-
|
|
108
|
-
const TAB_ICONS: Record<string, typeof Bot> = {};
|
|
109
|
-
TABS.forEach(t => { TAB_ICONS[t.id] = t.icon; });
|
|
110
|
-
|
|
111
|
-
interface DashboardOverviewProps {
|
|
112
|
-
onNavigate: (tabId: string) => void;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const ALL_AGENT_NAMES = [
|
|
116
|
-
"manager", "security", "architect", "backend", "frontend", "quality",
|
|
117
|
-
"database", "analyst", "mobile", "native", "devops", "explorer", "git"
|
|
118
|
-
];
|
|
119
|
-
|
|
120
|
-
function DashboardOverview({ onNavigate }: DashboardOverviewProps) {
|
|
121
|
-
const { data: agents } = useApi<AgentInfo[]>("/agents", 5000);
|
|
122
|
-
const { data: queueStats } = useApi<HermesStatsInfo>("/hermes/stats", 5000);
|
|
123
|
-
const { data: approvals } = useApi<ApprovalInfo[]>("/approvals", 5000);
|
|
124
|
-
const { data: compliance } = useApi<ComplianceInfo>("/compliance?path=src", 10000);
|
|
125
|
-
|
|
126
|
-
const activeAgentsCount = Array.isArray(agents) ? agents.filter(a => a.state !== "READY" && a.state !== "Idle").length : 0;
|
|
127
|
-
const totalAgentsCount = ALL_AGENT_NAMES.length;
|
|
128
|
-
const pendingMessages = queueStats?.pending ?? 0;
|
|
129
|
-
const pendingApprovalsCount = Array.isArray(approvals) ? approvals.filter(a => a.status === "PENDING").length : 0;
|
|
130
|
-
const totalViolations = compliance?.summary?.totalViolations ?? 0;
|
|
131
|
-
|
|
132
|
-
const { data: privacyStats } = useApi<{ stats: { total: number; byAction: Record<string, number>; byCategory: Record<string, number> } }>("/audit", 10000);
|
|
133
|
-
const piiMaskedCount = privacyStats?.stats?.byAction?.["MASK_PII"] || privacyStats?.stats?.byAction?.["PII_MASKED"] || 0;
|
|
134
|
-
const piiDetectedCount = privacyStats?.stats?.byAction?.["PII_DETECTED"] || 0;
|
|
135
|
-
const restrictedCount = privacyStats?.stats?.byCategory?.["RESTRICTED"] || 0;
|
|
136
|
-
|
|
137
|
-
const { data: metricsData } = useApi<{ totalToolCalls: number; totalEstimatedTokens: number; totalEstimatedCost: number }>("/metrics", 10000);
|
|
138
|
-
const totalToolCalls = metricsData?.totalToolCalls ?? 0;
|
|
139
|
-
const totalEstimatedTokens = metricsData?.totalEstimatedTokens ?? 0;
|
|
140
|
-
const totalEstimatedCost = metricsData?.totalEstimatedCost ?? 0;
|
|
141
|
-
|
|
142
|
-
const { data: mcpSessions } = useApi<{ total: number }>("/mcp/sessions", 10000);
|
|
143
|
-
const activeSessions = mcpSessions?.total ?? 0;
|
|
144
|
-
|
|
145
|
-
// Discipline stats
|
|
146
|
-
const { data: disciplineData } = useApi<Record<string, { violations: number; totalCalls: number; inCooldown: boolean }>>("/discipline", 10000);
|
|
147
|
-
const totalViolationsCount = Object.values(disciplineData || {}).reduce((s: number, v: Record<string, unknown>) => s + ((v.violations as number) || 0), 0);
|
|
148
|
-
const inCooldown = Object.values(disciplineData || {}).some((v: Record<string, unknown>) => v.inCooldown);
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
<div className="dashboard-overview animate-fade-in">
|
|
152
|
-
<div className="hero-banner">
|
|
153
|
-
<div className="hero-title-group">
|
|
154
|
-
<h1>Governance Plane</h1>
|
|
155
|
-
<p style={{ marginTop: "0.25rem", fontSize: "0.85rem", opacity: 0.8 }}>
|
|
156
|
-
Governance Engine: <span style={{ color: "var(--color-success)", fontWeight: 600 }}>Active</span> | Policy Target: <span style={{ color: "var(--color-highlight)", fontWeight: 600 }}>Phase 0 Enforced</span>
|
|
157
|
-
</p>
|
|
158
|
-
</div>
|
|
159
|
-
<div className="hero-meta">
|
|
160
|
-
<span className="hero-badge">v0.0.23</span>
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
<div style={{ marginBottom: "1.5rem" }}>
|
|
165
|
-
<h3 style={{ fontSize: "0.8rem", textTransform: "uppercase", color: "var(--color-text-secondary)", letterSpacing: "0.08em", marginBottom: "0.75rem", borderLeft: "3px solid var(--color-accent-primary)", paddingLeft: "8px", fontWeight: 700 }}>
|
|
166
|
-
Active Session & Specialist Status
|
|
167
|
-
</h3>
|
|
168
|
-
<div className="quick-stats-grid">
|
|
169
|
-
<div className="stat-card clickable" onClick={() => onNavigate("agents")}>
|
|
170
|
-
<div className="stat-card-header"><Bot size={18} className="stat-icon" /><span className="stat-title">Specialists</span></div>
|
|
171
|
-
<div className="stat-card-value">{activeAgentsCount} / {totalAgentsCount}</div>
|
|
172
|
-
<div className="stat-card-desc">Governed specialist nodes active</div>
|
|
173
|
-
</div>
|
|
174
|
-
|
|
175
|
-
<div className="stat-card clickable" onClick={() => onNavigate("hermes")}>
|
|
176
|
-
<div className="stat-card-header"><BarChart3 size={18} className="stat-icon" /><span className="stat-title">Hermes Queue</span></div>
|
|
177
|
-
<div className="stat-card-value">{pendingMessages}</div>
|
|
178
|
-
<div className="stat-card-desc">Pending messages in transit</div>
|
|
179
|
-
</div>
|
|
180
|
-
|
|
181
|
-
<div className="stat-card clickable" onClick={() => onNavigate("approvals")} style={{
|
|
182
|
-
borderColor: pendingApprovalsCount > 0 ? "var(--color-accent-primary)" : undefined,
|
|
183
|
-
background: pendingApprovalsCount > 0 ? "var(--color-accent-glow)" : undefined
|
|
184
|
-
}}>
|
|
185
|
-
<div className="stat-card-header"><ShieldCheck size={18} className="stat-icon" /><span className="stat-title">HITL Gates</span></div>
|
|
186
|
-
<div className="stat-card-value" style={{ color: pendingApprovalsCount > 0 ? "var(--color-accent-primary)" : undefined }}>{pendingApprovalsCount}</div>
|
|
187
|
-
<div className="stat-card-desc">{pendingApprovalsCount > 0 ? "Manual overrides pending" : "All gates clear"}</div>
|
|
188
|
-
</div>
|
|
189
|
-
|
|
190
|
-
<div className="stat-card clickable" onClick={() => onNavigate("mcp")}>
|
|
191
|
-
<div className="stat-card-header"><Server size={18} style={{ color: "var(--color-accent-primary)" }} /><span className="stat-title">MCP Server</span></div>
|
|
192
|
-
<div className="stat-card-value" style={{ color: "var(--color-accent-primary)", fontSize: "1.1rem" }}>{activeSessions > 0 ? `${activeSessions} session(s)` : "Ready"}</div>
|
|
193
|
-
<div className="stat-card-desc">{activeSessions > 0 ? "AI clients connected" : "Waiting for AI clients"}</div>
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
<div style={{ marginBottom: "2rem" }}>
|
|
199
|
-
<h3 style={{ fontSize: "0.8rem", textTransform: "uppercase", color: "var(--color-text-secondary)", letterSpacing: "0.08em", marginBottom: "0.75rem", borderLeft: "3px solid var(--color-accent-primary)", paddingLeft: "8px", fontWeight: 700 }}>
|
|
200
|
-
AI Policy & Governance Gates
|
|
201
|
-
</h3>
|
|
202
|
-
<div className="quick-stats-grid">
|
|
203
|
-
<div className="stat-card clickable" onClick={() => onNavigate("compliance")}>
|
|
204
|
-
<div className="stat-card-header"><CheckCircle size={18} className="stat-icon" /><span className="stat-title">Gate Auditing</span></div>
|
|
205
|
-
<div className="stat-card-value" style={{ color: totalViolations > 0 ? "var(--color-warning)" : undefined }}>{totalViolations}</div>
|
|
206
|
-
<div className="stat-card-desc">Quality Gate violations</div>
|
|
207
|
-
</div>
|
|
208
|
-
|
|
209
|
-
<div className="stat-card clickable" onClick={() => onNavigate("privacy")} style={{ borderColor: piiDetectedCount > 0 ? "var(--color-accent-primary)" : undefined }}>
|
|
210
|
-
<div className="stat-card-header"><ShieldCheck size={18} style={{ color: "var(--color-accent-primary)" }} /><span className="stat-title">GDPR / KVKK</span></div>
|
|
211
|
-
<div className="stat-card-value" style={{ color: "var(--color-accent-primary)", fontSize: "1.1rem" }}>{piiMaskedCount > 0 ? `${piiMaskedCount} masked` : "Active"}</div>
|
|
212
|
-
<div className="stat-card-desc">{piiDetectedCount > 0 ? `${piiDetectedCount} PII · ${restrictedCount} restricted` : "PII masking active"}</div>
|
|
213
|
-
</div>
|
|
214
|
-
|
|
215
|
-
<div className="stat-card clickable" onClick={() => onNavigate("discipline")} style={{ borderColor: inCooldown ? "var(--color-warning)" : undefined }}>
|
|
216
|
-
<div className="stat-card-header"><Ban size={18} style={{ color: totalViolationsCount > 0 ? "var(--color-error)" : "var(--color-success)" }} /><span className="stat-title">Discipline</span></div>
|
|
217
|
-
<div className="stat-card-value" style={{ color: totalViolationsCount > 0 ? "var(--color-error)" : "var(--color-success)", fontSize: "1.1rem" }}>
|
|
218
|
-
{totalViolationsCount > 0 ? `${totalViolationsCount} violations` : "All Clean"}
|
|
219
|
-
</div>
|
|
220
|
-
<div className="stat-card-desc">{inCooldown ? "Agent(s) in cooldown" : "All agents compliant"}</div>
|
|
221
|
-
</div>
|
|
222
|
-
|
|
223
|
-
<div className="stat-card clickable" onClick={() => onNavigate("tokens")} style={{ borderColor: totalEstimatedCost > 0.1 ? "var(--color-warning)" : undefined }}>
|
|
224
|
-
<div className="stat-card-header"><Cpu size={18} style={{ color: "var(--color-accent-muted)" }} /><span className="stat-title">Token Economy</span></div>
|
|
225
|
-
<div className="stat-card-value" style={{ color: "var(--color-accent-muted)", fontSize: "1.1rem" }}>{totalToolCalls > 0 ? `${totalToolCalls} calls` : "Active"}</div>
|
|
226
|
-
<div className="stat-card-desc">{totalEstimatedTokens > 0 ? `${(totalEstimatedTokens / 1000).toFixed(1)}K tokens · ~$${totalEstimatedCost.toFixed(2)}` : "Tracking tool call metrics"}</div>
|
|
227
|
-
</div>
|
|
228
|
-
</div>
|
|
229
|
-
</div>
|
|
230
|
-
|
|
231
|
-
<div className="overview-sections-layout">
|
|
232
|
-
<div className="overview-left-column">
|
|
233
|
-
<AgentMonitor />
|
|
234
|
-
<ApprovalCenter />
|
|
235
|
-
</div>
|
|
236
|
-
<div className="overview-right-column">
|
|
237
|
-
<HermesStats />
|
|
238
|
-
<LogViewer />
|
|
239
|
-
</div>
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export default function App() {
|
|
246
|
-
const [activeTab, setActiveTab] = useState("dashboard");
|
|
247
|
-
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
248
|
-
const [theme, setTheme] = useState<"dark" | "light">(() => {
|
|
249
|
-
const saved = localStorage.getItem("atabey-theme");
|
|
250
|
-
return (saved as "dark" | "light") || "dark";
|
|
251
|
-
});
|
|
252
|
-
const [authToken, setAuthTokenState] = useState(() => localStorage.getItem("atabey-auth-token") || "");
|
|
253
|
-
const saveAuthToken = (val: string) => {
|
|
254
|
-
localStorage.setItem("atabey-auth-token", val);
|
|
255
|
-
setAuthTokenState(val);
|
|
256
|
-
};
|
|
257
|
-
const wsConnected = useWS();
|
|
258
|
-
|
|
259
|
-
useEffect(() => {
|
|
260
|
-
document.documentElement.classList.remove("theme-dark", "theme-light");
|
|
261
|
-
document.documentElement.classList.add(`theme-${theme}`);
|
|
262
|
-
}, [theme]);
|
|
263
|
-
|
|
264
|
-
const toggleTheme = () => {
|
|
265
|
-
const next = theme === "dark" ? "light" : "dark";
|
|
266
|
-
setTheme(next);
|
|
267
|
-
localStorage.setItem("atabey-theme", next);
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const activeTabObj = TABS.find(t => t.id === activeTab) || TABS[0];
|
|
271
|
-
const ActiveComponent = activeTabObj.Component;
|
|
272
|
-
|
|
273
|
-
return (
|
|
274
|
-
<>
|
|
275
|
-
<style>{css}</style>
|
|
276
|
-
<div className={`sidebar-overlay ${sidebarOpen ? "open" : ""}`} onClick={() => setSidebarOpen(false)} />
|
|
277
|
-
<div className="app-shell">
|
|
278
|
-
<aside className={`sidebar ${sidebarOpen ? "open" : ""}`}>
|
|
279
|
-
<div className="sidebar-header"><span className="sidebar-logo">[ATABEY]</span></div>
|
|
280
|
-
<nav className="sidebar-nav">
|
|
281
|
-
{TABS.map(t => {
|
|
282
|
-
const Icon = t.icon;
|
|
283
|
-
return (
|
|
284
|
-
<button key={t.id} className={`sidebar-btn ${activeTab === t.id ? "active" : ""}`} onClick={() => { setActiveTab(t.id); setSidebarOpen(false); }} title={t.desc}>
|
|
285
|
-
<Icon /><span className="sidebar-label">{t.label}</span>
|
|
286
|
-
</button>
|
|
287
|
-
);
|
|
288
|
-
})}
|
|
289
|
-
</nav>
|
|
290
|
-
<div className="sidebar-footer">
|
|
291
|
-
<div className="ws-indicator">
|
|
292
|
-
<span className="ws-dot" style={{ background: wsConnected ? "var(--color-success)" : "var(--color-error)", boxShadow: wsConnected ? "0 0 6px var(--color-success)" : "none" }} />
|
|
293
|
-
{wsConnected ? "WS Live" : "WS Offline"}
|
|
294
|
-
</div>
|
|
295
|
-
<div style={{ marginTop: 6, opacity: 0.6 }}>Atabey Governance Engine v0.0.23</div>
|
|
296
|
-
</div>
|
|
297
|
-
</aside>
|
|
298
|
-
<div className="main-area">
|
|
299
|
-
<header className="main-header">
|
|
300
|
-
<div className="main-header-left">
|
|
301
|
-
<button className="menu-toggle" onClick={() => setSidebarOpen(!sidebarOpen)}>
|
|
302
|
-
{sidebarOpen ? <X /> : <Menu />}
|
|
303
|
-
</button>
|
|
304
|
-
<span style={{ display: "flex", alignItems: "center", gap: "0.5rem", fontWeight: 500, fontSize: "0.95rem" }}>
|
|
305
|
-
<span style={{ opacity: 0.85 }}>Hermes Control Center</span>
|
|
306
|
-
<span style={{ opacity: 0.4 }}>/</span>
|
|
307
|
-
<span style={{ color: "var(--color-accent-primary)", fontWeight: 600 }}>{activeTabObj.label}</span>
|
|
308
|
-
</span>
|
|
309
|
-
</div>
|
|
310
|
-
<div className="main-header-right">
|
|
311
|
-
<div className="auth-token-input-wrapper" style={{ position: "relative" }}>
|
|
312
|
-
{authToken ? (
|
|
313
|
-
<Lock size={12} style={{ position: "absolute", left: "6px", top: "50%", transform: "translateY(-50%)", color: "var(--color-success)" }} />
|
|
314
|
-
) : (
|
|
315
|
-
<Unlock size={12} style={{ position: "absolute", left: "6px", top: "50%", transform: "translateY(-50%)", color: "var(--color-text-muted)" }} />
|
|
316
|
-
)}
|
|
317
|
-
<input
|
|
318
|
-
type="password"
|
|
319
|
-
placeholder="MCP Token..."
|
|
320
|
-
className="auth-token-input"
|
|
321
|
-
value={authToken}
|
|
322
|
-
onChange={(e) => saveAuthToken(e.target.value)}
|
|
323
|
-
title="Enter MCP_AUTH_TOKEN if configured"
|
|
324
|
-
/>
|
|
325
|
-
</div>
|
|
326
|
-
<button className="theme-toggle-btn" onClick={toggleTheme} title={`Switch to ${theme === "dark" ? "light" : "dark"} mode`} style={{ marginRight: "0.5rem" }}>
|
|
327
|
-
{theme === "dark" ? <Sun size={16} /> : <Moon size={16} />}
|
|
328
|
-
</button>
|
|
329
|
-
<span className="badge">{TABS.length - 1} modules</span>
|
|
330
|
-
<a href="/api/health" target="_blank" rel="noopener noreferrer" style={{ color: "var(--color-accent-primary)", display: "flex", alignItems: "center", gap: 4 }}>
|
|
331
|
-
<ExternalLink size={14} /> API
|
|
332
|
-
</a>
|
|
333
|
-
<a href="https://github.com/ysf-bkr/atabey" target="_blank" rel="noopener noreferrer" style={{ color: "var(--color-accent-primary)", display: "flex", alignItems: "center", gap: 4 }}>
|
|
334
|
-
<Github size={14} /> GitHub
|
|
335
|
-
</a>
|
|
336
|
-
</div>
|
|
337
|
-
</header>
|
|
338
|
-
<main className="main-content">
|
|
339
|
-
{activeTab === "dashboard" ? (
|
|
340
|
-
<DashboardOverview onNavigate={(tabId) => setActiveTab(tabId)} />
|
|
341
|
-
) : (
|
|
342
|
-
<div className="focused-view animate-fade-in">
|
|
343
|
-
{ActiveComponent && <ActiveComponent />}
|
|
344
|
-
</div>
|
|
345
|
-
)}
|
|
346
|
-
</main>
|
|
347
|
-
<footer className="main-footer">{TABS.length - 1} Modules Live · Port {window.location.port || "5858"}</footer>
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
</>
|
|
351
|
-
);
|
|
352
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
Plug,
|
|
4
|
-
Cpu,
|
|
5
|
-
Wrench,
|
|
6
|
-
Folder,
|
|
7
|
-
Edit,
|
|
8
|
-
RefreshCw,
|
|
9
|
-
Lock,
|
|
10
|
-
Check,
|
|
11
|
-
Search,
|
|
12
|
-
Brain
|
|
13
|
-
} from "lucide-react";
|
|
14
|
-
|
|
15
|
-
interface AdapterSkillSummary {
|
|
16
|
-
id: string;
|
|
17
|
-
skillCount: number;
|
|
18
|
-
toolsCount: number;
|
|
19
|
-
skills: string[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function AdapterSkillsPanel() {
|
|
23
|
-
const [adapters, setAdapters] = useState<AdapterSkillSummary[]>([]);
|
|
24
|
-
const [loading, setLoading] = useState(true);
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
const fetchAdapters = () => {
|
|
28
|
-
fetch("/api/adapters/skills")
|
|
29
|
-
.then(r => r.json())
|
|
30
|
-
.then(d => {
|
|
31
|
-
if (d.success) setAdapters(d.data);
|
|
32
|
-
setLoading(false);
|
|
33
|
-
})
|
|
34
|
-
.catch(() => setLoading(false));
|
|
35
|
-
};
|
|
36
|
-
fetchAdapters();
|
|
37
|
-
const interval = setInterval(fetchAdapters, 15000);
|
|
38
|
-
return () => clearInterval(interval);
|
|
39
|
-
}, []);
|
|
40
|
-
|
|
41
|
-
const SKILL_ICONS: Record<string, React.ComponentType<{ size?: number; style?: React.CSSProperties }>> = {
|
|
42
|
-
file_system: Folder,
|
|
43
|
-
editing: Edit,
|
|
44
|
-
orchestration: RefreshCw,
|
|
45
|
-
governance: Lock,
|
|
46
|
-
quality: Check,
|
|
47
|
-
search: Search,
|
|
48
|
-
memory: Brain,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<div className="card">
|
|
53
|
-
<div className="card-header">
|
|
54
|
-
<h2>
|
|
55
|
-
<Plug size={20} style={{ display: "inline-block", verticalAlign: "middle", marginRight: 8 }} />
|
|
56
|
-
Adapter Skills
|
|
57
|
-
</h2>
|
|
58
|
-
{!loading && <span className="badge">{adapters.length} adapters</span>}
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
{loading && <div className="empty-state">Loading adapter skills...</div>}
|
|
62
|
-
|
|
63
|
-
{!loading && (
|
|
64
|
-
<div className="adapter-list">
|
|
65
|
-
{adapters.map(adapter => {
|
|
66
|
-
return (
|
|
67
|
-
<div key={adapter.id} className="adapter-item">
|
|
68
|
-
<div className="adapter-header">
|
|
69
|
-
<span className="adapter-name">
|
|
70
|
-
<Cpu size={14} style={{ display: "inline-block", verticalAlign: "middle", marginRight: 6 }} />
|
|
71
|
-
{adapter.id}
|
|
72
|
-
</span>
|
|
73
|
-
<span className="adapter-meta">
|
|
74
|
-
<Wrench size={12} style={{ display: "inline-block", verticalAlign: "middle", marginRight: 4 }} />
|
|
75
|
-
{adapter.toolsCount} tools · {adapter.skillCount} skills
|
|
76
|
-
</span>
|
|
77
|
-
</div>
|
|
78
|
-
<div className="adapter-skills-grid">
|
|
79
|
-
{adapter.skills.map(skill => {
|
|
80
|
-
const IconComp = SKILL_ICONS[skill];
|
|
81
|
-
return (
|
|
82
|
-
<span key={skill} className="skill-badge" style={{ display: "inline-flex", alignItems: "center", gap: "4px" }}>
|
|
83
|
-
{IconComp ? (
|
|
84
|
-
<IconComp size={12} />
|
|
85
|
-
) : (
|
|
86
|
-
<span style={{ fontSize: "10px" }}>•</span>
|
|
87
|
-
)}
|
|
88
|
-
{skill.replace(/_/g, " ")}
|
|
89
|
-
</span>
|
|
90
|
-
);
|
|
91
|
-
})}
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
);
|
|
95
|
-
})}
|
|
96
|
-
</div>
|
|
97
|
-
)}
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Bot, ChevronDown, ChevronUp } from "lucide-react";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { useApi } from "../hooks/useApi";
|
|
4
|
-
import { useWS } from "../hooks/useWS";
|
|
5
|
-
|
|
6
|
-
interface Agent {
|
|
7
|
-
name: string; state: string; task: string; last_updated: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const ALL_AGENT_NAMES = [
|
|
11
|
-
"manager",
|
|
12
|
-
"security",
|
|
13
|
-
"architect",
|
|
14
|
-
"backend",
|
|
15
|
-
"frontend",
|
|
16
|
-
"quality",
|
|
17
|
-
"database",
|
|
18
|
-
"analyst",
|
|
19
|
-
"mobile",
|
|
20
|
-
"native",
|
|
21
|
-
"devops",
|
|
22
|
-
"explorer",
|
|
23
|
-
"git"
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
export function AgentMonitor() {
|
|
27
|
-
const { data: initial, loading, error } = useApi<Agent[]>("/agents", 5000);
|
|
28
|
-
const [agents, setAgents] = useState<Agent[]>([]);
|
|
29
|
-
const [expanded, setExpanded] = useState<string | null>(null);
|
|
30
|
-
|
|
31
|
-
useWS({ handlers: { agent_update: (d) => {
|
|
32
|
-
const u = d as unknown as Agent;
|
|
33
|
-
if (u.name) setAgents(prev => {
|
|
34
|
-
const cleanName = u.name.replace("@", "");
|
|
35
|
-
const exists = prev.some(a => a.name.replace("@", "") === cleanName);
|
|
36
|
-
if (exists) {
|
|
37
|
-
return prev.map(a => a.name.replace("@", "") === cleanName ? { ...a, ...u } : a);
|
|
38
|
-
}
|
|
39
|
-
return [...prev, u];
|
|
40
|
-
});
|
|
41
|
-
}}});
|
|
42
|
-
|
|
43
|
-
const rawList = agents.length ? agents : (Array.isArray(initial) ? initial : []);
|
|
44
|
-
if (Array.isArray(initial) && agents.length === 0 && initial.length > 0) setAgents(initial);
|
|
45
|
-
|
|
46
|
-
// Merge database state with the full list of 13 corporate agents
|
|
47
|
-
const list = ALL_AGENT_NAMES.map(name => {
|
|
48
|
-
const existing = rawList.find(a => a.name.replace("@", "") === name);
|
|
49
|
-
if (existing) {
|
|
50
|
-
return {
|
|
51
|
-
...existing,
|
|
52
|
-
name: name
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
return {
|
|
56
|
-
name: name,
|
|
57
|
-
state: "READY",
|
|
58
|
-
task: "Idle",
|
|
59
|
-
last_updated: new Date().toISOString()
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (loading && !rawList.length) return <div className="card"><div className="card-header"><h2><Bot size={20} /> Governed Specialist Monitor</h2></div><div className="empty-state">Loading specialists...</div></div>;
|
|
64
|
-
if (error && !rawList.length) return <div className="card"><div className="card-header"><h2><Bot size={20} /> Governed Specialist Monitor</h2></div><div className="error">Error: {error}</div></div>;
|
|
65
|
-
|
|
66
|
-
return <div className="card">
|
|
67
|
-
<div className="card-header">
|
|
68
|
-
<h2><Bot size={20} /> Specialist Monitor</h2>
|
|
69
|
-
<span className="badge">{list.length} specialists</span>
|
|
70
|
-
</div>
|
|
71
|
-
<div className="agent-list-container">
|
|
72
|
-
<div className="agent-grid">
|
|
73
|
-
{list.map(a => {
|
|
74
|
-
const open = expanded === a.name;
|
|
75
|
-
const statusClass = a.state.toLowerCase();
|
|
76
|
-
return <div key={a.name} className={`agent-card ${open ? "expanded" : ""}`} onClick={() => setExpanded(open ? null : a.name)}>
|
|
77
|
-
<div className="agent-header">
|
|
78
|
-
<span className={`agent-dot ${statusClass}`} />
|
|
79
|
-
<span className="agent-name">@{a.name}</span>
|
|
80
|
-
<span className={`agent-state ${statusClass}`}>{a.state}</span>
|
|
81
|
-
{open ? <ChevronUp size={14} className="text-muted" /> : <ChevronDown size={14} className="text-muted" />}
|
|
82
|
-
</div>
|
|
83
|
-
<div className="detail-row"><span className="detail-label">Task:</span><span className="detail-value">{a.task || "Idle"}</span></div>
|
|
84
|
-
{open && <div className="detail-row"><span className="detail-label">Updated:</span><span className="detail-value">{new Date(a.last_updated).toLocaleString()}</span></div>}
|
|
85
|
-
</div>;
|
|
86
|
-
})}
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
</div>;
|
|
90
|
-
}
|