diff options
| author | Agando <roduccomm@gmail.com> | 2026-05-26 06:00:26 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-05-26 06:00:26 +0200 |
| commit | f4d934d341056142da1212c845eeeb170fd452c2 (patch) | |
| tree | 55dd11c70d1342857537f4b0aeee6ea63d21545e /modules/core | |
| parent | 4baa484b84c5184286cac2743575251454a5ee2b (diff) | |
auto: 2026-05-26_06:00 changes
Diffstat (limited to 'modules/core')
| -rw-r--r-- | modules/core/module-aiassist.js | 23 | ||||
| -rw-r--r-- | modules/core/terminal.js | 25 | ||||
| -rw-r--r-- | modules/core/virtual-fs.js | 21 |
3 files changed, 57 insertions, 12 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index 0ef6a2f..f9e1e98 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -366,6 +366,13 @@ RULES: }, { type: 'function', function: { + name: 'session_terminal', + description: "Read the last ~50 lines of terminal output from the auto-saved session. Use this when the user references something they did in the terminal that you don't remember. Shows commands, outputs, and timestamps.", + parameters: { type: 'object', properties: {}, required: [] } + } + }, { + type: 'function', + function: { name: 'session_stats', description: 'Aggregate statistics across all sessions: total tasks, most-used tools, common topics.', parameters: { type: 'object', properties: {}, required: [] } @@ -1015,6 +1022,22 @@ RULES: const sessions = dates.map(d => ({ date: d, ...rindex[d] })); return JSON.stringify({ sessions, count: sessions.length }); } + case 'session_terminal': { + const tfs = this.terminal.fs; + try { + const raw = tfs.readFile('_sessions/_auto.json'); + if (!raw) return JSON.stringify({ error: 'No auto-saved session found' }); + const data = JSON.parse(raw); + const lines = (data.terminalLines || []).slice(-50); + const text = lines.map(l => { + const ts = l.t ? '[' + l.t + '] ' : ''; + return ts + l.l; + }).join('\n'); + return JSON.stringify({ lines: lines.length, output: text, savedAt: data.savedAt || '' }); + } catch (e) { + return JSON.stringify({ error: 'Could not read terminal history: ' + e.message }); + } + } case 'session_stats': { const sfs = this.terminal.fs; const sindex = sfs.fsReadJSON('/memory/index.json') || {}; diff --git a/modules/core/terminal.js b/modules/core/terminal.js index 0a9538f..ee1afa4 100644 --- a/modules/core/terminal.js +++ b/modules/core/terminal.js @@ -20,6 +20,7 @@ this._pipeBufferSize = 5000; this._historyBuffer = []; this._historyMaxLines = 50; + this._historySavePending = false; this.MAX_OUTPUT_LINES = 200; this._aiBusy = false; this._dirty = false; @@ -325,12 +326,17 @@ } } _saveHistory() { - try { - const slice = this._historyBuffer.slice(-30); - localStorage.setItem('webx11_terminal_output', JSON.stringify(slice)); - } catch (e) { - // Silently ignore storage errors (e.g. quota exceeded) - } + if (this._historySavePending) return; + this._historySavePending = true; + setTimeout(() => { + this._historySavePending = false; + try { + const slice = this._historyBuffer.slice(-30); + localStorage.setItem('webx11_terminal_output', JSON.stringify(slice)); + } catch (e) { + // Silently ignore storage errors (e.g. quota exceeded) + } + }, 3000); } _saveCommandHistory() { try { @@ -369,10 +375,15 @@ _autoSaveSession() { try { this.fs.mkdirRecursive('_sessions'); + // Clone fsRoot and strip _sessions to prevent recursive nesting + var rootClone = JSON.parse(JSON.stringify(this.fs.root)); + if (rootClone && rootClone.content && rootClone.content['_sessions']) { + delete rootClone.content['_sessions']; + } const snapshot = { type: 'session', savedAt: new Date().toISOString(), - fsRoot: this.fs.root, + fsRoot: rootClone, currentPath: this.fs.currentPath, version: 1, terminalLines: this._historyBuffer.slice(-50) diff --git a/modules/core/virtual-fs.js b/modules/core/virtual-fs.js index a505699..68d02bf 100644 --- a/modules/core/virtual-fs.js +++ b/modules/core/virtual-fs.js @@ -8,6 +8,12 @@ class VirtualFileSystem { try { const saved = localStorage.getItem('webx11_filesystem'); if (saved) { + // Safety: refuse to load if data is excessively large (>512KB raw) + if (saved.length > 524288) { + console.warn('FS data too large (' + (saved.length/1024).toFixed(0) + 'KB), skipping load'); + localStorage.removeItem('webx11_filesystem'); + return; + } const data = JSON.parse(saved); this.root = data.root || this.root; this.currentPath = data.currentPath || []; @@ -15,11 +21,16 @@ class VirtualFileSystem { } catch (e) { console.error('FS load error:', e); } } saveToStorage() { - try { - localStorage.setItem('webx11_filesystem', JSON.stringify({ - root: this.root, currentPath: this.currentPath - })); - } catch (e) { console.error('FS save error:', e); } + if (this._storageSavePending) return; + this._storageSavePending = true; + setTimeout(() => { + this._storageSavePending = false; + try { + localStorage.setItem('webx11_filesystem', JSON.stringify({ + root: this.root, currentPath: this.currentPath + })); + } catch (e) { console.error('FS save error:', e); } + }, 2000); } getCurrentDir() { let dir = this.root; |