# Pr Comment Fix

> pr-comment-fix: PRレビューコメント自動修正

- Skill: `shotaiuchi/pr-comment-fix-2` (Agent Skill)
- Install (CLI): `npx skillmds@latest add shotaiuchi/pr-comment-fix-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shotaiuchi/pr-comment-fix-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ShotaIuchi (https://skillmd.com/u/shotaiuchi)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/shotaiuchi/pr-comment-fix-2

---


# pr-comment-fix: PRレビューコメント自動修正

プルリクエストからレビューコメントを取得し、各コメントを評価して、対応すべきものを修正し、`commit` スキル経由でコミットしてプッシュまで行う。定期実行（自動モード）とユーザーによる単独実行の両方を想定して設計されている。

## モード判定

このスキルには2つの実行モードがある。ワークフローは共通だが、曖昧な状況の扱いが異なる。

| モード | 起動条件 | 動作 |
|------|---------|------|
| **auto** | `$ARGUMENTS` に `--auto` または単独の `auto` を含む | ユーザーには一切確認しない。曖昧な状況は最も安全な選択肢で自律的に解決する。 |
| **manual** | デフォルト（autoフラグなし） | 基本は自律的に動作する。本当にユーザーの判断が必要な場合（例: 複数コメントが矛盾する設計を提案）のみ確認する。 |

パース前に `$ARGUMENTS` から auto フラグを取り除く。その他のフラグ（`--repo`、`--author <login>`（複数指定可）、`--include-drafts`）については Step 1 を参照。

## Step 1 — 対象PRの特定

このスキルは4つのターゲティングモードをサポートする。残りの引数からどのモードを適用するか決定し、処理対象のPRリストを構築する。

### ターゲティングモード

| モード | 起動条件 | 処理対象 |
|------|---------|--------|
| **single** | PR番号、`#N`、または PR URL が指定されている | そのPR1件のみ |
| **repo** | `--repo` フラグ指定（PR識別子なし） | カレントリポジトリの全オープンPR |
| **branch** | PR識別子も `--repo` フラグも無し | カレントブランチに紐づくPR（あれば） |
| **filtered repo** | `--repo` ＋ 1個以上の `--author <login>` | リポジトリ内のオープンPRのうち、指定ユーザーいずれかが作者のもの |

`--author` は複数指定可（例: `--author alice --author bob`）。PR の `author.login` フィールドと照合する。

### 自然言語引数

`$ARGUMENTS` は厳密なフラグ形式である必要はない。自然言語も解釈する。ユーザーは以下のように言うことがある:

- `自分のPRだけ` / `me` / `私の` / `my prs` → `gh api user --jq .login` でカレントユーザーのGitHub loginを解決し、`--author <login>` として扱う
- `aliceとbobのPR` / `alice and bob` → `alice`、`bob` を作者として抽出
- `リポジトリ全体` / `all open PRs` / `repo` → repoモードに設定
- `ドラフトも含めて` / `include drafts` → `--include-drafts` を設定
- `#123` / `PR 123` / `認証のPR` → singleモード。「認証のPR」のような曖昧な参照は `gh pr list` を実行してタイトルからベストマッチを選ぶが、**autoモード**では推測するより失敗させる方を優先する

自然言語が使われた場合、実行開始時に**解決されたスコープをエコーバック**して、ユーザーがどう解釈されたか確認できるようにする（例: `Scope: repo, authors=[shotaiuchi, alice], drafts=excluded`）。**manualモード**で解釈が本当に曖昧な場合は事前に確認する。**autoモード**では最も保守的な解釈を選んでログに残す。

`--include-drafts` フラグはドラフトPRを処理対象に含めるかを制御する。**デフォルトはドラフト除外**。`--include-drafts` 指定時はドラフトを通常PRと同じく扱う。これは **single** モード以外に適用される — ユーザーが特定のPRを明示的に指定した場合、ドラフト状態に関わらず処理する（明示的な指定そのものが意図表明）。

### repo / filtered-repo / branch モードでのPR列挙

`gh pr list` を適切なフィルタ付きで使用する。下流で必要なフィールドを含める:

```bash
gh pr list \
  --state open \
  --json number,headRefName,baseRefName,url,isDraft,author,title \
  --limit 100
```

