mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-10 02:15:02 +00:00
* feat(git): default review to all branch changes Keep the selected comparison stable while agents edit and commit so reviewing the complete result does not require switching scopes or interrupt unfinished comments. * test(git): release Windows checkout handles during cleanup Allow transient filesystem handles from subscription teardown to close before removing the test repository.
108 lines
3.4 KiB
TypeScript
108 lines
3.4 KiB
TypeScript
import type { QueryClient } from "@tanstack/react-query";
|
|
import type { CheckoutStatusResponse, CheckoutStatusUpdate } from "@getpaseo/protocol/messages";
|
|
import equal from "fast-deep-equal/es6";
|
|
import {
|
|
checkoutCommitsQueryKey,
|
|
checkoutPrStatusQueryKey,
|
|
checkoutStatusQueryKey,
|
|
invalidatePrPaneTimelineForCheckout,
|
|
} from "@/git/query-keys";
|
|
import { type CheckoutPrStatusPayload, normalizeCheckoutPrStatusPayload } from "@/git/pr-status";
|
|
import { resetDraftAgentCommandsForCheckout } from "@/hooks/agent-commands-query";
|
|
|
|
export type CheckoutStatusPayload = CheckoutStatusResponse["payload"];
|
|
export type { CheckoutPrStatusPayload } from "@/git/pr-status";
|
|
|
|
export interface CheckoutStatusClient {
|
|
getCheckoutStatus: (cwd: string) => Promise<CheckoutStatusPayload>;
|
|
}
|
|
|
|
export async function fetchCheckoutStatus({
|
|
client,
|
|
cwd,
|
|
}: {
|
|
client: CheckoutStatusClient;
|
|
serverId: string;
|
|
cwd: string;
|
|
}): Promise<CheckoutStatusPayload> {
|
|
const payload = await client.getCheckoutStatus(cwd);
|
|
return payload;
|
|
}
|
|
|
|
export async function ensureCheckoutStatus({
|
|
queryClient,
|
|
client,
|
|
serverId,
|
|
cwd,
|
|
}: {
|
|
queryClient: QueryClient;
|
|
client: CheckoutStatusClient;
|
|
serverId: string;
|
|
cwd: string;
|
|
}): Promise<CheckoutStatusPayload> {
|
|
return await queryClient.fetchQuery({
|
|
queryKey: checkoutStatusQueryKey(serverId, cwd),
|
|
queryFn: () => fetchCheckoutStatus({ client, serverId, cwd }),
|
|
staleTime: Infinity,
|
|
});
|
|
}
|
|
|
|
export function applyCheckoutStatusUpdateFromEvent({
|
|
queryClient,
|
|
serverId,
|
|
message,
|
|
}: {
|
|
queryClient: QueryClient;
|
|
serverId: string;
|
|
message: CheckoutStatusUpdate;
|
|
}): void {
|
|
const { payload } = message;
|
|
const prStatus = payload.prStatus
|
|
? normalizeCheckoutPrStatusPayload(payload.prStatus)
|
|
: undefined;
|
|
const cachePayload = prStatus ? { ...payload, prStatus } : payload;
|
|
const previousStatus = queryClient.getQueryData<CheckoutStatusPayload>(
|
|
checkoutStatusQueryKey(serverId, payload.cwd),
|
|
);
|
|
queryClient.setQueryData(checkoutStatusQueryKey(serverId, payload.cwd), cachePayload);
|
|
if (previousStatus?.currentBranch !== payload.currentBranch) {
|
|
void resetDraftAgentCommandsForCheckout(queryClient, { serverId, cwd: payload.cwd });
|
|
}
|
|
void queryClient.invalidateQueries({
|
|
queryKey: checkoutCommitsQueryKey(serverId, payload.cwd),
|
|
});
|
|
|
|
if (!prStatus) {
|
|
return;
|
|
}
|
|
|
|
const previous = queryClient.getQueryData<CheckoutPrStatusPayload>(
|
|
checkoutPrStatusQueryKey(serverId, prStatus.cwd),
|
|
);
|
|
queryClient.setQueryData(checkoutPrStatusQueryKey(serverId, prStatus.cwd), prStatus);
|
|
|
|
// The PR activity timeline has no push channel; mark it stale when the pushed PR status
|
|
// meaningfully changed. Active panes refetch immediately, evicted ones on next mount.
|
|
if (hasPrStatusChanged(previous, prStatus)) {
|
|
void invalidatePrPaneTimelineForCheckout(queryClient, { serverId, cwd: prStatus.cwd });
|
|
}
|
|
}
|
|
|
|
// requestId changes on every emission and carries no PR state.
|
|
function prStatusWithoutVolatileFields(
|
|
prStatus: CheckoutPrStatusPayload,
|
|
): Omit<CheckoutPrStatusPayload, "requestId"> {
|
|
const { requestId: _requestId, ...rest } = prStatus;
|
|
return rest;
|
|
}
|
|
|
|
function hasPrStatusChanged(
|
|
previous: CheckoutPrStatusPayload | undefined,
|
|
next: CheckoutPrStatusPayload,
|
|
): boolean {
|
|
if (!previous) {
|
|
return true;
|
|
}
|
|
return !equal(prStatusWithoutVolatileFields(previous), prStatusWithoutVolatileFields(next));
|
|
}
|