From 6848e71947caf6e096e265a9d2d5d7941214fb10 Mon Sep 17 00:00:00 2001 From: minpeter Date: Fri, 24 Jul 2026 03:16:20 +0900 Subject: [PATCH] fix(coding-agent): bound compaction progress preview --- .../src/modes/interactive/changes.md | 23 +++++++++++++++++++ .../src/modes/interactive/interactive-mode.ts | 6 +++-- .../test/interactive-mode-compaction.test.ts | 12 ++++++---- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/coding-agent/src/modes/interactive/changes.md b/packages/coding-agent/src/modes/interactive/changes.md index 8db8b087c..8e91d2e2d 100644 --- a/packages/coding-agent/src/modes/interactive/changes.md +++ b/packages/coding-agent/src/modes/interactive/changes.md @@ -1,5 +1,28 @@ # changes +## bounded compaction progress preview (2026-07-24) + +### What changed + +- Streamed compaction summary progress is normalized and rendered as a single `TruncatedText` row beneath the active + compaction indicator. +- Multiline summary content no longer expands the transient status container or pushes the editor and transcript + through repeated terminal viewport remaps. + +### Why + +- Compaction summaries can contain thousands of characters and many newlines. Rendering that temporary content + verbatim above the editor made the composer move with every progress update and pushed prior output into scrollback, + which looked like transcript deletion. + +### Why extension system couldn't handle this + +- Compaction progress events and the status/editor container layout are private interactive-mode rendering surfaces. + +### Expected merge conflict zones + +- MEDIUM: `interactive-mode.ts` compaction progress event rendering. + ## per-section thinking duration headers (2026-07-22) ### What changed diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 31640688d..f206ea92d 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -3561,11 +3561,13 @@ export class InteractiveMode { event.text !== undefined ? event.text : `${this.autoCompactionProgressText}${event.delta ?? ""}`; if (!nextText) break; this.autoCompactionProgressText = nextText; - const preview = nextText.length > 4_000 ? `...${nextText.slice(nextText.length - 4_000)}` : nextText; + const previewSource = nextText.length > 4_000 ? `...${nextText.slice(nextText.length - 4_000)}` : nextText; + const preview = previewSource.replace(/\s+/g, " ").trim(); + if (!preview) break; this.statusContainer.clear(); this.statusContainer.addChild(this.activeStatusIndicator); this.statusContainer.addChild(new Spacer(1)); - this.statusContainer.addChild(new Text(theme.fg("muted", preview), 1, 0)); + this.statusContainer.addChild(new TruncatedText(theme.fg("muted", preview), 1, 0)); this.ui.requestRender(); break; } diff --git a/packages/coding-agent/test/interactive-mode-compaction.test.ts b/packages/coding-agent/test/interactive-mode-compaction.test.ts index cb182601f..4e21253b2 100644 --- a/packages/coding-agent/test/interactive-mode-compaction.test.ts +++ b/packages/coding-agent/test/interactive-mode-compaction.test.ts @@ -83,12 +83,16 @@ describe("InteractiveMode compaction events", () => { await handleEvent.call(fakeThis, { type: "compaction_progress", reason: "extension", - delta: "live summary chunk", + delta: "live summary\nchunk", }); - const rendered = stripAnsi(statusContainer.children.flatMap((child) => child.render(120)).join("\n")); - expect(rendered).toContain("Compacting context"); - expect(rendered).toContain("live summary chunk"); + const rendered = statusContainer.children + .flatMap((child) => child.render(120)) + .map((line) => stripAnsi(line)) + .filter((line) => line.trim().length > 0); + expect(rendered).toHaveLength(2); + expect(rendered[0]).toContain("Compacting context"); + expect(rendered[1]).toContain("live summary chunk"); fakeThis.autoCompactionLoader?.stop(); });