mcpField
F
fetch-pr-feedback

fetch-pr-feedback

github.com/existential-birdsテスト・品質8568 回インストール11 週間前に更新
リポジトリ

fetch-pr-feedback について

fetch-pr-feedbackは、プルリクエストのコメントを取得し、receive-feedbackスキルで処理するスキルです。レビュー担当者ごとに整理し、既定では作者、現在のユーザー、解決済みスレッドの行コメントを除外します。

主な機能

  1. 01Issueコメントとレビューコメントの取得
  2. 02PR番号または現在のブランチのPRを指定
  3. 03既定で作者と現在のユーザーを除外
  4. 04解決済みスレッドのコメントを任意で含める
  5. 05レビュー担当者ごとにフィードバックを整理

活用シーン

  1. 01現在のブランチのPRへのフィードバック収集
  2. 02指定したPRのコメント確認
  3. 03作者または解決済みスレッドのコメントを含めた確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/existential-birds/beagle --skill fetch-pr-feedback

インストール後、Claude Code で/fetch-pr-feedbackを入力して読み込まれたか確認します。

詳細

PR フィードバックを取得

現在の PR に対するすべてのレビュアーのレビューコメントを取得して整形し、receive-feedback スキルを使用して評価します。デフォルトでは PR 作成者と現在のユーザーを除外します。解決済みのレビュー スレッドに属する行固有のコメントも、デフォルトでは除外されます。

使用方法

fetch-pr-feedback スキルを呼び出します。必要に応じて次のフラグを渡します。

fetch-pr-feedback [--pr <number>] [--include-author] [--include-resolved]

フラグ:

  • --pr <number> - 対象とする PR 番号(デフォルトは現在のブランチの PR)
  • --include-author - PR 作成者自身のコメントを含めます(デフォルトでは除外)
  • --include-resolved - 解決済みのレビュー スレッドに含まれる行固有のコメントを含めます(デフォルトでは除外)

手順

ゲート(順番どおりに実行し、省略しない)

各 Pass when の条件が満たされた後にのみ、次へ進みます。

  1. PR コンテキスト — Pass when: $PR_NUMBER が正の整数に設定され、対象の PR に対する gh pr view / gh api が終了コード 0 で完了していること。または、Get PR Context で指定された失敗メッセージ(“No PR found for current branch…”)のみを出力して停止していること。
  2. 取得 — Pass when: 解決済みスレッドに関する GraphQL 呼び出し(--include-resolved の場合はスキップ)と、ページネーションを使った 2 つの gh api … | jq -s -f … 実行(issue コメントとレビューコメント)が終了コード 0 で、JSON として解析されること(空の [] も有効です)。終了コードが 0 以外、または jq エラーの場合は停止し、コマンドの標準エラー出力を提示してください。コメントを捏造してはいけません。
  3. 整形済み成果物 — Pass when: 出力が次のいずれかであること。(a)Format Feedback Document に一致する Markdown(ヘッダーが # PR #$PR_NUMBER Review Feedback で、レビュアーごとに ## Reviewer: … があり、Summary / Line-Specific の各セクションを含む)、または(b)次の文と完全に一致すること:No review comments found on this PR (excluding PR author, current user, and resolved threads).
  4. receive-feedback の読み込み — Pass when: receive-feedback スキルが読み込まれていること。その後に限り、その整形済みドキュメントに対してスキルの verify → evaluate → execute ループを実行します。
1. 引数を解析する

$ARGUMENTS からフラグを抽出します。

  • --pr <number>、または現在のブランチから検出
  • --include-author フラグ(ブール値、デフォルトは false)
  • --include-resolved フラグ(ブール値、デフォルトは false)
2. PR コンテキストを取得する
# If --pr was specified, use that number directly
# Otherwise, get PR for current branch:
gh pr view --json number,headRefName,url,author --jq '{number, headRefName, url, author: .author.login}'

# Get repo owner/name
gh repo view --json owner,name --jq '{owner: .owner.login, name: .name}'

# Get current authenticated user
gh api user --jq '.login'

$PR_NUMBER、$PR_AUTHOR、$OWNER、$REPO、$CURRENT_USER として保存します。

注: $OWNER、$REPO などはプレースホルダーです。前の手順から実際の値を代入してください。

現在のブランチに PR が存在しない場合は、次のメッセージで失敗とします:--pr を使用して PR 番号を指定してください。

3. コメントを取得する

--include-author が設定されていない限り、$PR_AUTHOR と $CURRENT_USER を除外して、両方の種類のコメントを取得します。--paginate と jq -s を使用して、ページネーションされた JSON 配列を 1 つにまとめます。

--include-resolved が設定されていない場合は、まず、解決済みのレビュー スレッドに属するすべてのレビューコメントの databaseId を取得します。issue コメント(要約/ウォークスルー)はレビュー スレッドの一部ではないため、これは行固有のレビューコメントにのみ適用されます。

解決済みスレッドのコメント ID(--include-resolved が設定されている場合はこのブロック全体をスキップし、代わりに RESOLVED_IDS='[]' を設定します):

RESOLVED_IDS=$(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 {
              isResolved
              comments(first: 100) { nodes { databaseId } }
            }
          }
        }
      }
    }
  ' \
  --jq '[.data.repository.pullRequest.reviewThreads.nodes[]
         | select(.isResolved)
         | .comments.nodes[].databaseId
         | select(. != null)]')

first: 100 の上限で、一般的な PR には対応できます。非常に大きな PR(100 を超えるスレッド、または 1 つのスレッド内に 100 を超えるコメントがある場合)では、スレッドまたはコメント単位のページネーションを追加する必要があります。現時点では、これは既知の制限です。

