openclaw / src /gateway /terminal /buffer-text.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
5cb63c1 verified
Raw History Blame Contribute Delete
1.88 kB
// Renders a session's raw output ring as plain text for the agent terminal tool,
// which needs readable output rather than escape sequences.
import { stripAnsiSequences } from "../../../packages/terminal-core/src/ansi.js";
// Built at runtime so the source stays free of literal control characters and
// the no-control-regex lint rule cannot statically detect them (same approach
// as terminal-core's sanitizeForLog). Tab survives; \r/\n are handled above.
const C0_EXCEPT_TAB_CR_LF = `${String.fromCharCode(0x00)}-${String.fromCharCode(0x08)}${String.fromCharCode(0x0b)}${String.fromCharCode(0x0c)}${String.fromCharCode(0x0e)}-${String.fromCharCode(0x1f)}${String.fromCharCode(0x7f)}`;
// C1 control characters (0x80-0x9f) include the CSI introducer (0x9b),
// which is an alternative ANSI escape prefix equivalent to ESC [.
const C1 = `${String.fromCharCode(0x80)}-${String.fromCharCode(0x9f)}`;
const CONTROL_BYTES_REGEX = new RegExp(`[${C0_EXCEPT_TAB_CR_LF}${C1}]`, "g");
/**
* Approximates what a terminal would show without running a VT emulator:
* strips ANSI sequences, collapses carriage-return overwrites (progress bars
* emit "10%\r20%\r30%" — keep the last write per line), and drops remaining
* C0/C1 control bytes. Cursor-movement layouts (vim, htop) will not reconstruct
* faithfully; a true screen snapshot is a tracked follow-up.
*/
export function renderTerminalBufferText(raw: string): string {
const stripped = stripAnsiSequences(raw);
return stripped
.split("\n")
.map((line) => {
// A final CR has not overwritten anything yet. Exclude only that CR;
// an earlier CR still starts the last write, even when it is empty.
const end = line.endsWith("\r") ? line.length - 1 : line.length;
return line.slice(line.lastIndexOf("\r", end - 1) + 1, end).replace(CONTROL_BYTES_REGEX, "");
})
.join("\n");
}