diff --git a/client/src/pages/os.tsx b/client/src/pages/os.tsx index 968dace..56dc4f5 100644 --- a/client/src/pages/os.tsx +++ b/client/src/pages/os.tsx @@ -1,16 +1,22 @@ import { useState, useRef, useCallback, useEffect } from "react"; +import { useQuery } from "@tanstack/react-query"; import { motion, AnimatePresence } from "framer-motion"; +import { useLocation } from "wouter"; +import { useAuth } from "@/lib/auth"; +import { getIcon } from "@/lib/iconMap"; import { Terminal, FileText, IdCard, Music, Settings, Globe, X, Minus, Square, Maximize2, Volume2, Wifi, Battery, - ChevronUp + ChevronUp, FolderOpen, Award, MessageCircle, Send, + ExternalLink, User, LogOut, BarChart3, Loader2, + Presentation, Bell, Image, Monitor, Play, Pause, ChevronRight } from "lucide-react"; interface WindowState { id: string; title: string; icon: React.ReactNode; - content: React.ReactNode; + component: string; x: number; y: number; width: number; @@ -24,76 +30,131 @@ interface DesktopApp { id: string; title: string; icon: React.ReactNode; - content: React.ReactNode; + component: string; defaultWidth: number; defaultHeight: number; } +interface ContextMenuState { + x: number; + y: number; + type: 'desktop' | 'icon'; + appId?: string; +} + +const WALLPAPERS = [ + { id: 'default', name: 'Cyber Grid', bg: 'linear-gradient(to bottom right, #0f172a, #1e1b4b, #0f172a)' }, + { id: 'matrix', name: 'Matrix', bg: 'linear-gradient(to bottom, #001100, #002200, #001100)' }, + { id: 'sunset', name: 'Neon Sunset', bg: 'linear-gradient(to bottom, #1a0533, #4a1942, #0f172a)' }, + { id: 'ocean', name: 'Deep Ocean', bg: 'linear-gradient(to bottom, #0a1628, #0d3b66, #0a1628)' }, +]; + export default function AeThexOS() { + const [isBooting, setIsBooting] = useState(true); + const [bootProgress, setBootProgress] = useState(0); + const [bootStep, setBootStep] = useState(''); const [windows, setWindows] = useState([]); const [activeWindowId, setActiveWindowId] = useState(null); const [maxZIndex, setMaxZIndex] = useState(1); const [showStartMenu, setShowStartMenu] = useState(false); const [time, setTime] = useState(new Date()); + const [contextMenu, setContextMenu] = useState(null); + const [wallpaper, setWallpaper] = useState(WALLPAPERS[0]); + const [soundEnabled, setSoundEnabled] = useState(false); + const [showScreensaver, setShowScreensaver] = useState(false); + const [notifications, setNotifications] = useState([]); + const [showNotifications, setShowNotifications] = useState(false); const desktopRef = useRef(null); + const idleTimer = useRef(null); + const { user, isAuthenticated, logout } = useAuth(); + const [, setLocation] = useLocation(); + + useEffect(() => { + const bootSequence = async () => { + const steps = [ + { text: 'Initializing AeThex OS...', progress: 10 }, + { text: 'Loading kernel modules...', progress: 25 }, + { text: 'Mounting file systems...', progress: 40 }, + { text: 'Starting Aegis security layer...', progress: 55 }, + { text: 'Connecting to Nexus network...', progress: 70 }, + { text: 'Loading user profile...', progress: 85 }, + { text: 'Welcome, Architect.', progress: 100 }, + ]; + + for (const step of steps) { + setBootStep(step.text); + setBootProgress(step.progress); + await new Promise(r => setTimeout(r, 400)); + } + + await new Promise(r => setTimeout(r, 500)); + setIsBooting(false); + }; + + bootSequence(); + }, []); useEffect(() => { const timer = setInterval(() => setTime(new Date()), 1000); return () => clearInterval(timer); }, []); + useEffect(() => { + const fetchNotifications = async () => { + try { + const res = await fetch('/api/os/notifications'); + const data = await res.json(); + if (Array.isArray(data)) { + setNotifications(data.map((n: any) => n.message)); + } + } catch {} + }; + fetchNotifications(); + const interval = setInterval(fetchNotifications, 60000); + return () => clearInterval(interval); + }, []); + + useEffect(() => { + const resetIdle = () => { + if (showScreensaver) setShowScreensaver(false); + if (idleTimer.current) clearTimeout(idleTimer.current); + idleTimer.current = setTimeout(() => setShowScreensaver(true), 5 * 60 * 1000); + }; + + window.addEventListener('mousemove', resetIdle); + window.addEventListener('keydown', resetIdle); + resetIdle(); + + return () => { + window.removeEventListener('mousemove', resetIdle); + window.removeEventListener('keydown', resetIdle); + if (idleTimer.current) clearTimeout(idleTimer.current); + }; + }, [showScreensaver]); + const apps: DesktopApp[] = [ - { - id: "terminal", - title: "Terminal", - icon: , - defaultWidth: 700, - defaultHeight: 450, - content: - }, - { - id: "passport", - title: "Passport Viewer", - icon: , - defaultWidth: 500, - defaultHeight: 600, - content: - }, - { - id: "manifesto", - title: "Manifesto", - icon: , - defaultWidth: 600, - defaultHeight: 500, - content: - }, - { - id: "music", - title: "Ambient", - icon: , - defaultWidth: 400, - defaultHeight: 300, - content: - }, - { - id: "browser", - title: "Nexus", - icon: , - defaultWidth: 800, - defaultHeight: 600, - content: - }, - { - id: "settings", - title: "System", - icon: , - defaultWidth: 500, - defaultHeight: 400, - content: - } + { id: "terminal", title: "Terminal", icon: , component: "terminal", defaultWidth: 700, defaultHeight: 450 }, + { id: "passport", title: "Passport", icon: , component: "passport", defaultWidth: 500, defaultHeight: 600 }, + { id: "files", title: "Projects", icon: , component: "files", defaultWidth: 700, defaultHeight: 500 }, + { id: "achievements", title: "Achievements", icon: , component: "achievements", defaultWidth: 600, defaultHeight: 500 }, + { id: "chat", title: "Chat", icon: , component: "chat", defaultWidth: 400, defaultHeight: 500 }, + { id: "manifesto", title: "Manifesto", icon: , component: "manifesto", defaultWidth: 600, defaultHeight: 500 }, + { id: "music", title: "Ambient", icon: , component: "music", defaultWidth: 400, defaultHeight: 350 }, + { id: "pitch", title: "Pitch Deck", icon: , component: "pitch", defaultWidth: 500, defaultHeight: 400 }, + { id: "settings", title: "Settings", icon: , component: "settings", defaultWidth: 550, defaultHeight: 500 }, ]; + const playSound = useCallback((type: 'open' | 'close' | 'minimize' | 'click') => { + if (!soundEnabled) return; + // Visual feedback instead of actual sound + const flash = document.createElement('div'); + flash.className = 'fixed inset-0 bg-cyan-400/5 pointer-events-none z-[99999]'; + document.body.appendChild(flash); + setTimeout(() => flash.remove(), 50); + }, [soundEnabled]); + const openApp = useCallback((app: DesktopApp) => { + playSound('open'); const existingWindow = windows.find(w => w.id === app.id); if (existingWindow) { if (existingWindow.minimized) { @@ -117,7 +178,7 @@ export default function AeThexOS() { id: app.id, title: app.title, icon: app.icon, - content: app.content, + component: app.component, x: offsetX, y: offsetY, width: app.defaultWidth, @@ -131,62 +192,162 @@ export default function AeThexOS() { setMaxZIndex(prev => prev + 1); setActiveWindowId(app.id); setShowStartMenu(false); - }, [windows, maxZIndex]); + }, [windows, maxZIndex, playSound]); const closeWindow = useCallback((id: string) => { + playSound('close'); setWindows(prev => prev.filter(w => w.id !== id)); - if (activeWindowId === id) { - setActiveWindowId(null); - } - }, [activeWindowId]); + if (activeWindowId === id) setActiveWindowId(null); + }, [activeWindowId, playSound]); const minimizeWindow = useCallback((id: string) => { - setWindows(prev => prev.map(w => - w.id === id ? { ...w, minimized: true } : w - )); - }, []); + playSound('minimize'); + setWindows(prev => prev.map(w => w.id === id ? { ...w, minimized: true } : w)); + }, [playSound]); const toggleMaximize = useCallback((id: string) => { - setWindows(prev => prev.map(w => - w.id === id ? { ...w, maximized: !w.maximized } : w - )); + setWindows(prev => prev.map(w => w.id === id ? { ...w, maximized: !w.maximized } : w)); }, []); const focusWindow = useCallback((id: string) => { - setWindows(prev => prev.map(w => - w.id === id ? { ...w, zIndex: maxZIndex + 1 } : w - )); + setWindows(prev => prev.map(w => w.id === id ? { ...w, zIndex: maxZIndex + 1 } : w)); setMaxZIndex(prev => prev + 1); setActiveWindowId(id); }, [maxZIndex]); + const handleDesktopClick = (e: React.MouseEvent) => { + setShowStartMenu(false); + setContextMenu(null); + }; + + const handleDesktopContextMenu = (e: React.MouseEvent) => { + e.preventDefault(); + setContextMenu({ x: e.clientX, y: e.clientY, type: 'desktop' }); + }; + + const handleIconContextMenu = (e: React.MouseEvent, appId: string) => { + e.preventDefault(); + e.stopPropagation(); + setContextMenu({ x: e.clientX, y: e.clientY, type: 'icon', appId }); + }; + + const handleWindowSnap = useCallback((id: string, x: number, y: number, width: number, height: number) => { + const screenWidth = window.innerWidth; + const screenHeight = window.innerHeight - 48; + + if (x <= 10) { + setWindows(prev => prev.map(w => w.id === id ? { ...w, x: 0, y: 0, width: screenWidth / 2, height: screenHeight } : w)); + return true; + } + if (x + width >= screenWidth - 10) { + setWindows(prev => prev.map(w => w.id === id ? { ...w, x: screenWidth / 2, y: 0, width: screenWidth / 2, height: screenHeight } : w)); + return true; + } + if (y <= 10) { + setWindows(prev => prev.map(w => w.id === id ? { ...w, x: 0, y: 0, width: screenWidth, height: screenHeight, maximized: true } : w)); + return true; + } + return false; + }, []); + + const handleLogout = async () => { + await logout(); + setLocation("/"); + }; + + const renderAppContent = (component: string) => { + switch (component) { + case 'terminal': return ; + case 'passport': return ; + case 'files': return ; + case 'achievements': return ; + case 'chat': return ; + case 'manifesto': return ; + case 'music': return ; + case 'pitch': return setLocation('/pitch')} />; + case 'settings': return ; + default: return null; + } + }; + + if (isBooting) { + return ( +
+ +
+
+
+ A +
+
+ +
{bootStep}
+ +
+ +
+ +
AeThex OS v1.0.0
+ +
+ ); + } + + if (showScreensaver) { + return ( +
setShowScreensaver(false)} + > + +
+ AeThex +
+
Click to wake
+
+
+ ); + } + return (
setShowStartMenu(false)} + onClick={handleDesktopClick} + onContextMenu={handleDesktopContextMenu} > -
-
-
+
-
- {apps.map((app) => ( + + +
+ {apps.slice(0, 9).map((app) => ( openApp(app)} + onContextMenu={(e) => handleIconContextMenu(e, app.id)} /> ))}
@@ -201,20 +362,30 @@ export default function AeThexOS() { onMinimize={() => minimizeWindow(window.id)} onMaximize={() => toggleMaximize(window.id)} onFocus={() => focusWindow(window.id)} - onMove={(x, y) => { - setWindows(prev => prev.map(w => - w.id === window.id ? { ...w, x, y } : w - )); - }} - onResize={(width, height) => { - setWindows(prev => prev.map(w => - w.id === window.id ? { ...w, width, height } : w - )); - }} - desktopRef={desktopRef} + onMove={(x, y) => setWindows(prev => prev.map(w => w.id === window.id ? { ...w, x, y } : w))} + onResize={(width, height) => setWindows(prev => prev.map(w => w.id === window.id ? { ...w, width, height } : w))} + onSnap={(x, y) => handleWindowSnap(window.id, x, y, window.width, window.height)} + content={renderAppContent(window.component)} /> ))} + + + {contextMenu && ( + setContextMenu(null)} + onOpenApp={openApp} + onRefresh={() => window.location.reload()} + onChangeWallpaper={() => { + const idx = WALLPAPERS.findIndex(w => w.id === wallpaper.id); + setWallpaper(WALLPAPERS[(idx + 1) % WALLPAPERS.length]); + setContextMenu(null); + }} + /> + )} +
setShowStartMenu(!showStartMenu)} + onToggleNotifications={() => setShowNotifications(!showNotifications)} onWindowClick={(id) => { const window = windows.find(w => w.id === id); if (window?.minimized) { - setWindows(prev => prev.map(w => - w.id === id ? { ...w, minimized: false, zIndex: maxZIndex + 1 } : w - )); + setWindows(prev => prev.map(w => w.id === id ? { ...w, minimized: false, zIndex: maxZIndex + 1 } : w)); setMaxZIndex(prev => prev + 1); } focusWindow(id); }} onAppClick={openApp} + onLogout={handleLogout} + onNavigate={setLocation} />
); } -function DesktopIcon({ icon, label, onClick }: { icon: React.ReactNode; label: string; onClick: () => void }) { +function DesktopWidgets({ time }: { time: Date }) { + const { data: metrics } = useQuery({ + queryKey: ['os-metrics'], + queryFn: async () => { + const res = await fetch('/api/metrics'); + return res.json(); + }, + refetchInterval: 30000, + }); + + return ( +
+
+
+ {time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} +
+
+ {time.toLocaleDateString([], { weekday: 'long', month: 'short', day: 'numeric' })} +
+
+ + {metrics && ( +
+
System Status
+
+
+ Architects + {metrics.totalProfiles || 0} +
+
+ Projects + {metrics.totalProjects || 0} +
+
+ Online + {metrics.onlineUsers || 0} +
+
+
+ )} +
+ ); +} + +function DesktopIcon({ icon, label, onClick, onContextMenu }: { + icon: React.ReactNode; + label: string; + onClick: () => void; + onContextMenu?: (e: React.MouseEvent) => void; +}) { return ( @@ -259,6 +485,59 @@ function DesktopIcon({ icon, label, onClick }: { icon: React.ReactNode; label: s ); } +function ContextMenuComponent({ menu, apps, onClose, onOpenApp, onRefresh, onChangeWallpaper }: { + menu: ContextMenuState; + apps: DesktopApp[]; + onClose: () => void; + onOpenApp: (app: DesktopApp) => void; + onRefresh: () => void; + onChangeWallpaper: () => void; +}) { + const app = menu.appId ? apps.find(a => a.id === menu.appId) : null; + + return ( + e.stopPropagation()} + > + {menu.type === 'icon' && app ? ( + <> + } label="Open" onClick={() => { onOpenApp(app); onClose(); }} /> +
+ } label="Properties" onClick={onClose} /> + + ) : ( + <> + } label="Refresh" onClick={() => { onRefresh(); onClose(); }} /> + } label="Change Wallpaper" onClick={onChangeWallpaper} /> +
+ } label="Settings" onClick={() => { + const settingsApp = apps.find(a => a.id === 'settings'); + if (settingsApp) onOpenApp(settingsApp); + onClose(); + }} /> + + )} + + ); +} + +function MenuItem({ icon, label, onClick }: { icon: React.ReactNode; label: string; onClick: () => void }) { + return ( + + ); +} + interface WindowProps { window: WindowState; isActive: boolean; @@ -268,10 +547,11 @@ interface WindowProps { onFocus: () => void; onMove: (x: number, y: number) => void; onResize: (width: number, height: number) => void; - desktopRef: React.RefObject; + onSnap: (x: number, y: number) => boolean; + content: React.ReactNode; } -function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, onMove, onResize, desktopRef }: WindowProps) { +function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, onMove, onResize, onSnap, content }: WindowProps) { const [isDragging, setIsDragging] = useState(false); const [isResizing, setIsResizing] = useState(false); const dragStart = useRef({ x: 0, y: 0, windowX: 0, windowY: 0 }); @@ -281,12 +561,7 @@ function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, on if (window.maximized) return; e.preventDefault(); setIsDragging(true); - dragStart.current = { - x: e.clientX, - y: e.clientY, - windowX: window.x, - windowY: window.y - }; + dragStart.current = { x: e.clientX, y: e.clientY, windowX: window.x, windowY: window.y }; onFocus(); }; @@ -295,12 +570,7 @@ function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, on e.preventDefault(); e.stopPropagation(); setIsResizing(true); - resizeStart.current = { - x: e.clientX, - y: e.clientY, - width: window.width, - height: window.height - }; + resizeStart.current = { x: e.clientX, y: e.clientY, width: window.width, height: window.height }; }; useEffect(() => { @@ -315,14 +585,16 @@ function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, on if (isResizing) { const dx = e.clientX - resizeStart.current.x; const dy = e.clientY - resizeStart.current.y; - onResize( - Math.max(300, resizeStart.current.width + dx), - Math.max(200, resizeStart.current.height + dy) - ); + onResize(Math.max(300, resizeStart.current.width + dx), Math.max(200, resizeStart.current.height + dy)); } }; - const handleMouseUp = () => { + const handleMouseUp = (e: MouseEvent) => { + if (isDragging) { + const newX = dragStart.current.windowX + (e.clientX - dragStart.current.x); + const newY = Math.max(0, dragStart.current.windowY + (e.clientY - dragStart.current.y)); + onSnap(newX, newY); + } setIsDragging(false); setIsResizing(false); }; @@ -333,10 +605,10 @@ function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, on document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseup", handleMouseUp); }; - }, [isDragging, isResizing, onMove, onResize]); + }, [isDragging, isResizing, onMove, onResize, onSnap]); const style = window.maximized - ? { top: 0, left: 0, width: "100%", height: "100%", zIndex: window.zIndex } + ? { top: 0, left: 0, width: "100%", height: "calc(100vh - 48px)", zIndex: window.zIndex } : { top: window.y, left: window.x, width: window.width, height: window.height, zIndex: window.zIndex }; return ( @@ -345,17 +617,8 @@ function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, on animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.9 }} transition={{ duration: 0.15 }} - className={`absolute flex flex-col overflow-hidden ${ - isActive - ? 'ring-1 ring-cyan-400/50 shadow-lg shadow-cyan-500/20' - : 'ring-1 ring-white/10' - }`} - style={{ - ...style, - background: 'linear-gradient(to bottom, rgba(15, 23, 42, 0.98), rgba(15, 23, 42, 0.95))', - backdropFilter: 'blur(20px)', - borderRadius: window.maximized ? 0 : '8px' - }} + className={`absolute flex flex-col overflow-hidden ${isActive ? 'ring-1 ring-cyan-400/50 shadow-lg shadow-cyan-500/20' : 'ring-1 ring-white/10'}`} + style={{ ...style, background: 'linear-gradient(to bottom, rgba(15, 23, 42, 0.98), rgba(15, 23, 42, 0.95))', backdropFilter: 'blur(20px)', borderRadius: window.maximized ? 0 : '8px' }} onMouseDown={onFocus} data-testid={`window-${window.id}`} > @@ -364,45 +627,24 @@ function Window({ window, isActive, onClose, onMinimize, onMaximize, onFocus, on onMouseDown={handleDragStart} >
-
- {window.icon} -
+
{window.icon}
{window.title}
- - -
- -
- {window.content} -
- +
{content}
{!window.maximized && ( -
+
)} @@ -416,12 +658,19 @@ interface TaskbarProps { apps: DesktopApp[]; time: Date; showStartMenu: boolean; + user: any; + isAuthenticated: boolean; + notifications: string[]; + showNotifications: boolean; onToggleStartMenu: () => void; + onToggleNotifications: () => void; onWindowClick: (id: string) => void; onAppClick: (app: DesktopApp) => void; + onLogout: () => void; + onNavigate: (path: string) => void; } -function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, onToggleStartMenu, onWindowClick, onAppClick }: TaskbarProps) { +function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, user, isAuthenticated, notifications, showNotifications, onToggleStartMenu, onToggleNotifications, onWindowClick, onAppClick, onLogout, onNavigate }: TaskbarProps) { return ( <> @@ -430,46 +679,52 @@ function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, onToggleS initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: 20 }} - className="absolute bottom-12 left-2 w-64 bg-slate-900/95 backdrop-blur-xl border border-white/10 rounded-lg overflow-hidden shadow-2xl" + className="absolute bottom-12 left-2 w-72 bg-slate-900/95 backdrop-blur-xl border border-white/10 rounded-lg overflow-hidden shadow-2xl" style={{ zIndex: 9999 }} onClick={(e) => e.stopPropagation()} >
- A + {isAuthenticated ? : A}
-
-
AeThex OS
-
v1.0.0
+
+
{isAuthenticated ? user?.username : 'Guest'}
+
{isAuthenticated ? (user?.isAdmin ? 'Administrator' : 'Architect') : 'Not logged in'}
+ {isAuthenticated && ( + + )}
-
+ +
{apps.map(app => ( - ))}
+ + {isAuthenticated && user?.isAdmin && ( +
+
Admin
+ +
+ )} )}
-
-
+
+ @@ -512,126 +773,342 @@ function Taskbar({ windows, activeWindowId, apps, time, showStartMenu, onToggleS } function TerminalApp() { - const [history, setHistory] = useState([ - "AeThex Terminal v1.0.0", - "Type 'help' for available commands.", - "" - ]); + const [history, setHistory] = useState(["AeThex Terminal v2.0.0", "Type 'help' for available commands.", ""]); const [input, setInput] = useState(""); + const [isLoading, setIsLoading] = useState(false); - const commands: Record string[]> = { - help: () => ["Available commands:", " help - Show this message", " status - System status", " whoami - Current user", " clear - Clear terminal", " matrix - Enter the matrix", ""], - status: () => ["SYSTEM STATUS", " Aegis Shield: ACTIVE", " Threat Level: LOW", " Architects Online: 47", " Projects Active: 156", ""], - whoami: () => ["architect@aethex:~$ You are a Metaverse Architect", ""], - clear: () => [], - matrix: () => ["Wake up, Architect...", "The Matrix has you...", "Follow the white rabbit.", ""] + const runCommand = async (cmd: string): Promise => { + switch (cmd) { + case 'help': + return ["Available commands:", " help - Show this message", " status - System status from server", " architects - List architects in network", " projects - List active projects", " whoami - Current user info", " clear - Clear terminal", " matrix - Enter the matrix", ""]; + case 'status': + try { + const res = await fetch('/api/metrics'); + const data = await res.json(); + return ["SYSTEM STATUS", ` Total Architects: ${data.totalProfiles || 0}`, ` Total Projects: ${data.totalProjects || 0}`, ` Online Users: ${data.onlineUsers || 0}`, ` Verified Users: ${data.verifiedUsers || 0}`, ` Total XP: ${data.totalXP || 0}`, ""]; + } catch { + return ["Error fetching status", ""]; + } + case 'architects': + try { + const res = await fetch('/api/os/architects'); + const data = await res.json(); + if (!data.length) return ["No architects found in network.", ""]; + const lines = ["ARCHITECTS IN NETWORK:", ""]; + data.forEach((a: any) => { + lines.push(` ${a.username || 'Unknown'} - Level ${a.level} (${a.xp} XP)${a.verified ? ' [VERIFIED]' : ''}`); + }); + lines.push(""); + return lines; + } catch { + return ["Error fetching architects", ""]; + } + case 'projects': + try { + const res = await fetch('/api/os/projects'); + const data = await res.json(); + if (!data.length) return ["No projects found.", ""]; + const lines = ["ACTIVE PROJECTS:", ""]; + data.forEach((p: any) => { + lines.push(` ${p.title} [${p.status || 'unknown'}]${p.engine ? ` - ${p.engine}` : ''}`); + }); + lines.push(""); + return lines; + } catch { + return ["Error fetching projects", ""]; + } + case 'whoami': + return ["architect@aethex-os", "Role: Metaverse Architect", ""]; + case 'matrix': + return ["Wake up, Architect...", "The Matrix has you...", "Follow the white rabbit.", ""]; + default: + return [`Command not found: ${cmd}`, "Type 'help' for available commands.", ""]; + } }; - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const cmd = input.trim().toLowerCase(); - const output = commands[cmd]?.() || [`Command not found: ${input}`, "Type 'help' for available commands.", ""]; - - if (cmd === "clear") { - setHistory([]); - } else { - setHistory(prev => [...prev, `$ ${input}`, ...output]); - } setInput(""); + + if (cmd === 'clear') { + setHistory([]); + return; + } + + setHistory(prev => [...prev, `$ ${input}`]); + setIsLoading(true); + + const output = await runCommand(cmd); + setHistory(prev => [...prev, ...output]); + setIsLoading(false); }; return (
- {history.map((line, i) => ( -
{line}
- ))} + {history.map((line, i) =>
{line}
)} + {isLoading &&
Processing...
}
$ - setInput(e.target.value)} - className="flex-1 ml-2 bg-transparent outline-none text-green-400" - autoFocus - data-testid="terminal-input" - /> + setInput(e.target.value)} className="flex-1 ml-2 bg-transparent outline-none text-green-400" autoFocus disabled={isLoading} data-testid="terminal-input" />
); } function PassportApp() { + const { user, isAuthenticated } = useAuth(); + const { data: profile, isLoading } = useQuery({ + queryKey: ['os-user-profile'], + queryFn: async () => { + const res = await fetch('/api/metrics'); + return res.json(); + }, + enabled: true, + }); + return ( -
+
- + {isAuthenticated ? : }

AeThex Passport

-

Architect Credentials

+

{isAuthenticated ? user?.username : 'Guest Access'}

Status - VERIFIED + {isAuthenticated ? 'VERIFIED' : 'GUEST'}
- Passport ID - AX-2025-0001 -
-
- Tier - ARCHITECT -
-
- XP - 12,450 -
-
- Level - 15 -
-
- Skills - 7 Certified + Role + {isAuthenticated ? (user?.isAdmin ? 'ADMIN' : 'ARCHITECT') : 'VISITOR'}
+ {profile && ( + <> +
+ Network + {profile.totalProfiles || 0} Architects +
+
+ Projects + {profile.totalProjects || 0} +
+ + )}
-
-
- Issued by Codex Certification Authority -
+
+ Issued by Codex Certification Authority
); } +function FilesApp() { + const { data: projects, isLoading } = useQuery({ + queryKey: ['os-projects-list'], + queryFn: async () => { + const res = await fetch('/api/os/projects'); + return res.json(); + }, + }); + + const { data: metrics } = useQuery({ + queryKey: ['os-metrics'], + queryFn: async () => { + const res = await fetch('/api/metrics'); + return res.json(); + }, + }); + + return ( +
+
+
+ /home/architect/projects +
+
+
+ {isLoading ? ( +
+ +
+ ) : ( +
+
+
+ +
Total Projects
+
{metrics?.totalProjects || 0}
+
+
+ +
Architects
+
{metrics?.totalProfiles || 0}
+
+
+ +
Project Files
+ {projects?.length > 0 ? ( +
+ {projects.map((p: any) => ( +
+ +
+
{p.title}
+
{p.engine || 'Unknown engine'}
+
+ + {p.status || 'unknown'} + +
+ ))} +
+ ) : ( +

No projects found

+ )} +
+ )} +
+
+ ); +} + +function AchievementsApp() { + const { data: achievements, isLoading } = useQuery({ + queryKey: ['os-achievements-real'], + queryFn: async () => { + try { + const res = await fetch('/api/os/achievements'); + const data = await res.json(); + if (data.length > 0) return data; + } catch {} + return [ + { id: 1, name: 'First Steps', description: 'Complete your profile', icon: 'footprints' }, + { id: 2, name: 'Code Warrior', description: 'Submit your first project', icon: 'code' }, + { id: 3, name: 'Community Builder', description: 'Connect with 10 architects', icon: 'users' }, + { id: 4, name: 'Rising Star', description: 'Reach level 10', icon: 'star' }, + { id: 5, name: 'Certified Pro', description: 'Earn your first certification', icon: 'award' }, + ]; + }, + }); + + return ( +
+
+ +

Achievements

+
+ + {isLoading ? ( +
+ +
+ ) : ( +
+ {achievements?.map((achievement: any) => ( +
+
+ {getIcon(achievement.icon)} +
+
+
{achievement.name}
+
{achievement.description}
+
+ {achievement.unlocked &&
UNLOCKED
} +
+ ))} +
+ )} +
+ ); +} + +function ChatApp() { + const [messages, setMessages] = useState<{ role: 'user' | 'assistant'; content: string }[]>([ + { role: 'assistant', content: "Hi! I'm the AeThex assistant. How can I help you today?" } + ]); + const [input, setInput] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const sendMessage = async () => { + if (!input.trim() || isLoading) return; + + const userMsg = input.trim(); + setMessages(prev => [...prev, { role: 'user', content: userMsg }]); + setInput(""); + setIsLoading(true); + + try { + const res = await fetch('/api/chat', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + credentials: 'include', + body: JSON.stringify({ message: userMsg, history: messages.slice(-10) }), + }); + const data = await res.json(); + setMessages(prev => [...prev, { role: 'assistant', content: data.response || "I'm having trouble responding right now." }]); + } catch { + setMessages(prev => [...prev, { role: 'assistant', content: "Sorry, I encountered an error. Please try again." }]); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+ {messages.map((msg, i) => ( +
+
+ {msg.content} +
+
+ ))} + {isLoading && ( +
+
+ +
+
+ )} +
+
+
{ e.preventDefault(); sendMessage(); }} className="flex gap-2"> + setInput(e.target.value)} + placeholder="Type a message..." + className="flex-1 bg-white/10 border border-white/10 rounded-lg px-3 py-2 text-white text-sm outline-none focus:border-cyan-500/50" + disabled={isLoading} + /> + +
+
+
+ ); +} + function ManifestoApp() { return (
-

- The AeThex Manifesto -

- +

The AeThex Manifesto

We are the architects of tomorrow.

-

In a world where the digital and physical converge, we stand at the frontier of a new reality. The Metaverse is not just a destination - it is a canvas for human potential.

-

Our Three Pillars:

- -

AXIOM - The foundational truths that guide our work. We believe in decentralization, transparency, and the power of community-driven innovation.

- -

CODEX - The certification of excellence. Through rigorous training and real-world application, we transform talent into verified Metaverse Architects.

- -

AEGIS - The shield that protects. Security is not an afterthought but a fundamental principle woven into everything we create.

- -

- "Build. Certify. Protect. This is the way of the Architect." -

+

AXIOM - The foundational truths that guide our work.

+

CODEX - The certification of excellence.

+

AEGIS - The shield that protects.

+

"Build. Certify. Protect. This is the way of the Architect."

@@ -640,30 +1117,38 @@ function ManifestoApp() { function MusicApp() { const [isPlaying, setIsPlaying] = useState(false); - + const [currentTrack, setCurrentTrack] = useState(0); const tracks = [ - { name: "Neon Dreams", artist: "Synth Collective" }, - { name: "Digital Rain", artist: "Matrix OST" }, - { name: "Architect's Theme", artist: "AeThex Audio" }, + { name: "Neon Dreams", artist: "Synth Collective", duration: "3:42" }, + { name: "Digital Rain", artist: "Matrix OST", duration: "4:15" }, + { name: "Architect's Theme", artist: "AeThex Audio", duration: "5:01" }, ]; return ( -
+
-
- +
+
-
Ambient Player
-
v1.0
+
{tracks[currentTrack].name}
+
{tracks[currentTrack].artist}
-
+
+ + + +
+ +
{tracks.map((track, i) => ( -
+
{track.duration}
))}
- -
-
- Audio playback coming soon -
-
+
Audio playback simulated
); } -function BrowserApp() { +function PitchApp({ onNavigate }: { onNavigate: () => void }) { return ( -
-
-
- nexus://aethex.local -
-
-
-
- -

- Nexus Browser -

-

- The decentralized web browser for the Metaverse. Coming soon to AeThex OS. -

-
-
+
+ +

Investor Pitch Deck

+

+ View the complete AeThex investor presentation with metrics, projections, and the dual-entity model. +

+
); } -function SettingsApp() { +function SettingsApp({ wallpaper, setWallpaper, soundEnabled, setSoundEnabled }: { + wallpaper: typeof WALLPAPERS[0]; + setWallpaper: (w: typeof WALLPAPERS[0]) => void; + soundEnabled: boolean; + setSoundEnabled: (v: boolean) => void; +}) { return ( -
-

- System Settings -

+
+

System Settings

-
-
-
-
Dark Mode
-
Always on in AeThex OS
+
+
+
Appearance
+
+ {WALLPAPERS.map(wp => ( + + ))}
-
-
+
+ +
+
System
+ +
+
+
Sound Effects
+
UI interaction feedback
+
+ +
+ +
+
+
Dark Mode
+
Always enabled
+
+
+
+
-
-
-
Notifications
-
System alerts and updates
-
-
-
-
-
- -
-
-
Sound Effects
-
UI interaction sounds
-
-
-
-
-
- -
-
AeThex OS v1.0.0
+
+
AeThex OS v2.0.0
Build 2025.12.16
diff --git a/server/routes.ts b/server/routes.ts index e4118cc..00b9f4f 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -303,6 +303,66 @@ export async function registerRoutes( } }); + // ========== PUBLIC OS API ROUTES ========== + + // Get public project summaries for OS (limited data, no auth required) + app.get("/api/os/projects", async (req, res) => { + try { + const projects = await storage.getProjects(); + const summaries = projects.slice(0, 10).map(p => ({ + id: p.id, + title: p.title, + status: p.status, + engine: p.engine, + })); + res.json(summaries); + } catch (err: any) { + res.status(500).json({ error: err.message }); + } + }); + + // Get public architect summaries for OS (limited data, no auth required) + app.get("/api/os/architects", async (req, res) => { + try { + const profiles = await storage.getProfiles(); + const summaries = profiles.slice(0, 10).map(p => ({ + id: p.id, + username: p.username, + level: p.level || 1, + xp: p.total_xp || 0, + verified: p.is_verified || false, + })); + res.json(summaries); + } catch (err: any) { + res.status(500).json({ error: err.message }); + } + }); + + // Get achievements list for OS (public) + app.get("/api/os/achievements", async (req, res) => { + try { + const achievements = await storage.getAchievements(); + res.json(achievements.slice(0, 20)); + } catch (err: any) { + res.status(500).json({ error: err.message }); + } + }); + + // Get recent activity/notifications for OS (public summary) + app.get("/api/os/notifications", async (req, res) => { + try { + const metrics = await storage.getMetrics(); + const notifications = [ + { id: 1, message: `${metrics.totalProfiles} architects in network`, type: 'info' }, + { id: 2, message: `${metrics.totalProjects} active projects`, type: 'info' }, + { id: 3, message: 'Aegis security active', type: 'success' }, + ]; + res.json(notifications); + } catch (err: any) { + res.status(500).json({ error: err.message }); + } + }); + // ========== CHATBOT API (Rate limited) ========== const chatRateLimits = new Map();