safetext

package
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

Documentation

Overview

Package safetext converts raw process output bytes into model-safe text (spec "docs/specs/long-running-command-supervision.md", "Output capture and storage": "Model-visible text passes through safe-text normalization: invalid UTF-8 is replaced deterministically; disallowed terminal control sequences are escaped or removed; binary detection is reported; normalization is reported").

This package is pure text processing: it has no knowledge of processes, owners, handles, cursors, or storage, and it must stay that way -- the process package (process/render.go) is the only place that wires this package's output to a process's identity and cursor-addressed reads. safetext is stdlib-only.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LooksBinary

func LooksBinary(data []byte) bool

LooksBinary reports whether data looks like binary data rather than text, so a caller (process/render.go) can route it through base64 instead of inline safe text. This is a heuristic, not a proof: it combines a NUL-byte density check with a Shannon-entropy check over the byte-value distribution (task text: "NUL-byte density and/or Shannon-entropy-style byte-distribution check").

func Truncate

func Truncate(data []byte, limit int) []byte

Truncate trims data to at most limit bytes without splitting a multi-byte UTF-8 sequence in half. data is assumed to already be valid UTF-8 (as Normalize's own output always is), so any RuneError observed while backing off from the cut point can only mean the cut fell inside a multi-byte sequence, never a genuinely invalid byte -- backing off by at most utf8.UTFMax-1 bytes always reaches a valid boundary. A non-positive limit returns data unchanged (no cap requested); limit == 0 returns an empty slice.

Types

type Normalizer

type Normalizer struct {
	// contains filtered or unexported fields
}

Normalizer incrementally converts a raw byte stream, arriving in arbitrary chunks, into model-safe text. It:

  • replaces invalid UTF-8 byte sequences deterministically with the standard U+FFFD replacement character;
  • strips C0 control bytes (0x00-0x1F) and C1 control codepoints (U+0080-U+009F, however encoded) except approved whitespace (space, tab, newline, and carriage return -- see the isApprovedWhitespace doc comment for why \r is included);
  • recognizes and removes ANSI/terminal CSI (`ESC [ ... final-byte`), OSC (`ESC ] ... BEL` or `ESC ] ... ESC \`), and DCS (`ESC P ... ESC \`) sequences as complete units, even when a sequence is split across two separate Normalize calls.

The zero Normalizer is ready to use. A Normalizer carries state between calls (in-progress escape sequence, a truncated trailing UTF-8 byte sequence) and assumes its Normalize calls are fed strictly in stream order with no gaps or rewinds; it is NOT safe for concurrent use, and re-feeding an overlapping or out-of-order chunk produces undefined (though never unsafe -- no raw control byte can leak) results. Each distinct byte stream (e.g. one process's combined output) needs its own Normalizer.

func (*Normalizer) Normalize

func (n *Normalizer) Normalize(chunk []byte) []byte

Normalize consumes chunk -- the next slice of a byte stream, in stream order -- and returns the model-safe text produced from it. Bytes that belong to an in-progress escape sequence or a truncated UTF-8 rune carried over from a previous call (or held back for a future one) are never included in the returned slice's bytes as raw/partial data; they are either completed and dropped (escape sequences are removed entirely) or reconstructed and decoded (a completed multi-byte rune) on a later call.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL