From 41160ed5b21ed1e73db1ce6d60c6de067b8fc354 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Mon, 15 Jun 2026 15:10:12 +0300 Subject: [PATCH] fix: refresh pending changes from chat input Keeps pending changes state fresh even when the bar is hidden Updates the composer when workspace changes appear or disappear Removes duplicate refresh handling from the pending changes bar --- packages/ui/src/components/chat/ChatInput.tsx | 17 ++++++++++++- .../src/components/chat/PendingChangesBar.tsx | 24 ------------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/packages/ui/src/components/chat/ChatInput.tsx b/packages/ui/src/components/chat/ChatInput.tsx index 96cef170..64696d3f 100644 --- a/packages/ui/src/components/chat/ChatInput.tsx +++ b/packages/ui/src/components/chat/ChatInput.tsx @@ -69,6 +69,7 @@ import { buildSessionTargetOptions } from '@/sync/session-worktree-contract'; import { usePermissionStore } from '@/stores/permissionStore'; import { extractGitChangedFiles } from './changedFiles'; import { useI18n } from '@/lib/i18n'; +import { sessionEvents } from '@/lib/sessionEvents'; import { fetchResponseStyleInstruction } from '@/lib/responseStyle'; import { wrapSystemReminder } from '@/lib/systemReminder'; import { getSyncMessages } from '@/sync/sync-refs'; @@ -1044,6 +1045,8 @@ const ChatInputComponent: React.FC = ({ onOpenSettings, scrollTo const currentGitStatus = useGitStore((state) => currentDirectory ? state.directories.get(currentDirectory)?.status ?? null : null, ); + const ensureGitStatus = useGitStore((state) => state.ensureStatus); + const fetchGitStatus = useGitStore((state) => state.fetchStatus); const [showAbortStatus, setShowAbortStatus] = React.useState(false); const setSessionAutoAccept = usePermissionStore((state) => state.setSessionAutoAccept); const composerHighlightRef = React.useRef(null); @@ -1065,6 +1068,19 @@ const ChatInputComponent: React.FC = ({ onOpenSettings, scrollTo setImagePreviewOpen(open); }, [setImagePreviewOpen]); + React.useEffect(() => { + if (!currentDirectory || !runtimeGit) return; + void ensureGitStatus(currentDirectory, runtimeGit); + }, [currentDirectory, runtimeGit, ensureGitStatus]); + + React.useEffect(() => { + if (!currentDirectory || !runtimeGit) return; + return sessionEvents.onGitRefreshHint((hint) => { + if (normalizePath(hint.directory) !== normalizePath(currentDirectory)) return; + void fetchGitStatus(currentDirectory, runtimeGit); + }); + }, [currentDirectory, runtimeGit, fetchGitStatus]); + const handleStartReviewFlow = React.useCallback(async (execution: ReviewFlowExecution) => { if (!currentSessionId) return; const directory = useSessionUIStore.getState().getDirectoryForSession(currentSessionId) || currentDirectory || ''; @@ -3556,7 +3572,6 @@ const ChatInputComponent: React.FC = ({ onOpenSettings, scrollTo ); const selectedDraftProjectIsGitRepo = useIsGitRepo(selectedDraftProjectPath); const hasDraftBranchList = Boolean(selectedDraftProjectBranches?.all); - const fetchGitStatus = useGitStore((state) => state.fetchStatus); const fetchBranches = useGitStore((state) => state.fetchBranches); const [isDiscoveringDraftBranches, setIsDiscoveringDraftBranches] = React.useState(false); diff --git a/packages/ui/src/components/chat/PendingChangesBar.tsx b/packages/ui/src/components/chat/PendingChangesBar.tsx index 5ef7ab55..bd8cb31d 100644 --- a/packages/ui/src/components/chat/PendingChangesBar.tsx +++ b/packages/ui/src/components/chat/PendingChangesBar.tsx @@ -4,8 +4,6 @@ import { useGitStore, useIsGitRepo } from '@/stores/useGitStore'; import { useUIStore } from '@/stores/useUIStore'; import { RuntimeAPIContext } from '@/contexts/runtimeAPIContext'; import { useMobileAppActions } from '@/apps/mobileAppContext'; -import { sessionEvents } from '@/lib/sessionEvents'; -import { normalizePath } from '@/components/session/sidebar/utils'; import { Icon } from "@/components/icon/Icon"; import { cn } from '@/lib/utils'; import { @@ -28,8 +26,6 @@ export const PendingChangesBar: React.FC = React.memo(() => { const gitStatus = useGitStore((s) => currentDirectory ? s.directories.get(currentDirectory)?.status ?? null : null, ); - const ensureStatus = useGitStore((s) => s.ensureStatus); - const fetchStatus = useGitStore((s) => s.fetchStatus); const mobileActions = useMobileAppActions(); // Close popover when clicking outside @@ -46,26 +42,6 @@ export const PendingChangesBar: React.FC = React.memo(() => { return () => document.removeEventListener("mousedown", handleClickOutside); }, [isExpanded]); - // Seed git store for currentDirectory so the bar can render independently of - // DiffView/GitView/right-sidebar mounting. ensureStatus has a 5s staleness - // gate and inFlightStatusFetchesByDirectory dedupes against concurrent callers. - React.useEffect(() => { - if (!currentDirectory || !runtime?.git) return; - void ensureStatus(currentDirectory, runtime.git); - }, [currentDirectory, runtime?.git, ensureStatus]); - - // Mirror the onGitRefreshHint listener that lives in DiffView/GitView so the - // bar refreshes after mutating tools (edit/write/apply_patch/bash/...) even - // when neither of those views is open — e.g. VS Code runtime. - React.useEffect(() => { - if (!currentDirectory || !runtime?.git) return; - const git = runtime.git; - return sessionEvents.onGitRefreshHint((hint) => { - if (normalizePath(hint.directory) !== normalizePath(currentDirectory)) return; - void fetchStatus(currentDirectory, git); - }); - }, [currentDirectory, runtime?.git, fetchStatus]); - const gitChangedFiles = React.useMemo(() => { if (isGitRepo !== true || !gitStatus || gitStatus.isClean) return []; return extractGitChangedFiles(gitStatus.files, gitStatus.diffStats, currentDirectory);