authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-10-07 22:48:54-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-07 22:48:54-07:00
log70eeb3996d557a2e553f817c8e123bf79bbd378c
tree1d60cacd8b024f2a8f30a0a750f5a8b333a40577
parent85a41391e9625d760f5bb2294834c38f42bbf5b8
signature Signed by PGP key B5690EEEBB952194

fix(mobile): stop refreshing Git status on streamed thread updates (#15893)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

2 files changed, 19 insertions(+), 4 deletions(-)

apps/mobile/src/state/use-selected-thread-git-actions.test.ts+1
......@@ -26,6 +26,7 @@ vi.mock("react", () => ({
2626 useCallback: (callback: unknown) => callback,
2727 useMemo: (factory: () => unknown) => factory(),
2828 useEffect: () => {},
29 useEffectEvent: (callback: unknown) => callback,
2930}));
3031vi.mock("./session", () => ({
3132 useEnvironmentScope: (environmentId: unknown, scope: string) =>
apps/mobile/src/state/use-selected-thread-git-actions.ts+18-4
......@@ -1,4 +1,4 @@
1import { useCallback, useEffect, useMemo } from "react";
1import { useCallback, useEffect, useEffectEvent, useMemo } from "react";
22
33import { EnvironmentProject, EnvironmentThreadShell } from "@t3tools/client-runtime/state/shell";
44import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime";
......@@ -140,12 +140,26 @@ export function useSelectedThreadGitActions() {
140140 [refreshStatus, selectedThread, selectedThreadCwd, selectedThreadProject],
141141 );
142142
143 // Shell updates replace the selected thread object many times per second while a
144 // turn streams, so key the refresh on primitives. The server publishes status after
145 // each turn finishes; this only seeds status when the selection or cwd changes.
146 const selectedEnvironmentId = selectedThread?.environmentId ?? null;
147 const selectedThreadId = selectedThread?.id ?? null;
148 const hasSelectedThreadProject = selectedThreadProject !== null;
149 const refreshOnSelection = useEffectEvent(() => {
150 void refreshSelectedThreadGitStatus({ quiet: true });
151 });
143152 useEffect(() => {
144 if (!selectedThread || !selectedThreadProject) {
153 if (
154 selectedEnvironmentId === null ||
155 selectedThreadId === null ||
156 !hasSelectedThreadProject ||
157 selectedThreadCwd === null
158 ) {
145159 return;
146160 }
147 void refreshSelectedThreadGitStatus({ quiet: true });
148 }, [refreshSelectedThreadGitStatus, selectedThread, selectedThreadProject]);
161 refreshOnSelection();
162 }, [selectedEnvironmentId, selectedThreadId, hasSelectedThreadProject, selectedThreadCwd]);
149163
150164 const runSelectedThreadGitMutation = useCallback(
151165 async <T, E>(