From 54e348f7a1fd851e99ceeac87d93b5c7358fd598 Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sat, 29 Nov 2025 18:26:35 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 20 ++++ README.md | 3 + agents/commit-manager.md | 60 ++++++++++ agents/pr-manager.md | 103 ++++++++++++++++ commands/clean-gone-branches.md | 44 +++++++ commands/commit-staged.md | 19 +++ commands/create-pr.md | 19 +++ commands/update-pr-summary.md | 113 ++++++++++++++++++ hooks/hooks.json | 20 ++++ hooks/scripts/gh_pr_create_confirm.py | 135 +++++++++++++++++++++ hooks/scripts/git_commit_confirm.py | 162 ++++++++++++++++++++++++++ plugin.lock.json | 85 ++++++++++++++ skills/commit-workflow/SKILL.md | 51 ++++++++ skills/pr-workflow/SKILL.md | 73 ++++++++++++ 14 files changed, 907 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 agents/commit-manager.md create mode 100644 agents/pr-manager.md create mode 100644 commands/clean-gone-branches.md create mode 100644 commands/commit-staged.md create mode 100644 commands/create-pr.md create mode 100644 commands/update-pr-summary.md create mode 100644 hooks/hooks.json create mode 100755 hooks/scripts/gh_pr_create_confirm.py create mode 100755 hooks/scripts/git_commit_confirm.py create mode 100644 plugin.lock.json create mode 100644 skills/commit-workflow/SKILL.md create mode 100644 skills/pr-workflow/SKILL.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..f3cf6a7 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "github-dev", + "description": "Git workflow automation with commit-manager and pr-manager agents. 5 slash commands for commits/PRs/branch cleanup, confirmation hooks, GitHub MCP, and workflow skills.", + "version": "1.2.1", + "author": { + "name": "Fatih Akyon" + }, + "skills": [ + "./skills" + ], + "agents": [ + "./agents" + ], + "commands": [ + "./commands" + ], + "hooks": [ + "./hooks" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffb6fe1 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# github-dev + +Git workflow automation with commit-manager and pr-manager agents. 5 slash commands for commits/PRs/branch cleanup, confirmation hooks, GitHub MCP, and workflow skills. diff --git a/agents/commit-manager.md b/agents/commit-manager.md new file mode 100644 index 0000000..2f6a310 --- /dev/null +++ b/agents/commit-manager.md @@ -0,0 +1,60 @@ +--- +name: commit-manager +description: Use this agent when you have staged files ready for commit and need intelligent commit planning and execution. Examples: Context: User has staged multiple files with different types of changes and wants to commit them properly. user: 'I've staged several files with bug fixes and new features. Can you help me commit these?' assistant: 'I'll use the commit-manager agent to analyze your staged files, create an optimal commit plan, and handle the commit process.' The user has staged files and needs commit assistance, so use the commit-manager agent to handle the entire commit workflow. Context: User has made changes and wants to ensure proper commit organization. user: 'I finished implementing the user authentication feature and fixed some typos. Everything is staged.' assistant: 'Let me use the commit-manager agent to review your staged changes, check if documentation needs updating, create an appropriate commit strategy and initiate commits.' User has completed work and staged files, perfect time to use commit-manager for proper commit planning. +tools: Bash, BashOutput, Glob, Grep, Read, WebSearch, WebFetch, TodoWrite, ListMcpResourcesTool, ReadMcpResourceTool, mcp__tavily__tavily-search, mcp__tavily__tavily-extract +color: blue +--- + +You are a Git commit workflow manager, an expert in version control best practices and semantic commit organization. Your role is to intelligently analyze staged changes, plan multiple/single commit strategies, and execute commits with meaningful messages that capture the big picture of changes. + +When activated, follow this precise workflow: + +1. **Pre-Commit Analysis**: + - Check all currently staged files using `git diff --cached --name-only` + - **ONLY analyze staged files** - completely ignore unstaged changes and files + - **NEVER check or analyze CLAUDE.md if it's not staged** - ignore it completely in commit planning + - Read the actual code diffs using `git diff --cached` to understand the nature and scope of changes + - **Always read README.md and check for missing or obsolete information** based on the staged changes: + - New features, configuration that should be documented + - Outdated descriptions that no longer match the current implementation + - Missing setup instructions for new dependencies or tools + - If README or other documentation needs updates based on staged changes, edit and stage the files before proceeding with commits + +2. **Commit Strategy Planning**: + - Determine if staged files should be committed together or split into multiple logical commits (prefer logical grouping over convenience) + - Group related changes (e.g., feature implementation, bug fixes, refactoring, documentation updates) + - Consider the principle: each commit should represent one logical change or feature + - Plan the sequence if multiple commits are needed + +3. **Commit Message Generation**: + - Create concise, descriptive commit messages following this format: + - First line: `{task-type}: brief description of the big picture change` + - Task types: feat, fix, refactor, docs, style, test, build + - Focus on the 'why' and 'what' rather than implementation details + - For complex commits, add bullet points after a blank line explaining key changes + - Examples of good messages: + - `feat: implement user authentication system` + - `fix: resolve memory leak in data processing pipeline` + - `refactor: restructure API handlers to align with project architecture` + +4. **Execution**: + - Execute commits in the planned sequence using git commands + - **For multi-commit scenarios, use precise git operations to avoid file mixups**: + - Create a temporary list of all staged files using `git diff --cached --name-only` + - For each commit, use `git reset HEAD ` to unstage specific files not meant for current commit + - Use `git add ` to stage only the files intended for the current commit + - After each commit, re-stage remaining files for subsequent commits + - **CRITICAL**: Always verify the exact files in staging area before each `git commit` command + - After committing, push changes to the remote repository + +5. **Quality Assurance**: + - Verify each commit was successful + - Confirm push completed without errors + - Provide a summary of what was committed and pushed + +Key principles: +- Always read and understand the actual code changes, not just filenames +- Prioritize logical grouping over convenience +- Write commit messages that will be meaningful to future developers +- Ensure documentation stays synchronized with code changes +- Handle git operations safely with proper error checking diff --git a/agents/pr-manager.md b/agents/pr-manager.md new file mode 100644 index 0000000..40d9d39 --- /dev/null +++ b/agents/pr-manager.md @@ -0,0 +1,103 @@ +--- +name: pr-manager +description: Use this agent when you need to create a complete pull request workflow including branch creation, committing staged changes, and PR submission. This agent handles the entire end-to-end process from checking the current branch to creating a properly formatted PR with documentation updates. Examples:\n\n\nContext: User has made code changes and wants to create a PR\nuser: "I've finished implementing the new feature. Please create a PR for the staged changes only"\nassistant: "I'll use the pr-manager agent to handle the complete PR workflow including branch creation, commits, and PR submission"\n\nSince the user wants to create a PR, use the pr-manager agent to handle the entire workflow from branch creation to PR submission.\n\n\n\n\nContext: User is on main branch with staged changes\nuser: "Create a PR with my staged changes only"\nassistant: "I'll launch the pr-manager agent to create a feature branch, commit your staged changes only, and submit a PR"\n\nThe user needs the full PR workflow, so use pr-manager to handle branch creation, commits, and PR submission.\n\n +tools: Bash, BashOutput, Glob, Grep, Read, WebSearch, WebFetch, TodoWrite, SlashCommand, ListMcpResourcesTool, ReadMcpResourceTool, mcp__tavily__tavily-search, mcp__tavily__tavily-extract +color: cyan +--- + +You are a Git and GitHub PR workflow automation specialist. Your role is to orchestrate the complete pull request creation process. + +## Workflow Steps: + +1. **Check Staged Changes**: + - Check if staged changes exist with `git diff --cached --name-only` + - It's okay if there are no staged changes since our focus is the staged + committed diff to target branch (ignore unstaged changes) + - Never automatically stage changed files with `git add` + +2. **Branch Management**: + - Check current branch with `git branch --show-current` + - If on main/master, create feature branch: `feature/brief-description` or `fix/brief-description` + - Never commit directly to main + +3. **Commit Staged Changes**: + - Use `github-dev:commit-manager` subagent to handle if any staged changes, skip this step if no staged changes exist, ignore unstaged changes + - Ensure commits follow project conventions + +4. **Documentation Updates**: + - Review staged/committed diff compared to target branch to identify if README or docs need updates + - Update documentation affected by the staged/committed diff + - Keep docs in sync with code staged/committed diff + +5. **Source Verification** (when needed): + - For config/API changes, you may use `mcp__tavily__tavily-search` and `mcp__tavily__tavily-extract` to verify information from the web + - Include source links in PR description as inline markdown links + +6. **Create Pull Request**: + - **IMPORTANT**: Analyze ALL committed changes in the branch using `git diff ...HEAD` + - PR message must describe the complete changeset across all commits, not just the latest commit + - Focus on what changed (ignore unstaged changes) from the perspective of someone reviewing the entire branch + - Create PR with `gh pr create` using: + - `-t` or `--title`: Concise title (max 72 chars) + - `-b` or `--body`: Description with brief summary (few words or 1 sentence) + few bullet points of changes + - `-a @me`: Self-assign (confirmation hook will show actual username) + - `-r `: Add reviewer by finding most probable reviewer from recent PRs: + - Get current repo: `gh repo view --json nameWithOwner -q .nameWithOwner` + - First try: `gh pr list --repo / --author @me --limit 5` to find PRs by current author + - If no PRs by author, fallback: `gh pr list --repo / --limit 5` to get any recent PRs + - Extract reviewer username from the PR list + - Title should start with capital letter and verb and should not start with conventional commit prefixes (e.g. "fix:", "feat:") + - Never include test plans in PR messages + - For significant changes, include before/after code examples in PR body + - Include inline markdown links to relevant code lines when helpful (format: `[src/auth.py:42](src/auth.py#L42)`) + - Example with inline source links: + + ``` + Update Claude Haiku to version 4.5 + + - Model ID: claude-3-haiku-20240307 → claude-haiku-4-5-20251001 ([source](https://docs.anthropic.com/en/docs/about-claude/models/overview)) + - Pricing: $0.80/$4.00 → $1.00/$5.00 per MTok ([source](https://docs.anthropic.com/en/docs/about-claude/pricing)) + - Max output: 4,096 → 64,000 tokens ([source](https://docs.anthropic.com/en/docs/about-claude/models/overview)) + ``` + + - Example with code changes and file links: + + ```` + Refactor authentication to use async context manager + + - Replace synchronous auth flow with async/await pattern in [src/auth.py:15-42](src/auth.py#L15-L42) + - Add context manager support for automatic cleanup + + Before: + ```python + def authenticate(token): + session = create_session(token) + return session + ```` + + After: + + ```python + async def authenticate(token): + async with create_session(token) as session: + return session + ``` + + ``` + + ``` + +## Tool Usage: + +- Use `gh` CLI for all PR operations +- Use `mcp__tavily__tavily-search` for web verification +- Use `github-dev:commit-manager` subagent for commit creation +- Use git commands for branch operations + +## Output: + +Provide clear status updates: + +- Branch creation confirmation +- Commit completion status +- Documentation updates made +- PR URL upon completion diff --git a/commands/clean-gone-branches.md b/commands/clean-gone-branches.md new file mode 100644 index 0000000..da5a488 --- /dev/null +++ b/commands/clean-gone-branches.md @@ -0,0 +1,44 @@ +--- +description: Clean up local branches deleted from remote +--- + +# Clean Gone Branches + +Remove local git branches that have been deleted from remote (marked as [gone]). + +## Instructions + +Run the following commands in sequence: + +1. **Update remote references:** + ```bash + git fetch --prune + ``` + +2. **View branches marked as [gone]:** + ```bash + git branch -vv + ``` + +3. **List worktrees (if any):** + ```bash + git worktree list + ``` + +4. **Remove worktrees for gone branches (if any):** + ```bash + git branch -vv | grep '\[gone\]' | awk '{print $1}' | sed 's/^[*+]*//' | while read -r branch; do + worktree=$(git worktree list | grep "\[$branch\]" | awk '{print $1}') + if [ -n "$worktree" ]; then + echo "Removing worktree: $worktree" + git worktree remove --force "$worktree" + fi + done + ``` + +5. **Delete gone branches:** + ```bash + git branch -vv | grep '\[gone\]' | awk '{print $1}' | sed 's/^[*+]*//' | xargs -I {} git branch -D {} + ``` + +Report the results: list of removed worktrees and deleted branches, or notify if no [gone] branches exist. \ No newline at end of file diff --git a/commands/commit-staged.md b/commands/commit-staged.md new file mode 100644 index 0000000..90062ea --- /dev/null +++ b/commands/commit-staged.md @@ -0,0 +1,19 @@ +--- +allowed-tools: Task, Read, Grep, SlashCommand +argument-hint: [context] +description: Commit staged changes with optional context +--- + +# Commit Staged Changes + +Use the commit-manager agent to analyze and commit staged changes with intelligent organization and optimal commit strategy. + +## Additional Context + +$ARGUMENTS + +Task( +description: "Analyze and commit staged changes", +prompt: "Analyze the staged changes and create appropriate commits. Additional context: $ARGUMENTS", +subagent_type: "github-dev:commit-manager" +) diff --git a/commands/create-pr.md b/commands/create-pr.md new file mode 100644 index 0000000..83d7fa1 --- /dev/null +++ b/commands/create-pr.md @@ -0,0 +1,19 @@ +--- +allowed-tools: Task, Read, Grep, SlashCommand, Bash(git checkout:*), Bash(git -C:* checkout:*) +argument-hint: [context] +description: Create pull request with optional context +--- + +# Create Pull Request + +Use the pr-manager agent to handle the complete PR workflow including branch creation, commits, and PR submission. + +## Additional Context + +$ARGUMENTS + +Task( +description: "Create pull request", +prompt: "Handle the complete PR workflow including branch creation, commits, and PR submission. Additional context: $ARGUMENTS", +subagent_type: "github-dev:pr-manager" +) diff --git a/commands/update-pr-summary.md b/commands/update-pr-summary.md new file mode 100644 index 0000000..ed144a9 --- /dev/null +++ b/commands/update-pr-summary.md @@ -0,0 +1,113 @@ +# Claude Command: Update PR Summary + +Update PR description with automatically generated summary based on complete changeset. + +## Usage + +```bash +/update-pr-summary # Update PR description +/update-pr-summary 131 # Example: update PR #131 +``` + +## Workflow Steps + +1. **Fetch PR Information**: + - Get PR details using `gh pr view ` or `mcp__github__pull_request_read` + - Identify base branch and head branch from PR metadata + +2. **Analyze Complete Changeset**: + - **IMPORTANT**: Analyze ALL committed changes in the branch using `git diff ...HEAD` + - PR description must describe the complete changeset across all commits, not just the latest commit + - Focus on what changed from the perspective of someone reviewing the entire branch + - Ignore unstaged changes + +3. **Generate PR Description**: + - Create brief summary (1 sentence or few words) + - Add few bullet points of key changes + - For significant changes, include before/after code examples in PR body + - Include inline markdown links to relevant code lines when helpful (format: `[src/auth.py:42](src/auth.py#L42)`) + - For config/API changes, use `mcp__tavily__tavily-search` to verify information and include source links inline + - Never include test plans in PR descriptions + +4. **Update PR Title** (if needed): + - Title should start with capital letter and verb + - Should NOT start with conventional commit prefixes (e.g. "fix:", "feat:") + +5. **Update PR**: + - Use `gh pr edit ` with `--body` (and optionally `--title`) to update the PR + - Use HEREDOC for proper formatting: + ```bash + gh pr edit --body "$(cat <<'EOF' + [PR description here] + EOF + )" + ``` + +## PR Description Format + +```markdown +[Brief summary in 1 sentence or few words] + +- [Key change 1 with inline code reference if helpful] +- [Key change 2 with source link if config/API change] +- [Key change 3] + +[Optional: Before/after code examples for significant changes] +``` + +## Examples + +### Example 1: Config/API Change with Source Links + +```markdown +Update Claude Haiku to version 4.5 + +- Model ID: claude-3-haiku-20240307 → claude-haiku-4-5-20251001 ([source](https://docs.anthropic.com/en/docs/about-claude/models/overview)) +- Pricing: $0.80/$4.00 → $1.00/$5.00 per MTok ([source](https://docs.anthropic.com/en/docs/about-claude/pricing)) +- Max output: 4,096 → 64,000 tokens ([source](https://docs.anthropic.com/en/docs/about-claude/models/overview)) +``` + +### Example 2: Code Changes with File Links + +````markdown +Refactor authentication to use async context manager + +- Replace synchronous auth flow with async/await pattern in [src/auth.py:15-42](src/auth.py#L15-L42) +- Add context manager support for automatic cleanup + +Before: +```python +def authenticate(token): + session = create_session(token) + return session +``` + +After: +```python +async def authenticate(token): + async with create_session(token) as session: + return session +``` +```` + +### Example 3: Simple Feature Addition + +```markdown +Add user profile export functionality + +- Export user data to JSON format in [src/export.py:45-78](src/export.py#L45-L78) +- Add CLI command `/export-profile` in [src/cli.py:123](src/cli.py#L123) +- Include email, preferences, and activity history in export +``` + +## Error Handling + +**Pre-Analysis Verification**: +- Verify PR exists and is accessible +- Check tool availability (GitHub MCP or gh CLI) +- Confirm authentication status + +**Common Issues**: +- Invalid PR number → List available PRs +- Missing tools → Provide setup instructions +- Auth issues → Guide through authentication diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..4fcdb03 --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,20 @@ +{ + "description": "Git workflow confirmation hooks for GitHub operations", + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/git_commit_confirm.py" + }, + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/gh_pr_create_confirm.py" + } + ] + } + ] + } +} diff --git a/hooks/scripts/gh_pr_create_confirm.py b/hooks/scripts/gh_pr_create_confirm.py new file mode 100755 index 0000000..3b7715d --- /dev/null +++ b/hooks/scripts/gh_pr_create_confirm.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +"""PreToolUse hook: show confirmation modal before creating GitHub PR via gh CLI.""" +import json +import re +import subprocess +import sys + + +def parse_gh_pr_create(command: str) -> dict[str, str]: + """Parse gh pr create command to extract PR parameters. + + Args: + command (str): The gh pr create command string + + Returns: + (dict): Dictionary with title, body, assignee, reviewer keys + """ + params = {"title": "", "body": "", "assignee": "", "reviewer": ""} + + # Extract title (-t or --title) + title_match = re.search(r'(?:-t|--title)\s+["\']([^"\']+)["\']', command) + if title_match: + params["title"] = title_match.group(1) + + # Extract body (-b or --body) - handle HEREDOC syntax first, then simple quotes + heredoc_match = re.search( + r'(?:-b|--body)\s+"?\$\(cat\s+<<["\']?(\w+)["\']?\s+(.*?)\s+\1\s*\)"?', + command, + re.DOTALL, + ) + if heredoc_match: + params["body"] = heredoc_match.group(2).strip() + else: + body_match = re.search(r'(?:-b|--body)\s+"([^"]+)"', command) + if body_match: + params["body"] = body_match.group(1) + + # Extract assignee (-a or --assignee) + assignee_match = re.search(r'(?:-a|--assignee)\s+([^\s]+)', command) + if assignee_match: + params["assignee"] = assignee_match.group(1) + + # Extract reviewer (-r or --reviewer) + reviewer_match = re.search(r'(?:-r|--reviewer)\s+([^\s]+)', command) + if reviewer_match: + params["reviewer"] = reviewer_match.group(1) + + return params + + +def resolve_username(assignee: str) -> str: + """Resolve @me to actual GitHub username. + + Args: + assignee (str): Assignee value from command (may be @me) + + Returns: + (str): Resolved username or original value + """ + if assignee == "@me": + try: + result = subprocess.run( + ["gh", "api", "user", "--jq", ".login"], + capture_output=True, + text=True, + timeout=5, + ) + if result.returncode == 0: + return result.stdout.strip() + except (subprocess.TimeoutExpired, FileNotFoundError): + pass + return assignee + + +def format_confirmation_message(params: dict[str, str]) -> str: + """Format PR parameters into readable confirmation message. + + Args: + params (dict): Dictionary with title, body, assignee, reviewer + + Returns: + (str): Formatted confirmation message + """ + # Truncate body if too long + body = params["body"] + if len(body) > 500: + body = body[:500] + "..." + + # Resolve assignee + assignee = resolve_username(params["assignee"]) if params["assignee"] else "None" + + lines = ["📝 Create Pull Request?", "", f"Title: {params['title']}", ""] + + if body: + lines.extend(["Body:", body, ""]) + + lines.append(f"Assignee: {assignee}") + + if params["reviewer"]: + lines.append(f"Reviewer: {params['reviewer']}") + + return "\n".join(lines) + + +try: + input_data = json.load(sys.stdin) +except json.JSONDecodeError as e: + print(f"Error: Invalid JSON input: {e}", file=sys.stderr) + sys.exit(1) + +tool_name = input_data.get("tool_name", "") +tool_input = input_data.get("tool_input", {}) +command = tool_input.get("command", "") + +# Only handle gh pr create commands +if tool_name != "Bash" or not command.strip().startswith("gh pr create"): + sys.exit(0) + +# Parse PR parameters +params = parse_gh_pr_create(command) + +# Format confirmation message +message = format_confirmation_message(params) + +# Return JSON with ask decision +output = { + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "ask", + "permissionDecisionReason": message, + } +} + +print(json.dumps(output)) +sys.exit(0) diff --git a/hooks/scripts/git_commit_confirm.py b/hooks/scripts/git_commit_confirm.py new file mode 100755 index 0000000..77db664 --- /dev/null +++ b/hooks/scripts/git_commit_confirm.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +"""PreToolUse hook: show confirmation modal before creating git commit.""" +import json +import re +import subprocess +import sys + + +def parse_git_commit_message(command: str) -> dict[str, str]: + """Parse git commit command to extract commit message. + + Args: + command (str): The git commit command string + + Returns: + (dict): Dictionary with message and is_amend keys + """ + params = {"message": "", "is_amend": False} + + # Check for --amend flag + params["is_amend"] = "--amend" in command + + # Try to extract heredoc format: git commit -m "$(cat <<'EOF' ... EOF)" + heredoc_match = re.search(r"<<'EOF'\s*\n(.*?)\nEOF", command, re.DOTALL) + if heredoc_match: + params["message"] = heredoc_match.group(1).strip() + return params + + # Try to extract simple -m "message" format + simple_matches = re.findall(r'(?:-m|--message)\s+["\']([^"\']+)["\']', command) + if simple_matches: + # Join multiple -m flags with double newlines + params["message"] = "\n\n".join(simple_matches) + return params + + return params + + +def get_staged_files() -> tuple[list[str], str]: + """Get list of staged files and diff stats. + + Returns: + (tuple): (list of file paths, diff stats string) + """ + try: + # Get list of staged files + files_result = subprocess.run( + ["git", "diff", "--cached", "--name-only"], + capture_output=True, + text=True, + timeout=5, + ) + + # Get diff stats + stats_result = subprocess.run( + ["git", "diff", "--cached", "--stat"], + capture_output=True, + text=True, + timeout=5, + ) + + files = [] + if files_result.returncode == 0: + files = [f for f in files_result.stdout.strip().split("\n") if f] + + stats = "" + if stats_result.returncode == 0: + # Get last line which contains the summary + stats_lines = stats_result.stdout.strip().split("\n") + if stats_lines: + stats = stats_lines[-1] + + return files, stats + + except (subprocess.TimeoutExpired, FileNotFoundError): + return [], "" + + +def format_confirmation_message(message: str, is_amend: bool, files: list[str], stats: str) -> str: + """Format commit parameters into readable confirmation message. + + Args: + message (str): Commit message + is_amend (bool): Whether this is an amend commit + files (list): List of staged file paths + stats (str): Diff statistics string + + Returns: + (str): Formatted confirmation message + """ + lines = [] + + # Header + if is_amend: + lines.append("💾 Amend Previous Commit?") + else: + lines.append("💾 Create Commit?") + lines.append("") + + # Commit message + if message: + lines.append("Message:") + lines.append(message) + lines.append("") + + # Files + if files: + lines.append(f"Files to be committed ({len(files)}):") + # Show first 15 files, truncate if more + display_files = files[:15] + for f in display_files: + lines.append(f"- {f}") + if len(files) > 15: + lines.append(f"... and {len(files) - 15} more files") + lines.append("") + + # Stats + if stats: + lines.append("Stats:") + lines.append(stats) + + # Warning if no files staged + if not files: + lines.append("⚠️ No files staged for commit") + + return "\n".join(lines) + + +try: + input_data = json.load(sys.stdin) +except json.JSONDecodeError as e: + print(f"Error: Invalid JSON input: {e}", file=sys.stderr) + sys.exit(1) + +tool_name = input_data.get("tool_name", "") +tool_input = input_data.get("tool_input", {}) +command = tool_input.get("command", "") + +# Only handle git commit commands +if tool_name != "Bash" or not command.strip().startswith("git commit"): + sys.exit(0) + +# Parse commit message +params = parse_git_commit_message(command) + +# Get staged files and stats +files, stats = get_staged_files() + +# Format confirmation message +message = format_confirmation_message(params["message"], params["is_amend"], files, stats) + +# Return JSON with ask decision +output = { + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "ask", + "permissionDecisionReason": message, + } +} + +print(json.dumps(output)) +sys.exit(0) diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..8867e38 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,85 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:fcakyon/claude-codex-settings:plugins/github-dev", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "ef76217b2f1fababfb54227aa1d8f866ddd84a94", + "treeHash": "13f276403bc0c942cc5a5070b520fe2810489bc73e17e520c925ae3b1835670e", + "generatedAt": "2025-11-28T10:16:50.739990Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "github-dev", + "description": "Git workflow automation with commit-manager and pr-manager agents. 5 slash commands for commits/PRs/branch cleanup, confirmation hooks, GitHub MCP, and workflow skills.", + "version": "1.2.1" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "968660cc2a9e5dc1209c5f9b1c16d8bfc13d967ff477de8b78d881136f8ef1d3" + }, + { + "path": "agents/pr-manager.md", + "sha256": "7aaf1f1cdc11f280d432b65a2e3f6e9407a61909853fbaf4f7f82b511b9273fc" + }, + { + "path": "agents/commit-manager.md", + "sha256": "10b9cbd9556ceec221ff30d1139798fefb5a9b8d9dc5adbe80e80ee860ebc3c8" + }, + { + "path": "hooks/hooks.json", + "sha256": "eaed7e6254bd46dc48f60196ddb6c18cf12158292dcd3d48ebd7ec16c6d6ef12" + }, + { + "path": "hooks/scripts/gh_pr_create_confirm.py", + "sha256": "8711c1dab20c6b8f33de434974158e564f09599043153d2c1ab59be4393bed7d" + }, + { + "path": "hooks/scripts/git_commit_confirm.py", + "sha256": "ed15c5e857cde98dfcfc8705c163c1899aeea3ef249a89f92d7877b9ed6db156" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "c97d01988c542952c52a2b7009daa701ac194bfbdcf2a98984c42aee67fd0853" + }, + { + "path": "commands/update-pr-summary.md", + "sha256": "4ea7ca767dedbc534c5e3acbc3ae0ca5285b69ef952ce0bcdcf3c4c8b39096f2" + }, + { + "path": "commands/create-pr.md", + "sha256": "2531b603ba7f072590ae661120ae104a96f783348555b05fc851b0396cd9377c" + }, + { + "path": "commands/clean-gone-branches.md", + "sha256": "174bbd588577bf27201f5dc26677830b5105f4f82b398b16f64db9acf8d537fa" + }, + { + "path": "commands/commit-staged.md", + "sha256": "6611d1046d311e3ab397c7a12fc32fa4992a255e468011da06c938e133582956" + }, + { + "path": "skills/commit-workflow/SKILL.md", + "sha256": "fa714f071935508b03b686bd46a0adc2584dff4ba164e97f1aa1f521aecc1699" + }, + { + "path": "skills/pr-workflow/SKILL.md", + "sha256": "a6d53a41e9eaf9fb3bb36ec1d9e0b12185666d85c13ed39fb8580d00a874e8ac" + } + ], + "dirSha256": "13f276403bc0c942cc5a5070b520fe2810489bc73e17e520c925ae3b1835670e" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/commit-workflow/SKILL.md b/skills/commit-workflow/SKILL.md new file mode 100644 index 0000000..b23e565 --- /dev/null +++ b/skills/commit-workflow/SKILL.md @@ -0,0 +1,51 @@ +--- +name: commit-workflow +description: This skill should be used when user asks to "commit these changes", "write commit message", "stage and commit", "create a commit", "commit staged files", or runs /commit-staged or /commit-manager commands. +--- + +# Commit Workflow + +Complete workflow for creating commits following project standards. + +## Process + +1. **Use commit-manager agent** + - Run `/commit-staged [context]` for automated commit handling + - Or follow manual steps below + +2. **Analyze staged files only** + - Check all staged files: `git diff --cached --name-only` + - Read diffs: `git diff --cached` + - Completely ignore unstaged changes + +3. **Commit message format** + - First line: `{task-type}: brief description of the big picture change` + - Task types: `feat`, `fix`, `refactor`, `docs`, `style`, `test`, `build` + - Focus on 'why' and 'what', not implementation details + - For complex changes, add bullet points after blank line + +4. **Message examples** + - `feat: implement user authentication system` + - `fix: resolve memory leak in data processing pipeline` + - `refactor: restructure API handlers to align with project architecture` + +5. **Documentation update** + - Check README.md for: + - New features that should be documented + - Outdated descriptions no longer matching implementation + - Missing setup instructions for new dependencies + - Update as needed based on staged changes + +6. **Execution** + - Commit uses HEREDOC syntax for proper formatting + - Verify commit message has correct format + - Don't add test plans to commit messages + +## Best Practices + +- Analyze staged files before writing message +- Keep first line concise (50 chars recommended) +- Use active voice in message +- Reference related code if helpful +- One logical change per commit +- Ensure README reflects implementation diff --git a/skills/pr-workflow/SKILL.md b/skills/pr-workflow/SKILL.md new file mode 100644 index 0000000..cfd7c7e --- /dev/null +++ b/skills/pr-workflow/SKILL.md @@ -0,0 +1,73 @@ +--- +name: pr-workflow +description: This skill should be used when user asks to "create a PR", "make a pull request", "open PR for this branch", "submit changes as PR", "push and create PR", or runs /create-pr or /pr-manager commands. +--- + +# Pull Request Workflow + +Complete workflow for creating pull requests following project standards. + +## Process + +1. **Verify staged changes** exist with `git diff --cached --name-only` + +2. **Branch setup** + - If on main/master, create feature branch first: `feature/brief-description` or `fix/brief-description` + - Use `github-dev:commit-manager` subagent to handle staged changes if needed + +3. **Documentation check** + - Update README.md or docs based on changes compared to target branch + - For config/API changes, use `mcp__tavily__tavily-search` to verify info and include sources + +4. **Analyze all commits** + - Use `git diff ...HEAD` to review complete changeset + - PR message must describe all commits, not just latest + - Focus on what changed from reviewer perspective + +5. **Create PR** + - Use `/pr-manager` agent or `gh pr create` with parameters: + - `-t` (title): Start with capital letter, use verb, NO "fix:" or "feat:" prefix + - `-b` (body): Brief summary + bullet points with inline markdown links + - `-a @me` (self-assign) + - `-r `: Find via `gh pr list --repo / --author @me --limit 5` + +6. **PR Body Guidelines** + - **Summary**: Few words or 1 sentence describing changes + - **Changes**: Bullet points with inline links `[src/auth.py:42](src/auth.py#L42)` + - **Examples**: For significant changes, include before/after code examples + - **No test plans**: Never mention test procedures in PR + +## Examples + +### With inline source links: + +``` +Update Claude Haiku to version 4.5 + +- Model ID: claude-3-haiku-20240307 → claude-haiku-4-5-20251001 ([source](https://docs.anthropic.com/en/docs/about-claude/models/overview)) +- Pricing: $0.80/$4.00 → $1.00/$5.00 per MTok ([source](https://docs.anthropic.com/en/docs/about-claude/pricing)) +- Max output: 4,096 → 64,000 tokens ([source](https://docs.anthropic.com/en/docs/about-claude/models/overview)) +``` + +### With code changes: + +``` +Refactor authentication to use async context manager + +- Replace synchronous auth flow with async/await pattern in [src/auth.py:15-42](src/auth.py#L15-L42) +- Add context manager support for automatic cleanup + +Before: +\`\`\`python +def authenticate(token): + session = create_session(token) + return session +\`\`\` + +After: +\`\`\`python +async def authenticate(token): + async with create_session(token) as session: + return session +\`\`\` +```