feat(worktrees): démarrer une session sur la branche principale ou tout worktree
Ajoute le choix « créer un worktree OU bosser sur la branche principale » au moment de démarrer le travail, sur deux surfaces : - bouton « Démarrer » (claude/bash) sur chaque WorktreeCard, y compris le checkout principal (badge « principal ») — comblait un manque : impossible jusqu'ici de lancer une session sur un worktree existant depuis le dashboard ; - toggle de mode (Worktree / Branche principale) dans le formulaire d'entête de RepoSection. Option git « créer & basculer » : nouvel endpoint POST /api/v1/repos/:id/session qui lance UNE session dans le checkout principal (repo.path), avec création ou bascule de branche optionnelle (git switch[-c]) — refusée en 409 si l'arbre est sale. Pas de hooks ni de pré-trust (c'est le dépôt réel de l'utilisateur). - shared : type additif StartRepoSessionRequest. - server : git.switchBranch + WorktreeManager.startMainSession + route. - web : store worktrees.startMainSession, UI WorktreeCard/RepoSection, i18n fr/en. - tests : +5 unitaires (switchBranch, startMainSession) ; acceptance-p3 étendue.
This commit is contained in:
@@ -26,6 +26,30 @@
|
||||
</RouterLink>
|
||||
<span v-if="worktree.sessions.length === 0" class="text-xs text-zinc-600">{{ t('worktrees.noSession') }}</span>
|
||||
|
||||
<!-- lancement d'une session sur ce worktree ; carte principale = bosser sur la branche principale -->
|
||||
<button v-if="hasLiveSession && !showLauncher" class="btn text-xs" @click="showLauncher = true">+ {{ t('worktrees.start') }}</button>
|
||||
<form v-if="!hasLiveSession || showLauncher" class="flex flex-wrap items-center gap-1" @submit.prevent="onStart">
|
||||
<template v-if="worktree.isMain">
|
||||
<select v-model="branchMode" class="input text-xs" :aria-label="t('worktrees.branchModeLabel')">
|
||||
<option value="current">{{ t('worktrees.currentBranch') }}</option>
|
||||
<option value="new">{{ t('worktrees.newBranchOpt') }}</option>
|
||||
</select>
|
||||
<input v-if="branchMode === 'new'" v-model="newBranchName" class="input w-32 font-mono text-xs" placeholder="feature/…" />
|
||||
</template>
|
||||
<select v-model="startCommand" class="input text-xs" :aria-label="t('worktrees.commandLabel')">
|
||||
<option value="claude">claude</option>
|
||||
<option value="bash">bash</option>
|
||||
</select>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-primary text-xs"
|
||||
:disabled="starting || (worktree.isMain && branchMode === 'new' && newBranchName.trim() === '')"
|
||||
>
|
||||
{{ starting ? t('worktrees.starting') : t('worktrees.start') }}
|
||||
</button>
|
||||
</form>
|
||||
<span v-if="startError" class="text-xs text-amber-400">{{ startError }}</span>
|
||||
|
||||
<div v-if="!worktree.isMain" class="ml-auto flex items-center gap-2">
|
||||
<template v-if="confirming">
|
||||
<span v-if="error" class="text-xs text-amber-400">{{ error }}</span>
|
||||
@@ -74,6 +98,39 @@ const forceNeeded = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const busy = ref(false);
|
||||
|
||||
// --- lancement de session sur ce worktree ---
|
||||
const hasLiveSession = computed(() => props.worktree.sessions.some((s) => liveSession(s).live));
|
||||
const showLauncher = ref(false);
|
||||
const startCommand = ref<'claude' | 'bash'>('claude');
|
||||
const branchMode = ref<'current' | 'new'>('current'); // carte principale uniquement
|
||||
const newBranchName = ref('');
|
||||
const starting = ref(false);
|
||||
const startError = ref<string | null>(null);
|
||||
|
||||
async function onStart(): Promise<void> {
|
||||
if (starting.value) return;
|
||||
starting.value = true;
|
||||
startError.value = null;
|
||||
try {
|
||||
if (props.worktree.isMain && branchMode.value === 'new') {
|
||||
// bosser sur la branche principale en créant d'abord une branche dans le checkout principal.
|
||||
await store.startMainSession(props.worktree.repoId, { command: startCommand.value, branch: newBranchName.value.trim(), newBranch: true });
|
||||
} else {
|
||||
// worktree existant (ou branche principale actuelle) : session directe dans son cwd.
|
||||
await sessions.createSession(props.worktree.path, startCommand.value);
|
||||
}
|
||||
// resynchronise les worktrees du repo pour que la nouvelle session apparaisse sur la carte.
|
||||
await store.refreshRepoWorktrees(props.worktree.repoId);
|
||||
showLauncher.value = false;
|
||||
newBranchName.value = '';
|
||||
branchMode.value = 'current';
|
||||
} catch (err) {
|
||||
startError.value = err instanceof Error ? err.message : String(err);
|
||||
} finally {
|
||||
starting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const branchLabel = computed(() =>
|
||||
props.worktree.branch ?? (props.worktree.detached ? `${t('worktrees.detached')} ${props.worktree.head.slice(0, 7)}` : '—'),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user