feat: add mac-optimizer skill (92) — Claude Code only
macOS system health toolkit with 5 audit modules (packages, environment, security, cleanup, resources) and cleanup executor. Fixed bugs from review: - Replace GNU timeout with perl alarm (macOS compatible) - Remove Linux-only ps --sort flag, use portable sort - Add JSON escaping to all audit scripts - Remove redundant classify_size branch Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
169
custom-skills/92-mac-optimizer/scripts/cleanup_execute.sh
Executable file
169
custom-skills/92-mac-optimizer/scripts/cleanup_execute.sh
Executable file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env bash
|
||||
# cleanup_execute.sh — Execute cleanup actions on macOS
|
||||
# Usage: cleanup_execute.sh [--dry-run|--execute] <target> [<target>...]
|
||||
# Targets: user-logs, user-caches, brew-cache, npm-cache, pip-cache,
|
||||
# xcode-derived, xcode-archives, ios-support, docker, trash
|
||||
set -euo pipefail
|
||||
|
||||
MODE="dry-run"
|
||||
TARGETS=()
|
||||
BACKUP_DIR="${BACKUP_DIR:-$HOME/.config/mac-optimizer-backups}"
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [--dry-run|--execute] <target> [<target>...]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --dry-run Show what would be deleted (default)"
|
||||
echo " --execute Actually perform cleanup"
|
||||
echo ""
|
||||
echo "Targets:"
|
||||
echo " user-logs ~/Library/Logs/"
|
||||
echo " user-caches ~/Library/Caches/"
|
||||
echo " brew-cache Homebrew download cache"
|
||||
echo " npm-cache npm cache"
|
||||
echo " pip-cache pip cache"
|
||||
echo " xcode-derived Xcode DerivedData"
|
||||
echo " xcode-archives Xcode Archives"
|
||||
echo " ios-support iOS DeviceSupport files"
|
||||
echo " docker Docker system prune"
|
||||
echo " trash Empty Trash"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse args
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry-run) MODE="dry-run"; shift ;;
|
||||
--execute) MODE="execute"; shift ;;
|
||||
--help|-h) usage ;;
|
||||
*) TARGETS+=("$1"); shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ${#TARGETS[@]} -eq 0 ]; then
|
||||
echo "Error: No targets specified"
|
||||
usage
|
||||
fi
|
||||
|
||||
log_action() {
|
||||
local target="$1" action="$2" size="$3"
|
||||
echo "[${MODE}] ${target}: ${action} (${size})"
|
||||
}
|
||||
|
||||
clean_dir() {
|
||||
local name="$1" path="$2"
|
||||
if [ ! -d "$path" ]; then
|
||||
echo "[skip] ${name}: directory not found (${path})"
|
||||
return
|
||||
fi
|
||||
local size=$(du -sh "$path" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$MODE" = "dry-run" ]; then
|
||||
log_action "$name" "would remove contents of ${path}" "$size"
|
||||
else
|
||||
log_action "$name" "removing contents of ${path}" "$size"
|
||||
find "$path" -mindepth 1 -delete 2>/dev/null || {
|
||||
# Fallback: remove what we can
|
||||
find "$path" -mindepth 1 -maxdepth 1 -exec rm -rf {} + 2>/dev/null || true
|
||||
}
|
||||
echo "[done] ${name}: cleaned"
|
||||
fi
|
||||
}
|
||||
|
||||
for target in "${TARGETS[@]}"; do
|
||||
case "$target" in
|
||||
user-logs)
|
||||
clean_dir "User Logs" "$HOME/Library/Logs"
|
||||
;;
|
||||
user-caches)
|
||||
clean_dir "User Caches" "$HOME/Library/Caches"
|
||||
;;
|
||||
brew-cache)
|
||||
if command -v brew &>/dev/null; then
|
||||
brew_cache=$(brew --cache 2>/dev/null || echo "")
|
||||
if [ -n "$brew_cache" ]; then
|
||||
size=$(du -sh "$brew_cache" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$MODE" = "dry-run" ]; then
|
||||
log_action "Homebrew Cache" "would run brew cleanup" "$size"
|
||||
else
|
||||
log_action "Homebrew Cache" "running brew cleanup" "$size"
|
||||
brew cleanup --prune=0 2>/dev/null || true
|
||||
echo "[done] Homebrew Cache: cleaned"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "[skip] brew-cache: Homebrew not installed"
|
||||
fi
|
||||
;;
|
||||
npm-cache)
|
||||
if command -v npm &>/dev/null; then
|
||||
npm_cache="$HOME/.npm/_cacache"
|
||||
if [ -d "$npm_cache" ]; then
|
||||
size=$(du -sh "$npm_cache" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$MODE" = "dry-run" ]; then
|
||||
log_action "npm Cache" "would run npm cache clean --force" "$size"
|
||||
else
|
||||
log_action "npm Cache" "running npm cache clean" "$size"
|
||||
npm cache clean --force 2>/dev/null || true
|
||||
echo "[done] npm Cache: cleaned"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "[skip] npm-cache: npm not installed"
|
||||
fi
|
||||
;;
|
||||
pip-cache)
|
||||
pip_cache="$HOME/Library/Caches/pip"
|
||||
if [ -d "$pip_cache" ]; then
|
||||
size=$(du -sh "$pip_cache" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$MODE" = "dry-run" ]; then
|
||||
log_action "pip Cache" "would run pip cache purge" "$size"
|
||||
else
|
||||
log_action "pip Cache" "running pip cache purge" "$size"
|
||||
pip3 cache purge 2>/dev/null || pip cache purge 2>/dev/null || true
|
||||
echo "[done] pip Cache: cleaned"
|
||||
fi
|
||||
else
|
||||
echo "[skip] pip-cache: no pip cache found"
|
||||
fi
|
||||
;;
|
||||
xcode-derived)
|
||||
clean_dir "Xcode DerivedData" "$HOME/Library/Developer/Xcode/DerivedData"
|
||||
;;
|
||||
xcode-archives)
|
||||
clean_dir "Xcode Archives" "$HOME/Library/Developer/Xcode/Archives"
|
||||
;;
|
||||
ios-support)
|
||||
clean_dir "iOS DeviceSupport" "$HOME/Library/Developer/Xcode/iOS DeviceSupport"
|
||||
;;
|
||||
docker)
|
||||
if command -v docker &>/dev/null; then
|
||||
if [ "$MODE" = "dry-run" ]; then
|
||||
echo "[dry-run] Docker: would run docker system prune"
|
||||
docker system df 2>/dev/null || echo " (Docker not running)"
|
||||
else
|
||||
echo "[execute] Docker: running docker system prune -f"
|
||||
docker system prune -f 2>/dev/null || echo " Docker prune failed (is Docker running?)"
|
||||
fi
|
||||
else
|
||||
echo "[skip] docker: Docker not installed"
|
||||
fi
|
||||
;;
|
||||
trash)
|
||||
trash_dir="$HOME/.Trash"
|
||||
if [ -d "$trash_dir" ]; then
|
||||
size=$(du -sh "$trash_dir" 2>/dev/null | awk '{print $1}')
|
||||
if [ "$MODE" = "dry-run" ]; then
|
||||
log_action "Trash" "would empty Trash" "$size"
|
||||
else
|
||||
log_action "Trash" "emptying Trash" "$size"
|
||||
rm -rf "$trash_dir"/* 2>/dev/null || true
|
||||
rm -rf "$trash_dir"/.[!.]* 2>/dev/null || true
|
||||
echo "[done] Trash: emptied"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "[error] Unknown target: ${target}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
Reference in New Issue
Block a user