119 lines
3.5 KiB
Python
Executable File
119 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env -S uv run --script
|
|
# /// script
|
|
# requires-python = ">=3.8"
|
|
# dependencies = []
|
|
# ///
|
|
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
|
|
def run_git_command(command: list[str]) -> subprocess.CompletedProcess:
|
|
"""Run a git command and return the completed process."""
|
|
try:
|
|
return subprocess.run(
|
|
command, capture_output=True, text=True, check=True, cwd=Path.cwd()
|
|
)
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Git command failed: {' '.join(command)}")
|
|
print(f"Error: {e.stderr}")
|
|
sys.exit(1)
|
|
|
|
|
|
def count_changed_files(max_count: int = 6) -> int:
|
|
"""
|
|
Count all changed files (staged, unstaged, and untracked) with early exit.
|
|
Ignores files in .gitignore. Returns count up to max_count.
|
|
"""
|
|
changed_files = set()
|
|
|
|
try:
|
|
# 1. Get unstaged changes (working tree vs index)
|
|
result = subprocess.run(
|
|
["git", "diff-files", "--name-only"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
if result.stdout.strip():
|
|
changed_files.update(result.stdout.strip().split("\n"))
|
|
if len(changed_files) >= max_count:
|
|
return max_count
|
|
|
|
# 2. Get staged changes (index vs HEAD)
|
|
result = subprocess.run(
|
|
["git", "diff-index", "--cached", "--name-only", "HEAD"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
if result.stdout.strip():
|
|
changed_files.update(result.stdout.strip().split("\n"))
|
|
if len(changed_files) >= max_count:
|
|
return max_count
|
|
|
|
# 3. Get untracked files (respects .gitignore)
|
|
result = subprocess.run(
|
|
["git", "ls-files", "--others", "--exclude-standard"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
if result.stdout.strip():
|
|
changed_files.update(result.stdout.strip().split("\n"))
|
|
|
|
return min(len(changed_files), max_count)
|
|
|
|
except subprocess.CalledProcessError:
|
|
# If git command fails, assume no changes
|
|
return 0
|
|
|
|
|
|
def check_git_repository() -> bool:
|
|
"""Check if we're in a git repository."""
|
|
try:
|
|
subprocess.run(
|
|
["git", "rev-parse", "--git-dir"], capture_output=True, check=True
|
|
)
|
|
return True
|
|
except subprocess.CalledProcessError:
|
|
return False
|
|
|
|
|
|
def request_claude_commit():
|
|
"""Request Claude Code to make a commit by echoing the appropriate message."""
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
commit_message = f"Auto-commit: 5+ file changes detected at {timestamp}"
|
|
|
|
# Echo a message that Claude Code can interpret as a commit request
|
|
print(f"CLAUDE_COMMIT_REQUEST: {commit_message}")
|
|
print("🔄 Requesting Claude Code to stage and commit changes...")
|
|
|
|
|
|
def main():
|
|
"""Main execution function."""
|
|
print("🔍 Checking for file changes...")
|
|
|
|
# Verify we're in a git repository
|
|
if not check_git_repository():
|
|
print("❌ Not in a git repository. Exiting.")
|
|
sys.exit(1)
|
|
|
|
# Count changed files with early exit at 6
|
|
changed_count = count_changed_files(max_count=6)
|
|
|
|
print(f"📊 Found {changed_count} changed file(s)")
|
|
|
|
# Check if we hit the threshold
|
|
if changed_count >= 5:
|
|
print("🚨 Threshold reached: 5+ files changed")
|
|
request_claude_commit()
|
|
else:
|
|
print(f"✅ Below threshold: {changed_count}/5 files changed")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|