シェルのエスケープに関する問題を防ぐため、heredoc で単一引用符の区切り文字を使用し、jq フィルターを一時ファイルに書き込みます(!=、正規表現パターン、山括弧のエスケープに関する問題を防ぎます)。

issue コメント(要約/ウォークスルーの投稿):

cat > /tmp/issue_comments.jq << 'JQEOF'
def clean_body:
  gsub(".*?"; ""; "s")
  | gsub(""; ""; "s")
  | gsub("<details>\\s*<summary>\\s*🧩 Analysis chain[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>\\s*🤖 Prompt for AI Agents[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>\\s*📝 Committable suggestion[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>Past reviewee.*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>Recent review details[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>\\s*Tips\\b.*?</details>"; ""; "s")
  | gsub("\\n?\\n---\\n+(?=\\s*(?:✨\\s*Finishing Touches|🪧\\s*Tips?|🤖\\s*Generated|<sub>|_Generated by|Generated by Claude|Generated with))[\\s\\S]*$"; ""; "s")
  | gsub("^\\s+|\\s+$"; "")
  | if length > 4000 then .[:4000] + "\n\n[comment truncated]" else . end
;
[(add // []) | .[] | select(
  .user.login != $pr_author and
  .user.login != $current_user
)] |
map({id, user: .user.login, body: (.body | clean_body), created_at})
JQEOF

gh api --paginate "repos/$OWNER/$REPO/issues/$PR_NUMBER/comments" | \
  jq -s --arg pr_author "$PR_AUTHOR" --arg current_user "$CURRENT_USER" \
  -f /tmp/issue_comments.jq

レビューコメント(行固有):

cat > /tmp/review_comments.jq << 'JQEOF'
def clean_body:
  gsub(".*?"; ""; "s")
  | gsub(""; ""; "s")
  | gsub("<details>\\s*<summary>\\s*🧩 Analysis chain[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>\\s*🤖 Prompt for AI Agents[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>\\s*📝 Committable suggestion[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>Past reviewee.*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>Recent review details[\\s\\S]*?</details>"; ""; "s")
  | gsub("<details>\\s*<summary>\\s*Tips\\b.*?</details>"; ""; "s")
  | gsub("\\n?\\n---\\n+(?=\\s*(?:✨\\s*Finishing Touches|🪧\\s*Tips?|🤖\\s*Generated|<sub>|_Generated by|Generated by Claude|Generated with))[\\s\\S]*$"; ""; "s")
  | gsub("^\\s+|\\s+$"; "")
  | if length > 4000 then .[:4000] + "\n\n[comment truncated]" else . end
;
[(add // []) | .[] | select(
  .user.login != $pr_author and
  .user.login != $current_user and
  (.id as $comment_id | ($resolved_ids | index($comment_id) | not))
)] |
map({
  id,
  user: .user.login,
  path,
  line_display: (
    .line as $end | .start_line as $start |
    if $start and $start != $end then "\($start)-\($end)"
    else "\($end // .original_line)" end
  ),
  body: (.body | clean_body),
  created_at
})
JQEOF

gh api --paginate "repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments" | \
  jq -s --arg pr_author "$PR_AUTHOR" --arg current_user "$CURRENT_USER" \
  --argjson resolved_ids "$RESOLVED_IDS" \
  -f /tmp/review_comments.jq

--include-author が設定されている場合は、両方の jq フィルターファイルから --arg pr_author パラメーターと .user.login != $pr_author 条件を省略します。いずれの場合も $current_user の除外は維持してください。RESOLVED_IDS='[]'(--include-resolved の場合)では $resolved_ids フィルターが自然に何もしなくなるため、そのまま残してください。

4. フィードバック文書のフォーマット

ノイズの除去 — Step 3 の clean_body jq 関数で処理します。順序が重要です。まず ... ブロックを削除し、次に残りの HTML コメントを削除し、その後、既知のノイズである <details> ブロック(Analysis chain、Prompt for AI Agents、Committable suggestion、Past reviewee、Recent review details、Tips)を削除し、最後に --- のフッター定型文を削除します。ボットの分析チェーンには --- 区切りが含まれているため、実際の指摘が途中で切り詰められないよう、<details> ブロックは --- のフッターパターンより先に削除する必要があります。内容のある <details> ブロック(例:「Suggested fix」、「Proposed fix」)は保持します。削除後に4000文字を超えるコメントは、[comment truncated] マーカーを付けて切り詰めます。

レビュアーごとにグループ化 — フォーマット済みの出力をレビュアーのユーザー名ごとに整理します。

# PR #$PR_NUMBER Review Feedback

## Reviewer: coderabbitai[bot]

### Summary Comments
[Issue comments from this reviewer, each separated by ---]

### Line-Specific Comments
[Review comments from this reviewer, each formatted as:]

**File: `path/to/file.ts:42`**
[cleaned comment body]

---

## Reviewer: another-reviewer

### Summary Comments
...

### Line-Specific Comments
...

どのレビュアーからもコメントが見つからない場合は、次のように出力します。「この PR にはレビューコメントが見つかりませんでした(PR 作成者、現在のユーザー、および解決済みのスレッドを除く)。」

5. receive-feedback による評価

receive-feedback スキルを読み込みます。

その後、フォーマット済みのフィードバック文書を処理します。

  1. フォーマット済みの文書から、対応が必要な各項目を解析します
  2. 各項目を verify → evaluate → execute の順に処理します
  3. 構造化された応答の要約を作成します

例

# Fetch unresolved reviewer comments on current branch's PR (default)
fetch-pr-feedback

# Fetch from a specific PR
fetch-pr-feedback --pr 123

# Include PR author's own comments
fetch-pr-feedback --include-author

# Include line-specific comments from resolved review threads
fetch-pr-feedback --include-resolved

# Combined
fetch-pr-feedback --pr 456 --include-author --include-resolved

コメント