// module-world-model.js — Global World Model: system self-awareness synthesis engine // Aggregates from memory graph, neural VFS, skills index, telemetry // Commands: world-model, world-model-summary, world-model-ask, world-model-refresh, world-model-config class WorldModelModule { constructor() { this.commands = {}; this.terminal = null; this._model = null; this._lastRefresh = null; this._REFRESH_INTERVAL = 300000; // 5 minutes this._MAX_PROJECTS = 10; this._refreshTimer = null; } getHelpInfo() { return { 'world-model': 'world-model — Show full world model as structured output', 'world-model-summary': 'world-model-summary — One-line system self-awareness statement', 'world-model-ask': 'world-model-ask — Query the model (e.g. "what changed since yesterday")', 'world-model-refresh': 'world-model-refresh — Force re-synthesis from all subsystems', 'world-model-config': 'world-model-config — Tune: refresh-interval, max-projects', }; } registerCommands() { this.commands['world-model'] = () => this.showModel(); this.commands['world-model-summary'] = () => this.showSummary(); this.commands['world-model-ask'] = (args) => this.ask(args.join(' ')); this.commands['world-model-refresh'] = () => this.refresh(); this.commands['world-model-config'] = (args) => this.setConfig(args); } init(terminal) { this.terminal = terminal; this._loadFromVFS(); // Deferred initial synthesis — wait for ext modules (SkillPackCore etc) to fully load setTimeout(() => { this._synthesize(); this.terminal.print('🌐 World Model synthesized — system self-awareness active', 'info'); // Second pass after ext modules definitely finished loading setTimeout(() => { this._synthesize(); this.terminal.print('🌐 World Model refresh — full module load confirmed', 'info'); }, 7000); }, 5000); // Auto-refresh on a timer this._refreshTimer = setInterval(() => { const age = Date.now() - (this._lastRefresh ? new Date(this._lastRefresh).getTime() : 0); if (age > this._REFRESH_INTERVAL) this._synthesize(); }, this._REFRESH_INTERVAL); this.terminal.print('🌐 World Model loaded — system self-awareness active', 'info'); } // ─── Synthesis Engine ─── _synthesize() { try { const fs = this.terminal.fs; if (!fs) return; // Derive version from actual system state — no hardcoded strings const mInfo = this._gatherModuleInfo(); const agentInfo = this._gatherAgentInfo(); const fileInfo = this._gatherFileInfo(fs); const skillInfo = this._gatherSkillInfo(fs); const liveVersion = this._deriveVersion(mInfo); const model = { version: liveVersion, synthesized: new Date().toISOString(), system: this._gatherSystemInfo(fs, mInfo.loaded, liveVersion), modules: mInfo, files: fileInfo, skills: skillInfo, memory: this._gatherMemoryInfo(), agents: agentInfo, telemetry: this._gatherTelemetry(fs), projects: this._gatherProjects(fs), recent: this._gatherRecent(fs) }; this._model = model; this._lastRefresh = model.synthesized; this._saveToVFS(fs); // Log synthesis summary const mCount = model.modules?.loaded || '?'; const sCount = model.skills?.count || '?'; const fCount = model.files?.total || '?'; console.log(`[WorldModel] Synthesis complete: ${mCount} modules, ${sCount} skills, ${fCount} files`); } catch (e) { console.error('[WorldModel] Synthesis error:', e.message); } } _deriveVersion(mInfo) { // Single source of truth: the constant set at bootstrap if (window.NEWOS4_VERSION) return window.NEWOS4_VERSION; // Fallback: try to extract from script tag ?v= query param or LATEST_VER constant try { const scripts = document.querySelectorAll('script[src*="module-loader"]'); for (const s of scripts) { const match = s.src.match(/[?&]v=([^&]+)/); if (match) return match[1]; } // Try to find LATEST_VER in any inline script const allScripts = document.querySelectorAll('script:not([src])'); for (const s of allScripts) { const match = s.textContent.match(/LATEST_VER\s*=\s*['"]([^'"]+)['"]/); if (match) return match[1]; } } catch (e) { console.warn('[WorldModel] Version extraction error:', e.message); } return 'v?'; } _getTotalModules() { try { const mm = this.terminal?.moduleManager; if (!mm) return 0; // Count registry entries (all known modules) vs loaded const registry = mm.moduleRegistry || []; return registry.length || Object.keys(mm.modules || {}).length; } catch (e) { console.warn('[WorldModel] Total modules gather error:', e.message); return Object.keys(this.terminal?.moduleManager?.modules || {}).length || 0; } } _gatherSystemInfo(fs, moduleCount, version) { // Get real health data from ServerMonitorModule's _latencyLog and AI assistant's _errorLog const sm = this.terminal?.moduleManager?.modules?.['ServerMonitorModule']; const ai = this.terminal?.moduleManager?.modules?.['WebX11AIAssistantModule']; const errorCount = ai?._errorLog?.length || 0; const latencyErrors = sm?._latencyLog ? Object.values(sm._latencyLog).filter(e => e.status === 'error').length : 0; const totalErrors = errorCount + latencyErrors; return { version: `newOS4 ${version}`, modules: moduleCount || Object.keys(this.terminal?.moduleManager?.modules || {}).length || 0, vfsSize: JSON.stringify(fs?.root || {}).length, online: typeof navigator !== 'undefined' ? navigator.onLine : true, memory: typeof performance !== 'undefined' && performance.memory ? `${(performance.memory.usedJSHeapSize / 1048576).toFixed(1)}MB` : 'N/A', health: totalErrors > 0 ? `⚠️ ${totalErrors} errors` : 'OK', lastHealthCheck: new Date().toISOString() }; } _gatherModuleInfo() { const mm = this.terminal?.moduleManager; if (!mm) return { loaded: 0, modified: [] }; const modules = Object.keys(mm.modules || {}).map(name => { const mod = mm.modules[name]; const clsName = mod?.constructor?.name || name; return { name: clsName, hasCommands: !!mod?.commands }; }); // Check for local modifications const modsDir = this.terminal.fs?.readDir('/_mods/'); const modified = modsDir ? modsDir.filter(e => e.type === 'file' && e.name.endsWith('.js') && !e.name.endsWith('.orig.js')) .map(e => e.name.replace('.js', '')) : []; return { loaded: modules.length, total: this._getTotalModules(), modules, modified, modifiedCount: modified.length }; } _gatherFileInfo(fs) { if (!fs) return { total: 0, size: '0KB' }; let fileCount = 0, dirCount = 0; const walk = (path) => { const entries = fs.ls(path); if (!entries) return; for (const e of entries) { if (e.type === 'file') fileCount++; else { dirCount++; walk(path === '/' ? '/' + e.name : path + '/' + e.name); } } }; walk('/'); return { total: fileCount, directories: dirCount, size: `${(JSON.stringify(fs.root).length / 1024).toFixed(1)}KB` }; } _gatherSkillInfo(fs) { try { const idx = fs.fsReadJSON('/skills/index.json'); const count = idx ? Object.keys(idx).length : 0; return { count, skills: idx ? Object.keys(idx) : [] }; } catch (e) { console.warn('[WorldModel] Skill info gather error:', e.message); return { count: 0, skills: [] }; } } _gatherMemoryInfo() { const mg = this.terminal?.moduleManager?.modules?.['MemoryGraphModule']; if (mg && mg._nodes) { const nodes = Object.keys(mg._nodes).length; const edges = (mg._edges || []).length; return { nodes, edges, active: true, fallback: false }; } // Fallback: count memory files try { const memIndex = this.terminal.fs?.fsReadJSON('/memory/index.json'); return { nodes: memIndex ? Object.keys(memIndex).length : 0, edges: 0, active: false, fallback: true }; } catch (e) { console.warn('[WorldModel] Memory info gather error:', e.message); return { nodes: 0, edges: 0, active: false, fallback: true }; } } _gatherAgentInfo() { const orch = this.terminal?.moduleManager?.modules?.['OrchestratorModule']; if (!orch || !orch._agents) return { agents: -1, active: -1, error: 'Orchestrator not loaded' }; const agents = Object.keys(orch._agents).length; const active = Object.values(orch._agents).filter(a => a.status === 'busy').length; return { agents, active, totalLeases: Object.keys(orch._a2aMessages || {}).length }; } _gatherTelemetry(fs) { try { // Get real latency data from ServerMonitorModule and errors from AI assistant const sm = this.terminal?.moduleManager?.modules?.['ServerMonitorModule']; const ai = this.terminal?.moduleManager?.modules?.['WebX11AIAssistantModule']; const latencyDataPoints = sm?._latencyLog ? Object.keys(sm._latencyLog).length : 0; const recentErrors = ai?._errorLog?.length || 0; return { toolLatencyDataPoints: latencyDataPoints, recentErrors: recentErrors, }; } catch (e) { console.warn('[WorldModel] Telemetry gather error:', e.message); return { toolLatencyDataPoints: 0, recentErrors: 0 }; } } _gatherProjects(fs) { try { const mg = this.terminal?.moduleManager?.modules?.['MemoryGraphModule']; if (mg && mg._nodes) { // Find task clusters as "projects" const tasks = Object.values(mg._nodes).filter(n => n.type === 'task'); const recentFiles = Object.values(mg._nodes) .filter(n => n.type === 'file') .sort((a, b) => (b.access_count || 0) - (a.access_count || 0)) .slice(0, this._MAX_PROJECTS); return { totalTasks: tasks.length, activeProjects: recentFiles.slice(0, 5).map(f => ({ name: f.label, accesses: f.access_count || 0, lastModified: f.updated })) }; } return { totalTasks: 0, activeProjects: [] }; } catch (e) { console.warn('[WorldModel] Projects gather error:', e.message); return { totalTasks: 0, activeProjects: [] }; } } _gatherRecent(fs) { const recent = []; try { // Check modified modules const modsDir = fs.readDir('/_mods/'); if (modsDir) { for (const e of modsDir) { if (e.type === 'file' && e.name.endsWith('.js') && !e.name.endsWith('.orig.js') && !e.name.endsWith('.meta.json')) { recent.push(`Modified module: ${e.name.replace('.js', '')}`); } } } // Check skills activity const skills = fs.ls('/skills/'); if (skills && skills.length > 0) { recent.push(`Skills directory: ${skills.filter(s => s.type === 'file').length} files`); } // Check memory directory for recent changes const memDir = fs.readDir('/memory/'); if (memDir && memDir.length > 0) { const memFiles = memDir.filter(s => s.type === 'file'); if (memFiles.length > 0) { recent.push(`Memory: ${memFiles.length} files in /memory/`); } } // Check system config changes const sysDir = fs.readDir('/system/'); if (sysDir && sysDir.length > 0) { const configFiles = sysDir.filter(s => s.type === 'file' && s.name.endsWith('.json')); if (configFiles.length > 0) { recent.push(`System config: ${configFiles.length} config files`); } } } catch (e) { console.warn('[WorldModel] Recent gather error:', e.message); } return recent; } // ─── Commands ─── showModel() { if (!this._model) return this.terminal.print('No model yet — run world-model-refresh', 'warning'); const m = this._model; this.terminal.print('🌐 World Model', 'header'); this.terminal.print(` Version: ${m.version} (last synthsized: ${new Date(m.synthesized).toLocaleTimeString()})`, 'info'); this.terminal.print(` ⚙️ System — ${m.system.modules} modules loaded, ${m.system.vfsSize} VFS, ${m.system.memory}`, 'info'); this.terminal.print(` 🧩 Modules — ${m.modules.loaded} loaded (${m.modules.modifiedCount} modified)`, 'info'); this.terminal.print(` 📁 Files — ${m.files.total} files, ${m.files.directories} dirs, ${m.files.size}`, 'info'); this.terminal.print(` 📚 Skills — ${m.skills.count} installed`, 'info'); this.terminal.print(` 🧠 Memory Graph — ${m.memory.nodes} nodes, ${m.memory.edges} edges${m.memory.active ? ' ✅' : ''}`, 'info'); this.terminal.print(` 🤖 Agents — ${m.agents.agents} registered (${m.agents.active} active)`, 'info'); this.terminal.print(` 📊 Telemetry — ${m.telemetry.toolLatencyDataPoints} tool latency points, ${m.telemetry.recentErrors} recent errors`, 'info'); if (m.projects.activeProjects.length > 0) { this.terminal.print(' Active context:', 'header'); for (const p of m.projects.activeProjects.slice(0, 3)) { this.terminal.print(` 📌 ${p.name} (${p.accesses}x accesses)`, 'info'); } } if (m.recent.length > 0) { this.terminal.print(' Recent changes:', 'header'); for (const r of m.recent.slice(0, 3)) { this.terminal.print(` ${r}`, 'info'); } } } showSummary() { if (!this._model) return this.terminal.print('No model yet', 'warning'); const m = this._model; const summary = `newOS4 ${m.version} · ${m.modules.loaded}/${m.modules.total} modules · ${m.skills.count} skills · ${m.files.total} files · ${m.agents.agents} agents · ${m.memory.nodes} graph nodes · ${m.telemetry.recentErrors > 0 ? `⚠️ ${m.telemetry.recentErrors} errors` : '✅ OK'}`; this.terminal.print(summary, 'info'); return summary; } ask(question) { if (!question) return this.terminal.print('Usage: world-model-ask ', 'error'); if (!this._model) return this.terminal.print('No model — run world-model-refresh first', 'warning'); const q = question.toLowerCase(); const m = this._model; let answer = ''; if (q.includes('module') || q.includes('loaded')) { answer = `Loaded ${m.modules.loaded} modules (${m.modules.modifiedCount} modified: ${m.modules.modified.join(', ') || 'none'})`; } else if (q.includes('skill')) { answer = `Installed ${m.skills.count} skills: ${m.skills.skills.join(', ') || 'none'}`; } else if (q.includes('file') || q.includes('vfs')) { answer = `${m.files.total} files in ${m.files.directories} directories, total ${m.files.size}`; } else if (q.includes('agent') || q.includes('orchestrat')) { answer = `${m.agents.agents} agents (${m.agents.active} active)`; } else if (q.includes('health') || q.includes('status')) { answer = `Health: ${m.system.health} · Memory: ${m.system.memory} · ${m.telemetry.recentErrors > 0 ? `${m.telemetry.recentErrors} recent errors` : 'No errors'}`; } else if (q.includes('memory') || q.includes('graph')) { answer = `Memory Graph: ${m.memory.nodes} nodes, ${m.memory.edges} edges (${m.memory.active ? 'active' : 'inactive'})`; } else if (q.includes('change') || q.includes('yesterday') || q.includes('recent')) { const recent = m.recent; answer = recent.length > 0 ? `Recent changes: ${recent.join('; ')}` : 'No recent changes detected'; } else if (q.includes('project') || q.includes('work')) { const projects = m.projects.activeProjects; answer = projects.length > 0 ? `Active projects: ${projects.map(p => `${p.name} (${p.accesses}x)`).join(', ')}` : 'No active projects detected'; } else if (q.includes('telemetry') || q.includes('latency')) { answer = `${m.telemetry.toolLatencyDataPoints} tool latency data points tracked`; } else if (q.includes('summary') || q.includes('overview') || q.includes('all')) { answer = this.showSummary(); return; } else { answer = `I'm not sure how to answer "${question}". Try: modules, skills, files, agents, health, memory, changes, projects, telemetry, or summary.`; } this.terminal.print(`❓ ${question}`, 'info'); this.terminal.print(`💡 ${answer}`, 'success'); } refresh() { this._synthesize(); this.terminal.print(`✅ World Model refreshed at ${new Date().toLocaleTimeString()}`, 'success'); } setConfig(args) { if (args.length < 2) return this.terminal.print('Usage: world-model-config ', 'error'); const key = args[0]; const val = args[1]; const configMap = { 'refresh-interval': () => { const n = parseInt(val) * 1000; if (isNaN(n) || n < 10000) return 'Must be >= 10 seconds'; this._REFRESH_INTERVAL = n; if (this._refreshTimer) clearInterval(this._refreshTimer); this._refreshTimer = setInterval(() => this._synthesize(), n); return `refresh-interval set to ${val}s`; }, 'max-projects': () => { const n = parseInt(val); if (isNaN(n) || n < 1) return 'Must be >= 1'; this._MAX_PROJECTS = n; return `max-projects set to ${n}`; }, }; if (!configMap[key]) return this.terminal.print(`Unknown: ${key}. Valid: ${Object.keys(configMap).join(', ')}`, 'error'); const msg = configMap[key](); this.terminal.print(`✅ ${msg}`, 'success'); } // ─── Context Injection ─── getContextForPrompt() { if (!this._model) return ''; const m = this._model; const agentStr = m.agents.error ? 'agents: N/A' : `${m.agents.agents} agents`; return `[World Model Context]\\nSystem: newOS4 ${m.version} · ${m.modules.loaded} modules · ${m.skills.count} skills · ${m.files.total} files · ${agentStr}${m.telemetry.recentErrors > 0 ? ` · ⚠️ ${m.telemetry.recentErrors} errors` : ' · ✅ OK'}${m.modules.modifiedCount > 0 ? `\\nModified modules: ${m.modules.modified.slice(0, 3).join(', ')}${m.modules.modifiedCount > 3 ? ` (+${m.modules.modifiedCount - 3} more)` : ''}` : ''}`; } // ─── Persistence ─── _loadFromVFS() { try { const fs = this.terminal.fs; if (!fs) return; const data = fs.fsReadJSON('/system/world-model.json'); if (data) { this._model = data; this._lastRefresh = data.synthesized; } } catch (e) { console.warn('[WorldModel] Load error (fresh start):', e.message); } } _saveToVFS(fs) { try { if (!fs.readDir('/system')) fs.mkdir('system'); fs.fsWriteJSON('/system/world-model.json', this._model); } catch (e) { console.error('[WorldModel] Save error:', e.message); } } } // Required for module system if (typeof window !== 'undefined') { window.WorldModelModule = WorldModelModule; }