const pageCache = {};
function loadScript(src) {
return new Promise((resolve, reject) => {
if (pageCache[src]) { resolve(pageCache[src]); return; }
const script = document.createElement('script');
script.src = src;
script.onload = () => { pageCache[src] = true; resolve(); };
script.onerror = () => reject(new Error(`Failed to load ${src}`));
document.body.appendChild(script);
});
}
async function navigate(page) {
const hash = page || window.location.hash.slice(1) || 'dashboard';
const content = document.getElementById('pageContent');
document.querySelectorAll('.nav-item').forEach(el => el.classList.remove('active'));
const navItem = document.querySelector(`[data-page="${hash}"]`);
if (navItem) navItem.classList.add('active');
content.innerHTML = '
Loading...
';
try {
switch (hash) {
case 'dashboard':
content.innerHTML = 'Loading dashboard...
';
await loadScript('pages/dashboard.js');
content.innerHTML = '';
renderDashboard();
break;
case 'skills':
content.innerHTML = 'Loading skills...
';
await loadScript('pages/skills.js');
content.innerHTML = '';
renderSkills();
break;
case 'memory':
content.innerHTML = 'Loading memory...
';
await loadScript('pages/memory.js');
content.innerHTML = '';
renderMemory();
break;
case 'scheduler':
content.innerHTML = 'Loading scheduler...
';
await loadScript('pages/scheduler.js');
content.innerHTML = '';
renderScheduler();
break;
case 'audit':
content.innerHTML = 'Loading audit...
';
await loadScript('pages/audit.js');
content.innerHTML = '';
renderAudit();
break;
case 'cost':
content.innerHTML = 'Loading cost analytics...
';
await loadScript('pages/cost-analytics.js');
content.innerHTML = '';
renderCostAnalytics();
break;
case 'plugins':
content.innerHTML = 'Loading plugins...
';
await loadScript('pages/plugins.js');
content.innerHTML = '';
renderPlugins();
break;
case 'backups':
content.innerHTML = 'Loading backups...
';
await loadScript('pages/backups.js');
content.innerHTML = '';
renderBackups();
break;
case 'prompts':
content.innerHTML = 'Loading prompts...
';
await loadScript('pages/prompts.js');
content.innerHTML = '';
renderPrompts();
break;
case 'standards':
content.innerHTML = 'Loading standards...
';
await loadScript('pages/standards.js');
content.innerHTML = '';
renderStandards();
break;
case 'settings':
content.innerHTML = 'Loading settings...
';
await loadScript('pages/settings.js');
content.innerHTML = '';
renderSettings();
break;
default:
content.innerHTML = '';
}
} catch (err) {
content.innerHTML = `⚠
Error loading page
${escapeHtml(err.message)}
`;
console.error(err);
}
}
async function updateAgentStatus() {
try {
const status = await api.getStatus();
const el = document.getElementById('agentStatus');
const agents = status.agents || [];
const allOnline = agents.every(a => a.status === 'online');
const anyOnline = agents.some(a => a.status === 'online');
el.innerHTML = `
${agents.filter(a => a.status === 'online').length}/${agents.length} agents online
`;
} catch {
document.getElementById('agentStatus').innerHTML = 'Offline';
}
}
window.addEventListener('hashchange', () => navigate());
window.addEventListener('DOMContentLoaded', () => {
loadTheme();
navigate(window.location.hash.slice(1) || 'dashboard');
updateAgentStatus();
setInterval(updateAgentStatus, 30000);
});