その後コードで:
- `--include-drafts` が無ければドラフトを除外
- `--author` フラグが指定されていれば `author.login ∈ <author list>` でフィルタ
- **branch** モードでは `headRefName` がカレントブランチに一致するPRに限定

結果のリストが空の場合:
- **autoモード**: スコープをログに出して（例: `pr-comment-fix: 0 open PRs in scope (repo=<repo>, authors=<list>, drafts=<bool>)`）正常終了する。これはcron実行の正常な「やることなし」結果。
- **manualモード**: 空であることを報告して停止する。フィルタを暗黙に拡大しない。

### single モード: 識別子のパース

| 入力 | 動作 |
|------|------|
| `123` または `#123` | 現在のリポジトリでPR番号 `123` を使用 |
| `https://github.com/owner/repo/pull/123` | URLから owner、repo、番号を抽出 |

スコープ内の各PRについて、メタデータ（head ref、base ref、リポジトリ、ドラフト状態、作者）を取得しておく。コメント取得、ブランチ切り替え、プッシュで使用する。

### 複数PRの処理

スコープが2件以上のPRを返した場合、**並列ではなく逐次**処理する — 各PRはブランチチェックアウト・修正適用・コミット・プッシュを伴うため、並列化するとワーキングツリーが破綻する。各PRについて:

1. PRブランチをチェックアウト: `gh pr checkout <number>` （PRヘッドを追跡するローカルブランチを作成/更新する）
2. そのPRに対して本スキルの Step 2〜8 を実行
3. Step 8 完了後、次のPRへ進む

PRのチェックアウトが失敗した場合（ローカル変更との競合など）、**autoモード**ではそのPRをスキップして理由をログに記録、**manualモード**では停止して報告する。実行終了時（中断時も含めて）は必ず元のブランチを復元する。ユーザーの作業状態を別PRブランチに残さないため:

```bash
ORIGINAL_BRANCH=$(git branch --show-current)
# ... PRを処理 ...
git checkout "$ORIGINAL_BRANCH"
```

ワーキングツリーに未コミット変更がある状態で複数PRフローを開始することは拒否する — 他ブランチへのチェックアウトが上書きまたはブロックされてしまうため。**autoモード**はログを出して終了、**manualモード**はユーザーにstashまたはコミットを依頼する。

## Step 2 — 全種類のコメントを取得

プルリクエストのフィードバックは3つの異なるAPIに分散している。漏れがないよう全て取得すること。**resolved/outdated コメントも含めて取得する** — 「解決済み」スレッドにも未対応のサブポイントが残っている可能性があるため、ユーザーは全件考慮を望んでいる。

```bash
# 1. インラインレビューコメント（行に紐づく、スレッド化されている）
gh api repos/<owner>/<repo>/pulls/<num>/comments --paginate

# 2. レビューサマリー本文（Approved / Changes Requested / Commented）
gh api repos/<owner>/<repo>/pulls/<num>/reviews --paginate

# 3. Issue形式のPR会話コメント
gh api repos/<owner>/<repo>/issues/<num>/comments --paginate
```

すべてのコメントを以下の内部構造に正規化する:

```json
{
  "id": "<api id>",
  "source": "inline | review_body | issue",
  "author": "<login>",
  "author_type": "user | bot",
  "path": "<ファイルパスまたはnull>",
  "line": "<行番号またはnull>",
  "body": "<本文>",
  "created_at": "<iso>",
  "in_reply_to": "<idまたはnull>",
  "resolved": true | false,
  "outdated": true | false,
  "html_url": "<リンク>"
}
```

スレッドにグループ化されたインラインコメントは、**スレッド全体**を1単位として扱い、リプライまで読んだ上で対応を決める。

## Step 3 — 既処理コメントのフィルタリング

このスキルを繰り返し（特に定期実行で）安全に動かすために、すでに対応済みのコメントは再処理しないようにする。「対応済み」の判定は次の方法で行う。

1. **gitログ検索**: 各コメントについて、最近のコミットメッセージがその `html_url` または `id` を参照しているかを確認する。`commit` スキルはチケットIDをメッセージに書き込み、本スキルは Step 6 でコメントURLを追記するので、過去の実行を以下で発見できる:
   ```bash
   git log --since="60 days ago" --grep="<コメントidまたは短縮url>" --oneline
   ```
