fix(coding-agent/debug): Sanitized debug log rendering

- Sanitized debug log lines by stripping ANSI/control codes, replacing tabs, and truncating to terminal width.
- Added formatting helper and unit tests covering sanitization, tab handling, and truncation.
This commit is contained in:
julia
2026-02-13 23:58:47 +00:00
committed by can1357
parent 918bf9b043
commit 8d3fe37ca5
4 changed files with 47 additions and 2 deletions
+4
View File
@@ -9,6 +9,9 @@
- Fixed `session.abort()` not clearing `promptInFlight` flag due to microtask ordering, which blocked subsequent prompts
### Fixed
- Sanitized debug log display to strip control codes, normalize tabs, and trim width
## [12.4.0] - 2026-02-14
### Changed
@@ -69,6 +72,7 @@
- Improved error reporting in fetch tool to include HTTP status codes when URL fetching fails
- Fixed fetch tool to preserve actual response metadata (finalUrl, contentType) instead of defaults when requests fail
||||||| parent of a70a34c8b (fix(coding-agent/debug): Sanitized debug log rendering)
## [12.1.0] - 2026-02-13
### Added
+5 -2
View File
@@ -11,6 +11,7 @@ import { DynamicBorder } from "../modes/components/dynamic-border";
import { getSelectListTheme, getSymbolTheme, theme } from "../modes/theme/theme";
import type { InteractiveModeContext } from "../modes/types";
import { openPath } from "../utils/open";
import { formatDebugLogLine } from "./log-formatting";
import { generateHeapSnapshotData, type ProfilerSession, startCpuProfile } from "./profiler";
import { clearArtifactCache, createReportBundle, getArtifactCacheStats, getRecentLogs } from "./report-bundle";
import { collectSystemInfo, formatSystemInfo } from "./system-info";
@@ -284,10 +285,12 @@ export class DebugSelectorComponent extends Container {
this.ctx.chatContainer.addChild(new Spacer(1));
// Display logs with dim styling
const maxWidth = Math.max(1, this.ctx.ui.terminal.columns - 2);
const lines = logs.split("\n").slice(-50);
for (const line of lines) {
if (line.trim()) {
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", line), 1, 0));
const formatted = formatDebugLogLine(line, maxWidth);
if (formatted.trim()) {
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", formatted), 1, 0));
}
}
@@ -0,0 +1,9 @@
import { sanitizeText } from "@oh-my-pi/pi-utils";
import { replaceTabs, truncateToWidth } from "../tools/render-utils";
export function formatDebugLogLine(line: string, maxWidth: number): string {
const sanitized = sanitizeText(line);
const normalized = replaceTabs(sanitized);
const width = Math.max(1, maxWidth);
return truncateToWidth(normalized, width);
}
@@ -0,0 +1,29 @@
import { describe, expect, it } from "bun:test";
import { formatDebugLogLine } from "../../src/debug/log-formatting";
describe("formatDebugLogLine", () => {
it("strips ANSI codes and carriage returns", () => {
const input = "\u001b[31merror\r\u001b[0m";
const result = formatDebugLogLine(input, 80);
expect(result).toBe("error");
});
it("replaces tabs with spaces", () => {
const input = "col1\tcol2";
const result = formatDebugLogLine(input, 80);
expect(result).toBe("col1 col2");
});
it("removes unsafe control characters", () => {
const input = "ok\u0007bad";
const result = formatDebugLogLine(input, 80);
expect(result).toBe("okbad");
});
it("truncates long lines", () => {
const input = "0123456789ABCDEFGHIJ";
const result = formatDebugLogLine(input, 10);
expect(Bun.stringWidth(result)).toBeLessThanOrEqual(10);
expect(result.startsWith("012345")).toBe(true);
});
});