import * as git from '../lib/git.js' import * as branch from '../lib/branch.js' import * as config from '../lib/config.js' import * as worktree from '../lib/worktree.js' import type { CleanupResult, CleanupOptions } from './types.js' export async function execute( opts: CleanupOptions, cwd?: string, ): Promise { try { // Must be on main or develop const currentBranch = await git.getCurrentBranch(cwd) const branchType = branch.detectBranchType(currentBranch) if (branchType !== 'main' && branchType !== 'develop') { return { success: false, analyzed: 0, permanent: 0, active: 0, deleted: [], skipped: [], error: `Must be on main or develop branch, currently on ${currentBranch}`, } } // Fetch all to get latest state await git.fetchAll(cwd) // Read config — resolve from the worktree cwd (= --workdir), NOT process.cwd(). const cfg = await config.readConfigForPlatform((await config.resolveConfigPath(cwd)) ?? undefined) // List worktrees const wts = await worktree.listWorktrees(cwd) // Filter permanent worktrees (main, develop) const permanent = wts.filter((w) => { return w.branch === cfg.git.branches.main || w.branch === cfg.git.branches.develop }).length // Filter active worktrees (not merged) const active: typeof wts = [] const merged: typeof wts = [] for (const w of wts) { // Skip permanent if (w.branch === cfg.git.branches.main || w.branch === cfg.git.branches.develop) { continue } // Check if merged const isMerged = await git.isMerged(w.branch, cfg.git.branches.main, cwd) if (isMerged) { merged.push(w) } else { active.push(w) } } // Process merged worktrees const deleted: string[] = [] const skipped: string[] = [] for (const w of merged) { if (opts.force) { if (!opts.dryRun) { try { await worktree.removeWorktree(w.path, cwd) deleted.push(w.branch) } catch { skipped.push(`${w.branch} (cleanup failed)`) } } else { deleted.push(w.branch) } } else { skipped.push(`${w.branch} (not deleted: force flag not set)`) } } // Prune if (!opts.dryRun) { await git.execGit(['worktree', 'prune'], cwd) } return { success: true, analyzed: wts.length, permanent, active: active.length, deleted, skipped, } } catch (err) { const message = err instanceof Error ? err.message : String(err) return { success: false, analyzed: 0, permanent: 0, active: 0, deleted: [], skipped: [], error: message, } } }