feat(worktrees): création intelligente (auto) + commit/push/promotion + grille agrandissable

- addWorktree résout la branche par dépôt (branchExists) : checkout si présente, suivi de origin/<b> si seulement remote, sinon création (-b) depuis la branche par défaut. Corrige le 'fatal: invalid reference' sur les groupes hétérogènes ; newBranch -> mode (déprécié, mappé en route).
- Nouvelles opérations git : commit (add -A), push (upstream auto), promotion « en principal » (la branche du worktree devient le checkout principal, sans merge ni conflit, ancienne branche conservée). Routes /worktrees/{commit,push,promote} auditées + GET /repos/:id/branches.
- Web : actions Commit/Push/Promouvoir sur WorktreeCard, sélecteur de branche de base (datalist) dans RepoSection et GroupSessionModal, agrandissement d'un terminal au choix dans TerminalGrid.
- Court-circuite la session de groupe quand aucun worktree n'a pu être créé (fini le masquage par « no resolvable worktree »).
- Tests : git.ts (branchExists/listBranches/commitAll/auto), worktree-manager (commit/promote/branches) ; acceptance P5 étend le scénario worktree de groupe sur branche neuve + commit + promotion.
This commit is contained in:
2026-06-22 19:55:45 +02:00
parent e84c6a7f6d
commit f4fb6c3b52
18 changed files with 732 additions and 62 deletions

View File

@@ -28,9 +28,9 @@ export interface CrossRepoResult {
/** Options de lancement d'une session de groupe (P6). */
export interface GroupFeatureOptions {
command: 'claude' | 'bash';
/** présent → crée le worktree de cette branche dans chaque repo puis relie ; absent → checkouts principaux. */
/** présent → crée/réutilise le worktree de cette branche dans chaque repo puis relie ; absent → checkouts principaux. */
branch?: string;
newBranch?: boolean;
/** branche de base d'une branche créée (défaut serveur : branche par défaut du dépôt). */
baseRef?: string;
}
@@ -157,7 +157,7 @@ export const useGroupsStore = defineStore('groups', () => {
try {
const res = await wt.createWorktree(repoId, {
branch,
newBranch: opts.newBranch ?? true,
mode: 'auto', // détecte créer / checkout / suivi remote selon l'existence par dépôt
...(opts.baseRef ? { baseRef: opts.baseRef } : {}),
startSession: null,
});
@@ -176,6 +176,11 @@ export const useGroupsStore = defineStore('groups', () => {
}),
);
}
// Mode feature : si AUCUN worktree n'a pu être créé/résolu, ne pas tenter la session (elle
// échouerait en « no resolvable worktree » et masquerait les vraies erreurs par dépôt).
if (opts.branch && worktreeResults.length > 0 && !worktreeResults.some((r) => r.status === 'ok')) {
return { worktreeResults, session: null, dirs: [], skipped: [] };
}
const res = await createGroupSession(groupId, {
command: opts.command,
...(opts.branch ? { branch: opts.branch } : {}),