2. **マッチしたらスキップ**: コメントを参照するコミットがカレントブランチ上に存在する場合、それ以上評価せずスキップする。

このフィルタリングは分類の**前**に行い、対応済みコメントは評価対象にすら入れない。

## Step 4 — 残りのコメントを分類

各コメント（またはスレッド）について、コード変更が必要かどうかを判断し、以下のいずれかに分類する。

| クラス | 定義 | アクション |
|--------|------|----------|
| `actionable` | コード変更、バグ修正、リネーム、リファクタ、テスト追加など具体的な変更要求 | Step 5 で修正 |
| `question` | 説明や「なぜXにしたのか？」など説明を求める質問 | **スキップ + ログ** |
| `discussion` | 具体的な変更要求のない設計議論 | **スキップ + ログ** |
| `lgtm` | 承認、「looks good」、「nice work」、絵文字のみ | **スキップ + ログ** |
| `bot` | botアカウントによる投稿（`author_type == "bot"`、または既知のbotログイン） | **スキップ + ログ** |
| `already_done` | 現在のコード状態で既にコメントの要望が満たされている（ファイルを読んで検証） | **スキップ + ログ** |
| `unclear` | 何を求められているか不明 | **auto**: スキップ + ログ。**manual**: ユーザーに確認。 |

プロジェクト方針として、**非アクション系クラスはすべて静かにスキップする** — 質問や議論への自動返信はしない。後でユーザーがレビューできるよう、実行ログに記録するだけに留める。

## Step 5 — Actionable コメントの調査と修正

`actionable` の各コメントについて、(a) 何を求められているか理解し、(b) 要求された変更が正しいことを確認し、(c) 適用する必要がある。盲目的に変更しないこと — レビュアーの提案がコードベースの別の部分や別のコメントと矛盾することがある。

### 調査

各 actionable コメントについて:

1. **参照されたコードを読む** — `path:line` とその周辺コンテキスト。
2. **矛盾するコメントがないか確認** — 同じ行に対して2つのコメントが異なる提案をしている場合、より新しいか、より文脈のある方に基づいて判断する。曖昧な場合は、**manualモード**ではユーザーに確認。**autoモード**ではより安全/保守的な選択肢を採用し、衝突をログに記録する。
3. **影響範囲を追跡** — 要求された変更に波及効果はあるか？ あるなら同じ修正で対処する必要がある。

複雑なケース（複数ファイル、設計変更）では、インラインで追跡せずExploreエージェントを spawn する。これによりメインコンテキストを保護できる。

### 修正の適用

実際のコード変更を行う。コメントが要求した内容に最小限・焦点を絞った変更とする — 過剰修正や周辺コードのリファクタはしない。各修正後に:

- プロジェクトに lint/build/test コマンドが存在し、かつ高速なら（30秒未満）実行する。遅い場合はCIに任せる。
- 修正でテストが壊れた場合、テストを通すためにテストをスキップ・改変するのではなく、**実装を修正する**。

### 修正失敗時の処理

修正が適用できない場合（コードが移動した、要求がアーキテクチャ変更レベル、合理的なリトライ後も無関係なテストが壊れる）:

- **autoモード**: そのコメントをスキップし、理由とともに失敗をログに記録し、次のコメントに進む。実行全体を中断しない。
- **manualモード**: 中断してユーザーに状況を報告してから先へ進む。

## Step 6 — `commit` スキル経由でコミット

Step 5 のすべての修正適用後（または論理的グループごとに、下記参照）、`commit` スキルを呼び出してコミットを作成する。

### コミットのタイミング

`commit` スキルの自然な分割動作を活用して修正を論理的なコミットに分ける — 同スキルはステージ済み変更を分析し、意味ごとにグループ化する。手順:

1. Step 5 の修正をすべてステージする: `git add -A` （ただし**このスキルが変更したファイルのみ**に限定する。無関係なユーザー作業を巻き込まないよう、修正対象を逐次トラッキングする）。
2. Skill ツール経由で `commit` スキルを呼び出す: `Skill(skill: "commit")`。

### コミットメッセージへの注釈

`commit` スキルが各コミットを作成した直後に、対応したコメントへのリンクをトレーラーとして追加する。これにより Step 3 の「既処理」フィルタが次回実行時に機能する。

