diff --git a/.claude/commands/cleanup.md b/.claude/commands/cleanup.md new file mode 100644 index 0000000..1569b22 --- /dev/null +++ b/.claude/commands/cleanup.md @@ -0,0 +1,138 @@ +--- +name: cleanup +description: Post-work cleanup — stale branches, orphaned worktrees, unclosed issues, stale labels +allowed-tools: Bash, Read, Grep, Glob, Task +--- + +# /cleanup Skill + +Clean up stale branches, orphaned worktrees, unclosed issues, and stale labels after work is merged and deployed. + +## Usage + +``` +/cleanup # Show report and clean interactively +/cleanup --dry-run # Show report only, no changes +``` + +## Workflow + +### Step 1: Ensure Labels Exist + +Create all lifecycle labels idempotently: + +```bash +gh label create "priority:critical" --color "B60205" --description "Blocking other work" --force +gh label create "priority:high" --color "D93F0B" --description "Important, should be next" --force +gh label create "priority:medium" --color "FBCA04" --description "Standard priority" --force +gh label create "priority:low" --color "0E8A16" --description "Nice to have" --force +gh label create "in-progress" --color "6F42C1" --description "Actively being worked on" --force +gh label create "ready-for-review" --color "0075CA" --description "PR submitted" --force +gh label create "blocked" --color "9E9E9E" --description "Blocked by something" --force +``` + +### Step 2: Gather State (parallel) + +Launch parallel operations to collect cleanup candidates: + +**A — Stale local branches:** +```bash +git branch --list "issue-*" +``` +For each branch, extract the issue number and check if the issue is CLOSED. + +**B — Stale remote branches:** +```bash +git fetch --prune origin +git branch -r --list "origin/issue-*" +``` +For each, check if there's a merged PR. + +**C — Orphaned worktrees:** +```bash +git worktree list --porcelain +``` +For each worktree (not the main one), check if the branch still exists and if the associated issue is CLOSED. Worktree paths follow the pattern `../devsync--`. + +**D — Issues with stale labels:** +```bash +gh issue list --label "in-progress" --state closed --json number,title +gh issue list --label "ready-for-review" --state closed --json number,title +``` + +**E — Open issues with stale in-progress label:** +```bash +gh issue list --label "in-progress" --state open --json number,title +``` +Check if a corresponding branch exists locally or remotely. + +### Step 3: Reconcile Merged PRs with Open Issues + +Find merged PRs whose closing issues are still OPEN: +```bash +gh pr list --state merged --limit 20 --json number,title,closingIssuesReferences +``` + +### Step 4: Display Report + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 🧹 Cleanup Report +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +📋 Local Branches to Delete + issue-83-zed-tool-support → #83 — Add Zed AI tool support (CLOSED) + +📋 Remote Branches to Prune + origin/issue-83-zed-tool-support → PR #100 — feat: zed tool support (merged) + +📋 Worktrees to Remove + ../devsync-83-zed-tool-support → #83 — Add Zed AI tool support (CLOSED) + +📋 Issues to Close + #128 — Handle missing manifest → merged via PR #135 + +📋 Stale Labels to Remove + #91 — Install crash on empty lib → remove `in-progress` (issue closed) + +──────────────────────────────────────────── + 📊 Summary: N branches, N worktrees, N issues, N labels +──────────────────────────────────────────── +``` + +### Step 5: Check for Dry Run + +If `--dry-run` was passed, stop here. + +### Step 6: Prompt for Action + +Options: Clean all / Pick categories / Abort + +### Step 7: Execute Cleanup + +For each approved category: delete branches, remove worktrees, close issues, clean labels. + +### Step 8: Post-Cleanup Report + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✅ Cleanup Complete +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + 🔀 Branches deleted: N local, N remote + 📂 Worktrees removed: N + 📋 Issues closed: N + 🏷️ Labels cleaned: N + +──────────────────────────────────────────── + 👉 Next: /next to find your next task +──────────────────────────────────────────── +``` + +## Guidelines + +- Always show `#N — title` for issue references +- Always show `PR #N — title` for PR references +- Never delete branches or worktrees without user confirmation +- Be careful with `git worktree remove --force` — only use when the worktree's branch is confirmed gone +- If a worktree has uncommitted changes, warn the user and skip it diff --git a/.claude/commands/code-review.md b/.claude/commands/code-review.md new file mode 100644 index 0000000..f1df8f0 --- /dev/null +++ b/.claude/commands/code-review.md @@ -0,0 +1,163 @@ +--- +name: code-review +description: Code review a pull request with security audit and test verification +allowed-tools: Bash, Read, Edit, Grep, Glob, Task, WebFetch +--- + +# /code-review Skill + +Review a pull request for bugs, security issues, CLAUDE.md compliance, and test results. + +## Usage + +``` +/code-review 85 # Review PR #85 +/code-review # Review PR for current branch +``` + +## Workflow + +### Step 1: Resolve PR Number + +If a PR number is provided as an argument, use it. Otherwise, detect the PR for the current branch: +```bash +gh pr view --json number --jq '.number' +``` + +### Step 2: Eligibility and Context Detection + +Check if the PR is eligible for review: +```bash +gh pr view --json state,isDraft,author,title,body,reviews +gh api repos/{owner}/{repo}/issues//comments --jq '.[].body' +``` + +Do NOT proceed if: PR is closed/merged, is a draft, is automated, or already has a code review comment. + +**Submit-PR detection:** Check if a `/submit-pr` validation comment exists. If found, set `submit_pr_ran = true`. + +### Step 2b: PR Size Check + +```bash +gh pr diff --stat | tail -1 +``` +If under 300 lines, set `small_pr = true`. + +### Step 3: Gather Context (parallel Haiku agents) + +**Agent A — CLAUDE.md paths:** Find all relevant CLAUDE.md files. + +**Agent B — PR summary:** Run `gh pr view ` and `gh pr diff `. Return summary. + +**Agent C — Run unit tests:** Run `pytest tests/unit/ -v --tb=short 2>&1 | tail -80` or `invoke test-unit`. + +### Step 4: Deep Review (conditional parallel agents) + +| Condition | Agents to run | +|-----------|--------------| +| `submit_pr_ran = true` | #2 Bug scan, #4 Historical context, #5 Code comments | +| `small_pr = true` AND standalone | #2 Bug scan, #3 Security, #4 Historical context | +| Standalone, large PR | All 7 agents | + +**Bug scan (#2) ALWAYS runs.** + +**IMPORTANT:** Report ONLY failures. Do not report PASS or N/A items. Keep response under 500 words. + +--- + +**Agent #1 — CLAUDE.md compliance (Sonnet):** *(skipped when `submit_pr_ran`)* + +- [ ] New modules follow existing naming conventions +- [ ] New AI tools follow `AITool` base class pattern +- [ ] New CLI commands use Typer patterns +- [ ] No hardcoded paths or credentials +- [ ] Commits follow `type(scope): description (#issue)` +- [ ] No Co-Authored-By or Claude attribution lines + +--- + +**Agent #2 — Bug scan (Sonnet):** *(ALWAYS runs)* + +- [ ] **Return values**: Unchecked None returns? +- [ ] **Off-by-one**: Loop bounds, slice indices +- [ ] **Type mismatches**: Wrong types in YAML parsing, dict access +- [ ] **Null/empty handling**: Empty lists, missing dict keys, blank strings +- [ ] **Resource leaks**: Files/connections not closed? Missing `with`? +- [ ] **Exception handling**: Too broad? Swallowed silently? +- [ ] **String formatting**: Command concatenation with user input? +- [ ] **Import errors**: Missing or circular imports? +- [ ] **Logic inversion**: Negated conditions, `and`/`or` confusion? +- [ ] **Path handling**: Platform-specific paths? Unsanitized joins? + +--- + +**Agent #3 — Security audit (Sonnet):** *(skipped when `submit_pr_ran`)* + +- [ ] **Command injection**: `subprocess` with `shell=True` + user input? +- [ ] **Path traversal**: File ops with unsanitized `..`? +- [ ] **Hardcoded secrets**: API keys/passwords/tokens in source? +- [ ] **Insecure defaults**: Debug mode, disabled checks? +- [ ] **Input validation**: User input not validated? +- [ ] **Unsafe deserialization**: `pickle.loads`, `yaml.load()` without SafeLoader, `eval()`, `exec()`? +- [ ] **Credential safety**: Credentials stored in manifests or JSON trackers? +- [ ] **Git URL safety**: Credentials embedded in repo URLs? + +--- + +**Agent #4 — Historical context (Haiku):** *(ALWAYS runs)* + +Maximum 15 tool calls. Check: +- [ ] **Reverted fixes**: Does this undo a previous fix? +- [ ] **Recurring patterns**: Similar bugs in this file before? +- [ ] **TODO/FIXME regression**: TODOs addressed or ignored? +- [ ] **Breaking assumptions**: Violated documented assumptions? + +--- + +**Agent #5 — Code comments and intent (Sonnet):** *(ALWAYS runs)* + +- [ ] **Invariant violations**: "must be called after X" / "never modify without Y" — violated? +- [ ] **TODO completion**: TODOs this change should address but didn't? +- [ ] **Warning heeds**: `# WARNING:` / `# IMPORTANT:` — complied with? +- [ ] **Docstring accuracy**: Modified functions still match their docstrings? + +--- + +**Agent #6 — Vision and scope alignment (Haiku):** *(skipped when `submit_pr_ran`)* + +- [ ] Not an IDE / cloud service / code generator / plugin framework / package registry / config burden +- [ ] New dependencies justified +- [ ] New config options have sensible defaults +- [ ] Lean: could this be simpler? + +--- + +**Agent #7 — Documentation freshness (Haiku):** *(skipped when `submit_pr_ran`)* + +- [ ] New modules not in CLAUDE.md? +- [ ] Modified modules with stale CLAUDE.md descriptions? +- [ ] New CLI commands/flags missing from README? + +### Step 5: Confidence Scoring (parallel Haiku agents) + +For each FAIL item, independently verify and score confidence (0-100). + +### Step 6: Filter + +Keep only issues scoring 80+. + +### Step 7-10: Report, Post Comment, Summary + +Display local report, post condensed version as PR comment, show final summary. + +### Link Format + +``` +https://github.com/troylar/devsync/blob//path/to/file.py#L10-L15 +``` + +## Notes + +- Do NOT run builds or typechecks — CI handles those separately +- Use `gh` for all GitHub interactions +- Cite and link every issue diff --git a/.claude/commands/commit.md b/.claude/commands/commit.md new file mode 100644 index 0000000..10ff1cb --- /dev/null +++ b/.claude/commands/commit.md @@ -0,0 +1,168 @@ +--- +name: commit +description: Create a well-formatted commit with enforced conventions +allowed-tools: Bash, Read, Grep, Glob +--- + +# /commit Skill + +Create a commit that follows this project's conventions. Validates format, issue references, and test status before committing. + +## Usage + +``` +/commit # Auto-detect type, scope, and message from changes +/commit fix(core): handle empty manifest gracefully (#91) +/commit --amend # Amend the last commit (use sparingly) +``` + +If a message is provided, validate and use it. If no message is provided, generate one from the staged/unstaged changes. + +## Workflow + +### Step 1: Assess Changes + +Run in parallel: +```bash +git status --short +git diff --cached --stat +git diff --stat +``` + +- If nothing is staged and nothing is modified, abort: "Nothing to commit." +- If nothing is staged but files are modified, show the modified files and ask what to stage. + +### Step 2: Determine the Issue Number + +The current branch should be named `issue--...`. Extract the issue number: +```bash +git branch --show-current +``` + +If the branch name doesn't contain an issue number: +1. Check recent commits for an issue reference +2. If still not found, ask the user: "Which GitHub issue does this commit relate to?" + +Verify the issue exists: +```bash +gh issue view --json state,title --jq '"\(.state): \(.title)"' 2>&1 +``` + +### Step 3: Generate or Validate Message + +**If a message was provided:** Validate it matches `type(scope): description (#N)`: +- Correct type (feat/fix/docs/refactor/test/chore) +- Scope matches a known module (cli, core, storage, ai_tools, tui, utils) +- Issue reference present and matches the branch issue +- Description is lowercase, imperative, no trailing period + +If validation fails, show what's wrong and suggest a corrected version. + +**If no message was provided:** Generate one: +1. Analyze the diff to determine: + - **type**: new files/functions -> `feat`, bug fix -> `fix`, tests only -> `test`, docs only -> `docs`, restructuring -> `refactor`, everything else -> `chore` + - **scope**: primary module being changed (by file count or significance) + - **description**: concise summary of what changed, imperative mood +2. Draft: `type(scope): description (#N)` + +### Step 4: Stage Files + +If files aren't staged yet: +1. Show the list of modified/untracked files +2. Stage the relevant files (not `.env`, credentials, or large binaries): + ```bash + git add + ``` +3. Never use `git add -A` or `git add .` — always add specific files + +### Step 5: Pre-commit Checks + +Get the list of staged Python files first: +```bash +git diff --cached --name-only --diff-filter=ACMR -- '*.py' +``` + +Run checks scoped to staged files: +```bash +ruff check 2>&1 | tail -20 +black --check 2>&1 | tail -20 +``` + +Run tests: +```bash +pytest tests/unit/ -x -q 2>&1 | tail -20 +``` + +- If lint fails: auto-fix with `ruff check --fix `, then re-stage only those files +- If format fails: auto-fix with `black `, re-stage only those files, continue +- If tests fail: abort and show failures. Do not commit with failing tests. +- Never auto-fix or re-stage files that aren't already staged + +### Step 5b: Complexity Check + +Scan the staged diff for vision-relevant changes: + +1. **New dependencies**: Check if `pyproject.toml` is staged and has new entries in `dependencies` or `dev` dependencies. If so, note them. +2. **New config options**: Check if config-related files are staged with new user-facing settings. Flag if a default would suffice. +3. **New infrastructure**: Check for Docker files, external service integrations, or daemon-like patterns. + +If any are found, report them briefly: +``` + [WARN] New dependency: — is this justified? + [WARN] New config option: