mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 11:56:12 +00:00
Pre-count ordered normalization stages before materializing output. Charge original and normalized terminal bytes independently, omit whole over-budget chunks and preserve exact raw counts plus explicit unknown final sizes. Bound rendered normalization, retain legacy capture compatibility, and remove temporary per-match output arrays. Validation: UTF-8 surrogate boundaries, shrinking/no-op/literal rules, capture validation and public MCP expansion/equal-size controls with verified cleanup. CPU, process-family memory and token changes are unmeasured; no performance speedup claimed. Nonterminal derived payload bounds remain separate work. Fixes #3168
64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import { expect, it } from "vitest";
|
|
import type { IPty } from "@lydell/node-pty";
|
|
|
|
import { parseProcessScenario } from "../../domain/process/processScenario.js";
|
|
import type { TerminalFrame } from "../../domain/process/processCapture.js";
|
|
import { captureTerminalFrames } from "./ProcessCaptureLifecycle.js";
|
|
import { createBoundedProcessTextNormalizer } from "./ProcessNormalization.js";
|
|
|
|
it("omits an expanding chunk whole and retains a later smaller normalized chunk", () => {
|
|
let onData: ((data: string) => void) | undefined;
|
|
const terminal = {
|
|
onData: (listener: (data: string) => void) => {
|
|
onData = listener;
|
|
return { dispose: () => undefined };
|
|
},
|
|
} as unknown as IPty;
|
|
const scenario = parseProcessScenario({
|
|
executable: "unused",
|
|
limits: { output_bytes: 1_000 },
|
|
normalization: {
|
|
paths: false,
|
|
pids: false,
|
|
ports: false,
|
|
patterns: [{ pattern: "a", replacement: "x".repeat(500) }],
|
|
},
|
|
});
|
|
const frames: TerminalFrame[] = [];
|
|
const renderedChunks: string[] = [];
|
|
const journal: Array<[string, number]> = [];
|
|
const captureRetention = captureTerminalFrames({
|
|
terminal,
|
|
scenario,
|
|
frames,
|
|
started: 0,
|
|
onOutput: () => undefined,
|
|
renderer: { write: (data: string) => renderedChunks.push(data) } as never,
|
|
normalizeText: createBoundedProcessTextNormalizer(scenario, "/tmp", -1),
|
|
recordEvent: (collection, index) => journal.push([collection, index]),
|
|
});
|
|
|
|
onData?.("aaa");
|
|
onData?.("z");
|
|
|
|
expect(frames).toEqual([
|
|
{ sequence: 0, at_ms: expect.any(Number), data: "z" },
|
|
]);
|
|
expect(renderedChunks).toEqual(["z"]);
|
|
expect(journal).toEqual([["frames", 0]]);
|
|
expect(captureRetention()).toEqual({
|
|
raw_terminal: {
|
|
budget_bytes: 1_000,
|
|
observed_bytes: 4,
|
|
retained_bytes: 1,
|
|
observed_frames: 2,
|
|
retained_frames: 1,
|
|
},
|
|
normalized_terminal: {
|
|
budget_bytes: 1_000,
|
|
retained_bytes: 1,
|
|
omitted_frames: 1,
|
|
},
|
|
});
|
|
});
|