aboutsummaryrefslogtreecommitdiff
path: root/modules/core/terminal.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-09-29 15:56:27 +0200
committerAgando <roduccomm@gmail.com>2026-09-29 15:56:27 +0200
commitdde918a235ff8eac41f6d205e954dc4a4daa5b01 (patch)
treea58da7664e938d6d4d0fca0974932139e8b8584c /modules/core/terminal.js
parent0e454aecf55d862b7618ebd1c98ca9fd71a15817 (diff)
newOS4 v4.6.15: reentrant print-capture stack, AI tail -f block, read-only sed in safeRead, security test harness (21 checks)
Diffstat (limited to 'modules/core/terminal.js')
-rw-r--r--modules/core/terminal.js25
1 files changed, 22 insertions, 3 deletions
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index 3b28b52..123c224 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -300,6 +300,9 @@
this._pipeInput = null;
this._pipeBufferSize = 5000;
this._activeFollow = null;
+ // Print-capture stack: [{output: ''}] — see print() head. LIFO order:
+ // nested/parallel captures each get their own buffer.
+ this._printCaptureStack = [];
this._historyBuffer = [];
this._historyMaxLines = 50;
this._historySavePending = false;
@@ -357,6 +360,15 @@
_invalidateCommandCache() {
if (this.security) this.security.invalidateCommandCache();
}
+ _pushPrintCapture(onChunk) {
+ // onChunk(buffer) called at pop with the full captured text
+ if (!this._printCaptureStack) this._printCaptureStack = [];
+ this._printCaptureStack.push({ output: '', onChunk });
+ }
+ _popPrintCapture() {
+ const cap = this._printCaptureStack && this._printCaptureStack.pop();
+ if (cap && cap.onChunk) cap.onChunk(cap.output);
+ }
stopFollow(msg) {
if (!this._activeFollow) return false;
clearInterval(this._activeFollow.interval);
@@ -542,6 +554,14 @@
label.textContent = prefix + (path === '/' ? '$' : path + ' $');
}
print(text, type = '') {
+ // Print-capture stack: while active, output goes to the innermost capture
+ // buffer instead of the DOM. Reentrant — parallel/nested captures each
+ // collect their own output (race-safe, replaces monkey-patched print).
+ if (this._printCaptureStack && this._printCaptureStack.length > 0) {
+ const cap = this._printCaptureStack[this._printCaptureStack.length - 1];
+ cap.output += text + '\n';
+ return;
+ }
if (['error','warning','success','info','text-muted'].includes(type) && !this._showSystemMessages && !type.startsWith('command')) {
// Still log to history buffer so it can be shown again when toggled on,
// but don't create DOM nodes while system messages are hidden.
@@ -1532,13 +1552,12 @@
this._pipeInput = null;
}
async capturePipeOutput(cmd, args) {
- const originalPrint = this.print.bind(this);
let output = '';
- this.print = (text, type) => { output += text + '\n'; };
+ this._pushPrintCapture(buf => { output += buf; });
try {
await this.dispatchCommand(cmd, args);
} finally {
- this.print = originalPrint;
+ this._popPrintCapture();
}
const trimmed = output.trim();
if (trimmed.length > this._pipeBufferSize) {