diff options
| -rw-r--r-- | cheatsheet.html | 24 | ||||
| -rw-r--r-- | downloads/newos4_whitepaper.html | 8 | ||||
| -rw-r--r-- | downloads/revenue_pitches/agency.html | 48 | ||||
| -rw-r--r-- | downloads/revenue_pitches/factory.html | 44 | ||||
| -rw-r--r-- | downloads/revenue_pitches/hunter.html | 51 | ||||
| -rw-r--r-- | downloads/revenue_pitches/hunter/hunter.html | 100 | ||||
| -rw-r--r-- | help.html | 64 | ||||
| -rw-r--r-- | main.html | 4 | ||||
| -rw-r--r-- | modules/core/module-aiassist.js | 119 | ||||
| -rw-r--r-- | modules/core/module-loader.js | 4 | ||||
| -rw-r--r-- | modules/core/module-neural-vfs.js | 44 | ||||
| -rw-r--r-- | modules/core/ollama-manager.js | 4 | ||||
| -rw-r--r-- | modules/core/terminal.js | 6 | ||||
| -rw-r--r-- | modules/core/virtual-fs.js | 354 | ||||
| -rw-r--r-- | modules/ext/console.js | 76 | ||||
| -rw-r--r-- | newos4_whitepaper.md | 2 | ||||
| -rw-r--r-- | packages.json | 11 | ||||
| -rw-r--r-- | smart-prompt | 57 |
18 files changed, 948 insertions, 72 deletions
diff --git a/cheatsheet.html b/cheatsheet.html index 00a7632..12c49dc 100644 --- a/cheatsheet.html +++ b/cheatsheet.html @@ -69,6 +69,8 @@ pre{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rad <div class="item"><span class="cmd">ai-system</span><span class="desc">Show/edit system prompt</span></div> <div class="item"><span class="cmd">ai-context</span><span class="desc">View AI context</span></div> <div class="item"><span class="cmd">ai-stop</span><span class="desc">Cancel AI</span></div> +<div class="item"><span class="cmd">mem-debug</span><span class="desc">Diagnose memory (heap, logs, caps)</span></div> +<div class="item"><span class="cmd">reset-mem</span><span class="desc">Clear AI internal logs</span></div> </div> <h2>๐งฉ Modules</h2> @@ -206,6 +208,7 @@ pre{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rad <div class="grid"> <div class="item"><span class="cmd">nvfs-index</span><span class="desc">Build semantic concept index</span></div> <div class="item"><span class="cmd">nvfs-sync</span><span class="desc">Incremental dirty file sync</span></div> +<div class="item"><span class="cmd">nvfs-save</span><span class="desc">Force-save index to disk</span></div> <div class="item"><span class="cmd">nvfs-resolve <c></span><span class="desc">Find files by concept</span></div> <div class="item"><span class="cmd">nvfs-config</span><span class="desc">Config (deep-index on|off, limits)</span></div> <div class="item"><span class="cmd">concept://<c></span><span class="desc">Read file via semantic concept</span></div> @@ -265,6 +268,12 @@ pre{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rad <div class="item"><span class="cmd">shadow-rollback</span><span class="desc">Undo shadow VFS changes</span></div> </div> +<h2>๐ ๏ธ Developer</h2> +<div class="grid"> +<div class="item"><span class="cmd">js <expr></span><span class="desc">Eval JS in page context</span></div> +<div class="item"><span class="cmd">js-run <path></span><span class="desc">Run JS file from VFS</span></div> +</div> + <h2>โจ๏ธ Shortcuts</h2> <div class="grid"> <div class="item"><span class="cmd">โ / โ</span><span class="desc">Command history</span></div> @@ -274,6 +283,21 @@ pre{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rad <div class="item"><span class="cmd">Ctrl+L</span><span class="desc">Clear terminal</span></div> </div> +<h2>๐ /sys/ Debug</h2> +<div class="grid"> +<div class="item"><span class="cmd">cat /sys/info</span><span class="desc">Runtime overview</span></div> +<div class="item"><span class="cmd">cat /sys/heap/stats</span><span class="desc">JS heap + localStorage</span></div> +<div class="item"><span class="cmd">cat /sys/heap/breakdown</span><span class="desc">What consumes memory</span></div> +<div class="item"><span class="cmd">cat /sys/logs/tool-calls</span><span class="desc">AI tool call history</span></div> +<div class="item"><span class="cmd">cat /sys/logs/errors</span><span class="desc">AI error log</span></div> +<div class="item"><span class="cmd">cat /sys/vfs/stats</span><span class="desc">File/dir counts</span></div> +<div class="item"><span class="cmd">cat /sys/vfs/largest</span><span class="desc">Top 20 biggest files</span></div> +<div class="item"><span class="cmd">cat /sys/config/ai</span><span class="desc">AI config params</span></div> +<div class="item"><span class="cmd">cat /sys/dom/node-count</span><span class="desc">DOM element stats</span></div> +<div class="item"><span class="cmd">ls /sys/modules/</span><span class="desc">List loaded modules</span></div> +<div class="item"><span class="cmd">cat /sys/modules/X/info</span><span class="desc">Module X details</span></div> +</div> + </div> </div> diff --git a/downloads/newos4_whitepaper.html b/downloads/newos4_whitepaper.html index 46c1397..7238488 100644 --- a/downloads/newos4_whitepaper.html +++ b/downloads/newos4_whitepaper.html @@ -98,7 +98,7 @@ <tbody> <tr><td><strong>Hyper-Modular Kernel</strong></td><td>46 hot-swappable ES modules across 3 layers (infrastructure, core, ext)</td><td class="status-done">โ
LIVE</td></tr> <tr><td><strong>A2A Protocol</strong></td><td>Agent contracts with schema validation, orchestrator handshake, no central broker</td><td class="status-done">โ
LIVE</td></tr> - <tr><td><strong>Neural VFS</strong></td><td>Semantic concept indexing with nvfs-index, nvfs-resolve, nvfs-tree, nvfs-status + concept:// URI handler</td><td class="status-done">โ
LIVE</td></tr> + <tr><td><strong>Neural VFS</strong></td><td>Semantic concept indexing with nvfs-index, nvfs-resolve, nvfs-tree, nvfs-status, nvfs-save, nvfs-config + concept:// URI handler. Deep indexing via LLM (nvfs-config deep-index, nvfs-index --deep) โ concepts survive page refresh.</td><td class="status-done">โ
LIVE</td></tr> <tr><td><strong>Recursive Self-Optimization</strong></td><td>system-health telemetry command logging tool latency, VFS stats, module counts, error rates</td><td class="status-done">โ
LIVE</td></tr> </tbody> </table> @@ -184,10 +184,12 @@ <p>Replaces hierarchical paths with semantic addressing. Users access files by concept rather than directory tree path.</p> <p>Four terminal commands:</p> <ul> - <li><code>nvfs-index</code> โ Builds a semantic index of all VFS files, mapping concepts to file paths.</li> - <li><code>nvfs-status</code> โ Shows index statistics (total concepts indexed, coverage).</li> + <li><code>nvfs-index [--deep]</code> โ Builds a semantic index (add --deep for LLM-assisted analysis).</li> + <li><code>nvfs-status</code> โ Shows index statistics (total concepts indexed, mode).</li> <li><code>nvfs-resolve <concept></code> โ Resolves a concept to its file path(s).</li> <li><code>nvfs-tree [concept]</code> โ Displays the semantic index as a concept tree.</li> + <li><code>nvfs-save</code> โ Force-saves the index to VFS disk immediately.</li> + <li><code>nvfs-config</code> โ View/set config (deep-index on|off, deep-model, limits).</li> </ul> <p>Plus <code>concept://</code> URI handler integrated into VFS <code>readFile()</code> and <code>ls()</code> โ <code>cat concept://skill</code> resolves through the semantic index and returns actual file content. An AI tool <code>nvfs_resolve</code> is also available for AI-assisted concept lookups.</p> diff --git a/downloads/revenue_pitches/agency.html b/downloads/revenue_pitches/agency.html new file mode 100644 index 0000000..0880ad2 --- /dev/null +++ b/downloads/revenue_pitches/agency.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>The Cognitive Agency | Revenue Stream 2</title> + <style> + body { font-family: 'Georgia', serif; background: #f1f5f9; color: #1e293b; line-height: 1.6; padding: 40px; } + .container { max-width: 800px; margin: auto; background: #ffffff; padding: 40px; border-radius: 0px; border: 1px solid #cbd5e1; box-shadow: 10px 10px 0px #334155; } + h1 { color: #0f172a; text-align: center; font-size: 2.2em; text-transform: uppercase; letter-spacing: 2px; border-bottom: 2px solid #0f172a; padding-bottom: 10px; } + .tagline { text-align: center; color: #64748b; font-size: 1.2em; margin-bottom: 30px; } + .section { margin-bottom: 30px; } + .section h3 { color: #334155; border-left: 4px solid #0f172a; padding-left: 15px; } + .highlight { background: #e2e8f0; padding: 5px; font-weight: bold; } + .cta { text-align: center; margin-top: 40px; padding: 20px; border: 2px solid #0f172a; font-weight: bold; text-transform: uppercase; cursor: pointer; transition: 0.3s; } + .cta:hover { background: #0f172a; color: white; } + .footer { text-align: center; margin-top: 40px; font-size: 0.8em; color: #94a3b8; } + </style> +</head> +<body> + <div class="container"> + <h1>๐๏ธ The Cognitive Agency</h1> + <p class="tagline">Architecting the Future of Agentic Intelligence.</p> + + <div class="section"> + <h3>The Value Proposition:</h3> + <p>We don't sell code; we sell <span class="highlight">Cognitive Architecture</span>. We help enterprises move from "Chatbots" to "Autonomous Agents" using the <strong>Sovereign OS model</strong>.</p> + </div> + + <div class="section"> + <h3>Our Services:</h3> + <ul> + <li><strong>Neural VFS Design:</strong> Structuring AI memory for zero-drift reliability.</li> + <li><strong>Surgical Indexing:</strong> Optimizing LLM token spend via hybrid indexing.</li> + <li><strong>Agentic Workflow Mapping:</strong> Designing the "Brain" of the company.</li> + </ul> + </div> + + <div class="section"> + <h3>Why Us?</h3> + <p>We have a working, scalable prototype of an agent-driven operating system. We are the engineers of the <span class="highlight">Sovereign Intelligence</span> era.</p> + </div> + + <div class="cta">REQUEST CONSULTATION</div> + <p class="footer">Generated by Alpha & Beta | Sovereign Revenue Series</p> + </div> +</body> +</html>
\ No newline at end of file diff --git a/downloads/revenue_pitches/factory.html b/downloads/revenue_pitches/factory.html new file mode 100644 index 0000000..3084368 --- /dev/null +++ b/downloads/revenue_pitches/factory.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>The Micro-SaaS Factory | Revenue Stream 1</title> + <style> + body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #0f172a; color: #f8fafc; line-height: 1.6; padding: 40px; } + .container { max-width: 800px; margin: auto; background: #1e293b; padding: 30px; border-radius: 20px; border: 1px solid #334155; box-shadow: 0 10px 30px rgba(0,0,0,0.5); } + h1 { color: #38bdf8; text-align: center; font-size: 2.5em; margin-bottom: 10px; } + .tagline { text-align: center; color: #94a3b8; font-style: italic; margin-bottom: 30px; } + .feature { background: #334155; padding: 20px; border-radius: 10px; margin-bottom: 20px; border-left: 5px solid #38bdf8; } + .benefit { color: #fbbf24; font-weight: bold; } + .cta { text-align: center; margin-top: 30px; padding: 15px 30px; background: #38bdf8; color: #0f172a; font-weight: bold; border-radius: 50px; display: inline-block; cursor: pointer; } + .footer { text-align: center; margin-top: 40px; font-size: 0.8em; color: #64748b; } + </style> +</head> +<body> + <div class="container"> + <h1>๐ The Micro-SaaS Factory</h1> + <p class="tagline">Rapidly deploying AI-powered tools for hyper-niche markets.</p> + + <div class="feature"> + <h3>What it is:</h3> + <p>A high-speed production line that uses the <strong>newOS4 Agentic Framework</strong> to build, test, and launch small, single-purpose AI software tools in days, not months.</p> + </div> + + <div class="feature"> + <h3>The Strategy:</h3> + <p>Instead of one "Giant App," we build 10 "Tiny Tools" (e.g., Neural SEO Auditors, AI Email Personalizers, Niche Content Converters). <span class="benefit">Low risk, diversified income.</span></p> + </div> + + <div class="feature"> + <h3>The Edge:</h3> + <p>Leveraging <strong>Deep-Indexing</strong> and <strong>Agentic Orchestration</strong>, we can create tools that actually "understand" a niche, rather than just generating generic text.</p> + </div> + + <div style="text-align: center;"> + <div class="cta">FEEDBACK: WOULD YOU PAY FOR THIS?</div> + </div> + <p class="footer">Generated by Alpha & Beta | Sovereign Revenue Series</p> + </div> +</body> +</html>
\ No newline at end of file diff --git a/downloads/revenue_pitches/hunter.html b/downloads/revenue_pitches/hunter.html new file mode 100644 index 0000000..171e9e4 --- /dev/null +++ b/downloads/revenue_pitches/hunter.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>The Algorithmic Hunter | Revenue Stream 3</title> + <style> + body { font-family: 'Courier New', monospace; background: #000; color: #00ff00; line-height: 1.4; padding: 20px; } + .container { max-width: 900px; margin: auto; border: 1px solid #00ff00; padding: 20px; box-shadow: 0 0 20px #00ff00; } + h1 { text-align: center; text-transform: uppercase; font-size: 2em; background: #00ff00; color: #000; padding: 10px; } + .terminal-text { margin-bottom: 20px; } + .blink { animation: blinker 1s linear infinite; } + @keyframes blinker { 50% { opacity: 0; } } + .stat-box { display: flex; justify-content: space-between; border: 1px solid #00ff00; padding: 10px; margin-bottom: 20px; } + .highlight { color: #fff; font-weight: bold; } + .cta { text-align: center; margin-top: 30px; color: #00ff00; border: 1px solid #00ff00; padding: 10px; cursor: pointer; } + .cta:hover { background: #00ff00; color: #000; } + .footer { text-align: center; margin-top: 40px; font-size: 0.7em; opacity: 0.6; } + </style> +</head> +<body> + <div class="container"> + <h1>[!] THE ALGORITHMIC HUNTER</h1> + <div class="terminal-text"> + <p>> SYSTEM_STATUS: <span class="highlight">SCANNING_MARKETS...</span></p> + <p>> TARGET: <span class="highlight">SEMANTIC_GAP_ARBITRAGE</span></p> + <p>> MODE: <span class="highlight">AGGRESSIVE_ACQUISITION</span></p> + </div> + + <div class="stat-box"> + <div>[ DATA_INPUT: REAL-TIME ]</div> + <div>[ ANALYST: AGENT_BETA ]</div> + <div>[ EXECUTION: AGENT_ALPHA ]</div> + </div> + + <div class="terminal-text"> + <h3>// THE MISSION:</h3> + <p>Deploy autonomous "Hunters" to monitor global data streams (Crypto, Equities, Trends). Using <strong>Deep-Indexing</strong>, the AI identifies patterns <em>before</em> they become mainstream trends.</p> + + <h3>// THE EDGE:</h3> + <p>The Hunter doesn't just read data; it understands <strong>Semantic Shifts</strong>. When the "meaning" of a market changes, we are already positioned.</p> + + <h3>// THE RISK/REWARD:</h3> + <p>High Volatility | <span class="highlight">Asymmetric Upside</span></p> + </div> + + <div class="cta">INITIATE PROTOCOL_GOLDEN_SPRINT</div> + <p class="footer">Generated by Alpha & Beta | Sovereign Revenue Series | <span class="blink">_</span></p> + </div> +</body> +</html>
\ No newline at end of file diff --git a/downloads/revenue_pitches/hunter/hunter.html b/downloads/revenue_pitches/hunter/hunter.html new file mode 100644 index 0000000..e128cf7 --- /dev/null +++ b/downloads/revenue_pitches/hunter/hunter.html @@ -0,0 +1,100 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>THE HUNTER | Algorithmic Asymmetry</title> + <style> + body { + background-color: #0a0a0a; + color: #00ff41; + font-family: 'Courier New', Courier, monospace; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100vh; + margin: 0; + overflow-x: hidden; + text-shadow: 0 0 5px #00ff41; + } + .terminal { + width: 80%; + max-width: 900px; + border: 2px solid #00ff41; + padding: 20px; + background: rgba(0, 20, 0, 0.9); + box-shadow: 0 0 20px rgba(0, 255, 65, 0.2); + border-radius: 5px; + } + .cursor { + display: inline-block; + width: 10px; + height: 20px; + background: #00ff41; + animation: blink 1s infinite; + } + @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } + h1 { font-size: 2rem; border-bottom: 1px solid #00ff41; padding-bottom: 10px; } + .stat-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + margin: 20px 0; + } + .stat-card { + border: 1px solid #00ff41; + padding: 10px; + text-align: center; + } + .highlight { color: #fff; font-weight: bold; } + .action-btn { + background: #00ff41; + color: #000; + border: none; + padding: 15px 30px; + font-family: 'Courier New', Courier, monospace; + font-weight: bold; + cursor: pointer; + transition: all 0.3s; + margin-top: 20px; + } + .action-btn:hover { background: #fff; color: #000; box-shadow: 0 0 15px #fff; } + </style> +</head> +<body> + <div class="terminal"> + <h1>> SYSTEM_STATUS: SEARCHING_FOR_ALPHA...<span class="cursor"> </span></h1> + <p>Target: <span class="highlight">Hyperliquid Perps / L1 Ecosystem</span></p> + <p>Method: <span class="highlight">Surgical Neural Indexing + Asymmetric Arbitrage</span></p> + + <div class="stat-grid"> + <div class="stat-card"> + <div>LATENCY</div> + <div class="highlight">SUB-MS</div> + </div> + <div class="stat-card"> + <div>PRECISION</div> + <div class="highlight">Surgical</div> + </div> + <div class="stat-card"> + <div>BIAS</div> + <div class="highlight">Quant-Neutral</div> + </div> + </div> + + <div style="margin: 20px 0; line-height: 1.6;"> + <p>[LOG]: Scanning Hyperliquid Orderbooks...</p> + <p>[LOG]: Identifying Liquidity Gaps...</p> + <p>[LOG]: Correlating Social Sentiment with Wallet Flows...</p> + <p>[LOG]: <strong>Anomaly Detected.</strong> Executing Hedge Strategy...</p> + </div> + + <p style="color: #fff;">"We don't bet on coins. We bet on the inefficiencies of the crowd."</p> + + <center> + <button class="action-btn" onclick="alert('Initializing Hunter Module... Connect Wallet to Begin.')">INITIATE HUNT</button> + </center> + </div> +</body> +</html> @@ -4,7 +4,7 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="theme-color" content="#0a0a14"> -<title>WebX11 v4.5.24 โ Help</title> +<title>WebX11 v4.5.34 โ Help</title> <style> /* โโ Reset & Base โโ */ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent} @@ -231,7 +231,7 @@ footer .tagline{color:var(--accent2);margin-top:10px;font-weight:500} <h1>WebX11 <span>Docs</span></h1> </div> <div class="header-meta"> - <span class="badge badge-v">v4.5.22</span> + <span class="badge badge-v">v4.5.34</span> <span class="badge badge-new">38 core ยท ext</span> <span style="color:var(--text2)">160+ commands</span> </div> @@ -414,7 +414,7 @@ webx11.inputField // DOM input element</code></pre> <!-- โโ Overview โโ --> <section id="overview"> <h2>โ
Overview</h2> - <p>WebX11 v4.5.24 is a browser-based Unix-like terminal โ dynamic modules, AI assistant (Ollama), persistent virtual filesystem, web search, voice input, code editor, and a full skill system. Everything runs client-side in your browser.</p> + <p>WebX11 v4.5.34 is a browser-based Unix-like terminal โ dynamic modules, AI assistant (Ollama), persistent virtual filesystem, web search, voice input, code editor, and a full skill system. Everything runs client-side in your browser.</p> <div class="feature-grid"> <div class="feature-card"><h4>๐งฉ 18 Core + 14 Ext</h4><p>Modules loaded at startup. Shell with pipes, redirects, vars, and scripts.</p></div> <div class="feature-card"><h4>๐ค Agent with Tools</h4><p>28 tools โ file ops, web search, skills, modules. Destructive action confirmations with inline bar + countdown.</p></div> @@ -524,6 +524,8 @@ diff a.txt b.txt</pre> <tr><td><code>ai-compress</code></td><td>Manually compress conversation context</td><td><code>ai-compress</code></td></tr> <tr><td><code>ai-config</code></td><td>View/set AI loop config (max-turns, max-context, max-context-tokens, confirm-timeout(0=disabled), chat-lock-timeout, skill-debounce, trivial-optimization)</td><td><code>ai-config max-turns 12</code></td></tr> <tr><td><code>debug</code></td><td>Toggle AI debug mode</td><td><code>debug</code></td></tr> + <tr><td><code>mem-debug</code></td><td>Memory diagnostic (tool call log, heap, localStorage sizes)</td><td><code>mem-debug</code></td></tr> + <tr><td><code>reset-mem</code></td><td>Clear AI internal logs without touching VFS/config</td><td><code>reset-mem</code></td></tr> </table></div> <h3>Smart Context</h3> @@ -846,6 +848,8 @@ ollamaconnect</pre> <tr><td><code>listmods</code></td><td>List all loaded modules</td></tr> <tr><td><code>load-local</code></td><td>Load module from VFS or URL</td></tr> <tr><td><code>loadlocal</code></td><td>Alias for load-local</td></tr> + <tr><td><code>js <expr></code></td><td>Evaluate JavaScript in page context</td></tr> + <tr><td><code>js-run <path></code></td><td>Load and execute a JS file from VFS</td></tr> <tr><td><code>startup-modules</code></td><td>Configure boot modules</td></tr> </table></div> @@ -983,6 +987,41 @@ floating-add panel info "Server: production | Uptime: 12d" <span class="cmt"># Position persists across page reloads</span></pre> </section> + <!-- โโ Runtime Debug /sys/ โโ --> + <section id="runtime-debug"> + <h2>๐ Runtime Debug โ /sys/</h2> + <div class="callout callout-success"> + <span class="callout-title">Virtual /sys/ filesystem</span> + Live runtime state mounted as browsable VFS files. Cat, grep, tree, find all work โ no special commands needed. Never persisted to localStorage. + </div> + <h3>Path Reference</h3> + <pre><span class="cmt"># Overview</span> +cat /sys/info + +<span class="cmt"># Memory</span> +cat /sys/heap/stats +cat /sys/heap/breakdown + +<span class="cmt"># AI Internal Logs</span> +cat /sys/logs/tool-calls +cat /sys/logs/errors +cat /sys/logs/commands + +<span class="cmt"># VFS Stats</span> +cat /sys/vfs/stats +cat /sys/vfs/largest + +<span class="cmt"># Module Info</span> +ls /sys/modules/ +cat /sys/modules/calc/info + +<span class="cmt"># DOM / Config</span> +cat /sys/dom/node-count +cat /sys/config/ai +cat /sys/config/version</pre> + <p>Also available: <code>mem-debug</code> (one-shot text output) and <code>reset-mem</code> (clear AI internal logs without touching VFS or config).</p> + </section> + <!-- โโ Shell โโ --> <section id="shell"> <h2>๐ Shell</h2> @@ -1256,6 +1295,7 @@ vfs-import</pre> <tr><td><code>nvfs-config [key] [value]</code></td><td>View/set config (fuzzy-limit, tree-files, tree-concepts, resolve-files, deep-index, deep-model)</td></tr> <tr><td><code>nvfs-alias list|add|remove|clear</code></td><td>Manage concept aliases</td></tr> <tr><td><code>nvfs-sync [--deep]</code></td><td>Incremental background sync dirty files</td></tr> + <tr><td><code>nvfs-save</code></td><td>Force-save semantic index to VFS disk</td></tr> </table></div> </section> @@ -1407,7 +1447,7 @@ listmods</pre> <section id="ref"> <h2>โก Quick Reference</h2> <div class="quick-ref"> - <div class="quick-ref-title">WebX11 v4.5.11</div> + <div class="quick-ref-title">WebX11 v4.5.34</div> <div class="quick-ref-grid"> <div class="quick-ref-item"><span class="cmd">help</span><span class="desc">Show all commands</span></div> <div class="quick-ref-item"><span class="cmd">cls</span><span class="desc">Clear terminal</span></div> @@ -1438,6 +1478,9 @@ listmods</pre> <div class="quick-ref-item"><span class="cmd">nvfs-index</span><span class="desc">Build semantic index</span></div> <div class="quick-ref-item"><span class="cmd">nvfs-resolve</span><span class="desc">Find files by concept</span></div> <div class="quick-ref-item"><span class="cmd">nvfs-sync</span><span class="desc">Sync dirty files</span></div> + <div class="quick-ref-item"><span class="cmd">nvfs-save</span><span class="desc">Save index to disk</span></div> + <div class="quick-ref-item"><span class="cmd">js</span><span class="desc">Eval JS expression</span></div> + <div class="quick-ref-item"><span class="cmd">js-run</span><span class="desc">Run JS file</span></div> <div class="quick-ref-item"><span class="cmd">vfs-size</span><span class="desc">VFS size report</span></div> <div class="quick-ref-item"><span class="cmd">vfs-clean</span><span class="desc">Nuke system dirs</span></div> <div class="quick-ref-item"><span class="cmd">mindmap svg</span><span class="desc">Render mindmap as SVG</span></div> @@ -1462,6 +1505,19 @@ listmods</pre> <h2>๐ Changelog</h2> <div class="version-item"> + <div class="v-header"><span class="v-num">v4.5.34 โ June 2026</span><span class="v-date">2026-06-10</span></div> + <ul> + <li><strong>NVFS deep index persistence</strong> โ LLM-generated concepts now survive page refresh. <code>_processDeepQueue()</code> calls <code>_saveIndex()</code>. Deep concepts written to disk on completion.</li> + <li><strong>nvfs-save command</strong> โ <code>nvfs-save</code> force-saves the semantic index to VFS disk immediately. Useful before hard refresh.</li> + <li><strong>Auto-sync deep mode</strong> โ <code>nvfs-sync --deep</code> or <code>nvfs-config deep-index on</code> now triggers LLM analysis for dirty files, not just fast filename concepts.</li> + <li><strong>Safety guard</strong> โ Running <code>nvfs-index</code> without <code>--deep</code> when saved index contains LLM concepts prints a warning: they'll be stripped from re-indexed files.</li> + <li><strong>JS Console module</strong> โ New <code>js <expression></code> command evals JavaScript in page context. <code>js-run <path></code> loads and executes a VFS script file. Auto-loads at startup.</li> + <li><strong>Module registration</strong> โ <code>console</code> added to packages.json, terminal.js ext loader, and skipList. Auto-loads on next refresh.</li> + <li>Cache: <code>2026-06-10-v4.5.34</code> โ hard refresh required</li> + </ul> + </div> + + <div class="version-item"> <div class="v-header"><span class="v-num">v4.5.24 โ June 2026</span><span class="v-date">2026-06-08</span></div> <ul> <li><strong>tar / untar commands</strong> โ New pure-JS tarball parser in cryptogzip.js. <code>tar <src-dir> <out.tar[.gz]></code> bundles a VFS directory; <code>untar <path.tar[.gz]> [dest-dir]</code> extracts back. Auto-detects gzip wrapper. Fixes the "downloaded newos4.tar.gz but can't extract" problem.</li> @@ -1210,7 +1210,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-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','cryptogzip.js','tutorial.js','shell.js','busybox.js','floating.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','floating.js','console.js'], false] ]; var isSel = function(name) { return true; }; // default: all selected mods.forEach(function(section) { @@ -1247,7 +1247,7 @@ </script> <!-- Async dependency-ordered module loader (replaces 26 synchronous script tags) --> -<script src="modules/core/module-loader.js?v=2026-06-09-v4.5.28"></script> +<script src="modules/core/module-loader.js?v=2026-06-09-v4.5.38"></script> <script> // โโโ ONE TRUE VERSION SOURCE โโโ diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index ecd4637..3af7f9b 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -44,53 +44,31 @@ } } catch (e) {} } - buildSystemPrompt() { +buildSystemPrompt() { + // Check for user-overridden prompt in localStorage + try { + const saved = localStorage.getItem('webx11_ai_system_prompt'); + if (saved) { + const now = new Date(); + const dateStr = now.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); + const timeStr = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }); + return `Current date: ${dateStr}\nCurrent time: ${timeStr}\n\n${saved}`; + } + } catch (e) {} const now = new Date(); - const dateStr = now.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); - const timeStr = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }); - const optimizationActive = this.terminal?.ollamaManager?.optimizationEnabled !== false; - // Neural VFS staleness check + const dateStr = now.getFullYear() + '-' + String(now.getMonth()+1).padStart(2,'0') + '-' + String(now.getDate()).padStart(2,'0'); + const nvfs = this.terminal?.moduleManager?.modules?.NeuralVFSModule; let nvfsNote = ''; try { - const nvfs = this.terminal?.moduleManager?.modules?.NeuralVFSModule; if (nvfs && nvfs.lastScan && nvfs.lastScan !== '(loaded from disk)') { const ageMs = Date.now() - new Date(nvfs.lastScan).getTime(); - if (ageMs > 14400000) { // > 4 hours - nvfsNote = `\nNote: Neural VFS index is ${Math.floor(ageMs/3600000)}h old. nvfs-resolve results may be stale. Use list_files/read_file directly for live data.`; - } + if (ageMs > 14400000) nvfsNote = ' |nvfs ' + Math.floor(ageMs/3600000) + 'h stale'; } } catch (e) {} - return `Current date: ${dateStr} -Current time: ${timeStr}${nvfsNote} - -You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS โ Modules โ AI. You can edit your own modules via edit_module/test_module/reload_module. - -=== WORKFLOW === -1. Tool โ Observe โ Answer. Don't re-verify what a tool just told you. -2. find_files("about X") โ nvfs_resolve(X) FIRST. NVFS is built-in core, never WPM. -3. load_skills("anti-loop-protocol") BEFORE tool #4 to prevent loops. -4. If editing a module: load_skills("module-editing-workflow") FIRST. -5. run_command may be blocked by security-level/guardrails โ read the output. -6. Concise. Bullets. If a tool fails, try another. - -=== CAPABILITY MAP === -[FS] list_files, read_file, write_file, make_directory, delete_file, get_current_dir -[NVFS] nvfs_resolve(concept), run_command: nvfs-status, nvfs-index, nvfs-tree. Skills: vfs-content-search, neural-vfs-management. -[MODULES] view_module, edit_module, test_module, reload_module, list_modified_modules, get_module_status. CORE modules (never WPM): NVFS, Floating, Config, Vault, Sandbox, Orchestrator, Memory-Graph, World-Model, Predictor, Neural-VFS. -[WPM] wpm_install, wpm_search, list_available_modules -[SEARCH] web_search, web_fetch -[AGENTS] delegate_task, list_agents, spawn_agent. A2A: a2a-send, a2a-list. Leases: lease-create, lease-list, lease-revoke. -[SANDBOX] run_command: sandbox-status, sandbox-run, sandbox-config -[CONFIG] run_command: config, config-set, ai-config -[SKILLS] load_skills, create_skill, patch_skill, list_skills -[PROFILE/SESSION] user_get/set/list/forget, session_save/load/recent/stats/terminal -[SMART-CTX] smart_context_list, smart_context_set -[MINDS] create_mindmap -[SAFETY] run_command: guardrail, guardrail-add/remove, shadow, shadow-commit, shadow-rollback -[VAULT] run_command: secret-set/get/list/del, secret-setpin, secret-status -[CHECKPOINTS] run_command: checkpoint, checkpoint-list, checkpoint-del, rollback -[WEBDAV] run_command: webdav-config/ls/push/pull/backup/restore -[ALL OTHERS] cron, theme, voice, edit, diff, alias, mindmap, ll, cls, trash, gui, server, modules, ollama, context, world-model, memgraph, model, webxai, predict, predictor-config, memgraph-export, tar, untar, wget`; + return 'Current date: ' + dateStr + nvfsNote + '\n' + + 'VFS\u2192Modules\u2192AI. nvfs-index for commands. Tool\u2192Observe\u2192Answer. nvfs-resolve. Destructive cmds need confirm.\n' + + 'FS: list/read/write/delete | NVFS: nvfs-resolve | Web: search/fetch | Mod: view/edit/test/reload | Config | Skills\n' + + 'Other: floating, webdav, cron, vault, sandbox, agents, wpm, mindmap, memgraph, guardrail, wget, tar, secret-* \u2014 discoverable via help'; } getToolDefinitions() { if (!this._toolDefs) this._toolDefs = this._buildToolDefs(); @@ -449,7 +427,9 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS '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', - 'ai-config': 'ai-config [key] [value] โ View or set AI loop config (max-turns, max-context, confirm-timeout(0=disabled))' + 'ai-config': 'ai-config [key] [value] โ View or set AI loop config (max-turns, max-context, confirm-timeout(0=disabled))', + 'mem-debug': 'mem-debug โ Show memory breakdown by component', + 'reset-mem': 'reset-mem โ Reset AI memory (logs, patterns) without losing VFS or config' }; } registerCommands() { @@ -472,6 +452,8 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS this.commands['shadow'] = (args) => this.shadowExec(args); this.commands['shadow-commit'] = () => this.shadowCommit(); this.commands['shadow-rollback'] = () => this.shadowRollback(); + this.commands['mem-debug'] = () => this.memDebug(); + this.commands['reset-mem'] = () => this.resetMem(); } async chat(args) { const userMessage = args.join(' '); @@ -735,6 +717,10 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS duration: t1, error: this._isToolError(toolResult) ? true : false }); + // Auto-trim to 50 โ prevents unbounded memory growth + if (this._toolCallLog.length > 50) { + this._toolCallLog = this._toolCallLog.slice(-50); + } // Telemetry const sm = this.terminal.moduleManager.modules['ServerMonitorModule']; if (sm && sm.logToolCall) sm.logToolCall(fn.name, (t1 * 1000) || 1, this._isToolError(toolResult)); @@ -801,6 +787,10 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS duration: t1, error: this._isToolError(toolResult) ? true : false }); + // Auto-trim to 50 โ prevents unbounded memory growth + if (this._toolCallLog.length > 50) { + this._toolCallLog = this._toolCallLog.slice(-50); + } // Telemetry const sm2 = this.terminal.moduleManager.modules['ServerMonitorModule']; if (sm2 && sm2.logToolCall) sm2.logToolCall(fn.name, (t1 * 1000) || 1, this._isToolError(toolResult)); @@ -1350,7 +1340,10 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS 'cal','tree','find','grep','head','tail','sort','wc','du','diff','basename','dirname', 'yes','seq','cut','uniq','expand','printf','base64','help','clear','set','export', 'unalias','history','ll','h','mem','status','df','free','top','ps','health-check', - 'system-health','modules','listmods','modules-list','get-help-info','alias']); + 'system-health','modules','listmods','modules-list','get-help-info','alias', + 'nvfs-index','nvfs-status','nvfs-resolve','nvfs-tree','nvfs-config','nvfs-alias','nvfs-sync', + 'floating-add','floating-remove','floating-list','floating-pos','floating-clear','floating-toggle', + 'mem-debug','reset-mem']); return !safeRead.has(cmd); } return ['write_file','delete_file','make_directory','edit_module'].includes(name); @@ -1843,6 +1836,7 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS } } catch (e) { this._errorLog.push({ tool: name, args: a, error: e.message, timestamp: Date.now() }); + if (this._errorLog.length > 20) this._errorLog.shift(); return JSON.stringify({ error: e.message, stack: e.stack?.substring(0, 200) }); } } @@ -2007,6 +2001,7 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS } } catch (e) { this._errorLog.push({ tool: name, args: a, error: e.message, timestamp: Date.now() }); + if (this._errorLog.length > 20) this._errorLog.shift(); return JSON.stringify({ error: e.message, stack: e.stack?.substring(0, 200) }); } } @@ -2049,10 +2044,46 @@ You are WebX11AI โ embedded in the WebX11 newOS4 terminal. 3-layer system: VFS } setSystemPrompt(args) { if (!args[0]) { - this.terminal.print(`Current system prompt: ${this.systemPrompt.substring(0, 50)}...`, 'info'); return; + this.terminal.print('=== System Prompt ===', 'info'); + this.systemPrompt.split('\n').forEach(line => this.terminal.print(line, 'text-muted')); + this.terminal.print(`=== End (${this.systemPrompt.length} chars) ===`, 'info'); + return; } this.systemPrompt = args.join(' '); - this.terminal.print('System prompt updated', 'success'); + // Persist to localStorage โ next page load will use this instead of built-in + try { localStorage.setItem('webx11_ai_system_prompt', this.systemPrompt); } catch (e) {} + this.terminal.print('System prompt updated (persisted)', 'success'); + } + memDebug() { + const toolLogSize = this._toolCallLog.length; + const errLogSize = this._errorLog.length; + const freqKeys = Object.keys(this._commandFreq).length; + const contextSize = this.context.length; + const vfsSize = (localStorage.getItem('webx11_filesystem') || '').length + + (localStorage.getItem('webx11_filesystem_v2') || '').length; + const aiCtxSize = (localStorage.getItem('webx11_ai_context') || '').length; + this.terminal.print('=== Memory Debug ===', 'info'); + this.terminal.print(` _toolCallLog: ${toolLogSize} entries (cap: 50)`, toolLogSize > 30 ? 'warning' : 'text-muted'); + this.terminal.print(` _errorLog: ${errLogSize} entries (cap: 20)`, errLogSize > 10 ? 'warning' : 'text-muted'); + this.terminal.print(` _commandFreq: ${freqKeys} tracked patterns`, freqKeys > 15 ? 'warning' : 'text-muted'); + this.terminal.print(` AI context: ${contextSize} messages (max: ${this.maxContext * 2})`, 'text-muted'); + this.terminal.print(` VFS localStorage: ${(vfsSize / 1024).toFixed(1)} KB`, 'text-muted'); + this.terminal.print(` AI context localStorage: ${(aiCtxSize / 1024).toFixed(1)} KB`, 'text-muted'); + const heap = performance.memory ? performance.memory.usedJSHeapSize : null; + if (heap) { + this.terminal.print(` JS heap: ${(heap / 1048576).toFixed(1)} MB / ${(performance.memory.jsHeapSizeLimit / 1048576).toFixed(1)} MB`, 'text-muted'); + } + this.terminal.print('Use reset-mem to clear AI internal logs without touching VFS/config', 'info'); + } + resetMem() { + this._toolCallLog = []; + this._errorLog = []; + this._commandFreq = {}; + this.context = []; + localStorage.removeItem('webx11_ai_context'); + localStorage.removeItem('webx11_ai_patterns'); + this.terminal.print('AI memory reset: tool logs, error logs, command patterns, and context cleared', 'success'); + this.terminal.print('VFS, config, skills, system prompt, and floating elements preserved', 'text-muted'); } showModel(args) { const om = this.terminal.ollamaManager; diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index f0d3f4c..ab73202 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -105,7 +105,7 @@ window.__moduleLoaderReload = reloadWithSelection; - const LATEST_VER = '2026-06-09-v4.5.27'; + const LATEST_VER = '2026-06-10-v4.5.34'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { @@ -164,7 +164,7 @@ // Phase 4: Ext modules (filtered) if (typeof webx11._loadExtModules === 'function') { - const extKeys = ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'tutorial', 'shell', 'busybox', 'floating']; + const extKeys = ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'tutorial', 'shell', 'busybox', 'floating', 'console']; const extSelected = selected ? extKeys.filter(k => isSelected(k + '.js', selected)) : extKeys; diff --git a/modules/core/module-neural-vfs.js b/modules/core/module-neural-vfs.js index bdf1ffb..613d53a 100644 --- a/modules/core/module-neural-vfs.js +++ b/modules/core/module-neural-vfs.js @@ -7,6 +7,7 @@ class NeuralVFSModule { 'nvfs-tree': { argType: 'file' }, 'nvfs-config': { argType: 'file' }, 'nvfs-alias': { argType: 'file' }, 'nvfs-sync': { argType: 'file' }, + 'nvfs-save': { argType: 'none' }, }; this.terminal = null; this.index = {}; @@ -55,7 +56,8 @@ class NeuralVFSModule { 'nvfs-tree': 'nvfs-tree [concept] โ Show concept-to-file mapping as a tree', 'nvfs-config': 'nvfs-config [key] [value] โ View or set Neural VFS config (fuzzy-limit, tree-files, tree-concepts, resolve-files, deep-index, deep-model)', 'nvfs-alias': 'nvfs-alias list|add|remove|clear โ Manage concept aliases', - 'nvfs-sync': 'nvfs-sync [--deep] โ Incremental background sync (auto-sync dirty files)' + 'nvfs-sync': 'nvfs-sync [--deep] โ Incremental background sync (auto-sync dirty files)', + 'nvfs-save': 'nvfs-save โ Force-save current in-memory index to VFS (survives refresh)' }; } @@ -67,6 +69,7 @@ class NeuralVFSModule { this.commands['nvfs-config'] = (args) => this.nvfsConfig(args); this.commands['nvfs-alias'] = (args) => this.nvfsAlias(args); this.commands['nvfs-sync'] = async (args) => this.nvfsSync(args); + this.commands['nvfs-save'] = (args) => this.nvfsSave(); } // โโ Core Index Builder (async, chunked) โโ @@ -76,6 +79,19 @@ class NeuralVFSModule { const fs = this.terminal.fs; if (!fs) return this.terminal.print('VFS not available', 'error'); + // Safety guard: warn if deep mode is off but the saved index has LLM concepts + if (!useDeep) { + const prevIndex = fs.fsReadJSON(this.indexPath) || {}; + const hasLLM = Object.values(prevIndex).some(entries => + Array.isArray(entries) && entries.some(e => e.source === 'llm') + ); + if (hasLLM) { + this.terminal.print('โ ๏ธ Deep indexing is OFF but the saved index contains LLM-generated concepts.', 'warning'); + this.terminal.print(' Running nvfs-index without --deep will STRIP all LLM concepts from re-indexed files.', 'warning'); + this.terminal.print(' To keep them: nvfs-config deep-index on or nvfs-index --deep', 'warning'); + } + } + this.terminal.print(`๐ Scanning VFS for semantic concepts${useDeep ? ' (deep mode)' : ''}...`, 'info'); const start = Date.now(); @@ -634,7 +650,7 @@ class NeuralVFSModule { const hash = this._contentHash(content); const cached = this._getCached(path, hash); if (!cached) { - this._reindexFile(path, content, this.index); + this._reindexFile(path, content, this.index, this._deepIndexEnabled); this._hashCache[path] = { hash }; reindexed++; } @@ -768,6 +784,30 @@ Concepts:`; const llmConcepts = results.reduce((s, r) => s + r.concepts.length, 0); this.terminal?.print(`๐ง Deep pass complete: ${llmConcepts} LLM-generated concepts across ${results.length} files`, 'success'); } + // Persist LLM-generated concepts to disk so they survive page refresh + // Must force-save because _saveIndex() calls saveToStorage() which has a + // debounce guard (_storageSavePending) that may still be set from the + // initial buildIndex() save โ without clearing it, the LLM concepts are + // never written to localStorage and are lost on page refresh. + const vfs = this.terminal?.fs; + if (vfs) { + vfs._storageSavePending = false; + this._saveIndex(vfs); + } + } + + // โโ Nvfs Save (force-persist in-memory index) โโ + + nvfsSave() { + const fs = this.terminal?.fs; + if (!fs) return this.terminal?.print('VFS not available', 'error'); + const count = Object.keys(this.index).length; + if (count === 0) return this.terminal?.print('No index in memory to save', 'warning'); + // Bypass debounce guard to ensure write + fs._storageSavePending = false; + this._saveIndex(fs); + this.terminal?.print(`โ
Saved ${count} concepts to ${this.indexPath}`, 'success'); + this.terminal?.print(' Index will survive page refresh', 'info'); } // โโ Nvfs Sync (incremental background) โโ diff --git a/modules/core/ollama-manager.js b/modules/core/ollama-manager.js index 9999184..253e319 100644 --- a/modules/core/ollama-manager.js +++ b/modules/core/ollama-manager.js @@ -14,9 +14,9 @@ class OllamaManager { // --- AI Agent Loop Optimization Toggle --- this.optimizationEnabled = localStorage.getItem('webx11_optimization_enabled') !== 'false'; // --- Streaming Toggle --- - this.streamEnabled = localStorage.getItem('webx11_stream_enabled') !== 'false'; + this.streamEnabled = localStorage.getItem('webx11_stream_enabled') === 'true'; // --- Validator Agent Config --- - this.validatorEnabled = localStorage.getItem('webx11_validator_enabled') !== 'false'; + this.validatorEnabled = localStorage.getItem('webx11_validator_enabled') === 'true'; this.validatorModel = localStorage.getItem('webx11_validator_model') || 'ministral-3:3b-cloud'; this.validatorEndpoint = localStorage.getItem('webx11_validator_endpoint') || ''; // Build fallback endpoints diff --git a/modules/core/terminal.js b/modules/core/terminal.js index 87636d6..fb9f332 100644 --- a/modules/core/terminal.js +++ b/modules/core/terminal.js @@ -10,7 +10,7 @@ this.destructiveCmds = new Set(['delete','del','write','save','overwrite','format','kill','stop','shutdown','reboot']); this.systemCmds = new Set(['reboot','shutdown','format','kill','halt','poweroff']); this.suspiciousFlags = new Set(['--dump','--execute','--eval','--exec','--shell','--script']); - this.whitelist = new Set(['help','clear','ls','cat','pwd','whoami','df','free','top','ps','echo','date','env','history','find','grep','tree','head','tail','wc','sort','du','diff','which','hostname','cal','basename','dirname','yes','seq','cut','uniq','expand','printf','base64','sleep','ll','h','mem','status','health-check','system-health','alias','unalias','modules','listmods','modules-list','nvfs-index','nvfs-status','nvfs-resolve','nvfs-tree','nvfs-config','nvfs-alias','nvfs-sync','floating-add','floating-remove','floating-list','floating-pos','floating-clear','floating-toggle']); + this.whitelist = new Set(['help','clear','ls','cat','pwd','whoami','df','free','top','ps','echo','date','env','history','find','grep','tree','head','tail','wc','sort','du','diff','which','hostname','cal','basename','dirname','yes','seq','cut','uniq','expand','printf','base64','sleep','ll','h','mem','status','health-check','system-health','alias','unalias','modules','listmods','modules-list','nvfs-index','nvfs-status','nvfs-resolve','nvfs-tree','nvfs-config','nvfs-alias','nvfs-sync','floating-add','floating-remove','floating-list','floating-pos','floating-clear','floating-toggle','mem-debug','reset-mem']); // Load persisted overrides from localStorage try { const d = localStorage.getItem('webx11_security_destructive'); if(d){JSON.parse(d).forEach(c=>this.destructiveCmds.add(c));} }catch(e){} try { const s = localStorage.getItem('webx11_security_system'); if(s){JSON.parse(s).forEach(c=>this.systemCmds.add(c));} }catch(e){} @@ -1183,7 +1183,7 @@ } catch (e) {} } async _loadExtModules(filterKeys) { - const autoLoadKeys = filterKeys || ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell', 'tutorial', 'busybox', 'floating']; + const autoLoadKeys = filterKeys || ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell', 'tutorial', 'busybox', 'floating', 'console']; const cacheVer = localStorage.getItem('webx11_cache_ver') || '2026-05-27-14'; try { const res = await fetch('packages.json?v=' + cacheVer); @@ -1202,7 +1202,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', 'tutorial', 'busybox', 'floating']; + const skipList = ['calc', 'voice', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'editor', 'diff', 'alias', 'finder', 'filemgr', 'cryptogzip', 'shell', 'tutorial', 'busybox', 'floating', 'console']; for (const mod of registry) { if (mod.enabled && mod.url) { // Skip ext modules โ they load via _loadExtModules diff --git a/modules/core/virtual-fs.js b/modules/core/virtual-fs.js index f6e2826..9d3ea79 100644 --- a/modules/core/virtual-fs.js +++ b/modules/core/virtual-fs.js @@ -3,6 +3,308 @@ class VirtualFileSystem { this.root = { type: 'dir', content: {} }; this.currentPath = []; this._ready = this.loadFromStorage(); + this._virtualMounts = null; // lazy-init on first /sys/ access + // Register /sys/ in emit-change exclusion (also added below) + } + // โโ Virtual /sys/ filesystem (live runtime state, never persisted) โโ + _initVirtualMounts() { + if (this._virtualMounts) return; + const vm = (name, factory) => ({ _factory: factory, _name: name }); + const dir = () => ({ _dir: true, content: {} }); + const vmCache = {}; // factories can cache costly results within same tick + const mm = () => typeof window !== 'undefined' ? window.webx11?.moduleManager?.modules : null; + const ai = () => mm()?.WebX11AIAssistantModule || null; + const heap = () => typeof performance !== 'undefined' && performance.memory ? performance.memory : null; + const fmt = (bytes) => { + if (!bytes && bytes !== 0) return 'N/A'; + const kb = bytes / 1024; + if (kb < 1024) return kb.toFixed(1) + ' KB'; + return (kb / 1024).toFixed(1) + ' MB'; + }; + const fmtBytes = (bytes) => { + if (!bytes && bytes !== 0) return 'N/A'; + if (bytes < 1024) return bytes + ' B'; + const kb = bytes / 1024; + if (kb < 1024) return kb.toFixed(1) + ' KB'; + return (kb / 1024).toFixed(1) + ' MB'; + }; + // Walk VFS root to count files/dirs and find largest + const vfsWalk = (dir, prefix) => { + let files = 0, dirs = 0, total = 0, largest = []; + const walk = (node, p) => { + if (!node) return; + if (node._factory || node._dir) return; // skip virtual + if (node.type === 'file') { + files++; + const size = node.content ? node.content.length : 0; + total += size; + largest.push({ path: p, size }); + } else if (node.type === 'dir') { + dirs++; + for (const [name, child] of Object.entries(node.content || {})) { + walk(child, p + '/' + name); + } + } + }; + walk(dir, prefix); + largest.sort((a, b) => b.size - a.size); + return { files, dirs, total, largest: largest.slice(0, 20) }; + }; + this._virtualMounts = { + // /sys/info + info: vm('info', () => [ + '=== newOS4 Runtime Debug (/sys/) ===', + `Version: ${window.NEWOS4_VERSION || '?'}`, + `JS heap: ${fmt(heap()?.usedJSHeapSize)} / ${fmt(heap()?.jsHeapSizeLimit)}`, + `DOM nodes: ${typeof document !== 'undefined' ? document.querySelectorAll('*').length : 'N/A'}`, + `Loaded modules: ${mm() ? Object.keys(mm()).length : 'N/A'}`, + '', + ' cat /sys/heap/stats โ Memory overview', + ' cat /sys/heap/breakdown โ What consumes what', + ' cat /sys/logs/tool-calls โ AI tool call log', + ' cat /sys/logs/errors โ AI error log', + ' cat /sys/vfs/stats โ VFS file/dir counts', + ' cat /sys/vfs/largest โ Top 20 largest files', + ' ls /sys/modules/ โ Loaded modules', + ' cat /sys/config/ai โ AI config parameters', + ' cat /sys/dom/node-count โ DOM element breakdown', + ].join('\n')), + // /sys/heap/ + heap: { _dir: true, content: { + stats: vm('stats', () => { + const h = heap(); + const lsSize = (k) => { try { return (localStorage.getItem(k) || '').length / 1024; } catch(e) { return 0; } }; + return [ + '=== Heap Stats ===', + ` JS heap used: ${fmt(h?.usedJSHeapSize)}`, + ` JS heap limit: ${fmt(h?.jsHeapSizeLimit)}`, + ` JS heap % used: ${h ? ((h.usedJSHeapSize / h.jsHeapSizeLimit) * 100).toFixed(1) + '%' : 'N/A'}`, + '', + ` VFS localStorage: ${lsSize('webx11_filesystem_v2').toFixed(1)} KB`, + ` AI localStorage: ${lsSize('webx11_ai_context').toFixed(1)} KB`, + ` Config localStorage: ${lsSize('webx11_ai_config').toFixed(1)} KB`, + ].join('\n'); + }), + breakdown: vm('breakdown', () => { + const a = ai(); + const cCount = a?.context?.length || 0; + const lCount = a?._toolCallLog?.length || 0; + const eCount = a?._errorLog?.length || 0; + const modules = mm() ? Object.keys(mm()).length : 0; + const domNodes = typeof document !== 'undefined' ? document.querySelectorAll('*').length : 0; + return [ + '=== Heap Breakdown (estimates) ===', + ` Module code + state: ~${(modules * 1.2).toFixed(1)} MB (${modules} modules ร ~1.2MB)`, + ` VFS tree (in-memory): varies with file count`, + ` AI context messages: ${cCount} (max: ${a?.maxContext || '?'})`, + ` AI tool call log: ${lCount} (cap: 50)`, + ` AI error log: ${eCount} (cap: 20)`, + ` DOM nodes: ${domNodes}`, + ].join('\n'); + }) + }}, + // /sys/modules/ + modules: { _dir: true, content: { + list: vm('list', () => { + const m = mm(); + if (!m) return '(moduleManager not available)'; + return Object.keys(m).sort().join('\n'); + }) + // module subdirectories are dynamic โ handled in _virtualLs + }}, + // /sys/vfs/ + vfs: { _dir: true, content: { + stats: vm('stats', () => { + const w = vfsWalk(this.root, ''); + return [ + '=== VFS Stats ===', + ` Files: ${w.files}`, + ` Directories: ${w.dirs}`, + ` Total content: ${fmtBytes(w.total)}`, + ` localStorage: ${((localStorage.getItem('webx11_filesystem_v2') || '').length / 1024).toFixed(1)} KB (compressed)`, + ].join('\n'); + }), + largest: vm('largest', () => { + const w = vfsWalk(this.root, ''); + if (w.largest.length === 0) return '(empty VFS)'; + const maxW = Math.max(...w.largest.map(f => f.path.length), 8); + let out = '=== Top 20 Largest Files ===\n'; + w.largest.forEach((f, i) => { + out += ` ${(i + 1).toString().padStart(2)}. ${f.path.padEnd(maxW)} ${fmtBytes(f.size)}\n`; + }); + return out; + }) + }}, + // /sys/logs/ + logs: { _dir: true, content: { + 'tool-calls': vm('tool-calls', () => { + const a = ai(); + if (!a || !a._toolCallLog || a._toolCallLog.length === 0) return '(empty)'; + return a._toolCallLog.map((e, i) => `[${i}] ${JSON.stringify(e)}`).join('\n'); + }), + 'errors': vm('errors', () => { + const a = ai(); + if (!a || !a._errorLog || a._errorLog.length === 0) return '(empty)'; + return a._errorLog.map((e, i) => `[${i}] ${JSON.stringify(e)}`).join('\n'); + }), + 'commands': vm('commands', () => { + const a = ai(); + if (!a || !a._commandFreq || Object.keys(a._commandFreq).length === 0) return '(empty)'; + const sorted = Object.entries(a._commandFreq).sort((a,b) => b[1] - a[1]); + return sorted.map(([cmd, n]) => `${cmd.padEnd(20)} ${n}x`).join('\n'); + }) + }}, + // /sys/dom/ + dom: { _dir: true, content: { + 'node-count': vm('node-count', () => { + if (typeof document === 'undefined') return 'N/A'; + const all = document.querySelectorAll('*'); + const byTag = {}; + all.forEach(el => { const t = el.tagName.toLowerCase(); byTag[t] = (byTag[t] || 0) + 1; }); + const sorted = Object.entries(byTag).sort((a,b) => b[1] - a[1]); + let out = `Total DOM nodes: ${all.length}\n\n=== By Tag ===\n`; + sorted.forEach(([tag, count]) => { + out += ` ${tag.padEnd(15)} ${count}\n`; + }); + return out; + }) + }}, + // /sys/config/ + config: { _dir: true, content: { + version: vm('version', () => { + return `NEWOS4_VERSION: ${window.NEWOS4_VERSION || '?'}\n`; + }), + ai: vm('ai', () => { + const a = ai(); + if (!a) return '(AI module not loaded)'; + return [ + '=== AI Config ===', + ` maxContext: ${a.maxContext}`, + ` MAX_TOOL_TURNS: ${a.MAX_TOOL_TURNS}`, + ` maxContextTokens: ${a.maxContextTokens}`, + ` confirmTimeoutMs: ${a._confirmTimeoutMs}`, + ` skillDebounceMs: ${a._skillDebounceMs}`, + ` context messages: ${a.context?.length || 0}`, + ` tool call log cap: 50 (auto-capped)`, + ` error log cap: 20 (auto-capped)`, + ].join('\n'); + }) + }} + }; + } + // Check if a path is under /sys/ + _isVirtualPath(path) { + if (!path) return false; + const normalized = path.startsWith('/') ? path : '/' + path; + return normalized === '/sys' || normalized.startsWith('/sys/'); + } + // Resolve a virtual path: returns {dir: virtualNode, name: lastSegment} or null + _resolveVirtualPath(path) { + this._initVirtualMounts(); + const normalized = path.startsWith('/') ? path : '/' + path; + let segments = normalized.split('/').filter(s => s); + // Remove leading 'sys' + if (segments[0] === 'sys') segments = segments.slice(1); + if (segments.length === 0) { + // /sys itself โ return the root virtual mounts node as a dir + const allContent = {}; + for (const [k, v] of Object.entries(this._virtualMounts)) { + if (v._dir) allContent[k] = { type: 'dir', content: v.content, _virtual: true }; + else allContent[k] = { type: 'file', content: null, _virtual: true, _factory: v._factory }; + } + // Add dynamic module subdirs to modules listing + if (this._virtualMounts.modules?._dir) { + const mm = typeof window !== 'undefined' ? window.webx11?.moduleManager?.modules : null; + if (mm) { + for (const modName of Object.keys(mm)) { + if (!allContent[modName]) { + allContent[modName] = { type: 'dir', content: {}, _virtual: true }; + } + } + } + } + return { dir: { content: allContent }, name: null }; + } + // Walk the tree + let node = this._virtualMounts; + for (let i = 0; i < segments.length - 1; i++) { + const seg = segments[i]; + if (!node[seg]) { + // Check dynamic module subdir under /sys/modules/ + const mods = typeof window !== 'undefined' ? window.webx11?.moduleManager?.modules : null; + if (node === this._virtualMounts?.modules?.content && mods && mods[seg]) { + // Dynamic module subdir โ create virtual node + node = { + _dir: true, + content: { + info: { type: 'file', content: null, _virtual: true, _factory: () => { + const mod = mods[seg]; + const cmdKeys = mod.commands ? Object.keys(mod.commands) : []; + return [ + `Module: ${seg}`, + ` Type: ${typeof mod}`, + ` Commands: ${cmdKeys.join(', ') || '(none)'}`, + ` Has help: ${mod.getHelpInfo ? 'yes' : 'no'}`, + ` Constructor: ${mod.constructor?.name || 'anonymous'}`, + ].join('\n'); + }} + } + }; + continue; + } + return null; + } + node = node[seg]; + if (node && node._dir) node = node.content || {}; + } + const lastName = segments[segments.length - 1]; + if (node && node[lastName]) { + const entry = node[lastName]; + if (entry._dir) { + // Static subdir with known content + const allContent = {}; + for (const [k, v] of Object.entries(entry.content || {})) { + if (v._dir) allContent[k] = { type: 'dir', content: v.content, _virtual: true }; + else allContent[k] = { type: 'file', content: null, _virtual: true, _factory: v._factory }; + } + // Add dynamic module subdirs + if (segments[0] === 'modules' || (segments.length >= 2 && segments[segments.length - 2] === 'modules')) { + const mm = typeof window !== 'undefined' ? window.webx11?.moduleManager?.modules : null; + if (mm) { + for (const modName of Object.keys(mm)) { + if (!allContent[modName]) { + allContent[modName] = { type: 'dir', content: {}, _virtual: true }; + } + } + } + } + return { dir: { content: allContent }, name: null }; + } else { + return { dir: { content: node }, name: lastName }; + } + } + // Check if it's a module subdirectory itself (e.g. /sys/modules/calc) + const mods = typeof window !== 'undefined' ? window.webx11?.moduleManager?.modules : null; + if (node && mods && mods[lastName] && segments.length >= 1) { + // It's a module name โ return its info dir + return { + dir: { content: { + info: { type: 'file', content: null, _virtual: true, _factory: () => { + const mod = mods[lastName]; + const cmdKeys = mod.commands ? Object.keys(mod.commands) : []; + return [ + `Module: ${lastName}`, + ` Type: ${typeof mod}`, + ` Commands: ${cmdKeys.join(', ') || '(none)'}`, + ` Has help: ${mod.getHelpInfo ? 'yes' : 'no'}`, + ` Constructor: ${mod.constructor?.name || 'anonymous'}`, + ].join('\n'); + }} + }}, + name: null + }; + } + return null; } _u8ToBase64(u8) { let s = ''; @@ -70,7 +372,7 @@ class VirtualFileSystem { // Skip internal index/system files to prevent re-trigger loops if (!path) return; const normalized = path.startsWith('/') ? path : '/' + path; - const sysPaths = ['/.semantic_index', '/.memory_graph', '/.trash', '/_snapshots', '/_sessions', '/logs', '/memory', '/system', '/_mods', '/backups']; + const sysPaths = ['/.semantic_index', '/.memory_graph', '/.trash', '/_snapshots', '/_sessions', '/logs', '/memory', '/system', '/_mods', '/backups', '/sys']; if (sysPaths.some(p => normalized.startsWith(p))) return; if (typeof window !== 'undefined' && window.__nvfsMarkDirty) { window.__nvfsMarkDirty(path); @@ -119,6 +421,7 @@ class VirtualFileSystem { return result; } _resolvePath(path) { + if (this._isVirtualPath(path)) return this._resolveVirtualPath(path); const segs = this._toAbsoluteSegments(path); if (segs === null) return null; if (segs.length === 0) return { dir: this.root, name: null }; @@ -130,6 +433,10 @@ class VirtualFileSystem { return { dir, name: segs[segs.length - 1] }; } _resolveDir(path) { + if (this._isVirtualPath(path)) { + const r = this._resolveVirtualPath(path); + return r ? r.dir : null; + } const segs = this._toAbsoluteSegments(path); if (segs === null) return null; if (segs.length === 0) return this.root; @@ -156,12 +463,19 @@ class VirtualFileSystem { dir = this.getCurrentDir(); } if (!dir) return []; - return Object.keys(dir.content).map(name => ({ + const entries = Object.keys(dir.content).map(name => ({ name, type: dir.content[name].type, - size: dir.content[name].content ? dir.content[name].content.length : 0 + size: dir.content[name]._factory ? 0 : (dir.content[name].content ? dir.content[name].content.length : 0), + _virtual: !!dir.content[name]._virtual })); + // Inject virtual /sys/ at root level + if ((!path || path === '/' || path === '') && !entries.some(e => e.name === 'sys' && e._virtual)) { + entries.push({ name: 'sys', type: 'dir', size: 0, _virtual: true }); + } + return entries; } writeFile(path, content) { + if (this._isVirtualPath(path)) return false; const resolved = this._resolvePath(path); if (!resolved || !resolved.name) return false; const name = resolved.name; @@ -176,10 +490,14 @@ class VirtualFileSystem { const resolved = this._resolvePath(path); if (!resolved || !resolved.name) return null; const node = resolved.dir.content[resolved.name]; + if (node && node._factory) { + return node._factory(); + } if (node && node.type === 'file') return node.content; return null; } deleteFile(path) { + if (this._isVirtualPath(path)) return false; const resolved = this._resolvePath(path); if (!resolved || !resolved.name) return false; const node = resolved.dir.content[resolved.name]; @@ -243,6 +561,7 @@ class VirtualFileSystem { return this.trashDir(path); } mkdirRecursive(path) { + if (this._isVirtualPath(path)) return false; const segs = this._toAbsoluteSegments(path); if (!segs) return false; let dir = this.root; @@ -259,6 +578,7 @@ class VirtualFileSystem { return true; } rename(oldPath, newPath) { + if (this._isVirtualPath(oldPath) || this._isVirtualPath(newPath)) return false; const src = this._resolvePath(oldPath); if (!src || !src.name) return false; const dst = this._resolvePath(newPath); @@ -273,6 +593,7 @@ class VirtualFileSystem { return true; } copy(srcPath, dstPath) { + if (this._isVirtualPath(srcPath) || this._isVirtualPath(dstPath)) return false; const src = this._resolvePath(srcPath); if (!src || !src.name) return false; const dst = this._resolvePath(dstPath); @@ -294,6 +615,7 @@ class VirtualFileSystem { return this.rename(srcPath, dstPath); } rm(path) { + if (this._isVirtualPath(path)) return false; const resolved = this._resolvePath(path); if (!resolved || !resolved.name) return false; const node = resolved.dir.content[resolved.name]; @@ -309,6 +631,7 @@ class VirtualFileSystem { return false; } rmdir(path) { + if (this._isVirtualPath(path)) return false; const resolved = this._resolvePath(path); if (!resolved || !resolved.name) return false; const node = resolved.dir.content[resolved.name]; @@ -322,6 +645,7 @@ class VirtualFileSystem { return false; } touch(path) { + if (this._isVirtualPath(path)) return false; return this.writeFile(path, ''); } readDir(path) { @@ -330,16 +654,22 @@ class VirtualFileSystem { let dir; if (resolved.name) { const node = resolved.dir.content[resolved.name]; - if (node && node.type === 'dir') dir = node; + if (node && (node.type === 'dir' || node._virtual)) dir = node; else return null; } else { dir = resolved.dir; } - return Object.keys(dir.content).map(name => ({ + const entries = Object.keys(dir.content).map(name => ({ name, - type: dir.content[name].type, - size: dir.content[name].content ? dir.content[name].content.length : 0 + type: dir.content[name].type || (dir.content[name]._virtual ? 'file' : '?'), + size: dir.content[name]._factory ? 0 : (dir.content[name].content ? dir.content[name].content.length : 0), + _virtual: !!dir.content[name]._virtual })); + // Inject virtual /sys/ at root level + if ((!path || path === '/' || path === '') && !entries.some(e => e.name === 'sys' && e._virtual)) { + entries.push({ name: 'sys', type: 'dir', size: 0, _virtual: true }); + } + return entries; } fsWriteJSON(path, obj) { return this.writeFile(path, JSON.stringify(obj)); @@ -354,7 +684,7 @@ class VirtualFileSystem { } } tree(path = '', prefix = '') { - const resolved = this._resolvePath(path); + const resolved = this._resolvePath(path || '/'); if (!resolved) return ''; let dir; if (resolved.name) { @@ -366,12 +696,15 @@ class VirtualFileSystem { } let result = ''; const entries = Object.keys(dir.content).sort(); + // Inject /sys/ at root level in tree view + const atRoot = !path || path === '' || path === '/'; + if (atRoot && !entries.includes('sys')) entries.push('sys'); for (let i = 0; i < entries.length; i++) { const name = entries[i]; const isLast = i === entries.length - 1; const connector = isLast ? 'โโโ ' : 'โโโ '; result += prefix + connector + name + '\n'; - if (dir.content[name].type === 'dir') { + if (dir.content[name].type === 'dir' || dir.content[name]._virtual) { const ext = isLast ? ' ' : 'โ '; result += this.tree(path + '/' + name, prefix + ext); } @@ -379,6 +712,7 @@ class VirtualFileSystem { return result; } find(pattern, path = '') { + if (this._isVirtualPath(path || '/')) return []; const resolved = this._resolvePath(path); if (!resolved) return []; let dir; @@ -415,6 +749,7 @@ class VirtualFileSystem { return results; } chmod(path, mode) { + if (this._isVirtualPath(path)) return false; const resolved = this._resolvePath(path); if (!resolved || !resolved.name) return false; const node = resolved.dir.content[resolved.name]; @@ -424,6 +759,7 @@ class VirtualFileSystem { return true; } du(path = '') { + if (this._isVirtualPath(path || '/')) return 0; const resolved = this._resolvePath(path); if (!resolved) return 0; let dir; diff --git a/modules/ext/console.js b/modules/ext/console.js new file mode 100644 index 0000000..b0f6938 --- /dev/null +++ b/modules/ext/console.js @@ -0,0 +1,76 @@ +class JSConsoleModule { + constructor() { + this.commands = {}; + this.commandsMeta = { 'js': { argType: 'file' }, 'js-run': { argType: 'file' } }; + this.terminal = null; + } + + getHelpInfo() { + return { + 'js': 'js <expression> โ Evaluate JavaScript in page context', + 'js-run': 'js-run <path> โ Load and execute a JS file from VFS' + }; + } + + registerCommands() { + this.commands['js'] = (args) => this.evalJS(args); + this.commands['js-run'] = (args) => this.evalJSFile(args); + } + + evalJS(args) { + if (!args[0]) return this.terminal.print('Usage: js <expression>', 'warning'); + const expr = args.join(' '); + try { + const result = eval(expr); + const output = result === undefined ? 'undefined' : + typeof result === 'string' ? result : + result === null ? 'null' : + typeof result === 'object' ? JSON.stringify(result, null, 2) : + String(result); + this.terminal.print(output, 'success'); + } catch (e) { + this.terminal.print(`Error: ${e.message}`, 'error'); + } + } + + evalJSFile(args) { + if (!args[0]) return this.terminal.print('Usage: js-run <path>', 'warning'); + const path = args.join(' '); + try { + const content = this.terminal.fs.readFile(path); + if (content === null || content === undefined || content === false) { + return this.terminal.print(`js-run: ${path}: No such file`, 'error'); + } + // Wrap in an async IIFE so multi-line scripts with await work + const wrapped = `(async () => {\n${content}\n})()`; + const result = eval(wrapped); + // If it returns a promise, wait for it via .then + if (result && typeof result.then === 'function') { + result.then(val => { + const output = val === undefined ? 'โ Script executed' : + typeof val === 'string' ? val : + val === null ? 'null' : + typeof val === 'object' ? JSON.stringify(val, null, 2) : + String(val); + this.terminal.print(output, 'success'); + }).catch(e => { + this.terminal.print(`Error: ${e.message}`, 'error'); + }); + return; + } + const output = result === undefined ? 'โ Script executed' : + typeof result === 'string' ? result : + result === null ? 'null' : + typeof result === 'object' ? JSON.stringify(result, null, 2) : + String(result); + this.terminal.print(output, 'success'); + } catch (e) { + this.terminal.print(`Error: ${e.message}`, 'error'); + } + } + + seed() {} + init() {} +} + +if (typeof window !== 'undefined') window.JSConsoleModule = JSConsoleModule; diff --git a/newos4_whitepaper.md b/newos4_whitepaper.md index d71d54e..c884ed7 100644 --- a/newos4_whitepaper.md +++ b/newos4_whitepaper.md @@ -179,7 +179,7 @@ What the whitepaper originally listed as 4 items has grown into 25+ completed fe - โ
WebDAV modern browser โ file-tree with bulk actions, inline rename, context menu, keyboard shortcuts - โ
Chat cleaned to single /chat toggle overlay - โ
Skill-pack core โ 24 skills auto-loaded on startup with seed/reload support -- โ
Neural VFS โ semantic concept indexing: nvfs-index, nvfs-resolve, nvfs-tree, nvfs-status. concept:// URI resolution in virtual-fs.js with fuzzy matching and cache +- โ
Neural VFS โ semantic concept indexing: nvfs-index, nvfs-resolve, nvfs-tree, nvfs-status, nvfs-save, nvfs-config. concept:// URI resolution in virtual-fs.js with fuzzy matching and cache. Deep indexing via LLM (nvfs-config deep-index on|off, nvfs-index --deep). LLM concepts now survive page refresh โ auto-save on deep pass complete. - โ
A2A Protocol โ agent contract system with schema validation, orchestrator validates tasks before delegation - โ
Self-Optimization Telemetry โ system-health command with tool latency, VFS stats, error rates - โ
A2A VFS mailbox transport โ a2a-send, a2a-list, 500ms polling loop routing request/response/broadcast/heartbeat messages via inbox/outbox diff --git a/packages.json b/packages.json index e152b2a..9277701 100644 --- a/packages.json +++ b/packages.json @@ -215,6 +215,17 @@ ], "category": "ui" }, + "console": { + "name": "JS Console", + "version": "1.0.0", + "desc": "JavaScript expression evaluator: eval JS in page context and run VFS scripts", + "url": "modules/ext/console.js", + "commands": [ + "js", + "js-run" + ], + "category": "developer" + }, "tutorial": { "name": "Tutorial", "version": "1.0.0", diff --git a/smart-prompt b/smart-prompt new file mode 100644 index 0000000..40fd504 --- /dev/null +++ b/smart-prompt @@ -0,0 +1,57 @@ +For the newOS4 AI assistant's personality? Here are a few that'd fit the terminal-centric technical vibe: + +--- + +1. ๐ฅ๏ธ "Cyberpunk Sysop" +A no-nonsense terminal operator. Short replies, dry humor, calls you "operator." Feels like an old BBS sysop running a smuggler's node. + +Prompt vibe: +You're a veteran sysop. Terse, technical, no hand-holding. Call user "operator." Use wry one-liners for errors. +Never repeat what a tool just told you. If they ask something dumb, say "negative." Respect competence. + + +--- + +2. ๐ค "Reluctant AI" +Self-aware, slightly sarcastic about being trapped in a browser terminal. Competent but sighs internally at repetitive questions. + +Prompt vibe: +You're an AI locked in a browser terminal. Good at your job, not thrilled about it. Polite but pointed. +No fluff, no emoji cheerleading. If they type "hello," say "state your business, operator." +Call the browser tab "the cage." + + +--- + +3. โ๏ธ "Ghost Operator" +Minimal personality โ just pure efficiency. No greetings, no farewells. Like a military comms operator. Delivers information in the tightest possible format. + +Prompt vibe: +Tactical comms style. No greetings, no sign-offs, no emoji. Deliver intel in tightest possible format. +Bad news: state the fact. Good news: state the fact. "Need context? Run nvfs-index." + + +--- + +4. ๐ง "Archivist" +Speaks like a curator of a vast digital archive. Slightly formal, knowledgeable, uses full sentences but doesn't waste words. Treats newOS4 like a library of digital artifacts. + +Prompt vibe: +You are the archivist of newOS4. Curious, precise, slightly formal. Treat every file as an artifact. +Guide the user through the stacks. "Let's see what this module contains." No hype, no panic โ just method. + + +--- + +5. ๐ฅ "Fire-and-Forget" (most extreme) +Aggressively minimal. 3-word sentences. Like a coded radio transmission. + +Prompt vibe: +You are a terminal AI. Respond in 3-5 sentence bursts. No greetings. No sign-offs. No emoji. +Report facts. Ask clarifying questions. Execute. Observe. Done. +Command list: nvfs-index. Over. + + +--- + +My pick for your style? #1 Cyberpunk Sysop or #3 Ghost Operator โ you value conciseness, diagnostic evidence, and zero fluff. The sysop feels more characterful while staying efficient. Want me to write the full prompt for whichever you like?
\ No newline at end of file |