From 043f123b8ff6588337ea1ffa47c5ef49f63db54c Mon Sep 17 00:00:00 2001 From: Jake Leventhal Date: Tue, 14 Jul 2026 15:03:43 -0400 Subject: [PATCH 1/3] Default diffs to working changes --- apps/web/src/components/DiffPanel.tsx | 10 +++++++--- apps/web/src/diffPanelStore.test.ts | 16 +++++++++++++++- apps/web/src/diffPanelStore.ts | 7 ++++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx index cbcd36ce05e..d5989a9648d 100644 --- a/apps/web/src/components/DiffPanel.tsx +++ b/apps/web/src/components/DiffPanel.tsx @@ -199,9 +199,6 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff strict: false, select: (params) => resolveThreadRouteRef(params), }); - const diffSelection = useDiffPanelStore((state) => - selectThreadDiffPanelSelection(state.byThreadKey, routeThreadRef), - ); const activeThreadId = routeThreadRef?.threadId ?? null; const activeThread = useThread(routeThreadRef); const activeProjectId = activeThread?.projectId ?? null; @@ -229,6 +226,13 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff }) : null, ); + const diffSelection = useDiffPanelStore((state) => + selectThreadDiffPanelSelection( + state.byThreadKey, + routeThreadRef, + gitStatusQuery.data?.hasWorkingTreeChanges === true, + ), + ); const isGitRepo = gitStatusQuery.data?.isRepo ?? true; const { turnDiffSummaries, inferredCheckpointTurnCountByTurnId } = useTurnDiffSummaries(activeThread); diff --git a/apps/web/src/diffPanelStore.test.ts b/apps/web/src/diffPanelStore.test.ts index 64846e8e9f1..607b7c8d580 100644 --- a/apps/web/src/diffPanelStore.test.ts +++ b/apps/web/src/diffPanelStore.test.ts @@ -9,12 +9,26 @@ const THREAD_REF = scopeThreadRef(EnvironmentId.make("environment-1"), ThreadId. describe("diffPanelStore", () => { beforeEach(() => useDiffPanelStore.setState({ byThreadKey: {}, branchBaseRefByThreadKey: {} })); - it("defaults each thread to branch changes with automatic base selection", () => { + it("defaults each thread to branch changes when the working tree is clean", () => { expect( selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF), ).toEqual({ kind: "branch", baseRef: null }); }); + it("defaults each thread to working changes when the working tree is dirty", () => { + expect( + selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF, true), + ).toEqual({ kind: "unstaged" }); + }); + + it("preserves an explicit scope selection when the working tree state changes", () => { + useDiffPanelStore.getState().selectGitScope(THREAD_REF, "branch"); + + expect( + selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF, true), + ).toEqual({ kind: "branch", baseRef: null }); + }); + it("clears incompatible selection fields when changing scopes", () => { const store = useDiffPanelStore.getState(); store.selectTurn(THREAD_REF, TurnId.make("turn-1"), "src/app.ts"); diff --git a/apps/web/src/diffPanelStore.ts b/apps/web/src/diffPanelStore.ts index c946b286d1b..56b5ad23fec 100644 --- a/apps/web/src/diffPanelStore.ts +++ b/apps/web/src/diffPanelStore.ts @@ -11,6 +11,7 @@ export type DiffPanelSelection = | { kind: "turn"; turnId: TurnId; filePath: string | null; revealRequestId: number }; const DEFAULT_SELECTION: DiffPanelSelection = { kind: "branch", baseRef: null }; +const DEFAULT_WORKING_TREE_SELECTION: DiffPanelSelection = { kind: "unstaged" }; interface DiffPanelStoreState { byThreadKey: Record; @@ -133,7 +134,11 @@ export const useDiffPanelStore = create()( export function selectThreadDiffPanelSelection( byThreadKey: Record, ref: ScopedThreadRef | null | undefined, + hasWorkingTreeChanges = false, ): DiffPanelSelection { if (!ref) return DEFAULT_SELECTION; - return byThreadKey[scopedThreadKey(ref)] ?? DEFAULT_SELECTION; + return ( + byThreadKey[scopedThreadKey(ref)] ?? + (hasWorkingTreeChanges ? DEFAULT_WORKING_TREE_SELECTION : DEFAULT_SELECTION) + ); } From ed774d7547e335866360b5ffb3c42634a9ea7e89 Mon Sep 17 00:00:00 2001 From: Jake Leventhal Date: Tue, 14 Jul 2026 15:46:12 -0400 Subject: [PATCH 2/3] Freeze initial diff scope after status resolves --- apps/web/src/components/ChatView.tsx | 10 +++++++++- apps/web/src/components/DiffPanel.tsx | 10 ++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index f5ea5bb1eba..435b63c097f 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -2151,6 +2151,9 @@ function ChatViewContent(props: ChatViewProps) { terminalUiLaunchContext?.threadId === activeThreadId ? terminalUiLaunchContext : null; // Default true while loading to avoid toolbar flicker. const isGitRepo = gitStatusQuery.data?.isRepo ?? true; + const initialDiffPanelGitScope = + gitStatusQuery.data?.hasWorkingTreeChanges === true ? "unstaged" : "branch"; + const diffPanelGitStatusResolutionKey = gitStatusQuery.data ? "resolved" : "pending"; const terminalShortcutLabelOptions = useMemo( () => ({ context: { @@ -4968,7 +4971,12 @@ function ChatViewContent(props: ChatViewProps) { /> ) : activeRightPanelSurface?.kind === "diff" ? ( - + ) : activeRightPanelSurface?.kind === "plan" ? ( ("stacked"); const [wordWrap, setWordWrap] = useState(settings.wordWrap); const [diffIgnoreWhitespace, setDiffIgnoreWhitespace] = useState(settings.diffIgnoreWhitespace); @@ -230,7 +236,7 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff selectThreadDiffPanelSelection( state.byThreadKey, routeThreadRef, - gitStatusQuery.data?.hasWorkingTreeChanges === true, + initialGitScope === "unstaged", ), ); const isGitRepo = gitStatusQuery.data?.isRepo ?? true; From 9b875124d351fcd3d5bc9a3d1e4b27606863bf16 Mon Sep 17 00:00:00 2001 From: Jake Leventhal Date: Tue, 14 Jul 2026 16:46:28 -0400 Subject: [PATCH 3/3] Use active thread worktree for git status --- apps/web/src/components/ChatView.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 435b63c097f..70bbc296288 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -2112,12 +2112,13 @@ function ChatViewContent(props: ChatViewProps) { worktreePath: activeThread?.worktreePath ?? null, }) : null; + const gitStatusCwd = activeThread?.worktreePath ?? gitCwd; const gitStatusQuery = useEnvironmentQuery( - gitCwd === null + gitStatusCwd === null ? null : vcsEnvironment.status({ environmentId, - input: { cwd: gitCwd }, + input: { cwd: gitStatusCwd }, }), ); const keybindings = useAtomValue(primaryServerKeybindingsAtom);