'use client'; import {CommunityPanel,OperationsPanel} from './community-panel'; import { useState,useEffect,useCallback } from 'react'; import { LayoutDashboard,Users,BookOpen,Compass,Server,Activity,Brain,Sparkles,Plus,Play,Pause,ArrowRight,Shield,Terminal,ScrollText,Radio,RefreshCw,Heart,MapPin,Network,Copy,Send,House,Globe2,Moon,Sun,Skull,Clock3 } from 'lucide-react'; import { SidebarProvider,Sidebar,SidebarHeader,SidebarContent,SidebarMenu,SidebarMenuItem,SidebarMenuButton,SidebarFooter,SidebarTrigger } from '@/components/ui/sidebar'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Dialog,DialogContent,DialogHeader,DialogTitle,DialogDescription } from '@/components/ui/dialog'; import { Sheet,SheetContent,SheetHeader,SheetTitle,SheetDescription } from '@/components/ui/sheet'; import { AlertDialog,AlertDialogContent,AlertDialogHeader,AlertDialogTitle,AlertDialogDescription,AlertDialogFooter,AlertDialogCancel,AlertDialogAction } from '@/components/ui/alert-dialog'; import { Tabs,TabsList,TabsTrigger,TabsContent } from '@/components/ui/tabs'; import { Select,SelectTrigger,SelectValue,SelectContent,SelectItem } from '@/components/ui/select'; import { Slider } from '@/components/ui/slider'; import { Checkbox } from '@/components/ui/checkbox'; import { Switch } from '@/components/ui/switch'; import { Table,TableHeader,TableRow,TableHead,TableBody,TableCell } from '@/components/ui/table'; import { Skeleton } from '@/components/ui/skeleton'; import { Toaster,toast } from 'sonner'; import type { State,Bot,Recipe,RealmEvent,Activity as BotActivity } from '@/core/types'; const NAV=[['Dashboard',LayoutDashboard],['World Monitor',Globe2],['Social Life',Heart],['System Health',Activity],['Realm Director',Compass],['World & Housing',House],['Bots',Users],['Bot Recipes',BookOpen],['Memory & Bonds',Heart],['Event Stream',Activity],['GM Console',Terminal],['Server & Models',Server]] as const; const ACTIVITIES:BotActivity[]=['explore','quest','socialize','trade','rest']; function Choice({value,onChange,items,label}:{value:string;onChange:(v:string)=>void;items:{value:string;label:string}[];label:string}){return } const options=(items:string[])=>items.map(value=>({value,label:value})); function Avatar({bot}:{bot:Bot}){return } function Panel({title,icon:Icon,children,action,className=''}:any){return

{Icon&&}{title}

{action}
{children}
} function Events({events}:{events:RealmEvent[]}){return
{events.length?[...events].reverse().map(e=>
{new Date(e.at).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit'})}{e.kind}{e.message}
):
No events match this filter.
}
} export default function Home({readOnly=false}:{readOnly?:boolean}){ const [state,setState]=useState(null),[page,setPage]=useState('Dashboard'),[error,setError]=useState(''),[busy,setBusy]=useState(false),[query,setQuery]=useState(''),[filter,setFilter]=useState('all'),[botId,setBotId]=useState(null),[createOpen,setCreateOpen]=useState(false),[recipe,setRecipe]=useState(null),[recipeOpen,setRecipeOpen]=useState(false),[confirm,setConfirm]=useState<{title:string;description:string;action:any}|null>(null),[capabilities,setCapabilities]=useState({}),[monitor,setMonitor]=useState(null); const refresh=useCallback(async()=>{try{const r=await fetch('/api/state');const d:any=await r.json();if(!r.ok)throw new Error(d.error);setState(d);setError('');}catch(e){setError(e instanceof Error?e.message:'Could not load realm');}},[]); useEffect(()=>{void refresh();void fetch('/api/health').then(r=>r.json()).then(setCapabilities).catch(()=>{});const timer=setInterval(refresh,5000);return()=>clearInterval(timer);},[refresh]); useEffect(()=>{if(page!=='World Monitor')return;let cancelled=false;const load=async()=>{try{const r=await fetch('/api/world-monitor');const d=await r.json();if(!cancelled)setMonitor(d);}catch{if(!cancelled)setMonitor(null);}};void load();const timer=setInterval(load,3000);return()=>{cancelled=true;clearInterval(timer);};},[page]); const act=useCallback(async(action:any)=>{if(readOnly)throw new Error('Visitor access is read-only');setBusy(true);try{const r=await fetch('/api/actions',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(action)});const d:any=await r.json();if(!r.ok)throw new Error(d.error);await refresh();return d;}catch(e){toast.error(e instanceof Error?e.message:'Action failed');await refresh();throw e;}finally{setBusy(false);}},[refresh,readOnly]); const perform=(action:any)=>{void act(action).catch(()=>{});}; useEffect(()=>{if(readOnly)return;const context=(document as any).modelContext;if(!context?.registerTool)return;const controller=new AbortController();const register=(tool:any)=>{try{Promise.resolve(context.registerTool(tool,{signal:controller.signal})).catch(()=>{});}catch{}}; register({name:'azerothai_read_realm',description:'Read current bot identities, recipes, director settings and recent events.',inputSchema:{type:'object',properties:{},additionalProperties:false},annotations:{readOnlyHint:true},execute:async()=>{const r=await fetch('/api/state');if(!r.ok)throw new Error('Realm unavailable');return r.json();}}); register({name:'azerothai_create_bot',description:'Create an offline bot identity; does not spawn it in game.',inputSchema:{type:'object',properties:{name:{type:'string'},role:{type:'string'},race:{type:'string'},recipeId:{type:'string'},goal:{type:'string'}},required:['name','role','race','recipeId','goal'],additionalProperties:false},annotations:{readOnlyHint:false},execute:async(input:any)=>act({...input,type:'createBot'})});return()=>controller.abort();},[act,readOnly]); function nav(p:string){setPage(p);setQuery('');setFilter('all');} const selected=state?.bots.find(b=>b.id===botId); const visible=state?.bots.filter(b=>(`${b.name} ${b.role} ${b.zone}`.toLowerCase().includes(query.toLowerCase()))&&(filter==='all'||b.status===filter))??[]; function botTable(bots:Bot[]){return CharacterStatusLocationRecipe{bots.map(b=>setBotId(b.id)}>
Lv. {b.level} · {b.race} {b.role}
{b.status}{b.zone}{b.personality.name.replace('The ','')}
)}
} return
A
AzerothAIYOUR WORLD. ALIVE.
REALM MANAGEMENT
{NAV.map(([name,Icon])=>nav(name)}>{name})}

