feat: add project-hygiene plugin
Post-task cleanup hook that runs after Claude completes work: - Deletes temp files (*.tmp, *.bak, __pycache__, etc.) - Warns about unexpected files in project root - Identifies orphaned files (test_*, debug_*, *_backup.*) - Logs actions to .dev/logs/ - Supports project-local config via .hygiene.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,12 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Sprint planning and project management with Gitea and Wiki.js integration",
|
"description": "Sprint planning and project management with Gitea and Wiki.js integration",
|
||||||
"source": "./../../projman"
|
"source": "./../../projman"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "project-hygiene",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Post-task cleanup hook that removes temp files, warns about unexpected root files, and manages orphans",
|
||||||
|
"source": "./../../project-hygiene"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
22
project-hygiene/.claude-plugin/plugin.json
Normal file
22
project-hygiene/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "project-hygiene",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Post-task cleanup hook that removes temp files, warns about unexpected root files, and manages orphaned supporting files",
|
||||||
|
"author": {
|
||||||
|
"name": "Bandit Labs",
|
||||||
|
"email": "dev@banditlabs.io"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": ["cleanup", "hygiene", "automation", "hooks", "maintenance"],
|
||||||
|
"repository": "https://github.com/bandit-labs/project-hygiene",
|
||||||
|
"config": {
|
||||||
|
"default_shell": "bash",
|
||||||
|
"environment": {
|
||||||
|
"PLUGIN_HOME": "${CLAUDE_PLUGIN_ROOT}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"file_access": ["read", "write"],
|
||||||
|
"shell_access": true
|
||||||
|
}
|
||||||
|
}
|
||||||
135
project-hygiene/README.md
Normal file
135
project-hygiene/README.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# project-hygiene
|
||||||
|
|
||||||
|
Post-task cleanup hook plugin for Claude Code. Automatically cleans up temporary files, warns about unexpected files in the project root, and manages orphaned supporting files after task completion.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Delete temp files**: Removes `*.tmp`, `*.bak`, `__pycache__`, `.pytest_cache`, and other common temporary patterns
|
||||||
|
- **Root file warnings**: Alerts when unexpected files appear in project root
|
||||||
|
- **Orphan detection**: Identifies `test_*`, `debug_*`, `*_backup.*` and similar files that may have been left behind
|
||||||
|
- **Cleanup logging**: Records all actions to `.dev/logs/`
|
||||||
|
- **Configurable**: Project-local `.hygiene.json` for custom rules
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Add to your Claude Code configuration or install from the marketplace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude plugin install project-hygiene
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The plugin registers a `task-completed` hook that runs after Claude completes any task. It:
|
||||||
|
|
||||||
|
1. Scans for and deletes known temporary file patterns
|
||||||
|
2. Removes temporary directories (`__pycache__`, `.pytest_cache`, etc.)
|
||||||
|
3. Checks for unexpected files in project root and warns
|
||||||
|
4. Identifies orphaned supporting files (test files, debug scripts, backups)
|
||||||
|
5. Optionally moves orphans to `.dev/scratch/` for review
|
||||||
|
6. Logs all actions to `.dev/logs/hygiene-TIMESTAMP.log`
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Create `.hygiene.json` in your project root to customize behavior:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"move_orphans": true,
|
||||||
|
"allowed_root_files": [
|
||||||
|
"custom-config.yaml",
|
||||||
|
"my-script.sh"
|
||||||
|
],
|
||||||
|
"temp_patterns": [
|
||||||
|
"*.cache",
|
||||||
|
"*.pid"
|
||||||
|
],
|
||||||
|
"ignore_patterns": [
|
||||||
|
"important_test_*.py",
|
||||||
|
"keep_this_backup.*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
| Option | Type | Default | Description |
|
||||||
|
|--------|------|---------|-------------|
|
||||||
|
| `move_orphans` | boolean | `false` | Move orphaned files to `.dev/scratch/` instead of just warning |
|
||||||
|
| `allowed_root_files` | array | (see below) | Additional files allowed in project root |
|
||||||
|
| `temp_patterns` | array | `[]` | Additional temp file patterns to delete |
|
||||||
|
| `ignore_patterns` | array | `[]` | Files to never touch during cleanup |
|
||||||
|
|
||||||
|
### Default Allowed Root Files
|
||||||
|
|
||||||
|
The plugin recognizes common project files in root:
|
||||||
|
- Git files: `.git`, `.gitignore`, `.gitattributes`
|
||||||
|
- Config: `.editorconfig`, `.env*`, `.nvmrc`, etc.
|
||||||
|
- Documentation: `README.md`, `LICENSE`, `CHANGELOG.md`, `CLAUDE.md`
|
||||||
|
- Package managers: `package.json`, `requirements.txt`, `Cargo.toml`, `go.mod`, etc.
|
||||||
|
- Build configs: `Makefile`, `Dockerfile`, `docker-compose.yml`, `tsconfig.json`, etc.
|
||||||
|
|
||||||
|
### Default Temp Patterns
|
||||||
|
|
||||||
|
Automatically cleaned:
|
||||||
|
- `*.tmp`, `*.bak`, `*.swp`, `*.swo`, `*~`
|
||||||
|
- `.DS_Store`, `Thumbs.db`
|
||||||
|
- `*.log`, `*.orig`, `*.pyc`, `*.pyo`
|
||||||
|
|
||||||
|
### Default Temp Directories
|
||||||
|
|
||||||
|
Automatically removed:
|
||||||
|
- `__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`
|
||||||
|
- `node_modules/.cache`, `.next/cache`, `.nuxt/.cache`, `.turbo`
|
||||||
|
- `*.egg-info`, `.eggs`
|
||||||
|
|
||||||
|
### Orphan Patterns
|
||||||
|
|
||||||
|
Files flagged as orphans:
|
||||||
|
- `test_*.py` (standalone test files)
|
||||||
|
- `debug_*` (debug scripts)
|
||||||
|
- `*_backup.*`, `*_old.*`, `*_bak.*`, `*.backup`
|
||||||
|
- `temp_*`, `tmp_*`
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
After each task, you'll see output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
[14:32:15] Starting project hygiene cleanup...
|
||||||
|
|
||||||
|
[14:32:15] Cleaning temp files...
|
||||||
|
[14:32:15] DELETED: ./src/__pycache__/utils.cpython-311.pyc
|
||||||
|
[14:32:15] DELETED: ./temp.bak
|
||||||
|
|
||||||
|
[14:32:15] Cleaning temp directories...
|
||||||
|
[14:32:15] DELETED DIR: ./src/__pycache__
|
||||||
|
|
||||||
|
[14:32:15] Checking root files...
|
||||||
|
[14:32:15] WARNING: Unexpected root file: random_notes.txt
|
||||||
|
|
||||||
|
[14:32:15] Checking for orphaned files...
|
||||||
|
[14:32:15] ORPHAN: ./test_scratch.py
|
||||||
|
[14:32:15] ORPHAN: ./debug_api.py
|
||||||
|
|
||||||
|
=== Cleanup Summary ===
|
||||||
|
Deleted: 3 items
|
||||||
|
Warnings: 1 unexpected root files
|
||||||
|
Orphans: 2 files
|
||||||
|
Log file: .dev/logs/hygiene-20250110-143215.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
.dev/
|
||||||
|
├── logs/
|
||||||
|
│ └── hygiene-YYYYMMDD-HHMMSS.log
|
||||||
|
└── scratch/ # (if move_orphans enabled)
|
||||||
|
└── debug_api.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Bash 4.0+
|
||||||
|
- Optional: `jq` for JSON config parsing (falls back to defaults if not installed)
|
||||||
365
project-hygiene/hooks/cleanup.sh
Executable file
365
project-hygiene/hooks/cleanup.sh
Executable file
@@ -0,0 +1,365 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# project-hygiene cleanup hook
|
||||||
|
# Runs after task completion to clean up temp files and manage orphans
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
PROJECT_ROOT="${PROJECT_ROOT:-.}"
|
||||||
|
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$(realpath "$0")")")}"
|
||||||
|
CONFIG_FILE="${PROJECT_ROOT}/.hygiene.json"
|
||||||
|
LOG_DIR="${PROJECT_ROOT}/.dev/logs"
|
||||||
|
SCRATCH_DIR="${PROJECT_ROOT}/.dev/scratch"
|
||||||
|
LOG_FILE="${LOG_DIR}/hygiene-$(date +%Y%m%d-%H%M%S).log"
|
||||||
|
|
||||||
|
# Default allowed root files (can be overridden by .hygiene.json)
|
||||||
|
DEFAULT_ALLOWED_ROOT=(
|
||||||
|
".git"
|
||||||
|
".gitignore"
|
||||||
|
".gitattributes"
|
||||||
|
".editorconfig"
|
||||||
|
".env"
|
||||||
|
".env.example"
|
||||||
|
".env.local"
|
||||||
|
".nvmrc"
|
||||||
|
".node-version"
|
||||||
|
".python-version"
|
||||||
|
".ruby-version"
|
||||||
|
".tool-versions"
|
||||||
|
"README.md"
|
||||||
|
"LICENSE"
|
||||||
|
"CHANGELOG.md"
|
||||||
|
"CONTRIBUTING.md"
|
||||||
|
"CLAUDE.md"
|
||||||
|
"package.json"
|
||||||
|
"package-lock.json"
|
||||||
|
"yarn.lock"
|
||||||
|
"pnpm-lock.yaml"
|
||||||
|
"Makefile"
|
||||||
|
"Dockerfile"
|
||||||
|
"docker-compose.yml"
|
||||||
|
"docker-compose.yaml"
|
||||||
|
"Cargo.toml"
|
||||||
|
"Cargo.lock"
|
||||||
|
"go.mod"
|
||||||
|
"go.sum"
|
||||||
|
"requirements.txt"
|
||||||
|
"setup.py"
|
||||||
|
"pyproject.toml"
|
||||||
|
"poetry.lock"
|
||||||
|
"Gemfile"
|
||||||
|
"Gemfile.lock"
|
||||||
|
"tsconfig.json"
|
||||||
|
"jsconfig.json"
|
||||||
|
".eslintrc*"
|
||||||
|
".prettierrc*"
|
||||||
|
"vite.config.*"
|
||||||
|
"webpack.config.*"
|
||||||
|
"rollup.config.*"
|
||||||
|
".hygiene.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Temp file patterns to delete
|
||||||
|
TEMP_PATTERNS=(
|
||||||
|
"*.tmp"
|
||||||
|
"*.bak"
|
||||||
|
"*.swp"
|
||||||
|
"*.swo"
|
||||||
|
"*~"
|
||||||
|
".DS_Store"
|
||||||
|
"Thumbs.db"
|
||||||
|
"*.log"
|
||||||
|
"*.orig"
|
||||||
|
"*.pyc"
|
||||||
|
"*.pyo"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Directory patterns to delete
|
||||||
|
TEMP_DIRS=(
|
||||||
|
"__pycache__"
|
||||||
|
".pytest_cache"
|
||||||
|
".mypy_cache"
|
||||||
|
".ruff_cache"
|
||||||
|
"node_modules/.cache"
|
||||||
|
".next/cache"
|
||||||
|
".nuxt/.cache"
|
||||||
|
".turbo"
|
||||||
|
"*.egg-info"
|
||||||
|
".eggs"
|
||||||
|
"dist"
|
||||||
|
"build"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Orphan patterns to identify
|
||||||
|
ORPHAN_PATTERNS=(
|
||||||
|
"test_*.py"
|
||||||
|
"debug_*"
|
||||||
|
"*_backup.*"
|
||||||
|
"*_old.*"
|
||||||
|
"*_bak.*"
|
||||||
|
"*.backup"
|
||||||
|
"temp_*"
|
||||||
|
"tmp_*"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize
|
||||||
|
DELETED_COUNT=0
|
||||||
|
WARNED_COUNT=0
|
||||||
|
ORPHAN_COUNT=0
|
||||||
|
MOVE_ORPHANS=false
|
||||||
|
|
||||||
|
# Logging function
|
||||||
|
log() {
|
||||||
|
local msg="[$(date +%H:%M:%S)] $1"
|
||||||
|
echo "$msg"
|
||||||
|
if [[ -f "$LOG_FILE" ]]; then
|
||||||
|
echo "$msg" >> "$LOG_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log_action() {
|
||||||
|
local action="$1"
|
||||||
|
local target="$2"
|
||||||
|
log " $action: $target"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load project-local config if exists
|
||||||
|
load_config() {
|
||||||
|
if [[ -f "$CONFIG_FILE" ]]; then
|
||||||
|
log "Loading config from $CONFIG_FILE"
|
||||||
|
|
||||||
|
# Check if move_orphans is enabled
|
||||||
|
if command -v jq &>/dev/null; then
|
||||||
|
MOVE_ORPHANS=$(jq -r '.move_orphans // false' "$CONFIG_FILE" 2>/dev/null || echo "false")
|
||||||
|
|
||||||
|
# Load additional allowed root files
|
||||||
|
local extra_allowed
|
||||||
|
extra_allowed=$(jq -r '.allowed_root_files // [] | .[]' "$CONFIG_FILE" 2>/dev/null || true)
|
||||||
|
if [[ -n "$extra_allowed" ]]; then
|
||||||
|
while IFS= read -r file; do
|
||||||
|
DEFAULT_ALLOWED_ROOT+=("$file")
|
||||||
|
done <<< "$extra_allowed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load additional temp patterns
|
||||||
|
local extra_temp
|
||||||
|
extra_temp=$(jq -r '.temp_patterns // [] | .[]' "$CONFIG_FILE" 2>/dev/null || true)
|
||||||
|
if [[ -n "$extra_temp" ]]; then
|
||||||
|
while IFS= read -r pattern; do
|
||||||
|
TEMP_PATTERNS+=("$pattern")
|
||||||
|
done <<< "$extra_temp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load ignore patterns (files to never touch)
|
||||||
|
IGNORE_PATTERNS=()
|
||||||
|
local ignore
|
||||||
|
ignore=$(jq -r '.ignore_patterns // [] | .[]' "$CONFIG_FILE" 2>/dev/null || true)
|
||||||
|
if [[ -n "$ignore" ]]; then
|
||||||
|
while IFS= read -r pattern; do
|
||||||
|
IGNORE_PATTERNS+=("$pattern")
|
||||||
|
done <<< "$ignore"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Warning: jq not installed, using default config"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if file should be ignored
|
||||||
|
should_ignore() {
|
||||||
|
local file="$1"
|
||||||
|
local basename
|
||||||
|
basename=$(basename "$file")
|
||||||
|
|
||||||
|
for pattern in "${IGNORE_PATTERNS[@]:-}"; do
|
||||||
|
if [[ "$basename" == $pattern ]] || [[ "$file" == $pattern ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if file is in allowed root list
|
||||||
|
is_allowed_root() {
|
||||||
|
local file="$1"
|
||||||
|
local basename
|
||||||
|
basename=$(basename "$file")
|
||||||
|
|
||||||
|
for allowed in "${DEFAULT_ALLOWED_ROOT[@]}"; do
|
||||||
|
# Support wildcards in allowed patterns
|
||||||
|
if [[ "$basename" == $allowed ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if file matches orphan pattern
|
||||||
|
is_orphan() {
|
||||||
|
local file="$1"
|
||||||
|
local basename
|
||||||
|
basename=$(basename "$file")
|
||||||
|
|
||||||
|
for pattern in "${ORPHAN_PATTERNS[@]}"; do
|
||||||
|
if [[ "$basename" == $pattern ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup directories
|
||||||
|
setup_dirs() {
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
if [[ "$MOVE_ORPHANS" == "true" ]]; then
|
||||||
|
mkdir -p "$SCRATCH_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start log file
|
||||||
|
echo "=== Project Hygiene Cleanup ===" > "$LOG_FILE"
|
||||||
|
echo "Started: $(date)" >> "$LOG_FILE"
|
||||||
|
echo "Project: $PROJECT_ROOT" >> "$LOG_FILE"
|
||||||
|
echo "" >> "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Delete temp files
|
||||||
|
cleanup_temp_files() {
|
||||||
|
log "Cleaning temp files..."
|
||||||
|
|
||||||
|
for pattern in "${TEMP_PATTERNS[@]}"; do
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
if should_ignore "$file"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
rm -f "$file"
|
||||||
|
log_action "DELETED" "$file"
|
||||||
|
((DELETED_COUNT++))
|
||||||
|
done < <(find "$PROJECT_ROOT" -name "$pattern" -type f -print0 2>/dev/null || true)
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Delete temp directories
|
||||||
|
cleanup_temp_dirs() {
|
||||||
|
log "Cleaning temp directories..."
|
||||||
|
|
||||||
|
for pattern in "${TEMP_DIRS[@]}"; do
|
||||||
|
while IFS= read -r -d '' dir; do
|
||||||
|
if should_ignore "$dir"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
rm -rf "$dir"
|
||||||
|
log_action "DELETED DIR" "$dir"
|
||||||
|
((DELETED_COUNT++))
|
||||||
|
done < <(find "$PROJECT_ROOT" -name "$pattern" -type d -print0 2>/dev/null || true)
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Warn about unexpected root files
|
||||||
|
check_root_files() {
|
||||||
|
log "Checking root files..."
|
||||||
|
|
||||||
|
local unexpected_files=()
|
||||||
|
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
local basename
|
||||||
|
basename=$(basename "$file")
|
||||||
|
|
||||||
|
# Skip directories
|
||||||
|
[[ -d "$file" ]] && continue
|
||||||
|
|
||||||
|
# Skip if in allowed list
|
||||||
|
is_allowed_root "$basename" && continue
|
||||||
|
|
||||||
|
# Skip if should be ignored
|
||||||
|
should_ignore "$basename" && continue
|
||||||
|
|
||||||
|
unexpected_files+=("$basename")
|
||||||
|
log_action "WARNING" "Unexpected root file: $basename"
|
||||||
|
((WARNED_COUNT++))
|
||||||
|
done < <(find "$PROJECT_ROOT" -maxdepth 1 -print0 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [[ ${#unexpected_files[@]} -gt 0 ]]; then
|
||||||
|
log ""
|
||||||
|
log "⚠️ Unexpected files in project root:"
|
||||||
|
for f in "${unexpected_files[@]}"; do
|
||||||
|
log " - $f"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Identify and handle orphaned files
|
||||||
|
handle_orphans() {
|
||||||
|
log "Checking for orphaned files..."
|
||||||
|
|
||||||
|
local orphan_files=()
|
||||||
|
|
||||||
|
for pattern in "${ORPHAN_PATTERNS[@]}"; do
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
if should_ignore "$file"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
orphan_files+=("$file")
|
||||||
|
|
||||||
|
if [[ "$MOVE_ORPHANS" == "true" ]]; then
|
||||||
|
local dest="${SCRATCH_DIR}/$(basename "$file")"
|
||||||
|
# Handle duplicates
|
||||||
|
if [[ -f "$dest" ]]; then
|
||||||
|
dest="${SCRATCH_DIR}/$(date +%Y%m%d%H%M%S)_$(basename "$file")"
|
||||||
|
fi
|
||||||
|
mv "$file" "$dest"
|
||||||
|
log_action "MOVED" "$file -> $dest"
|
||||||
|
else
|
||||||
|
log_action "ORPHAN" "$file"
|
||||||
|
fi
|
||||||
|
((ORPHAN_COUNT++))
|
||||||
|
done < <(find "$PROJECT_ROOT" -name "$pattern" -type f -print0 2>/dev/null || true)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#orphan_files[@]} -gt 0 && "$MOVE_ORPHANS" != "true" ]]; then
|
||||||
|
log ""
|
||||||
|
log "📦 Orphaned files found (enable move_orphans in .hygiene.json to auto-move):"
|
||||||
|
for f in "${orphan_files[@]}"; do
|
||||||
|
log " - $f"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print_summary() {
|
||||||
|
log ""
|
||||||
|
log "=== Cleanup Summary ==="
|
||||||
|
log " Deleted: $DELETED_COUNT items"
|
||||||
|
log " Warnings: $WARNED_COUNT unexpected root files"
|
||||||
|
log " Orphans: $ORPHAN_COUNT files"
|
||||||
|
if [[ "$MOVE_ORPHANS" == "true" ]]; then
|
||||||
|
log " Orphans moved to: $SCRATCH_DIR"
|
||||||
|
fi
|
||||||
|
log " Log file: $LOG_FILE"
|
||||||
|
log ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main
|
||||||
|
main() {
|
||||||
|
cd "$PROJECT_ROOT" || exit 1
|
||||||
|
|
||||||
|
load_config
|
||||||
|
setup_dirs
|
||||||
|
|
||||||
|
log "Starting project hygiene cleanup..."
|
||||||
|
log ""
|
||||||
|
|
||||||
|
cleanup_temp_files
|
||||||
|
cleanup_temp_dirs
|
||||||
|
check_root_files
|
||||||
|
handle_orphans
|
||||||
|
|
||||||
|
print_summary
|
||||||
|
|
||||||
|
# Exit with warning code if issues found
|
||||||
|
if [[ $WARNED_COUNT -gt 0 || $ORPHAN_COUNT -gt 0 ]]; then
|
||||||
|
exit 0 # Still success, but logged warnings
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
9
project-hygiene/hooks/hooks.json
Normal file
9
project-hygiene/hooks/hooks.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"event": "task-completed",
|
||||||
|
"script": "${CLAUDE_PLUGIN_ROOT}/hooks/cleanup.sh",
|
||||||
|
"description": "Post-task cleanup: remove temp files, warn about unexpected root files, manage orphans"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user