From 4240984594ff9f4da6da45dd20093d697a98d201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Salavisa?= Date: Mon, 2 Feb 2026 22:53:29 +0000 Subject: [PATCH] Fix diff view not updating when agent modifies files (#157) --- .../internal/orchestrator/event_handlers.go | 10 +++++-- .../components/task/task-changes-panel.tsx | 8 +++-- .../session-runtime/session-runtime-slice.ts | 30 ++----------------- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/apps/backend/internal/orchestrator/event_handlers.go b/apps/backend/internal/orchestrator/event_handlers.go index ec21d4844e..668b6158a6 100644 --- a/apps/backend/internal/orchestrator/event_handlers.go +++ b/apps/backend/internal/orchestrator/event_handlers.go @@ -1141,7 +1141,7 @@ func (s *Service) isSnapshotDuplicate(existing, new *models.GitSnapshot) bool { return false } - // Compare file paths, staged status, and line counts + // Compare file paths, staged status, line counts, and diff content for path, newFileData := range new.Files { existingFileData, exists := existing.Files[path] if !exists { @@ -1154,7 +1154,8 @@ func (s *Service) isSnapshotDuplicate(existing, new *models.GitSnapshot) bool { if newInfo.staged != existingInfo.staged || newInfo.additions != existingInfo.additions || - newInfo.deletions != existingInfo.deletions { + newInfo.deletions != existingInfo.deletions || + newInfo.diff != existingInfo.diff { return false } } @@ -1167,6 +1168,7 @@ type fileInfoCompare struct { staged bool additions int deletions int + diff string } // extractFileInfo extracts comparable fields from a file info interface @@ -1190,6 +1192,10 @@ func extractFileInfo(fileData interface{}) fileInfoCompare { } else if deletions, ok := fileMap["deletions"].(int); ok { info.deletions = deletions } + // Extract diff content for comparison + if diff, ok := fileMap["diff"].(string); ok { + info.diff = diff + } } return info } diff --git a/apps/web/components/task/task-changes-panel.tsx b/apps/web/components/task/task-changes-panel.tsx index 8dbfdaaf11..b0868c0979 100644 --- a/apps/web/components/task/task-changes-panel.tsx +++ b/apps/web/components/task/task-changes-panel.tsx @@ -99,8 +99,9 @@ const TaskChangesPanel = memo(function TaskChangesPanel({ }, [cumulativeDiff]); const selectedFile = selectedDiffPath && gitStatus?.files ? gitStatus.files[selectedDiffPath] : null; - // Use provided content if available, otherwise fall back to git status - const selectedDiffContent = selectedDiff?.content ?? selectedFile?.diff ?? ''; + // Prioritize current git status for uncommitted files, use provided content only for historical diffs + // This ensures that when a file is modified by the agent, we show the latest diff + const selectedDiffContent = selectedFile?.diff ?? selectedDiff?.content ?? ''; const isSingleDiffSelected = Boolean(selectedDiffPath && (hasProvidedContent || selectedFile)); // Discard only works for uncommitted changes (not committed/historical diffs) const canDiscard = Boolean(selectedDiffPath && selectedFile && !hasProvidedContent); @@ -192,7 +193,8 @@ const TaskChangesPanel = memo(function TaskChangesPanel({ {isSingleDiffSelected && selectedDiffContent ? ( // Render single file diff (from commit, snapshot, or uncommitted) -
+ // Use timestamp from git status to ensure re-render when file changes +
set((draft) => { - const existing = draft.gitStatus.bySessionId[sessionId]; - // Skip update if git status content hasn't meaningfully changed - // Compare branch, file counts, and modified/added/deleted arrays - if (existing) { - const sameContent = - existing.branch === gitStatus.branch && - existing.ahead === gitStatus.ahead && - existing.behind === gitStatus.behind && - arraysEqual(existing.modified, gitStatus.modified) && - arraysEqual(existing.added, gitStatus.added) && - arraysEqual(existing.deleted, gitStatus.deleted) && - arraysEqual(existing.untracked, gitStatus.untracked) && - arraysEqual(existing.renamed, gitStatus.renamed); - if (sameContent) { - return; // Skip update - no meaningful changes - } - } + // Always update git status - the timestamp and file diffs may have changed + // even if the file lists are the same. The backend sends updates when content changes. draft.gitStatus.bySessionId[sessionId] = gitStatus; }), clearGitStatus: (sessionId) =>