# Resolve All Gh Pr Comments

> |

- **Type:** Skill
- **Install:** `agentstack add skill-vinhnxv-rune-resolve-all-gh-pr-comments`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [vinhnxv](https://agentstack.voostack.com/s/vinhnxv)
- **Installs:** 0
- **Category:** [Communication](https://agentstack.voostack.com/c/communication)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [vinhnxv](https://github.com/vinhnxv)
- **Source:** https://github.com/vinhnxv/rune/tree/main/plugins/rune/skills/resolve-all-gh-pr-comments

## Install

```sh
agentstack add skill-vinhnxv-rune-resolve-all-gh-pr-comments
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Resolve All GitHub PR Comments

Batch-resolve all unresolved PR review comments — both review thread comments (line-level)
and issue comments (PR-level from bots). Supports pagination for large PRs, hallucination
checking for bot findings, and grouped batch processing.

## Prerequisites

- `gh` CLI installed and authenticated
- Current directory is a git repository with a GitHub remote
- PR exists and has unresolved comments

## Phase 0: Parse Arguments & Resolve PR

```
INPUT: $ARGUMENTS → PR number or empty (auto-detect)

if $ARGUMENTS is empty:
  prNumber = Bash("GH_PROMPT_DISABLED=1 gh pr view --json number -q '.number' 2>/dev/null")
  if prNumber is empty:
    AskUserQuestion("No PR found for current branch. Please provide a PR number.")
    exit
else:
  prNumber = parseInt($ARGUMENTS)

# Validate PR number is a positive integer
if prNumber does not match /^[1-9][0-9]*$/:
  error("Invalid PR number: must be a positive integer")
  exit
```

## Phase 1: Resolve Repository & Configuration

```
# CONCERN 5: Explicitly extract owner/repo for GraphQL
owner = Bash("GH_PROMPT_DISABLED=1 gh repo view --json owner -q '.owner.login'")
repo = Bash("GH_PROMPT_DISABLED=1 gh repo view --json name -q '.name'")

if owner is empty or repo is empty:
  error("Cannot resolve repository owner/name. Ensure gh CLI is configured.")
  exit

# v3.x: defaults baked from former v2.x talisman config (arc.ship.bot_review); see references/v3-defaults.md
BATCH_SIZE = 10
AUTO_RESOLVE_OUTDATED = true
HALLUCINATION_CHECK = true
KNOWN_BOTS = [
  "gemini-code-assist[bot]",
  "coderabbitai[bot]",
  "copilot[bot]",
  "cubic-dev-ai[bot]",
]
QUALITY_COMMANDS = []
```

## Phase 2: Checkout PR Branch

```
# Checkout the PR branch to have the correct code context
Bash("GH_PROMPT_DISABLED=1 gh pr checkout ${prNumber}")
```

## Phase 3: Paginated Fetch — Write to Tmp Files

Fetch ALL comments to tmp files to avoid loading everything into context at once. Uses GraphQL cursor pagination (`$endCursor`) for review threads and REST pagination for issue/review comments.

```
outputDir = "tmp/pr-comments/${prNumber}"
Bash("mkdir -p '${outputDir}'")
```

See [paginated-fetch.md](references/paginated-fetch.md) for the full GraphQL and REST pagination protocol.

## Phase 4: Categorize from Tmp Files

Extract and categorize using `jq` — never load all comments into agent context.

```
# Build bot login regex pattern for jq
botPattern = KNOWN_BOTS
  .map(b => b.replace("[", "\\[").replace("]", "\\]"))
  .join("|")

# 4a. Extract unresolved, non-outdated review threads
Bash("jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false and .isOutdated == false)]' '${outputDir}/review-threads.json' > '${outputDir}/unresolved-threads.json'")

# 4b. Extract outdated threads (candidates for auto-resolve)
Bash("jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false and .isOutdated == true)]' '${outputDir}/review-threads.json' > '${outputDir}/outdated-threads.json'")

# 4c. Extract bot issue comments
Bash("jq '[.[] | select(.user.login | test(\"${botPattern}\"))]' '${outputDir}/issue-comments.json' > '${outputDir}/bot-issue-comments.json'")

# 4d. Extract bot review comments (inline)
Bash("jq '[.[] | select(.user.login | test(\"${botPattern}\"))]' '${outputDir}/review-comments.json' > '${outputDir}/bot-review-comments.json'")

# 4e. Count categories
unresolvedCount = Bash("jq 'length' '${outputDir}/unresolved-threads.json'").trim()
outdatedCount = Bash("jq 'length' '${outputDir}/outdated-threads.json'").trim()
botIssueCount = Bash("jq 'length' '${outputDir}/bot-issue-comments.json'").trim()
botReviewCount = Bash("jq 'length' '${outputDir}/bot-review-comments.json'").trim()

log("Found: ${unresolvedCount} unresolved threads, ${outdatedCount} outdated, ${botIssueCount} bot issue comments, ${botReviewCount} bot review comments")
```

## Phase 5: Auto-Resolve Outdated Threads

```
if AUTO_RESOLVE_OUTDATED and outdatedCount > 0:
  # Resolve each outdated thread via GraphQL mutation
  Bash("jq -r '.[].id' '${outputDir}/outdated-threads.json' | while read tid; do
    # Validate thread ID format before interpolation
    if echo \"$tid\" | grep -qE '^[A-Za-z0-9_=-]+$'; then
      GH_PROMPT_DISABLED=1 gh api graphql -f query=\"mutation { resolveReviewThread(input: {threadId: \\\"$tid\\\"}) { thread { isResolved } } }\" 2>/dev/null
    fi
  done")
  log("Auto-resolved ${outdatedCount} outdated review threads.")
```

## Phase 6: Batch-Process Bot Comments

Process comments in batches of BATCH_SIZE to protect context window. Merges bot issue comments + unresolved threads into a single actionable list, splits into batches, then verifies and classifies each comment. Includes hallucination check algorithm that verifies bot findings against actual code (file existence, line validity, recent commits, code analysis).

See [batch-process.md](references/batch-process.md) for the full batch processing and hallucination check protocol.

## Phase 7: Present Analysis to User

```
# Group results by verdict
validFindings = allResults.filter(r => r.verdict.verdict == "VALID")
falsePositives = allResults.filter(r => r.verdict.verdict == "FALSE_POSITIVE")
alreadyAddressed = allResults.filter(r => r.verdict.verdict == "ALREADY_ADDRESSED")
notApplicable = allResults.filter(r => r.verdict.verdict == "NOT_APPLICABLE")
needsReview = allResults.filter(r => r.verdict.verdict == "NEEDS_REVIEW")

# Present summary
log("## Comment Analysis Summary")
log("- Valid findings (will fix): ${validFindings.length}")
log("- False positives (will dismiss): ${falsePositives.length}")
log("- Already addressed: ${alreadyAddressed.length}")
log("- Not applicable: ${notApplicable.length}")
log("- Needs manual review: ${needsReview.length}")

# For each group that needs user input, present details
if needsReview.length > 0:
  for each group of related needsReview comments:
    AskUserQuestion("How should I handle these comments?\n${groupDetails}\n\nOptions: fix / dismiss / skip")
    # Record user decision

if validFindings.length > 0:
  AskUserQuestion("Found ${validFindings.length} valid bot findings. Proceed with fixes?\n${validSummary}")
```

## Phase 8: Implement Fixes

```
# 8a. Collect all approved fixes (valid + user-approved)
fixPlan = buildFixPlan(validFindings, approvedNeedsReview)

# 8b. Group by file to minimize Edit operations
fixesByFile = groupBy(fixPlan, 'file')

# 8c. Implement fixes file by file
for each [file, fixes] in fixesByFile:
  Read(file)
  for each fix in fixes (sorted by line descending to avoid offset drift):
    Edit(file, fix.oldCode, fix.newCode)

# 8d. Run quality checks (once, after all fixes)
for each cmd in QUALITY_COMMANDS:
  result = Bash(cmd)
  if result.exitCode != 0:
    warn("Quality check failed: ${cmd}")
    AskUserQuestion("Quality check '${cmd}' failed. Continue anyway?")

# 8e. Single commit + push
Bash("git add -A && git commit -m 'fix: resolve PR review comments from bot feedback'")
Bash("git push")
commitSha = Bash("git rev-parse HEAD").trim()
```

## Phase 9: Reply to Resolved Comments

```
# 9a. Reply to review thread comments
for each fix in resolvedThreadFixes:
  # Validate thread ID format
  threadId = fix.comment_id
  if threadId matches /^[A-Za-z0-9_=-]+$/:
    # Post reply on the review thread
    Bash("GH_PROMPT_DISABLED=1 gh api graphql -f query='mutation {
      addPullRequestReviewComment(input: {
        pullRequestReviewId: \"${fix.review_id}\",
        body: \"Addressed in ${commitSha}\",
        inReplyTo: \"${fix.comment_id}\"
      }) { comment { id } }
    }'")
    # Resolve the thread
    Bash("GH_PROMPT_DISABLED=1 gh api graphql -f query='mutation {
      resolveReviewThread(input: {threadId: \"${threadId}\"}) {
        thread { isResolved }
      }
    }'")

# 9b. Reply to bot issue comments
for each fix in resolvedIssueCommentFixes:
  commentId = fix.comment_id
  if commentId matches /^[0-9]+$/:
    Bash("GH_PROMPT_DISABLED=1 gh api repos/${owner}/${repo}/issues/comments/${commentId}/replies -f body='Addressed in ${commitSha}'")

# 9c. Reply to dismissed/false-positive comments
for each dismissed in falsePositives:
  Bash("GH_PROMPT_DISABLED=1 gh api ... -f body='Reviewed and dismissed: ${dismissed.reason}'")
```

## Phase 10: Summary Report

```
summary = """
# PR Comment Resolution Summary

PR: #${prNumber}
Repository: ${owner}/${repo}

## Statistics
- Outdated threads auto-resolved: ${outdatedCount}
- Valid findings fixed: ${validFindings.length}
- False positives dismissed: ${falsePositives.length}
- Already addressed: ${alreadyAddressed.length}
- Not applicable: ${notApplicable.length}
- Manually reviewed: ${needsReview.length}
- Commit: ${commitSha}

## Fixes Applied
${fixPlan.map(f => "- ${f.file}:${f.line} — ${f.summary}").join('\n')}

## Dismissed Findings
${falsePositives.map(f => "- ${f.author}: ${f.body.slice(0, 80)}... — ${f.reason}").join('\n')}
"""

Write("${outputDir}/summary.md", summary)
log(summary)
```

## Security Constraints

- **SEC-DECREE-003**: All `gh` commands prefixed with `GH_PROMPT_DISABLED=1`
- **Input validation**: PR number validated as positive integer before shell interpolation
- **Thread ID validation**: GraphQL thread IDs validated with `/^[A-Za-z0-9_=-]+$/` before mutation
- **Bot name validation**: Known bot names baked into the skill, escaped for regex
- **No context overload**: Comments written to tmp files and processed in BATCH_SIZE batches
- **Quality commands**: Empty by default in v3.x; baked literal at top of skill

## Defaults (v3.x)

Behavior is hardcoded in v3.x — no user config layer. See `references/v3-defaults.md`.

| Key | Value | Description |
|-----|-------|-------------|
| `BATCH_SIZE` | `10` | Comments per processing batch |
| `AUTO_RESOLVE_OUTDATED` | `true` | Auto-resolve outdated review threads |
| `HALLUCINATION_CHECK` | `true` | Verify bot findings against actual code |
| `KNOWN_BOTS` | 4 bots | gemini-code-assist, coderabbitai, copilot, cubic-dev-ai |
| `QUALITY_COMMANDS` | `[]` | Reserved — runs no commands by default |

## Error Handling

| Error | Action |
|-------|--------|
| `gh` not installed | Exit with instructions to install GitHub CLI |
| PR not found | Exit with clear error message |
| GraphQL rate limit | Retry with exponential backoff (max 3 attempts) |
| Quality check fails | AskUserQuestion — user decides to continue or abort |
| No actionable comments | Exit cleanly with summary (no fixes needed) |
| Pagination timeout | Write partial results, process what was fetched |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [vinhnxv](https://github.com/vinhnxv)
- **Source:** [vinhnxv/rune](https://github.com/vinhnxv/rune)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-vinhnxv-rune-resolve-all-gh-pr-comments
- Seller: https://agentstack.voostack.com/s/vinhnxv
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
