feat: improve resolve-pr-feedback skill (#379)

This commit is contained in:
Trevin Chow
2026-03-25 16:51:45 -07:00
committed by GitHub
parent efa798c52c
commit 2ba4f3fd58
9 changed files with 567 additions and 219 deletions

View File

@@ -0,0 +1,87 @@
#!/usr/bin/env bash
set -e
if [ $# -lt 1 ]; then
echo "Usage: get-pr-comments PR_NUMBER [OWNER/REPO]"
echo "Example: get-pr-comments 123"
echo "Example: get-pr-comments 123 EveryInc/cora"
exit 1
fi
PR_NUMBER=$1
if [ -n "$2" ]; then
OWNER=$(echo "$2" | cut -d/ -f1)
REPO=$(echo "$2" | cut -d/ -f2)
else
OWNER=$(gh repo view --json owner -q .owner.login 2>/dev/null)
REPO=$(gh repo view --json name -q .name 2>/dev/null)
fi
if [ -z "$OWNER" ] || [ -z "$REPO" ]; then
echo "Error: Could not detect repository. Pass OWNER/REPO as second argument."
exit 1
fi
# Fetch review threads, regular PR comments, and review bodies in one query.
# Output is a JSON object with three keys:
# review_threads - unresolved, non-outdated inline code review threads
# pr_comments - top-level PR conversation comments (excludes PR author)
# review_bodies - review submissions with non-empty body text (excludes PR author)
gh api graphql -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUMBER" -f query='
query FetchPRFeedback($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
author { login }
reviewThreads(first: 100) {
edges {
node {
id
isResolved
isOutdated
path
line
comments(first: 50) {
nodes {
id
author { login }
body
createdAt
url
}
}
}
}
}
comments(first: 100) {
nodes {
id
author { login }
body
createdAt
url
}
}
reviews(first: 50) {
nodes {
id
author { login }
body
state
createdAt
url
}
}
}
}
}' | jq '.data.repository.pullRequest as $pr | {
review_threads: [$pr.reviewThreads.edges[]
| select(.node.isResolved == false and .node.isOutdated == false)],
pr_comments: [$pr.comments.nodes[]
| select(.author.login != $pr.author.login)
| select(.body | test("^\\s*$") | not)],
review_bodies: [$pr.reviews.nodes[]
| select(.body != null and .body != "")
| select(.author.login != $pr.author.login)]
}'

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Maps a PR review comment node ID to its parent thread.
# Fetches thread IDs and first comment IDs to find the match,
# then returns the matching thread with full comment details.
set -e
if [ $# -lt 2 ]; then
echo "Usage: get-thread-for-comment PR_NUMBER COMMENT_NODE_ID [OWNER/REPO]"
echo "Example: get-thread-for-comment 378 PRRC_kwDOP_gZVc6ySv89"
exit 1
fi
PR_NUMBER=$1
COMMENT_NODE_ID=$2
if [ -n "$3" ]; then
OWNER=$(echo "$3" | cut -d/ -f1)
REPO=$(echo "$3" | cut -d/ -f2)
else
OWNER=$(gh repo view --json owner -q .owner.login 2>/dev/null)
REPO=$(gh repo view --json name -q .name 2>/dev/null)
fi
if [ -z "$OWNER" ] || [ -z "$REPO" ]; then
echo "Error: Could not detect repository. Pass OWNER/REPO as third argument."
exit 1
fi
gh api graphql -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUMBER" -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
id
isResolved
path
line
comments(first: 100) {
nodes {
id
author { login }
body
createdAt
url
}
}
}
}
}
}
}' | jq -e --arg cid "$COMMENT_NODE_ID" '
[.data.repository.pullRequest.reviewThreads.nodes[]
| select(.comments.nodes | map(.id) | index($cid))]
| if length == 0 then error("No thread found for comment \($cid)") else .[0] end
'

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Replies to a PR review thread. Body is read from stdin to avoid
# shell escaping issues with markdown (quotes, newlines, etc.).
set -e
if [ $# -lt 1 ]; then
echo "Usage: echo 'reply body' | reply-to-pr-thread THREAD_ID"
echo "Example: echo 'Addressed: added null check' | reply-to-pr-thread PRRT_kwDOABC123"
exit 1
fi
THREAD_ID=$1
BODY=$(cat)
if [ -z "$BODY" ]; then
echo "Error: No body provided on stdin."
exit 1
fi
gh api graphql -f threadId="$THREAD_ID" -f body="$BODY" -f query='
mutation ReplyToReviewThread($threadId: ID!, $body: String!) {
addPullRequestReviewThreadReply(input: {
pullRequestReviewThreadId: $threadId
body: $body
}) {
comment {
id
url
}
}
}'

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -e
if [ $# -eq 0 ]; then
echo "Usage: resolve-pr-thread THREAD_ID"
echo "Example: resolve-pr-thread PRRT_kwDOABC123"
exit 1
fi
THREAD_ID=$1
gh api graphql -f threadId="$THREAD_ID" -f query='
mutation ResolveReviewThread($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread {
id
isResolved
path
line
}
}
}'