fix(ui): hold the changed-files gate until post-bootstrap status lands
Refresh hints fired while setup commands run can cache a mid-creation dirty snapshot; lifting the gate the moment bootstrap settles flashed that stale snapshot until the forced fetch resolved. The gate now stays down until the post-bootstrap status fetch completes.
This commit is contained in:
@@ -70,32 +70,38 @@ export const WorkStatusPrimaryGroup: React.FC<Props> = ({ sessionId, directory,
|
||||
|
||||
// A worktree that is still being created transiently looks dirty until its
|
||||
// setup commands and initial git reset finish. Those files are not changes
|
||||
// on the branch, so status is neither fetched nor displayed until the
|
||||
// bootstrap settles.
|
||||
// on the branch, so the changed-files readout stays hidden while the
|
||||
// bootstrap runs — and stays hidden until one fresh status fetch completes
|
||||
// afterwards, because the shared cache may still hold a snapshot captured
|
||||
// mid-creation (refresh hints fire while setup commands touch files) and
|
||||
// lifting the gate onto it would flash the transient state.
|
||||
const worktreeCreationPending = useWorktreeBootstrapPending(gitDirectory);
|
||||
const awaitingPostBootstrapStatusRef = React.useRef<string | null>(null);
|
||||
const [postBootstrapRefreshDirectory, setPostBootstrapRefreshDirectory] = React.useState<string | null>(null);
|
||||
const awaitingPostBootstrapStatus = postBootstrapRefreshDirectory !== null
|
||||
&& postBootstrapRefreshDirectory === gitDirectory;
|
||||
|
||||
// Warm the shared git cache through the background-network gate so the panel
|
||||
// never competes with the chat's own bootstrap traffic for sockets.
|
||||
React.useEffect(() => {
|
||||
if (!showRepository || !gitDirectory || !git) return;
|
||||
if (worktreeCreationPending) {
|
||||
awaitingPostBootstrapStatusRef.current = gitDirectory;
|
||||
setPostBootstrapRefreshDirectory(gitDirectory);
|
||||
return;
|
||||
}
|
||||
// Right after bootstrap the cache may still hold a status captured
|
||||
// mid-creation; force one fetch so the lifted gate reveals the real
|
||||
// (reset) working tree instead of the transient one.
|
||||
const finishedBootstrap = awaitingPostBootstrapStatusRef.current === gitDirectory;
|
||||
awaitingPostBootstrapStatusRef.current = null;
|
||||
void runBackgroundNetworkTask(async () => {
|
||||
if (finishedBootstrap) {
|
||||
await fetchStatus(gitDirectory, git, { silent: true });
|
||||
} else {
|
||||
await ensureStatus(gitDirectory, git);
|
||||
}
|
||||
});
|
||||
}, [gitDirectory, git, ensureStatus, fetchStatus, showRepository, worktreeCreationPending]);
|
||||
if (awaitingPostBootstrapStatus) {
|
||||
let cancelled = false;
|
||||
void runBackgroundNetworkTask(() => fetchStatus(gitDirectory, git, { silent: true }))
|
||||
.finally(() => {
|
||||
if (!cancelled) {
|
||||
setPostBootstrapRefreshDirectory((current) => (current === gitDirectory ? null : current));
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}
|
||||
void runBackgroundNetworkTask(() => ensureStatus(gitDirectory, git));
|
||||
}, [gitDirectory, git, ensureStatus, fetchStatus, showRepository, worktreeCreationPending, awaitingPostBootstrapStatus]);
|
||||
|
||||
// Own the live invalidation for the repository readout. The desktop
|
||||
// composer's changed-files row no longer renders, so this panel must not
|
||||
@@ -198,7 +204,7 @@ export const WorkStatusPrimaryGroup: React.FC<Props> = ({ sessionId, directory,
|
||||
// event is reset to an empty array too, and carries real content only on
|
||||
// revert. Git status is the one authoritative, already-cached answer.
|
||||
const changed = React.useMemo(() => {
|
||||
if (worktreeCreationPending) return null;
|
||||
if (worktreeCreationPending || awaitingPostBootstrapStatus) return null;
|
||||
const files = gitStatus?.files ?? [];
|
||||
if (files.length === 0) return null;
|
||||
const stats = gitStatus?.diffStats;
|
||||
@@ -211,7 +217,7 @@ export const WorkStatusPrimaryGroup: React.FC<Props> = ({ sessionId, directory,
|
||||
}
|
||||
}
|
||||
return { files: files.length, additions, deletions, hasStats: Boolean(stats) };
|
||||
}, [gitStatus?.files, gitStatus?.diffStats, worktreeCreationPending]);
|
||||
}, [gitStatus?.files, gitStatus?.diffStats, worktreeCreationPending, awaitingPostBootstrapStatus]);
|
||||
|
||||
const attentionReason = gitStatus?.attentionReason
|
||||
?? (gitStatus?.rebaseInProgress ? 'rebase' : null)
|
||||
|
||||
Reference in New Issue
Block a user