// ========================================== // Chat Switchboard – Application (Chat Surface) // ========================================== // Boot, auth, init, listener dispatch. // Shared state (App) and model loading (fetchModels) live in app-state.js // (loaded by base.html for all surfaces). // Domain logic lives in chat.js, notes.js, settings-handlers.js, // admin-handlers.js. UI rendering in ui-*.js files. async function init() { console.log('🔀 Chat Switchboard initializing...'); initBranding(); // Apply branding before splash is visible API.loadTokens(); let health = null; try { health = await API.health(); console.log('✅ Backend reachable:', health.version); } catch (e) { console.error('❌ Backend unreachable:', e.message); const splashErr = document.getElementById('splashError'); if (e.proxyBlocked) { splashErr.innerHTML = `Network proxy blocked this request
` + `Proxy response: "${API._esc(e.proxyTitle)}"
` + `Ask your network admin to whitelist this domain. ` + `Run diagnostics`; } else if (e.name === 'TimeoutError' || e.name === 'AbortError') { splashErr.innerHTML = `Connection timed out
` + `Server may be starting up, or a proxy is blocking the connection. ` + `Run diagnostics`; } else { splashErr.innerHTML = `Cannot reach server
` + `${API._esc(e.message)}. ` + `Run diagnostics`; } showSplash(null); return; } if (API.isAuthed) { try { await API.getProfile(); console.log('✅ Session valid for', API.user?.username); } catch (e) { console.warn('⚠️ Session expired, clearing'); API.clearTokens(); } } if (API.isAuthed) { try { await startApp(); } catch (e) { console.error('💥 startApp crashed:', e); // Surface the error visibly (crash banner from chat.html) const b = document.getElementById('crashBanner'); const d = document.getElementById('crashDetail'); if (b && d) { b.style.display = ''; d.textContent += 'startApp: ' + e.message + '\n' + (e.stack || '') + '\n'; } } } else { showSplash(health); } } async function startApp() { hideSplash(); UI.restoreSidebar(); await loadSettings(); // Load extensions BEFORE chats so block renderers (mermaid, katex, csv, diff) // are registered when messages are first rendered. try { await Extensions.loadAll(); // fetch manifests + inject