feat: support multi-run for non-Git projects
Creates non-Git multi-runs in the same project directory Shows concise footer info when worktree isolation is unavailable Displays default model variants with a friendly label
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { useGitStore, useGitBranches, useGitLoadingBranches } from '@/stores/useGitStore';
|
||||
import { useGitStore, useGitBranches, useGitLoadingBranches, useGitLoadingStatus, useIsGitRepo } from '@/stores/useGitStore';
|
||||
import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs';
|
||||
import { getRootBranch } from '@/lib/worktrees/worktreeStatus';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
@@ -53,15 +53,26 @@ export interface BranchSelectorState {
|
||||
export function useBranchOptions(directory: string | null): BranchSelectorState {
|
||||
const { git } = useRuntimeAPIs();
|
||||
const branches = useGitBranches(directory);
|
||||
const isLoading = useGitLoadingBranches(directory);
|
||||
const isGitRepo = useIsGitRepo(directory);
|
||||
const isLoadingStatus = useGitLoadingStatus(directory);
|
||||
const isLoadingBranches = useGitLoadingBranches(directory);
|
||||
const fetchBranches = useGitStore((state) => state.fetchBranches);
|
||||
const fetchStatus = useGitStore((state) => state.fetchStatus);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!directory || !git || isGitRepo !== null || isLoadingStatus) return;
|
||||
void fetchStatus(directory, git, { silent: true });
|
||||
}, [directory, git, fetchStatus, isGitRepo, isLoadingStatus]);
|
||||
|
||||
// Fetch branches if not cached
|
||||
React.useEffect(() => {
|
||||
if (!directory || !git) return;
|
||||
if (isGitRepo !== true) return;
|
||||
if (branches?.all) return; // Already cached
|
||||
void fetchBranches(directory, git);
|
||||
}, [directory, git, branches?.all, fetchBranches]);
|
||||
}, [directory, git, isGitRepo, branches?.all, fetchBranches]);
|
||||
|
||||
const isLoading = isLoadingStatus || (isGitRepo === true && isLoadingBranches);
|
||||
|
||||
// Compute local and remote branch lists (same as NewWorktreeDialog)
|
||||
const localBranches = React.useMemo(() => {
|
||||
@@ -82,10 +93,10 @@ export function useBranchOptions(directory: string | null): BranchSelectorState
|
||||
// isGitRepository: true if we got branches, false if fetch returned empty, null if not yet loaded
|
||||
const isGitRepository = React.useMemo<boolean | null>(() => {
|
||||
if (!directory) return null;
|
||||
if (isGitRepo !== null) return isGitRepo;
|
||||
if (isLoading) return null;
|
||||
if (!branches) return null;
|
||||
return Boolean(branches.all);
|
||||
}, [directory, isLoading, branches]);
|
||||
return branches?.all ? true : null;
|
||||
}, [directory, isLoading, branches, isGitRepo]);
|
||||
|
||||
return { localBranches, remoteBranches, isLoading, isGitRepository };
|
||||
}
|
||||
|
||||
@@ -560,7 +560,11 @@ export const ModelMultiSelect: React.FC<ModelMultiSelectProps> = ({
|
||||
variantValue === DEFAULT_VARIANT_VALUE ? 'text-muted-foreground' : 'text-[color:var(--status-info)]'
|
||||
)}
|
||||
/>
|
||||
<SelectValue placeholder={t('multirun.modelMultiSelect.variant.placeholder')} />
|
||||
<SelectValue placeholder={t('multirun.modelMultiSelect.variant.placeholder')}>
|
||||
{(value) => value === DEFAULT_VARIANT_VALUE
|
||||
? t('multirun.modelMultiSelect.variant.default')
|
||||
: value}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent fitContent>
|
||||
<SelectItem value={DEFAULT_VARIANT_VALUE} className="pr-2 [&>span:first-child]:hidden">
|
||||
|
||||
@@ -587,7 +587,12 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
||||
};
|
||||
|
||||
const isValid = Boolean(
|
||||
name.trim() && prompt.trim() && selectedModels.length >= 2 && worktreeBaseBranch && isGitRepository && !isLoadingWorktreeBaseBranches
|
||||
name.trim() &&
|
||||
prompt.trim() &&
|
||||
selectedModels.length >= 2 &&
|
||||
selectedProjectDirectory &&
|
||||
!isLoadingWorktreeBaseBranches &&
|
||||
(isGitRepository === false || (isGitRepository === true && worktreeBaseBranch))
|
||||
);
|
||||
|
||||
const configuredSetupCount = setupCommands.filter(cmd => cmd.trim()).length;
|
||||
@@ -929,6 +934,12 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
||||
{/* ── Fixed footer ── */}
|
||||
<div className="shrink-0 px-4 sm:px-6 py-3">
|
||||
<div className="mx-auto w-full max-w-2xl flex items-center justify-end gap-2">
|
||||
{isGitRepository === false ? (
|
||||
<div className="mr-auto flex min-w-0 items-center gap-1.5 typography-micro text-muted-foreground">
|
||||
<Icon name="information" className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="truncate">{t('multirun.launcher.project.gitRequired')}</span>
|
||||
</div>
|
||||
) : null}
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
|
||||
Reference in New Issue
Block a user