feat(mission-control): restore MC tabs - temple, office, memory, claude, pdf-viewer, resume, resume-upload, temple-3d, demos

Also added:
- Memory API endpoints
- Briefs API endpoints
- AnveVoice stats API
- Claude spawn API
- TTS proxy
- Cleopatra voice widget
- api-auth middleware
This commit is contained in:
2026-03-23 16:30:44 +01:00
parent d5575b58e3
commit 45af56d9cf
30 changed files with 5092 additions and 715 deletions
@@ -0,0 +1,546 @@
"use client";
import { useState, useEffect } from "react";
interface Agent {
id: string;
name: string;
role: string;
symbol: string;
status: "active" | "idle" | "busy" | "offline";
currentTask: string;
location: string;
templeArea: string;
tasksCompleted: number;
}
interface TempleRoom {
id: string;
name: string;
agent: Agent | null;
status: "active" | "inactive";
description: string;
}
const ANVEVOICE_API_KEY = "anvk_6a217415c671b8e613df1f0b37f72c492a91b625";
const CLEOPATRA_BOT_ID = "022ae3d3-ed11-45a9-b663-f4a6dfa34f77";
export default function TempleOfAIDashboard() {
const [activeRoom, setActiveRoom] = useState<string>("sanctuary");
const [anvevoiceStats, setAnvevoiceStats] = useState<any>(null);
const [isLoading, setIsLoading] = useState(false);
// Egyptian Agents
const agents: Agent[] = [
{ id: "horus", name: "Horus", role: "Master Orchestrator", symbol: "👁️", status: "active", currentTask: "Monitoring all systems", location: "Sanctuary", templeArea: "Head", tasksCompleted: 847 },
{ id: "cleopatra", name: "Cleopatra", role: "Voice AI / Sales", symbol: "👑", status: "active", currentTask: "Conversing with visitor", location: "Hall 2", templeArea: "Voice Lab", tasksCompleted: 234 },
{ id: "anubis", name: "Anubis", role: "Outreach / Lead Gen", symbol: "🐕", status: "busy", currentTask: "Qualifying lead #4521", location: "Entrance", templeArea: "Reception", tasksCompleted: 156 },
{ id: "thoth", name: "Thoth", role: "Research / Strategy", symbol: "🐦", status: "idle", currentTask: "Analyzing market trends", location: "Pylon 2", templeArea: "Research", tasksCompleted: 89 },
{ id: "ptah", name: "Ptah", role: "Development / Ops", symbol: "🔨", status: "active", currentTask: "Deploying SiteMente v2.1", location: "Courtyard", templeArea: "Workspace", tasksCompleted: 312 },
{ id: "seshat", name: "Seshat", role: "Content / SEO", symbol: "📝", status: "idle", currentTask: "Writing blog post", location: "Courtyard", templeArea: "Workspace", tasksCompleted: 445 },
{ id: "sekhmet", name: "Sekhmet", role: "Trading / Risk", symbol: "🦁", status: "active", currentTask: "Monitoring BTC position", location: "Courtyard", templeArea: "Trading", tasksCompleted: 67 },
{ id: "maat", name: "Maat", role: "Quality Assurance", symbol: "⚖️", status: "idle", currentTask: "Reviewing code quality", location: "Pylon 3", templeArea: "QA Lab", tasksCompleted: 198 },
];
const templeRooms: TempleRoom[] = [
{ id: "sanctuary", name: "Holy of Holies", agent: agents[0], status: "active", description: "Horus commands from the golden throne. The Eye of Providence sees all." },
{ id: "hall2", name: "Hall of Queens", agent: agents[1], status: "active", description: "Cleopatra's voice echoes through the halls. Visitors feel welcomed." },
{ id: "pylon3", name: "Pylon of Maat", agent: agents[7], status: "active", description: "The Feather of Truth guards quality standards." },
{ id: "pylon2", name: "Pylon of Thoth", agent: agents[3], status: "active", description: "Sacred knowledge flows through ibis-headed archives." },
{ id: "hypostyle", name: "Hypostyle Hall", agent: null, status: "active", description: "The great meeting hall. Columns reach to heaven." },
{ id: "courtyard", name: "Courtyard", agent: null, status: "active", description: "Ptah builds, Seshat writes, Sekhmet trades. The heart beats strong." },
{ id: "entrance", name: "Avenue of Sphinxes", agent: agents[2], status: "active", description: "Anubis greets visitors. No soul passes unseen." },
];
const getStatusColor = (status: string) => {
switch(status) {
case "active": return "bg-green-500";
case "busy": return "bg-yellow-500";
case "idle": return "bg-blue-500";
case "offline": return "bg-gray-500";
default: return "bg-gray-500";
}
};
const getStatusText = (status: string) => {
switch(status) {
case "active": return "Working";
case "busy": return "On Task";
case "idle": return "Ready";
case "offline": return "Offline";
default: return status;
}
};
useEffect(() => {
// Fetch AnveVoice stats
const fetchStats = async () => {
try {
const res = await fetch("/api/anvevoice-stats");
if (res.ok) {
const data = await res.json();
setAnvevoiceStats(data);
}
} catch (e) {
console.error("Failed to fetch AnveVoice stats");
}
};
fetchStats();
}, []);
return (
<div className="min-h-screen bg-gradient-to-br from-amber-950 via-stone-900 to-amber-950 p-6">
{/* Header */}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-amber-200 via-yellow-400 to-amber-200 mb-2">
🏛 TEMPLE OF AI
</h1>
<p className="text-amber-300/80 text-lg">
Where Ancient Wisdom Meets Machine Intelligence
</p>
<div className="flex justify-center gap-4 mt-4">
<span className="px-4 py-1 bg-amber-500/20 text-amber-300 rounded-full text-sm border border-amber-500/30">
🟢 {agents.filter(a => a.status === "active").length} Active
</span>
<span className="px-4 py-1 bg-yellow-500/20 text-yellow-300 rounded-full text-sm border border-yellow-500/30">
🟡 {agents.filter(a => a.status === "busy").length} Busy
</span>
<span className="px-4 py-1 bg-blue-500/20 text-blue-300 rounded-full text-sm border border-blue-500/30">
🔵 {agents.filter(a => a.status === "idle").length} Ready
</span>
</div>
</div>
{/* Temple Visualization */}
<div className="max-w-7xl mx-auto grid lg:grid-cols-3 gap-6">
{/* Left Column - Temple Map */}
<div className="lg:col-span-1">
<div className="bg-stone-900/80 backdrop-blur rounded-2xl border border-amber-500/20 p-6">
<h2 className="text-xl font-bold text-amber-200 mb-4 flex items-center gap-2">
🗺 Temple Map
</h2>
{/* Vertical Temple Layout */}
<div className="space-y-2">
{/* Sanctuary */}
<div
onClick={() => setActiveRoom("sanctuary")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "sanctuary"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">👁</span>
<div>
<p className="font-bold text-amber-200">HOLY OF HOLIES</p>
<p className="text-xs text-amber-400/60">{agents[0].name} - {agents[0].role}</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[0].status)} ml-auto`}></span>
</div>
</div>
{/* Hall 2 */}
<div className="flex items-center justify-center">
<div className="w-0 h-0 border-l-8 border-r-8 border-t-8 border-l-transparent border-r-transparent border-t-amber-600"></div>
</div>
<div
onClick={() => setActiveRoom("hall2")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "hall2"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">👑</span>
<div>
<p className="font-bold text-amber-200">HALL OF QUEENS</p>
<p className="text-xs text-amber-400/60">{agents[1].name} - Voice AI</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[1].status)} ml-auto`}></span>
</div>
</div>
{/* Pylon 3 */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-800 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("pylon3")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "pylon3"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl"></span>
<div>
<p className="font-bold text-amber-200">PYLON OF MAAT</p>
<p className="text-xs text-amber-400/60">{agents[7].name} - Quality</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[7].status)} ml-auto`}></span>
</div>
</div>
{/* Pylon 2 */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-800 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("pylon2")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "pylon2"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">🐦</span>
<div>
<p className="font-bold text-amber-200">PYLON OF THOTH</p>
<p className="text-xs text-amber-400/60">{agents[3].name} - Research</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[3].status)} ml-auto`}></span>
</div>
</div>
{/* Hypostyle Hall */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-700 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("hypostyle")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "hypostyle"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl"></span>
<div>
<p className="font-bold text-amber-200">HYPOSTYLE HALL</p>
<p className="text-xs text-amber-400/60">Conference - Standups</p>
</div>
<span className="w-3 h-3 rounded-full bg-green-500 ml-auto"></span>
</div>
</div>
{/* Courtyard */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-600 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("courtyard")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "courtyard"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">🏛</span>
<div>
<p className="font-bold text-amber-200">COURTYARD</p>
<p className="text-xs text-amber-400/60">Ptah 🔨 | Seshat 📝 | Sekhmet 🦁</p>
</div>
<span className="w-3 h-3 rounded-full bg-green-500 ml-auto"></span>
</div>
</div>
{/* Entrance */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-500 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("entrance")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "entrance"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">🐕</span>
<div>
<p className="font-bold text-amber-200">AVENUE OF SPHINXES</p>
<p className="text-xs text-amber-400/60">{agents[2].name} - Reception</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[2].status)} ml-auto`}></span>
</div>
</div>
</div>
</div>
</div>
{/* Center Column - Active Room Details */}
<div className="lg:col-span-1">
<div className="bg-stone-900/80 backdrop-blur rounded-2xl border border-amber-500/20 p-6">
<h2 className="text-xl font-bold text-amber-200 mb-4">
{templeRooms.find(r => r.id === activeRoom)?.name}
</h2>
<div className="space-y-4">
{activeRoom === "sanctuary" && (
<>
<div className="text-center py-8">
<span className="text-8xl">👁</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">HORUS</h3>
<p className="text-amber-300">Master Orchestrator</p>
</div>
<div className="bg-yellow-500/10 rounded-xl p-4 border border-yellow-500/30">
<p className="text-yellow-200 font-medium">🗣 Current Task:</p>
<p className="text-amber-300 mt-1">{agents[0].currentTask}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-yellow-400">847</p>
<p className="text-xs text-amber-400/60">Tasks Done</p>
</div>
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-green-400">99.9%</p>
<p className="text-xs text-amber-400/60">Uptime</p>
</div>
</div>
</>
)}
{activeRoom === "hall2" && (
<>
<div className="text-center py-8">
<span className="text-8xl">👑</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">CLEOPATRA</h3>
<p className="text-amber-300">Voice AI / Sales</p>
<div className="mt-2 inline-flex items-center gap-2 px-3 py-1 bg-green-500/20 rounded-full border border-green-500/30">
<span className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></span>
<span className="text-green-300 text-sm">Live on AnveVoice</span>
</div>
</div>
<div className="bg-purple-500/10 rounded-xl p-4 border border-purple-500/30">
<p className="text-purple-200 font-medium">🗣 Welcome Message:</p>
<p className="text-amber-300 mt-1 italic">"Hola! Soy Cleopatra, tu asistente de ventas de HostPioneers. Como puedo ayudarte hoy?"</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-purple-400">234</p>
<p className="text-xs text-amber-400/60">Conversations</p>
</div>
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-green-400">89%</p>
<p className="text-xs text-amber-400/60">Lead Capture</p>
</div>
</div>
<a
href="https://anvevoice.com/dashboard"
target="_blank"
className="block w-full py-3 bg-purple-600 hover:bg-purple-500 text-center rounded-xl font-bold text-white transition-colors"
>
📊 View AnveVoice Dashboard
</a>
</>
)}
{activeRoom === "courtyard" && (
<>
<div className="text-center py-4">
<span className="text-6xl">🏛</span>
<h3 className="text-xl font-bold text-yellow-400 mt-4">THE WORKING HEART</h3>
<p className="text-amber-300">Where the heart beats strong</p>
</div>
<div className="space-y-3">
<div className="flex items-center gap-3 bg-stone-800/50 rounded-lg p-3">
<span className="text-2xl">🔨</span>
<div className="flex-1">
<p className="font-bold text-amber-200">Ptah - Dev/Ops</p>
<p className="text-xs text-amber-400/60">{agents[5].currentTask}</p>
</div>
<span className={`w-2 h-2 rounded-full ${getStatusColor(agents[5].status)}`}></span>
</div>
<div className="flex items-center gap-3 bg-stone-800/50 rounded-lg p-3">
<span className="text-2xl">📝</span>
<div className="flex-1">
<p className="font-bold text-amber-200">Seshat - Content</p>
<p className="text-xs text-amber-400/60">{agents[6].currentTask}</p>
</div>
<span className={`w-2 h-2 rounded-full ${getStatusColor(agents[6].status)}`}></span>
</div>
<div className="flex items-center gap-3 bg-stone-800/50 rounded-lg p-3">
<span className="text-2xl">🦁</span>
<div className="flex-1">
<p className="font-bold text-amber-200">Sekhmet - Trading</p>
<p className="text-xs text-amber-400/60">{agents[7].currentTask}</p>
</div>
<span className={`w-2 h-2 rounded-full ${getStatusColor(agents[7].status)}`}></span>
</div>
</div>
</>
)}
{activeRoom === "hypostyle" && (
<>
<div className="text-center py-8">
<span className="text-8xl"></span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">MEETING HALL</h3>
<p className="text-amber-300">Where decisions are made</p>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">📅 Next Standup</h4>
<div className="flex items-center gap-3">
<span className="text-2xl"></span>
<div>
<p className="text-white font-medium">9:00 AM - Daily Standup</p>
<p className="text-amber-400/60 text-sm">All agents gather</p>
</div>
</div>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">📋 Sprint Status</h4>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-amber-300">Progress</span>
<span className="text-green-400">72%</span>
</div>
<div className="w-full bg-stone-700 rounded-full h-2">
<div className="bg-green-500 h-2 rounded-full" style={{ width: "72%" }}></div>
</div>
</div>
</div>
</>
)}
{activeRoom === "entrance" && (
<>
<div className="text-center py-8">
<span className="text-8xl">🐕</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">ANUBIS</h3>
<p className="text-amber-300">Guardian of Leads</p>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">🎯 Lead Pipeline</h4>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-amber-300">New Today</span>
<span className="text-yellow-400">23</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Qualified</span>
<span className="text-green-400">8</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Conversion</span>
<span className="text-blue-400">34%</span>
</div>
</div>
</div>
</>
)}
{(activeRoom === "pylon2" || activeRoom === "pylon3") && (
<>
<div className="text-center py-8">
<span className="text-8xl">{activeRoom === "pylon2" ? "🐦" : "⚖️"}</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">
{activeRoom === "pylon2" ? "THOTH" : "MAAT"}
</h3>
<p className="text-amber-300">
{activeRoom === "pylon2" ? "Knowledge Keeper" : "Quality Guardian"}
</p>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">
{activeRoom === "pylon2" ? "🔬 Research" : "✓ Quality Metrics"}
</h4>
<div className="space-y-2">
{activeRoom === "pylon2" ? (
<>
<div className="flex justify-between">
<span className="text-amber-300">Market Analysis</span>
<span className="text-green-400">Complete</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Competitor Report</span>
<span className="text-yellow-400">In Progress</span>
</div>
</>
) : (
<>
<div className="flex justify-between">
<span className="text-amber-300">Code Coverage</span>
<span className="text-green-400">94%</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Bugs Fixed</span>
<span className="text-blue-400">12</span>
</div>
</>
)}
</div>
</div>
</>
)}
</div>
</div>
</div>
{/* Right Column - All Agents */}
<div className="lg:col-span-1">
<div className="bg-stone-900/80 backdrop-blur rounded-2xl border border-amber-500/20 p-6">
<h2 className="text-xl font-bold text-amber-200 mb-4">
👥 Divine Council
</h2>
<div className="space-y-3">
{agents.map(agent => (
<div
key={agent.id}
className="bg-stone-800/50 rounded-xl p-3 hover:bg-stone-700/50 transition-colors cursor-pointer"
onClick={() => setActiveRoom(agent.location === "Entrance" ? "entrance" : agent.location === "Hall 2" ? "hall2" : agent.location === "Pylon 2" ? "pylon2" : agent.location === "Pylon 3" ? "pylon3" : agent.location === "Courtyard" ? "courtyard" : "sanctuary")}
>
<div className="flex items-center gap-3">
<span className="text-2xl">{agent.symbol}</span>
<div className="flex-1">
<p className="font-bold text-amber-200">{agent.name}</p>
<p className="text-xs text-amber-400/60">{agent.role}</p>
</div>
<div className="text-right">
<span className={`w-2 h-2 rounded-full ${getStatusColor(agent.status)} inline-block`}></span>
<p className="text-xs text-amber-400/60 mt-1">{getStatusText(agent.status)}</p>
</div>
</div>
<p className="text-xs text-amber-300/60 mt-2 ml-9 truncate">
{agent.currentTask}
</p>
</div>
))}
</div>
{/* Cleopatra's Voice Widget */}
<div className="mt-6 pt-6 border-t border-amber-500/20">
<h3 className="text-lg font-bold text-purple-300 mb-3">🎙 Cleopatra Voice</h3>
<div className="bg-purple-900/30 rounded-xl p-4 border border-purple-500/20">
<p className="text-purple-200 text-sm mb-3">Test Cleopatra's voice AI on AnveVoice:</p>
<a
href="https://anvevoice.com/dashboard"
target="_blank"
className="block w-full py-2 bg-purple-600 hover:bg-purple-500 text-center rounded-lg font-medium text-white text-sm transition-colors"
>
Open Voice Dashboard
</a>
</div>
</div>
</div>
</div>
</div>
{/* Footer */}
<div className="text-center mt-8 text-amber-400/40 text-sm">
<p>🏛 Temple of AI - Ancient Wisdom Meets Machine Intelligence</p>
<p className="mt-1">Powered by HostPioneers | Built on OpenClaw & AnveVoice</p>
</div>
</div>
);
}