各コミット直後に `git commit --amend` でトレーラーブロックを追加する:

```
Addresses-PR-Comment: <html_url 1>
Addresses-PR-Comment: <html_url 2>
```

（コメント1件につき1行。トレーラー名は `git log --grep` で検索可能。）

### auto / manual でのID扱い

`commit` スキルはブランチ名やPRからチケットIDを既に判定するので、そのまま渡すだけでよい — 本スキルで特別な扱いは不要。理由:

- **autoモード**では、`commit` スキルがIDを判定できない場合通常はユーザーに確認する。しかしこのスキルは自律実行のため、ブロックではなくID無しで進めるよう commit スキルに指示する。サポートしていれば Skill ツールの引数で `Skill(skill: "commit", args: "--auto")` のように渡す。サポートしていなければ呼び出し前にIDを事前解決して引数で渡す。
- **manualモード**では `commit` を通常通り動作させる — 最終手段としてのみユーザーに確認する設計になっており、本スキルの「本当に必要な時だけ確認する」方針と一致する。

`commit` スキルが `--auto` をサポートしていない場合は、commit 呼び出し前に PR番号 / ブランチのチケットIDを自分で検出し、同じソースから commit にも自動検出させる方式にフォールバックする。

## Step 7 — プッシュ

コミットが成功したら、リモート追跡ブランチへ無条件にプッシュする:

```bash
git push
```

プロジェクト方針として、本スキルは保護チェックなしで常に**カレントブランチ**へプッシュする。upstream が無いために `git push` が失敗したら、明示的に設定する:

```bash
git push -u origin <カレントブランチ>
```

リモートに新しいコミットがあって（誰かがpushして）プッシュが拒否された場合、**autoモード**では実行を中断し衝突をログに残す — force-push や自動rebaseは**しない**。**manualモード**ではユーザーに状況を報告してどう進めるか確認する。

## Step 8 — 実行サマリー

すべて完了したら簡潔なレポートを書く。autoモードでもレポートは出力する — スケジュールジョブのログに残る。

複数PRを処理した場合は、PRごとにセクションを出力した上でトップレベルの集計ブロックを付ける。単一PR実行では集計ブロックは省略してよい。

```markdown
# PR Comment Fix Run

**スコープ**: single | repo | branch | filtered repo (authors=<list>, drafts=<bool>)
**モード**: auto | manual
**処理PR数**: N（チェックアウト失敗で M 件スキップ）

## PR #123 — <タイトル>
**ブランチ**: <head ref>

### 修正済み (N)
| コメント | ファイル | コミット |
|---------|------|--------|
| <短縮url> | path:line | <commit sha> |

### スキップ (M)
| コメント | クラス | 理由 |
|---------|-------|------|
| <短縮url> | lgtm | 承認のみ、対応不要 |
| <短縮url> | already_done | コードが既に要望どおり |

### 失敗 (K)
| コメント | 理由 |
|---------|------|
| <短縮url> | 修正後にテストが壊れ、2回リトライ後失敗 |

### プッシュ
- N コミットを origin/<ブランチ> へプッシュ

<!-- 複数PR実行時はPRごとに繰り返す -->
```

autoモードでスコープ内の対応すべきコメントが**ゼロ件**だった場合も、スケジュールジョブのハートビート用に1行サマリーを出力する: `pr-comment-fix: scope=<repo|branch|...>, N PRs, 0 actionable comments, nothing to do.`

## Tips

- **冪等性**は autoモードで決定的に重要。Step 3 のフィルタが無いと、同じコメントが繰り返し「修正」されてしまう。cronで運用する前に実際の実行でフィルタをテストすること。
- 複数のリプライがあるコメントスレッドでは、**最新**のコメントが現時点での要望を表していることが多い。古いメッセージは陳腐化していることがある。
- 「Xを検討してみては」というレビュアーの提案は「Yであるべき」より柔らかい。具体的な変更を記述している場合のみ `actionable` として扱い、それ以外は `discussion` としてログする。
- 1つのコメントのために多くのファイルを変更したくなったら、立ち止まって考え直す — そのコメントは恐らく、このブランチ上の散漫な修正ではなく別PRに値する深い問題を指している。

