Compare commits

...

4 Commits

Author SHA1 Message Date
35d797f8d8 chore: remove check_uncommitted.py (replaced by git-status-check.sh)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 12:02:12 -05:00
8006695e26 feat: add git-status-check.sh scan script
Scans all git repos in a directory for uncommitted changes and
unpushed commits. Outputs structured TAB-separated results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:58:21 -05:00
a90f5a3e12 docs: add finish-up implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:44:39 -05:00
131cfb26bb docs: add finish-up skill design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:43:49 -05:00
4 changed files with 244 additions and 96 deletions

View File

@@ -1,96 +0,0 @@
#!/usr/bin/env python3
import os
import subprocess
from pathlib import Path
def check_git_status(repo_path):
"""Check if a git repository has uncommitted changes."""
try:
# Check if directory is a git repo
result = subprocess.run(
['git', 'rev-parse', '--git-dir'],
cwd=repo_path,
capture_output=True,
text=True,
timeout=5
)
if result.returncode != 0:
return None, "Not a git repository"
# Check for uncommitted changes
status_result = subprocess.run(
['git', 'status', '--porcelain'],
cwd=repo_path,
capture_output=True,
text=True,
timeout=5
)
if status_result.returncode != 0:
return None, "Error checking status"
changes = status_result.stdout.strip()
if changes:
# Parse changed files
lines = changes.split('\n')
files = [line[2:].lstrip() if len(line) > 2 else line for line in lines]
return True, (f"{len(lines)} uncommitted change(s)", files)
else:
return False, ("Clean (no uncommitted changes)", [])
except subprocess.TimeoutExpired:
return None, "Timeout"
except Exception as e:
return None, f"Error: {str(e)}"
def main():
current_dir = Path.cwd()
print(f"Checking projects in: {current_dir}\n")
print("=" * 70)
# Get all subdirectories
subdirs = [d for d in current_dir.iterdir() if d.is_dir() and not d.name.startswith('.')]
if not subdirs:
print("No subdirectories found.")
return
projects_with_changes = []
clean_projects = []
non_git_dirs = []
for subdir in sorted(subdirs):
result = check_git_status(subdir)
if result[0] is None:
# Not a git repo or error
has_changes, message = result
non_git_dirs.append((subdir.name, message))
elif result[0]:
# Has changes
has_changes, (message, files) = result
projects_with_changes.append((subdir.name, message, files))
print(f"⚠️ {subdir.name}: {message}")
for file in files:
print(f" {file}")
else:
# Clean
has_changes, (message, files) = result
clean_projects.append(subdir.name)
print(f"{subdir.name}: {message}")
# Summary
print("\n" + "=" * 70)
print("SUMMARY:")
print(f" Projects with uncommitted changes: {len(projects_with_changes)}")
print(f" Clean projects: {len(clean_projects)}")
print(f" Non-git directories: {len(non_git_dirs)}")
if projects_with_changes:
print("\nProjects needing attention:")
for name, msg, files in projects_with_changes:
print(f" - {name}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,155 @@
# /finish-up Skill Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Create a `/finish-up` Claude Code slash command that scans all projects for uncommitted/unpushed changes, reports findings, then dispatches parallel subagents to commit and push.
**Architecture:** A bash scan script (`git-status-check.sh`) outputs structured CSV-like results. The skill file (`finish-up.md`) instructs Claude to run the script, parse results, present a report, confirm with the user, then spawn one Bash subagent per project for autonomous commit/push.
**Tech Stack:** Bash (scan script), Claude Code skill markdown (command file)
---
### Task 1: Create the git-status-check.sh scan script
**Files:**
- Create: `C:/Users/aisaacs/Desktop/Projects/project-scripts/git-status-check.sh`
**Step 1: Write the scan script**
```bash
#!/usr/bin/env bash
# git-status-check.sh - Scan git repos for uncommitted changes and unpushed commits
# Usage: git-status-check.sh [directory]
# directory: path to scan (default: parent of script directory)
# Output: TAB-separated lines: project_name \t uncommitted_count \t unpushed_count \t branch
set -euo pipefail
SCAN_DIR="${1:-$(dirname "$(dirname "$(readlink -f "$0")")")}"
for dir in "$SCAN_DIR"/*/; do
[ -d "$dir/.git" ] || continue
name=$(basename "$dir")
branch=$(git -C "$dir" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
# Count uncommitted changes
uncommitted=$(git -C "$dir" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
# Count unpushed commits (0 if no upstream)
unpushed=$(git -C "$dir" log @{u}..HEAD --oneline 2>/dev/null | wc -l | tr -d ' ' || echo "0")
echo -e "${name}\t${uncommitted}\t${unpushed}\t${branch}"
done
```
**Step 2: Make it executable and test**
Run: `chmod +x C:/Users/aisaacs/Desktop/Projects/project-scripts/git-status-check.sh`
Run: `bash C:/Users/aisaacs/Desktop/Projects/project-scripts/git-status-check.sh C:/Users/aisaacs/Desktop/Projects`
Expected: TAB-separated output with one line per git repo, showing project name, uncommitted count, unpushed count, and branch.
**Step 3: Verify edge cases**
Run the script and confirm:
- Non-git directories (like loose `.py`/`.cs` files) are skipped
- Repos with no upstream tracking show `0` for unpushed (not an error)
**Step 4: Commit**
```bash
cd C:/Users/aisaacs/Desktop/Projects/project-scripts
git add git-status-check.sh
git commit -m "feat: add git-status-check.sh scan script
Scans all git repos in a directory for uncommitted changes and
unpushed commits. Outputs structured TAB-separated results.
Replaces check_uncommitted.py with additional unpushed detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
```
---
### Task 2: Create the /finish-up skill file
**Files:**
- Create: `C:/Users/aisaacs/.claude/commands/finish-up.md`
**Step 1: Write the skill file**
The skill markdown instructs Claude on how to execute the /finish-up workflow:
1. Detect context (all projects vs single project)
2. Run `git-status-check.sh` and parse output
3. Present report table
4. Ask user which projects to process
5. Spawn parallel Bash subagents for commit/push
6. Collect results and present summary
Key instructions for the skill:
- Use `Task` tool with `subagent_type="Bash"` for parallel work
- Each subagent: `git add -A && git diff --cached --stat` to review, craft commit message, commit, push with retry
- Handle Gitea cold-start (retry push after 5s on first failure)
- Never commit `.env`, `credentials`, `secrets` files
- Use conventional commit format
- Include `Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>`
**Step 2: Test the skill**
Run `/finish-up` in a Claude Code session from `C:\Users\aisaacs\Desktop\Projects` and verify:
- Script runs and output is parsed correctly
- Report is presented clearly
- Subagents are dispatched for selected projects
**Step 3: Commit**
```bash
cd C:/Users/aisaacs/Desktop/Projects/project-scripts
git add C:/Users/aisaacs/.claude/commands/finish-up.md
git commit -m "feat: add /finish-up Claude Code slash command
Scans projects for uncommitted/unpushed changes, reports findings,
then dispatches parallel subagents to commit and push.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
```
---
### Task 3: Clean up old check_uncommitted.py
**Files:**
- Delete: `C:/Users/aisaacs/Desktop/Projects/check_uncommitted.py` (loose copy in Projects root)
- Delete: `C:/Users/aisaacs/Desktop/Projects/project-scripts/check_uncommitted.py`
**Step 1: Remove old scripts**
```bash
rm C:/Users/aisaacs/Desktop/Projects/check_uncommitted.py
cd C:/Users/aisaacs/Desktop/Projects/project-scripts
git rm check_uncommitted.py
```
**Step 2: Commit**
```bash
git commit -m "chore: remove check_uncommitted.py (replaced by git-status-check.sh)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
```
---
### Task 4: Push project-scripts to remote
**Step 1: Push**
```bash
cd C:/Users/aisaacs/Desktop/Projects/project-scripts
git push
```
If push fails (Gitea cold-start), wait 5 seconds and retry.

View File

@@ -0,0 +1,61 @@
# /finish-up Skill Design
**Date:** 2026-02-23
## Purpose
A Claude Code slash command (`/finish-up`) that scans git projects for uncommitted changes and unpushed commits, reports findings, then autonomously commits and pushes selected projects via parallel subagents.
## Behavior
### Context Detection
- If CWD is `C:\Users\aisaacs\Desktop\Projects` (or not inside a git repo), scan all subdirectories
- If CWD is inside a specific project, scan just that project
### Phase 1 - Scan
Run a `git-status-check.sh` script from the Projects directory that:
- Checks each git repo for uncommitted changes (`git status --porcelain`)
- Checks for unpushed commits (`git log @{u}..HEAD --oneline`)
- Outputs structured results (project name, has uncommitted, has unpushed, file count, commit count)
This replaces the existing `check_uncommitted.py` with a bash script that also covers unpushed commits.
### Phase 2 - Report
Present findings as a summary:
- Projects with uncommitted changes (file counts)
- Projects with unpushed commits (commit counts)
- Clean projects (brief list)
- If everything clean, say so and exit
### Phase 3 - Confirm
Ask which projects to process (default: all that need attention).
### Phase 4 - Parallel Subagents
Spawn a Bash subagent per selected project. Each autonomously:
1. Stages all changes (`git add -A`)
2. Reviews the diff (`git diff --cached`)
3. Crafts a conventional commit message based on the changes
4. Commits
5. Pushes to remote (with retry for Gitea cold-start)
### Phase 5 - Summary
Report what was committed and pushed across all projects.
## Files
| File | Purpose |
|------|---------|
| `~/.claude/commands/finish-up.md` | Claude Code skill file |
| `~/Desktop/Projects/project-scripts/git-status-check.sh` | Scan script (replaces check_uncommitted.py) |
## Commit Message Style
Subagents craft conventional commit messages (feat/fix/chore/refactor/docs/etc.) with:
- Short summary line
- Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

28
git-status-check.sh Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# git-status-check.sh - Scan git repos for uncommitted changes and unpushed commits
# Usage: git-status-check.sh [directory]
# directory: path to scan (default: parent of script directory)
# Output: TAB-separated lines: project_name \t uncommitted_count \t unpushed_count \t branch
set -euo pipefail
SCAN_DIR="${1:-$(dirname "$(dirname "$(readlink -f "$0")")")}"
for dir in "$SCAN_DIR"/*/; do
[ -d "$dir/.git" ] || continue
name=$(basename "$dir")
branch=$(git -C "$dir" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
# Count uncommitted changes
uncommitted=$(git -C "$dir" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
# Count unpushed commits (0 if no upstream)
if git -C "$dir" rev-parse --verify '@{u}' &>/dev/null; then
unpushed=$(git -C "$dir" log '@{u}..HEAD' --oneline 2>/dev/null | wc -l | tr -d ' ')
else
unpushed=0
fi
printf '%s\t%s\t%s\t%s\n' "$name" "$uncommitted" "$unpushed" "$branch"
done