refactor: Improve all git operations, add stash support, add improved pull request flow, add worktree file copy options, address code review comments, add cherry pick options

This commit is contained in:
gsxdsm
2026-02-17 22:02:58 -08:00
parent f4e87d4c25
commit 9af63bc1ef
89 changed files with 6811 additions and 351 deletions

View File

@@ -9,6 +9,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { getElectronAPI } from '@/lib/electron';
import { queryKeys } from '@/lib/query-keys';
import { toast } from 'sonner';
import type { Feature } from '@/store/app-store';
/**
* Start running a feature in auto mode
@@ -159,9 +160,26 @@ export function useVerifyFeature(projectPath: string) {
if (!result.success) {
throw new Error(result.error || 'Failed to verify feature');
}
return result;
return { ...result, featureId };
},
onSuccess: () => {
onSuccess: (data) => {
// If verification passed, optimistically update React Query cache
// to move the feature to 'verified' status immediately
if (data.passes) {
const previousFeatures = queryClient.getQueryData<Feature[]>(
queryKeys.features.all(projectPath)
);
if (previousFeatures) {
queryClient.setQueryData<Feature[]>(
queryKeys.features.all(projectPath),
previousFeatures.map((f) =>
f.id === data.featureId
? { ...f, status: 'verified' as const, justFinishedAt: undefined }
: f
)
);
}
}
queryClient.invalidateQueries({ queryKey: queryKeys.features.all(projectPath) });
},
onError: (error: Error) => {

View File

@@ -126,10 +126,18 @@ export function usePushWorktree() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ worktreePath, force }: { worktreePath: string; force?: boolean }) => {
mutationFn: async ({
worktreePath,
force,
remote,
}: {
worktreePath: string;
force?: boolean;
remote?: string;
}) => {
const api = getElectronAPI();
if (!api.worktree) throw new Error('Worktree API not available');
const result = await api.worktree.push(worktreePath, force);
const result = await api.worktree.push(worktreePath, force, remote);
if (!result.success) {
throw new Error(result.error || 'Failed to push changes');
}
@@ -156,10 +164,10 @@ export function usePullWorktree() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (worktreePath: string) => {
mutationFn: async ({ worktreePath, remote }: { worktreePath: string; remote?: string }) => {
const api = getElectronAPI();
if (!api.worktree) throw new Error('Worktree API not available');
const result = await api.worktree.pull(worktreePath);
const result = await api.worktree.pull(worktreePath, remote);
if (!result.success) {
throw new Error(result.error || 'Failed to pull changes');
}
@@ -283,17 +291,6 @@ export function useMergeWorktree(projectPath: string) {
});
}
/**
* Result from the switch branch API call
*/
interface SwitchBranchResult {
previousBranch: string;
currentBranch: string;
message: string;
hasConflicts?: boolean;
stashedChanges?: boolean;
}
/**
* Switch to a different branch
*
@@ -316,14 +313,17 @@ export function useSwitchBranch(options?: {
}: {
worktreePath: string;
branchName: string;
}): Promise<SwitchBranchResult> => {
}) => {
const api = getElectronAPI();
if (!api.worktree) throw new Error('Worktree API not available');
const result = await api.worktree.switchBranch(worktreePath, branchName);
if (!result.success) {
throw new Error(result.error || 'Failed to switch branch');
}
return result.result as SwitchBranchResult;
if (!result.result) {
throw new Error('Switch branch returned no result');
}
return result.result;
},
onSuccess: (data, variables) => {
queryClient.invalidateQueries({ queryKey: ['worktrees'] });
@@ -388,6 +388,36 @@ export function useCheckoutBranch() {
});
}
/**
* Generate a PR title and description from branch diff
*
* @returns Mutation for generating a PR description
*/
export function useGeneratePRDescription() {
return useMutation({
mutationFn: async ({
worktreePath,
baseBranch,
}: {
worktreePath: string;
baseBranch?: string;
}) => {
const api = getElectronAPI();
if (!api.worktree) throw new Error('Worktree API not available');
const result = await api.worktree.generatePRDescription(worktreePath, baseBranch);
if (!result.success) {
throw new Error(result.error || 'Failed to generate PR description');
}
return { title: result.title ?? '', body: result.body ?? '' };
},
onError: (error: Error) => {
toast.error('Failed to generate PR description', {
description: error.message,
});
},
});
}
/**
* Generate a commit message from git diff
*