mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-06 01:54:11 +08:00
Major Changes: 1. Add classify-folders.sh script - Extract folder classification logic from inline script - Support for code/navigation/skip folder types - Placed in .claude/scripts/ for reusability 2. Optimize /workflow:docs command (docs.md) - Simplify Phase 1: single-step session initialization - Add Path Mirroring Strategy section - Document structure now mirrors source structure - Update to single config.json file (replace multiple .process files) - Fix path detection for Windows/Git Bash compatibility - Update all task templates with mirrored output paths 3. Add parent .gitignore support - detect_changed_modules.sh: parse .gitignore from current or git root - update_module_claude.sh: respect .gitignore patterns when counting files - Unified build_exclusion_filters() function across scripts Key Improvements: - Documentation output: .workflow/docs/ with project structure mirroring - Session init: 4 steps → 1 bash command block - Config files: multiple files → single config.json - Path detection: improved Windows/Git Bash normalization - Gitignore support: current dir → parent dir fallback Related Issue: Fix core directory exclusion in get_modules_by_depth.sh (Note: get_modules_by_depth.sh is in user global config, not in this repo)
157 lines
5.8 KiB
Bash
157 lines
5.8 KiB
Bash
#!/bin/bash
|
|
# Detect modules affected by git changes or recent modifications
|
|
# Usage: detect_changed_modules.sh [format]
|
|
# format: list|grouped|paths (default: paths)
|
|
#
|
|
# Features:
|
|
# - Respects .gitignore patterns (current directory or git root)
|
|
# - Detects git changes (staged, unstaged, or last commit)
|
|
# - Falls back to recently modified files (last 24 hours)
|
|
|
|
# Build exclusion filters from .gitignore
|
|
build_exclusion_filters() {
|
|
local filters=""
|
|
|
|
# Common system/cache directories to exclude
|
|
local system_excludes=(
|
|
".git" "__pycache__" "node_modules" ".venv" "venv" "env"
|
|
"dist" "build" ".cache" ".pytest_cache" ".mypy_cache"
|
|
"coverage" ".nyc_output" "logs" "tmp" "temp"
|
|
)
|
|
|
|
for exclude in "${system_excludes[@]}"; do
|
|
filters+=" -not -path '*/$exclude' -not -path '*/$exclude/*'"
|
|
done
|
|
|
|
# Find and parse .gitignore (current dir first, then git root)
|
|
local gitignore_file=""
|
|
|
|
# Check current directory first
|
|
if [ -f ".gitignore" ]; then
|
|
gitignore_file=".gitignore"
|
|
else
|
|
# Try to find git root and check for .gitignore there
|
|
local git_root=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
if [ -n "$git_root" ] && [ -f "$git_root/.gitignore" ]; then
|
|
gitignore_file="$git_root/.gitignore"
|
|
fi
|
|
fi
|
|
|
|
# Parse .gitignore if found
|
|
if [ -n "$gitignore_file" ]; then
|
|
while IFS= read -r line; do
|
|
# Skip empty lines and comments
|
|
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
|
|
|
|
# Remove trailing slash and whitespace
|
|
line=$(echo "$line" | sed 's|/$||' | xargs)
|
|
|
|
# Skip wildcards patterns (too complex for simple find)
|
|
[[ "$line" =~ \* ]] && continue
|
|
|
|
# Add to filters
|
|
filters+=" -not -path '*/$line' -not -path '*/$line/*'"
|
|
done < "$gitignore_file"
|
|
fi
|
|
|
|
echo "$filters"
|
|
}
|
|
|
|
detect_changed_modules() {
|
|
local format="${1:-paths}"
|
|
local changed_files=""
|
|
local affected_dirs=""
|
|
local exclusion_filters=$(build_exclusion_filters)
|
|
|
|
# Step 1: Try to get git changes (staged + unstaged)
|
|
if git rev-parse --git-dir > /dev/null 2>&1; then
|
|
changed_files=$(git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null)
|
|
|
|
# If no changes in working directory, check last commit
|
|
if [ -z "$changed_files" ]; then
|
|
changed_files=$(git diff --name-only HEAD~1 HEAD 2>/dev/null)
|
|
fi
|
|
fi
|
|
|
|
# Step 2: If no git changes, find recently modified source files (last 24 hours)
|
|
# Apply exclusion filters from .gitignore
|
|
if [ -z "$changed_files" ]; then
|
|
changed_files=$(eval "find . -type f \( \
|
|
-name '*.md' -o \
|
|
-name '*.js' -o -name '*.ts' -o -name '*.jsx' -o -name '*.tsx' -o \
|
|
-name '*.py' -o -name '*.go' -o -name '*.rs' -o \
|
|
-name '*.java' -o -name '*.cpp' -o -name '*.c' -o -name '*.h' -o \
|
|
-name '*.sh' -o -name '*.ps1' -o \
|
|
-name '*.json' -o -name '*.yaml' -o -name '*.yml' \
|
|
\) $exclusion_filters -mtime -1 2>/dev/null")
|
|
fi
|
|
|
|
# Step 3: Extract unique parent directories
|
|
if [ -n "$changed_files" ]; then
|
|
affected_dirs=$(echo "$changed_files" | \
|
|
sed 's|/[^/]*$||' | \
|
|
grep -v '^\.$' | \
|
|
sort -u)
|
|
|
|
# Add current directory if files are in root
|
|
if echo "$changed_files" | grep -q '^[^/]*$'; then
|
|
affected_dirs=$(echo -e ".\n$affected_dirs" | sort -u)
|
|
fi
|
|
fi
|
|
|
|
# Step 4: Output in requested format
|
|
case "$format" in
|
|
"list")
|
|
if [ -n "$affected_dirs" ]; then
|
|
echo "$affected_dirs" | while read dir; do
|
|
if [ -d "$dir" ]; then
|
|
local file_count=$(find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l)
|
|
local depth=$(echo "$dir" | tr -cd '/' | wc -c)
|
|
if [ "$dir" = "." ]; then depth=0; fi
|
|
|
|
local types=$(find "$dir" -maxdepth 1 -type f -name "*.*" 2>/dev/null | \
|
|
grep -E '\.[^/]*$' | sed 's/.*\.//' | sort -u | tr '\n' ',' | sed 's/,$//')
|
|
local has_claude="no"
|
|
[ -f "$dir/CLAUDE.md" ] && has_claude="yes"
|
|
echo "depth:$depth|path:$dir|files:$file_count|types:[$types]|has_claude:$has_claude|status:changed"
|
|
fi
|
|
done
|
|
fi
|
|
;;
|
|
|
|
"grouped")
|
|
if [ -n "$affected_dirs" ]; then
|
|
echo "📊 Affected modules by changes:"
|
|
# Group by depth
|
|
echo "$affected_dirs" | while read dir; do
|
|
if [ -d "$dir" ]; then
|
|
local depth=$(echo "$dir" | tr -cd '/' | wc -c)
|
|
if [ "$dir" = "." ]; then depth=0; fi
|
|
local claude_indicator=""
|
|
[ -f "$dir/CLAUDE.md" ] && claude_indicator=" [✓]"
|
|
echo "$depth:$dir$claude_indicator"
|
|
fi
|
|
done | sort -n | awk -F: '
|
|
{
|
|
if ($1 != prev_depth) {
|
|
if (prev_depth != "") print ""
|
|
print " 📁 Depth " $1 ":"
|
|
prev_depth = $1
|
|
}
|
|
print " - " $2 " (changed)"
|
|
}'
|
|
else
|
|
echo "📊 No recent changes detected"
|
|
fi
|
|
;;
|
|
|
|
"paths"|*)
|
|
echo "$affected_dirs"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Execute function if script is run directly
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
detect_changed_modules "$@"
|
|
fi |