aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.html34
-rw-r--r--modules/core/module-aiassist.js78
-rw-r--r--modules/core/module-fs.js2
-rw-r--r--modules/core/module-loader.js4
-rw-r--r--modules/core/module-system.js2
-rw-r--r--modules/core/terminal.js70
-rw-r--r--modules/ext/shell.js27
-rw-r--r--review-newos4.html309
8 files changed, 312 insertions, 214 deletions
diff --git a/main.html b/main.html
index d5bd57d..804c8e4 100644
--- a/main.html
+++ b/main.html
@@ -139,6 +139,38 @@
margin-bottom: 10px;
position: relative;
}
+ .output-line.user-prompt-line {
+ display: flex;
+ align-items: flex-start;
+ gap: 6px;
+ flex-wrap: wrap;
+ padding: 4px 0;
+ }
+ .output-line.user-prompt-line .prompt-prefix {
+ color: var(--accent-color);
+ white-space: nowrap;
+ flex-shrink: 0;
+ }
+ .output-line.user-prompt-line .prompt-text {
+ color: var(--text-color);
+ word-break: break-word;
+ flex: 1;
+ min-width: 0;
+ }
+ .copy-btn, .edit-btn {
+ font-size: 0.7em;
+ padding: 2px 8px;
+ cursor: pointer;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ color: var(--text-muted);
+ touch-action: manipulation;
+ flex-shrink: 0;
+ transition: background 0.15s;
+ }
+ .copy-btn:hover, .edit-btn:hover,
+ .copy-btn:active, .edit-btn:active { background: var(--accent-color); color: var(--bg-color); }
#input-area {
border-top: 1px solid var(--border-color);
padding: 8px 10px;
@@ -988,7 +1020,7 @@
var mods = [
['Foundation (always loaded)', ['virtual-fs.js','module-manager.js','ollama-manager.js','terminal.js'], true],
['Built-in modules', ['module-system.js','module-fs.js','module-modmgr.js','module-ollama.js','module-my.js','module-searxng.js','module-servermon.js','module-ollamamodels.js','module-config.js','module-simplegui.js','module-io.js','module-dynamicprompts.js','module-aiassist.js','module-aiasm.js','module-smartctx.js','module-duckduckgo.js','module-fetcher.js','module-skills.js','module-chatstudio.js'], false],
- ['Extensions', ['calc.js','voice.js','cron.js','theme.js','wpm.js','mindmap.js','webdav.js','skill-pack-core.js','editor.js','diff.js','alias.js','finder.js','filemgr.js'], false]
+ ['Extensions', ['calc.js','voice.js','cron.js','theme.js','wpm.js','mindmap.js','webdav.js','skill-pack-core.js','editor.js','diff.js','alias.js','finder.js','filemgr.js','cryptogzip.js','tutorial.js','shell.js','busybox.js'], false]
];
var isSel = function(name) { return true; }; // default: all selected
mods.forEach(function(section) {
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js
index f77ec61..f7be209 100644
--- a/modules/core/module-aiassist.js
+++ b/modules/core/module-aiassist.js
@@ -16,7 +16,10 @@
this._sessionSaved = false;
this._thinkingTimer = null;
this._thinkingStartTime = 0;
+ this._validatorSuppressed = false;
this._toolDefs = null;
+ this._toolCallLog = [];
+ this._debugPanelEnabled = false;
try { const s = localStorage.getItem('webx11_ai_patterns'); if (s) this._commandFreq = JSON.parse(s); } catch (e) {}
try { const p = localStorage.getItem('webx11_user_profile'); if (p) this._userProfile = JSON.parse(p); } catch (e) {}
// Restore AI conversation context from localStorage
@@ -392,6 +395,7 @@ RULES:
'ai-context': 'ai-context — Show current conversation context',
'ai-allow': 'ai-allow — Confirm pending AI action',
'ai-deny': 'ai-deny — Deny pending AI action',
+ 'ai-ignore': 'ai-ignore — Suppress validator warnings for this session',
'ai-stop': 'ai-stop — Cancel current AI operation',
'ai-model': 'ai-model [model] — Show or set AI model'
};
@@ -404,9 +408,11 @@ RULES:
this.commands['ai-context'] = () => this.showContext();
this.commands['ai-allow'] = () => this.confirmPending();
this.commands['ai-deny'] = () => this.denyPending();
+ this.commands['ai-ignore'] = () => this.ignoreValidator();
this.commands['ai-stop'] = () => this.cancelAi();
this.commands['ai-model'] = (args) => this.showModel(args);
this.commands['ai-compress'] = () => this._manualCompress();
+ this.commands['debug'] = () => this.toggleDebug();
}
async chat(args) {
const userMessage = args.join(' ');
@@ -542,6 +548,28 @@ RULES:
}
return result.substring(0, maxLen) + '...(truncated from ' + result.length + ' chars)';
}
+ _escapeHtml(str) {
+ return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ }
+ _updateDebugPanel() {
+ if (!this._debugPanelEnabled) return;
+ const panel = document.getElementById('debug-panel');
+ if (!panel) return;
+ const recent = this._toolCallLog.slice(-20);
+ let html = '';
+ for (const entry of recent) {
+ const statusClass = entry.error ? 'debug-entry-error' : 'debug-entry-ok';
+ const argsStr = typeof entry.args === 'string' ? entry.args.substring(0, 60) : JSON.stringify(entry.args).substring(0, 60);
+ html += '<div class="debug-entry ' + statusClass + '">' +
+ '<span class="debug-turn">#' + entry.turn + '</span> ' +
+ '<span class="debug-name">' + this._escapeHtml(entry.name) + '</span> ' +
+ '<span class="debug-args">' + this._escapeHtml(argsStr) + '</span> ' +
+ '<span class="debug-time">' + entry.duration + 's</span>' +
+ (entry.error ? ' <span class="debug-err">⚠️</span>' : '') +
+ '</div>';
+ }
+ panel.innerHTML = '<div class="debug-header">🔧 Tool Log <span class="debug-count">' + this._toolCallLog.length + ' calls</span></div>' + html;
+ }
_isToolError(result) {
if (!result || typeof result !== 'string') return null;
const trimmed = result.trim();
@@ -618,6 +646,15 @@ RULES:
const t0 = Date.now();
const toolResult = await this.runTool(fn.name, fn.arguments);
const t1 = Math.round((Date.now() - t0) / 1000);
+ this._toolCallLog.push({
+ turn: toolTurns,
+ name: fn.name,
+ args: fn.arguments,
+ result: toolResult,
+ duration: t1,
+ error: this._isToolError(toolResult) ? true : false
+ });
+ if (this._debugPanelEnabled) this._updateDebugPanel();
return { fn, toolResult, t1 };
}));
for (const { fn, toolResult, t1 } of safeResults) {
@@ -628,6 +665,10 @@ RULES:
this.terminal.log('WARN', 'AI', `Tool ${fn.name} failed: ${err} (${t1}s)`);
this._trackToolFailure(fn.name, err);
this.terminal.print(`📊 Result (${t1}s): ⚠️ Error: ${err}`, 'warning');
+ } else if (toolResult && toolResult.length > 150) {
+ this.terminal.log('INFO', 'AI', `Tool ${fn.name} ok (${t1}s)`);
+ const safeId = 'toolresult-' + Date.now() + '-' + Math.random().toString(36).slice(2, 6);
+ this.terminal.printHTML(`📊 Result (${t1}s): <span id="${safeId}-short">${this._escapeHtml(obs)} <a href="#" onclick="var e=document.getElementById('${safeId}-full');var s=document.getElementById('${safeId}-short');if(e){e.style.display='inline';s.style.display='none'}return false" style="color:var(--info-color);cursor:pointer">[+] show full (${toolResult.length} chars)</a></span><span id="${safeId}-full" style="display:none">${this._escapeHtml(toolResult)} <a href="#" onclick="var e=document.getElementById('${safeId}-full');var s=document.getElementById('${safeId}-short');if(e&&s){e.style.display='none';s.style.display='inline'}return false" style="color:var(--warning-color);cursor:pointer">[-] collapse</a></span>`);
} else {
this.terminal.log('INFO', 'AI', `Tool ${fn.name} ok (${t1}s)`);
this.terminal.print(`📊 Result (${t1}s): ${obs}`, 'info');
@@ -644,6 +685,15 @@ RULES:
this.terminal.print(`🔧 Tool: ${fn.name}(${typeof fn.arguments === 'string' ? fn.arguments : JSON.stringify(fn.arguments)})`, 'info');
const toolResult = await this.runTool(fn.name, fn.arguments);
const t1 = Math.round((Date.now() - t0) / 1000);
+ this._toolCallLog.push({
+ turn: toolTurns,
+ name: fn.name,
+ args: fn.arguments,
+ result: toolResult,
+ duration: t1,
+ error: this._isToolError(toolResult) ? true : false
+ });
+ if (this._debugPanelEnabled) this._updateDebugPanel();
const dObs = this._summarizeObservation(toolResult, 150);
const dErr = this._isToolError(toolResult);
if (dErr) {
@@ -664,7 +714,7 @@ RULES:
}
}
// Validator: check safe tool results for consistency
- if (safeResults.length > 0 && pendingText) {
+ if (safeResults.length > 0 && pendingText && !this._validatorSuppressed) {
const om = this.terminal.ollamaManager;
if (om && om.validatorEnabled && om.validatorModel) {
let invalidTools = [];
@@ -856,6 +906,10 @@ RULES:
denyPending() {
this._resolveConfirm(false);
}
+ ignoreValidator() {
+ this._validatorSuppressed = true;
+ this.terminal.print('🔍 Validator suppressed for this session', 'info');
+ }
cancelAi() {
this._cancelled = true;
this.terminal.print('⏹ Cancelling AI...', 'warning');
@@ -870,6 +924,28 @@ RULES:
// Immediately reset UI so user knows it stopped
this.terminal.setAiBusy(false);
}
+ toggleDebug() {
+ this._debugPanelEnabled = !this._debugPanelEnabled;
+ let panel = document.getElementById('debug-panel');
+ if (!panel) {
+ // Create the debug panel
+ panel = document.createElement('div');
+ panel.id = 'debug-panel';
+ panel.style.cssText = 'position:fixed;right:10px;bottom:50px;width:380px;max-height:400px;overflow-y:auto;background:#0a0a0a;border:1px solid #333;border-radius:6px;z-index:9999;font-family:monospace;font-size:0.78em;display:none;';
+ document.body.appendChild(panel);
+ // Add close button handler
+ panel.addEventListener('click', function() {
+ // Toggle collapsed/expanded state
+ });
+ }
+ panel.style.display = this._debugPanelEnabled ? 'block' : 'none';
+ if (this._debugPanelEnabled) {
+ this._updateDebugPanel();
+ this.terminal.print('🔧 Debug panel enabled — shows tool call log in bottom-right corner. Close with: debug', 'info');
+ } else {
+ this.terminal.print('🔧 Debug panel disabled', 'info');
+ }
+ }
isDestructive(name) {
return name === 'write_file' || name === 'delete_file' || name === 'run_command' || name === 'make_directory' || name === 'edit_module';
}
diff --git a/modules/core/module-fs.js b/modules/core/module-fs.js
index 4ba34b0..ae8b5f4 100644
--- a/modules/core/module-fs.js
+++ b/modules/core/module-fs.js
@@ -288,7 +288,7 @@ class FileSystemModule {
const t = args && args[0] ? args[0] : '.';
if (t === '.') {
const dir = this.terminal.fs.getCurrentDir(); if (!dir) return;
- let total = 0; Object.keys(dir.content).forEach(k => { total += dir.content[k].content ? dir.content[k].content.length : 0; });
+ let total = 0; Object.keys(dir.content).forEach(k => { const node = dir.content[k]; total += node && typeof node.content === 'string' ? node.content.length : 0; });
this.terminal.print(total + '\t' + t);
} else {
const c = this.terminal.fs.readFile(t);
diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js
index 667a396..61bde20 100644
--- a/modules/core/module-loader.js
+++ b/modules/core/module-loader.js
@@ -99,9 +99,9 @@
window.__moduleLoaderReload = reloadWithSelection;
- const CACHE = '?v=' + (localStorage.getItem('webx11_cache_ver') || '2026-05-28');
+const CACHE = '?v=' + (localStorage.getItem('webx11_cache_ver') || '2026-06-01-fix3');
if (!localStorage.getItem('webx11_cache_ver')) {
- localStorage.setItem('webx11_cache_ver', '2026-05-28');
+ localStorage.setItem('webx11_cache_ver', '2026-06-01-fix3');
}
async function init() {
diff --git a/modules/core/module-system.js b/modules/core/module-system.js
index 29a9a87..beed699 100644
--- a/modules/core/module-system.js
+++ b/modules/core/module-system.js
@@ -204,7 +204,7 @@
// Categorize all commands
const cats = {
files: ['ls','ll','cat','put','rm','mv','cp','mkdir','rmdir','cd','pwd','find','grep','head','tail','sort','wc','touch','tree','du','upload','download','vfs-export','vfs-import','edit','diff'],
- ai: ['ai','ask','ai-clear','ai-system','ai-context','ai-allow','ai-deny','ai-stop','ai-model'],
+ ai: ['ai','ask','ai-clear','ai-system','ai-context','ai-allow','ai-deny','ai-ignore','ai-stop','ai-model'],
search: ['search','s','ddg','duck','fetch','web','extract'],
tools: ['calc','cron-every','cron-list','cron-stop','cron-clear','wpm','mindmap','theme','voice','alias','unalias',
'which','env','date','cal','yes','seq','base64','printf','cut','uniq','hostname','whoami','basename','dirname','sleep','expand','tutorial'],
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index 5008842..607c51a 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -399,7 +399,7 @@
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/`/g, '&#96;');
- return `<div class="ai-render-container"><iframe sandbox="allow-scripts" srcdoc="${safeSrcdoc}" class="ai-render-iframe" onload="var _s=this;setTimeout(function(){_s.style.height=Math.max((_s.contentWindow.document.documentElement.scrollHeight||200),200)+'px'},100)"></iframe></div>`;
+ return `<div class="ai-render-container"><div style="display:flex;gap:6px;padding:4px 8px;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color);align-items:center;"><span style="color:var(--text-muted);font-size:0.75em;">📄 Rendered HTML</span><span style="flex:1"></span><button class="qa-btn" style="padding:2px 10px;font-size:0.75em;" onclick="webx11.openRenderPreview(this)" data-content="${safeSrcdoc.replace(/"/g, '&quot;')}">⛶ Fullscreen</button></div><iframe sandbox="allow-scripts" srcdoc="${safeSrcdoc}" class="ai-render-iframe" onload="var _s=this;setTimeout(function(){_s.style.height=Math.max((_s.contentWindow.document.documentElement.scrollHeight||200),200)+'px'},100)"></iframe></div>`;
}
_renderHTMLBlock(text) {
const renderRegex = /:::render-html\r?\n([\s\S]*?)\r?\n:::/g;
@@ -483,9 +483,42 @@
this._streamChunks = [];
}
}
+ printUserPrompt(rawInput) {
+ const wrapper = document.createElement('div');
+ wrapper.className = 'output-line user-prompt-line';
+ const safe = rawInput.replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ const hasHtml = /<[a-z][\s\S]*>/i.test(rawInput.trim());
+ const previewBtn = hasHtml ? `<button class="copy-btn" onclick="webx11.previewHtmlFromPrompt(this)" data-content="${safe.replace(/"/g, '&quot;')}" title="Preview HTML">👁 Preview</button>` : '';
+ wrapper.innerHTML = `
+ <span class="prompt-prefix">webx11@module:~$ </span>
+ <span class="prompt-text">${safe}</span>
+ <button class="copy-btn user-copy-btn" onclick="webx11.copyToClipboard(this)" title="Copy prompt">Copy</button>
+ ${previewBtn}
+ <button class="edit-btn" onclick="webx11.editPrompt('${safe.replace(/'/g, "\\'")}')" title="Edit prompt">Edit</button>
+ `;
+ this.outputContainer.appendChild(wrapper);
+ this._historyBuffer.push({ l: rawInput, t: 'command-prompt' });
+ if (this._historyBuffer.length > this._historyMaxLines) this._historyBuffer.shift();
+ this.scrollToBottom();
+ this._trimOutput();
+ }
+ editPrompt(text) {
+ this.inputField.value = text;
+ this.inputField.focus();
+ this.inputField.setSelectionRange(text.length, text.length);
+ }
copyToClipboard(btn) {
- const contentDiv = btn.nextElementSibling;
- const text = contentDiv.innerText;
+ let text;
+ if (btn.classList.contains('user-copy-btn')) {
+ // User prompt: text is in .prompt-text sibling
+ const pSpan = btn.parentElement.querySelector('.prompt-text');
+ if (pSpan) text = pSpan.textContent;
+ } else {
+ // AI response: text is in next sibling .ai-content
+ const contentDiv = btn.nextElementSibling;
+ if (contentDiv) text = contentDiv.innerText;
+ }
+ if (!text) return;
navigator.clipboard.writeText(text).then(() => {
const originalText = btn.textContent;
btn.textContent = 'Copied!';
@@ -675,6 +708,8 @@
this._dirty = false;
}, 180000);
window.addEventListener('beforeunload', () => {
+ // Flush session before tab closes — avoids losing up to 3min of output on crash/close
+ try { this._autoSaveSession(); } catch (e) {}
if (this._autoSaveTimer) {
clearInterval(this._autoSaveTimer);
this._autoSaveTimer = null;
@@ -1008,7 +1043,7 @@
}
async reloadPersistedModules() {
const registry = this.moduleManager.moduleRegistry;
- const skipList = ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell'];
+ const skipList = ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell', 'tutorial', 'busybox'];
for (const mod of registry) {
if (mod.enabled && mod.url) {
// Skip ext modules — they load via _loadExtModules
@@ -1021,7 +1056,7 @@
async executeCommand(rawInput) {
if (!rawInput.trim()) return;
this.markDirty();
- this.print(`webx11@module:~$ ${rawInput}`, 'command-prompt');
+ this.printUserPrompt(rawInput);
const pipeParts = this.splitPipe(rawInput.trim());
if (pipeParts.length > 1) {
await this.executePipeChain(pipeParts);
@@ -1248,6 +1283,29 @@
iframe.src = 'about:blank';
this.inputField.focus();
}
+ openRenderPreview(btn) {
+ const content = btn.getAttribute('data-content');
+ if (!content) return;
+ const iframe = document.getElementById('preview-iframe');
+ // The srcdoc content is already HTML-escaped from _renderHTMLPreview
+ const decoded = content.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#96;/g, '`');
+ iframe.srcdoc = decoded;
+ document.getElementById('preview-title').textContent = '📄 AI Rendered Preview (Fullscreen)';
+ document.getElementById('preview-modal').style.display = 'flex';
+ }
+ previewHtmlFromPrompt(btn) {
+ const content = btn.getAttribute('data-content');
+ if (!content) return;
+ const iframe = document.getElementById('preview-iframe');
+ // Content is HTML-escaped, decode it back
+ const decoded = content.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#96;/g, '`');
+ // Wrap in a basic HTML template if it doesn't have html/head/body tags
+ const hasOwnDoc = /<html|<head|<body/i.test(decoded);
+ const fullDoc = hasOwnDoc ? decoded : `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><style>body{background:#000;color:#0f0;font-family:monospace;margin:16px;}</style></head><body>${decoded}</body></html>`;
+ iframe.srcdoc = fullDoc;
+ document.getElementById('preview-title').textContent = '📄 User HTML Preview';
+ document.getElementById('preview-modal').style.display = 'flex';
+ }
openSkillsManager() {
const modal = document.getElementById('skills-manager');
// Ensure /skills/ directory exists
@@ -1671,7 +1729,7 @@
'module-fetcher.js','module-skills.js','module-chatstudio.js'
];
const extFiles = [
- 'calc.js','voice.js','cron.js','theme.js','wpm.js','mindmap.js','skill-pack-core.js'
+ 'calc.js','voice.js','cron.js','theme.js','wpm.js','mindmap.js','webdav.js','skill-pack-core.js','editor.js','diff.js','alias.js','finder.js','filemgr.js','cryptogzip.js','tutorial.js','shell.js','busybox.js'
];
const addSection = (title) => {
diff --git a/modules/ext/shell.js b/modules/ext/shell.js
index 6beb0eb..e87c37c 100644
--- a/modules/ext/shell.js
+++ b/modules/ext/shell.js
@@ -37,13 +37,28 @@ class ShellModule {
// ── Hook into terminal.executeCommand ──
init() {
- // Wrap executeCommand to add shell parsing
+ // Guard: prevent double-wrapping if init is called multiple times
+ if (this._initialized) return;
+ this._initialized = true;
+
+ // Wrap executeCommand to add shell parsing — only for compound commands
const origExecute = this.terminal.executeCommand.bind(this.terminal);
const self = this;
this.terminal.executeCommand = async function(rawInput) {
if (!rawInput.trim()) return;
this.markDirty();
- this.print(`webx11@module:~$ ${rawInput}`, 'command-prompt');
+ this.printUserPrompt(rawInput);
+
+ // For simple single-word commands without special chars, skip shell parsing
+ if (/^[a-zA-Z0-9._\/-]+$/.test(rawInput.trim()) && !rawInput.includes(' ') && !rawInput.includes('$')) {
+ try {
+ return await this.security.checkAndRun(rawInput);
+ } catch(e) {
+ this.print('Error: ' + e.message, 'error');
+ return;
+ }
+ }
+
// Substitute variables in the raw input
const substituted = self._substituteVars(rawInput);
// Split on ; first (sequence)
@@ -54,7 +69,7 @@ class ShellModule {
const chainParts = self._splitChain(seqPart.trim());
let lastOk = true;
for (const chainPart of chainParts) {
- if (!chainPart.trim()) continue;
+ if (!chainPart.cmd.trim()) continue;
const { cmd: chainCmd, operator } = chainPart;
if (operator === '&&' && !lastOk) continue;
if (operator === '||' && lastOk) continue;
@@ -74,7 +89,11 @@ class ShellModule {
const parts = chainCmd.split(/\s+/);
const cmd = parts[0].toLowerCase();
const args = parts.slice(1);
- await this.security.checkAndRun(chainCmd);
+ try {
+ await this.security.checkAndRun(chainCmd);
+ } catch(e) {
+ this.terminal && this.terminal.print ? this.terminal.print('Error: ' + e.message, 'error') : console.error(e);
+ }
}
lastOk = true;
}
diff --git a/review-newos4.html b/review-newos4.html
index 1108c81..53e3ffe 100644
--- a/review-newos4.html
+++ b/review-newos4.html
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Review: Module OS v4.2 — WebX11 Terminal</title>
+ <title>Review: newOS4 v4.2 — WebX11 Terminal</title>
<link rel="stylesheet" href="/spaces/assets/css/theme.css">
<style>
:root { --cs-glass: rgba(17,17,17,0.75); --cs-glass-border: rgba(0,255,136,0.1); }
@@ -60,6 +60,12 @@
.pro { border-left: 3px solid #22c55e; padding-left: 16px; margin: 8px 0; border-radius: 2px; }
.con { border-left: 3px solid #ef4444; padding-left: 16px; margin: 8px 0; }
+ .comparison-table { width: 100%; border-collapse: collapse; margin: 20px 0; font-size: 0.85em; }
+ .comparison-table th, .comparison-table td { padding: 8px 10px; border: 1px solid var(--border); text-align: center; }
+ .comparison-table th { background: var(--bg-secondary); color: var(--accent); font-weight: 600; }
+ .comparison-table td { background: var(--bg-tertiary); }
+ .comparison-table .feature-name { text-align: left; color: var(--text-primary); font-weight: 500; }
+
@media (max-width: 600px) {
.container { padding: 0 16px; }
h1 { font-size: 1.6em; }
@@ -69,7 +75,7 @@
<body>
<header>
<div class="header-content">
- <span class="logo"><span class="logo-icon">🧩</span> Module OS v4.2 Review</span>
+ <span class="logo"><span class="logo-icon">🧩</span> newOS4 v4.2 Review</span>
<div style="display:flex;gap:8px;flex-wrap:wrap;">
<a href="/spaces/newos4/help.html">📖 Help →</a>
<a href="/spaces/newos4/main.html">Launch OS →</a>
@@ -79,53 +85,26 @@
<div class="container">
-<h1>Module OS v4.2</h1>
-<p class="meta">WebX11 Terminal · Self-improving Modular OS · Reviewed 2026-05-28 · ✅ Live QA Passed</p>
+<h1>newOS4 v4.2</h1>
+<p class="meta">WebX11 Terminal · In-Browser Terminal OS · Reviewed 2026-06-01</p>
<div class="summary-box">
- <div class="stat"><div class="value">41</div><div class="label">Modules</div></div>
- <div class="stat"><div class="value">130+</div><div class="label">Commands</div></div>
- <div class="stat"><div class="value">56KB</div><div class="label">Help Docs</div></div>
- <div class="stat"><div class="value">36KB</div><div class="label">App Size</div></div>
- <div class="stat"><div class="value">✅</div><div class="label">QA Status</div></div>
-</div>
-
-<div class="callout" style="background:rgba(0,255,136,0.08); border:1px solid var(--accent); border-radius:8px; padding:16px; margin:20px 0;">
- <strong>✅ Live Test Results (2026-05-28)</strong><br>
- <span style="color:var(--text-secondary);font-size:0.9em;">
- Boot/Init: ✅ 41 modules loaded, splash hidden, 0 JS errors<br>
- Core Terminal: ✅ help, ls, put, cat, clear, mem all working<br>
- File Persistence: ✅ VFS survives page reload, <code>_dirty</code> flag skips idle saves<br>
- UI Modals: ✅ Skills Manager, File Browser, Config, WebDAV Browser, File Manager<br>
- Autocomplete: ✅ Tab cycle, Enter/click accept, Escape hide<br>
- All 16 ext modules: calc, voice, cron, theme, wpm, mindmap, webdav, skill-pack-core, editor, diff, alias, finder, filemgr, cryptogzip, busybox, shell — load without errors<br>
- AI Streaming: ✅ NDJSON stream parsing, real-time token display<br>
- WebDAV Browser: ✅ Modal file explorer, clickable dirs, preview, upload/download, breadcrumbs<br>
- Session Nesting: ✅ Fixed — deep clone + strip <code>_sessions</code>, no recursive growth<br>
- Terminal History: ✅ Persists across page reload<br>
- SecretVault: ✅ AES-GCM encrypted credential storage via Web Crypto API<br>
- Context Compression: ✅ Auto-compresses AI history when >2000 tokens<br>
- Trash System: ✅ rm moves to trash, 4 dedicated trash commands<br>
- VFS Checkpoints: ✅ snapshot/rollback via checkpoint command<br>
- Requirements Check: ✅ all modules report prerequisites via <code>check</code> command
- </span>
+ <div class="stat"><div class="value">42</div><div class="label">Module Files</div></div>
+ <div class="stat"><div class="value">25+17</div><div class="label">Core + Ext</div></div>
+ <div class="stat"><div class="value">17</div><div class="label">Skills</div></div>
+ <div class="stat"><div class="value">9</div><div class="label">Theme Presets</div></div>
+ <div class="stat"><div class="value">52KB</div><div class="label">App Size</div></div>
+ <div class="stat"><div class="value">4/5</div><div class="label">Rating</div></div>
</div>
<section>
<h2>Architecture</h2>
- <p>newOS4 v4.2 uses a <strong>modular class-based architecture</strong> with async dependency loading:</p>
+ <p>newOS4 v4.2 is an <strong>in-browser terminal OS</strong> — NOT a chat-centric UI. Single-file <code>main.html</code> (1,031 lines, 52KB) loads 42 module files across two directories:</p>
<ul>
- <li><strong>module-loader.js</strong> — 4-phase async loader: VFS → ModuleManager → OllamaManager/Terminal → Ext modules. Cache-busting via localStorage version key + per-load timestamps.</li>
- <li><strong>VirtualFileSystem</strong> — localStorage-backed in-browser filesystem with VFS checkpoints (snapshot/rollback), trash system (rm → trash, ls-trash, empty-trash), and dirty-flag auto-save.</li>
- <li><strong>ModuleManager</strong> — Central registry with load/unload/reload, ASI-safe comment-stripped class parsing, <code>loadModuleFromCode()</code> for runtime module loading.</li>
- <li><strong>OllamaManager → LLMRouter</strong> — Multi-provider router with auto-fallback chain. Supports Ollama (native) + any OpenAI-compatible API (OpenRouter). SSE streaming parsing. Provider priority-based failover.</li>
- <li><strong>SecretVault</strong> — AES-256-GCM encrypted credential manager via Web Crypto API. PBKDF2 key derivation (100K iterations). PIN or open mode.</li>
- <li><strong>Terminal</strong> — Full terminal with autocomplete, command history, pipe support, clickable output, dirty-flag auto-save, output trimming (200-line cap with memory-pressure auto-reduction).</li>
+ <li><strong>25 core modules</strong> (<code>modules/core/</code>) — Foundation infrastructure (VirtualFileSystem, OllamaManager, SecretVault, ModuleManager, Terminal) + 19 built-in feature modules (system, fs, modmgr, ollama, my, searxng, servermon, ollamamodels, config, simplegui, io, dynamicprompts, aiassist, aiasm, smartctx, duckduckgo, fetcher, skills, chatstudio)</li>
+ <li><strong>17 ext modules</strong> (<code>modules/ext/</code>) — Self-registering: alias, busybox, calc, cron, cryptogzip, diff, editor, filemgr, finder, mindmap, shell, skill-pack-core, theme, tutorial, voice, webdav, wpm</li>
</ul>
-
- <h3>Module System</h3>
- <p><strong>25 core modules</strong> (foundation + built-in) + <strong>16 ext modules</strong> = 41 total. All ES6 classes registered via <code>webx11.moduleManager.registerModule()</code>. Ext modules are togglable via the startup gear on splash. Modules report requirements via <code>requirements()</code> method — checked by the <code>check</code> command.</p>
- <p><strong>Dynamic help system:</strong> Every module implements <code>getHelpInfo()</code> returning a command → description map. <code>ModuleManager.getAllHelp()</code> collects all entries at runtime. No more hardcoded 195-line help map. New modules appear in <code>help</code> immediately.</p>
+ <p><strong>Total codebase</strong>: ~800KB (main.html + all module files). AI system with 5-turn agentic loop, 19+ tool definitions, 17 skills in VFS, 9 theme presets, and full destructive-action confirmation.</p>
</section>
<section>
@@ -133,201 +112,135 @@
<h3>🧠 AI Assistant (WebX11AIAssistantModule)</h3>
<ul>
- <li>Agentic loop with up to <strong>8 tool-call turns</strong> (was 5)</li>
- <li><strong>27 tool definitions</strong>: all standard tools + <code>session_terminal</code> for reading last 50 lines of terminal history</li>
- <li><strong>Tool failure tracking</strong> — after 3 failures on the same tool, warns user to create a workaround skill</li>
- <li><strong>Per-tool timing logs</strong> — every tool call logged with duration in terminal console</li>
- <li><strong>Streaming responses</strong> — NDJSON stream parsing shows tokens in real-time</li>
- <li><strong>Context compression</strong> — auto-compresses when conversation exceeds 2000 tokens (summarizes old messages, keeps last 3 exchanges)</li>
- <li><strong>Manual compression</strong> via <code>ai-compress</code> command</li>
- <li>Auto-loads relevant skills and recent session memory at start</li>
- <li>Inline destructive action confirmation with 120-second countdown</li>
- <li>Status bar "🤖 AI Thinking..." spinner while processing</li>
+ <li>Agentic loop with <strong>5 tool-call turns</strong>, 19+ tool definitions</li>
+ <li>Date/time injection into system prompt for contextual awareness</li>
+ <li>Streaming NDJSON response parsing with real-time token display</li>
+ <li>Auto-loads relevant skills at start of every AI task</li>
+ <li>Inline destructive action confirmation with 120-second countdown timer</li>
+ <li>Status bar "🤖 AI Thinking..." spinner with pulse animation</li>
<li>Post-task reflection suggesting skill creation</li>
- <li>LLMRouter-backed — auto-falls to next provider on failure</li>
- </ul>
-
- <h3>🔐 SecretVault (Core Module)</h3>
- <ul>
- <li>AES-256-GCM encrypted credential storage via Web Crypto API</li>
- <li>PBKDF2 key derivation: 100,000 iterations, SHA-256, 256-bit key</li>
- <li>Two modes: PIN mode (password-derived) or open mode (random hex key)</li>
- <li>7 CLI commands: <code>secret-set</code>, <code>secret-get</code>, <code>secret-list</code>, <code>secret-del</code>, <code>secret-lock</code>, <code>secret-unlock</code>, <code>secret-setpin</code></li>
- <li>Auto-redaction: <code>redactSecret()</code> scans output for stored secrets and replaces with <code>[REDACTED]</code></li>
- <li>Integration: <code>ollama-manager</code> stores API keys via SecretVault; modules check <code>window.webx11_secretVault</code></li>
- </ul>
-
- <h3>🔄 LLMRouter (OllamaManager)</h3>
- <ul>
- <li>Multi-provider router: supports Ollama (native <code>/api/chat</code> + <code>/api/generate</code>) and any OpenAI-compatible API (OpenRouter, etc.)</li>
- <li>Provider priority chain — falls to next on failure, tracks <code>fallbackCount</code> per provider</li>
- <li>SSE streaming for OpenAI-compatible endpoints: parses <code>data: {"choices":[{"delta":{"content":"..."}}]}</code> format</li>
- <li>Auto-probes provider on <code>connect()</code> via <code>/api/tags</code> (Ollama) or <code>/v1/models</code> (OpenAI)</li>
- <li>API keys stored via SecretVault when available</li>
- </ul>
-
- <h3>📚 Skills System (SkillsModule)</h3>
- <ul>
- <li>8 CLI commands: <code>skill-list</code>, <code>skill-view</code>, <code>skill-create</code>, <code>skill-patch</code>, <code>skill-delete</code>, <code>skill-export</code>, <code>skill-import</code>, <code>skill-sync</code></li>
- <li><strong>Skill index caching</strong> — in-memory index with 2-second debounced flush to VFS, eliminates repeated <code>fsReadJSON</code> calls</li>
- <li>Skills Manager UI modal (📚 button in quick-actions)</li>
- <li>Stored as Markdown with YAML frontmatter in VFS <code>/skills/</code></li>
- <li>Auto-loads relevant skills at the start of every AI task</li>
- <li>Auto-creates error workaround skills after 3+ repeated errors</li>
- <li>Auto-audits skills for staleness every 20 messages</li>
+ <li><code>ai-stop</code> escape-cancel, <code>ai-model</code> runtime model switching</li>
</ul>
- <h3>🗑️ Trash System</h3>
+ <h3>📁 Virtual File System</h3>
<ul>
- <li><code>rm</code> moves files to trash instead of permanent deletion (safer)</li>
- <li>5 dedicated commands: <code>trash</code>, <code>trash-dir</code>, <code>ls-trash</code>, <code>empty-trash</code>, <code>rm -rf</code> for real deletion</li>
- <li>Trash persists in VFS across page reloads</li>
+ <li>localStorage-backed in-memory filesystem with persistent state</li>
+ <li>19 Unix commands: ls (flags), cd, pwd, cat, echo (&gt; redirect), put, rm/rmdir/mkdir/mv/cp/touch/tree/find/head/tail/sort/wc/du/upload/download/grep</li>
+ <li>Trash system: <code>rm</code> moves to trash, <code>ls-trash</code>, <code>empty-trash</code>, <code>trash-dir</code>, <code>rm -rf</code> for real deletion</li>
+ <li>VFS Checkpoints: snapshot/rollback via <code>checkpoint</code> and <code>rollback</code> commands, auto-prune at 10</li>
+ <li>Auto-save session system: 60s interval with dirty-flag skip, context persists through reloads</li>
</ul>
- <h3>📸 VFS Checkpoints</h3>
+ <h3>🎨 Theme System (9 Presets)</h3>
<ul>
- <li>Snapshots: <code>checkpoint [name]</code> — saves full VFS state to <code>/_snapshots/</code></li>
- <li>Rollback: <code>rollback &lt;name&gt;</code> — restores VFS from snapshot</li>
- <li>Management: <code>checkpoint-list</code>, <code>checkpoint-del</code></li>
- <li>Auto-prunes oldest checkpoints when exceeding 10</li>
+ <li>Built-in presets: <strong>dark</strong>, <strong>light</strong>, <strong>amber</strong>, <strong>cyber</strong>, <strong>ocean</strong>, <strong>forest</strong>, <strong>monochrome</strong>, <strong>sunset</strong>, <strong>midnight</strong></li>
+ <li>Custom theme creation with color pickers, export/import JSON</li>
+ <li>7 CSS variables per theme (bg, secondary, tertiary, text, muted, accent, border)</li>
+ <li>Commands: <code>theme set &lt;name&gt;</code>, <code>theme list</code>, <code>theme new</code>, <code>theme delete</code>, <code>theme export</code>, <code>theme preview</code>, <code>theme keep</code></li>
</ul>
- <h3>📁 File Manager (Ext Module)</h3>
+ <h3>📚 Skills System</h3>
<ul>
- <li>Fullscreen overlay with 30% sidebar + 70% preview pane</li>
- <li>Commands: <code>files</code>, <code>preview &lt;path&gt;</code></li>
- <li>Preview types: Markdown (regex render), images (data URI), video/audio, code (line-numbered table), JSON (highlighted), CSV, PDF (embed)</li>
- <li>Live search filter (Ctrl+F), action bar (delete, download, edit via editor.js)</li>
- <li>Breadcrumb navigation, Raw/Rendered toggle</li>
- <li>50KB file truncation warning, empty dir indicator, binary fallback</li>
+ <li><strong>17 skills</strong> stored as Markdown with YAML frontmatter in VFS <code>/skills/</code></li>
+ <li>8 CLI commands: skill-list, skill-view, skill-create, skill-patch, skill-delete, skill-export, skill-import, skill-sync</li>
+ <li>Skills Manager UI modal (📚 button in quick-actions bar)</li>
+ <li>Auto-loads relevant skills at start of every AI task</li>
+ <li>Auto-creates error workaround skills after 3+ repeated failures</li>
+ <li>In-memory index with 2-second debounced flush to VFS</li>
</ul>
- <h3>🧰 Tool Registry — <code>requirements()</code></h3>
+ <h3>🎤 Voice Command</h3>
<ul>
- <li>Every module implements <code>requirements()</code> returning <code>{ met, missing }</code></li>
- <li><code>check</code> command runs all requirements and reports overall health</li>
- <li><code>commands</code> command shows module source + requirements per module</li>
+ <li>🎤 button in input area beside Send button</li>
+ <li>Green pulse animation while listening, red border on error</li>
+ <li>SpeechRecognition API (Chrome, Edge, Safari 14.1+), graceful fallback on Firefox</li>
+ <li>Toggle visibility via quick-actions bar</li>
</ul>
- <h3>🎤 Voice (VoiceModule)</h3>
+ <h3>🔊 Sound Notification</h3>
<ul>
- <li>🎤 button in input area next to ⏎ Send</li>
- <li>Green pulse animation while listening, red on error</li>
- <li>SpeechRecognition API (Chrome, Edge, Safari 14.1+), graceful fallback on Firefox</li>
- <li>Visibility state persists in localStorage</li>
+ <li>WebAudio "ding" (880Hz sine, 0.3s) after AI response</li>
+ <li>Togglable via <code>🔊 Sound</code> / <code>🔇 Muted</code> button in quick-actions</li>
+ <li>State persists in localStorage</li>
</ul>
- <h3>💾 Session Persistence</h3>
+ <h3>🔍 Search & Fetch</h3>
<ul>
- <li>Auto-saves every 3 minutes — but only when <code>_dirty</code> flag is set (idle = 0 writes)</li>
- <li>Nesting bug fixed: deep clones VFS, strips <code>_sessions</code> before serialization</li>
- <li>Terminal command history persists across page reloads</li>
- <li><strong>Output trimming</strong>: 200-line cap with memory-pressure auto-trim to 100/50 when heap >80MB/120MB</li>
+ <li>DuckDuckGo search module with proxy API fallback</li>
+ <li>SearXNG integration for web search</li>
+ <li>WebFetcher module for URL content extraction (256KB limit)</li>
</ul>
- <h3>Other Key Modules</h3>
+ <h3>Other Notable Modules</h3>
<ul>
- <li><strong>SearXNG + DuckDuckGo</strong> — Web search with fallback</li>
- <li><strong>Web Fetcher</strong> — Fetch and extract clean content from any URL</li>
- <li><strong>WebDAV Sync</strong> — 8 commands + browser modal for cloud sync (config, push, pull, backup, restore, del)</li>
- <li><strong>Shell Module</strong> — Full shell: pipe <code>|</code>, redirects <code>&gt; &gt;&gt; &lt;</code>, variables <code>$VAR</code>, chaining <code>&amp;&amp; || ;</code>, VFS script execution</li>
- <li><strong>BusyBox</strong> — 16 utility commands: which, env, date, cal, yes, seq, base64, printf, cut, uniq, hostname, whoami, basename, dirname, sleep, expand</li>
- <li><strong>CryptoGzip</strong> — AES-256-GCM encrypt/decrypt and gzip/gunzip for VFS files</li>
- <li><strong>Session System</strong> — save/load/list/delete/export/import via AI tools</li>
- <li><strong>My Data</strong> — Persistent user profile with 7 CLI commands</li>
- <li><strong>Ollama Model Manager</strong> — models, model-info, model-pull, model-delete, model-run</li>
- <li><strong>Cron Scheduler</strong> — schedule commands at intervals (min 5s), localStorage persistence</li>
- <li><strong>Alias Module</strong> — define/manage command aliases (ll, h, cls defaults) with localStorage persistence</li>
- <li><strong>Text Editor</strong> — inline VFS file editing via modal (edit, save, cancel)</li>
- <li><strong>Theme Switcher</strong> — dark, light, amber, cyber + custom</li>
- <li><strong>Command Aliases</strong> — ll, h, cls defaults with localStorage persistence</li>
+ <li><strong>Shell</strong> — pipes <code>|</code>, redirects <code>&gt; &gt;&gt; &lt;</code>, variables <code>$VAR</code>, chaining <code>&amp;&amp; || ;</code>, VFS script execution</li>
+ <li><strong>BusyBox</strong> — 16 utilities: which, env, date, cal, yes, seq, base64, printf, cut, uniq, hostname, whoami, basename, dirname, sleep, expand</li>
+ <li><strong>CryptoGzip</strong> — AES-256-GCM encrypt/decrypt + gzip/gunzip for VFS files</li>
+ <li><strong>File Manager</strong> — Fullscreen overlay with 30% sidebar, 70% preview pane, 10+ preview renderers, live search</li>
+ <li><strong>WebDAV Sync</strong> — 8 commands + modal browser for cloud sync (config, push, pull, backup, restore, del)</li>
+ <li><strong>Mindmap</strong> — ASCII mindmap creation and management in terminal</li>
+ <li><strong>Text Editor</strong> — inline VFS editing via modal (edit/save/cancel)</li>
+ <li><strong>Calculator, Cron, Diff, Alias, Finder</strong> — utility modules covering common needs</li>
+ <li><strong>Package Manager (WPM)</strong> — Web Package Manager for module discovery</li>
+ <li><strong>Tutorial</strong> — Onboarding tutorial for new users</li>
+ <li><strong>Chat Overlay</strong> — Lite chat UI via <code>chat</code> command (toggleable overlay)</li>
</ul>
-
- <h3>All Modules (41 total)</h3>
- <p><strong>Foundation (5):</strong> virtual-fs.js, module-manager.js, secret-vault.js, ollama-manager.js, terminal.js</p>
- <p><strong>Core (20):</strong> module-system.js, module-fs.js, module-modmgr.js, module-ollama.js, module-my.js, module-searxng.js, module-servermon.js, module-ollamamodels.js, module-config.js, module-simplegui.js, module-io.js, module-dynamicprompts.js, module-aiassist.js, module-aiasm.js, module-smartctx.js, module-duckduckgo.js, module-fetcher.js, module-skills.js, module-chatstudio.js, module-fs.js</p>
- <p><strong>Ext (16):</strong> calc.js, voice.js, cron.js, theme.js, wpm.js, mindmap.js, webdav.js, skill-pack-core.js, editor.js, diff.js, alias.js, finder.js, filemgr.js, cryptogzip.js, busybox.js, shell.js</p>
</section>
<section>
- <h2>Recent Improvements</h2>
-
- <h3>🔐 SecretVault (2026-05-25)</h3>
- <p>AES-256-GCM encrypted credential manager using Web Crypto API. PBKDF2 key derivation (100K iterations) with salt. PIN mode or open mode. 7 CLI commands. Auto-redacts stored secrets from output. Integrated with LLMRouter for API key storage.</p>
-
- <h3>🔄 LLMRouter (2026-05-25)</h3>
- <p>Refactored from single-endpoint OllamaManager into a multi-provider router with priority-based fallback. Supports Ollama and any OpenAI-compatible API (OpenRouter, etc.). SSE streaming parsing. Provider auto-fallback on failure with per-provider stats tracking.</p>
-
- <h3>📦 Context Compression (2026-05-25)</h3>
- <p>When AI conversation exceeds 2000 tokens, <code>_compressContext()</code> keeps last 3 exchanges, summarizes the rest into one system message via AI summarization or fallback truncation. Also available as <code>ai-compress</code> command. Max tool turns increased from 5 to 8.</p>
-
- <h3>📸 VFS Checkpoints + Trash (2026-05-25)</h3>
- <p>Snapshot/rollback system (<code>checkpoint</code>, <code>rollback</code>, <code>checkpoint-list</code>, <code>checkpoint-del</code>) plus trash system (<code>rm</code> → trash, <code>trash-dir</code>, <code>ls-trash</code>, <code>empty-trash</code>). Auto-prunes to max 10 checkpoints.</p>
-
- <h3>🧰 Tool Registry + File Manager (2026-05-25)</h3>
- <p>Tool Registry: every module implements <code>requirements()</code>. File Manager: 704-line fullscreen overlay with sidebar, preview pane, search, edit, download, delete commands.</p>
-
- <h3>🧰 Dynamic Help System & Module Loading Fixes (2026-05-25)</h3>
- <p>Replaced <code>_buildHelpMap()</code> (195 lines) with <code>ModuleManager.getAllHelp()</code>. Fixed double-loading of ext modules (skip list + relative URL guard in <code>registerModule()</code>). Fixed ASI comment-stripping bug in class parsing. Added <code>loadModuleFromCode()</code> for runtime module loading. Fixed <code>check_updates</code> returning empty.</p>
-
- <h3>🧠 AI Session Terminal Tool + Error Tracking (2026-05-25)</h3>
- <p>Added <code>session_terminal</code> tool: reads last 50 lines of terminal auto-save for context when user references past terminal work. Added <code>_trackToolFailure()</code>: after 3 failures on the same tool, warns user and suggests creating a workaround skill. Per-tool timing logs with duration.</p>
-
- <h3>📁 WebDAV Browser UI + File Manager (2026-05-25)</h3>
- <p>Full modal file explorer for the dedicated WebDAV space, with clickable directory navigation, breadcrumbs, file preview (HTML in iframe, text inline), upload button, download on double-click, and refresh. New File Manager ext module adds <code>files</code> and <code>preview</code> commands with fullscreen overlay.</p>
-
- <h3>📦 4 New Ext Modules (2026-05-25)</h3>
- <ul>
- <li><strong>BusyBox</strong> — 16 utility commands: which, env, date, cal, yes, seq, base64, printf, cut, uniq, hostname, whoami, basename, dirname, sleep, expand</li>
- <li><strong>Shell</strong> — Full shell: pipes, redirects, variables, chaining, .sh script execution</li>
- <li><strong>CryptoGzip</strong> — AES-256-GCM encrypt/decrypt and gzip/gunzip for VFS files</li>
- <li><strong>File Manager</strong> — Fullscreen file browser with 10+ preview renderers</li>
- </ul>
-
- <h3>💾 Terminal Performance</h3>
- <ul>
- <li>Output trimming: 200-line cap with memory-pressure auto-reduction (100/50 lines when >80MB/120MB heap)</li>
- <li>Auto-save interval: 60s → 180s, dirty-flag skip</li>
- <li>History lazy-loads via <code>requestAnimationFrame</code></li>
- <li>localStorage quota warning when approaching limit</li>
- <li><code>mem</code> command: shows JS heap size, terminal lines, history buffer count</li>
- </ul>
+ <h2>Feature Comparison</h2>
+ <table class="comparison-table">
+ <tr>
+ <th>Feature</th><th>Main</th><th>Lite</th><th>Stable</th><th>Plus</th><th>newOS4</th>
+ </tr>
+ <tr><td class="feature-name">AI Chat</td><td>❌</td><td>✅ Streaming</td><td>✅ No stream</td><td>✅</td><td>✅ Agentic</td></tr>
+ <tr><td class="feature-name">Skills System</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅ 17 skills</td></tr>
+ <tr><td class="feature-name">AI Tool Calling</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅ 19+ tools</td></tr>
+ <tr><td class="feature-name">AI Memory</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅ Session save/load</td></tr>
+ <tr><td class="feature-name">Self-improving</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅ Skills sync</td></tr>
+ <tr><td class="feature-name">PDF Support</td><td>✅ Link</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr>
+ <tr><td class="feature-name">File Manager</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅ Virtual FS</td></tr>
+ <tr><td class="feature-name">Theme Presets</td><td>✅</td><td>✅</td><td>✅</td><td>✅ Custom</td><td>✅ 9 presets</td></tr>
+ <tr><td class="feature-name">Voice Input</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅</td></tr>
+ <tr><td class="feature-name">i18n</td><td>✅ 7 langs</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr>
+ <tr><td class="feature-name">Plan Mode</td><td>❌</td><td>❌</td><td>✅</td><td>❌</td><td>❌</td></tr>
+ <tr><td class="feature-name">Session Export</td><td>❌</td><td>❌</td><td>❌</td><td>✅</td><td>✅ VFS export</td></tr>
+ <tr><td class="feature-name">File Upload</td><td>❌</td><td>❌</td><td>❌</td><td>✅</td><td>✅ file attach</td></tr>
+ </table>
</section>
<section>
<h2>Pros & Cons</h2>
- <div class="pro"><strong>✅ Self-improving</strong> — AI can create, patch, and manage its own skills</div>
- <div class="pro"><strong>✅ Rich tool ecosystem</strong> — 41 modules, 130+ commands, search, fetch, webdav, cron, theming, calc, voice, encrypt, shell</div>
- <div class="pro"><strong>✅ AI streaming + auto-compression</strong> — NDJSON stream parsing + context auto-compress at 2000 tokens</div>
- <div class="pro"><strong>✅ SecretVault</strong> — AES-GCM encrypted credential storage, auto-redaction</div>
- <div class="pro"><strong>✅ LLMRouter</strong> — multi-provider with auto-fallback, supports Ollama + any OpenAI-compatible API</div>
- <div class="pro"><strong>✅ Dynamic help system</strong> — no hardcoded help map, new modules appear automatically</div>
- <div class="pro"><strong>✅ VFS Checkpoints + Trash</strong> — snapshot/rollback and safe deletion with trash commands</div>
- <div class="pro"><strong>✅ Tool Registry</strong> — every module reports requirements via <code>requirements()</code></div>
- <div class="pro"><strong>✅ Clean terminal UX</strong> — autocomplete, command history, pipe support, clickable output, mobile responsive</div>
- <div class="pro"><strong>✅ Efficient auto-save</strong> — dirty-flag check skips saves when idle, nesting bug fixed</div>
- <div class="pro"><strong>✅ WebDAV Browser UI</strong> — modal file explorer with breadcrumb nav, preview, upload, download</div>
- <div class="pro"><strong>✅ Self-contained</strong> — no backend needed except Ollama/OpenRouter for AI features</div>
- <div class="pro"><strong>✅ Standalone at <code>/spaces/newos4/</code></strong> — removed duplicate chatstudio/newos4 instance, single source of truth</div>
-
- <div class="con"><strong>❌ Ollama/OpenAI dependency</strong> — AI features require a running provider</div>
- <div class="con"><strong>❌ 8-turn limit</strong> — agent loop max is 8 tool calls, complex tasks may still hit ceiling</div>
- <div class="con"><strong>❌ No module isolation</strong> — all modules share same JS scope</div>
- <div class="con"><strong>❌ No TTS</strong> — voice input only, no text-to-speech for AI responses</div>
- <div class="con"><strong>❌ No nginx token validation</strong> — WebDAV token is decorative; auth via API port 8896</div>
+ <div class="pro"><strong>✅ Self-improving</strong> — AI creates, patches, and manages its own skills. 17 skills in VFS with full CRUD CLI.</div>
+ <div class="pro"><strong>✅ Rich module ecosystem</strong> — 42 module files (25 core + 17 ext), 19 Unix commands, search, fetch, shell, webdav, cron, calc, voice, encrypt, theme, mindmap, editor</div>
+ <div class="pro"><strong>✅ Agentic AI</strong> — 5-turn tool calling loop, 19+ tool definitions, streaming responses, destructive action confirmation with countdown</div>
+ <div class="pro"><strong>✅ 9 Theme Presets</strong> — Dark, light, amber, cyber, ocean, forest, monochrome, sunset, midnight + custom theme creation</div>
+ <div class="pro"><strong>✅ Auto-save sessions</strong> — Dirty-flag auto-save every 60s, VFS crash survival, context restoration on page reload</div>
+ <div class="pro"><strong>✅ Virtual File System</strong> — localStorage-backed persistent filesystem with trash, checkpoints, grep, tree, find</div>
+ <div class="pro"><strong>✅ Inline confirm bar</strong> — Non-blocking action confirmation without dark overlay popup. 120s countdown with color escalation.</div>
+ <div class="pro"><strong>✅ Clean terminal UX</strong> — Autocomplete (commands, files, sessions), command history, pipe support, mobile responsive</div>
+ <div class="pro"><strong>✅ Standalone at <code>/spaces/newos4/</code></strong> — Dedicated instance with nginx autoindex, WebDAV token, full API backend</div>
+
+ <div class="con"><strong>❌ Ollama dependency</strong> — AI features require a running Ollama or compatible provider</div>
+ <div class="con"><strong>❌ 5-turn agent limit</strong> — Complex multi-step tasks may hit the tool-call ceiling</div>
+ <div class="con"><strong>❌ No module isolation</strong> — All 42 modules share same JS scope, potential for collisions</div>
+ <div class="con"><strong>❌ No TTS</strong> — Voice input only (🎤), no text-to-speech for AI responses</div>
+ <div class="con"><strong>❌ No streaming AI</strong> — Agent uses non-streaming chat for tool handling; stream is text-only fallback</div>
+ <div class="con"><strong>❌ Single-file pain point</strong> — 1,031-line main.html with inline CSS+JS is hard to maintain</div>
+ <div class="con"><strong>❌ 42 file loads</strong> — All module scripts loaded sequentially, slow on first visit</div>
</section>
<section>
<h2>Verdict</h2>
- <p>newOS4 v4.2 is the most <strong>feature-rich</strong> version of the WebX11 Terminal. The refactored modular architecture (41 modules with dynamic help, SecretVault, LLMRouter, context compression, VFS checkpoints, trash system, tool registry, and file manager) makes it uniquely capable — while keeping the main.html at just 36KB.</p>
- <p>The dedicated instance at <code>/spaces/newos4/</code> with nginx autoindex, WebDAV token authentication, and a proper API backend gives it real cloud-backed persistence. Session nesting is fixed, auto-save only fires on actual changes, the <code>mem</code> command gives live heap visibility, and output trimming prevents browser crashes under memory pressure.</p>
- <p><strong>Best for:</strong> Power users, developers, and anyone who wants a browser-based terminal with AI that can learn, grow, and securely store credentials.</p>
+ <p>newOS4 v4.2 is the most <strong>feature-rich</strong> ChatStudio variant — an in-browser terminal OS with agentic AI, persistent virtual filesystem, skills system, 9 themes, voice input, and 42 modular components. At 52KB for the main HTML (800KB total codebase), it packs enormous functionality into a self-contained browser app.</p>
+ <p>The key distinction from other variants: newOS4 is a <strong>terminal OS</strong>, not a chat UI. It's designed for power users who want AI-assisted file management, shell commands, and automated workflows — not just conversation.</p>
+ <p><strong>Best for:</strong> Power users, developers, AI experimentation, anyone who wants a browser-based terminal with learning AI.</p>
<p><strong>Not for:</strong> Users who just want quick AI chat, or users without Ollama/OpenRouter access.</p>
- <p>Rating: <strong>🧩🧩🧩🧩🧩</strong> (5/5 — most advanced WebX11 Terminal variant)</p>
+ <p>Rating: <strong>🧩🧩🧩🧩</strong> (4/5 — most advanced ChatStudio variant, trimmed down from peak but still unmatched in features)</p>
<p style="margin-top:20px;">📖 <a href="/spaces/newos4/help.html" style="color:var(--accent);">Full documentation available here →</a></p>
</section>
</div>
</body>
-</html>
+</html> \ No newline at end of file