[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled

This commit is contained in:
2026-09-13 18:24:01 +08:00
commit 3c72efcb7f
3255 changed files with 907009 additions and 0 deletions

View File

@@ -0,0 +1,276 @@
import assert from "node:assert/strict";
import test from "node:test";
import type { Terminal as XTerm } from "@xterm/xterm";
import {
getTerminalOutputPressure,
isTerminalScrollbackSaturated,
noteTerminalOutputPressureData,
resetTerminalOutputPressure,
setTerminalOutputPressureVisibility,
shouldDegradeTerminalSideWork,
shouldDegradeTerminalKeywordHighlight,
shouldSkipTerminalLineTimestamps,
} from "./terminalOutputPressure.ts";
import { TERMINAL_LONG_LINE_PRESSURE_BYTES } from "./terminalFlowConstants.ts";
import { XTERM_PERFORMANCE_CONFIG } from "../../../infrastructure/config/xtermPerformance.ts";
const createFakeTerm = (overrides: Record<string, unknown> = {}) => ({
rows: 24,
options: { scrollback: 1000 },
buffer: { active: { length: 10, baseY: 0 } },
...overrides,
}) as unknown as XTerm;
test("tracks long unbroken terminal output pressure until a line break arrives", () => {
const term = createFakeTerm();
noteTerminalOutputPressureData(term, "x".repeat(TERMINAL_LONG_LINE_PRESSURE_BYTES - 1));
assert.equal(getTerminalOutputPressure(term).longLine, false);
noteTerminalOutputPressureData(term, "x");
assert.equal(getTerminalOutputPressure(term).longLine, true);
assert.equal(getTerminalOutputPressure(term).mode, "long-line");
noteTerminalOutputPressureData(term, "\nshort");
assert.equal(getTerminalOutputPressure(term).longLine, false);
// Crossing the long-line threshold also arms the high-rate large-output window.
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
resetTerminalOutputPressure(term);
});
test("reports newline-terminated long terminal lines as long-line pressure", () => {
const term = createFakeTerm();
noteTerminalOutputPressureData(term, `${"x".repeat(TERMINAL_LONG_LINE_PRESSURE_BYTES)}\n`);
assert.equal(getTerminalOutputPressure(term).longLine, true);
assert.equal(getTerminalOutputPressure(term).mode, "long-line");
assert.equal(getTerminalOutputPressure(term).consecutiveUnbrokenBytes, 0);
noteTerminalOutputPressureData(term, "short\n");
assert.equal(getTerminalOutputPressure(term).longLine, false);
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
resetTerminalOutputPressure(term);
});
test("reports background pressure separately from output volume", () => {
const term = createFakeTerm();
setTerminalOutputPressureVisibility(term, false);
assert.equal(getTerminalOutputPressure(term).background, true);
assert.equal(getTerminalOutputPressure(term).mode, "background");
assert.equal(shouldDegradeTerminalSideWork(term), false);
setTerminalOutputPressureVisibility(term, true);
assert.equal(getTerminalOutputPressure(term).background, false);
assert.equal(getTerminalOutputPressure(term).mode, "normal");
resetTerminalOutputPressure(term);
});
test("keeps large-output pressure through small input echoes until output is quiet", () => {
const term = createFakeTerm();
const originalNow = performance.now.bind(performance);
let now = 1_000;
Object.defineProperty(performance, "now", {
configurable: true,
value: () => now,
});
try {
noteTerminalOutputPressureData(term, "x\n".repeat(Math.ceil(TERMINAL_LONG_LINE_PRESSURE_BYTES / 2)));
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
now += 16;
noteTerminalOutputPressureData(term, "a");
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
now += XTERM_PERFORMANCE_CONFIG.highlighting.largeOutputQuietMs + 1;
assert.equal(getTerminalOutputPressure(term).largeOutput, false);
assert.equal(getTerminalOutputPressure(term).mode, "normal");
} finally {
Object.defineProperty(performance, "now", {
configurable: true,
value: originalNow,
});
resetTerminalOutputPressure(term);
}
});
test("detects large-output pressure from high-rate small chunks", () => {
const term = createFakeTerm();
const originalNow = performance.now.bind(performance);
let now = 5_000;
Object.defineProperty(performance, "now", {
configurable: true,
value: () => now,
});
try {
// ~16KB of short lines inside the 100ms rate window (not one unbroken run).
// Threshold is intentionally below one Tabby-sized xterm shard.
for (let index = 0; index < 16; index += 1) {
noteTerminalOutputPressureData(term, `${"y".repeat(1023)}\n`);
}
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(getTerminalOutputPressure(term).longLine, false);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
} finally {
Object.defineProperty(performance, "now", {
configurable: true,
value: originalNow,
});
resetTerminalOutputPressure(term);
}
});
test("arms large-output early on multi-line writes when scrollback is saturated", () => {
// rows(24) + scrollback(1000) = 1024 max; length near cap → second-seq path.
const term = createFakeTerm({
rows: 24,
options: { scrollback: 1000 },
buffer: { active: { length: 1020, baseY: 996 } },
});
const originalNow = performance.now.bind(performance);
let now = 9_000;
Object.defineProperty(performance, "now", {
configurable: true,
value: () => now,
});
try {
assert.equal(isTerminalScrollbackSaturated(term), true);
// Far below the long-line / 16KB rate thresholds — only saturated multi-line
// arming should trip bulk mode (second `seq` cold start).
noteTerminalOutputPressureData(term, "1\n2\n3\n4\n5\n");
assert.equal(getTerminalOutputPressure(term).scrollbackSaturated, true);
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(shouldDegradeTerminalSideWork(term), true);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
// Quiet window is extended while saturated so prompt-echo gaps do not
// reopen the expensive timestamp/highlight path before a second dump.
now += XTERM_PERFORMANCE_CONFIG.highlighting.largeOutputQuietMs + 1;
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
now += XTERM_PERFORMANCE_CONFIG.highlighting.largeOutputQuietMs + 1;
assert.equal(getTerminalOutputPressure(term).largeOutput, false);
} finally {
Object.defineProperty(performance, "now", {
configurable: true,
value: originalNow,
});
resetTerminalOutputPressure(term);
}
});
test("a one-line prompt does not degrade keyword coloring on saturated scrollback", () => {
const term = createFakeTerm({
rows: 24,
options: { scrollback: 1000 },
buffer: { active: { length: 1020, baseY: 996 } },
});
const prompt = "\r\nplain prompt # ";
noteTerminalOutputPressureData(term, prompt);
assert.equal(shouldDegradeTerminalSideWork(term), true);
assert.equal(shouldDegradeTerminalKeywordHighlight(term, prompt), false);
resetTerminalOutputPressure(term);
});
test("does not treat an empty buffer as scrollback-saturated", () => {
const term = createFakeTerm({
rows: 24,
options: { scrollback: 1000 },
buffer: { active: { length: 12, baseY: 0 } },
});
assert.equal(isTerminalScrollbackSaturated(term), false);
noteTerminalOutputPressureData(term, "1\n2\n3\n");
assert.equal(getTerminalOutputPressure(term).largeOutput, false);
assert.equal(getTerminalOutputPressure(term).scrollbackSaturated, false);
resetTerminalOutputPressure(term);
});
test("saturated multi-line degrades side work but keeps line timestamps", () => {
const term = createFakeTerm({
rows: 24,
options: { scrollback: 1000 },
buffer: { active: { length: 1020, baseY: 996 } },
});
// docker-ps-sized multi-line on a full scrollback: highlight/prep may degrade,
// but per-line gutter timestamps must still stamp.
noteTerminalOutputPressureData(term, "CONTAINER ID IMAGE\n".repeat(20));
assert.equal(shouldDegradeTerminalSideWork(term), true);
assert.equal(
shouldDegradeTerminalKeywordHighlight(term, "CONTAINER ID IMAGE\n".repeat(20)),
false,
);
assert.equal(shouldSkipTerminalLineTimestamps(term), false);
resetTerminalOutputPressure(term);
});
test("true flood rate skips line timestamps", () => {
const term = createFakeTerm();
const originalNow = performance.now.bind(performance);
let now = 20_000;
Object.defineProperty(performance, "now", {
configurable: true,
value: () => now,
});
try {
// 64KB+ inside the rate window → timestamp flood gate.
for (let index = 0; index < 64; index += 1) {
noteTerminalOutputPressureData(term, `${"z".repeat(1023)}\n`);
}
assert.equal(shouldSkipTerminalLineTimestamps(term), true);
assert.equal(shouldDegradeTerminalSideWork(term), true);
} finally {
Object.defineProperty(performance, "now", {
configurable: true,
value: originalNow,
});
resetTerminalOutputPressure(term);
}
});
test("rate detector uses a true rolling window across early tiny samples", () => {
const term = createFakeTerm();
const originalNow = performance.now.bind(performance);
let now = 1;
Object.defineProperty(performance, "now", {
configurable: true,
value: () => now,
});
try {
noteTerminalOutputPressureData(term, "x\n");
now = 60;
noteTerminalOutputPressureData(term, `${"x".repeat(40 * 1024)}\n`);
now = 102;
noteTerminalOutputPressureData(term, `${"x".repeat(40 * 1024)}\n`);
// 80KB arrived within 42ms; the tiny sample at t=1 should age out, not reset the window.
assert.equal(getTerminalOutputPressure(term).largeOutput, true);
assert.equal(getTerminalOutputPressure(term).mode, "large-output");
} finally {
Object.defineProperty(performance, "now", {
configurable: true,
value: originalNow,
});
resetTerminalOutputPressure(term);
}
});