-
Notifications
You must be signed in to change notification settings - Fork 40
feat(planning): add auto-commit for planning files #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,209 @@ | ||||||||||||||||
| #!/bin/bash | ||||||||||||||||
| # shellcheck disable=SC2310 | ||||||||||||||||
| # ============================================================================= | ||||||||||||||||
| # Planning File Auto-Commit Helper | ||||||||||||||||
| # ============================================================================= | ||||||||||||||||
| # Commits and pushes changes to TODO.md and todo/ without branch ceremony. | ||||||||||||||||
| # Called automatically by Plan+ agent after planning file modifications. | ||||||||||||||||
| # | ||||||||||||||||
| # Usage: | ||||||||||||||||
| # planning-commit-helper.sh "plan: add new task" | ||||||||||||||||
| # planning-commit-helper.sh --check # Just check if changes exist | ||||||||||||||||
| # planning-commit-helper.sh --status # Show planning file status | ||||||||||||||||
| # | ||||||||||||||||
| # Exit codes: | ||||||||||||||||
| # 0 - Success (or no changes to commit) | ||||||||||||||||
| # 1 - Error (not in git repo, etc.) | ||||||||||||||||
| # ============================================================================= | ||||||||||||||||
|
|
||||||||||||||||
| set -euo pipefail | ||||||||||||||||
|
|
||||||||||||||||
| # Colors | ||||||||||||||||
| readonly RED='\033[0;31m' | ||||||||||||||||
| readonly GREEN='\033[0;32m' | ||||||||||||||||
| readonly YELLOW='\033[1;33m' | ||||||||||||||||
| readonly BLUE='\033[0;34m' | ||||||||||||||||
| readonly NC='\033[0m' | ||||||||||||||||
|
|
||||||||||||||||
| # Planning file patterns | ||||||||||||||||
| readonly PLANNING_PATTERNS="^TODO\.md$|^todo/" | ||||||||||||||||
|
|
||||||||||||||||
| log_info() { | ||||||||||||||||
| echo -e "${BLUE}[plan]${NC} $1" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| log_success() { | ||||||||||||||||
| echo -e "${GREEN}[plan]${NC} $1" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| log_warning() { | ||||||||||||||||
| echo -e "${YELLOW}[plan]${NC} $1" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| log_error() { | ||||||||||||||||
| echo -e "${RED}[plan]${NC} $1" >&2 | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| # Check if we're in a git repository | ||||||||||||||||
| check_git_repo() { | ||||||||||||||||
| if ! git rev-parse --is-inside-work-tree &>/dev/null; then | ||||||||||||||||
| log_error "Not in a git repository" | ||||||||||||||||
| return 1 | ||||||||||||||||
| fi | ||||||||||||||||
| return 0 | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| # Check if there are planning file changes | ||||||||||||||||
| has_planning_changes() { | ||||||||||||||||
| # Check both staged and unstaged changes | ||||||||||||||||
| if git diff --name-only HEAD 2>/dev/null | grep -qE "$PLANNING_PATTERNS"; then | ||||||||||||||||
| return 0 | ||||||||||||||||
| fi | ||||||||||||||||
| if git diff --name-only --cached 2>/dev/null | grep -qE "$PLANNING_PATTERNS"; then | ||||||||||||||||
| return 0 | ||||||||||||||||
| fi | ||||||||||||||||
| # Also check untracked files in todo/ | ||||||||||||||||
| if git ls-files --others --exclude-standard 2>/dev/null | grep -qE "$PLANNING_PATTERNS"; then | ||||||||||||||||
| return 0 | ||||||||||||||||
| fi | ||||||||||||||||
| return 1 | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| # List planning file changes | ||||||||||||||||
| list_planning_changes() { | ||||||||||||||||
| local changes="" | ||||||||||||||||
|
|
||||||||||||||||
| # Staged changes | ||||||||||||||||
| local staged | ||||||||||||||||
| staged=$(git diff --name-only --cached 2>/dev/null | grep -E "$PLANNING_PATTERNS" || true) | ||||||||||||||||
|
|
||||||||||||||||
| # Unstaged changes | ||||||||||||||||
| local unstaged | ||||||||||||||||
| unstaged=$(git diff --name-only 2>/dev/null | grep -E "$PLANNING_PATTERNS" || true) | ||||||||||||||||
|
|
||||||||||||||||
| # Untracked | ||||||||||||||||
| local untracked | ||||||||||||||||
| untracked=$(git ls-files --others --exclude-standard 2>/dev/null | grep -E "$PLANNING_PATTERNS" || true) | ||||||||||||||||
|
|
||||||||||||||||
| # Combine unique | ||||||||||||||||
| changes=$(echo -e "${staged}\n${unstaged}\n${untracked}" | sort -u | grep -v '^$' || true) | ||||||||||||||||
| echo "$changes" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| # Show status of planning files | ||||||||||||||||
| show_status() { | ||||||||||||||||
| check_git_repo || return 1 | ||||||||||||||||
|
|
||||||||||||||||
| echo "Planning file status:" | ||||||||||||||||
| echo "=====================" | ||||||||||||||||
|
|
||||||||||||||||
| if has_planning_changes; then | ||||||||||||||||
| echo -e "${YELLOW}Modified planning files:${NC}" | ||||||||||||||||
| list_planning_changes | while read -r file; do | ||||||||||||||||
| [[ -n "$file" ]] && echo " - $file" | ||||||||||||||||
| done | ||||||||||||||||
| else | ||||||||||||||||
| echo -e "${GREEN}No planning file changes${NC}" | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| return 0 | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| # Main commit function | ||||||||||||||||
| commit_planning_files() { | ||||||||||||||||
| local commit_msg="${1:-plan: update planning files}" | ||||||||||||||||
|
|
||||||||||||||||
| check_git_repo || return 1 | ||||||||||||||||
|
|
||||||||||||||||
| # Check for changes | ||||||||||||||||
| if ! has_planning_changes; then | ||||||||||||||||
| log_info "No planning file changes to commit" | ||||||||||||||||
| return 0 | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| # Show what we're committing | ||||||||||||||||
| log_info "Planning files to commit:" | ||||||||||||||||
| list_planning_changes | while read -r file; do | ||||||||||||||||
| [[ -n "$file" ]] && echo " - $file" | ||||||||||||||||
| done | ||||||||||||||||
|
|
||||||||||||||||
| # Pull latest to avoid conflicts (rebase to keep history clean) | ||||||||||||||||
| local current_branch | ||||||||||||||||
| current_branch=$(git branch --show-current) | ||||||||||||||||
| if git remote get-url origin &>/dev/null; then | ||||||||||||||||
| log_info "Pulling latest changes..." | ||||||||||||||||
| if ! git pull --rebase origin "$current_branch" 2>/dev/null; then | ||||||||||||||||
| log_warning "Pull failed (may be offline or new branch)" | ||||||||||||||||
| fi | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| # Stage only planning files | ||||||||||||||||
| git add TODO.md 2>/dev/null || true | ||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||
| git add todo/ 2>/dev/null || true | ||||||||||||||||
|
Comment on lines
+141
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current implementation uses A more robust approach is to use the
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| # Check if anything was staged | ||||||||||||||||
| if git diff --cached --quiet 2>/dev/null; then | ||||||||||||||||
| log_info "No changes staged after adding planning files" | ||||||||||||||||
| return 0 | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| # Commit (skip hooks - planning commits don't need full linting) | ||||||||||||||||
| log_info "Committing: $commit_msg" | ||||||||||||||||
| if ! git commit -m "$commit_msg" --no-verify; then | ||||||||||||||||
| log_error "Commit failed" | ||||||||||||||||
| return 1 | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| # Push (silent fail if offline or no permissions) | ||||||||||||||||
| if git remote get-url origin &>/dev/null; then | ||||||||||||||||
| log_info "Pushing to remote..." | ||||||||||||||||
| if git push origin HEAD 2>/dev/null; then | ||||||||||||||||
| log_success "Planning files committed and pushed" | ||||||||||||||||
| else | ||||||||||||||||
| log_warning "Committed locally (push failed - will retry later)" | ||||||||||||||||
| fi | ||||||||||||||||
| else | ||||||||||||||||
| log_success "Committed locally (no remote configured)" | ||||||||||||||||
| fi | ||||||||||||||||
|
|
||||||||||||||||
| return 0 | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| # Main | ||||||||||||||||
| main() { | ||||||||||||||||
| case "${1:-}" in | ||||||||||||||||
| --check) | ||||||||||||||||
| check_git_repo || exit 1 | ||||||||||||||||
| if has_planning_changes; then | ||||||||||||||||
| echo "PLANNING_CHANGES=true" | ||||||||||||||||
| exit 0 | ||||||||||||||||
| else | ||||||||||||||||
| echo "PLANNING_CHANGES=false" | ||||||||||||||||
| exit 0 | ||||||||||||||||
| fi | ||||||||||||||||
| ;; | ||||||||||||||||
| --status) | ||||||||||||||||
| show_status | ||||||||||||||||
| exit $? | ||||||||||||||||
| ;; | ||||||||||||||||
| --help|-h) | ||||||||||||||||
| echo "Usage: planning-commit-helper.sh [OPTIONS] [COMMIT_MESSAGE]" | ||||||||||||||||
| echo "" | ||||||||||||||||
| echo "Options:" | ||||||||||||||||
| echo " --check Check if planning files have changes" | ||||||||||||||||
| echo " --status Show planning file status" | ||||||||||||||||
| echo " --help Show this help" | ||||||||||||||||
| echo "" | ||||||||||||||||
| echo "Examples:" | ||||||||||||||||
| echo " planning-commit-helper.sh 'plan: add new task'" | ||||||||||||||||
| echo " planning-commit-helper.sh --check" | ||||||||||||||||
| exit 0 | ||||||||||||||||
| ;; | ||||||||||||||||
| *) | ||||||||||||||||
| commit_planning_files "$@" | ||||||||||||||||
| exit $? | ||||||||||||||||
| ;; | ||||||||||||||||
| esac | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| main "$@" | ||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edge case:
git diff HEADfails on repos with no commits.On a brand new repository with no commits,
git diff --name-only HEADreturns an error (fatal: ambiguous argument 'HEAD'). Withpipefailenabled, this could cause unexpected behavior.🔧 Suggested fix for initial-commit edge case
has_planning_changes() { - # Check both staged and unstaged changes - if git diff --name-only HEAD 2>/dev/null | grep -qE "$PLANNING_PATTERNS"; then + # Check unstaged changes (works even with no commits) + if git diff --name-only 2>/dev/null | grep -qE "$PLANNING_PATTERNS"; then return 0 fi if git diff --name-only --cached 2>/dev/null | grep -qE "$PLANNING_PATTERNS"; thenUsing
git diff --name-only(without HEAD) checks working tree vs index, which works on fresh repos.📝 Committable suggestion
🤖 Prompt for AI Agents