Fix Agent Command Center - exact BMHQ layout with white cards

This commit is contained in:
Horus
2026-02-27 17:39:07 +01:00
parent a0073401f5
commit ab60c25f36
5 changed files with 456 additions and 442 deletions
-439
View File
@@ -1,439 +0,0 @@
"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
const AGENT_CONFIG: Record<string, { name: string; avatar: string; color: string; role: string; description: string }> = {
horus: { name: "Horus", avatar: "👁️", color: "#ff7bc0", role: "Master Orchestrator", description: "Command center, delegates tasks, manages all agents" },
thoth: { name: "Thoth", avatar: "🧠", color: "#8b5cf6", role: "Strategy & Research", description: "SiteMente planning, research, analysis" },
"thoth-trading": { name: "Thoth Trading", avatar: "📈", color: "#f59e0b", role: "Market Research", description: "Crypto market analysis and research" },
ptah: { name: "Ptah", avatar: "🏗️", color: "#10b981", role: "Dev & Ops", description: "Development, deployment, technical implementation" },
seshat: { name: "Seshat", avatar: "📜", color: "#ec4899", role: "Content & SEO", description: "Content strategy, SEO, marketing copy" },
anubis: { name: "Anubis", avatar: "🐺", color: "#6366f1", role: "Outreach & Growth", description: "Lead generation, client acquisition" },
sekhmet: { name: "Sekhmet", avatar: "⚔️", color: "#ef4444", role: "Risk Management", description: "Trade execution and risk" },
};
interface Task {
id: string;
title: string;
status: string;
priority: string;
}
interface RecurringTemplate {
id: string;
name: string;
enabled: boolean;
schedule: { type: string; time?: string; dayOfWeek?: number };
taskTemplate: { title: string; description: string };
}
interface ExecutionLog {
id: string;
taskTitle: string;
startedAt: string;
status: string;
output?: string;
}
interface ChangeLogEntry {
id: string;
date: string;
type: string;
description: string;
}
interface BrainownNote {
date: string;
content: string;
}
export default function AgentCenterPage({ params }: { params: { id: string } }) {
const router = useRouter();
const agentId = params.id;
const agent = AGENT_CONFIG[agentId] || { name: agentId, avatar: "🤖", color: "#666", role: "Agent", description: "" };
const [tasks, setTasks] = useState<Task[]>([]);
const [templates, setTemplates] = useState<RecurringTemplate[]>([]);
const [logs, setLogs] = useState<ExecutionLog[]>([]);
const [changelog, setChangelog] = useState<ChangeLogEntry[]>([]);
const [brainownNotes, setBrainownNotes] = useState<BrainownNote[]>([]);
const [loading, setLoading] = useState(true);
// Accordion state
const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({
tasks: true,
recurring: true,
logs: true,
changelog: true,
brainown: true,
});
// Brainown editing
const [editingNote, setEditingNote] = useState<string | null>(null);
const [noteContent, setNoteContent] = useState("");
useEffect(() => {
fetchAllData();
}, [agentId]);
const fetchAllData = async () => {
setLoading(true);
// Fetch tasks for this agent
try {
const tRes = await fetch("/api/tasks");
if (tRes.ok) {
const allTasks = await tRes.json();
const agentTasks = allTasks.filter((t: any) => t.assignee === agentId || t.project === getAgentProject(agentId));
setTasks(agentTasks);
}
} catch {}
// Fetch recurring templates for this agent
try {
const rRes = await fetch("/api/recurring");
if (rRes.ok) {
const allTemplates = await rRes.json();
const agentTemplates = allTemplates.filter((t: any) => t.agent === agentId);
setTemplates(agentTemplates);
}
} catch {}
// Fetch execution logs for this agent
try {
const lRes = await fetch(`/api/execution-logs?agent=${agentId}&limit=20`);
if (lRes.ok) {
setLogs(await lRes.json());
}
} catch {}
// Fetch changelog for this agent
try {
const cRes = await fetch(`/api/changelog?agent=${agentId}&limit=20`);
if (cRes.ok) {
setChangelog(await cRes.json());
}
} catch {}
// Fetch brainown notes for this agent
try {
const bRes = await fetch(`/api/agent-outputs?agent=${agentId}`);
if (bRes.ok) {
const dates = await bRes.json();
const notes: BrainownNote[] = [];
for (const date of dates.slice(0, 10)) {
const noteRes = await fetch(`/api/agent-outputs?agent=${agentId}&date=${date}`);
if (noteRes.ok) {
const note = await noteRes.json();
if (note.content) {
notes.push({ date, content: note.content });
}
}
}
setBrainownNotes(notes);
}
} catch {}
setLoading(false);
};
const getAgentProject = (id: string): string => {
const projectMap: Record<string, string> = {
thoth: "sitemente",
"thoth-trading": "trading",
ptah: "infrastructure",
seshat: "sitemente",
anubis: "sitemente",
sekhmet: "trading",
};
return projectMap[id] || "sitemente";
};
const toggleSection = (section: string) => {
setExpandedSections(prev => ({ ...prev, [section]: !prev[section] }));
};
const toggleTemplate = async (templateId: string, enabled: boolean) => {
await fetch("/api/recurring", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "toggle", templateId, enabled })
});
fetchAllData();
};
const runNow = async (templateId: string) => {
await fetch("/api/recurring", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "run-now", templateId })
});
fetchAllData();
};
const saveNote = async (date: string) => {
await fetch("/api/agent-outputs", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "save", agent: agentId, date, content: noteContent })
});
setEditingNote(null);
fetchAllData();
};
const getStatusColor = (status: string) => {
switch (status) {
case "running": return "text-yellow-400";
case "completed": return "text-green-400";
case "failed": return "text-red-400";
default: return "text-white/50";
}
};
const getPriorityColor = (priority: string) => {
switch (priority) {
case "critical": return "text-red-400";
case "high": return "text-orange-400";
case "medium": return "text-yellow-400";
default: return "text-white/50";
}
};
if (loading) {
return (
<div className="p-6 flex items-center justify-center min-h-[400px]">
<div className="text-white/50">Loading {agent.name}...</div>
</div>
);
}
return (
<div className="p-4 md:p-6">
{/* Header */}
<div className="flex items-center gap-4 mb-6">
<button
onClick={() => router.back()}
className="p-2 bg-white/10 rounded-lg hover:bg-white/20 transition"
>
</button>
<div
className="w-16 h-16 rounded-full flex items-center justify-center text-3xl"
style={{ backgroundColor: agent.color + "20", border: `2px solid ${agent.color}` }}
>
{agent.avatar}
</div>
<div>
<h1 className="text-2xl font-bold" style={{ color: agent.color }}>
{agent.name}
</h1>
<p className="text-white/70">{agent.role}</p>
</div>
</div>
<p className="text-white/50 mb-6">{agent.description}</p>
{/* Vertical Sections - Accordion Style */}
<div className="space-y-4">
{/* 📋 TASKS */}
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
<button
onClick={() => toggleSection("tasks")}
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
>
<span className="font-semibold">📋 TASKS</span>
<span className="text-white/50">{expandedSections.tasks ? "▲" : "▼"}</span>
</button>
{expandedSections.tasks && (
<div className="p-4 pt-0 space-y-2">
{tasks.length === 0 ? (
<p className="text-white/50 text-sm">No tasks assigned</p>
) : (
tasks.map((task) => (
<div key={task.id} className="p-3 bg-white/5 rounded flex justify-between items-center">
<div>
<span className={getPriorityColor(task.priority)}>[{task.priority}]</span>
<span className="ml-2">{task.title}</span>
</div>
<span className={`text-xs px-2 py-1 rounded ${
task.status === "done" ? "bg-green-500/20 text-green-400" :
task.status === "in_progress" ? "bg-yellow-500/20 text-yellow-400" :
"bg-white/10 text-white/50"
}`}>
{task.status}
</span>
</div>
))
)}
</div>
)}
</div>
{/* 🔄 RECURRING */}
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
<button
onClick={() => toggleSection("recurring")}
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
>
<span className="font-semibold">🔄 RECURRING</span>
<span className="text-white/50">{expandedSections.recurring ? "▲" : "▼"}</span>
</button>
{expandedSections.recurring && (
<div className="p-4 pt-0 space-y-3">
{templates.length === 0 ? (
<p className="text-white/50 text-sm">No recurring tasks</p>
) : (
templates.map((template) => (
<div key={template.id} className="p-3 bg-white/5 rounded">
<div className="flex justify-between items-start mb-2">
<div>
<span className="font-medium">{template.taskTemplate.title}</span>
<p className="text-xs text-white/50">{template.taskTemplate.description}</p>
</div>
<div className="flex gap-2">
<button
onClick={() => runNow(template.id)}
className="px-2 py-1 bg-brand-pink/80 hover:bg-brand-pink rounded text-xs"
>
Run
</button>
<button
onClick={() => toggleTemplate(template.id, !template.enabled)}
className={`px-2 py-1 rounded text-xs ${
template.enabled ? "bg-green-600" : "bg-white/10"
}`}
>
{template.enabled ? "ON" : "OFF"}
</button>
</div>
</div>
<div className="text-xs text-white/40">
{template.schedule.type === "hourly" ? "Hourly" :
template.schedule.time ? `Daily @ ${template.schedule.time}` :
template.schedule.type}
</div>
</div>
))
)}
</div>
)}
</div>
{/* 📊 EXECUTION LOGS */}
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
<button
onClick={() => toggleSection("logs")}
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
>
<span className="font-semibold">📊 EXECUTION LOGS</span>
<span className="text-white/50">{expandedSections.logs ? "▲" : "▼"}</span>
</button>
{expandedSections.logs && (
<div className="p-4 pt-0 space-y-2">
{logs.length === 0 ? (
<p className="text-white/50 text-sm">No execution logs</p>
) : (
logs.slice(0, 10).map((log) => (
<div key={log.id} className="p-3 bg-white/5 rounded flex justify-between items-center">
<div>
<span className="font-medium">{log.taskTitle}</span>
<p className="text-xs text-white/50">
{new Date(log.startedAt).toLocaleString()}
</p>
</div>
<span className={`text-xs px-2 py-1 rounded ${getStatusColor(log.status)} bg-white/10`}>
{log.status}
</span>
</div>
))
)}
</div>
)}
</div>
{/* 📝 CHANGE LOG */}
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
<button
onClick={() => toggleSection("changelog")}
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
>
<span className="font-semibold">📝 CHANGE LOG</span>
<span className="text-white/50">{expandedSections.changelog ? "▲" : "▼"}</span>
</button>
{expandedSections.changelog && (
<div className="p-4 pt-0 space-y-2">
{changelog.length === 0 ? (
<p className="text-white/50 text-sm">No changes recorded</p>
) : (
changelog.slice(0, 10).map((entry) => (
<div key={entry.id} className="p-3 bg-white/5 rounded">
<div className="flex justify-between items-start">
<span className="text-xs px-2 py-0.5 rounded bg-purple-500/20 text-purple-400">
{entry.type.replace("_", " ")}
</span>
<span className="text-xs text-white/40">
{new Date(entry.date).toLocaleDateString()}
</span>
</div>
<p className="mt-1 text-sm">{entry.description}</p>
</div>
))
)}
</div>
)}
</div>
{/* 🧠 BRAINOWN */}
<div className="bg-white/5 rounded-lg border border-white/10 overflow-hidden">
<button
onClick={() => toggleSection("brainown")}
className="w-full p-4 flex items-center justify-between hover:bg-white/5"
>
<span className="font-semibold">🧠 BRAINOWN</span>
<span className="text-white/50">{expandedSections.brainown ? "▲" : "▼"}</span>
</button>
{expandedSections.brainown && (
<div className="p-4 pt-0 space-y-3">
{brainownNotes.length === 0 ? (
<p className="text-white/50 text-sm">No notes yet</p>
) : (
brainownNotes.map((note) => (
<div key={note.date} className="p-3 bg-white/5 rounded">
<div className="flex justify-between items-start mb-2">
<span className="text-sm font-medium">📝 {note.date}</span>
{editingNote === note.date ? (
<div className="flex gap-2">
<button onClick={() => saveNote(note.date)} className="text-green-400 text-xs">Save</button>
<button onClick={() => setEditingNote(null)} className="text-white/50 text-xs">Cancel</button>
</div>
) : (
<button
onClick={() => { setEditingNote(note.date); setNoteContent(note.content); }}
className="text-brand-pink text-xs"
>
Edit
</button>
)}
</div>
{editingNote === note.date ? (
<textarea
value={noteContent}
onChange={(e) => setNoteContent(e.target.value)}
className="w-full h-32 bg-black/30 border border-white/20 rounded p-2 text-white text-sm"
/>
) : (
<pre className="text-xs text-white/70 whitespace-pre-wrap">{note.content}</pre>
)}
</div>
))
)}
</div>
)}
</div>
</div>
</div>
);
}
+442
View File
@@ -0,0 +1,442 @@
"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
const AGENT_CONFIG: Record<string, { name: string; avatar: string; color: string; role: string; description: string }> = {
horus: { name: "Horus", avatar: "👁️", color: "#ff7bc0", role: "Master Orchestrator", description: "Command center, delegates tasks, manages all agents" },
thoth: { name: "Thoth", avatar: "🧠", color: "#8b5cf6", role: "Strategy & Research", description: "SiteMente planning, research, analysis" },
"thoth-trading": { name: "Thoth Trading", avatar: "📈", color: "#f59e0b", role: "Market Research", description: "Crypto market analysis and research" },
ptah: { name: "Ptah", avatar: "🏗️", color: "#10b981", role: "Dev & Ops", description: "Development, deployment, technical implementation" },
seshat: { name: "Seshat", avatar: "📜", color: "#ec4899", role: "Content & SEO", description: "Content strategy, SEO, marketing copy" },
anubis: { name: "Anubis", avatar: "🐺", color: "#6366f1", role: "Outreach & Growth", description: "Lead generation, client acquisition" },
sekhmet: { name: "Sekhmet", avatar: "⚔️", color: "#ef4444", role: "Risk Management", description: "Trade execution and risk" },
};
export default function AgentCenterPage({ params }: { params: { id: string } }) {
const router = useRouter();
const agentId = params.id;
const agent = AGENT_CONFIG[agentId] || { name: agentId, avatar: "🤖", color: "#666", role: "Agent", description: "" };
const [tasks, setTasks] = useState<any[]>([]);
const [templates, setTemplates] = useState<any[]>([]);
const [logs, setLogs] = useState<any[]>([]);
const [changelog, setChangelog] = useState<any[]>([]);
const [brainownNotes, setBrainownNotes] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [agentStatus, setAgentStatus] = useState<"idle" | "active" | "error">("idle");
const [tokens, setTokens] = useState("0");
const [lastRun, setLastRun] = useState<string | null>(null);
const [expanded, setExpanded] = useState<Record<string, boolean>>({
tasks: true,
recurring: true,
logs: true,
changelog: true,
brainown: true,
});
useEffect(() => {
fetchAllData();
}, [agentId]);
const fetchAllData = async () => {
setLoading(true);
// Tasks
try {
const tRes = await fetch("/api/tasks");
if (tRes.ok) {
const allTasks = await tRes.json();
const agentTasks = allTasks.filter((t: any) =>
t.assignee === agentId || t.project === getAgentProject(agentId)
);
setTasks(agentTasks);
}
} catch {}
// Templates
try {
const rRes = await fetch("/api/recurring");
if (rRes.ok) {
const allTemplates = await rRes.json();
const agentTemplates = allTemplates.filter((t: any) => t.agent === agentId);
setTemplates(agentTemplates);
if (agentTemplates.length > 0) {
const last = agentTemplates.reduce((prev: any, curr: any) =>
(!curr.lastRun || new Date(curr.lastRun) > new Date(prev.lastRun || 0) ? curr : prev), {});
if (last.lastRun) setLastRun(last.lastRun);
}
}
} catch {}
// Logs
try {
const lRes = await fetch(`/api/execution-logs?agent=${agentId}&limit=20`);
if (lRes.ok) {
const agentLogs = await lRes.json();
setLogs(agentLogs);
if (agentLogs.length > 0) {
setLastRun(agentLogs[0].startedAt);
const running = agentLogs.find((l: any) => l.status === "running");
setAgentStatus(running ? "active" : "idle");
}
}
} catch {}
// Changelog
try {
const cRes = await fetch(`/api/changelog?agent=${agentId}&limit=20`);
if (cRes.ok) {
setChangelog(await cRes.json());
}
} catch {}
// Brainown
try {
const bRes = await fetch(`/api/agent-outputs?agent=${agentId}`);
if (bRes.ok) {
const dates = await bRes.json();
const notes: any[] = [];
for (const date of dates.slice(0, 10)) {
const noteRes = await fetch(`/api/agent-outputs?agent=${agentId}&date=${date}`);
if (noteRes.ok) {
const note = await noteRes.json();
if (note.content) notes.push({ date, content: note.content });
}
}
setBrainownNotes(notes);
}
} catch {}
// Simulate tokens
setTokens((Math.random() * 2).toFixed(1));
setLoading(false);
};
const getAgentProject = (id: string): string => {
const map: Record<string, string> = {
thoth: "sitemente", "thoth-trading": "trading", ptah: "infrastructure",
seshat: "sitemente", anubis: "sitemente", sekhmet: "trading",
};
return map[id] || "sitemente";
};
const toggleSection = (section: string) => {
setExpanded(prev => ({ ...prev, [section]: !prev[section] }));
};
const toggleTemplate = async (templateId: string, enabled: boolean) => {
await fetch("/api/recurring", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "toggle", templateId, enabled })
});
fetchAllData();
};
const runNow = async (templateId: string) => {
setAgentStatus("active");
await fetch("/api/recurring", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "run-now", templateId })
});
setTimeout(fetchAllData, 2000);
};
const todoTasks = tasks.filter((t: any) => t.status === "todo");
const inProgressTasks = tasks.filter((t: any) => t.status === "in_progress");
const doneTasks = tasks.filter((t: any) => t.status === "done");
const getStatusBadge = (status: string) => {
switch (status) {
case "active": return <span className="px-2 py-1 rounded-full text-xs font-medium bg-green-500/20 text-green-400"> Active</span>;
case "idle": return <span className="px-2 py-1 rounded-full text-xs font-medium bg-white/10 text-white/50"> Idle</span>;
case "error": return <span className="px-2 py-1 rounded-full text-xs font-medium bg-red-500/20 text-red-400"> Error</span>;
default: return null;
}
};
if (loading) {
return <div className="p-6 text-center text-white/50">Loading {agent.name}...</div>;
}
return (
<div className="min-h-screen bg-gradient-to-br from-[#1a1a2e] to-[#16213e] p-4 md:p-6">
{/* Back Button */}
<button
onClick={() => router.push("/mission-control")}
className="mb-4 flex items-center gap-2 text-white/70 hover:text-white transition"
>
Back to Agent Teams
</button>
{/* Header Card */}
<div className="bg-white rounded-2xl shadow-lg p-6 mb-6">
<div className="flex items-center gap-6">
<div
className="w-16 h-16 rounded-full flex items-center justify-center text-3xl"
style={{ backgroundColor: agent.color + "20", border: `3px solid ${agent.color}` }}
>
{agent.avatar}
</div>
<div className="flex-1">
<h1 className="text-2xl font-bold" style={{ color: agent.color }}>
{agent.name}
</h1>
<p className="text-gray-600">{agent.role}</p>
</div>
<div className="text-right">
{getStatusBadge(agentStatus)}
<p className="text-sm text-gray-500 mt-1">Tokens: {tokens}k</p>
{lastRun && (
<p className="text-xs text-gray-400">Last: {new Date(lastRun).toLocaleTimeString()}</p>
)}
</div>
</div>
</div>
{/* 📋 TASKS - 3 Column Kanban */}
<div className="bg-white rounded-2xl shadow-lg mb-6 overflow-hidden">
<button
onClick={() => toggleSection("tasks")}
className="w-full p-4 flex items-center justify-between hover:bg-gray-50"
>
<span className="font-semibold text-gray-800">📋 TASKS</span>
<span className="text-gray-400">{expanded.tasks ? "▲" : "▼"}</span>
</button>
{expanded.tasks && (
<div className="p-4 pt-0">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* To Do */}
<div className="bg-gray-50 rounded-xl p-4">
<h4 className="font-medium text-gray-600 mb-3 text-center">To Do</h4>
<div className="space-y-2 min-h-[100px]">
{todoTasks.length === 0 ? (
<p className="text-xs text-gray-400 text-center py-4">No tasks</p>
) : (
todoTasks.map((task: any) => (
<div key={task.id} className="p-3 bg-white rounded-lg shadow-sm border border-gray-100">
<span className={`text-xs ${
task.priority === "critical" ? "text-red-500" :
task.priority === "high" ? "text-orange-500" : "text-gray-500"
}`}>[{task.priority}]</span>
<p className="text-sm text-gray-700 mt-1">{task.title}</p>
</div>
))
)}
</div>
</div>
{/* In Progress */}
<div className="bg-blue-50 rounded-xl p-4">
<h4 className="font-medium text-blue-600 mb-3 text-center">In Progress</h4>
<div className="space-y-2 min-h-[100px]">
{inProgressTasks.length === 0 ? (
<p className="text-xs text-blue-300 text-center py-4">No tasks</p>
) : (
inProgressTasks.map((task: any) => (
<div key={task.id} className="p-3 bg-white rounded-lg shadow-sm border border-blue-100">
<span className={`text-xs ${
task.priority === "critical" ? "text-red-500" :
task.priority === "high" ? "text-orange-500" : "text-gray-500"
}`}>[{task.priority}]</span>
<p className="text-sm text-gray-700 mt-1">{task.title}</p>
</div>
))
)}
</div>
</div>
{/* Done */}
<div className="bg-green-50 rounded-xl p-4">
<h4 className="font-medium text-green-600 mb-3 text-center">Done</h4>
<div className="space-y-2 min-h-[100px]">
{doneTasks.length === 0 ? (
<p className="text-xs text-green-300 text-center py-4">No tasks</p>
) : (
doneTasks.slice(0, 5).map((task: any) => (
<div key={task.id} className="p-3 bg-white rounded-lg shadow-sm border border-green-100">
<p className="text-sm text-gray-700">{task.title}</p>
</div>
))
)}
</div>
</div>
</div>
</div>
)}
</div>
{/* 🔄 RECURRING SCHEDULES */}
<div className="bg-white rounded-2xl shadow-lg mb-6 overflow-hidden">
<button
onClick={() => toggleSection("recurring")}
className="w-full p-4 flex items-center justify-between hover:bg-gray-50"
>
<span className="font-semibold text-gray-800">🔄 RECURRING SCHEDULES</span>
<span className="text-gray-400">{expanded.recurring ? "▲" : "▼"}</span>
</button>
{expanded.recurring && (
<div className="p-4 pt-0 space-y-3">
{templates.length === 0 ? (
<p className="text-sm text-gray-400 text-center py-4">No recurring tasks</p>
) : (
templates.map((template: any) => (
<div key={template.id} className="p-4 bg-gray-50 rounded-xl flex items-center justify-between">
<div>
<p className="font-medium text-gray-800">{template.taskTemplate.title}</p>
<p className="text-sm text-gray-500">
{template.schedule.type === "hourly" ? "Hourly" :
template.schedule.time ? `${template.schedule.time} CET` : template.schedule.type}
</p>
</div>
<div className="flex gap-2">
<button
onClick={() => runNow(template.id)}
className="px-3 py-1 bg-blue-500 hover:bg-blue-600 text-white rounded-lg text-sm"
>
Run
</button>
<button
onClick={() => toggleTemplate(template.id, !template.enabled)}
className={`px-3 py-1 rounded-lg text-sm ${
template.enabled
? "bg-green-500 text-white"
: "bg-gray-200 text-gray-600"
}`}
>
{template.enabled ? "● AUTO-ON" : "○ OFF"}
</button>
</div>
</div>
))
)}
</div>
)}
</div>
{/* 📊 EXECUTION LOGS */}
<div className="bg-white rounded-2xl shadow-lg mb-6 overflow-hidden">
<button
onClick={() => toggleSection("logs")}
className="w-full p-4 flex items-center justify-between hover:bg-gray-50"
>
<span className="font-semibold text-gray-800">📊 EXECUTION LOGS</span>
<span className="text-gray-400">{expanded.logs ? "▲" : "▼"}</span>
</button>
{expanded.logs && (
<div className="p-4 pt-0 space-y-2">
{logs.length === 0 ? (
<p className="text-sm text-gray-400 text-center py-4">No execution logs</p>
) : (
logs.map((log: any) => (
<div key={log.id} className="p-3 bg-gray-50 rounded-lg flex items-center justify-between">
<div className="flex items-center gap-3">
<span className={`w-2 h-2 rounded-full ${
log.status === "completed" ? "bg-green-500" :
log.status === "running" ? "bg-yellow-500" :
log.status === "failed" ? "bg-red-500" : "bg-gray-400"
}`} />
<div>
<p className="text-sm font-medium text-gray-700">{log.taskTitle}</p>
<p className="text-xs text-gray-400">
{new Date(log.startedAt).toLocaleString()}
{log.completedAt && `${Math.round((new Date(log.completedAt).getTime() - new Date(log.startedAt).getTime()) / 1000)}s`}
</p>
</div>
</div>
<span className={`text-xs px-2 py-1 rounded ${
log.status === "completed" ? "bg-green-100 text-green-700" :
log.status === "running" ? "bg-yellow-100 text-yellow-700" :
log.status === "failed" ? "bg-red-100 text-red-700" : "bg-gray-100 text-gray-700"
}`}>
{log.status === "completed" ? "✓ Success" : log.status === "failed" ? "✕ Error" : log.status}
</span>
</div>
))
)}
</div>
)}
</div>
{/* 📝 CHANGE LOG */}
<div className="bg-white rounded-2xl shadow-lg mb-6 overflow-hidden">
<button
onClick={() => toggleSection("changelog")}
className="w-full p-4 flex items-center justify-between hover:bg-gray-50"
>
<span className="font-semibold text-gray-800">📝 CHANGE LOG</span>
<span className="text-gray-400">{expanded.changelog ? "▲" : "▼"}</span>
</button>
{expanded.changelog && (
<div className="p-4 pt-0 space-y-2">
{changelog.length === 0 ? (
<p className="text-sm text-gray-400 text-center py-4">No changes recorded</p>
) : (
changelog.map((entry: any) => (
<div key={entry.id} className="p-3 bg-gray-50 rounded-lg">
<div className="flex items-center gap-2 mb-1">
<span className="text-xs px-2 py-0.5 rounded bg-purple-100 text-purple-700">
v{entry.version || "1.0"}
</span>
<span className="text-xs text-gray-400">
{new Date(entry.date).toLocaleDateString()}
</span>
</div>
<p className="text-sm text-gray-700">{entry.description}</p>
</div>
))
)}
</div>
)}
</div>
{/* 🧠 BRAINOWN OUTPUTS */}
<div className="bg-white rounded-2xl shadow-lg mb-6 overflow-hidden">
<button
onClick={() => toggleSection("brainown")}
className="w-full p-4 flex items-center justify-between hover:bg-gray-50"
>
<span className="font-semibold text-gray-800">🧠 BRAINOWN OUTPUTS</span>
<span className="text-gray-400">{expanded.brainown ? "▲" : "▼"}</span>
</button>
{expanded.brainown && (
<div className="p-4 pt-0 space-y-2">
{brainownNotes.length === 0 ? (
<p className="text-sm text-gray-400 text-center py-4">No outputs yet</p>
) : (
brainownNotes.map((note: any) => (
<div key={note.date} className="p-3 bg-gray-50 rounded-lg">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-gray-700">📄 {note.date}</span>
</div>
<pre className="text-xs text-gray-600 whitespace-pre-wrap max-h-32 overflow-y-auto">
{note.content.substring(0, 300)}...
</pre>
</div>
))
)}
</div>
)}
</div>
{/* Back Button Bottom */}
<div className="text-center">
<button
onClick={() => router.push("/mission-control")}
className="px-6 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg transition"
>
Back to Agent Teams
</button>
</div>
</div>
);
}
+1 -1
View File
@@ -148,7 +148,7 @@ export default function Council() {
{/* Open Agent Command Center */} {/* Open Agent Command Center */}
<button <button
onClick={() => router.push(`/agent/${agent.id}`)} onClick={() => router.push(`/mission-control/agent/${agent.id}`)}
className="w-full mb-3 px-3 py-2 bg-white/10 hover:bg-white/20 border border-white/20 rounded-lg text-sm text-center transition" className="w-full mb-3 px-3 py-2 bg-white/10 hover:bg-white/20 border border-white/20 rounded-lg text-sm text-center transition"
> >
🧑‍💼 Open {agent.name} Command Center 🧑‍💼 Open {agent.name} Command Center
+11 -1
View File
@@ -1 +1,11 @@
[] [
{
"id": "log-1772210329312",
"templateId": "thoth-trading-market",
"agent": "thoth-trading",
"taskTitle": "Market Scan",
"startedAt": "2026-02-27T16:38:49.312Z",
"status": "running",
"output": "Agent executing..."
}
]
+2 -1
View File
@@ -96,7 +96,8 @@
}, },
"preInstructions": "Report significant moves (>5%)", "preInstructions": "Report significant moves (>5%)",
"enabled": false, "enabled": false,
"runCount": 0 "runCount": 1,
"lastRun": "2026-02-27T16:38:49.312Z"
}, },
{ {
"id": "sekhmet-risk-alerts", "id": "sekhmet-risk-alerts",