aboutsummaryrefslogtreecommitdiff
path: root/modules/core/terminal.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-10-23 18:15:05 +0200
committerAgando <roduccomm@gmail.com>2026-10-23 18:15:05 +0200
commit5a7230121afc75ad96f1ed32ac90791a98fabce2 (patch)
tree4a4420f7e65425b3bf39a9696494e836ba1ab6a2 /modules/core/terminal.js
parent2eec7a5c7ab9b724a718ece8b1ffc434677068ac (diff)
fix(newos4): one error counter for errors/dashboard/world-model (v4.6.61)
Packet 2 (three surfaces, three answers). Measured first: `errors` scanned /logs/current.log for [ERROR] lines, but that file only ever receives explicit terminal.log('ERROR', ...) calls -- exactly one call site in the whole app -- so it read 0. The dashboard added DebugSupervisor._errorDB plus failed tool calls (18), and the world model read the debug DB alone (11). - terminal.countErrors() / countLogErrors(): the single counter, exposed on the one object all three surfaces already hold - `errors` prints the canonical total with its breakdown, the entry list (hash, count, severity, message), and reports the log scan separately as a mirror - dashboard health.errors and health.errorBreakdown derive from it - world model telemetry.recentErrors derives from it, plus errorsBySource - terminal.log('ERROR', ...) now also records into DebugSupervisor, so the log is a human-readable mirror of one store instead of a second store almost nobody wrote Verified live on v4.6.61: with a seeded debug entry + failed tool call, all three report 2; a single log('ERROR') call moves debug 1->2 and the total by exactly 1 (the mirror line is counted once, in the log, and reported separately).
Diffstat (limited to 'modules/core/terminal.js')
-rw-r--r--modules/core/terminal.js32
1 files changed, 32 insertions, 0 deletions
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index 10608d1..76406b5 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -2954,6 +2954,16 @@
}
}
log(level, source, message) {
+ // v4.6.60: an ERROR also goes to the DebugSupervisor DB, so the log is a
+ // human-readable MIRROR of one store instead of a second store that only one
+ // code path ever wrote to (packet §2: 0 / 18 / 11 in the same second).
+ if (String(level).toUpperCase() === 'ERROR') {
+ try {
+ const ds = this.moduleManager && this.moduleManager.modules
+ ? this.moduleManager.modules['DebugSupervisorModule'] : null;
+ if (ds && typeof ds._recordError === 'function') ds._recordError(String(message), String(source || 'terminal'));
+ } catch (e) { /* never let logging throw */ }
+ }
const d = new Date();
const ts = d.toISOString().split('T')[1].split('.')[0];
const entry = `[${ts}][${level}][${source}] ${message}`;
@@ -2972,6 +2982,28 @@
}
} catch (e) {}
}
+ // v4.6.59: ONE error counter. Three surfaces used to disagree because each
+ // tallied a different sink: `errors` scanned /logs/current.log (which only ever
+ // receives explicit terminal.log('ERROR') calls — one call site in the whole app),
+ // the dashboard added debug-DB + failed tool calls, and the world model read the
+ // debug DB alone. Measured: 0 / 18 / 11 in the same second (packet §2).
+ countLogErrors() {
+ try {
+ const c = this.fs.readFile('/logs/current.log') || '';
+ return c.split('\n').filter(l => l.includes('[ERROR]')).length;
+ } catch (e) { return 0; }
+ }
+ countErrors() {
+ const mm = this.moduleManager;
+ const ds = mm && mm.modules ? mm.modules['DebugSupervisorModule'] : null;
+ const sm = mm && mm.modules ? mm.modules['ServerMonitorModule'] : null;
+ const debug = (ds && ds._errorDB && ds._errorDB.errors)
+ ? Object.keys(ds._errorDB.errors).length : 0;
+ const latency = (sm && Array.isArray(sm._latencyLog))
+ ? sm._latencyLog.filter(e => e && e.error).length : 0;
+ const log = this.countLogErrors();
+ return { debug: debug, latency: latency, log: log, total: debug + latency };
+ }
setAiBusy(busy) {
this._aiBusy = !!busy;
if (this._aiBusyInterval) {