From 6a0f359d24a4d2e07aa029b1a227f27f68840c70 Mon Sep 17 00:00:00 2001 From: JJ Lee Date: Wed, 2 Sep 2026 18:27:46 -0400 Subject: [PATCH] fix(app): suppress per-message Changed files section (harmoniqs/amicode#733) Remove the per-message DiffSummary row from the chat timeline. The side-panel Files Changed tab is the canonical diff surface; the inline section was redundant and leaked cross-session file changes during concurrent turns. - rows.ts: comment out the DiffSummary block - rows-current.test.ts: add test confirming DiffSummary rows are no longer emitted --- .../session/timeline/rows-current.test.ts | 52 +++++++++++++++++++ .../app/src/pages/session/timeline/rows.ts | 14 ++--- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/packages/app/src/pages/session/timeline/rows-current.test.ts b/packages/app/src/pages/session/timeline/rows-current.test.ts index 942ed8819..8c09bafc5 100644 --- a/packages/app/src/pages/session/timeline/rows-current.test.ts +++ b/packages/app/src/pages/session/timeline/rows-current.test.ts @@ -308,6 +308,58 @@ describe("current session timeline rows", () => { } }) + test("suppresses per-message DiffSummary rows even when summary.diffs is populated (#733)", () => { + const source = [ + { + id: "msg_u", + type: "user", + text: "edit some files", + time: { created: 1 }, + summary: { + additions: 10, + deletions: 3, + files: 2, + diffs: [ + { file: "src/foo.ts", additions: 7, deletions: 2 }, + { file: "src/bar.ts", additions: 3, deletions: 1 }, + ], + }, + }, + { + id: "msg_a", + type: "assistant", + agent: "build", + model: { id: "model", providerID: "provider" }, + content: [{ type: "text", text: "done" }], + time: { created: 2, completed: 3 }, + }, + ] as SessionMessageInfo[] + const normalized = normalizeSessionMessages("ses_1", source) + const messages = new Map(normalized.messages.map((message) => [message.id, message])) + // Inject summary.diffs onto the user message (normalizeSessionMessages + // strips it, but the live store propagates it) + const userMsg = messages.get("msg_u")! + ;(userMsg as any).summary = (source[0] as any).summary + + const result = Timeline.constructSessionMessageRows( + source, + (messageID) => messages.get(messageID), + (messageID) => normalized.parts.get(messageID) ?? [], + true, + "idle", + true, + normalized.messages.filter((m) => m.role === "user"), + ) + + // No DiffSummary row should appear — the section is suppressed (#733) + const tags = result.rows.map((r) => r._tag) + expect(tags).not.toContain("DiffSummary") + // The normal rows are still present + expect(tags).toContain("UserMessage") + expect(tags).toContain("AssistantPart") + expect(tags).toContain("ThinkingMeta") + }) + test("turnStartedAt is threaded through Thinking and AssistantPart rows from user message time.created", () => { const source = [ { id: "msg_u", type: "user", text: "go", time: { created: 1000 } }, diff --git a/packages/app/src/pages/session/timeline/rows.ts b/packages/app/src/pages/session/timeline/rows.ts index 202c3e42c..7f7e78c0c 100644 --- a/packages/app/src/pages/session/timeline/rows.ts +++ b/packages/app/src/pages/session/timeline/rows.ts @@ -3,7 +3,7 @@ import type { SessionMessageInfo } from "@opencode-ai/client/promise" import { AssistantMessage, Part, SessionStatus, UserMessage } from "@opencode-ai/sdk/v2" import { groupParts, renderable, type PartGroup } from "@opencode-ai/session-ui/message-part" import { TimelineRow, type SummaryDiff } from "./timeline-row" -import { uniqueSummaryDiffs } from "./summary-diffs" +// import { uniqueSummaryDiffs } from "./summary-diffs" // suppressed (harmoniqs/amicode#733) export { TimelineRow, type SummaryDiff } from "./timeline-row" @@ -290,15 +290,9 @@ export namespace Timeline { if (isActive && status === "retry") rows.push(new TimelineRow.Retry({ userMessageID: userMessage.id })) - const diffs = uniqueSummaryDiffs(userMessage.summary?.diffs) - if (diffs.length > 0 && (status === "idle" || !isActive)) { - rows.push( - new TimelineRow.DiffSummary({ - userMessageID: userMessage.id, - diffs, - }), - ) - } + // Per-message "Changed files" section suppressed (harmoniqs/amicode#733): + // redundant with the side-panel Files Changed tab, and the unfiltered + // snapshot diff leaks cross-session file changes during concurrent turns. if (error) { const data = error.data?.message