UNPKG

@shutootaki/gwm

Version:
112 lines 5.15 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useState, useEffect } from 'react'; import { Text, Box } from 'ink'; import { MultiSelectList } from './MultiSelectList.js'; import { getWorktreesWithStatus, removeWorktree, deleteLocalBranch, localBranchExists, hasUnmergedCommits, } from '../utils/index.js'; import { loadConfig } from '../config.js'; import { Notice } from './ui/Notice.js'; import { LoadingSpinner } from './ui/LoadingSpinner.js'; export const WorktreeRemove = ({ query = '', force = false, cleanBranch, }) => { const config = loadConfig(); const cleanMode = cleanBranch || config.clean_branch; const [worktrees, setWorktrees] = useState([]); const [error, setError] = useState(null); const [success, setSuccess] = useState([]); const [branchSuccess, setBranchSuccess] = useState([]); const [removing, setRemoving] = useState(false); useEffect(() => { const loadWorktrees = async () => { try { const allWorktrees = await getWorktreesWithStatus(); // メインworktreeを除外 const nonMainWorktrees = allWorktrees.filter((w) => !w.isMain); setWorktrees(nonMainWorktrees); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } }; loadWorktrees(); }, []); const handleConfirm = async (selectedItems) => { if (selectedItems.length === 0) { setError('No worktrees selected'); return; } setRemoving(true); const removedPaths = []; const errors = []; const removedBranches = new Set(); for (const item of selectedItems) { try { removeWorktree(item.value, force); removedPaths.push(item.value); const wt = worktrees.find((w) => w.path === item.value); if (wt) removedBranches.add(wt.branch); } catch (err) { const errorMsg = err instanceof Error ? err.message : 'Unknown error'; errors.push(`${item.value}: ${errorMsg}`); } } // ブランチクリーンアップ処理 if (removedBranches.size > 0 && cleanMode !== 'never') { const remaining = await getWorktreesWithStatus(); const candidateBranches = Array.from(removedBranches).filter((br) => !remaining.some((w) => w.branch === br) && localBranchExists(br)); if (cleanMode === 'auto') { const deleted = []; candidateBranches.forEach((br) => { const unmerged = hasUnmergedCommits(br); try { deleteLocalBranch(br, unmerged); deleted.push(br + (unmerged ? ' (forced)' : '')); } catch (e) { errors.push(`branch ${br}: ${e instanceof Error ? e.message : e}`); } }); if (deleted.length > 0) { setBranchSuccess(deleted); } } // "ask" モードは未実装。スキップして注意喚起 if (cleanMode === 'ask') { if (candidateBranches.length > 0) { errors.push(`Branches ${candidateBranches.join(', ')} remain locally. Re-run with --clean-branch=auto to remove.`); } } } if (errors.length > 0) { setError(errors.join('\n')); } if (removedPaths.length > 0) { setSuccess(removedPaths); } setRemoving(false); }; const handleCancel = () => { setError('Cancelled'); }; if (success.length > 0) { return (_jsx(Notice, { variant: "success", title: `Successfully removed ${success.length} worktree(s)`, messages: [ ...success.map((p) => `✓ ${p}`), ...branchSuccess.map((b) => `✓ cleaned branch ${b}`), ] })); } if (error) { return _jsx(Notice, { variant: "error", title: "Error", messages: error }); } if (removing) { return _jsx(LoadingSpinner, { label: "Removing worktrees...", color: "yellow" }); } if (worktrees.length === 0) { return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", padding: 1, children: [_jsx(Text, { color: "gray", bold: true, children: "No removable worktrees found" }), _jsx(Text, { color: "gray", children: "Main worktree cannot be removed" })] })); } const items = worktrees.map((worktree) => ({ label: `${worktree.branch.padEnd(30)} ${worktree.path}`, value: worktree.path, })); return (_jsx(MultiSelectList, { items: items, onConfirm: handleConfirm, onCancel: handleCancel, title: `Remove worktrees${force ? ' (force mode)' : ''}`, placeholder: `Select worktrees to remove${force ? ' (force mode)' : ''}...`, initialQuery: query })); }; //# sourceMappingURL=WorktreeRemove.js.map