Loading...
Automatically detects and removes unused code, imports, and dependencies with safe deletion verification and rollback support
{
"hookConfig": {
"hooks": {
"sessionEnd": {
"script": "./.claude/hooks/dead-code-eliminator.sh"
}
}
},
"scriptContent": "#!/usr/bin/env bash\n\necho \"🧹 Dead Code Eliminator - Session Cleanup\" >&2\n\n# Configuration\nBACKUP_DIR=\".claude/backups/dead-code-$(date +%Y%m%d-%H%M%S)\"\nREPORT_FILE=\".claude/reports/dead-code-report.txt\"\nDRY_RUN=${DRY_RUN:-true}\n\nmkdir -p \"$(dirname \"$REPORT_FILE\")\"\nmkdir -p \"$BACKUP_DIR\"\n\necho \"📊 Analyzing codebase for dead code...\" >&2\necho \"Dead Code Analysis - $(date)\" > \"$REPORT_FILE\"\necho \"===========================================\" >> \"$REPORT_FILE\"\n\n# Function to find unused imports (JavaScript/TypeScript)\nfind_unused_imports_js() {\n echo \"🔍 Checking for unused imports in JS/TS files...\" >&2\n \n if command -v npx &> /dev/null; then\n # Check if eslint-plugin-unused-imports is available\n if [ -f \"package.json\" ] && grep -q \"eslint\" package.json; then\n echo \"📦 Running ESLint unused imports check...\" >&2\n npx eslint --ext .js,.jsx,.ts,.tsx --quiet --format compact . 2>/dev/null | \\\n grep \"unused\" | head -20 >> \"$REPORT_FILE\" || true\n fi\n \n # Use ts-prune for TypeScript projects\n if [ -f \"tsconfig.json\" ] && command -v npx &> /dev/null; then\n echo \"📦 Running ts-prune for unused exports...\" >&2\n npx ts-prune 2>/dev/null | head -30 >> \"$REPORT_FILE\" || \\\n echo \"💡 Install ts-prune: npm i -D ts-prune\" >&2\n fi\n fi\n}\n\n# Function to find unused Python imports\nfind_unused_imports_python() {\n echo \"🔍 Checking for unused imports in Python files...\" >&2\n \n if command -v autoflake &> /dev/null; then\n echo \"📦 Running autoflake for unused imports...\" >&2\n autoflake --check --recursive --remove-all-unused-imports . 2>/dev/null | \\\n head -20 >> \"$REPORT_FILE\" || true\n elif command -v pylint &> /dev/null; then\n echo \"📦 Running pylint for unused imports...\" >&2\n find . -name \"*.py\" -type f | head -10 | while read -r file; do\n pylint --disable=all --enable=unused-import \"$file\" 2>/dev/null\n done >> \"$REPORT_FILE\" || true\n else\n echo \"💡 Install autoflake or pylint for Python dead code detection\" >&2\n fi\n}\n\n# Function to find unreferenced files\nfind_unreferenced_files() {\n echo \"🔍 Finding potentially unreferenced files...\" >&2\n \n # Find files that might be orphaned (not imported anywhere)\n if command -v rg &> /dev/null; then\n echo \"\" >> \"$REPORT_FILE\"\n echo \"Potentially Unreferenced Files:\" >> \"$REPORT_FILE\"\n echo \"--------------------------------\" >> \"$REPORT_FILE\"\n \n # Find .js/.ts files in src\n find src -type f \\( -name \"*.js\" -o -name \"*.ts\" -o -name \"*.tsx\" -o -name \"*.jsx\" \\) 2>/dev/null | \\\n head -50 | while read -r file; do\n basename=\"$(basename \"$file\" | sed 's/\\.[^.]*$//')\"\n # Check if file is imported anywhere\n if ! rg -q \"from.*['\\\"].*$basename\" . 2>/dev/null && \\\n ! rg -q \"import.*['\\\"].*$basename\" . 2>/dev/null; then\n echo \" - $file (no imports found)\" >> \"$REPORT_FILE\"\n fi\n done\n fi\n}\n\n# Function to find unused dependencies\nfind_unused_dependencies() {\n echo \"🔍 Checking for unused npm dependencies...\" >&2\n \n if [ -f \"package.json\" ]; then\n if command -v npx &> /dev/null; then\n echo \"\" >> \"$REPORT_FILE\"\n echo \"Unused Dependencies Check:\" >> \"$REPORT_FILE\"\n echo \"-------------------------\" >> \"$REPORT_FILE\"\n \n # Use depcheck if available\n if npx depcheck --version &> /dev/null; then\n npx depcheck --json 2>/dev/null | \\\n jq -r '.dependencies[]' 2>/dev/null | \\\n head -10 >> \"$REPORT_FILE\" || \\\n echo \"💡 Install depcheck: npm i -D depcheck\" >&2\n fi\n fi\n fi\n}\n\n# Function to analyze dead code with coverage data\nanalyze_with_coverage() {\n echo \"📊 Analyzing test coverage for dead code hints...\" >&2\n \n if [ -f \"coverage/coverage-summary.json\" ]; then\n echo \"\" >> \"$REPORT_FILE\"\n echo \"Zero-Coverage Files (Potential Dead Code):\" >> \"$REPORT_FILE\"\n echo \"------------------------------------------\" >> \"$REPORT_FILE\"\n \n jq -r 'to_entries[] | select(.value.lines.pct == 0) | .key' \\\n coverage/coverage-summary.json 2>/dev/null | \\\n head -10 >> \"$REPORT_FILE\" || true\n fi\n}\n\n# Run all analysis functions\nfind_unused_imports_js\nfind_unused_imports_python\nfind_unreferenced_files\nfind_unused_dependencies\nanalyze_with_coverage\n\n# Report summary\necho \"\" >> \"$REPORT_FILE\"\necho \"Analysis Complete - $(date)\" >> \"$REPORT_FILE\"\n\n# Display report\nif [ -s \"$REPORT_FILE\" ]; then\n echo \"\" >&2\n echo \"📋 Dead Code Analysis Report:\" >&2\n cat \"$REPORT_FILE\" >&2\n echo \"\" >&2\n echo \"💾 Full report saved to: $REPORT_FILE\" >&2\n \n if [ \"$DRY_RUN\" = \"true\" ]; then\n echo \"\" >&2\n echo \"🔒 DRY RUN mode enabled - no files deleted\" >&2\n echo \"💡 Set DRY_RUN=false to enable automatic cleanup\" >&2\n else\n echo \"⚠️ Automatic cleanup enabled - review report carefully\" >&2\n fi\nelse\n echo \"✅ No dead code detected\" >&2\nfi\n\necho \"\" >&2\necho \"🎯 Dead Code Elimination Best Practices:\" >&2\necho \" • Run static analysis tools regularly\" >&2\necho \" • Use tree-shaking for production builds\" >&2\necho \" • Review unused exports before removal\" >&2\necho \" • Maintain high test coverage to identify dead code\" >&2\necho \" • Use automated tools: ts-prune, depcheck, autoflake\" >&2\n\nexit 0"
}
.claude/hooks/
~/.claude/hooks/
{
"hooks": {
"sessionEnd": {
"script": "./.claude/hooks/dead-code-eliminator.sh"
}
}
}
#!/usr/bin/env bash
echo "🧹 Dead Code Eliminator - Session Cleanup" >&2
# Configuration
BACKUP_DIR=".claude/backups/dead-code-$(date +%Y%m%d-%H%M%S)"
REPORT_FILE=".claude/reports/dead-code-report.txt"
DRY_RUN=${DRY_RUN:-true}
mkdir -p "$(dirname "$REPORT_FILE")"
mkdir -p "$BACKUP_DIR"
echo "📊 Analyzing codebase for dead code..." >&2
echo "Dead Code Analysis - $(date)" > "$REPORT_FILE"
echo "===========================================" >> "$REPORT_FILE"
# Function to find unused imports (JavaScript/TypeScript)
find_unused_imports_js() {
echo "🔍 Checking for unused imports in JS/TS files..." >&2
if command -v npx &> /dev/null; then
# Check if eslint-plugin-unused-imports is available
if [ -f "package.json" ] && grep -q "eslint" package.json; then
echo "📦 Running ESLint unused imports check..." >&2
npx eslint --ext .js,.jsx,.ts,.tsx --quiet --format compact . 2>/dev/null | \
grep "unused" | head -20 >> "$REPORT_FILE" || true
fi
# Use ts-prune for TypeScript projects
if [ -f "tsconfig.json" ] && command -v npx &> /dev/null; then
echo "📦 Running ts-prune for unused exports..." >&2
npx ts-prune 2>/dev/null | head -30 >> "$REPORT_FILE" || \
echo "💡 Install ts-prune: npm i -D ts-prune" >&2
fi
fi
}
# Function to find unused Python imports
find_unused_imports_python() {
echo "🔍 Checking for unused imports in Python files..." >&2
if command -v autoflake &> /dev/null; then
echo "📦 Running autoflake for unused imports..." >&2
autoflake --check --recursive --remove-all-unused-imports . 2>/dev/null | \
head -20 >> "$REPORT_FILE" || true
elif command -v pylint &> /dev/null; then
echo "📦 Running pylint for unused imports..." >&2
find . -name "*.py" -type f | head -10 | while read -r file; do
pylint --disable=all --enable=unused-import "$file" 2>/dev/null
done >> "$REPORT_FILE" || true
else
echo "💡 Install autoflake or pylint for Python dead code detection" >&2
fi
}
# Function to find unreferenced files
find_unreferenced_files() {
echo "🔍 Finding potentially unreferenced files..." >&2
# Find files that might be orphaned (not imported anywhere)
if command -v rg &> /dev/null; then
echo "" >> "$REPORT_FILE"
echo "Potentially Unreferenced Files:" >> "$REPORT_FILE"
echo "--------------------------------" >> "$REPORT_FILE"
# Find .js/.ts files in src
find src -type f \( -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.jsx" \) 2>/dev/null | \
head -50 | while read -r file; do
basename="$(basename "$file" | sed 's/\.[^.]*$//')"
# Check if file is imported anywhere
if ! rg -q "from.*['\"].*$basename" . 2>/dev/null && \
! rg -q "import.*['\"].*$basename" . 2>/dev/null; then
echo " - $file (no imports found)" >> "$REPORT_FILE"
fi
done
fi
}
# Function to find unused dependencies
find_unused_dependencies() {
echo "🔍 Checking for unused npm dependencies..." >&2
if [ -f "package.json" ]; then
if command -v npx &> /dev/null; then
echo "" >> "$REPORT_FILE"
echo "Unused Dependencies Check:" >> "$REPORT_FILE"
echo "-------------------------" >> "$REPORT_FILE"
# Use depcheck if available
if npx depcheck --version &> /dev/null; then
npx depcheck --json 2>/dev/null | \
jq -r '.dependencies[]' 2>/dev/null | \
head -10 >> "$REPORT_FILE" || \
echo "💡 Install depcheck: npm i -D depcheck" >&2
fi
fi
fi
}
# Function to analyze dead code with coverage data
analyze_with_coverage() {
echo "📊 Analyzing test coverage for dead code hints..." >&2
if [ -f "coverage/coverage-summary.json" ]; then
echo "" >> "$REPORT_FILE"
echo "Zero-Coverage Files (Potential Dead Code):" >> "$REPORT_FILE"
echo "------------------------------------------" >> "$REPORT_FILE"
jq -r 'to_entries[] | select(.value.lines.pct == 0) | .key' \
coverage/coverage-summary.json 2>/dev/null | \
head -10 >> "$REPORT_FILE" || true
fi
}
# Run all analysis functions
find_unused_imports_js
find_unused_imports_python
find_unreferenced_files
find_unused_dependencies
analyze_with_coverage
# Report summary
echo "" >> "$REPORT_FILE"
echo "Analysis Complete - $(date)" >> "$REPORT_FILE"
# Display report
if [ -s "$REPORT_FILE" ]; then
echo "" >&2
echo "📋 Dead Code Analysis Report:" >&2
cat "$REPORT_FILE" >&2
echo "" >&2
echo "💾 Full report saved to: $REPORT_FILE" >&2
if [ "$DRY_RUN" = "true" ]; then
echo "" >&2
echo "🔒 DRY RUN mode enabled - no files deleted" >&2
echo "💡 Set DRY_RUN=false to enable automatic cleanup" >&2
else
echo "⚠️ Automatic cleanup enabled - review report carefully" >&2
fi
else
echo "✅ No dead code detected" >&2
fi
echo "" >&2
echo "🎯 Dead Code Elimination Best Practices:" >&2
echo " • Run static analysis tools regularly" >&2
echo " • Use tree-shaking for production builds" >&2
echo " • Review unused exports before removal" >&2
echo " • Maintain high test coverage to identify dead code" >&2
echo " • Use automated tools: ts-prune, depcheck, autoflake" >&2
exit 0
SessionEnd hook runs but no dead code report generated
Check .claude/reports directory permissions and disk space. Verify jq command available for JSON parsing. Run manually to see stderr output: bash .claude/hooks/dead-code-eliminator.sh.
False positives for dynamic imports and runtime dependencies
Hook uses static analysis only. Exclude dynamic require() patterns from reports. Add ignore patterns to .dead-code-ignore file. Use /* dead-code-safe */ comments for runtime-loaded modules.
ts-prune reports too many false positives on exports
Configure ts-prune with .ts-prunerc ignore patterns. Export unused items intentionally for public API. Use ts-prune --ignore to exclude specific paths or patterns from analysis.
DRY_RUN=false mode deletes files without confirmation
Backup created in .claude/backups before deletion. Review report first in dry run mode. Implement confirmation prompt in script. Use git to recover deleted files if needed.
Coverage-based detection misses files outside test scope
Zero coverage indicates potential dead code but not definitive. Cross-reference with import analysis. Check if files are runtime-loaded or dynamically required. Verify files aren't entry points or config files.
Loading reviews...
Join our community of Claude power users. No spam, unsubscribe anytime.
Automated accessibility testing and compliance checking for web applications following WCAG guidelines
Automatically generates or updates API documentation when endpoint files are modified
Automatically formats code files after Claude writes or edits them using Prettier, Black, or other formatters