From 9d1160d6c7278de7d925621e16500ef4ec6262d9 Mon Sep 17 00:00:00 2001 From: "Ramin B." Date: Tue, 19 May 2026 15:18:16 -0400 Subject: [PATCH] feat: add reviews and rebased skills MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - reviews: end-to-end GitHub PR review workflow — fetches all comments via REST + GraphQL, triages actionable vs ambiguous, applies fixes, posts replies, resolves threads, and summarizes in a PR comment - rebased: intelligent git rebase onto origin/main — resolves conflicts by merging intent from both sides, handles lock files and generated files, never force-pushes without confirmation Co-Authored-By: Claude Sonnet 4.6 (1M context) --- README.md | 39 ++++++ skills/rebased/README.md | 49 ++++++++ skills/rebased/SKILL.md | 124 ++++++++++++++++++ skills/rebased/metadata.json | 18 +++ skills/reviews/README.md | 52 ++++++++ skills/reviews/SKILL.md | 236 +++++++++++++++++++++++++++++++++++ skills/reviews/metadata.json | 20 +++ 7 files changed, 538 insertions(+) create mode 100644 skills/rebased/README.md create mode 100644 skills/rebased/SKILL.md create mode 100644 skills/rebased/metadata.json create mode 100644 skills/reviews/README.md create mode 100644 skills/reviews/SKILL.md create mode 100644 skills/reviews/metadata.json diff --git a/README.md b/README.md index bb8f7d6..52bc6b2 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,43 @@ Error prevention and best practices enforcement for AI agent-assisted coding. - Model configuration recommendations (Claude 3.5+, GPT-4+, extended thinking) - 60KB+ of reference documentation +### [reviews](./skills/reviews) + +Address GitHub PR review feedback end-to-end from your agent. + +**Use when:** + +- User types `/reviews` or asks to "address review comments" +- Going through inline PR feedback after a code review +- Responding to a specific PR by number, URL, or branch name + +**Features:** + +- Fetches all reviews, inline comments, and conversation threads via REST + GraphQL +- Triages actionable vs ambiguous items; skips already-resolved threads +- Applies code changes, posts replies, and resolves threads incrementally +- Surfaces ambiguous items and disagreements for human review before proceeding +- Posts a structured summary comment to the PR +- Never pushes — the human always reviews the commit and pushes + +### [rebased](./skills/rebased) + +Rebase the current branch onto `origin/main` and resolve conflicts intelligently. + +**Use when:** + +- User types `/rebased` or asks to "rebase and fix conflicts" +- Branch has fallen behind main and needs to be brought up to date +- A rebase is already in progress and needs help resolving remaining conflicts + +**Features:** + +- Pre-flight checks for dirty working tree, in-progress rebases, and edge cases +- Merges both sides of each conflict by understanding intent, not blindly picking one +- Regenerates lock files (`bun.lockb`, `package-lock.json`, etc.) rather than hand-merging +- Works commit-by-commit through multi-step rebases +- Never force-pushes without explicit user confirmation + ### [ascii-renderer](./skills/ascii-renderer) Generate ASCII art from images or text using shape vector rendering. @@ -97,6 +134,8 @@ npx skills add dupe-com/skills/dupe-research npx skills add dupe-com/skills/dupe npx skills add dupe-com/skills/nomistakes npx skills add dupe-com/skills/ascii-renderer +npx skills add dupe-com/skills/reviews +npx skills add dupe-com/skills/rebased ``` This works with Claude Code, OpenCode, Cursor, Windsurf, Cline, Codex, AMP, Copilot, and any agent that supports the [agentskills.io](https://agentskills.io) standard. diff --git a/skills/rebased/README.md b/skills/rebased/README.md new file mode 100644 index 0000000..bb834cd --- /dev/null +++ b/skills/rebased/README.md @@ -0,0 +1,49 @@ +# rebased + +> Intelligent git rebase with conflict resolution for AI coding agents + +## What It Does + +**rebased** fetches `origin/main`, starts the rebase, and works through conflicts one commit at a time — understanding the *intent* of both sides rather than blindly picking one. It handles lock files, generated files, and complex multi-step rebases, then hands the result back to you to test and force-push. + +## Use When + +- User types `/rebased` in their agent session +- User says "rebase me on main", "rebase and fix conflicts", "get this branch up to date with main" +- Branch has fallen behind main and needs to be brought up to date before merging + +## Features + +- **Pre-flight checks** — detects dirty working tree, already-in-progress rebases, detached HEAD, and main/master branches before touching anything +- **Intent-preserving resolution** — reads both sides of each conflict and merges them semantically rather than choosing one +- **Lock file handling** — regenerates `bun.lockb`, `package-lock.json`, `yarn.lock` rather than hand-merging them +- **Generated file handling** — detects migrations and snapshots and regenerates from source +- **Step-by-step loop** — processes one commit at a time, type-checking after each resolution +- **Error recovery** — handles rename conflicts, empty commits, and stuck states with clear guidance +- **Never force-pushes automatically** — always confirms with the user before any destructive operation + +## Installation + +```bash +npx skills add dupe-com/skills/rebased +``` + +## Usage + +``` +/rebased # rebase current branch onto origin/main +``` + +## Requirements + +- `git` with a remote named `origin` pointing to the repo +- The base branch is named `main` (not `master` — ask the user if the default branch differs) + +## Hard Rules + +The skill will never: +- Run `git rebase --skip` or `--abort` without asking +- Use `--theirs`/`--ours` to wholesale discard one side +- Delete a conflicted file unless there's clear evidence it was intentionally deleted +- Bypass commit hooks with `--no-verify` +- Force-push without explicit user confirmation diff --git a/skills/rebased/SKILL.md b/skills/rebased/SKILL.md new file mode 100644 index 0000000..77c25d3 --- /dev/null +++ b/skills/rebased/SKILL.md @@ -0,0 +1,124 @@ +--- +name: rebased +description: Rebase the current branch onto origin/main and intelligently resolve any conflicts that arise. Use when the user invokes /rebased or asks to rebase the current branch on main and resolve conflicts. +allowed-tools: Bash, Read, Edit, Write +--- + +# Rebased + +Rebases the current branch onto `origin/main` and resolves conflicts as they appear, one rebase step at a time. + +## When to use + +The user typed `/rebased`, or asked something like "rebase me on main", "rebase and fix conflicts", "get this branch up to date with main". + +## Pre-flight checks (run in parallel) + +Before touching anything, gather state: + +```bash +git status --porcelain=v1 -b +git rev-parse --abbrev-ref HEAD +git rev-parse --git-dir # to detect in-progress rebase via $GIT_DIR/rebase-merge or rebase-apply +``` + +Decision matrix: + +- **Working tree dirty** → stop and ask the user whether to stash, commit, or abort. Do not silently `git stash` — that hides their work. +- **Already on `main`/`master`** → stop and ask. Rebasing main onto itself is almost never what they want. +- **Rebase already in progress** (`.git/rebase-merge` or `.git/rebase-apply` exists) → skip the fetch/rebase-start step and jump straight to the conflict-resolution loop. +- **Detached HEAD** → stop and ask. + +## Execution + +### 1. Fetch and start the rebase + +```bash +git fetch origin main +git rebase origin/main +``` + +If it returns clean ("Successfully rebased"), report that and stop. + +If it stops with conflicts, proceed to the loop. + +### 2. Conflict-resolution loop + +Repeat until rebase is complete or the user tells you to stop. + +**a. Identify what's conflicted:** + +```bash +git status --porcelain=v1 +git diff --name-only --diff-filter=U +``` + +**b. Understand the current rebase step.** This is critical — the conflict is between *their* commit (the one being replayed, marked `<<<<<<< HEAD` in working-tree convention during rebase is actually the *upstream* / `main` side; `>>>>>>> commit-sha` is the *branch* side being replayed). Get context: + +```bash +git log --oneline -1 REBASE_HEAD # the commit being applied +git show --stat REBASE_HEAD # what it tried to change +git log --oneline origin/main -5 # recent main commits for context +``` + +**c. For each conflicted file:** + +1. `Read` the file to see the conflict markers. +2. Decide the right resolution by understanding **both intents**: + - What was main trying to do? (`git log -1 -p origin/main -- ` for the most recent main change to this file) + - What was the branch commit trying to do? (`git show REBASE_HEAD -- `) +3. Edit the file to merge both intents — do not blindly pick one side. Common patterns: + - Both sides added imports → keep both, deduped, in sorted order + - Both sides edited the same function differently → combine the changes if they're orthogonal; ask if they conflict semantically + - One side renamed/moved code the other side edited → apply the edit at the new location + - Lock files (`bun.lockb`, `package-lock.json`, `yarn.lock`) → regenerate (`bun install` / `npm install` / `yarn`) rather than hand-merge + - Generated files (migrations, snapshots) → regenerate from source +4. Remove all `<<<<<<<`, `=======`, `>>>>>>>` markers. +5. `git add `. + +**d. Sanity-check the resolution before continuing:** + +- For TypeScript/JS, run the project's type checker on affected files if the change touches types or imports. +- For tests, **don't** run the full suite — too slow per step. Save that for after the rebase completes. + +**e. Continue the rebase:** + +```bash +git -c core.editor=true rebase --continue +``` + +The `-c core.editor=true` skips the commit-message editor. If a commit becomes empty (all its changes are now upstream), use `git rebase --skip` instead. + +**f. If `--continue` produces another conflict**, loop back to step (a). Each rebase step is one commit being replayed, so you may go through this several times. + +### 3. Post-rebase + +When rebase finishes: + +```bash +git status +git log --oneline origin/main..HEAD # show what was replayed +``` + +Report back: how many commits replayed, how many files had conflicts, anything you regenerated (lock files, migrations). + +**Do not push.** Pushing a rebased branch requires a force-push, which is destructive — confirm with the user first, and use `--force-with-lease` not `--force`. + +## Hard rules + +- **Never use `git rebase --skip` or `--abort` without asking** — these throw away work. +- **Never use `git checkout --theirs`/`--ours` blindly** — these discard one side wholesale and almost always lose intent. +- **Never resolve a conflict by deleting the file** unless you have positive evidence the file was deleted on purpose on one side (check `git log --diff-filter=D`). +- **Never bypass hooks** with `--no-verify`. If a pre-commit hook blocks `--continue`, fix the underlying issue. +- **Never force-push automatically.** Always confirm. +- If the conflict resolution is non-obvious (e.g. both sides rewrote the same function with different intent), **stop and ask the user** rather than guessing. + +## Error recovery + +- **"could not apply ..." with no obvious conflict** → check for renames; `git status` will show "both modified" vs "added by us/them". For a rename conflict, find the new path with `git log --follow --name-status` and apply the change there. +- **Lock-file conflict that won't resolve cleanly** → `git checkout --theirs && && git add ` (using "theirs" = the branch being replayed onto, i.e. main's lockfile as the base). +- **Stuck and want to bail out** → tell the user the state, then ask before running `git rebase --abort`. Their working tree will return to pre-rebase state. + +## Reporting + +End with a one-line summary: `Rebased onto origin/main: N commits replayed, M files had conflicts (resolved). Run tests before pushing.` diff --git a/skills/rebased/metadata.json b/skills/rebased/metadata.json new file mode 100644 index 0000000..71675b7 --- /dev/null +++ b/skills/rebased/metadata.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0", + "organization": "Dupe.com", + "author": "Ramin Bozorgzadeh", + "date": "May 2026", + "abstract": "Rebases the current branch onto origin/main and intelligently resolves merge conflicts one commit at a time. Understands both sides of each conflict, merges intent rather than blindly picking a side, regenerates lock files and generated files, and reports what was resolved. Never force-pushes without confirmation.", + "references": [ + "https://agentskills.io/specification", + "https://git-scm.com/docs/git-rebase" + ], + "compatibility": ["claude-code", "opencode", "cursor", "amp"], + "tags": [ + "git", + "rebase", + "conflict-resolution", + "workflow" + ] +} diff --git a/skills/reviews/README.md b/skills/reviews/README.md new file mode 100644 index 0000000..4cca6f0 --- /dev/null +++ b/skills/reviews/README.md @@ -0,0 +1,52 @@ +# reviews + +> End-to-end GitHub PR review workflow for AI coding agents + +## What It Does + +**reviews** handles the full cycle of addressing PR review feedback: fetching every comment and inline thread, triaging what's actionable vs ambiguous, making code changes, posting replies, resolving threads, and leaving a summary comment on the PR. + +## Use When + +- User types `/reviews` in their agent session +- User says "address review comments", "go through PR feedback", "handle the review on #123" +- Responding to inline comments after a code review + +## Features + +- **Full comment fetch** — pulls top-level reviews, inline comments, and conversation-tab comments in parallel via GitHub REST + GraphQL +- **Smart triage** — categorizes comments as actionable, question, disagreement, ambiguous, or out-of-scope; skips already-resolved threads +- **Code changes** — applies edits using exact file + line context from the diff hunk +- **Selective replies** — posts replies only where they add value for other reviewers +- **Thread resolution** — resolves threads immediately after addressing them (not in a batch at the end) +- **Human-in-the-loop** — surfaces ambiguous items and disagreements for the user before proceeding +- **Summary comment** — posts a structured summary to the PR listing fixed, won't-fix, and follow-up items +- **Never pushes** — always leaves the final push decision to the human + +## Installation + +```bash +npx skills add dupe-com/skills/reviews +``` + +## Usage + +``` +/reviews # address reviews on the current branch's PR +/reviews 3239 # address reviews on PR #3239 +/reviews feature/foo # address reviews on the PR for branch feature/foo +``` + +## Requirements + +- `gh` CLI installed and authenticated (`gh auth status`) +- Write access to the repository (for posting replies and resolving threads) + +## Hard Rules + +The skill will never: +- Push the resulting commit (that's yours to review and push) +- Close, merge, approve, or dismiss-review the PR +- Delete or edit other people's comments +- Resolve threads it didn't address +- Silently accept a suggestion it disagrees with diff --git a/skills/reviews/SKILL.md b/skills/reviews/SKILL.md new file mode 100644 index 0000000..bcdcd71 --- /dev/null +++ b/skills/reviews/SKILL.md @@ -0,0 +1,236 @@ +--- +name: reviews +description: Pull down GitHub PR reviews and inline comments for the current branch (or a given PR number / URL / branch name), address them with code changes, reply where clarification helps other reviewers, resolve handled threads, and post a summary comment. Use when the user invokes /reviews or asks to address PR feedback. +allowed-tools: Bash, Read, Edit, Write +--- + +# Reviews + +Triage and address PR review feedback end-to-end: fetch every comment, fix what's actionable, ask the user about anything ambiguous, reply on threads where it helps other reviewers, resolve handled threads, and post a summary of what was addressed. + +## When to use + +User typed `/reviews`, or asked something like "address review comments", "go through PR feedback", "handle the review on #3239", "respond to the inline comments". + +## Resolve the target PR + +Argument forms (`/reviews ` or no arg): + +- **No arg** → use current branch's PR. Detect with: + ```bash + gh pr view --json number,url,headRefName,baseRefName,state + ``` + If no PR exists for the current branch, stop and tell the user. +- **Number** (e.g. `3239`) → `gh pr view 3239 --json ...` +- **URL** (e.g. `https://github.com/owner/repo/pull/3239`) → extract the number, same as above +- **Branch name** (e.g. `feature/foo`) → `gh pr view feature/foo --json ...` + +Resolve `OWNER/REPO` from `gh repo view --json owner,name`. + +Stop and ask if: +- The PR is `MERGED` or `CLOSED` (addressing review on a merged PR is almost always wrong). +- The PR is `DRAFT` and has no reviews yet. +- The current branch is `main`/`master` and no arg was given. + +## Pre-flight on the local checkout + +Before editing anything: + +```bash +git status --porcelain=v1 -b +git rev-parse --abbrev-ref HEAD +``` + +- **Working tree dirty** → ask whether to stash, commit, or proceed. Don't silently mix unrelated changes into the review-fix commit. +- **Not on the PR's `headRefName`** → ask before checking it out. The user may be intentionally addressing reviews from a different worktree. +- **Mid-rebase / mid-merge** (`.git/rebase-merge`, `.git/MERGE_HEAD` exists) → stop. Finish that first. + +## Fetch all feedback + +Run these in parallel — they're independent reads: + +```bash +# Top-level reviews (the "Approve / Request changes / Comment" submissions, plus their summary body) +gh api "repos/$OWNER/$REPO/pulls/$NUM/reviews?per_page=100" + +# Inline review comments (line-by-line — these are the ones with path + line + diff_hunk) +gh api "repos/$OWNER/$REPO/pulls/$NUM/comments?per_page=100" + +# Issue/conversation-tab comments (top-level chat on the PR) +gh api "repos/$OWNER/$REPO/issues/$NUM/comments?per_page=100" + +# Review threads with resolved state — GraphQL is the only way to get this +gh api graphql -f query=' + query($owner:String!, $repo:String!, $num:Int!) { + repository(owner:$owner, name:$repo) { + pullRequest(number:$num) { + reviewThreads(first:100) { + nodes { + id + isResolved + isOutdated + comments(first:50) { + nodes { id databaseId author { login } body path line originalLine diffHunk url } + } + } + } + } + } + }' -F owner="$OWNER" -F repo="$REPO" -F num=$NUM +``` + +The GraphQL `reviewThreads.nodes[].id` is the **thread ID** needed for `resolveReviewThread`. The `comments.nodes[].databaseId` matches the REST `id` on inline comments — use this to bridge the two APIs. + +If pagination hits the cap (>100 of any kind), page through with `--paginate` or follow `Link` headers. + +## Triage + +Build a working list. For each comment: + +**Skip:** +- Threads where `isResolved == true`. +- Comments authored by the PR author (you / the user) — those are replies, not asks. +- Bot comments unless they are CodeRabbit / Copilot review bots making concrete suggestions (those count). +- Outdated threads (`isOutdated == true`) where the line no longer exists — note for the summary as "no longer applicable" but don't try to fix. +- Pure approvals ("LGTM", `state: APPROVED` with empty body and no inline asks). + +**Categorize the rest:** +- **Actionable** — clear code change requested ("rename this", "this should be `Promise.all`", "missing null check"). Make the change. +- **Question** — reviewer is asking for clarification ("why this approach?", "is this safe?"). Reply, don't change code. +- **Suggestion you disagree with** — flag for the user. Don't silently dismiss. +- **Ambiguous** — can't tell what they want. Flag for the user. +- **Out of scope** — valid but belongs in a follow-up. Reply saying so + (with user OK) open a follow-up issue. + +## Address actionable comments + +For each one: + +1. Read the surrounding code (use `path`, `line`, and `diffHunk` from the inline comment payload to locate exactly what they're pointing at). +2. Read the comment carefully — reviewers often link to other code, paste suggested diffs, or reference related comments. Honor suggested diffs (`suggestion` blocks) when they're correct. +3. Make the change with `Edit`. +4. Track in a running list: `{ commentId, threadId, file, line, what_changed }`. + +**Don't batch-edit blindly.** Each comment is a separate decision. If two comments contradict, ask the user. + +After all changes, run a quick sanity pass: +- Run the project's type checker on touched files (e.g. `tsc --noEmit`, `bun typecheck`, `npx tsc`) +- If the change touches tests or business logic the user explicitly cited, run the relevant test file + +Commit the changes locally with a clear message: + +```bash +git add +git commit -m "$(cat <<'EOF' +review: address feedback from PR # + + + +Co-Authored-By: Claude +EOF +)" +``` + +**Do not push.** The user reviews and pushes. + +## Reply to comments + +Reply when it adds value for *other reviewers* — not just for the original commenter: + +- **Worth replying:** explanation of the fix's approach (esp. if non-obvious), pointer to the commit/line where the fix landed, "good catch — also fixed the same issue in X", a "won't fix because Y" rationale, or answers to direct questions. +- **Skip the reply:** trivial typo fixes, formatting nits, anything where the diff itself is self-explanatory. + +Post a reply to a specific inline comment: + +```bash +gh api -X POST "repos/$OWNER/$REPO/pulls/$NUM/comments/$COMMENT_ID/replies" \ + -f body="" +``` + +For a thread-level reply via GraphQL: + +```bash +gh api graphql -f query=' + mutation($threadId:ID!, $body:String!) { + addPullRequestReviewThreadReply(input:{pullRequestReviewThreadId:$threadId, body:$body}) { + comment { id url } + } + }' -F threadId="$THREAD_ID" -f body="$BODY" +``` + +Keep replies short. One or two sentences. Reference the commit SHA when useful (`fixed in abc1234`). + +## Resolve threads + +Resolve a thread once it's handled (code changed + optional reply posted), or once the user has explicitly said "won't fix" with a reply explaining why. + +```bash +gh api graphql -f query=' + mutation($threadId:ID!) { + resolveReviewThread(input:{threadId:$threadId}) { + thread { id isResolved } + } + }' -F threadId="$THREAD_ID" +``` + +**Do not resolve threads:** +- That you didn't address. +- That are still pending user input. +- That belong to a reviewer who explicitly requested the author resolve them — ask first if you see that pattern. + +## Ambiguous / human-in-the-loop items + +Before posting the summary, surface anything that needs the user: + +- Comments you classified as ambiguous → list them with the comment URL + a one-line description, and ask what to do. +- Suggestions you disagreed with → state your reasoning and ask whether to push back, accept, or punt. +- Out-of-scope items → propose the follow-up issue title/body and ask before opening. + +Wait for user response. **Do not guess on these.** + +## Post the summary comment + +After all decisions are made and changes committed, post one summary comment to the PR. Format: + +```markdown +## Review feedback addressed + +Thanks for the review! Here's what was addressed in : + +### Fixed +- **`path/to/file.ts:42`** — ([comment](url)) +- **`path/to/other.ts:88`** — ([comment](url)) + +### Won't fix (with rationale) +- **`path/to/x.ts:10`** — ([comment](url)) + +### Follow-up +- Opened # for ([comment](url)) +``` + +Post it with: + +```bash +gh pr comment $NUM --body "$(cat <<'EOF' + +EOF +)" +``` + +Skip the summary if there were ≤2 small items handled — individual replies suffice. + +## Hard rules + +- **Never push** the resulting commit. The user reviews and pushes. +- **Never close, merge, approve, or dismiss-review** the PR. +- **Never delete or edit other people's comments.** +- **Never resolve a thread you didn't address** or that is awaiting user input. +- **Never post the summary comment before the user has confirmed any ambiguous items.** +- **Never silently disagree** — if a reviewer's suggestion is wrong, post a reply explaining why and let them respond. +- **Don't batch-resolve at the end** — resolve each thread immediately after addressing it. +- **If `gh` returns 403 / 404**, the user likely needs to re-auth (`gh auth refresh -s repo,read:org`) or doesn't have write access. Stop and tell them. + +## Reporting + +End-of-skill summary: + +`Addressed N comments on PR # in : K fixed, L replied-only, M won't-fix, P escalated to user. Summary posted. Run tests, then push.` diff --git a/skills/reviews/metadata.json b/skills/reviews/metadata.json new file mode 100644 index 0000000..a944b94 --- /dev/null +++ b/skills/reviews/metadata.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0", + "organization": "Dupe.com", + "author": "Ramin Bozorgzadeh", + "date": "May 2026", + "abstract": "End-to-end GitHub PR review workflow: fetches all review comments and inline threads via REST + GraphQL, triages actionable vs ambiguous items, applies code fixes, posts replies, resolves threads, and summarizes what was addressed in a PR comment. Designed to close review loops without pushing — the human reviews the commit and pushes.", + "references": [ + "https://agentskills.io/specification", + "https://cli.github.com/manual/gh_pr_review", + "https://docs.github.com/en/graphql/reference/mutations#resolvereviewthread" + ], + "compatibility": ["claude-code", "opencode", "cursor", "amp"], + "tags": [ + "github", + "pull-requests", + "code-review", + "workflow", + "git" + ] +}