{readOnly?'Realm visitor · Read only':'Realm administrator'}

{readOnly?'Live realm monitor':'Prototype 0.1 · Private realm'}

“What if Azeroth never felt empty?”

Living Realm / {page}
{capabilities.aleActiveRecently?'AZEROTHCORE LIVE':state?.settings.connector==='azerothcore'?'AzerothCore bridge':'SIMULATION REALM'}{readOnly?'Visitor · Read only':'GM workspace'}
{page==='GM Console'?'THE WORLD IS YOUR SANDBOX':'AZEROTHAI CONTROL PLANE'}

{page==='Dashboard'?'Your realm, alive.':page}

{({'Dashboard':'The people, personalities, and stories that make your world.','World Monitor':'Watch Azeroth breathe: population, activity, systems, and the lives unfolding right now.','Realm Director':'Shape the adventure around you. Let your characters bring it to life.','World & Housing':'Homes, routines, simulation bands, and believable population flow.','Bots':'Give every character a purpose, then let their story unfold.','Bot Recipes':'Same model. Different personalities. A world of possibilities.','Memory & Bonds':'A shared history makes the next encounter matter.','Event Stream':'Follow the decisions and changes happening across your realm.','GM Console':'Pull up a chair. Put on the blue robe. Run your world.','Server & Models':'Connect the game engine and the minds behind your characters.'} as any)[page]}

