From f4d934d341056142da1212c845eeeb170fd452c2 Mon Sep 17 00:00:00 2001 From: Agando Date: Tue, 26 May 2026 06:00:26 +0200 Subject: auto: 2026-05-26_06:00 changes --- modules/core/module-aiassist.js | 23 +++++++++++++++++++++++ modules/core/terminal.js | 25 ++++++++++++++++++------- modules/core/virtual-fs.js | 21 ++++++++++++++++----- 3 files changed, 57 insertions(+), 12 deletions(-) (limited to 'modules/core') 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 @@ -363,6 +363,13 @@ RULES: description: 'Show summaries from the most recent sessions.', parameters: { type: 'object', properties: { count: { type: 'number', description: 'Number of recent sessions to show (default 3)' } }, required: [] } } + }, { + 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: { @@ -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; -- cgit v1.2.3