Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ Each session stays in its issue scope. If Session A discovers a bug in Session B
3. Recent Completed >30? → Archive oldest batch (verify each issue is CLOSED before archiving)
4. MEMORY.md >150 lines? → Trim with `/memory-cleanup`
5. Never use range notation (`#1534-#1545`) in archive refs — enumerate individual issue numbers
6. Stale worktrees? → Run `scripts/cleanup-worktrees.sh --dry-run` and review, then `scripts/cleanup-worktrees.sh` to remove closed-issue worktrees

### Multi-Agent Safety

Expand Down
116 changes: 116 additions & 0 deletions scripts/cleanup-worktrees.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env bash
# AutoBot - AI-Powered Automation Platform
# Copyright (c) 2025 mrveiss
# Author: mrveiss
#
# Cleanup stale git worktrees under .worktrees/ whose GitHub issues are closed.
# Usage: scripts/cleanup-worktrees.sh [--dry-run]

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
WORKTREES_DIR="${REPO_ROOT}/.worktrees"
DRY_RUN=false

for arg in "$@"; do
case "$arg" in
--dry-run)
DRY_RUN=true
;;
--help|-h)
echo "Usage: $0 [--dry-run]"
echo ""
echo "Removes git worktrees under .worktrees/ whose GitHub issues are closed."
echo ""
echo "Options:"
echo " --dry-run Show what would be cleaned without making changes"
echo " --help Show this help message"
exit 0
;;
*)
echo "Error: unknown argument '$arg'" >&2
echo "Run '$0 --help' for usage." >&2
exit 1
;;
esac
done

if ! command -v gh &>/dev/null; then
echo "Error: GitHub CLI (gh) is required but not found." >&2
exit 1
fi

if [ ! -d "$WORKTREES_DIR" ]; then
echo "No .worktrees/ directory found. Nothing to clean."
exit 0
fi

removed=0
skipped=0
errors=0

echo "Scanning worktrees in ${WORKTREES_DIR}..."
if $DRY_RUN; then
echo "(dry-run mode -- no changes will be made)"
fi
echo ""

for worktree_path in "$WORKTREES_DIR"/*/; do
# Skip if glob matched nothing
[ -d "$worktree_path" ] || continue

dir_name="$(basename "$worktree_path")"

# Extract issue number from directory name (e.g., issue-2467 -> 2467)
issue_number=""
if [[ "$dir_name" =~ issue-([0-9]+) ]]; then
issue_number="${BASH_REMATCH[1]}"
else
echo " SKIP ${dir_name} -- cannot extract issue number"
skipped=$((skipped + 1))
continue
fi

# Check issue state via GitHub CLI
issue_state=""
issue_state=$(gh issue view "$issue_number" --json state --jq '.state' 2>/dev/null) || true

if [ -z "$issue_state" ]; then
echo " ERROR ${dir_name} -- could not fetch state for issue #${issue_number}"
errors=$((errors + 1))
continue
fi

if [ "$issue_state" = "CLOSED" ]; then
if $DRY_RUN; then
echo " WOULD REMOVE ${dir_name} (issue #${issue_number} is closed)"
else
echo " REMOVING ${dir_name} (issue #${issue_number} is closed)"
if git -C "$REPO_ROOT" worktree remove --force "$worktree_path" 2>/dev/null; then
# Also delete the local branch if it exists
branch_name="fix/issue-${issue_number}"
git -C "$REPO_ROOT" branch -D "$branch_name" 2>/dev/null || true
else
echo " WARNING: git worktree remove failed; attempting manual cleanup"
rm -rf "$worktree_path"
git -C "$REPO_ROOT" worktree prune
fi
fi
removed=$((removed + 1))
else
echo " KEEP ${dir_name} (issue #${issue_number} is ${issue_state})"
skipped=$((skipped + 1))
fi
done

echo ""
echo "--- Summary ---"
if $DRY_RUN; then
echo "Would remove: ${removed}"
else
echo "Removed: ${removed}"
fi
echo "Kept: ${skipped}"
if [ "$errors" -gt 0 ]; then
echo "Errors: ${errors}"
fi
Loading