aboutsummaryrefslogtreecommitdiff
path: root/modules/core
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-05-26 06:00:26 +0200
committerAgando <roduccomm@gmail.com>2026-05-26 06:00:26 +0200
commitf4d934d341056142da1212c845eeeb170fd452c2 (patch)
tree55dd11c70d1342857537f4b0aeee6ea63d21545e /modules/core
parent4baa484b84c5184286cac2743575251454a5ee2b (diff)
auto: 2026-05-26_06:00 changes
Diffstat (limited to 'modules/core')
-rw-r--r--modules/core/module-aiassist.js23
-rw-r--r--modules/core/terminal.js25
-rw-r--r--modules/core/virtual-fs.js21
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;