{readOnly?:page==='Bot Recipes'?:<>}
{error&&
{error}
} {!state?
{[1,2,3,4].map(n=>)}
:<> {page==='Dashboard'&&<>
{[[Users,'Active bots',state.bots.filter(b=>b.status==='online'&&(state.settings.connector==='simulation'||b.autonomy?.managed)).length,'Online in the simulation'],[BookOpen,'Bot recipes',state.recipes.length,'Distinct ways to experience the world'],[Brain,'Memories',state.bots.reduce((n,b)=>n+b.memories.length,0),'Stories carried into future decisions'],[Network,'Relationships',state.bots.reduce((n,b)=>n+b.relationships.length,0),'Directed bonds between characters']].map(([Icon,label,value,note]:any)=>
{label}
{value}
{label==='Active bots'&&state.settings.connector!=='simulation'?'Acknowledged by the game bridge':note}
)}
YOUR NEXT ADVENTURE

{state.director.experience}

{state.director.zone} · {state.director.brief}

nav('Bots')}>{readOnly?'View bots':'Manage bots'} }>{botTable(state.bots.slice(0,5))}
{Array.from(new Set(state.bots.filter(b=>b.status==='online').map(b=>b.zone))).map(zone=>{const n=state.bots.filter(b=>b.status==='online'&&b.zone===zone).length;return
{zone}b.status==='online').length)*100}%`}}/>{n}
})}

Bot locations from the selected connector. Simulation locations are illustrative.

{state.settings.provider==='deterministic'?'Personality simulator':state.settings.model}

{state.settings.provider==='deterministic'?'No model required. Try a decision from any online bot.':'Local model selected. Each decision includes identity and memories.'}

nav('Event Stream')}>View stream }>{}

Set the scene. Announce a gathering. Move a character to the next chapter of their story.

<GM> AzerothAI

Welcome to your world.

.announce An adventure awaits...
} {page==='World Monitor'&&} {page==='Bots'&&<>
setQuery(e.target.value)}/>{visible.length} characters
{visible.length?botTable(visible):
No matching bots. Create a character or adjust your filters.
}
} {page==='Bot Recipes'&&<>
Recipes are versioned. Saving a recipe preserves existing bots’ personalities until you explicitly apply the new version.
{state.recipes.map((r,i)=>)}
} {page==='Realm Director'&&
} {page==='World & Housing'&&
} {page==='Memory & Bonds'&&
{state.bots.map(b=>setBotId(b.id)}>Open profile}>

{b.memories.length} memories · {b.relationships.length} relationships

{b.memories.at(-1)?.text??'No memories yet.'}

{b.relationships.map(r=>

{state.bots.find(x=>x.id===r.targetId)?.name} · {r.affinity>0?'+':''}{r.affinity} affinity
{r.note}

)}
)}
} {page==='Social Life'&&} {page==='System Health'&&} {page==='Event Stream'&&} {page==='Server & Models'&&
} {page==='GM Console'&&
} }

AzerothAI shapes identity and intent. AzerothCore owns the rules of the world.

Create a characterStart with an identity and recipe. Spawn when you’re ready.{state&&setCreateOpen(false)}/>} {readOnly?'Bot recipe':recipe?'Edit bot recipe':'Create bot recipe'}Traits guide high-level decisions. They never override game rules.
setRecipeOpen(false)}/>
{if(!o)setBotId(null)}}>Bot profileIdentity, intent, and the story so far.{selected&&state&&} {if(!o)setConfirm(null)}}>{confirm?.title}{confirm?.description}Cancel{if(confirm)perform(confirm.action);setConfirm(null)}}>Confirm
; } function CreateBot({state,act,busy,close}:any){const [name,setName]=useState(''),[role,setRole]=useState('Priest'),[race,setRace]=useState('Human'),[recipeId,setRecipeId]=useState(state.recipes[0].id),[goal,setGoal]=useState(`Support ${state.director.experience.toLowerCase()} in ${state.director.zone}`);return
{e.preventDefault();try{await act({type:'createBot',name,role,race,recipeId,goal});toast.success('Character created');close();}catch{}}}>