// Extracted from newOS4 index.html — SystemModule class SystemModule { constructor() { this.commands = {}; this.terminal = null; } getHelpInfo() { return { 'help': 'help [command] — Show all commands or usage for a specific command', 'echo': 'echo — Print text to the terminal', 'mem': 'mem — Show memory usage (heap + localStorage + VFS)', 'status': 'status — Display system status (network, files, modules, Ollama)', 'version': 'version — Show version, build date, and cache key', 'uptime': 'uptime — Show time since page load + last save time', 'errors': 'errors [n] — Show last n ERROR log entries (default: 20)', 'doctor': 'doctor — Run all health checks, rank issues, show top 3 warnings', 'bug-report': 'bug-report — Generate a markdown bug report to /tmp/ for debugging', 'preview': 'preview — Render an HTML file from the VFS in a preview pane', 'factory-reset': 'factory-reset [--confirm] — Wipe all webx11_ data (VFS, config, AI profile, mindmaps, themes, all localStorage)', 'reset-vfs': 'reset-vfs [--confirm] — Clear only the virtual filesystem (keeps settings, modules, AI profile)', 'logs': 'logs [n] [LEVEL] — Show last n log entries (optionally filtered by level: INFO/WARN/ERROR)', 'logrotate': 'logrotate — Rotate current.log to a dated archive (auto-cleans old)', 'health-check': 'health-check — Audit VFS size, modules, logs, trash, skills, tool failures', 'memory-map-export': 'memory-map-export — Export memory index to /memory/reference.md (overwrites file)', 'font-size': 'font-size <8-32> — Set terminal font size (persists across sessions)', 'setfont': 'setfont <8-32> — Alias for font-size', 'smart-prompt': 'smart-prompt [on|off] — Toggle context-aware prompt (shows name, skills, sessions, memory, edits)', 'checkpoint': 'checkpoint [name] — Create a VFS snapshot (name defaults to ISO timestamp)', 'checkpoint-list': 'checkpoint-list — List all VFS checkpoints', 'rollback': 'rollback — Restore VFS from a checkpoint', 'checkpoint-del': 'checkpoint-del — Delete a VFS checkpoint', }; } registerCommands() { this.commands['help'] = (args) => this.handleHelp(args); this.commands['echo'] = (args) => this.terminal.print(args.join(' ')); this.commands['mem'] = () => { const heap = performance.memory ? (performance.memory.usedJSHeapSize / 1048576).toFixed(2) : 'N/A'; const heapLimit = performance.memory ? (performance.memory.jsHeapSizeLimit / 1048576).toFixed(0) : 'N/A'; // localStorage size let lsBytes = 0; try { for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i); if (k) lsBytes += (k.length + (localStorage.getItem(k) || '').length) * 2; } } catch (e) {} const lsKB = (lsBytes / 1024).toFixed(1); // VFS size (in-memory) let vfsBytes = 0; try { vfsBytes = JSON.stringify(this.terminal.fs.root).length; } catch (e) {} const vfsKB = (vfsBytes / 1024).toFixed(1); // sessionStorage size let ssBytes = 0; try { for (let i = 0; i < sessionStorage.length; i++) { const k = sessionStorage.key(i); if (k) ssBytes += (k.length + (sessionStorage.getItem(k) || '').length) * 2; } } catch (e) {} const ssKB = (ssBytes / 1024).toFixed(1); // Total const total = (parseFloat(heap === 'N/A' ? '0' : heap) + parseFloat(lsKB) + parseFloat(ssKB) + parseFloat(vfsKB)).toFixed(1); this.terminal.print('💾 Memory Usage', 'header'); this.terminal.print(` JS heap: ${heap} MB${heap !== 'N/A' ? ' / ' + heapLimit + ' MB limit' : ''}`, parseFloat(heap) > 100 ? 'warning' : ''); this.terminal.print(` localStorage: ${lsKB} KB (${localStorage.length} keys)`, parseFloat(lsKB) > 1024 ? 'warning' : ''); this.terminal.print(` sessionStorage: ${ssKB} KB (${sessionStorage.length} keys)`, ''); this.terminal.print(` VFS in-memory: ${vfsKB} KB`, parseFloat(vfsKB) > 256 ? 'warning' : ''); this.terminal.print(` Total: ${total} MB`, ''); document.getElementById('header-status').innerText = `Mem: ${heap}MB`; }; // Refresh memory display on boot setTimeout(() => { if (performance.memory) { const mem = (performance.memory.usedJSHeapSize / 1048576).toFixed(1); document.getElementById('header-status').innerText = `Mem: ${mem}MB`; } }, 500); this.commands['status'] = () => { this.terminal.print(`System: WebX11 ${window.NEWOS4_VERSION || 'v4.0'}`); this.terminal.print(`Network: ${navigator.onLine ? 'Online' : 'Offline'}`); this.terminal.print(`Files: ${this.terminal.fs.ls().length} items`); this.terminal.print(`Modules: ${Object.keys(this.terminal.moduleManager.modules).length} loaded`); this.terminal.print(`Ollama: ${this.terminal.ollamaManager.connected ? 'Connected' : 'Disconnected'}`); }; // v4.5.43: version — show version, build date, cache key this.commands['version'] = () => { const v = window.NEWOS4_VERSION || 'unknown'; const cacheKey = localStorage.getItem('webx11_cache_ver') || 'unknown'; // Try to get build date from script tag or module list const buildDate = (() => { try { const scripts = document.querySelectorAll('script[src*="v="]'); for (const s of scripts) { const m = s.src.match(/v=([0-9-]+-v[0-9.]+[a-z]?)/); if (m) return m[1].split('-').slice(0, 3).join('-'); } } catch (e) {} return 'unknown'; })(); const ua = navigator.userAgent.split(' ').slice(-1)[0] || 'unknown'; this.terminal.print('ℹ️ WebX11 newOS4', 'header'); this.terminal.print(` Version: ${v}`); this.terminal.print(` Build: ${buildDate}`); this.terminal.print(` Cache key: ${cacheKey}`); this.terminal.print(` Browser: ${ua}`); this.terminal.print(` Online: ${navigator.onLine ? 'yes' : 'no'}`); }; // v4.5.43: uptime — time since page load + last save time this.commands['uptime'] = () => { const loadTime = performance.timeOrigin || Date.now() - (window.__pageLoadMs || 0); const ms = Date.now() - loadTime; const s = Math.floor(ms / 1000); const days = Math.floor(s / 86400); const hours = Math.floor((s % 86400) / 3600); const mins = Math.floor((s % 3600) / 60); const secs = s % 60; let uptime; if (days > 0) uptime = `${days}d ${hours}h ${mins}m`; else if (hours > 0) uptime = `${hours}h ${mins}m ${secs}s`; else if (mins > 0) uptime = `${mins}m ${secs}s`; else uptime = `${secs}s`; this.terminal.print('⏱️ Uptime', 'header'); this.terminal.print(` Since load: ${uptime} (${s}s)`); // Check last save time from localStorage modification try { const lastSave = localStorage.getItem('webx11_last_save'); if (lastSave) { const ago = Math.floor((Date.now() - parseInt(lastSave)) / 1000); this.terminal.print(` Last save: ${ago}s ago`, ago > 300 ? 'warning' : ''); } else { this.terminal.print(` Last save: unknown`, 'info'); } } catch (e) {} }; // v4.5.43: errors [n] — alias for logs [n] ERROR this.commands['errors'] = (args) => { const n = parseInt(args[0]) || 20; const content = this.terminal.fs.readFile('/logs/current.log'); if (!content) { this.terminal.print('No logs yet', 'info'); return; } const lines = content.split('\n').filter(l => l && l.includes('[ERROR]')); const tail = lines.slice(-n); if (tail.length === 0) { this.terminal.print('✅ No errors found in logs', 'success'); return; } this.terminal.print(`--- Errors (last ${tail.length}) ---`, 'error'); tail.forEach(l => this.terminal.print(l, 'error')); }; // v4.5.43: doctor — run all health checks, rank issues, show top 3 this.commands['doctor'] = () => { const issues = []; const fs = this.terminal.fs; // Check 1: Network if (!navigator.onLine) issues.push({ severity: 'high', msg: 'Network: offline' }); // Check 2: Ollama if (!this.terminal.ollamaManager.connected) { issues.push({ severity: 'medium', msg: 'Ollama: not connected (AI features limited)' }); } // Check 3: VFS size try { const vfsBytes = JSON.stringify(fs.root).length; if (vfsBytes > 524288) issues.push({ severity: 'high', msg: `VFS: ${(vfsBytes/1024).toFixed(0)}KB > 512KB limit` }); else if (vfsBytes > 262144) issues.push({ severity: 'medium', msg: `VFS: ${(vfsBytes/1024).toFixed(0)}KB > 256KB (consider reset-vfs)` }); } catch (e) {} // Check 4: Heap if (performance.memory) { const heapMB = performance.memory.usedJSHeapSize / 1048576; if (heapMB > 200) issues.push({ severity: 'high', msg: `Heap: ${heapMB.toFixed(0)}MB > 200MB` }); else if (heapMB > 100) issues.push({ severity: 'medium', msg: `Heap: ${heapMB.toFixed(0)}MB > 100MB` }); } // Check 5: Logs try { const logContent = fs.readFile('/logs/current.log') || ''; const logLines = logContent.split('\n').filter(l => l).length; if (logLines > 500) issues.push({ severity: 'low', msg: `Logs: ${logLines} lines (consider logrotate)` }); } catch (e) {} // Check 6: Errors in last 100 log lines try { const logContent = fs.readFile('/logs/current.log') || ''; const recent = logContent.split('\n').filter(l => l).slice(-100); const errorCount = recent.filter(l => l.includes('[ERROR]')).length; if (errorCount > 5) issues.push({ severity: 'high', msg: `Errors: ${errorCount} errors in last 100 log lines` }); else if (errorCount > 0) issues.push({ severity: 'medium', msg: `Errors: ${errorCount} errors in last 100 log lines` }); } catch (e) {} // Check 7: localStorage quota let lsBytes = 0; try { for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i); if (k) lsBytes += (k.length + (localStorage.getItem(k) || '').length) * 2; } } catch (e) {} if (lsBytes > 4 * 1024 * 1024) issues.push({ severity: 'high', msg: `localStorage: ${(lsBytes/1024/1024).toFixed(1)}MB approaching 5MB quota` }); // Check 8: Disabled modules let disabled = []; try { disabled = JSON.parse(localStorage.getItem('webx11_module_disabled') || '[]'); } catch (e) {} if (disabled.length > 0) { issues.push({ severity: 'low', msg: `Disabled modules: ${disabled.length} (${disabled.join(', ')})` }); } this.terminal.print('🩺 Doctor Report', 'header'); if (issues.length === 0) { this.terminal.print(' ✅ All systems healthy', 'success'); return; } // Sort by severity: high > medium > low const sevOrder = { high: 0, medium: 1, low: 2 }; issues.sort((a, b) => sevOrder[a.severity] - sevOrder[b.severity]); this.terminal.print(` Found ${issues.length} issue(s):`, 'warning'); for (const i of issues.slice(0, 5)) { const icon = i.severity === 'high' ? '🔴' : i.severity === 'medium' ? '🟡' : '🟢'; this.terminal.print(` ${icon} [${i.severity.toUpperCase()}] ${i.msg}`, i.severity === 'high' ? 'error' : 'warning'); } if (issues.length > 5) this.terminal.print(` ... and ${issues.length - 5} more`, 'info'); this.terminal.print('', ''); this.terminal.print(' Recommended actions:', 'info'); if (issues.some(i => i.msg.startsWith('Network'))) this.terminal.print(' → Check internet connection'); if (issues.some(i => i.msg.startsWith('Ollama'))) this.terminal.print(' → Check Ollama is running (ollama serve)'); if (issues.some(i => i.msg.startsWith('VFS'))) this.terminal.print(' → Run reset-vfs --confirm to clear or checkpoint/rollback'); if (issues.some(i => i.msg.startsWith('Heap'))) this.terminal.print(' → Refresh the page to clear memory'); if (issues.some(i => i.msg.startsWith('Logs'))) this.terminal.print(' → Run logrotate'); if (issues.some(i => i.msg.startsWith('Errors'))) this.terminal.print(' → Run errors to see details, or bug-report to save state'); if (issues.some(i => i.msg.startsWith('localStorage'))) this.terminal.print(' → Run factory-reset --confirm (last resort)'); }; // v4.5.43: bug-report — generate markdown report to /tmp/ this.commands['bug-report'] = () => { const fs = this.terminal.fs; const lines = []; const ts = new Date().toISOString(); lines.push(`# WebX11 newOS4 Bug Report`); lines.push(`Generated: ${ts}`); lines.push(''); lines.push('## System'); lines.push(`- Version: ${window.NEWOS4_VERSION || 'unknown'}`); lines.push(`- Cache key: ${localStorage.getItem('webx11_cache_ver') || 'unknown'}`); lines.push(`- Online: ${navigator.onLine ? 'yes' : 'no'}`); lines.push(`- Browser: ${navigator.userAgent}`); lines.push(`- Screen: ${screen.width}x${screen.height}`); lines.push(`- Heap: ${performance.memory ? (performance.memory.usedJSHeapSize / 1048576).toFixed(1) + 'MB' : 'N/A'}`); lines.push(`- VFS size: ${(JSON.stringify(fs.root).length / 1024).toFixed(1)}KB`); lines.push(`- Modules loaded: ${Object.keys(this.terminal.moduleManager.modules).length}`); lines.push(`- Ollama: ${this.terminal.ollamaManager.connected ? 'connected' : 'disconnected'}`); lines.push(''); // Uptime const loadTime = performance.timeOrigin || Date.now(); const upSec = Math.floor((Date.now() - loadTime) / 1000); lines.push(`- Uptime: ${upSec}s`); lines.push(''); lines.push('## Recent Errors (last 20)'); try { const logContent = fs.readFile('/logs/current.log') || ''; const errs = logContent.split('\n').filter(l => l && l.includes('[ERROR]')).slice(-20); if (errs.length === 0) lines.push('_No errors found_'); else errs.forEach(e => lines.push('- ' + e)); } catch (e) { lines.push('_Could not read logs_'); } lines.push(''); lines.push('## Recent Commands (last 10)'); try { const hist = JSON.parse(localStorage.getItem('webx11_command_history') || '[]'); const recent = hist.slice(-10); if (recent.length === 0) lines.push('_No history_'); else recent.forEach(c => lines.push('- ' + c)); } catch (e) { lines.push('_No history available_'); } lines.push(''); lines.push('## Disabled Modules'); try { const disabled = JSON.parse(localStorage.getItem('webx11_module_disabled') || '[]'); if (disabled.length === 0) lines.push('_None_'); else disabled.forEach(d => lines.push('- ' + d)); } catch (e) { lines.push('_Unknown_'); } lines.push(''); lines.push('## File List (top-level VFS)'); try { const items = fs.ls(); items.slice(0, 20).forEach(i => lines.push('- ' + i)); if (items.length > 20) lines.push(`- ... and ${items.length - 20} more`); } catch (e) { lines.push('_Could not list_'); } lines.push(''); lines.push('---'); lines.push('Send this file when reporting a bug.'); const content = lines.join('\n'); const filename = `/tmp/bug-report-${Date.now()}.md`; try { fs.writeFile(filename, content); this.terminal.print(`✅ Bug report saved to ${filename}`, 'success'); this.terminal.print(` (${(content.length / 1024).toFixed(1)}KB)`, 'info'); } catch (e) { this.terminal.print(`❌ Could not save bug report: ${e.message}`, 'error'); } }; this.commands['preview'] = (args) => this.terminal.openPreview(args); this.commands['factory-reset'] = (args) => { if (!args[0] || args[0] !== '--confirm') { this.terminal.print('⚠️ FACTORY RESET will clear all data:', 'error'); this.terminal.print(' • Filesystem (all files + directories)', 'warning'); this.terminal.print(' • AI memory, patterns, user profile', 'warning'); this.terminal.print(' • Ollama endpoint, model selection', 'warning'); this.terminal.print(' • Terminal history, font size', 'warning'); this.terminal.print(' • All config, modules, packages', 'warning'); this.terminal.print(' • Mindmaps, notes, bookmarks', 'warning'); this.terminal.print(' • Themes, context profiles, servers', 'warning'); this.terminal.print(' • Chat settings, my data', 'warning'); this.terminal.print('Type: factory-reset --confirm to proceed', 'error'); return; } for (let i = localStorage.length - 1; i >= 0; i--) { const key = localStorage.key(i); if (key && key.startsWith('webx11_')) localStorage.removeItem(key); } this.terminal.fs.root = { type: 'dir', content: {} }; this.terminal.fs.currentPath = []; this.terminal.outputContainer.innerHTML = ''; this.terminal.print('✅ Factory reset complete. Reloading...', 'success'); setTimeout(() => location.reload(), 1000); }; this.commands['reset-vfs'] = (args) => { if (!args[0] || args[0] !== '--confirm') { this.terminal.print('⚠️ RESET VFS will clear all files and directories:', 'warning'); this.terminal.print(' • Virtual filesystem (all files + directories)', 'warning'); this.terminal.print(' • VFS will be reset to empty root', 'warning'); this.terminal.print(' • All settings, modules, AI profile preserved', 'info'); this.terminal.print('Type: reset-vfs --confirm to proceed', 'error'); return; } this.terminal.fs.root = { type: 'dir', content: {} }; this.terminal.fs.currentPath = []; this.terminal.fs.saveToStorage(); this.terminal.print('✅ VFS reset complete. Reloading...', 'success'); setTimeout(() => location.reload(), 1000); }; this.commands['logs'] = (args) => { const n = parseInt(args[0]) || 20; const level = args[1] ? args[1].toUpperCase() : null; const content = this.terminal.fs.readFile('/logs/current.log'); if (!content) { this.terminal.print('No logs yet', 'info'); return; } let lines = content.split('\n').filter(l => l); if (level) lines = lines.filter(l => l.includes('[' + level + ']')); const tail = lines.slice(-n); if (tail.length === 0) { this.terminal.print('No matching log entries', 'info'); return; } this.terminal.print('--- Logs (last ' + tail.length + ') ---', 'info'); tail.forEach(l => this.terminal.print(l, l.includes('[ERROR]') ? 'error' : 'info')); }; // Auto-rotate logs on startup (silently) this._autoRotateLogs(); this.commands['logrotate'] = () => { const rotated = this._autoRotateLogs(true); if (rotated) { this.terminal.print('Log rotated: ' + rotated, 'success'); } else { this.terminal.print('Log rotation not needed (<50KB, <500 lines)', 'info'); } }; this.commands['health-check'] = () => this._healthCheck(); this.commands['memory-map-export'] = () => this._memoryMapExport(); this.commands['font-size'] = (args) => { if (!args.length || !args[0]) { const cur = localStorage.getItem('webx11_font_size'); this.terminal.print(`Current font-size: ${cur || '16'}px`, 'info'); this.terminal.print('Usage: font-size <8-32>', 'info'); return; } const val = parseInt(args[0], 10); if (isNaN(val) || val < 8 || val > 32) { this.terminal.print('font-size must be between 8 and 32', 'error'); return; } localStorage.setItem('webx11_font_size', val.toString()); // Apply directly to body — bypasses CSS inheritance issues document.body.style.fontSize = val + 'px'; document.getElementById('terminal-container').style.fontSize = val + 'px'; document.getElementById('command-input').style.fontSize = val + 'px'; this.terminal.print(`Font size set to ${val}px (saved) 👆`, 'success'); }; this.commands['setfont'] = this.commands['font-size']; // Checkpoint commands (delegated to virtual-fs.js) this.commands['checkpoint'] = (args) => { try { const name = args[0] || ''; this.terminal.fs.checkpoint(name); const displayName = name || new Date().toISOString(); this.terminal.print('✅ Checkpoint created: ' + displayName, 'success'); } catch (e) { this.terminal.print('Checkpoint failed: ' + e.message, 'error'); } }; this.commands['checkpoint-list'] = () => { try { const list = this.terminal.fs.listCheckpoints(); if (!list || list.length === 0) { this.terminal.print('No checkpoints found', 'info'); return; } this.terminal.print('📋 Checkpoints:', 'text-muted'); list.forEach(c => this.terminal.print(' • ' + c)); } catch (e) { this.terminal.print('checkpoint-list failed: ' + e.message, 'error'); } }; this.commands['checkpoint-del'] = (args) => { if (!args[0]) return this.terminal.print('Usage: checkpoint-del ', 'warning'); try { if (this.terminal.fs.deleteCheckpoint(args[0])) { this.terminal.print('Deleted checkpoint: ' + args[0], 'success'); } else { this.terminal.print('Checkpoint not found: ' + args[0], 'error'); } } catch (e) { this.terminal.print('checkpoint-del failed: ' + e.message, 'error'); } }; this.commands['rollback'] = (args) => { if (!args[0]) return this.terminal.print('Usage: rollback ', 'warning'); try { if (this.terminal.fs.rollback(args[0])) { this.terminal.print('↻ Rolled back to checkpoint: ' + args[0], 'success'); } else { this.terminal.print('Rollback failed: checkpoint not found or invalid', 'error'); } } catch (e) { this.terminal.print('Rollback failed: ' + e.message, 'error'); } }; } _autoRotateLogs(force = false) { try { const content = this.terminal.fs.readFile('/logs/current.log') || ''; const lines = content.split('\n').filter(l => l); const size = content.length; if (!force && size < 51200 && lines.length < 500) return null; const now = new Date(); const stamp = now.getFullYear() + '-' + String(now.getMonth()+1).padStart(2,'0') + '-' + String(now.getDate()).padStart(2,'0') + '_' + String(now.getHours()).padStart(2,'0') + '00'; this.terminal.fs.writeFile('/logs/' + stamp + '.log', content); this.terminal.fs.writeFile('/logs/current.log', ''); // Clean oldest rotated logs (>10) const logsDir = this.terminal.fs.readDir('/logs'); if (logsDir && logsDir.content) { const rotated = Object.keys(logsDir.content) .filter(k => k.endsWith('.log') && k !== 'current.log') .sort(); while (rotated.length > 10) { const oldest = rotated.shift(); this.terminal.fs.deleteFile('/logs/' + oldest); } } return stamp + '.log'; } catch (e) { return null; } } _healthCheck() { const fs = this.terminal.fs; let warnings = 0; this.terminal.print('╔══════════════════════════════════════╗', 'info'); this.terminal.print('║ 🔍 SYSTEM HEALTH CHECK ║', 'info'); this.terminal.print('╚══════════════════════════════════════╝', 'info'); // VFS size const dump = JSON.stringify(fs.root).length; const vfsOk = dump < 524288; this.terminal.print(`VFS size: ${(dump/1024).toFixed(1)}KB ${vfsOk ? '✅' : '⚠️ > 512KB'}`, vfsOk ? 'info' : 'warning'); if (!vfsOk) warnings++; // Modules const modTotal = Object.keys(this.terminal.moduleManager.modules || {}).length; this.terminal.print(`Modules loaded: ${modTotal} ✅`, 'info'); // Logs const logContent = fs.readFile('/logs/current.log') || ''; const logLines = logContent.split('\n').filter(l => l).length; this.terminal.print(`Current log: ${logLines} lines`, logLines > 500 ? 'warning' : 'info'); if (logLines > 500) warnings++; // Trash const trashList = fs.listTrash ? fs.listTrash() : []; this.terminal.print(`Trash items: ${trashList.length}`, 'info'); // Skills const skillIdx = fs.fsReadJSON ? (fs.fsReadJSON('/skills/index.json') || {}) : {}; const skillCount = Object.keys(skillIdx).length; this.terminal.print(`Skills: ${skillCount}`, skillCount > 0 ? 'info' : 'warning'); if (skillCount === 0) warnings++; // Summary this.terminal.print('─'.repeat(40), 'text-muted'); if (warnings === 0) { this.terminal.print('All checks passed ✅', 'success'); } else { this.terminal.print(`${warnings} warning(s) found`, 'warning'); } } _memoryMapExport() { const fs = this.terminal.fs; const idx = fs.fsReadJSON ? (fs.fsReadJSON('/memory/index.json') || {}) : null; if (!idx) { this.terminal.print('No memory index found at /memory/index.json', 'error'); return; } // v4.5.43: Actually export to /memory/reference.md (was: print to terminal) const lines = []; lines.push('---'); lines.push('name: adaptive-memory-map'); lines.push('description: Auto-generated from memory/index.json'); lines.push('tags: [memory, context, tracking, adaptation]'); lines.push('category: system'); lines.push('---'); lines.push(''); for (const [k, v] of Object.entries(idx)) { lines.push(`## ${k}`); lines.push(`- Tasks: ${v.tasks || 0}`); lines.push(`- Updated: ${v.updated || 'unknown'}`); lines.push(`- Summary: ${(v.summary || '').substring(0, 200)}...`); lines.push(''); } const content = lines.join('\n'); try { fs.writeFile('/memory/reference.md', content); this.terminal.print(`✅ Memory map exported to /memory/reference.md (${(content.length / 1024).toFixed(1)}KB)`, 'success'); } catch (e) { this.terminal.print(`❌ Could not save: ${e.message}`, 'error'); } } handleHelp(args) { const helpMap = this.terminal.moduleManager.getAllHelp(); // Single command lookup if (args && args.length > 0) { const cmd = args[0].toLowerCase(); const allCommands = this.terminal.moduleManager.getAllCommands(); if (allCommands[cmd]) { const helpEntry = helpMap[cmd]; if (helpEntry) { this.terminal.print(helpEntry, 'info'); } else { this.terminal.print(`No help available for ${cmd}`, 'warning'); } } else { this.terminal.print(`No help available for ${cmd}`, 'warning'); } return; } // Dynamically group commands by owning module const cmdToModule = this.terminal.moduleManager.getAllCommands(); const moduleGroups = {}; for (const [cmd, modName] of Object.entries(cmdToModule)) { if (!moduleGroups[modName]) moduleGroups[modName] = []; moduleGroups[modName].push(cmd); } const modLabels = { FileSystemModule: '📁 Filesystem', WebX11AIAssistantModule: '🤖 AI', WebXAIAliasModule: '🌐 WebX', DuckDuckGoModule: '🔍 Search & Web', SearXNGModule: '🔍 Search & Web', WebFetcherModule: '🔍 Search & Web', AliasModule: '🔧 Tools', BusyBoxModule: '🔧 Tools', CalcModule: '🔧 Tools', CronModule: '🔧 Tools', CryptoGzipModule: '🔧 Tools', DiffModule: '🔧 Tools', EditorModule: '🔧 Tools', FileManagerModule: '🔧 Tools', FinderModule: '🔧 Tools', MindmapModule: '🔧 Tools', ThemeModule: '🔧 Tools', TutorialModule: '🔧 Tools', VoiceModule: '🔧 Tools', WpmModule: '🔧 Tools', SystemModule: '⚙️ System', ShellModule: '⚙️ System', ServerMonitorModule: '📡 Network', ModuleManagerModule: '🧩 Modules', OllamaModule: '🦙 Ollama', NeuralVFSModule: '🧠 Neural VFS', SkillPackCoreModule: '📚 Skills', ConfigManagerModule: '⚙️ Config', ModuleIOModule: '🔌 I/O', SandboxModule: '🏖️ Sandbox', MyModule: '💾 Data', WebDAVModule: '🧰 Extras', ChatStudioModule: '🧰 Extras', SimpleGUIModule: '🖥️ GUI', SecretVault: '🔒 Vault', OrchestratorModule: '🧠 Orchestrator', PredictorModule: '🔮 Prediction', SmartContextModule: '🧠 Context', MemoryGraphModule: '📊 Memory', DynamicPromptsModule: '💬 Prompts', WorldModelModule: '🌍 World', LeaseModule: '🔐 Leases', AgentRegistryModule: '🤖 Agents', }; // Merge modules with the same label const grouped = {}; const usedLabels = new Set(); for (const [modName, cmds] of Object.entries(moduleGroups)) { const label = modLabels[modName] || `🧩 ${modName.replace(/Module$/, '')}`; if (!grouped[label]) grouped[label] = []; grouped[label].push(...cmds); usedLabels.add(label); } let result = '╔══════════════════════════════════════╗\n║ 🔷 WebX11 ' + (window.NEWOS4_VERSION || 'v4.0') + ' — All Commands ║\n╚══════════════════════════════════════╝\n\n'; const total = Object.keys(helpMap).length; result += `📊 ${total} commands loaded\n\n`; for (const [label, cmds] of Object.entries(grouped)) { result += label + '\n'; cmds.forEach(c => { const desc = (helpMap[c] || c).split(' — ')[1] || ''; const short = desc.substring(0, 55); result += ` ${c.padEnd(16)}${short}\n`; }); result += '\n'; } result += '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n help → detailed usage\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'; this.terminal.print(result.trim(), 'info'); } }