const FILE_PROTOCOL_MESSAGE = ` Three.js modules cannot boot from file://.
Serve the Nexus over HTTP, for example:
python3 -m http.server 8888 `; function setText(node, text) { if (node) node.textContent = text; } function setHtml(node, html) { if (node) node.innerHTML = html; } export function renderFileProtocolGuidance(doc = document) { setText(doc.querySelector('.loader-subtitle'), 'Serve this world over HTTP to initialize Three.js.'); const bootMessage = doc.getElementById('boot-message'); if (bootMessage) { bootMessage.style.display = 'block'; setHtml(bootMessage, FILE_PROTOCOL_MESSAGE.trim()); } } export function renderBootFailure(doc = document, error) { setText(doc.querySelector('.loader-subtitle'), 'Nexus boot failed. Check console logs.'); const bootMessage = doc.getElementById('boot-message'); if (bootMessage) { bootMessage.style.display = 'block'; setHtml(bootMessage, `Boot error: ${error?.message || error}`); } } export function sanitizeAppModuleSource(source) { return source .replace(/;\\n(\s*)/g, ';\n$1') .replace(/import\s*\{[\s\S]*?\}\s*from '\.\/nexus\/symbolic-engine\.js';\n?/, '') .replace( /\n \}\n \} else if \(data\.type && data\.type\.startsWith\('evennia\.'\)\) \{\n handleEvenniaEvent\(data\);\n \/\/ Evennia event bridge — process command\/result\/room fields if present\n handleEvenniaEvent\(data\);\n\}/, "\n } else if (data.type && data.type.startsWith('evennia.')) {\n handleEvenniaEvent(data);\n }\n}" ) .replace( /\/\*\*[\s\S]*?Called from handleHermesMessage for any message carrying evennia metadata\.\n \*\/\nfunction handleEvenniaEvent\(data\) \{[\s\S]*?\n\}\n\n\n\/\/ ═══════════════════════════════════════════/, "// ═══════════════════════════════════════════" ) .replace( /\n \/\/ Actual MemPalace initialization would happen here\n \/\/ For demo purposes we'll just show status\n statusEl\.textContent = 'Connected to local MemPalace';\n statusEl\.style\.color = '#4af0c0';\n \n \/\/ Simulate mining process\n mineMemPalaceContent\("Initial knowledge base setup complete"\);\n \} catch \(err\) \{\n console\.error\('Failed to initialize MemPalace:', err\);\n document\.getElementById\('mem-palace-status'\)\.textContent = 'MemPalace ERROR';\n document\.getElementById\('mem-palace-status'\)\.style\.color = '#ff4466';\n \}\n try \{/, "\n try {" ) .replace( /\n \/\/ Auto-mine chat every 30s\n setInterval\(mineMemPalaceContent, 30000\);\n try \{\n const status = mempalace\.status\(\);\n document\.getElementById\('compression-ratio'\)\.textContent = status\.compression_ratio\.toFixed\(1\) \+ 'x';\n document\.getElementById\('docs-mined'\)\.textContent = status\.total_docs;\n document\.getElementById\('aaak-size'\)\.textContent = status\.aaak_size \+ 'B';\n \} catch \(error\) \{\n console\.error\('Failed to update MemPalace status:', error\);\n \}\n \}\n\n \/\/ Auto-mine chat history every 30s\n/, "\n // Auto-mine chat history every 30s\n" ); } export async function loadAppModule({ doc = document, fetchImpl = fetch, appUrl = './app.js', } = {}) { const response = await fetchImpl(appUrl, { cache: 'no-store' }); if (!response.ok) { throw new Error(`Failed to load ${appUrl}: ${response.status}`); } const source = sanitizeAppModuleSource(await response.text()); const script = doc.createElement('script'); script.type = 'module'; script.textContent = source; return await new Promise((resolve, reject) => { script.onload = () => resolve(script); script.onerror = () => reject(new Error(`Failed to execute ${appUrl}`)); doc.body.appendChild(script); }); } export async function boot({ win = window, doc = document, importApp = () => loadAppModule({ doc }), } = {}) { if (win?.location?.protocol === 'file:') { renderFileProtocolGuidance(doc); return { mode: 'file' }; } try { await importApp(); return { mode: 'imported' }; } catch (error) { renderBootFailure(doc, error); throw error; } } if (typeof window !== 'undefined' && typeof document !== 'undefined') { boot().catch((error) => { console.error('Nexus boot failed:', error); }); }