diff options
| author | Agando <roduccomm@gmail.com> | 2026-05-28 18:01:22 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-05-28 18:01:22 +0200 |
| commit | f8a04e76ea9aa5156e6e80a7534f1aa5a336429b (patch) | |
| tree | 35f08d7228f1da9493e45d2fcd64e7277f008589 /modules/ext | |
| parent | d1af24deb8ad344994c0a06b909b7a6f4bac4c94 (diff) | |
auto: 2026-05-28_18:00 changes
Diffstat (limited to 'modules/ext')
| -rw-r--r-- | modules/ext/alias.js | 2 | ||||
| -rw-r--r-- | modules/ext/busybox.js | 3 | ||||
| -rw-r--r-- | modules/ext/calc.js | 2 | ||||
| -rw-r--r-- | modules/ext/cron.js | 2 | ||||
| -rw-r--r-- | modules/ext/cryptogzip.js | 18 | ||||
| -rw-r--r-- | modules/ext/diff.js | 2 | ||||
| -rw-r--r-- | modules/ext/editor.js | 2 | ||||
| -rw-r--r-- | modules/ext/filemgr.js | 169 | ||||
| -rw-r--r-- | modules/ext/finder.js | 2 | ||||
| -rw-r--r-- | modules/ext/mindmap.js | 20 | ||||
| -rw-r--r-- | modules/ext/shell.js | 3 | ||||
| -rw-r--r-- | modules/ext/skill-pack-core.js | 3 | ||||
| -rw-r--r-- | modules/ext/theme.js | 2 | ||||
| -rw-r--r-- | modules/ext/voice.js | 2 | ||||
| -rw-r--r-- | modules/ext/wpm.js | 4 |
15 files changed, 179 insertions, 57 deletions
diff --git a/modules/ext/alias.js b/modules/ext/alias.js index 4ffab72..80663ac 100644 --- a/modules/ext/alias.js +++ b/modules/ext/alias.js @@ -104,5 +104,5 @@ class AliasModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new AliasModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/ext/alias.js'); + webx11.moduleManager.registerModule(new AliasModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/alias.js'); } diff --git a/modules/ext/busybox.js b/modules/ext/busybox.js index f143087..709324f 100644 --- a/modules/ext/busybox.js +++ b/modules/ext/busybox.js @@ -405,3 +405,6 @@ class BusyBoxModule { this.terminal.print(expanded, 'info'); } } +if (typeof window.webx11 !== 'undefined' && window.webx11) { + webx11.moduleManager.registerModule(new BusyBoxModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/busybox.js'); +} diff --git a/modules/ext/calc.js b/modules/ext/calc.js index e28079e..9b602f6 100644 --- a/modules/ext/calc.js +++ b/modules/ext/calc.js @@ -73,5 +73,5 @@ class CalcModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new CalcModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/calc.js'); + webx11.moduleManager.registerModule(new CalcModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/calc.js'); } diff --git a/modules/ext/cron.js b/modules/ext/cron.js index 66cd18e..5ed5ff6 100644 --- a/modules/ext/cron.js +++ b/modules/ext/cron.js @@ -106,5 +106,5 @@ class CronModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new CronModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/cron.js'); + webx11.moduleManager.registerModule(new CronModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/cron.js'); } diff --git a/modules/ext/cryptogzip.js b/modules/ext/cryptogzip.js index 6f873ff..b67e067 100644 --- a/modules/ext/cryptogzip.js +++ b/modules/ext/cryptogzip.js @@ -1,9 +1,18 @@ class CryptoGzipModule { // CryptoGzipModule — VFS-level gzip/encrypt commands for WebX11 newOS4 - // Commands: gzip <path>, gunzip <path.gz>, encrypt <path>, decrypt <path.enc> - constructor(terminal) { - this.terminal = terminal; + // Commands: gzip <path>, gunzip <path.gz>, encrypt <path> <passphrase>, decrypt <path.enc> <passphrase> + constructor() { this.commands = {}; + this.terminal = null; + } + + getHelpInfo() { + return { + 'gzip': 'gzip <path> — Compress a VFS file to .gz', + 'gunzip': 'gunzip <path.gz> — Decompress a .gz file', + 'encrypt': 'encrypt <path> <passphrase> — AES-256-GCM encrypt a VFS file', + 'decrypt': 'decrypt <path.enc> <passphrase> — Decrypt a .enc file' + }; } _vfsExists(path) { @@ -279,3 +288,6 @@ class CryptoGzipModule { }; } } +if (typeof window.webx11 !== 'undefined' && window.webx11) { + webx11.moduleManager.registerModule(new CryptoGzipModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/cryptogzip.js'); +} diff --git a/modules/ext/diff.js b/modules/ext/diff.js index 8b79b6b..64469ac 100644 --- a/modules/ext/diff.js +++ b/modules/ext/diff.js @@ -283,5 +283,5 @@ class DiffModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new DiffModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/diff.js'); + webx11.moduleManager.registerModule(new DiffModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/diff.js'); } diff --git a/modules/ext/editor.js b/modules/ext/editor.js index 571a535..c597dd5 100644 --- a/modules/ext/editor.js +++ b/modules/ext/editor.js @@ -66,5 +66,5 @@ class EditorModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new EditorModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/editor.js'); + webx11.moduleManager.registerModule(new EditorModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/editor.js'); } diff --git a/modules/ext/filemgr.js b/modules/ext/filemgr.js index 5532cee..4074f06 100644 --- a/modules/ext/filemgr.js +++ b/modules/ext/filemgr.js @@ -7,6 +7,7 @@ class FileManagerModule { this._selectedFile = null; this._searchFilter = ''; this._rawMode = false; + this._inlineHtml = false; } requirements() { @@ -15,8 +16,8 @@ class FileManagerModule { getHelpInfo() { return { - 'files': 'Open the file manager overlay with VFS directory listing and preview', - 'preview': 'Preview a specific file (usage: preview <path>)', + 'files': 'files — Open the file manager overlay with VFS directory listing, preview, encrypt, zip', + 'preview': 'preview <path> — Preview a specific file', }; } @@ -52,15 +53,16 @@ class FileManagerModule { _detectType(filePath) { const ext = filePath.split('.').pop().toLowerCase(); if (!ext || ext === filePath) return 'other'; - const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp']; - const videoExts = ['mp4', 'webm']; - const audioExts = ['mp3', 'wav', 'ogg']; - const codeExts = ['js', 'py', 'html', 'css', 'yaml', 'yml', 'toml']; + const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico']; + const videoExts = ['mp4', 'webm', 'avi', 'mov', 'mkv']; + const audioExts = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a']; + const codeExts = ['js', 'py', 'css', 'yaml', 'yml', 'toml']; if (ext === 'md') return 'md'; if (imageExts.includes(ext)) return 'image'; if (videoExts.includes(ext)) return 'video'; if (audioExts.includes(ext)) return 'audio'; if (codeExts.includes(ext)) return 'code'; + if (ext === 'html') return 'html'; if (ext === 'json') return 'json'; if (ext === 'csv') return 'csv'; if (ext === 'pdf') return 'pdf'; @@ -113,7 +115,10 @@ class FileManagerModule { const fileName = path.split('/').pop() || path; // Handle binary detection for media types - const isLikelyBinary = typeof content === 'string' && content.length > 0 && !content.startsWith('\n') && !content.startsWith('\r') && !content.startsWith(' ') && !content.startsWith('<') && !content.startsWith('{') && !content.startsWith('[') && content.charCodeAt(0) < 32 && content.charCodeAt(0) !== 9 && content.charCodeAt(0) !== 10 && content.charCodeAt(0) !== 13; + if (typeof content !== 'string') { + return '<div style="padding:20px;text-align:center;color:var(--text-muted)">Cannot preview: non-string content</div>'; + } + const isLikelyBinary = content.length > 0 && !content.startsWith('\n') && !content.startsWith('\r') && !content.startsWith(' ') && !content.startsWith('<') && !content.startsWith('{') && !content.startsWith('[') && content.charCodeAt(0) < 32 && content.charCodeAt(0) !== 9 && content.charCodeAt(0) !== 10 && content.charCodeAt(0) !== 13; const isTextContent = typeof content === 'string' && (content.startsWith('{') || content.startsWith('[') || content.startsWith('<') || content.startsWith('#') || /^[\w\s\n\r\t.,;:!?()\-=+*@#$%^&"'\/\\|`~]/.test(content.substring(0, 100))); @@ -121,6 +126,17 @@ class FileManagerModule { return '<div class="markdown-preview" style="padding:12px;font-family:var(--font-primary);line-height:1.5">' + this._renderMarkdown(content) + '</div>'; } + if (type === 'html') { + // Render HTML in an inline sandbox frame + const safeHtml = content + .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') + .replace(/on\w+\s*=\s*"[^"]*"/gi, '') + .replace(/on\w+\s*=\s*'[^']*'/gi, ''); + return '<div style="padding:0;width:100%;height:60vh;border:none;overflow:hidden">' + + '<iframe srcdoc="' + this._escapeHtml(safeHtml.replace(/"/g, '"').replace(/'/g, ''')) + '" ' + + 'style="width:100%;height:100%;border:none;background:#fff" sandbox="allow-same-origin"></iframe></div>'; + } + if (type === 'text') { const truncated = content.substring(0, 2000); const extra = content.length > 2000 ? '<div style="color:var(--text-muted);margin-top:8px">(truncated to 2000 chars)</div>' : ''; @@ -158,11 +174,14 @@ class FileManagerModule { } if (type === 'image') { - if (isLikelyBinary && !isTextContent) { - return '<div style="padding:20px;text-align:center;color:var(--text-muted)">📷 Image — <span style="color:var(--info-color);cursor:pointer;text-decoration:underline" onclick="' + this._escapeHtml("var a=document.createElement('a');a.href='data:image/" + ext + ";base64," + btoa(content) + "';a.download='" + fileName + "';a.click()") + '">download to view</span></div>'; + // VFS stores images as base64 strings — detect and render inline + const isBase64 = /^[A-Za-z0-9+/=]+$/.test(content.substring(0, 100)); + if (isBase64) { + const mimeTypes = {jpg:'image/jpeg',jpeg:'image/jpeg',png:'image/png',gif:'image/gif',webp:'image/webp',bmp:'image/bmp',ico:'image/x-icon'}; + const mime = mimeTypes[ext] || 'image/png'; + return '<div style="padding:12px;text-align:center;max-width:100%"><img src="data:' + mime + ';base64,' + content + '" style="max-width:100%;max-height:70vh;border-radius:4px;border:1px solid var(--border-color)" alt="' + this._escapeHtml(fileName) + '"></div>'; } - const base64 = btoa(unescape(encodeURIComponent(content))); - return '<div style="padding:12px;text-align:center"><img src="data:image/' + ext + ';base64,' + base64 + '" style="max-width:80%;max-height:60vh;border-radius:4px;border:1px solid var(--border-color)" alt="' + this._escapeHtml(fileName) + '"></div>'; + return '<div style="padding:20px;text-align:center;color:var(--text-muted)">📷 Image — cannot render, file may be stored as binary</div>'; } if (type === 'svg') { @@ -187,28 +206,31 @@ class FileManagerModule { } if (type === 'video') { - if (isLikelyBinary && !isTextContent) { - return '<div style="padding:20px;text-align:center;color:var(--text-muted)">📷 Video — <span style="color:var(--info-color);cursor:pointer;text-decoration:underline" onclick="var a=document.createElement(\'a\');a.href=\'data:video/' + ext + ';base64,' + btoa(content) + '\';a.download=\'' + fileName + '\';a.click()">download to view</span></div>'; + const isBase64 = /^[A-Za-z0-9+/=]+$/.test(content.substring(0, 100)); + if (isBase64) { + const mimeTypes = {mp4:'video/mp4',webm:'video/webm',avi:'video/x-msvideo',mov:'video/quicktime',mkv:'video/x-matroska'}; + const mime = mimeTypes[ext] || 'video/mp4'; + return '<div style="padding:12px;text-align:center"><video controls style="max-width:90%;max-height:65vh;border-radius:4px"><source src="data:' + mime + ';base64,' + content + '" type="' + mime + '"></video></div>'; } - const base64 = btoa(unescape(encodeURIComponent(content))); - return '<div style="padding:12px;text-align:center"><video controls style="max-width:80%;max-height:60vh;border-radius:4px"><source src="data:video/' + ext + ';base64,' + base64 + '" type="video/' + ext + '"></video></div>'; + return '<div style="padding:20px;text-align:center;color:var(--text-muted)">🎬 Video — cannot render</div>'; } if (type === 'audio') { - if (isLikelyBinary && !isTextContent) { - return '<div style="padding:20px;text-align:center;color:var(--text-muted)">🎵 Audio — <span style="color:var(--info-color);cursor:pointer;text-decoration:underline" onclick="var a=document.createElement(\'a\');a.href=\'data:audio/' + ext + ';base64,' + btoa(content) + '\';a.download=\'' + fileName + '\';a.click()">download to play</span></div>'; + const isBase64 = /^[A-Za-z0-9+/=]+$/.test(content.substring(0, 100)); + if (isBase64) { + const mimeTypes = {mp3:'audio/mpeg',wav:'audio/wav',ogg:'audio/ogg',flac:'audio/flac',aac:'audio/aac',m4a:'audio/mp4'}; + const mime = mimeTypes[ext] || 'audio/mpeg'; + return '<div style="padding:12px;text-align:center"><audio controls style="max-width:90%"><source src="data:' + mime + ';base64,' + content + '" type="' + mime + '"></audio></div>'; } - const base64 = btoa(unescape(encodeURIComponent(content))); - return '<div style="padding:12px;text-align:center"><audio controls style="max-width:80%"><source src="data:audio/' + ext + ';base64,' + base64 + '" type="audio/' + ext + '"></audio></div>'; + return '<div style="padding:20px;text-align:center;color:var(--text-muted)">🎵 Audio — cannot render</div>'; } if (type === 'pdf') { - try { - const base64 = btoa(unescape(encodeURIComponent(content))); - return '<div style="padding:12px;text-align:center;height:70vh"><embed src="data:application/pdf;base64,' + base64 + '" type="application/pdf" style="width:100%;height:100%;border:1px solid var(--border-color);border-radius:4px"></div>'; - } catch (e) { - return '<div style="padding:20px;text-align:center;color:var(--text-muted)">📄 PDF — <span style="color:var(--info-color);cursor:pointer;text-decoration:underline" onclick="var a=document.createElement(\'a\');a.href=\'data:application/pdf;base64,' + btoa(content) + '\';a.download=\'' + fileName + '\';a.click()">download to view</span></div>'; + const isBase64 = /^[A-Za-z0-9+/=]+$/.test(content.substring(0, 100)); + if (isBase64) { + return '<div style="padding:12px;text-align:center;height:70vh"><embed src="data:application/pdf;base64,' + content + '" type="application/pdf" style="width:100%;height:100%;border:1px solid var(--border-color);border-radius:4px"></div>'; } + return '<div style="padding:20px;text-align:center;color:var(--text-muted)">📄 PDF — cannot render</div>'; } if (type === 'csv') { @@ -285,7 +307,7 @@ class FileManagerModule { const overlay = document.createElement('div'); overlay.id = 'filemgr-overlay'; - overlay.style.cssText = 'position:fixed;inset:0;z-index:1800;display:flex;flex-direction:column;background:var(--bg-color);color:var(--text-color);font-family:var(--font-primary);font-size:14px;'; + overlay.style.cssText = 'position:fixed;inset:0;z-index:1800;display:flex;flex-direction:column;background:var(--bg-color);color:var(--text-color);font-family:var(--font-primary);font-size:14px;height:100vh;'; // Inject responsive styles for the overlay const styleId = 'filemgr-styles'; @@ -318,10 +340,11 @@ class FileManagerModule { border-right: none !important; border-bottom: 1px solid var(--border-color); } - #filemgr-overlay #filemgr-preview { - width: 100% !important; - min-height: 40vh; - } + #filemgr-overlay #filemgr-preview { + width: 100% !important; + flex: 1 !important; + min-height: 0; + } #filemgr-action-bar { flex-wrap: wrap; gap: 6px; @@ -384,12 +407,12 @@ class FileManagerModule { const mainArea = document.createElement('div'); mainArea.id = 'filemgr-main-container'; mainArea.className = 'filemgr-main'; - mainArea.style.cssText = 'overflow:hidden;'; + mainArea.style.cssText = 'flex:1;overflow:hidden;display:flex;min-height:0;'; // Sidebar const sidebar = document.createElement('div'); sidebar.id = 'filemgr-sidebar'; - sidebar.style.cssText = 'width:30%;min-width:200px;overflow-y:auto;background:var(--bg-secondary);border-right:1px solid var(--border-color);'; + sidebar.style.cssText = 'width:25%;min-width:150px;overflow-y:auto;background:var(--bg-secondary);border-right:1px solid var(--border-color);'; mainArea.appendChild(sidebar); @@ -413,6 +436,18 @@ class FileManagerModule { statusSpan.textContent = 'No file selected'; actionBar.appendChild(statusSpan); + const encryptBtn = document.createElement('button'); + encryptBtn.textContent = '🔐 Encrypt'; + encryptBtn.style.cssText = 'padding:6px 14px;background:var(--bg-tertiary);border:1px solid var(--warning-color);color:var(--warning-color);border-radius:4px;cursor:pointer;font-family:inherit;font-size:0.9em;min-height:44px;touch-action:manipulation;'; + encryptBtn.onclick = () => this._actionEncrypt(); + actionBar.appendChild(encryptBtn); + + const compressBtn = document.createElement('button'); + compressBtn.textContent = '📦 Zip'; + compressBtn.style.cssText = 'padding:6px 14px;background:var(--bg-tertiary);border:1px solid var(--info-color);color:var(--info-color);border-radius:4px;cursor:pointer;font-family:inherit;font-size:0.9em;min-height:44px;touch-action:manipulation;'; + compressBtn.onclick = () => this._actionCompress(); + actionBar.appendChild(compressBtn); + const deleteBtn = document.createElement('button'); deleteBtn.textContent = '🗑 Delete'; deleteBtn.style.cssText = 'padding:6px 14px;background:var(--bg-tertiary);border:1px solid var(--error-color);color:var(--error-color);border-radius:4px;cursor:pointer;font-family:inherit;font-size:0.9em;min-height:44px;touch-action:manipulation;'; @@ -431,6 +466,12 @@ class FileManagerModule { editBtn.onclick = () => this._actionEdit(); actionBar.appendChild(editBtn); + const newFileBtn = document.createElement('button'); + newFileBtn.textContent = '📄 New'; + newFileBtn.style.cssText = 'padding:6px 14px;background:var(--bg-tertiary);border:1px solid var(--success-color);color:var(--success-color);border-radius:4px;cursor:pointer;font-family:inherit;font-size:0.9em;min-height:44px;touch-action:manipulation;'; + newFileBtn.onclick = () => this._actionNewFile(); + actionBar.appendChild(newFileBtn); + const previewToggleBtn = document.createElement('button'); previewToggleBtn.id = 'filemgr-toggle-raw'; previewToggleBtn.textContent = '📄 Raw'; @@ -727,9 +768,14 @@ class FileManagerModule { this._updateStatus('No file selected to edit'); return; } - if (typeof webx11 !== 'undefined' && webx11 && webx11.executeCommand) { - webx11.executeCommand('edit ' + this._selectedFile); - this._updateStatus('✏ Opened in editor: ' + this._selectedFile); + const path = this._selectedFile; + // Close file manager first so code editor modal (z-index:1000) is visible above + this._closeOverlay(); + if (typeof webx11 !== 'undefined' && webx11 && webx11.dispatchCommand) { + setTimeout(() => { + webx11.dispatchCommand('edit', [path]); + }, 100); + this._updateStatus('✏ Opened in editor: ' + path); } else { this._updateStatus('❌ Editor not available'); } @@ -748,8 +794,61 @@ class FileManagerModule { this._renderPreview(this._selectedFile, content); } } + + _actionEncrypt() { + if (!this._selectedFile) { + this._updateStatus('No file selected'); + return; + } + if (this._selectedFile.endsWith('.enc')) { + this._updateStatus('⚠ Already encrypted (.enc)'); + return; + } + const passphrase = prompt('Enter passphrase for AES-256-GCM encryption:'); + if (!passphrase || passphrase.length < 4) { + this._updateStatus('❌ Passphrase too short (min 4 chars)'); + return; + } + // Delegate to cryptogzip module's encrypt command + if (typeof webx11 !== 'undefined' && webx11.executeCommand) { + webx11.executeCommand('encrypt ' + this._selectedFile + ' ' + passphrase); + this._updateStatus('🔐 Encrypted: ' + this._selectedFile + '.enc'); + this._refreshFileList(); + } + } + + _actionCompress() { + if (!this._selectedFile) { + this._updateStatus('No file selected'); + return; + } + if (this._selectedFile.endsWith('.gz')) { + this._updateStatus('⚠ Already compressed (.gz)'); + return; + } + if (typeof webx11 !== 'undefined' && webx11.executeCommand) { + webx11.executeCommand('gzip ' + this._selectedFile); + this._updateStatus('📦 Compressed: ' + this._selectedFile + '.gz'); + this._refreshFileList(); + } + } + + _actionNewFile() { + const name = prompt('New file name (e.g. myfile.txt):'); + if (!name) return; + const pathStr = '/' + this.currentPath.join('/'); + const cleanPath = pathStr === '/' ? '/' + name : pathStr + '/' + name; + const content = prompt('Enter file content (optional):') || ''; + const ok = this.terminal.fs.writeFile(cleanPath, content); + if (ok) { + this._updateStatus('✅ Created: ' + cleanPath + ' (' + content.length + ' chars)'); + this._refreshFileList(); + } else { + this._updateStatus('❌ Failed to create file'); + } + } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new FileManagerModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/ext/filemgr.js'); + webx11.moduleManager.registerModule(new FileManagerModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/filemgr.js'); } diff --git a/modules/ext/finder.js b/modules/ext/finder.js index 1ca8cf7..8230668 100644 --- a/modules/ext/finder.js +++ b/modules/ext/finder.js @@ -43,5 +43,5 @@ class FinderModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new FinderModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/finder.js'); + webx11.moduleManager.registerModule(new FinderModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/finder.js'); } diff --git a/modules/ext/mindmap.js b/modules/ext/mindmap.js index 30d6889..9f62cba 100644 --- a/modules/ext/mindmap.js +++ b/modules/ext/mindmap.js @@ -166,7 +166,9 @@ class MindmapModule { if (!args[0]) return this.terminal.print('Usage: mindmap save <name>', 'warning'); if (!this.root) return this.terminal.print('No mindmap to save.', 'warning'); try { - localStorage.setItem('webx11_mindmap_' + args[0], JSON.stringify(this.root)); + const fs = this.terminal.fs; + fs.mkdirRecursive('/mindmaps'); + fs.writeFile('/mindmaps/' + args[0] + '.json', JSON.stringify(this.root, null, 2)); this.terminal.print('Mindmap saved as: ' + args[0], 'success'); } catch (e) { this.terminal.print('Failed to save: ' + e.message, 'error'); @@ -175,7 +177,8 @@ class MindmapModule { _load(args) { if (!args[0]) return this.terminal.print('Usage: mindmap load <name>', 'warning'); try { - const data = localStorage.getItem('webx11_mindmap_' + args[0]); + const fs = this.terminal.fs; + const data = fs.readFile('/mindmaps/' + args[0] + '.json'); if (!data) return this.terminal.print('No saved mindmap: ' + args[0], 'error'); this.root = JSON.parse(data); this.terminal.print('Loaded mindmap: ' + args[0] + ' (' + this._countNodes(this.root) + ' nodes)', 'success'); @@ -184,18 +187,17 @@ class MindmapModule { } } _list() { - const keys = []; - for (let i = 0; i < localStorage.length; i++) { - const k = localStorage.key(i); - if (k && k.startsWith('webx11_mindmap_')) keys.push(k.replace('webx11_mindmap_', '')); - } + const fs = this.terminal.fs; + const files = fs.readDir('/mindmaps') || []; + const keys = files.filter(f => f.name.endsWith('.json')).map(f => f.name.replace('.json', '')); if (!keys.length) return this.terminal.print('No saved mindmaps.', 'info'); this.terminal.print('=== Saved Mindmaps ===', 'info'); keys.forEach(k => this.terminal.print(' ' + k)); } _delete(args) { if (!args[0]) return this.terminal.print('Usage: mindmap delete <name>', 'warning'); - localStorage.removeItem('webx11_mindmap_' + args[0]); + const fs = this.terminal.fs; + fs.deleteFile('/mindmaps/' + args[0] + '.json'); this.terminal.print('Deleted mindmap: ' + args[0], 'success'); } _rename(args) { @@ -232,5 +234,5 @@ class MindmapModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new MindmapModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/mindmap.js'); + webx11.moduleManager.registerModule(new MindmapModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/mindmap.js'); } diff --git a/modules/ext/shell.js b/modules/ext/shell.js index d5e6a43..6beb0eb 100644 --- a/modules/ext/shell.js +++ b/modules/ext/shell.js @@ -515,3 +515,6 @@ class ShellModule { this.terminal.print(`Script ${path} completed (${lineNum} lines)`, 'success'); } } +if (typeof window.webx11 !== 'undefined' && window.webx11) { + webx11.moduleManager.registerModule(new ShellModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/shell.js'); +} diff --git a/modules/ext/skill-pack-core.js b/modules/ext/skill-pack-core.js index 51a2e55..cc8ae88 100644 --- a/modules/ext/skill-pack-core.js +++ b/modules/ext/skill-pack-core.js @@ -283,3 +283,6 @@ class SkillPackCoreModule { this._seeded = true; } } +if (typeof window.webx11 !== 'undefined' && window.webx11) { + webx11.moduleManager.registerModule(new SkillPackCoreModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/skill-pack-core.js'); +} diff --git a/modules/ext/theme.js b/modules/ext/theme.js index 9a1dab5..1d99b2c 100644 --- a/modules/ext/theme.js +++ b/modules/ext/theme.js @@ -168,5 +168,5 @@ class ThemeModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new ThemeModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/theme.js'); + webx11.moduleManager.registerModule(new ThemeModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/theme.js'); } diff --git a/modules/ext/voice.js b/modules/ext/voice.js index 0fd96cd..06c5480 100644 --- a/modules/ext/voice.js +++ b/modules/ext/voice.js @@ -98,5 +98,5 @@ class VoiceModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new VoiceModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/voice.js'); + webx11.moduleManager.registerModule(new VoiceModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/voice.js'); } diff --git a/modules/ext/wpm.js b/modules/ext/wpm.js index 9c8d820..4dc9c29 100644 --- a/modules/ext/wpm.js +++ b/modules/ext/wpm.js @@ -2,7 +2,7 @@ class WpmModule { constructor() { this.commands = {}; this.terminal = null; - this.indexUrl = 'https://webx11.duckdns.org/spaces/chatstudio/newos4/packages.json'; + this.indexUrl = 'https://webx11.duckdns.org/spaces/newos4/packages.json'; this.index = null; this.installed = this.loadInstalled(); } @@ -145,5 +145,5 @@ class WpmModule { } } if (typeof window.webx11 !== 'undefined' && window.webx11) { - webx11.moduleManager.registerModule(new WpmModule(), 'https://webx11.duckdns.org/spaces/chatstudio/newos4/modules/wpm.js'); + webx11.moduleManager.registerModule(new WpmModule(), 'https://webx11.duckdns.org/spaces/newos4/modules/ext/wpm.js'); } |