diff --git a/.serena/project.yml b/.serena/project.yml index bdc18918..a1257bd8 100644 --- a/.serena/project.yml +++ b/.serena/project.yml @@ -1,39 +1,4 @@ -# list of languages for which language servers are started (LSP backend only); choose from: -# ada al angular ansible bash -# bsl clojure cpp cpp_ccls crystal -# csharp csharp_omnisharp cue dart elixir -# elm erlang fortran fsharp gdscript -# go groovy haskell haxe hlsl -# html java json julia kotlin -# latex lean4 lua luau markdown -# matlab msl nix ocaml pascal -# perl php php_phpactor php_phpantom powershell -# python python_jedi python_pyrefly python_ty r -# rego ruby ruby_solargraph rust scala -# scss solidity svelte swift systemverilog -# terraform toml typescript typescript_vts vue -# yaml zig -# (This list may be outdated; generated with scripts/print_language_list.py; -# For the current list, see values of Language enum here: -# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py) -# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) -# Note: -# - For C, use cpp -# - For JavaScript, use typescript -# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) -# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) -# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) -# - For Free Pascal/Lazarus, use pascal -# Special requirements: -# Some languages require additional setup/installations. -# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers -# When using multiple languages, the first language server that supports a given file will be used for that file. -# The first language is the default language and the respective language server will be used as a fallback. -# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. -languages: -- bash - # the encoding used by text files in the project # For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings encoding: "utf-8" @@ -43,6 +8,13 @@ ignore_all_files_in_gitignore: true # list of additional paths to ignore in this project. # Same syntax as gitignore, so you can use * and **. +# Important: quote patterns that start with `*`, otherwise YAML treats them as aliases. +# Example: +# ignored_paths: +# - "examples/**" +# - ".worktrees/**" +# - "**/bin/**" +# - "**/obj/**" # Note: global ignored_paths from serena_config.yml are also applied additively. ignored_paths: [] @@ -166,3 +138,38 @@ activation_command: # maximum time in seconds to wait for activation_command to complete before killing it (default 180s). # must be a positive number. activation_command_timeout: 180.0 + +# list of language servers to start when using the LSP backend; choose from: +# ada al angular ansible bash +# bsl clojure cpp cpp_ccls crystal +# csharp csharp_omnisharp cue dart elixir +# elm erlang fortran fsharp gdscript +# go groovy haskell haxe hlsl +# html java json julia kotlin +# latex lean4 lua luau markdown +# matlab msl nix ocaml pascal +# perl php php_phpactor php_phpantom powershell +# python python_basedpyright python_jedi python_pyrefly python_ty +# qml r rego ruby ruby_solargraph +# rust scala scss solidity svelte +# swift systemverilog terraform toml typescript +# typescript_vts vue yaml zig +# (This list may be outdated; generated with scripts/print_language_list.py; +# For the current list, see values of the LanguageServerId enum here: +# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py) +# For some languages, there are several alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) +# Note: +# - For C, use cpp +# - For JavaScript, use typescript +# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) +# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) +# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) +# - For Free Pascal/Lazarus, use pascal +# Special requirements: +# Some language servers require additional setup/installations. +# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers +# When using multiple language servers, the first language server that supports a given file will be used for that file. +# The first language server is the default language and the respective language server will be used as a fallback. +# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. +language_servers: +- bash diff --git a/.serena/serena_config.yml b/.serena/serena_config.yml index 3411fe6b..b9ba4eff 100644 --- a/.serena/serena_config.yml +++ b/.serena/serena_config.yml @@ -103,6 +103,7 @@ projects: # list of paths to ignore across all projects. # Same syntax as gitignore, so you can use * and **. # These patterns are merged additively with each project's own ignored_paths. +# Quote patterns that start with `*`, e.g. `"**/bin/**"`. ignored_paths: [] # time budget (seconds) per tool call for the retrieval of additional symbol information @@ -191,7 +192,22 @@ jetbrains_launch_command: # - /home/user/projects/** # - C:\Users\Anna\Dev\work\** # The pattern "**" matches any project path, so it can be used to trust all projects. -# NOTE: リポジトリにコミットする設定では信頼対象を空にしておく。 -# 任意の project.yml の trusted 限定設定(activation_command / ls_specific_settings 等)を -# 無条件に受け入れないようにするため。信頼が必要な場合は各自のローカル設定で指定する。 trusted_project_path_patterns: [] + +# mapping from language server keys to integer priority values (higher = more preferred), which determine +# language server selection during automatic project creation and are used to break ties when multiple +# language servers match an equal number of source files. +# The priority values override Serena's default priorities: +# * 0 = experimental or secondary language servers, which are never auto-detected +# (e.g. `python_*` and `php_*` are "secondary"; also applies to non-programming languages like `json`) +# * 1 = supersets of other languages, which shall be preferred only if they match more files +# (e.g. `vue` and `svelte`, which are supersets of `typescript`) +# * 2 = default priority +# Example: +# ls_priorities: +# python: 0 +# python_basedpyright: 3 +# This example would achieve that `python_basedpyright` becomes the preferred language server for Python, +# giving it a high priority of 3, while the default Python language server is fully excluded from +# auto-detection with priority 0. +ls_priorities: diff --git a/README.md b/README.md index bd206e4b..ad8381b4 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ Claude Code / Codex / Kiro CLI向けのスキル・MCP設定を共有するた **NDFプラグイン v4.20.1** は、同じ `ndf@ai-plugins` という名前で Claude Code / Codex / Kiro CLI へ配布されるランタイム別プラグインです。共通ソースは `plugins/ndf-shared/` に集約し、利用者が install する配布物は `plugins/ndf-claude/` / `plugins/ndf-codex/` / `plugins/ndf-kiro/` に分かれています。 -- **公開Skills**: Claude Code向け core 27個、Kiro向け core 26個、Codex向け core 27個に分離。 -- **元Skills(36個)**: - - PR/レビューワークフロー (12): pr, pr-tests, fix, review, review-branch, review-pr-comments, resolve-pr-comments, cherry-pick-pr, deploy, sync-main, merged, clean +- **公開Skills**: Claude Code向け core 24個、Kiro向け core 23個、Codex向け core 24個に分離。 +- **元Skills(33個)**: + - PR/レビューワークフロー (9): pr, pr-tests, fix, review, cherry-pick-pr, deploy, sync-main, merged, clean - 原則・ガイドライン (10): ndf-policies, branch-fix-strategy, implementation-plan, plan-to-spec, investigation-rules, problem-solving, logging-guidelines, markdown-writing, issue-plan-strategy, ml-model-structure - データ分析・品質・環境 (5): qa-security-scan, docker-container-access, google-auth, codex, official-skills-autoloader - E2Eテスト/Playwright (4): playwright-planning, playwright-authoring, playwright-evidence, playwright-kit-ops @@ -100,7 +100,7 @@ kiro-cli chat | プラグイン名 | バージョン | 説明 | 詳細 | |------------|----------|------|------| -| **ndf** | 4.20.1 | Claude Code / Codex / Kiro CLI 向けに runtime 別配布物を提供する NDF プラグイン。8個の専門エージェント(Claude版)、公開Skills(Claude Code向け core 29個、Kiro向け core 28個、Codex向け core 30個)、Claude SessionStart/Stopフック、Codex/Kiro向け通知・実行補助を提供。v4.0.0 で Codex MCP サーバを廃止し、`/ndf:codex` skill + `corder` エージェント経由の CLI 直接実行に一本化。 | [Claude](./plugins/ndf-claude/README.md) / [Codex](./plugins/ndf-codex/README.md) / [Kiro](./plugins/ndf-kiro/README.md) | +| **ndf** | 4.20.1 | Claude Code / Codex / Kiro CLI 向けに runtime 別配布物を提供する NDF プラグイン。8個の専門エージェント(Claude版)、公開Skills(Claude Code向け core 26個、Kiro向け core 25個、Codex向け core 27個)、Claude SessionStart/Stopフック、Codex/Kiro向け通知・実行補助を提供。v4.0.0 で Codex MCP サーバを廃止し、`/ndf:codex` skill + `corder` エージェント経由の CLI 直接実行に一本化。 | [Claude](./plugins/ndf-claude/README.md) / [Codex](./plugins/ndf-codex/README.md) / [Kiro](./plugins/ndf-kiro/README.md) | ### NDF v4.20.1 の主な変更 diff --git a/docs/ndf-plugin-reference.md b/docs/ndf-plugin-reference.md index ae45ae91..37d1ccac 100644 --- a/docs/ndf-plugin-reference.md +++ b/docs/ndf-plugin-reference.md @@ -64,7 +64,7 @@ NDF の Skill 実装は `plugins/ndf-shared/skills/` が編集元です。公開 主な Skill 領域: -- PR / review workflow: `pr`, `pr-tests`, `fix`, `review`, `cross-review`, `resolve-pr-comments` +- PR / review workflow: `pr`, `pr-tests`, `fix`, `review`, `cross-review` - branch / release workflow: `deploy`, `cherry-pick-pr`, `sync-main`, `merged`, `clean` - planning / documentation: `implementation-plan`, `issue-plan-strategy`, `plan-to-spec`, `markdown-writing` - quality / execution: `playwright-*`, `docker-container-access` diff --git a/plugins/ndf-claude/.claude-plugin/plugin.json b/plugins/ndf-claude/.claude-plugin/plugin.json index 74efe800..ed834739 100644 --- a/plugins/ndf-claude/.claude-plugin/plugin.json +++ b/plugins/ndf-claude/.claude-plugin/plugin.json @@ -46,9 +46,6 @@ "./skills/sync-main", "./skills/cherry-pick-pr", "./skills/deploy", - "./skills/review-branch", - "./skills/review-pr-comments", - "./skills/resolve-pr-comments", "./skills/playwright-authoring", "./skills/codex", "./skills/gemini", diff --git a/plugins/ndf-claude/skills/cross-review/SKILL.md b/plugins/ndf-claude/skills/cross-review/SKILL.md index 034dae4f..21223ddd 100644 --- a/plugins/ndf-claude/skills/cross-review/SKILL.md +++ b/plugins/ndf-claude/skills/cross-review/SKILL.md @@ -468,10 +468,9 @@ pint / larastan / test / build などは **中断** を原則とする。 ## 関連 - `/ndf:review` — 単発レビュー(AI 直接投稿対応) -- `/ndf:fix` — 修正対応(サブエージェント起動対応) +- `/ndf:fix` — 指摘の分類・修正・返信・Resolve(サブエージェント起動対応) - `/ndf:codex` — codex CLI 呼び出し手順 - `/ndf:gemini` — gemini CLI 呼び出し手順 -- `/ndf:resolve-pr-comments` — Resolve Conversation の詳細 - `/ndf:issue-plan-strategy` — multi-PR ワークフローでは **個別 PR ごとに本 cross-review が原則必須**。 `/ndf:review` 単発や Claude Code の `code-reviewer` は代替にせず、release ブランチへ merge する前に codex + gemini の APPROVE 収束を確認する (Step 6) diff --git a/plugins/ndf-claude/skills/fix/SKILL.md b/plugins/ndf-claude/skills/fix/SKILL.md index 92471ddd..e6c85ee3 100644 --- a/plugins/ndf-claude/skills/fix/SKILL.md +++ b/plugins/ndf-claude/skills/fix/SKILL.md @@ -1,8 +1,8 @@ --- name: fix -description: "Fix actionable PR review comments." -when_to_use: "PRレビューコメント (codex/gemini/人間) の指摘を実際にコード修正で対応したいとき。review-pr-comments で分類した後の修正フェーズに使う。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PR fix', 'review feedback fix', 'コメントに対応して修正'" -argument-hint: "[PR番号] [--defer-nit] [--severity-min critical|major|minor]" +description: "Classify PR review comments, fix the actionable ones, then reply and resolve each thread. Use when responding to PR review feedback from codex, gemini, bots, or humans." +when_to_use: "PR レビューコメントへの対応全般。分類だけしたいときは --classify-only。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR fix', 'classify PR comments', 'コメントに対応して修正', 'Resolveして'" +argument-hint: "[PR番号] [--classify-only] [--defer-nit] [--severity-min critical|major|minor]" allowed-tools: - Bash - Read @@ -12,17 +12,37 @@ allowed-tools: - Grep --- -# PR修正コマンド +# PR コメント対応コマンド -直前PR、または引数で指定されたPRのreview comment確認・修正対応実行。 +指定 PR(省略時は直前 PR)のレビューコメントを **分類 → 修正 → 返信 → Resolve** まで +一貫して処理する。 + +## 引数 + +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | 対象 PR | 直前 PR | +| `--classify-only` | **分類・優先度判定のみ**で終了する(読み取り専用)。修正・返信・Resolve は行わない | OFF | +| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | +| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` | + +``` +/ndf:fix # 直前 PR のコメントに対応 +/ndf:fix 9352 # PR 番号を指定 +/ndf:fix 9352 --classify-only # まず全体像を把握したいとき +/ndf:fix 9352 --defer-nit # nit を残して critical/major/minor だけ修正 +``` + +大量のコメントがある PR では、`--classify-only` で全体像と優先度を確認してから修正へ +進むと、修正範囲の判断を誤りにくい。 ## 起動モード -このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** の両方に対応する。 -長丁場のクロスレビューループ(`/ndf:cross-review`)からは **必ずサブエージェント経由で起動** されることを想定: +このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** +の両方に対応する。長丁場のクロスレビューループ(`/ndf:cross-review`)からは +**必ずサブエージェント経由で起動** されることを想定する。 ```python -# メインからの起動例(cross-review が内部でこれを行う) Agent( subagent_type="general-purpose", description="Fix PR review comments (sub-agent)", @@ -41,263 +61,284 @@ PR: **修正 → コミット → push → reply → Resolve Conversation** まで実行する。 メインへの戻り値は最小限のサマリのみ。 -## 引数 +## コメントの取得(3 ソース) -| 引数 | 意味 | 既定 | -|---|---|---| -| `[PR番号]` | 対象 PR | 直前 PR | -| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | -| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` (= minor 以上を修正) | +インラインコメント / レビュー body / PR レベルコメントを一括取得する。 +どれか 1 つでも欠けると指摘を取りこぼす。 + +`$ARGUMENTS` には PR 番号とオプションが混在するため、**そのまま PR 番号として扱わない**。 +数値トークンだけを PR 番号として取り出し、`--` で始まるトークンはオプションとして解釈する。 -## 重要度ベースの自動修正ポリシー +```bash +# PR 番号 = 最初の数値トークン。無ければ直前 PR +PR_NUMBER=$(printf '%s\n' "$ARGUMENTS" | tr ' ' '\n' | grep -m1 -E '^[0-9]+$' || true) +PR_NUMBER="${PR_NUMBER:-$(gh pr view --json number --jq .number)}" + +# オプションは $ARGUMENTS から個別に判定する +case " $ARGUMENTS " in *" --classify-only "*) CLASSIFY_ONLY=1 ;; esac +case " $ARGUMENTS " in *" --defer-nit "*) DEFER_NIT=1 ;; esac +SEVERITY_MIN=$(printf '%s\n' "$ARGUMENTS" | sed -n 's/.*--severity-min[ =]\([a-z]*\).*/\1/p') +SEVERITY_MIN="${SEVERITY_MIN:-minor}" + +FETCH_SCRIPT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh" +"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" + +# 補助情報 +gh pr view "$PR_NUMBER" --json reviewDecision,body +``` + +GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用する。 + +**PR 本文を必ず読む**。「やらないこと」「別 PR 対応」セクションに記載された内容への +指摘は、この PR では対応しない(分類は「別 PR 対応」)。 + +## 重要度の判定 -`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` 出力規約)で分類。 -**ただし重要度ラベルを鵜呑みにしない** — 各指摘ごとにコード/仕様を独自に調査し、 -本来の重要度を判定し直してから下表の動作を適用する(bot のラベリングは参考値に過ぎない)。 +`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` の出力規約)を手がかりにするが、 +**重要度ラベルを鵜呑みにしない**。各指摘ごとにコード・仕様を独自に調査し、本来の重要度を +判定し直してから下表の動作を適用する。bot のラベリングは参考値に過ぎない。 | 重要度 | 動作 | ユーザ問い合わせ | |---|---|---| | `critical` | **必ず自動修正** | なし | | `major` | **必ず自動修正** | なし | -| `minor` / `nit` (パフォーマンス・可読性・重複コード排除) | **このPRで修正対応**。特にトータル行数が減る方向の修正は積極的に実施 | なし | -| `minor` / `nit` (上記カテゴリ、修正範囲が +30 行を超えそう) | ユーザ問い合わせ | あり | -| `minor` (その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred 扱い | なし | -| `nit` (その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加。最後にまとめてユーザ問い合わせ | あり(最後に1回) | +| `minor` / `nit`(パフォーマンス・可読性・重複コード排除) | **この PR で修正**。特にトータル行数が減る方向の修正は積極的に実施 | なし | +| `minor` / `nit`(上記カテゴリ、修正範囲が +30 行を超えそう) | deferred | あり | +| `minor`(その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred | なし | +| `nit`(その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加 | あり(最後に 1 回) | **重要度の独自判定**: -- AI agent (CodeRabbit / Copilot 等) が `nit` と付けていても、実体がパフォーマンス改善や重複排除なら **minor/nit カテゴリ修正対象** として扱う -- 逆に AI agent が `critical` と付けていても、実害がないスタイル指摘なら `nit` 相当に格下げして deferred 化してよい -- 重要度はカテゴリ(performance/readability/duplication/security/style/etc)と合わせて、コード本体を読んだ上で判定する +- AI agent(CodeRabbit / Copilot 等)が `nit` と付けていても、実体がパフォーマンス改善や + 重複排除なら修正対象として扱う +- 逆に `critical` と付いていても、実害がないスタイル指摘なら `nit` 相当に格下げしてよい +- 重要度はカテゴリ(performance / readability / duplication / security / style 等)と + 合わせて、コード本体を読んだ上で判定する **指摘の正否判断**: -- ロジック・仕様逸脱・セキュリティ: コード/仕様を確認してから修正可否判断 -- bot 指摘で **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘する等): 修正しない、reply で理由説明 -- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象(critical でもエスカレーション) - -**自動判断できない場合の取り扱い** (context 節約のため安易に user に投げない): -- 仕様文書(docs/, README)を読んで判断する -- 既存テストを読んで挙動を確認する -- 関連する他コードの慣例を確認する -- それでも不明なら deferred リストに「要ユーザ判断」として記録、最後にまとめて問い合わせ - -## 手順 - -1. review comment取得 + 重要度を**独自に再判定**(AI agent のラベルは参考値) -2. **CIエラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) - - **完了待ちはしない**。実行中(PENDING/IN_PROGRESS)のチェックは無視して次ステップへ進む - - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む -3. 修正対象を確定: - - `critical` / `major` → 全件修正対象 - - `minor` / `nit` (パフォーマンス・可読性・重複排除) → 修正対象。+30行超なら **deferred + ユーザ問い合わせ** - - `minor` (その他) → 修正対象(明らかでないものは `deferred[]` へ) - - `nit` (その他、`--defer-nit` 時) → `deferred[]` のみ、修正しない - - CIエラー → 全件修正対象(PRテスト範囲外の **flaky テストも見つけ次第修正**) -4. 問題点修正 - - **コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去 等) -5. **コミット前の再確認**(修正作業中に状況が変わっている可能性への対応) - - **review comment再取得**: 作業中に新しいコメントが追加されていないか確認 - - **CI状態再確認**: 現時点の状態だけ確認(完了待ちはしない)。新しい失敗が出ていれば対象に取り込む - - 新しい指摘/失敗があれば手順3に戻る -6. コミット・プッシュ -7. PRにSummaryコメントを追加(対応した件数 + deferred 件数を明記) -8. 対応したインラインコメントに個別に返信 -9. **deferred スレッドには `[deferred / nit]` のラベル付き返信** を投稿(resolve はしない) -10. reviewerに再レビューを依頼 -11. 対応完了したインラインコメントを「Resolve Conversation」にする(`resolveReviewThread` mutation) - - resolve した thread_id / comment_id / path / line を `resolved_threads[]` に記録 - - `deferred` / `rejected` の thread は Resolve しない(次ラウンドで再評価するため) -12. **戻り値ファイルを書き出す**: `/tmp/fix-pr<番号>-result.json` (後述「戻り値フォーマット」参照) - - `ci_failed_checks` には `gh pr checks --json name,state` から `state=FAILURE` の name を抽出して列挙 - - push 直後の CI 再実行結果は**待たない**ため、戻り値の `ci_status` は push 時点での既知失敗のみを反映する +- ロジック・仕様逸脱・セキュリティ: コード / 仕様を確認してから修正可否を判断 +- bot 指摘が **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘): + 修正せず reply で理由を説明(`rejected` として記録、Resolve しない) +- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象 -- 4〜6はgit、1〜2/5と7以降はgithub mcpまたはghを利用 +**自動判断できない場合**(context 節約のため安易にユーザへ投げない): +仕様文書(`docs/`, `README`)を読む → 既存テストを読んで挙動を確認する → 関連する他コードの +慣例を確認する。それでも不明なら deferred リストに「要ユーザ判断」として記録し、最後に +まとめて問い合わせる。 -**flakyテストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第このPRで修正する。 -flaky を放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれるため。 +## `--classify-only` の出力 -## CIエラーチェック +修正は一切行わず、次の形式で分類結果だけを報告する。 -### 失敗ジョブの検出 +| カテゴリ | 説明 | 対応判断 | +|---|---|---| +| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | +| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | +| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | +| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | +| 🔵 別 PR 対応 | PR 本文で別 PR 対応と明記されている内容 | **対応不要** | + +```markdown +## PR #XXXX コメント分類結果 + +### サマリー +- 総コメント数 / 対応必須 / 対応推奨 / 対応すべき / 対応任意・不要 + +### 詳細 +| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | +|---|---|---|---|---|---| +| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | + +### 推奨アクション +1. 対応すべき項目(重大 + 軽微) +2. 対応推奨項目 +3. 別 PR で対応(コメントで返信推奨) +``` -```bash -# PRの全チェック状態を確認(FAIL/PASS/PENDING) -gh pr checks +分類の根拠(なぜその分類になったか)を簡潔に添える。 -# JSON形式で詳細取得 -gh pr checks --json name,state,link,completedAt +## 修正手順 -# 失敗ジョブのみ抽出 -gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" +1. コメント取得(上記 3 ソース)+ 重要度を**独自に再判定** +2. **CI エラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) + - **完了待ちはしない**。実行中(PENDING / IN_PROGRESS)は無視して次へ進む + - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む +3. 修正対象を確定(「重要度の判定」の表に従う)。CI エラーは全件修正対象 +4. 問題点を修正。**コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去) +5. **コミット前の再確認** — 作業中に新しいコメントが追加されていないか再取得し、CI 状態も + 現時点だけ確認する(完了待ちはしない)。新しい指摘・失敗があれば手順 3 に戻る +6. コミット・プッシュ +7. **PR レベルの Summary コメントを投稿**(対応件数 + deferred 件数を明記) +8. 対応したインラインコメントに個別に返信 +9. **deferred スレッドには `[deferred / nit]` ラベル付き返信** を投稿(Resolve はしない) +10. reviewer に再レビューを依頼 +11. 対応完了したスレッドを **Resolve Conversation** にする +12. **戻り値ファイルを書き出す**(後述) + +**flaky テストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第この PR で +修正する。放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれる。 + +## CI エラーチェック -# 実行中ジョブのみ抽出(状態スナップショット用。完了は待たない) +```bash +gh pr checks # 全チェック状態 +gh pr checks --json name,state,link # JSON 形式 gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state'] in ('PENDING','IN_PROGRESS','QUEUED')]" + python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" ``` -### CI完了待ちはしない +**CI 完了待ちはしない**(`gh pr checks --watch` 等は使わない)。各チェックポイントでは +「現時点で FAILURE のジョブ」のみを取り込む。push 後の CI 再実行結果も待たない。 +ただし状態スナップショットの取得は行い、戻り値の `ci_status` / `ci_failed_checks` に反映する。 -このスキルでは **CI 完了待ちは行わない**(`gh pr checks --watch` 等は使わない)。 -- 各チェックポイントでは「現時点で FAILURE のジョブ」のみを取り込んで修正する -- push 後の CI 再実行結果も待たない(待機中に context を消費しないため) -- ただし `gh pr checks --json name,state` での **状態スナップショット取得は実施** - し、戻り値の `ci_status` / `ci_failed_checks` に反映する - -### 失敗ログの取得 +失敗ログの取得: ```bash -# ワークフロー実行ID取得 RUN_ID=$(gh run list --branch --limit 1 --json databaseId --jq '.[0].databaseId // empty') [ -z "$RUN_ID" ] && { echo "No CI run found for this branch"; exit 0; } - -# 失敗ステップのログだけ表示(効率的) -gh run view $RUN_ID --log-failed - -# 特定ジョブのログ -gh run view $RUN_ID --job --log +gh run view $RUN_ID --log-failed # 失敗ステップのログだけ ``` -### CIエラーの分類と対応方針 - | エラー種別 | 対応方針 | |---|---| | **lint/format** | 自動修正ツール実行(`ruff`, `prettier`, `eslint --fix` 等)→ コミット | | **型チェック** | 型定義・アノテーションを修正。無視コメントは原則禁止(根本対応) | -| **テスト失敗** | 失敗テストを読み、実装/テストどちらが正しいか判断してから修正。テスト側の問題なら仕様確認 | +| **テスト失敗** | 失敗テストを読み、実装 / テストどちらが正しいか判断してから修正 | | **ビルドエラー** | 依存関係・構文・設定ファイルを確認 | | **依存脆弱性** | 可能ならバージョン更新、無理なら除外ルール追加(理由明記) | -| **タイムアウト/flaky** | retry設定、テスト分割、リトライ追加。**PR範囲外の flaky も見つけ次第修正**(放置でリポジトリ全体の品質劣化を招くため) | -| **インフラ一時障害** | 再実行で解消することがあるため `gh run rerun $RUN_ID` を先に試す | +| **タイムアウト/flaky** | retry 設定、テスト分割。**PR 範囲外の flaky も見つけ次第修正** | +| **インフラ一時障害** | `gh run rerun $RUN_ID` を先に試す | -### review指摘との統合 +review 指摘と CI エラーは**同じ PR で一緒に修正**する。同じファイル・機能に関するものは +1 コミットにまとめ、独立しているなら別コミットに分離する。 -review指摘とCIエラーは**同じPRで一緒に修正**する: -- 同じファイル・機能に関する指摘とCIエラーは1コミットにまとめる -- 独立しているなら別コミットに分離(git log で追いやすい) +## 返信と Resolve -## ghコマンド例 +### 返信の書き分け -### PR コメント一括取得 (3 ソース) - -```bash -# インラインコメント / レビュー body / PR レベルコメントを一括取得 -FETCH_SCRIPT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" -``` - -### コメントへの返信 +| 状況 | 返信の型 | +|---|---| +| 修正した | `対応しました — <ファイル>:<行> で〇〇 (commit )` | +| 別 PR で対応 | `別 PR で対応予定です。PR 説明の「やらないこと」に記載のとおり、<理由>` | +| deferred | `[deferred / nit] 後続 PR で対応予定` | +| rejected | `bot 指摘は誤読です — 理由: ...` | +| 対応不要 | `確認しました。<対応不要と判断した理由>` | ```bash -# PRのレビューコメント一覧を取得 (インラインコメントのみ) -gh api repos/{owner}/{repo}/pulls/{pr_number}/comments - -# 特定のコメントに返信(in_reply_to にコメントIDを指定) +# 特定のコメントに返信(in_reply_to にコメント ID を指定) gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ - -f body="修正しました。" \ - -F in_reply_to={comment_id} + -f body="対応しました。" -F in_reply_to={comment_id} ``` ### Resolve Conversation -```bash -# GraphQL APIでスレッドをresolveする -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: "{thread_node_id}"}) { - thread { isResolved } - } - } -' -``` +**修正済みのスレッドのみ** Resolve する。`deferred` / `rejected` は次ラウンドで再評価する +ため Resolve しない。 -### thread_node_idの取得方法 +`resolveReviewThread` が要求するのは **review thread** の ID(`PRRT_...`)であり、 +レビューコメントの `node_id`(`PRRT_` ではなく `PRRC_...`)ではない。 +`repos/{owner}/{repo}/pulls/comments/` から引ける `node_id` はコメント側の ID +なので **Resolve には使えない**。必ず下記 query の `nodes[].id` を使い、 +`comments.nodes[].databaseId`(返信に使ったコメント ID)または本文と突き合わせて特定する。 ```bash -# PRのレビュースレッド一覧を取得(node_id含む) +# スレッド一覧を thread ID (PRRT_...) 付きで取得 gh api graphql -f query=' query { repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {pr_number}) { reviewThreads(first: 100) { nodes { - id - isResolved - comments(first: 1) { - nodes { body } - } + id isResolved path line + comments(first: 1) { nodes { databaseId body } } } } } } - } -' + }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] + | select(.isResolved == false) + | {thread_id: .id, path, line, comment_id: .comments.nodes[0].databaseId}' + +# 上で得た thread_id(PRRT_...)を THREAD_ID に入れて Resolve +gh api graphql -f query=' + mutation($id: ID!) { + resolveReviewThread(input: {threadId: $id}) { thread { isResolved } } + }' -f id="$THREAD_ID" ``` -**方針**: -- 品質・可読性・セキュリティ向上、既存機能影響なし -- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断すること -- 未対応の場合はその理由をコメントに書き込む +### PR レベル Summary コメント(必須) + +インラインへの返信と Resolve **だけでは不十分**。PR ページの Conversation タブに +まとめが出ないと、レビュアー視点で見落とされる。 + +```bash +gh pr comment --body "$(cat <<'EOMD' +## 🔧 /ndf:fix サマリ + +対応件数: critical=X / major=Y / minor=Z (合計 N 件) +deferred: D 件 / rejected: R 件 +commit: +CI: SUCCESS | FAILURE | NONE + +### 詳細 +- 各 thread の対応概要(行リンク付き) +EOMD +)" +``` ## 戻り値フォーマット(必須) -サブエージェント呼び出し時の context 節約のため、**実行結果は `/tmp/fix-pr<番号>-result.json` に書き出す**: +サブエージェント呼び出し時の context 節約のため、**実行結果を +`$TMP_DIR/fix-pr<番号>-result.json` に書き出す**(`$TMP_DIR` は環境変数 +`CROSS_REVIEW_TMP_DIR` があればそれ、なければ `/tmp`)。 ```json { "pr": 67, "fix_commit": "abc1234", - "ci_status": "SUCCESS" | "FAILURE" | "PENDING" | "NONE", + "ci_status": "SUCCESS", "ci_failed_checks": [], "ci_note": null, "fixed_count": 5, "by_severity": {"critical": 1, "major": 2, "minor": 2, "nit": 0}, "resolved_threads": [ - { - "thread_id": "PRRT_...", - "comment_id": 3222849090, - "path": "src/foo.py", - "line": 42 - } + {"thread_id": "PRRT_...", "comment_id": 3222849090, "path": "src/foo.py", "line": 42} ], "deferred": [ - { - "comment_id": 3222849090, - "thread_id": "PRRT_...", - "path": "src/foo.py", - "line": 42, - "severity": "nit", - "category": "style", - "summary": "末尾セミコロンの有無", - "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし" - } + {"comment_id": 3222849090, "thread_id": "PRRT_...", "path": "src/foo.py", "line": 42, + "severity": "nit", "category": "style", "summary": "末尾セミコロンの有無", + "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし"} ], "rejected": [ - { - "comment_id": 3222849090, - "summary": "heredoc を <<'JSON' にせよ", - "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる" - } + {"comment_id": 3222849090, "summary": "heredoc を <<'JSON' にせよ", + "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる"} ], "summary_comment_url": "https://github.com/.../pull/67#issuecomment-..." } ``` -**フィールド説明**: +- `resolved_threads` / `deferred` / `rejected` は **必ず配列**で返す(件数の int は誤り)。 + 該当が無ければ空配列 +- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。 + `/ndf:cross-review` 側で code-related(`pint` / `larastan` / `test` / `build` / `lint` / + `type`)と meta-only(`check_pr_requirements` / `assignees` / `reviewers` / `labels`)を + 分類し、メタチェックのみ失敗ならループを継続する +- `ci_note` — code-related ではない CI 失敗の補足 -- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。`/ndf:cross-review` 側で code-related (`pint/larastan/test/build/lint/type`) と meta-only (`check_pr_requirements/assignees/reviewers/labels`) を分類し、メタチェックのみ失敗ならループ継続する -- `ci_note` — code-related ではない CI 失敗の補足。例: `"メタチェックのみ失敗: check_pr_requirements — Assignees 未設定"` -- `resolved_threads` — 手順 11 で `resolveReviewThread` mutation を実行したスレッド一覧。`deferred` / `rejected` の thread は **Resolve しない**(再評価のため) +## 方針 -サブエージェントとして起動された場合は、この JSON をメインに返すサマリの基礎とする。 +- 品質・可読性・セキュリティ向上を目的とし、既存機能に影響を与えない +- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断する +- 未対応の場合はその理由をコメントに書き込む ## 作業完了報告(必須) -メイン or PR への報告内容(戻り値ファイルから抽出): -- 対応した指摘の件数(重要度別: critical/major/minor/nit) -- **deferred 件数**(主に nit、最後にユーザ問い合わせ予定) -- **rejected 件数**(bot 指摘が不適切で修正しなかった件、各々理由付き) -- **対応したCIエラーの一覧**(ジョブ名、エラー内容、修正方法) -- **対応した flaky テストの一覧**(PR範囲外も含む) -- 修正コミット SHA / 修正ファイル一覧 -- 戻り値ファイルパス: `/tmp/fix-pr<番号>-result.json` -- **PR URL を最後に必ず記載**(例: `https://github.com///pull/<番号>`) +- 対応した指摘の件数(重要度別)/ deferred 件数 / rejected 件数(各々理由付き) +- 対応した CI エラーの一覧(ジョブ名、エラー内容、修正方法) +- 対応した flaky テストの一覧(PR 範囲外も含む) +- 修正コミット SHA / 修正ファイル一覧 / 戻り値ファイルパス +- **PR URL を最後に必ず記載** + +## 関連 + +- `/ndf:review` — PR / ブランチのレビュー(Approve / Request Changes 判定) +- `/ndf:cross-review` — codex + gemini の収束レビュー。内部からこの Skill を呼ぶ diff --git a/plugins/ndf-claude/skills/issue-plan-strategy/SKILL.md b/plugins/ndf-claude/skills/issue-plan-strategy/SKILL.md index add1e621..175939ce 100644 --- a/plugins/ndf-claude/skills/issue-plan-strategy/SKILL.md +++ b/plugins/ndf-claude/skills/issue-plan-strategy/SKILL.md @@ -232,7 +232,7 @@ git worktree add ../--ui feature/-ui | 用途 | コマンド | 位置づけ | |---|---|---| -| PR 作成前のセルフレビュー | `/ndf:review-branch` | push / PR 化の前段。cross-review の代替にはしない | +| PR 作成前のセルフレビュー | `/ndf:review --branch` | push / PR 化の前段。cross-review の代替にはしない | | 個別 PR の収束レビュー (原則必須) | `/ndf:cross-review ` | codex + gemini 両方の APPROVE 収束を確認する本線 | | GitHub 上の例外的な単発確認 | `/ndf:review ` | ごく軽微な差分の単発確認に限定。cross-review の代替にはしない | | 指摘の修正 | `/ndf:fix ` | cross-review ループ内・後で自動起動される | @@ -353,6 +353,6 @@ git checkout release/ - `/ndf:branch-fix-strategy` — ブランチ汚染を避ける原則 - `/ndf:pr` — 通常の PR 作成 / 更新 - `/ndf:cherry-pick-pr` — 検証ブランチへの cherry-pick PR -- `/ndf:review` / `/ndf:review-branch` / `/ndf:cross-review` — レビュー -- `/ndf:fix` / `/ndf:resolve-pr-comments` — コメント対応 +- `/ndf:review` / `/ndf:cross-review` — レビュー(`--branch` で PR 前のセルフレビュー) +- `/ndf:fix` — コメントの分類・修正・返信・Resolve - `/ndf:playwright-planning` — release ブランチでの E2E 結合テスト diff --git a/plugins/ndf-claude/skills/playwright-authoring/SKILL.md b/plugins/ndf-claude/skills/playwright-authoring/SKILL.md index 32754982..3742e685 100644 --- a/plugins/ndf-claude/skills/playwright-authoring/SKILL.md +++ b/plugins/ndf-claude/skills/playwright-authoring/SKILL.md @@ -243,7 +243,7 @@ Chrome DevTools MCP の利用可能な方を自動選択する。どちらも使 - `/ndf:playwright-evidence` — 証跡とレポート (後段) - `/ndf:playwright-kit-ops` — 実行環境の運用 (init_project / codegen / スキャン) - `/ndf:docker-container-access` — Docker コンテナアクセス一般 -- `/ndf:review-branch` — 変更差分のコードレビュー +- `/ndf:review --branch` — 変更差分のコードレビュー - `/ndf:pr-tests` — PR Test Plan の自動実行 > `playwright-planning` / `playwright-evidence` / `playwright-kit-ops` は Codex 公開セットに同梱される。 diff --git a/plugins/ndf-claude/skills/resolve-pr-comments/SKILL.md b/plugins/ndf-claude/skills/resolve-pr-comments/SKILL.md deleted file mode 100644 index 433a72d6..00000000 --- a/plugins/ndf-claude/skills/resolve-pr-comments/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: resolve-pr-comments -description: "Reply to and resolve fixed PR comments." -argument-hint: "[PR番号]" -disable-model-invocation: true -allowed-tools: - - Bash - - Read ---- - -# PRコメントResolveコマンド - -対応済みのPRコメント全てに返信し、スレッドを resolved にする。`/ndf:fix` で修正完了後に呼び出す**クロージング専用**コマンド。 - -## 使用方法 - -``` -/ndf:resolve-pr-comments # 現在のブランチのPRを対象 -/ndf:resolve-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | fix | resolve-pr-comments | -|---|---|---| -| 動作 | コード修正+commit+push | 返信+スレッドresolve | -| 前提 | レビュー後、修正が必要 | 修正済み、クロージングのみ | -| 推奨順序 | 先に実行 | fix後の最後に実行 | - -## 処理フロー - -### 1. PR情報の取得 - -```bash -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 - -GitHub API でレビューコメントを取得: - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" -``` - -### 3. 対応状況の確認 - -各コメントについて、対応済みかどうかを確認する: -- コードの変更履歴(`git log`, `git diff`)と照合 -- 指摘された問題が修正されているか確認 -- PR body の「やらないこと」セクションで別PR対応と明記されているか確認 - -### 4. コメントへの返信 - -対応済みのコメントに対して、内容に応じた返信を投稿する: - -#### 修正対応した場合 -``` -対応しました。 - -{修正内容の簡潔な説明} -``` - -#### 別PRで対応予定の場合 -``` -別PRで対応予定です。 - -PR説明の「やらないこと」に記載の通り、{理由}のため別PRで対応します。 -``` - -#### 対応不要と判断した場合 -``` -確認しました。 - -{対応不要と判断した理由} -``` - -### 5. gh CLI コマンド - -#### レビューコメントに返信(スレッド内) - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" \ - -f body="返信メッセージ" \ - -f in_reply_to= -``` - -#### スレッドをResolve(GraphQL) - -まず Thread Node ID を取得: - -```bash -gh api "repos/:owner/:repo/pulls/comments/" --jq '.node_id' -``` - -その上でResolve: - -```bash -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: ""}) { - thread { isResolved } - } - } -' -``` - -### 6. 実行フロー - -各コメントに対して以下を順次実行: - -1. コメントの内容と対応状況を確認 -2. 適切な返信メッセージを生成 -3. 返信を投稿 -4. スレッドをresolve -5. 結果を報告 - -### 7. 出力フォーマット - -```markdown -## PR #XXXX コメント対応結果 - -### 処理結果 -| # | コメント | 返信内容 | Resolve | -|---|---------|---------|---------| -| 1 | {指摘要約} | 対応しました | ✅ | -| 2 | {指摘要約} | 別PRで対応予定 | ✅ | - -### サマリー -- 処理済み: X件 -- Resolved: X件 -- エラー: X件 -``` - -## 重要ルール - -- **確認してから実行**: 各コメントの対応状況を必ず確認してから返信 -- **コード修正はしない**: 修正は `/ndf:fix` の責務。このコマンドはクロージングのみ -- **適切な返信**: 対応内容に応じた適切な返信メッセージを使用 -- **エラーハンドリング**: API エラー発生時は報告して継続 -- **ユーザー確認**: 判断に迷う場合はユーザーに確認を求める - -## 関連 - -- `/ndf:review-pr-comments` — コメント分類・優先度判定 (READ-ONLY) -- `/ndf:fix` — コメント対応の修正を実施 diff --git a/plugins/ndf-claude/skills/review-branch/SKILL.md b/plugins/ndf-claude/skills/review-branch/SKILL.md deleted file mode 100644 index 951e5ea1..00000000 --- a/plugins/ndf-claude/skills/review-branch/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: review-branch -description: "Review the current branch before opening a PR." -when_to_use: "PR作成前にローカルブランチの実装をセルフレビューしたいとき。Triggers: 'ブランチをレビュー', 'PR前にレビュー', 'セルフレビュー', 'review my branch', 'review before PR', 'self review', 'pre-PR review'" -argument-hint: "[focus-area] (例: security, performance, tests)" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# ブランチ実装レビューコマンド - -現在のブランチで実装された変更を**PR作成前に**コードレビューする。mainブランチとの差分を分析し、コード品質・セキュリティ・パフォーマンスの観点でフィードバックを返す。 - -## `/ndf:review` との使い分け - -| 観点 | review-branch | review | -|---|---|---| -| 対象 | ローカルブランチの差分(PR前) | GitHub上の既存PR | -| 判定 | フィードバックを返す | Approve / Request Changes を判定 | -| 用途 | PR作成前のセルフレビュー | PR作成後のレビュー | - -## 使用方法 - -``` -/ndf:review-branch # 全般レビュー -/ndf:review-branch security # セキュリティに焦点 -/ndf:review-branch performance # パフォーマンスに焦点 -/ndf:review-branch tests # テスト網羅性に焦点 -/ndf:review-branch "ビジネスロジック" # 任意のフォーカス -``` - -## レビュー手順 - -### 1. 変更の把握 - -```bash -git diff main --name-only # 変更ファイル一覧 -git diff main --stat # 差分の統計 -git log main..HEAD --oneline # コミット履歴 -``` - -### 2. 変更内容の分析 - -各変更ファイルに対して以下を確認: - -- **追加・変更されたロジック**: 意図が明確か、正しく実装されているか -- **テストカバレッジ**: 適切なテストが追加されているか -- **コーディング規約**: プロジェクトの規約に準拠しているか - -### 3. 品質チェック観点 - -#### コード品質 -- 命名規則の一貫性 -- 関数/メソッドの責務(単一責任原則) -- DRY原則(重複コードの排除) -- 可読性・保守性 -- 過剰な抽象化がないか(YAGNI) - -#### セキュリティ -- SQLインジェクション対策 -- XSS対策 -- CSRF対策 -- 入力値バリデーション -- 認証・認可の適切性 -- 機密情報(トークン、キー、PII)の取り扱い - -#### パフォーマンス -- N+1 クエリの有無 -- 不要なデータベースアクセス -- メモリ使用量 -- インデックスの活用 - -#### エラーハンドリング -- 例外が適切に捕捉されているか -- ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) -- リトライ/タイムアウトの設計 - -### 4. レビュー結果の報告 - -```markdown -## レビュー結果 - -### 概要 -- 変更ファイル数: X -- 追加行数: +XXX -- 削除行数: -XXX - -### Good(良い点) -- ... - -### Suggestions(改善提案) -- `path/to/file.ext:123` — 提案内容 - -### Issues(要修正) -- `path/to/file.ext:456` — 問題点と修正方針 -``` - -## 使用例 - -```bash -# 全般的なレビュー -/ndf:review-branch - -# セキュリティ重視(認証系変更など) -/ndf:review-branch security - -# N+1クエリ等のパフォーマンス問題に焦点 -/ndf:review-branch performance - -# テストの網羅性を確認 -/ndf:review-branch tests -``` - -## 注意事項 - -- 大量の変更がある場合、重要な変更から優先的にレビューする -- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする -- レビュー結果は提案であり、最終判断は開発者が行う -- **コード修正は行わない**(分析とフィードバックのみ。修正は `/ndf:fix` で別途実行) - -## 関連 - -- `/ndf:review` — PR単位レビュー (Approve/Request Changes判定) -- `/ndf:review-pr-comments` — 既存PRコメントの分類 -- `/ndf:fix` — PRレビューコメントの修正対応 -- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-claude/skills/review-pr-comments/SKILL.md b/plugins/ndf-claude/skills/review-pr-comments/SKILL.md deleted file mode 100644 index 1b51139d..00000000 --- a/plugins/ndf-claude/skills/review-pr-comments/SKILL.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: review-pr-comments -description: "Classify existing PR comments before fixing." -when_to_use: "既存PRのレビューコメントを分類・優先度判定したいとき (修正前)。Triggers: 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR comments review', 'classify PR comments', 'PRレビュー結果を見て'" -argument-hint: "[PR番号]" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# PRコメント分析コマンド (READ-ONLY) - -GitHub PRのレビューコメントを全て確認し、対応可否を判定する。**修正は一切行わない。分析・判定のみ**。 - -## 使用方法 - -``` -/ndf:review-pr-comments # 現在のブランチのPRを対象 -/ndf:review-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | review-pr-comments | fix | -|---|---|---| -| 動作 | 分類・優先度判定のみ | 実際にコード修正 | -| 出力 | 分類テーブル+推奨アクション | 修正差分+commit | -| 推奨順序 | 最初に実行 | review-pr-commentsの結果を見て実行 | - -「まず全体像を把握 → 優先度を決めてから修正」という流れに使う。 - -## 処理フロー - -### 1. PR情報の取得 - -引数でPR番号が指定されていればそれを使用、なければ現在のブランチから取得。 - -```bash -CURRENT_BRANCH=$(git branch --show-current) -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 (3 ソース) - -fix skill の共有スクリプトで インラインコメント / レビュー body / PR レベルコメントを一括取得: - -```bash -FETCH_SCRIPT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" -``` - -補助情報 (reviewDecision 等): - -```bash -gh pr view "$PR_NUMBER" --json reviewDecision -``` - -GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用。 - -### 3. コメント分析・分類 - -各コメントを以下のカテゴリに分類する: - -| カテゴリ | 説明 | 対応判断 | -|---------|------|---------| -| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | -| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | -| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | -| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | -| 🔵 別PR対応 | 別PRで対応予定と明記されている内容 | **対応不要** | - -### 4. 出力フォーマット - -```markdown -## PR #XXXX コメントレビュー結果 - -### サマリー -- 総コメント数: X件 -- 対応必須: X件 -- 対応推奨: X件 -- 対応すべき: X件 -- 対応任意/不要: X件 - -### 詳細 - -| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | -|---|---------|----|---------|----|---------| -| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | -| 2 | ... | ... | ... | ... | ... | - -### 推奨アクション -1. まず対応すべき項目(重大+軽微) -2. 次に対応推奨項目 -3. 別PRで対応(コメントで返信推奨) -``` - -## 重要ルール - -- **READ-ONLY**: コードの修正は一切行わない -- **PR説明文を確認**: 「やらないこと」「別PR対応」セクションに記載されている内容は「🔵 別PR対応」として分類 -- **コンテキスト理解**: コメントが指摘している問題の本質を理解して分類 -- **判断根拠**: なぜその分類になったかの理由を簡潔に説明 - -## 関連 - -- `/ndf:fix` — 分類結果を踏まえてコード修正を実施 -- `/ndf:resolve-pr-comments` — 修正完了後の返信+Resolve -- `/ndf:review` — PRを新規にレビューする (Approve/Request Changes判定) diff --git a/plugins/ndf-claude/skills/review/SKILL.md b/plugins/ndf-claude/skills/review/SKILL.md index 5dfeb4a8..983c4e4a 100644 --- a/plugins/ndf-claude/skills/review/SKILL.md +++ b/plugins/ndf-claude/skills/review/SKILL.md @@ -1,7 +1,8 @@ --- name: review -description: "Review PRs and post approve or changes verdicts." -argument-hint: "[PR番号] [AIエージェント(codex|gemini)]" +description: "Review a PR diff, or the current branch diff with --branch, and post an approve or request-changes verdict." +when_to_use: "PR をレビューするとき、および PR 作成前にローカルブランチをセルフレビューするとき (--branch)。Triggers: 'レビューして', 'PRレビュー', 'マージ前チェック', 'ブランチをレビュー', 'セルフレビュー', 'PR前にレビュー', 'review my branch', 'self review', 'pre-PR review'" +argument-hint: "[PR番号 | --branch] [AIエージェント(codex|gemini)] [--focus AREA]" disable-model-invocation: true allowed-tools: - Bash @@ -10,52 +11,115 @@ allowed-tools: - Grep --- -# PRレビューコマンド +# コードレビューコマンド -直前PR、または引数で指定されたPRを専門家としてレビュー。 +PR 差分、または `--branch` 指定時は現在のブランチの差分を、専門家としてレビューする。 ## 引数 -- 第一引数 `[PR番号]`: レビュー対象のPR番号(省略時は直前のPR) -- 第二引数 `[AIエージェント]`: レビュー実行者(任意) - - 省略時: Claude(自身)でレビュー - - `codex`: Codex CLI に委譲 - - `gemini`: Gemini CLI に委譲 +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | レビュー対象の PR | 直前の PR | +| `--branch` | PR ではなく **ローカルブランチの差分**をレビューする(PR 作成前のセルフレビュー) | OFF | +| `[AIエージェント]` | `codex` / `gemini` に委譲。省略時は Claude 自身 | Claude | +| `--focus AREA` | 重点観点(`security` / `performance` / `tests` / 任意の文字列) | なし | + +``` +/ndf:review # 直前 PR をレビュー +/ndf:review 9352 # PR 番号を指定 +/ndf:review 9352 codex # Codex CLI に委譲 +/ndf:review --branch # ローカルブランチをセルフレビュー +/ndf:review --branch security # セキュリティに焦点を当ててセルフレビュー +``` + +## 2 つのモード -## 実行 +| 観点 | PR モード(既定) | `--branch` モード | +|---|---|---| +| 対象 | GitHub 上の PR 差分 | `git diff <既定ブランチ>` の差分 | +| 出力先 | **PR 上にインラインコメント + 総評を投稿** | セッション上の報告のみ(投稿しない) | +| 判定 | `APPROVE` / `REQUEST_CHANGES` | 判定を出さず改善提案を返す | +| 用途 | PR 作成後のレビュー | PR 作成前のセルフレビュー | -- 問題点・改善点あり → 「Request Changes」 -- 指摘なし → 「Approve」 -- **レビュー結果は必ず GitHub PR 上に投稿する**(後述「レビュー結果の投稿」参照) - - 指摘は可能な限り **コード行に紐付くインラインコメント** として書く - - ファイル横断・設計レベルの所見のみ review body(総評)に書く +**どちらのモードでもコード修正は行わない**(分析と指摘のみ。修正は `/ndf:fix`)。 ## 観点 -言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ -- 上から順に優先して指摘 +言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ。 +上から順に優先して指摘する。 ### 具体的なチェックポイント - **その言語らしい記述方式**: イディオム・標準ライブラリ・言語機能の活用 -- **メモリ効率・演算性能を意識したコード** - - キャッシュ利用 +- **メモリ効率・演算性能** + - キャッシュ利用、不要なループ・コピーの排除 - Python: numpy 利用、内包表記、ジェネレータ - PHP: switch 文の map(連想配列)化 - - 不要なループ・コピーの排除 + - N+1 クエリ、不要なデータベースアクセス、インデックスの活用 - **関数・メソッド・ファイル行数の適正化** - - 目安: 関数/メソッド 50 行、ファイル 300 行 - - ただしプロジェクトの慣例に従う + - 目安: 関数/メソッド 50 行、ファイル 300 行。ただしプロジェクトの慣例に従う + - 単一責任原則から外れていないか - **重複・冗長コードの排除** - PR 範囲にこだわらず積極的にまとめるよう指摘 + - 逆に過剰な抽象化(YAGNI 違反)も指摘する - **柔軟性を損なう定数化の排除** - 数字をそのまま定数にするような硬直化を避ける - 定数よりも DB の master テーブル、または json/yaml による外部化を検討 +- **セキュリティ** + - SQL インジェクション / XSS / CSRF 対策、入力値バリデーション + - 認証・認可の適切性、機密情報(トークン、キー、個人情報)の取り扱い +- **エラーハンドリング** + - 例外が適切に捕捉されているか、リトライ / タイムアウトの設計 + - ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) + +`--focus` が指定された場合は、該当する観点を優先し、他の観点は重大なもののみ指摘する。 + +## `--branch` モードの手順 -## レビュー結果の投稿 +### 1. 変更の把握 + +```bash +git diff main --name-only # 変更ファイル一覧 +git diff main --stat # 差分の統計 +git log main..HEAD --oneline # コミット履歴 +``` + +### 2. 分析 + +各変更ファイルについて、追加・変更されたロジックの意図が明確か、テストが追加されて +いるか、プロジェクトの規約に準拠しているかを、上記「観点」に沿って確認する。 + +### 3. 報告 + +```markdown +## レビュー結果 + +### 概要 +- 変更ファイル数 / 追加行数 / 削除行数 + +### Issues(要修正) +- `path/to/file.ext:456` — 問題点と修正方針 + +### Suggestions(改善提案) +- `path/to/file.ext:123` — 提案内容 +``` + +指摘は重要度の高いものから並べる。良い点の列挙は行わない。 + +### 注意事項 + +- 大量の変更がある場合、重要な変更から優先的にレビューする +- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする +- レビュー結果は提案であり、最終判断は開発者が行う + +## PR モードの手順 レビュー結果は **GitHub の PR レビュー機能** を使って必ず PR 上に書き込む。 -個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ書くのは避ける。 +個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ +書くのは避ける。 + +- 問題点・改善点あり → `REQUEST_CHANGES` +- 指摘なし → `APPROVE` ### 指摘の振り分け @@ -68,17 +132,16 @@ allowed-tools: ### 投稿フロー(推奨: 1 リクエストで一括投稿) -`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を 1 回で送信** する。 +`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を +1 回で送信** する。 ```bash PR= OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) SHA=$(gh pr view "$PR" --json headRefOid -q .headRefOid) -# 1. インラインコメントを JSON 配列で組み立て -# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) -# -# ▼ 推奨: jq -n でシェル変数を安全に流し込む(特殊文字混入時の JSON 破損を防ぐ) +# インラインコメントを JSON 配列で組み立て +# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) SUMMARY=$'## 総評\n\n... 全体所見をここに ...' jq -n \ --arg sha "$SHA" \ @@ -96,13 +159,13 @@ jq -n \ ] }' > /tmp/review-payload.json -# 2. Reviews API に POST gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload.json ``` -> 💡 **JSON 組み立てに heredoc (`< JSON が壊れる(あるいはクオート未エスケープで JSON injection になる)。`jq -n --arg` 経由なら値が自動で -> JSON エスケープされるため安全。クオート付き heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 +> 💡 **JSON 組み立てに heredoc (`< 特殊文字が混入した場合 JSON が壊れる(あるいはクオート未エスケープで JSON injection に +> なる)。`jq -n --arg` 経由なら値が自動で JSON エスケープされるため安全。クオート付き +> heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 **`event` の値**: - `APPROVE` — 指摘なし @@ -120,18 +183,22 @@ gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload [nit / スタイル] スペースが揃っていない。 ``` -重要度の目安: -- `critical` — セキュリティ・データ破損・本番障害につながる -- `major` — 保守性 / 性能 / 仕様逸脱の重要問題 -- `minor` — 改善推奨だがブロッカーではない -- `nit` — 好み・スタイル +### 重要度の運用ガイド(auto-fix 判定に直結) + +| 重要度 | 定義 | 後段(`/ndf:fix`)の扱い | +|---|---|---| +| `critical` | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | +| `major` | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | +| `minor` | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | +| `nit` | 好み・スタイル | **修正しない**、最後にユーザ判断にまとめる | + +過剰な nit 量産は避ける。critical / major で対応すべき真の問題に集中すること。 ### 既存コメントがある場合の重複防止 同じ箇所への二重指摘を避けるため、投稿前に既存コメントを確認する: ```bash -# 既存のレビューコメント一覧 gh api "repos/$OWNER_REPO/pulls/$PR/comments" --paginate \ | jq -r '.[] | "\(.path):\(.line) \(.body | split("\n")[0])"' ``` @@ -150,153 +217,102 @@ gh pr comment "$PR" --body "..." # 1 件だけインラインコメントを追加(既存 review に含めない) gh api -X POST "repos/$OWNER_REPO/pulls/$PR/comments" \ - -F commit_id="$SHA" \ - -F path="src/foo.py" \ - -F line=42 -F side=RIGHT \ - -F body="..." + -F commit_id="$SHA" -F path="src/foo.py" -F line=42 -F side=RIGHT -F body="..." ``` -## 外部AIへの委譲手順 +## 外部 AI への委譲 -第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」の内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 +第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「PR モードの手順」の +内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 -### 共通: プロンプト組み立て +呼び出し手順の詳細は、利用 runtime に `/ndf:codex` / `/ndf:gemini` skill が同梱されて +いる場合はその skill に従う。同梱されていない runtime では以下の要点に従う。 -1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` で PR メタ情報を取得 -2. `gh pr diff ` で差分を取得(または変更ファイル一覧 + 必要箇所を `gh pr view --json files` 経由で抽出) -3. 上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」セクションをそのままプロンプトに転記 -4. PR タイトル・URL・差分を **対象情報** として明記 -5. **出力は GitHub Reviews API のペイロード形式(JSON)で出させる**(後述「外部AIに必須化する出力形式」参照) - -### 外部AIに必須化する出力形式と直接投稿 +**`codex` 指定時** -**外部AIは Reviews API ペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する**。 -(旧版では生成した JSON をメインに返してメインが投稿していたが、メイン context 消費と往復回数が無駄なので削除) +- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し +- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** +- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 +- `grep -q '^tokens used$' err` で完了検知 +- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 -メインに返すのは「投稿が成功したか」「最終 verdict (event)」「review URL」「件数」の小さな結果サマリのみ。 +> ⚠️ `--dangerously-bypass-approvals-and-sandbox` は codex のサンドボックスを完全に無効化し、 +> 任意のシェル実行・ファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の +> 外部隔離環境内** でのみ使用すること。ホスト直接実行や本番リポジトリでは使わない。 -#### プロンプトに必ず含める指示(テンプレート) +**`gemini` 指定時** -```markdown -## 出力形式と投稿手順(必須) +- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し +- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) +- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示する +- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 +- `kill -0 $PID` ポーリングで完了検知(codex と異なり sentinel 不要 / プロセス exit を見る) +- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 -レビュー結果は以下の手順で **あなた自身が PR に投稿** してください。 -メイン側に返すのは投稿結果サマリだけです。 +> ⚠️ `--yolo` も同様に外部隔離環境内でのみ実行する。プロンプトでの「リポジトリ編集禁止」明示は必須だが、 +> sandbox の代替にはならない。 -### 1. ペイロード組み立て +### プロンプト組み立て -以下の JSON を `/tmp/-review-pr<番号>-payload.json` に書き出す -(codex なら `apply_patch`、gemini なら `write_file` を使用): +1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` でメタ情報を取得 +2. `gh pr diff ` で差分を取得 +3. 上記「観点」「PR モードの手順」をそのままプロンプトに転記 +4. PR タイトル・URL・差分を **対象情報** として明記 +5. **出力は Reviews API のペイロード形式(JSON)で出させ、外部 AI 自身に投稿させる** -\`\`\`json -{ - "commit_id": "", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "body": "## 総評\n\n...(設計レベル・PR全体所見のみ)...", - "comments": [ - { - "path": "src/foo.py", - "line": 42, - "side": "RIGHT", - "body": "[major / 可読性] ..." - } - ] -} -\`\`\` - -ルール: -- 個別指摘は必ず `comments[]` のインラインコメントにすること(行を絞れない場合はファイル代表行) -- `body` (総評) には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 -- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける(critical/major/minor/nit) -- `path` は **PR差分に登場するファイルのみ**(事前に `gh pr diff --name-only` で取得した一覧から選ぶ) -- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` がデフォルト -- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +### 外部 AI に必須化する出力形式と直接投稿 -### 2. 投稿 +**外部 AI はペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する。** +メインに返すのは「投稿が成功したか」「最終 verdict」「review URL」「件数」の小さな +結果サマリのみ。 -\`\`\`bash -OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) -gh api -X POST "repos/$OWNER_REPO/pulls//reviews" \ - --input /tmp/-review-pr<番号>-payload.json \ - > /tmp/-review-pr<番号>-response.json -\`\`\` +プロンプトに必ず含める指示: -### 3. 結果サマリの書き出し(メインが読む) +- 個別指摘は必ず `comments[]` のインラインコメントにする(行を絞れない場合はファイル代表行) +- `body`(総評)には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 +- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける +- `path` は **PR 差分に登場するファイルのみ**(`gh pr diff --name-only` の一覧から選ぶ) +- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` が既定 +- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +- 投稿後 `/tmp/-review-pr<番号>-result.json` に結果サマリを書き出す -`/tmp/-review-pr<番号>-result.json` に投稿結果を書き出す: +結果サマリの形式: -\`\`\`json +```json { - "status": "posted" | "failed", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "posted_as": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", + "status": "posted", + "event": "REQUEST_CHANGES", + "posted_as": "COMMENT", "review_url": "https://github.com/.../pull/#pullrequestreview-...", "comments_count": 5, "by_severity": {"critical": 0, "major": 2, "minor": 2, "nit": 1}, "payload_path": "/tmp/-review-pr<番号>-payload.json", "error": null } -\`\`\` +``` -投稿失敗時は `status: "failed"`、`error` にエラーメッセージ、`payload_path` で payload は残す -(メイン側のフォールバック投稿で使う)。 +投稿失敗時は `status: "failed"`、`error` にエラーメッセージを入れ、`payload_path` に +payload を残す(メイン側のフォールバック投稿で使う)。 -**`event` と `posted_as` の使い分け**: +### `event` と `posted_as` の使い分け - `event` — **AI 本来の判定 (intent)**。ループ収束判定(`/ndf:cross-review`)はこれを見る -- `posted_as` — **GitHub に実際投稿した event**。`event` と同じ値がデフォルト +- `posted_as` — **GitHub に実際投稿した event**。既定は `event` と同じ値 -GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない**(`HTTP 422: Can not request changes on your own pull request`)。自分 PR レビューの場合は以下のダウングレードを行う: +GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない** +(`HTTP 422: Can not request changes on your own pull request`)。自分の PR をレビュー +する場合は次のダウングレードを行う。 - `event = "REQUEST_CHANGES"` のままにしておく(intent 保持) - ペイロードの `event` だけ `"COMMENT"` にして投稿 - `posted_as = "COMMENT"` を結果サマリに記録 -これにより、後段のループ判定で「本当は REQ なので継続が必要」と判断できる。判定にあたっては事前に `gh api user --jq .login` と `gh pr view --json author --jq .author.login` を比較すること。 - -### 4. 重要度の運用ガイド(auto-fix 判定に直結) - -| 重要度 | 定義 | 後段の扱い | -|---|---|---| -| critical | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | -| major | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | -| minor | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | -| nit | 好み・スタイル | **修正しない、最後にユーザ判断にまとめる** | - -過剰な nit 量産は避ける。critical/major で対応すべき真の問題に集中すること。 -``` - -### `codex` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:codex` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し -- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** -- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 -- `grep -q '^tokens used$' err` で完了検知 -- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 - -> ⚠️ **`--dangerously-bypass-approvals-and-sandbox` のセキュリティ注意**: このフラグは codex の bwrap サンドボックスを完全に無効化し、 -> 任意のシェル実行・任意のファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の外部隔離環境内** でのみ使用すること。 -> ホスト直接実行や本番リポジトリでは使わない。詳細な背景・代替策(`unprivileged_userns_clone` 有効化など)は `/ndf:codex` skill の -> 「サンドボックス制約」節を参照。 - -### `gemini` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:gemini` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し -- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) -- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示することで `--yolo` のリスクを抑える -- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 -- `kill -0 $PID` ポーリングで完了検知(Codex と異なり sentinel 不要 / プロセス exit を見る) -- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 - -> ⚠️ **`--yolo` の制約は依然有効**: `/ndf:gemini` skill のセキュリティ警告通り、必ず外部隔離環境内でのみ実行する。プロンプトで「リポジトリ編集禁止」を明示することは必須だが、それは sandbox の代替にはならない。 +判定にあたっては事前に `gh api user --jq .login` と +`gh pr view --json author --jq .author.login` を比較する。 ### メイン側の検証とフォールバック -メインエージェントの責務は **結果サマリ読み込みと検証のみ**: +メインエージェントの責務は **結果サマリの読み込みと検証のみ**。 ```bash AGENT=codex # or gemini @@ -307,10 +323,7 @@ if [ ! -s "$RESULT" ]; then exit 1 fi -STATUS=$(jq -r '.status' "$RESULT") -EVENT=$(jq -r '.event // empty' "$RESULT") - -if [ "$STATUS" = "failed" ]; then +if [ "$(jq -r '.status' "$RESULT")" = "failed" ]; then echo "⚠️ $AGENT: 投稿失敗。payload からメインがフォールバック投稿します" >&2 PAYLOAD=$(jq -r '.payload_path' "$RESULT") OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) @@ -318,20 +331,26 @@ if [ "$STATUS" = "failed" ]; then jq --arg sha "$SHA" '.commit_id = $sha' "$PAYLOAD" > /tmp/review-fallback.json gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-fallback.json fi - -echo "$AGENT: event=$EVENT url=$(jq -r .review_url $RESULT)" ``` -**Claude 自身による追加判定は行わず**、外部AIの判定(`event`)と指摘内容をそのまま採用する。 +**Claude 自身による追加判定は行わず**、外部 AI の判定(`event`)と指摘内容をそのまま採用する。 ## 作業完了報告(必須) -レビュー結果は **PR 上に投稿済み** であることが前提。ユーザーへの報告は以下に絞る: +PR モードではレビュー結果が **PR 上に投稿済み** であることが前提。報告は以下に絞る。 -- 利用エージェント(claude / codex / gemini のいずれか) -- 投稿結果(review URL、event = APPROVE / REQUEST_CHANGES / COMMENT) +- 利用エージェント(claude / codex / gemini) +- 投稿結果(review URL、event) - 件数サマリ(インラインコメント数、重要度別内訳) -- 総評(review body)の要約 -- PR URL +- 総評の要約 / PR URL + +詳細な指摘内容は PR 上のインラインコメントに残っているため、報告では繰り返さない。 +`--branch` モードでは投稿先がないため、上記「報告」の書式でセッション上に出力する。 + +## 関連 -詳細な指摘内容は PR 上のインラインコメントに残っているため、ユーザー宛報告では繰り返さない。 +- `/ndf:fix` — レビュー指摘の分類と修正対応 +- `/ndf:cross-review` — codex + gemini の収束レビュー +- `/ndf:codex` — Codex CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:gemini` — Gemini CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-codex/skills/cross-review/SKILL.md b/plugins/ndf-codex/skills/cross-review/SKILL.md index 473b07f8..a8f69176 100644 --- a/plugins/ndf-codex/skills/cross-review/SKILL.md +++ b/plugins/ndf-codex/skills/cross-review/SKILL.md @@ -468,10 +468,9 @@ pint / larastan / test / build などは **中断** を原則とする。 ## 関連 - `/ndf:review` — 単発レビュー(AI 直接投稿対応) -- `/ndf:fix` — 修正対応(サブエージェント起動対応) +- `/ndf:fix` — 指摘の分類・修正・返信・Resolve(サブエージェント起動対応) - `/ndf:codex` — codex CLI 呼び出し手順 - `/ndf:gemini` — gemini CLI 呼び出し手順 -- `/ndf:resolve-pr-comments` — Resolve Conversation の詳細 - `/ndf:issue-plan-strategy` — multi-PR ワークフローでは **個別 PR ごとに本 cross-review が原則必須**。 `/ndf:review` 単発や Claude Code の `code-reviewer` は代替にせず、release ブランチへ merge する前に codex + gemini の APPROVE 収束を確認する (Step 6) diff --git a/plugins/ndf-codex/skills/fix/SKILL.md b/plugins/ndf-codex/skills/fix/SKILL.md index 3b001bb8..32f4c515 100644 --- a/plugins/ndf-codex/skills/fix/SKILL.md +++ b/plugins/ndf-codex/skills/fix/SKILL.md @@ -1,8 +1,8 @@ --- name: fix -description: "Fix actionable PR review comments." -when_to_use: "PRレビューコメント (codex/gemini/人間) の指摘を実際にコード修正で対応したいとき。review-pr-comments で分類した後の修正フェーズに使う。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PR fix', 'review feedback fix', 'コメントに対応して修正'" -argument-hint: "[PR番号] [--defer-nit] [--severity-min critical|major|minor]" +description: "Classify PR review comments, fix the actionable ones, then reply and resolve each thread. Use when responding to PR review feedback from codex, gemini, bots, or humans." +when_to_use: "PR レビューコメントへの対応全般。分類だけしたいときは --classify-only。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR fix', 'classify PR comments', 'コメントに対応して修正', 'Resolveして'" +argument-hint: "[PR番号] [--classify-only] [--defer-nit] [--severity-min critical|major|minor]" allowed-tools: - Bash - Read @@ -12,17 +12,37 @@ allowed-tools: - Grep --- -# PR修正コマンド +# PR コメント対応コマンド -直前PR、または引数で指定されたPRのreview comment確認・修正対応実行。 +指定 PR(省略時は直前 PR)のレビューコメントを **分類 → 修正 → 返信 → Resolve** まで +一貫して処理する。 + +## 引数 + +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | 対象 PR | 直前 PR | +| `--classify-only` | **分類・優先度判定のみ**で終了する(読み取り専用)。修正・返信・Resolve は行わない | OFF | +| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | +| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` | + +``` +/ndf:fix # 直前 PR のコメントに対応 +/ndf:fix 9352 # PR 番号を指定 +/ndf:fix 9352 --classify-only # まず全体像を把握したいとき +/ndf:fix 9352 --defer-nit # nit を残して critical/major/minor だけ修正 +``` + +大量のコメントがある PR では、`--classify-only` で全体像と優先度を確認してから修正へ +進むと、修正範囲の判断を誤りにくい。 ## 起動モード -このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** の両方に対応する。 -長丁場のクロスレビューループ(`/ndf:cross-review`)からは **必ずサブエージェント経由で起動** されることを想定: +このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** +の両方に対応する。長丁場のクロスレビューループ(`/ndf:cross-review`)からは +**必ずサブエージェント経由で起動** されることを想定する。 ```python -# メインからの起動例(cross-review が内部でこれを行う) Agent( subagent_type="general-purpose", description="Fix PR review comments (sub-agent)", @@ -41,263 +61,284 @@ PR: **修正 → コミット → push → reply → Resolve Conversation** まで実行する。 メインへの戻り値は最小限のサマリのみ。 -## 引数 +## コメントの取得(3 ソース) -| 引数 | 意味 | 既定 | -|---|---|---| -| `[PR番号]` | 対象 PR | 直前 PR | -| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | -| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` (= minor 以上を修正) | +インラインコメント / レビュー body / PR レベルコメントを一括取得する。 +どれか 1 つでも欠けると指摘を取りこぼす。 + +`$ARGUMENTS` には PR 番号とオプションが混在するため、**そのまま PR 番号として扱わない**。 +数値トークンだけを PR 番号として取り出し、`--` で始まるトークンはオプションとして解釈する。 -## 重要度ベースの自動修正ポリシー +```bash +# PR 番号 = 最初の数値トークン。無ければ直前 PR +PR_NUMBER=$(printf '%s\n' "$ARGUMENTS" | tr ' ' '\n' | grep -m1 -E '^[0-9]+$' || true) +PR_NUMBER="${PR_NUMBER:-$(gh pr view --json number --jq .number)}" + +# オプションは $ARGUMENTS から個別に判定する +case " $ARGUMENTS " in *" --classify-only "*) CLASSIFY_ONLY=1 ;; esac +case " $ARGUMENTS " in *" --defer-nit "*) DEFER_NIT=1 ;; esac +SEVERITY_MIN=$(printf '%s\n' "$ARGUMENTS" | sed -n 's/.*--severity-min[ =]\([a-z]*\).*/\1/p') +SEVERITY_MIN="${SEVERITY_MIN:-minor}" + +FETCH_SCRIPT="${PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/skills/fix/scripts/fetch-pr-comments.sh" +"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" + +# 補助情報 +gh pr view "$PR_NUMBER" --json reviewDecision,body +``` + +GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用する。 + +**PR 本文を必ず読む**。「やらないこと」「別 PR 対応」セクションに記載された内容への +指摘は、この PR では対応しない(分類は「別 PR 対応」)。 + +## 重要度の判定 -`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` 出力規約)で分類。 -**ただし重要度ラベルを鵜呑みにしない** — 各指摘ごとにコード/仕様を独自に調査し、 -本来の重要度を判定し直してから下表の動作を適用する(bot のラベリングは参考値に過ぎない)。 +`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` の出力規約)を手がかりにするが、 +**重要度ラベルを鵜呑みにしない**。各指摘ごとにコード・仕様を独自に調査し、本来の重要度を +判定し直してから下表の動作を適用する。bot のラベリングは参考値に過ぎない。 | 重要度 | 動作 | ユーザ問い合わせ | |---|---|---| | `critical` | **必ず自動修正** | なし | | `major` | **必ず自動修正** | なし | -| `minor` / `nit` (パフォーマンス・可読性・重複コード排除) | **このPRで修正対応**。特にトータル行数が減る方向の修正は積極的に実施 | なし | -| `minor` / `nit` (上記カテゴリ、修正範囲が +30 行を超えそう) | ユーザ問い合わせ | あり | -| `minor` (その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred 扱い | なし | -| `nit` (その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加。最後にまとめてユーザ問い合わせ | あり(最後に1回) | +| `minor` / `nit`(パフォーマンス・可読性・重複コード排除) | **この PR で修正**。特にトータル行数が減る方向の修正は積極的に実施 | なし | +| `minor` / `nit`(上記カテゴリ、修正範囲が +30 行を超えそう) | deferred | あり | +| `minor`(その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred | なし | +| `nit`(その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加 | あり(最後に 1 回) | **重要度の独自判定**: -- AI agent (CodeRabbit / Copilot 等) が `nit` と付けていても、実体がパフォーマンス改善や重複排除なら **minor/nit カテゴリ修正対象** として扱う -- 逆に AI agent が `critical` と付けていても、実害がないスタイル指摘なら `nit` 相当に格下げして deferred 化してよい -- 重要度はカテゴリ(performance/readability/duplication/security/style/etc)と合わせて、コード本体を読んだ上で判定する +- AI agent(CodeRabbit / Copilot 等)が `nit` と付けていても、実体がパフォーマンス改善や + 重複排除なら修正対象として扱う +- 逆に `critical` と付いていても、実害がないスタイル指摘なら `nit` 相当に格下げしてよい +- 重要度はカテゴリ(performance / readability / duplication / security / style 等)と + 合わせて、コード本体を読んだ上で判定する **指摘の正否判断**: -- ロジック・仕様逸脱・セキュリティ: コード/仕様を確認してから修正可否判断 -- bot 指摘で **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘する等): 修正しない、reply で理由説明 -- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象(critical でもエスカレーション) - -**自動判断できない場合の取り扱い** (context 節約のため安易に user に投げない): -- 仕様文書(docs/, README)を読んで判断する -- 既存テストを読んで挙動を確認する -- 関連する他コードの慣例を確認する -- それでも不明なら deferred リストに「要ユーザ判断」として記録、最後にまとめて問い合わせ - -## 手順 - -1. review comment取得 + 重要度を**独自に再判定**(AI agent のラベルは参考値) -2. **CIエラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) - - **完了待ちはしない**。実行中(PENDING/IN_PROGRESS)のチェックは無視して次ステップへ進む - - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む -3. 修正対象を確定: - - `critical` / `major` → 全件修正対象 - - `minor` / `nit` (パフォーマンス・可読性・重複排除) → 修正対象。+30行超なら **deferred + ユーザ問い合わせ** - - `minor` (その他) → 修正対象(明らかでないものは `deferred[]` へ) - - `nit` (その他、`--defer-nit` 時) → `deferred[]` のみ、修正しない - - CIエラー → 全件修正対象(PRテスト範囲外の **flaky テストも見つけ次第修正**) -4. 問題点修正 - - **コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去 等) -5. **コミット前の再確認**(修正作業中に状況が変わっている可能性への対応) - - **review comment再取得**: 作業中に新しいコメントが追加されていないか確認 - - **CI状態再確認**: 現時点の状態だけ確認(完了待ちはしない)。新しい失敗が出ていれば対象に取り込む - - 新しい指摘/失敗があれば手順3に戻る -6. コミット・プッシュ -7. PRにSummaryコメントを追加(対応した件数 + deferred 件数を明記) -8. 対応したインラインコメントに個別に返信 -9. **deferred スレッドには `[deferred / nit]` のラベル付き返信** を投稿(resolve はしない) -10. reviewerに再レビューを依頼 -11. 対応完了したインラインコメントを「Resolve Conversation」にする(`resolveReviewThread` mutation) - - resolve した thread_id / comment_id / path / line を `resolved_threads[]` に記録 - - `deferred` / `rejected` の thread は Resolve しない(次ラウンドで再評価するため) -12. **戻り値ファイルを書き出す**: `/tmp/fix-pr<番号>-result.json` (後述「戻り値フォーマット」参照) - - `ci_failed_checks` には `gh pr checks --json name,state` から `state=FAILURE` の name を抽出して列挙 - - push 直後の CI 再実行結果は**待たない**ため、戻り値の `ci_status` は push 時点での既知失敗のみを反映する +- ロジック・仕様逸脱・セキュリティ: コード / 仕様を確認してから修正可否を判断 +- bot 指摘が **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘): + 修正せず reply で理由を説明(`rejected` として記録、Resolve しない) +- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象 -- 4〜6はgit、1〜2/5と7以降はgithub mcpまたはghを利用 +**自動判断できない場合**(context 節約のため安易にユーザへ投げない): +仕様文書(`docs/`, `README`)を読む → 既存テストを読んで挙動を確認する → 関連する他コードの +慣例を確認する。それでも不明なら deferred リストに「要ユーザ判断」として記録し、最後に +まとめて問い合わせる。 -**flakyテストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第このPRで修正する。 -flaky を放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれるため。 +## `--classify-only` の出力 -## CIエラーチェック +修正は一切行わず、次の形式で分類結果だけを報告する。 -### 失敗ジョブの検出 +| カテゴリ | 説明 | 対応判断 | +|---|---|---| +| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | +| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | +| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | +| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | +| 🔵 別 PR 対応 | PR 本文で別 PR 対応と明記されている内容 | **対応不要** | + +```markdown +## PR #XXXX コメント分類結果 + +### サマリー +- 総コメント数 / 対応必須 / 対応推奨 / 対応すべき / 対応任意・不要 + +### 詳細 +| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | +|---|---|---|---|---|---| +| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | + +### 推奨アクション +1. 対応すべき項目(重大 + 軽微) +2. 対応推奨項目 +3. 別 PR で対応(コメントで返信推奨) +``` -```bash -# PRの全チェック状態を確認(FAIL/PASS/PENDING) -gh pr checks +分類の根拠(なぜその分類になったか)を簡潔に添える。 -# JSON形式で詳細取得 -gh pr checks --json name,state,link,completedAt +## 修正手順 -# 失敗ジョブのみ抽出 -gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" +1. コメント取得(上記 3 ソース)+ 重要度を**独自に再判定** +2. **CI エラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) + - **完了待ちはしない**。実行中(PENDING / IN_PROGRESS)は無視して次へ進む + - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む +3. 修正対象を確定(「重要度の判定」の表に従う)。CI エラーは全件修正対象 +4. 問題点を修正。**コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去) +5. **コミット前の再確認** — 作業中に新しいコメントが追加されていないか再取得し、CI 状態も + 現時点だけ確認する(完了待ちはしない)。新しい指摘・失敗があれば手順 3 に戻る +6. コミット・プッシュ +7. **PR レベルの Summary コメントを投稿**(対応件数 + deferred 件数を明記) +8. 対応したインラインコメントに個別に返信 +9. **deferred スレッドには `[deferred / nit]` ラベル付き返信** を投稿(Resolve はしない) +10. reviewer に再レビューを依頼 +11. 対応完了したスレッドを **Resolve Conversation** にする +12. **戻り値ファイルを書き出す**(後述) + +**flaky テストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第この PR で +修正する。放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれる。 + +## CI エラーチェック -# 実行中ジョブのみ抽出(状態スナップショット用。完了は待たない) +```bash +gh pr checks # 全チェック状態 +gh pr checks --json name,state,link # JSON 形式 gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state'] in ('PENDING','IN_PROGRESS','QUEUED')]" + python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" ``` -### CI完了待ちはしない +**CI 完了待ちはしない**(`gh pr checks --watch` 等は使わない)。各チェックポイントでは +「現時点で FAILURE のジョブ」のみを取り込む。push 後の CI 再実行結果も待たない。 +ただし状態スナップショットの取得は行い、戻り値の `ci_status` / `ci_failed_checks` に反映する。 -このスキルでは **CI 完了待ちは行わない**(`gh pr checks --watch` 等は使わない)。 -- 各チェックポイントでは「現時点で FAILURE のジョブ」のみを取り込んで修正する -- push 後の CI 再実行結果も待たない(待機中に context を消費しないため) -- ただし `gh pr checks --json name,state` での **状態スナップショット取得は実施** - し、戻り値の `ci_status` / `ci_failed_checks` に反映する - -### 失敗ログの取得 +失敗ログの取得: ```bash -# ワークフロー実行ID取得 RUN_ID=$(gh run list --branch --limit 1 --json databaseId --jq '.[0].databaseId // empty') [ -z "$RUN_ID" ] && { echo "No CI run found for this branch"; exit 0; } - -# 失敗ステップのログだけ表示(効率的) -gh run view $RUN_ID --log-failed - -# 特定ジョブのログ -gh run view $RUN_ID --job --log +gh run view $RUN_ID --log-failed # 失敗ステップのログだけ ``` -### CIエラーの分類と対応方針 - | エラー種別 | 対応方針 | |---|---| | **lint/format** | 自動修正ツール実行(`ruff`, `prettier`, `eslint --fix` 等)→ コミット | | **型チェック** | 型定義・アノテーションを修正。無視コメントは原則禁止(根本対応) | -| **テスト失敗** | 失敗テストを読み、実装/テストどちらが正しいか判断してから修正。テスト側の問題なら仕様確認 | +| **テスト失敗** | 失敗テストを読み、実装 / テストどちらが正しいか判断してから修正 | | **ビルドエラー** | 依存関係・構文・設定ファイルを確認 | | **依存脆弱性** | 可能ならバージョン更新、無理なら除外ルール追加(理由明記) | -| **タイムアウト/flaky** | retry設定、テスト分割、リトライ追加。**PR範囲外の flaky も見つけ次第修正**(放置でリポジトリ全体の品質劣化を招くため) | -| **インフラ一時障害** | 再実行で解消することがあるため `gh run rerun $RUN_ID` を先に試す | +| **タイムアウト/flaky** | retry 設定、テスト分割。**PR 範囲外の flaky も見つけ次第修正** | +| **インフラ一時障害** | `gh run rerun $RUN_ID` を先に試す | -### review指摘との統合 +review 指摘と CI エラーは**同じ PR で一緒に修正**する。同じファイル・機能に関するものは +1 コミットにまとめ、独立しているなら別コミットに分離する。 -review指摘とCIエラーは**同じPRで一緒に修正**する: -- 同じファイル・機能に関する指摘とCIエラーは1コミットにまとめる -- 独立しているなら別コミットに分離(git log で追いやすい) +## 返信と Resolve -## ghコマンド例 +### 返信の書き分け -### PR コメント一括取得 (3 ソース) - -```bash -# インラインコメント / レビュー body / PR レベルコメントを一括取得 -FETCH_SCRIPT="${PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" -``` - -### コメントへの返信 +| 状況 | 返信の型 | +|---|---| +| 修正した | `対応しました — <ファイル>:<行> で〇〇 (commit )` | +| 別 PR で対応 | `別 PR で対応予定です。PR 説明の「やらないこと」に記載のとおり、<理由>` | +| deferred | `[deferred / nit] 後続 PR で対応予定` | +| rejected | `bot 指摘は誤読です — 理由: ...` | +| 対応不要 | `確認しました。<対応不要と判断した理由>` | ```bash -# PRのレビューコメント一覧を取得 (インラインコメントのみ) -gh api repos/{owner}/{repo}/pulls/{pr_number}/comments - -# 特定のコメントに返信(in_reply_to にコメントIDを指定) +# 特定のコメントに返信(in_reply_to にコメント ID を指定) gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ - -f body="修正しました。" \ - -F in_reply_to={comment_id} + -f body="対応しました。" -F in_reply_to={comment_id} ``` ### Resolve Conversation -```bash -# GraphQL APIでスレッドをresolveする -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: "{thread_node_id}"}) { - thread { isResolved } - } - } -' -``` +**修正済みのスレッドのみ** Resolve する。`deferred` / `rejected` は次ラウンドで再評価する +ため Resolve しない。 -### thread_node_idの取得方法 +`resolveReviewThread` が要求するのは **review thread** の ID(`PRRT_...`)であり、 +レビューコメントの `node_id`(`PRRT_` ではなく `PRRC_...`)ではない。 +`repos/{owner}/{repo}/pulls/comments/` から引ける `node_id` はコメント側の ID +なので **Resolve には使えない**。必ず下記 query の `nodes[].id` を使い、 +`comments.nodes[].databaseId`(返信に使ったコメント ID)または本文と突き合わせて特定する。 ```bash -# PRのレビュースレッド一覧を取得(node_id含む) +# スレッド一覧を thread ID (PRRT_...) 付きで取得 gh api graphql -f query=' query { repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {pr_number}) { reviewThreads(first: 100) { nodes { - id - isResolved - comments(first: 1) { - nodes { body } - } + id isResolved path line + comments(first: 1) { nodes { databaseId body } } } } } } - } -' + }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] + | select(.isResolved == false) + | {thread_id: .id, path, line, comment_id: .comments.nodes[0].databaseId}' + +# 上で得た thread_id(PRRT_...)を THREAD_ID に入れて Resolve +gh api graphql -f query=' + mutation($id: ID!) { + resolveReviewThread(input: {threadId: $id}) { thread { isResolved } } + }' -f id="$THREAD_ID" ``` -**方針**: -- 品質・可読性・セキュリティ向上、既存機能影響なし -- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断すること -- 未対応の場合はその理由をコメントに書き込む +### PR レベル Summary コメント(必須) + +インラインへの返信と Resolve **だけでは不十分**。PR ページの Conversation タブに +まとめが出ないと、レビュアー視点で見落とされる。 + +```bash +gh pr comment --body "$(cat <<'EOMD' +## 🔧 /ndf:fix サマリ + +対応件数: critical=X / major=Y / minor=Z (合計 N 件) +deferred: D 件 / rejected: R 件 +commit: +CI: SUCCESS | FAILURE | NONE + +### 詳細 +- 各 thread の対応概要(行リンク付き) +EOMD +)" +``` ## 戻り値フォーマット(必須) -サブエージェント呼び出し時の context 節約のため、**実行結果は `/tmp/fix-pr<番号>-result.json` に書き出す**: +サブエージェント呼び出し時の context 節約のため、**実行結果を +`$TMP_DIR/fix-pr<番号>-result.json` に書き出す**(`$TMP_DIR` は環境変数 +`CROSS_REVIEW_TMP_DIR` があればそれ、なければ `/tmp`)。 ```json { "pr": 67, "fix_commit": "abc1234", - "ci_status": "SUCCESS" | "FAILURE" | "PENDING" | "NONE", + "ci_status": "SUCCESS", "ci_failed_checks": [], "ci_note": null, "fixed_count": 5, "by_severity": {"critical": 1, "major": 2, "minor": 2, "nit": 0}, "resolved_threads": [ - { - "thread_id": "PRRT_...", - "comment_id": 3222849090, - "path": "src/foo.py", - "line": 42 - } + {"thread_id": "PRRT_...", "comment_id": 3222849090, "path": "src/foo.py", "line": 42} ], "deferred": [ - { - "comment_id": 3222849090, - "thread_id": "PRRT_...", - "path": "src/foo.py", - "line": 42, - "severity": "nit", - "category": "style", - "summary": "末尾セミコロンの有無", - "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし" - } + {"comment_id": 3222849090, "thread_id": "PRRT_...", "path": "src/foo.py", "line": 42, + "severity": "nit", "category": "style", "summary": "末尾セミコロンの有無", + "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし"} ], "rejected": [ - { - "comment_id": 3222849090, - "summary": "heredoc を <<'JSON' にせよ", - "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる" - } + {"comment_id": 3222849090, "summary": "heredoc を <<'JSON' にせよ", + "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる"} ], "summary_comment_url": "https://github.com/.../pull/67#issuecomment-..." } ``` -**フィールド説明**: +- `resolved_threads` / `deferred` / `rejected` は **必ず配列**で返す(件数の int は誤り)。 + 該当が無ければ空配列 +- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。 + `/ndf:cross-review` 側で code-related(`pint` / `larastan` / `test` / `build` / `lint` / + `type`)と meta-only(`check_pr_requirements` / `assignees` / `reviewers` / `labels`)を + 分類し、メタチェックのみ失敗ならループを継続する +- `ci_note` — code-related ではない CI 失敗の補足 -- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。`/ndf:cross-review` 側で code-related (`pint/larastan/test/build/lint/type`) と meta-only (`check_pr_requirements/assignees/reviewers/labels`) を分類し、メタチェックのみ失敗ならループ継続する -- `ci_note` — code-related ではない CI 失敗の補足。例: `"メタチェックのみ失敗: check_pr_requirements — Assignees 未設定"` -- `resolved_threads` — 手順 11 で `resolveReviewThread` mutation を実行したスレッド一覧。`deferred` / `rejected` の thread は **Resolve しない**(再評価のため) +## 方針 -サブエージェントとして起動された場合は、この JSON をメインに返すサマリの基礎とする。 +- 品質・可読性・セキュリティ向上を目的とし、既存機能に影響を与えない +- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断する +- 未対応の場合はその理由をコメントに書き込む ## 作業完了報告(必須) -メイン or PR への報告内容(戻り値ファイルから抽出): -- 対応した指摘の件数(重要度別: critical/major/minor/nit) -- **deferred 件数**(主に nit、最後にユーザ問い合わせ予定) -- **rejected 件数**(bot 指摘が不適切で修正しなかった件、各々理由付き) -- **対応したCIエラーの一覧**(ジョブ名、エラー内容、修正方法) -- **対応した flaky テストの一覧**(PR範囲外も含む) -- 修正コミット SHA / 修正ファイル一覧 -- 戻り値ファイルパス: `/tmp/fix-pr<番号>-result.json` -- **PR URL を最後に必ず記載**(例: `https://github.com///pull/<番号>`) +- 対応した指摘の件数(重要度別)/ deferred 件数 / rejected 件数(各々理由付き) +- 対応した CI エラーの一覧(ジョブ名、エラー内容、修正方法) +- 対応した flaky テストの一覧(PR 範囲外も含む) +- 修正コミット SHA / 修正ファイル一覧 / 戻り値ファイルパス +- **PR URL を最後に必ず記載** + +## 関連 + +- `/ndf:review` — PR / ブランチのレビュー(Approve / Request Changes 判定) +- `/ndf:cross-review` — codex + gemini の収束レビュー。内部からこの Skill を呼ぶ diff --git a/plugins/ndf-codex/skills/issue-plan-strategy/SKILL.md b/plugins/ndf-codex/skills/issue-plan-strategy/SKILL.md index add1e621..175939ce 100644 --- a/plugins/ndf-codex/skills/issue-plan-strategy/SKILL.md +++ b/plugins/ndf-codex/skills/issue-plan-strategy/SKILL.md @@ -232,7 +232,7 @@ git worktree add ../--ui feature/-ui | 用途 | コマンド | 位置づけ | |---|---|---| -| PR 作成前のセルフレビュー | `/ndf:review-branch` | push / PR 化の前段。cross-review の代替にはしない | +| PR 作成前のセルフレビュー | `/ndf:review --branch` | push / PR 化の前段。cross-review の代替にはしない | | 個別 PR の収束レビュー (原則必須) | `/ndf:cross-review ` | codex + gemini 両方の APPROVE 収束を確認する本線 | | GitHub 上の例外的な単発確認 | `/ndf:review ` | ごく軽微な差分の単発確認に限定。cross-review の代替にはしない | | 指摘の修正 | `/ndf:fix ` | cross-review ループ内・後で自動起動される | @@ -353,6 +353,6 @@ git checkout release/ - `/ndf:branch-fix-strategy` — ブランチ汚染を避ける原則 - `/ndf:pr` — 通常の PR 作成 / 更新 - `/ndf:cherry-pick-pr` — 検証ブランチへの cherry-pick PR -- `/ndf:review` / `/ndf:review-branch` / `/ndf:cross-review` — レビュー -- `/ndf:fix` / `/ndf:resolve-pr-comments` — コメント対応 +- `/ndf:review` / `/ndf:cross-review` — レビュー(`--branch` で PR 前のセルフレビュー) +- `/ndf:fix` — コメントの分類・修正・返信・Resolve - `/ndf:playwright-planning` — release ブランチでの E2E 結合テスト diff --git a/plugins/ndf-codex/skills/playwright-authoring/SKILL.md b/plugins/ndf-codex/skills/playwright-authoring/SKILL.md index 32754982..3742e685 100644 --- a/plugins/ndf-codex/skills/playwright-authoring/SKILL.md +++ b/plugins/ndf-codex/skills/playwright-authoring/SKILL.md @@ -243,7 +243,7 @@ Chrome DevTools MCP の利用可能な方を自動選択する。どちらも使 - `/ndf:playwright-evidence` — 証跡とレポート (後段) - `/ndf:playwright-kit-ops` — 実行環境の運用 (init_project / codegen / スキャン) - `/ndf:docker-container-access` — Docker コンテナアクセス一般 -- `/ndf:review-branch` — 変更差分のコードレビュー +- `/ndf:review --branch` — 変更差分のコードレビュー - `/ndf:pr-tests` — PR Test Plan の自動実行 > `playwright-planning` / `playwright-evidence` / `playwright-kit-ops` は Codex 公開セットに同梱される。 diff --git a/plugins/ndf-codex/skills/resolve-pr-comments/SKILL.md b/plugins/ndf-codex/skills/resolve-pr-comments/SKILL.md deleted file mode 100644 index 433a72d6..00000000 --- a/plugins/ndf-codex/skills/resolve-pr-comments/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: resolve-pr-comments -description: "Reply to and resolve fixed PR comments." -argument-hint: "[PR番号]" -disable-model-invocation: true -allowed-tools: - - Bash - - Read ---- - -# PRコメントResolveコマンド - -対応済みのPRコメント全てに返信し、スレッドを resolved にする。`/ndf:fix` で修正完了後に呼び出す**クロージング専用**コマンド。 - -## 使用方法 - -``` -/ndf:resolve-pr-comments # 現在のブランチのPRを対象 -/ndf:resolve-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | fix | resolve-pr-comments | -|---|---|---| -| 動作 | コード修正+commit+push | 返信+スレッドresolve | -| 前提 | レビュー後、修正が必要 | 修正済み、クロージングのみ | -| 推奨順序 | 先に実行 | fix後の最後に実行 | - -## 処理フロー - -### 1. PR情報の取得 - -```bash -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 - -GitHub API でレビューコメントを取得: - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" -``` - -### 3. 対応状況の確認 - -各コメントについて、対応済みかどうかを確認する: -- コードの変更履歴(`git log`, `git diff`)と照合 -- 指摘された問題が修正されているか確認 -- PR body の「やらないこと」セクションで別PR対応と明記されているか確認 - -### 4. コメントへの返信 - -対応済みのコメントに対して、内容に応じた返信を投稿する: - -#### 修正対応した場合 -``` -対応しました。 - -{修正内容の簡潔な説明} -``` - -#### 別PRで対応予定の場合 -``` -別PRで対応予定です。 - -PR説明の「やらないこと」に記載の通り、{理由}のため別PRで対応します。 -``` - -#### 対応不要と判断した場合 -``` -確認しました。 - -{対応不要と判断した理由} -``` - -### 5. gh CLI コマンド - -#### レビューコメントに返信(スレッド内) - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" \ - -f body="返信メッセージ" \ - -f in_reply_to= -``` - -#### スレッドをResolve(GraphQL) - -まず Thread Node ID を取得: - -```bash -gh api "repos/:owner/:repo/pulls/comments/" --jq '.node_id' -``` - -その上でResolve: - -```bash -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: ""}) { - thread { isResolved } - } - } -' -``` - -### 6. 実行フロー - -各コメントに対して以下を順次実行: - -1. コメントの内容と対応状況を確認 -2. 適切な返信メッセージを生成 -3. 返信を投稿 -4. スレッドをresolve -5. 結果を報告 - -### 7. 出力フォーマット - -```markdown -## PR #XXXX コメント対応結果 - -### 処理結果 -| # | コメント | 返信内容 | Resolve | -|---|---------|---------|---------| -| 1 | {指摘要約} | 対応しました | ✅ | -| 2 | {指摘要約} | 別PRで対応予定 | ✅ | - -### サマリー -- 処理済み: X件 -- Resolved: X件 -- エラー: X件 -``` - -## 重要ルール - -- **確認してから実行**: 各コメントの対応状況を必ず確認してから返信 -- **コード修正はしない**: 修正は `/ndf:fix` の責務。このコマンドはクロージングのみ -- **適切な返信**: 対応内容に応じた適切な返信メッセージを使用 -- **エラーハンドリング**: API エラー発生時は報告して継続 -- **ユーザー確認**: 判断に迷う場合はユーザーに確認を求める - -## 関連 - -- `/ndf:review-pr-comments` — コメント分類・優先度判定 (READ-ONLY) -- `/ndf:fix` — コメント対応の修正を実施 diff --git a/plugins/ndf-codex/skills/review-branch/SKILL.md b/plugins/ndf-codex/skills/review-branch/SKILL.md deleted file mode 100644 index 951e5ea1..00000000 --- a/plugins/ndf-codex/skills/review-branch/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: review-branch -description: "Review the current branch before opening a PR." -when_to_use: "PR作成前にローカルブランチの実装をセルフレビューしたいとき。Triggers: 'ブランチをレビュー', 'PR前にレビュー', 'セルフレビュー', 'review my branch', 'review before PR', 'self review', 'pre-PR review'" -argument-hint: "[focus-area] (例: security, performance, tests)" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# ブランチ実装レビューコマンド - -現在のブランチで実装された変更を**PR作成前に**コードレビューする。mainブランチとの差分を分析し、コード品質・セキュリティ・パフォーマンスの観点でフィードバックを返す。 - -## `/ndf:review` との使い分け - -| 観点 | review-branch | review | -|---|---|---| -| 対象 | ローカルブランチの差分(PR前) | GitHub上の既存PR | -| 判定 | フィードバックを返す | Approve / Request Changes を判定 | -| 用途 | PR作成前のセルフレビュー | PR作成後のレビュー | - -## 使用方法 - -``` -/ndf:review-branch # 全般レビュー -/ndf:review-branch security # セキュリティに焦点 -/ndf:review-branch performance # パフォーマンスに焦点 -/ndf:review-branch tests # テスト網羅性に焦点 -/ndf:review-branch "ビジネスロジック" # 任意のフォーカス -``` - -## レビュー手順 - -### 1. 変更の把握 - -```bash -git diff main --name-only # 変更ファイル一覧 -git diff main --stat # 差分の統計 -git log main..HEAD --oneline # コミット履歴 -``` - -### 2. 変更内容の分析 - -各変更ファイルに対して以下を確認: - -- **追加・変更されたロジック**: 意図が明確か、正しく実装されているか -- **テストカバレッジ**: 適切なテストが追加されているか -- **コーディング規約**: プロジェクトの規約に準拠しているか - -### 3. 品質チェック観点 - -#### コード品質 -- 命名規則の一貫性 -- 関数/メソッドの責務(単一責任原則) -- DRY原則(重複コードの排除) -- 可読性・保守性 -- 過剰な抽象化がないか(YAGNI) - -#### セキュリティ -- SQLインジェクション対策 -- XSS対策 -- CSRF対策 -- 入力値バリデーション -- 認証・認可の適切性 -- 機密情報(トークン、キー、PII)の取り扱い - -#### パフォーマンス -- N+1 クエリの有無 -- 不要なデータベースアクセス -- メモリ使用量 -- インデックスの活用 - -#### エラーハンドリング -- 例外が適切に捕捉されているか -- ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) -- リトライ/タイムアウトの設計 - -### 4. レビュー結果の報告 - -```markdown -## レビュー結果 - -### 概要 -- 変更ファイル数: X -- 追加行数: +XXX -- 削除行数: -XXX - -### Good(良い点) -- ... - -### Suggestions(改善提案) -- `path/to/file.ext:123` — 提案内容 - -### Issues(要修正) -- `path/to/file.ext:456` — 問題点と修正方針 -``` - -## 使用例 - -```bash -# 全般的なレビュー -/ndf:review-branch - -# セキュリティ重視(認証系変更など) -/ndf:review-branch security - -# N+1クエリ等のパフォーマンス問題に焦点 -/ndf:review-branch performance - -# テストの網羅性を確認 -/ndf:review-branch tests -``` - -## 注意事項 - -- 大量の変更がある場合、重要な変更から優先的にレビューする -- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする -- レビュー結果は提案であり、最終判断は開発者が行う -- **コード修正は行わない**(分析とフィードバックのみ。修正は `/ndf:fix` で別途実行) - -## 関連 - -- `/ndf:review` — PR単位レビュー (Approve/Request Changes判定) -- `/ndf:review-pr-comments` — 既存PRコメントの分類 -- `/ndf:fix` — PRレビューコメントの修正対応 -- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-codex/skills/review-pr-comments/SKILL.md b/plugins/ndf-codex/skills/review-pr-comments/SKILL.md deleted file mode 100644 index d275cb0c..00000000 --- a/plugins/ndf-codex/skills/review-pr-comments/SKILL.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: review-pr-comments -description: "Classify existing PR comments before fixing." -when_to_use: "既存PRのレビューコメントを分類・優先度判定したいとき (修正前)。Triggers: 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR comments review', 'classify PR comments', 'PRレビュー結果を見て'" -argument-hint: "[PR番号]" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# PRコメント分析コマンド (READ-ONLY) - -GitHub PRのレビューコメントを全て確認し、対応可否を判定する。**修正は一切行わない。分析・判定のみ**。 - -## 使用方法 - -``` -/ndf:review-pr-comments # 現在のブランチのPRを対象 -/ndf:review-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | review-pr-comments | fix | -|---|---|---| -| 動作 | 分類・優先度判定のみ | 実際にコード修正 | -| 出力 | 分類テーブル+推奨アクション | 修正差分+commit | -| 推奨順序 | 最初に実行 | review-pr-commentsの結果を見て実行 | - -「まず全体像を把握 → 優先度を決めてから修正」という流れに使う。 - -## 処理フロー - -### 1. PR情報の取得 - -引数でPR番号が指定されていればそれを使用、なければ現在のブランチから取得。 - -```bash -CURRENT_BRANCH=$(git branch --show-current) -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 (3 ソース) - -fix skill の共有スクリプトで インラインコメント / レビュー body / PR レベルコメントを一括取得: - -```bash -FETCH_SCRIPT="${PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" -``` - -補助情報 (reviewDecision 等): - -```bash -gh pr view "$PR_NUMBER" --json reviewDecision -``` - -GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用。 - -### 3. コメント分析・分類 - -各コメントを以下のカテゴリに分類する: - -| カテゴリ | 説明 | 対応判断 | -|---------|------|---------| -| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | -| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | -| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | -| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | -| 🔵 別PR対応 | 別PRで対応予定と明記されている内容 | **対応不要** | - -### 4. 出力フォーマット - -```markdown -## PR #XXXX コメントレビュー結果 - -### サマリー -- 総コメント数: X件 -- 対応必須: X件 -- 対応推奨: X件 -- 対応すべき: X件 -- 対応任意/不要: X件 - -### 詳細 - -| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | -|---|---------|----|---------|----|---------| -| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | -| 2 | ... | ... | ... | ... | ... | - -### 推奨アクション -1. まず対応すべき項目(重大+軽微) -2. 次に対応推奨項目 -3. 別PRで対応(コメントで返信推奨) -``` - -## 重要ルール - -- **READ-ONLY**: コードの修正は一切行わない -- **PR説明文を確認**: 「やらないこと」「別PR対応」セクションに記載されている内容は「🔵 別PR対応」として分類 -- **コンテキスト理解**: コメントが指摘している問題の本質を理解して分類 -- **判断根拠**: なぜその分類になったかの理由を簡潔に説明 - -## 関連 - -- `/ndf:fix` — 分類結果を踏まえてコード修正を実施 -- `/ndf:resolve-pr-comments` — 修正完了後の返信+Resolve -- `/ndf:review` — PRを新規にレビューする (Approve/Request Changes判定) diff --git a/plugins/ndf-codex/skills/review/SKILL.md b/plugins/ndf-codex/skills/review/SKILL.md index 5dfeb4a8..983c4e4a 100644 --- a/plugins/ndf-codex/skills/review/SKILL.md +++ b/plugins/ndf-codex/skills/review/SKILL.md @@ -1,7 +1,8 @@ --- name: review -description: "Review PRs and post approve or changes verdicts." -argument-hint: "[PR番号] [AIエージェント(codex|gemini)]" +description: "Review a PR diff, or the current branch diff with --branch, and post an approve or request-changes verdict." +when_to_use: "PR をレビューするとき、および PR 作成前にローカルブランチをセルフレビューするとき (--branch)。Triggers: 'レビューして', 'PRレビュー', 'マージ前チェック', 'ブランチをレビュー', 'セルフレビュー', 'PR前にレビュー', 'review my branch', 'self review', 'pre-PR review'" +argument-hint: "[PR番号 | --branch] [AIエージェント(codex|gemini)] [--focus AREA]" disable-model-invocation: true allowed-tools: - Bash @@ -10,52 +11,115 @@ allowed-tools: - Grep --- -# PRレビューコマンド +# コードレビューコマンド -直前PR、または引数で指定されたPRを専門家としてレビュー。 +PR 差分、または `--branch` 指定時は現在のブランチの差分を、専門家としてレビューする。 ## 引数 -- 第一引数 `[PR番号]`: レビュー対象のPR番号(省略時は直前のPR) -- 第二引数 `[AIエージェント]`: レビュー実行者(任意) - - 省略時: Claude(自身)でレビュー - - `codex`: Codex CLI に委譲 - - `gemini`: Gemini CLI に委譲 +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | レビュー対象の PR | 直前の PR | +| `--branch` | PR ではなく **ローカルブランチの差分**をレビューする(PR 作成前のセルフレビュー) | OFF | +| `[AIエージェント]` | `codex` / `gemini` に委譲。省略時は Claude 自身 | Claude | +| `--focus AREA` | 重点観点(`security` / `performance` / `tests` / 任意の文字列) | なし | + +``` +/ndf:review # 直前 PR をレビュー +/ndf:review 9352 # PR 番号を指定 +/ndf:review 9352 codex # Codex CLI に委譲 +/ndf:review --branch # ローカルブランチをセルフレビュー +/ndf:review --branch security # セキュリティに焦点を当ててセルフレビュー +``` + +## 2 つのモード -## 実行 +| 観点 | PR モード(既定) | `--branch` モード | +|---|---|---| +| 対象 | GitHub 上の PR 差分 | `git diff <既定ブランチ>` の差分 | +| 出力先 | **PR 上にインラインコメント + 総評を投稿** | セッション上の報告のみ(投稿しない) | +| 判定 | `APPROVE` / `REQUEST_CHANGES` | 判定を出さず改善提案を返す | +| 用途 | PR 作成後のレビュー | PR 作成前のセルフレビュー | -- 問題点・改善点あり → 「Request Changes」 -- 指摘なし → 「Approve」 -- **レビュー結果は必ず GitHub PR 上に投稿する**(後述「レビュー結果の投稿」参照) - - 指摘は可能な限り **コード行に紐付くインラインコメント** として書く - - ファイル横断・設計レベルの所見のみ review body(総評)に書く +**どちらのモードでもコード修正は行わない**(分析と指摘のみ。修正は `/ndf:fix`)。 ## 観点 -言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ -- 上から順に優先して指摘 +言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ。 +上から順に優先して指摘する。 ### 具体的なチェックポイント - **その言語らしい記述方式**: イディオム・標準ライブラリ・言語機能の活用 -- **メモリ効率・演算性能を意識したコード** - - キャッシュ利用 +- **メモリ効率・演算性能** + - キャッシュ利用、不要なループ・コピーの排除 - Python: numpy 利用、内包表記、ジェネレータ - PHP: switch 文の map(連想配列)化 - - 不要なループ・コピーの排除 + - N+1 クエリ、不要なデータベースアクセス、インデックスの活用 - **関数・メソッド・ファイル行数の適正化** - - 目安: 関数/メソッド 50 行、ファイル 300 行 - - ただしプロジェクトの慣例に従う + - 目安: 関数/メソッド 50 行、ファイル 300 行。ただしプロジェクトの慣例に従う + - 単一責任原則から外れていないか - **重複・冗長コードの排除** - PR 範囲にこだわらず積極的にまとめるよう指摘 + - 逆に過剰な抽象化(YAGNI 違反)も指摘する - **柔軟性を損なう定数化の排除** - 数字をそのまま定数にするような硬直化を避ける - 定数よりも DB の master テーブル、または json/yaml による外部化を検討 +- **セキュリティ** + - SQL インジェクション / XSS / CSRF 対策、入力値バリデーション + - 認証・認可の適切性、機密情報(トークン、キー、個人情報)の取り扱い +- **エラーハンドリング** + - 例外が適切に捕捉されているか、リトライ / タイムアウトの設計 + - ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) + +`--focus` が指定された場合は、該当する観点を優先し、他の観点は重大なもののみ指摘する。 + +## `--branch` モードの手順 -## レビュー結果の投稿 +### 1. 変更の把握 + +```bash +git diff main --name-only # 変更ファイル一覧 +git diff main --stat # 差分の統計 +git log main..HEAD --oneline # コミット履歴 +``` + +### 2. 分析 + +各変更ファイルについて、追加・変更されたロジックの意図が明確か、テストが追加されて +いるか、プロジェクトの規約に準拠しているかを、上記「観点」に沿って確認する。 + +### 3. 報告 + +```markdown +## レビュー結果 + +### 概要 +- 変更ファイル数 / 追加行数 / 削除行数 + +### Issues(要修正) +- `path/to/file.ext:456` — 問題点と修正方針 + +### Suggestions(改善提案) +- `path/to/file.ext:123` — 提案内容 +``` + +指摘は重要度の高いものから並べる。良い点の列挙は行わない。 + +### 注意事項 + +- 大量の変更がある場合、重要な変更から優先的にレビューする +- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする +- レビュー結果は提案であり、最終判断は開発者が行う + +## PR モードの手順 レビュー結果は **GitHub の PR レビュー機能** を使って必ず PR 上に書き込む。 -個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ書くのは避ける。 +個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ +書くのは避ける。 + +- 問題点・改善点あり → `REQUEST_CHANGES` +- 指摘なし → `APPROVE` ### 指摘の振り分け @@ -68,17 +132,16 @@ allowed-tools: ### 投稿フロー(推奨: 1 リクエストで一括投稿) -`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を 1 回で送信** する。 +`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を +1 回で送信** する。 ```bash PR= OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) SHA=$(gh pr view "$PR" --json headRefOid -q .headRefOid) -# 1. インラインコメントを JSON 配列で組み立て -# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) -# -# ▼ 推奨: jq -n でシェル変数を安全に流し込む(特殊文字混入時の JSON 破損を防ぐ) +# インラインコメントを JSON 配列で組み立て +# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) SUMMARY=$'## 総評\n\n... 全体所見をここに ...' jq -n \ --arg sha "$SHA" \ @@ -96,13 +159,13 @@ jq -n \ ] }' > /tmp/review-payload.json -# 2. Reviews API に POST gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload.json ``` -> 💡 **JSON 組み立てに heredoc (`< JSON が壊れる(あるいはクオート未エスケープで JSON injection になる)。`jq -n --arg` 経由なら値が自動で -> JSON エスケープされるため安全。クオート付き heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 +> 💡 **JSON 組み立てに heredoc (`< 特殊文字が混入した場合 JSON が壊れる(あるいはクオート未エスケープで JSON injection に +> なる)。`jq -n --arg` 経由なら値が自動で JSON エスケープされるため安全。クオート付き +> heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 **`event` の値**: - `APPROVE` — 指摘なし @@ -120,18 +183,22 @@ gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload [nit / スタイル] スペースが揃っていない。 ``` -重要度の目安: -- `critical` — セキュリティ・データ破損・本番障害につながる -- `major` — 保守性 / 性能 / 仕様逸脱の重要問題 -- `minor` — 改善推奨だがブロッカーではない -- `nit` — 好み・スタイル +### 重要度の運用ガイド(auto-fix 判定に直結) + +| 重要度 | 定義 | 後段(`/ndf:fix`)の扱い | +|---|---|---| +| `critical` | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | +| `major` | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | +| `minor` | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | +| `nit` | 好み・スタイル | **修正しない**、最後にユーザ判断にまとめる | + +過剰な nit 量産は避ける。critical / major で対応すべき真の問題に集中すること。 ### 既存コメントがある場合の重複防止 同じ箇所への二重指摘を避けるため、投稿前に既存コメントを確認する: ```bash -# 既存のレビューコメント一覧 gh api "repos/$OWNER_REPO/pulls/$PR/comments" --paginate \ | jq -r '.[] | "\(.path):\(.line) \(.body | split("\n")[0])"' ``` @@ -150,153 +217,102 @@ gh pr comment "$PR" --body "..." # 1 件だけインラインコメントを追加(既存 review に含めない) gh api -X POST "repos/$OWNER_REPO/pulls/$PR/comments" \ - -F commit_id="$SHA" \ - -F path="src/foo.py" \ - -F line=42 -F side=RIGHT \ - -F body="..." + -F commit_id="$SHA" -F path="src/foo.py" -F line=42 -F side=RIGHT -F body="..." ``` -## 外部AIへの委譲手順 +## 外部 AI への委譲 -第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」の内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 +第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「PR モードの手順」の +内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 -### 共通: プロンプト組み立て +呼び出し手順の詳細は、利用 runtime に `/ndf:codex` / `/ndf:gemini` skill が同梱されて +いる場合はその skill に従う。同梱されていない runtime では以下の要点に従う。 -1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` で PR メタ情報を取得 -2. `gh pr diff ` で差分を取得(または変更ファイル一覧 + 必要箇所を `gh pr view --json files` 経由で抽出) -3. 上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」セクションをそのままプロンプトに転記 -4. PR タイトル・URL・差分を **対象情報** として明記 -5. **出力は GitHub Reviews API のペイロード形式(JSON)で出させる**(後述「外部AIに必須化する出力形式」参照) - -### 外部AIに必須化する出力形式と直接投稿 +**`codex` 指定時** -**外部AIは Reviews API ペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する**。 -(旧版では生成した JSON をメインに返してメインが投稿していたが、メイン context 消費と往復回数が無駄なので削除) +- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し +- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** +- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 +- `grep -q '^tokens used$' err` で完了検知 +- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 -メインに返すのは「投稿が成功したか」「最終 verdict (event)」「review URL」「件数」の小さな結果サマリのみ。 +> ⚠️ `--dangerously-bypass-approvals-and-sandbox` は codex のサンドボックスを完全に無効化し、 +> 任意のシェル実行・ファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の +> 外部隔離環境内** でのみ使用すること。ホスト直接実行や本番リポジトリでは使わない。 -#### プロンプトに必ず含める指示(テンプレート) +**`gemini` 指定時** -```markdown -## 出力形式と投稿手順(必須) +- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し +- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) +- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示する +- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 +- `kill -0 $PID` ポーリングで完了検知(codex と異なり sentinel 不要 / プロセス exit を見る) +- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 -レビュー結果は以下の手順で **あなた自身が PR に投稿** してください。 -メイン側に返すのは投稿結果サマリだけです。 +> ⚠️ `--yolo` も同様に外部隔離環境内でのみ実行する。プロンプトでの「リポジトリ編集禁止」明示は必須だが、 +> sandbox の代替にはならない。 -### 1. ペイロード組み立て +### プロンプト組み立て -以下の JSON を `/tmp/-review-pr<番号>-payload.json` に書き出す -(codex なら `apply_patch`、gemini なら `write_file` を使用): +1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` でメタ情報を取得 +2. `gh pr diff ` で差分を取得 +3. 上記「観点」「PR モードの手順」をそのままプロンプトに転記 +4. PR タイトル・URL・差分を **対象情報** として明記 +5. **出力は Reviews API のペイロード形式(JSON)で出させ、外部 AI 自身に投稿させる** -\`\`\`json -{ - "commit_id": "", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "body": "## 総評\n\n...(設計レベル・PR全体所見のみ)...", - "comments": [ - { - "path": "src/foo.py", - "line": 42, - "side": "RIGHT", - "body": "[major / 可読性] ..." - } - ] -} -\`\`\` - -ルール: -- 個別指摘は必ず `comments[]` のインラインコメントにすること(行を絞れない場合はファイル代表行) -- `body` (総評) には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 -- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける(critical/major/minor/nit) -- `path` は **PR差分に登場するファイルのみ**(事前に `gh pr diff --name-only` で取得した一覧から選ぶ) -- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` がデフォルト -- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +### 外部 AI に必須化する出力形式と直接投稿 -### 2. 投稿 +**外部 AI はペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する。** +メインに返すのは「投稿が成功したか」「最終 verdict」「review URL」「件数」の小さな +結果サマリのみ。 -\`\`\`bash -OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) -gh api -X POST "repos/$OWNER_REPO/pulls//reviews" \ - --input /tmp/-review-pr<番号>-payload.json \ - > /tmp/-review-pr<番号>-response.json -\`\`\` +プロンプトに必ず含める指示: -### 3. 結果サマリの書き出し(メインが読む) +- 個別指摘は必ず `comments[]` のインラインコメントにする(行を絞れない場合はファイル代表行) +- `body`(総評)には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 +- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける +- `path` は **PR 差分に登場するファイルのみ**(`gh pr diff --name-only` の一覧から選ぶ) +- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` が既定 +- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +- 投稿後 `/tmp/-review-pr<番号>-result.json` に結果サマリを書き出す -`/tmp/-review-pr<番号>-result.json` に投稿結果を書き出す: +結果サマリの形式: -\`\`\`json +```json { - "status": "posted" | "failed", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "posted_as": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", + "status": "posted", + "event": "REQUEST_CHANGES", + "posted_as": "COMMENT", "review_url": "https://github.com/.../pull/#pullrequestreview-...", "comments_count": 5, "by_severity": {"critical": 0, "major": 2, "minor": 2, "nit": 1}, "payload_path": "/tmp/-review-pr<番号>-payload.json", "error": null } -\`\`\` +``` -投稿失敗時は `status: "failed"`、`error` にエラーメッセージ、`payload_path` で payload は残す -(メイン側のフォールバック投稿で使う)。 +投稿失敗時は `status: "failed"`、`error` にエラーメッセージを入れ、`payload_path` に +payload を残す(メイン側のフォールバック投稿で使う)。 -**`event` と `posted_as` の使い分け**: +### `event` と `posted_as` の使い分け - `event` — **AI 本来の判定 (intent)**。ループ収束判定(`/ndf:cross-review`)はこれを見る -- `posted_as` — **GitHub に実際投稿した event**。`event` と同じ値がデフォルト +- `posted_as` — **GitHub に実際投稿した event**。既定は `event` と同じ値 -GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない**(`HTTP 422: Can not request changes on your own pull request`)。自分 PR レビューの場合は以下のダウングレードを行う: +GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない** +(`HTTP 422: Can not request changes on your own pull request`)。自分の PR をレビュー +する場合は次のダウングレードを行う。 - `event = "REQUEST_CHANGES"` のままにしておく(intent 保持) - ペイロードの `event` だけ `"COMMENT"` にして投稿 - `posted_as = "COMMENT"` を結果サマリに記録 -これにより、後段のループ判定で「本当は REQ なので継続が必要」と判断できる。判定にあたっては事前に `gh api user --jq .login` と `gh pr view --json author --jq .author.login` を比較すること。 - -### 4. 重要度の運用ガイド(auto-fix 判定に直結) - -| 重要度 | 定義 | 後段の扱い | -|---|---|---| -| critical | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | -| major | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | -| minor | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | -| nit | 好み・スタイル | **修正しない、最後にユーザ判断にまとめる** | - -過剰な nit 量産は避ける。critical/major で対応すべき真の問題に集中すること。 -``` - -### `codex` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:codex` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し -- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** -- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 -- `grep -q '^tokens used$' err` で完了検知 -- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 - -> ⚠️ **`--dangerously-bypass-approvals-and-sandbox` のセキュリティ注意**: このフラグは codex の bwrap サンドボックスを完全に無効化し、 -> 任意のシェル実行・任意のファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の外部隔離環境内** でのみ使用すること。 -> ホスト直接実行や本番リポジトリでは使わない。詳細な背景・代替策(`unprivileged_userns_clone` 有効化など)は `/ndf:codex` skill の -> 「サンドボックス制約」節を参照。 - -### `gemini` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:gemini` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し -- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) -- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示することで `--yolo` のリスクを抑える -- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 -- `kill -0 $PID` ポーリングで完了検知(Codex と異なり sentinel 不要 / プロセス exit を見る) -- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 - -> ⚠️ **`--yolo` の制約は依然有効**: `/ndf:gemini` skill のセキュリティ警告通り、必ず外部隔離環境内でのみ実行する。プロンプトで「リポジトリ編集禁止」を明示することは必須だが、それは sandbox の代替にはならない。 +判定にあたっては事前に `gh api user --jq .login` と +`gh pr view --json author --jq .author.login` を比較する。 ### メイン側の検証とフォールバック -メインエージェントの責務は **結果サマリ読み込みと検証のみ**: +メインエージェントの責務は **結果サマリの読み込みと検証のみ**。 ```bash AGENT=codex # or gemini @@ -307,10 +323,7 @@ if [ ! -s "$RESULT" ]; then exit 1 fi -STATUS=$(jq -r '.status' "$RESULT") -EVENT=$(jq -r '.event // empty' "$RESULT") - -if [ "$STATUS" = "failed" ]; then +if [ "$(jq -r '.status' "$RESULT")" = "failed" ]; then echo "⚠️ $AGENT: 投稿失敗。payload からメインがフォールバック投稿します" >&2 PAYLOAD=$(jq -r '.payload_path' "$RESULT") OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) @@ -318,20 +331,26 @@ if [ "$STATUS" = "failed" ]; then jq --arg sha "$SHA" '.commit_id = $sha' "$PAYLOAD" > /tmp/review-fallback.json gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-fallback.json fi - -echo "$AGENT: event=$EVENT url=$(jq -r .review_url $RESULT)" ``` -**Claude 自身による追加判定は行わず**、外部AIの判定(`event`)と指摘内容をそのまま採用する。 +**Claude 自身による追加判定は行わず**、外部 AI の判定(`event`)と指摘内容をそのまま採用する。 ## 作業完了報告(必須) -レビュー結果は **PR 上に投稿済み** であることが前提。ユーザーへの報告は以下に絞る: +PR モードではレビュー結果が **PR 上に投稿済み** であることが前提。報告は以下に絞る。 -- 利用エージェント(claude / codex / gemini のいずれか) -- 投稿結果(review URL、event = APPROVE / REQUEST_CHANGES / COMMENT) +- 利用エージェント(claude / codex / gemini) +- 投稿結果(review URL、event) - 件数サマリ(インラインコメント数、重要度別内訳) -- 総評(review body)の要約 -- PR URL +- 総評の要約 / PR URL + +詳細な指摘内容は PR 上のインラインコメントに残っているため、報告では繰り返さない。 +`--branch` モードでは投稿先がないため、上記「報告」の書式でセッション上に出力する。 + +## 関連 -詳細な指摘内容は PR 上のインラインコメントに残っているため、ユーザー宛報告では繰り返さない。 +- `/ndf:fix` — レビュー指摘の分類と修正対応 +- `/ndf:cross-review` — codex + gemini の収束レビュー +- `/ndf:codex` — Codex CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:gemini` — Gemini CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-kiro/skills/cross-review/SKILL.md b/plugins/ndf-kiro/skills/cross-review/SKILL.md index 77e13848..b355bff2 100644 --- a/plugins/ndf-kiro/skills/cross-review/SKILL.md +++ b/plugins/ndf-kiro/skills/cross-review/SKILL.md @@ -468,10 +468,9 @@ pint / larastan / test / build などは **中断** を原則とする。 ## 関連 - `/ndf:review` — 単発レビュー(AI 直接投稿対応) -- `/ndf:fix` — 修正対応(サブエージェント起動対応) +- `/ndf:fix` — 指摘の分類・修正・返信・Resolve(サブエージェント起動対応) - `/ndf:codex` — codex CLI 呼び出し手順 - `/ndf:gemini` — gemini CLI 呼び出し手順 -- `/ndf:resolve-pr-comments` — Resolve Conversation の詳細 - `/ndf:issue-plan-strategy` — multi-PR ワークフローでは **個別 PR ごとに本 cross-review が原則必須**。 `/ndf:review` 単発や Claude Code の `code-reviewer` は代替にせず、release ブランチへ merge する前に codex + gemini の APPROVE 収束を確認する (Step 6) diff --git a/plugins/ndf-kiro/skills/fix/SKILL.md b/plugins/ndf-kiro/skills/fix/SKILL.md index 4e1e6c58..74e038b9 100644 --- a/plugins/ndf-kiro/skills/fix/SKILL.md +++ b/plugins/ndf-kiro/skills/fix/SKILL.md @@ -1,8 +1,8 @@ --- name: fix -description: "Fix actionable PR review comments." -when_to_use: "PRレビューコメント (codex/gemini/人間) の指摘を実際にコード修正で対応したいとき。review-pr-comments で分類した後の修正フェーズに使う。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PR fix', 'review feedback fix', 'コメントに対応して修正'" -argument-hint: "[PR番号] [--defer-nit] [--severity-min critical|major|minor]" +description: "Classify PR review comments, fix the actionable ones, then reply and resolve each thread. Use when responding to PR review feedback from codex, gemini, bots, or humans." +when_to_use: "PR レビューコメントへの対応全般。分類だけしたいときは --classify-only。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR fix', 'classify PR comments', 'コメントに対応して修正', 'Resolveして'" +argument-hint: "[PR番号] [--classify-only] [--defer-nit] [--severity-min critical|major|minor]" allowed-tools: - Bash - Read @@ -12,17 +12,37 @@ allowed-tools: - Grep --- -# PR修正コマンド +# PR コメント対応コマンド -直前PR、または引数で指定されたPRのreview comment確認・修正対応実行。 +指定 PR(省略時は直前 PR)のレビューコメントを **分類 → 修正 → 返信 → Resolve** まで +一貫して処理する。 + +## 引数 + +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | 対象 PR | 直前 PR | +| `--classify-only` | **分類・優先度判定のみ**で終了する(読み取り専用)。修正・返信・Resolve は行わない | OFF | +| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | +| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` | + +``` +/ndf:fix # 直前 PR のコメントに対応 +/ndf:fix 9352 # PR 番号を指定 +/ndf:fix 9352 --classify-only # まず全体像を把握したいとき +/ndf:fix 9352 --defer-nit # nit を残して critical/major/minor だけ修正 +``` + +大量のコメントがある PR では、`--classify-only` で全体像と優先度を確認してから修正へ +進むと、修正範囲の判断を誤りにくい。 ## 起動モード -このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** の両方に対応する。 -長丁場のクロスレビューループ(`/ndf:cross-review`)からは **必ずサブエージェント経由で起動** されることを想定: +このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** +の両方に対応する。長丁場のクロスレビューループ(`/ndf:cross-review`)からは +**必ずサブエージェント経由で起動** されることを想定する。 ```python -# メインからの起動例(cross-review が内部でこれを行う) Agent( subagent_type="general-purpose", description="Fix PR review comments (sub-agent)", @@ -41,263 +61,284 @@ PR: **修正 → コミット → push → reply → Resolve Conversation** まで実行する。 メインへの戻り値は最小限のサマリのみ。 -## 引数 +## コメントの取得(3 ソース) -| 引数 | 意味 | 既定 | -|---|---|---| -| `[PR番号]` | 対象 PR | 直前 PR | -| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | -| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` (= minor 以上を修正) | +インラインコメント / レビュー body / PR レベルコメントを一括取得する。 +どれか 1 つでも欠けると指摘を取りこぼす。 + +`$ARGUMENTS` には PR 番号とオプションが混在するため、**そのまま PR 番号として扱わない**。 +数値トークンだけを PR 番号として取り出し、`--` で始まるトークンはオプションとして解釈する。 -## 重要度ベースの自動修正ポリシー +```bash +# PR 番号 = 最初の数値トークン。無ければ直前 PR +PR_NUMBER=$(printf '%s\n' "$ARGUMENTS" | tr ' ' '\n' | grep -m1 -E '^[0-9]+$' || true) +PR_NUMBER="${PR_NUMBER:-$(gh pr view --json number --jq .number)}" + +# オプションは $ARGUMENTS から個別に判定する +case " $ARGUMENTS " in *" --classify-only "*) CLASSIFY_ONLY=1 ;; esac +case " $ARGUMENTS " in *" --defer-nit "*) DEFER_NIT=1 ;; esac +SEVERITY_MIN=$(printf '%s\n' "$ARGUMENTS" | sed -n 's/.*--severity-min[ =]\([a-z]*\).*/\1/p') +SEVERITY_MIN="${SEVERITY_MIN:-minor}" + +FETCH_SCRIPT="${PLUGIN_ROOT:-plugins/ndf-kiro}/skills/fix/scripts/fetch-pr-comments.sh" +"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" + +# 補助情報 +gh pr view "$PR_NUMBER" --json reviewDecision,body +``` + +GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用する。 + +**PR 本文を必ず読む**。「やらないこと」「別 PR 対応」セクションに記載された内容への +指摘は、この PR では対応しない(分類は「別 PR 対応」)。 + +## 重要度の判定 -`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` 出力規約)で分類。 -**ただし重要度ラベルを鵜呑みにしない** — 各指摘ごとにコード/仕様を独自に調査し、 -本来の重要度を判定し直してから下表の動作を適用する(bot のラベリングは参考値に過ぎない)。 +`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` の出力規約)を手がかりにするが、 +**重要度ラベルを鵜呑みにしない**。各指摘ごとにコード・仕様を独自に調査し、本来の重要度を +判定し直してから下表の動作を適用する。bot のラベリングは参考値に過ぎない。 | 重要度 | 動作 | ユーザ問い合わせ | |---|---|---| | `critical` | **必ず自動修正** | なし | | `major` | **必ず自動修正** | なし | -| `minor` / `nit` (パフォーマンス・可読性・重複コード排除) | **このPRで修正対応**。特にトータル行数が減る方向の修正は積極的に実施 | なし | -| `minor` / `nit` (上記カテゴリ、修正範囲が +30 行を超えそう) | ユーザ問い合わせ | あり | -| `minor` (その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred 扱い | なし | -| `nit` (その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加。最後にまとめてユーザ問い合わせ | あり(最後に1回) | +| `minor` / `nit`(パフォーマンス・可読性・重複コード排除) | **この PR で修正**。特にトータル行数が減る方向の修正は積極的に実施 | なし | +| `minor` / `nit`(上記カテゴリ、修正範囲が +30 行を超えそう) | deferred | あり | +| `minor`(その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred | なし | +| `nit`(その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加 | あり(最後に 1 回) | **重要度の独自判定**: -- AI agent (CodeRabbit / Copilot 等) が `nit` と付けていても、実体がパフォーマンス改善や重複排除なら **minor/nit カテゴリ修正対象** として扱う -- 逆に AI agent が `critical` と付けていても、実害がないスタイル指摘なら `nit` 相当に格下げして deferred 化してよい -- 重要度はカテゴリ(performance/readability/duplication/security/style/etc)と合わせて、コード本体を読んだ上で判定する +- AI agent(CodeRabbit / Copilot 等)が `nit` と付けていても、実体がパフォーマンス改善や + 重複排除なら修正対象として扱う +- 逆に `critical` と付いていても、実害がないスタイル指摘なら `nit` 相当に格下げしてよい +- 重要度はカテゴリ(performance / readability / duplication / security / style 等)と + 合わせて、コード本体を読んだ上で判定する **指摘の正否判断**: -- ロジック・仕様逸脱・セキュリティ: コード/仕様を確認してから修正可否判断 -- bot 指摘で **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘する等): 修正しない、reply で理由説明 -- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象(critical でもエスカレーション) - -**自動判断できない場合の取り扱い** (context 節約のため安易に user に投げない): -- 仕様文書(docs/, README)を読んで判断する -- 既存テストを読んで挙動を確認する -- 関連する他コードの慣例を確認する -- それでも不明なら deferred リストに「要ユーザ判断」として記録、最後にまとめて問い合わせ - -## 手順 - -1. review comment取得 + 重要度を**独自に再判定**(AI agent のラベルは参考値) -2. **CIエラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) - - **完了待ちはしない**。実行中(PENDING/IN_PROGRESS)のチェックは無視して次ステップへ進む - - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む -3. 修正対象を確定: - - `critical` / `major` → 全件修正対象 - - `minor` / `nit` (パフォーマンス・可読性・重複排除) → 修正対象。+30行超なら **deferred + ユーザ問い合わせ** - - `minor` (その他) → 修正対象(明らかでないものは `deferred[]` へ) - - `nit` (その他、`--defer-nit` 時) → `deferred[]` のみ、修正しない - - CIエラー → 全件修正対象(PRテスト範囲外の **flaky テストも見つけ次第修正**) -4. 問題点修正 - - **コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去 等) -5. **コミット前の再確認**(修正作業中に状況が変わっている可能性への対応) - - **review comment再取得**: 作業中に新しいコメントが追加されていないか確認 - - **CI状態再確認**: 現時点の状態だけ確認(完了待ちはしない)。新しい失敗が出ていれば対象に取り込む - - 新しい指摘/失敗があれば手順3に戻る -6. コミット・プッシュ -7. PRにSummaryコメントを追加(対応した件数 + deferred 件数を明記) -8. 対応したインラインコメントに個別に返信 -9. **deferred スレッドには `[deferred / nit]` のラベル付き返信** を投稿(resolve はしない) -10. reviewerに再レビューを依頼 -11. 対応完了したインラインコメントを「Resolve Conversation」にする(`resolveReviewThread` mutation) - - resolve した thread_id / comment_id / path / line を `resolved_threads[]` に記録 - - `deferred` / `rejected` の thread は Resolve しない(次ラウンドで再評価するため) -12. **戻り値ファイルを書き出す**: `/tmp/fix-pr<番号>-result.json` (後述「戻り値フォーマット」参照) - - `ci_failed_checks` には `gh pr checks --json name,state` から `state=FAILURE` の name を抽出して列挙 - - push 直後の CI 再実行結果は**待たない**ため、戻り値の `ci_status` は push 時点での既知失敗のみを反映する +- ロジック・仕様逸脱・セキュリティ: コード / 仕様を確認してから修正可否を判断 +- bot 指摘が **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘): + 修正せず reply で理由を説明(`rejected` として記録、Resolve しない) +- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象 -- 4〜6はgit、1〜2/5と7以降はgithub mcpまたはghを利用 +**自動判断できない場合**(context 節約のため安易にユーザへ投げない): +仕様文書(`docs/`, `README`)を読む → 既存テストを読んで挙動を確認する → 関連する他コードの +慣例を確認する。それでも不明なら deferred リストに「要ユーザ判断」として記録し、最後に +まとめて問い合わせる。 -**flakyテストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第このPRで修正する。 -flaky を放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれるため。 +## `--classify-only` の出力 -## CIエラーチェック +修正は一切行わず、次の形式で分類結果だけを報告する。 -### 失敗ジョブの検出 +| カテゴリ | 説明 | 対応判断 | +|---|---|---| +| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | +| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | +| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | +| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | +| 🔵 別 PR 対応 | PR 本文で別 PR 対応と明記されている内容 | **対応不要** | + +```markdown +## PR #XXXX コメント分類結果 + +### サマリー +- 総コメント数 / 対応必須 / 対応推奨 / 対応すべき / 対応任意・不要 + +### 詳細 +| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | +|---|---|---|---|---|---| +| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | + +### 推奨アクション +1. 対応すべき項目(重大 + 軽微) +2. 対応推奨項目 +3. 別 PR で対応(コメントで返信推奨) +``` -```bash -# PRの全チェック状態を確認(FAIL/PASS/PENDING) -gh pr checks +分類の根拠(なぜその分類になったか)を簡潔に添える。 -# JSON形式で詳細取得 -gh pr checks --json name,state,link,completedAt +## 修正手順 -# 失敗ジョブのみ抽出 -gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" +1. コメント取得(上記 3 ソース)+ 重要度を**独自に再判定** +2. **CI エラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) + - **完了待ちはしない**。実行中(PENDING / IN_PROGRESS)は無視して次へ進む + - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む +3. 修正対象を確定(「重要度の判定」の表に従う)。CI エラーは全件修正対象 +4. 問題点を修正。**コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去) +5. **コミット前の再確認** — 作業中に新しいコメントが追加されていないか再取得し、CI 状態も + 現時点だけ確認する(完了待ちはしない)。新しい指摘・失敗があれば手順 3 に戻る +6. コミット・プッシュ +7. **PR レベルの Summary コメントを投稿**(対応件数 + deferred 件数を明記) +8. 対応したインラインコメントに個別に返信 +9. **deferred スレッドには `[deferred / nit]` ラベル付き返信** を投稿(Resolve はしない) +10. reviewer に再レビューを依頼 +11. 対応完了したスレッドを **Resolve Conversation** にする +12. **戻り値ファイルを書き出す**(後述) + +**flaky テストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第この PR で +修正する。放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれる。 + +## CI エラーチェック -# 実行中ジョブのみ抽出(状態スナップショット用。完了は待たない) +```bash +gh pr checks # 全チェック状態 +gh pr checks --json name,state,link # JSON 形式 gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state'] in ('PENDING','IN_PROGRESS','QUEUED')]" + python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" ``` -### CI完了待ちはしない +**CI 完了待ちはしない**(`gh pr checks --watch` 等は使わない)。各チェックポイントでは +「現時点で FAILURE のジョブ」のみを取り込む。push 後の CI 再実行結果も待たない。 +ただし状態スナップショットの取得は行い、戻り値の `ci_status` / `ci_failed_checks` に反映する。 -このスキルでは **CI 完了待ちは行わない**(`gh pr checks --watch` 等は使わない)。 -- 各チェックポイントでは「現時点で FAILURE のジョブ」のみを取り込んで修正する -- push 後の CI 再実行結果も待たない(待機中に context を消費しないため) -- ただし `gh pr checks --json name,state` での **状態スナップショット取得は実施** - し、戻り値の `ci_status` / `ci_failed_checks` に反映する - -### 失敗ログの取得 +失敗ログの取得: ```bash -# ワークフロー実行ID取得 RUN_ID=$(gh run list --branch --limit 1 --json databaseId --jq '.[0].databaseId // empty') [ -z "$RUN_ID" ] && { echo "No CI run found for this branch"; exit 0; } - -# 失敗ステップのログだけ表示(効率的) -gh run view $RUN_ID --log-failed - -# 特定ジョブのログ -gh run view $RUN_ID --job --log +gh run view $RUN_ID --log-failed # 失敗ステップのログだけ ``` -### CIエラーの分類と対応方針 - | エラー種別 | 対応方針 | |---|---| | **lint/format** | 自動修正ツール実行(`ruff`, `prettier`, `eslint --fix` 等)→ コミット | | **型チェック** | 型定義・アノテーションを修正。無視コメントは原則禁止(根本対応) | -| **テスト失敗** | 失敗テストを読み、実装/テストどちらが正しいか判断してから修正。テスト側の問題なら仕様確認 | +| **テスト失敗** | 失敗テストを読み、実装 / テストどちらが正しいか判断してから修正 | | **ビルドエラー** | 依存関係・構文・設定ファイルを確認 | | **依存脆弱性** | 可能ならバージョン更新、無理なら除外ルール追加(理由明記) | -| **タイムアウト/flaky** | retry設定、テスト分割、リトライ追加。**PR範囲外の flaky も見つけ次第修正**(放置でリポジトリ全体の品質劣化を招くため) | -| **インフラ一時障害** | 再実行で解消することがあるため `gh run rerun $RUN_ID` を先に試す | +| **タイムアウト/flaky** | retry 設定、テスト分割。**PR 範囲外の flaky も見つけ次第修正** | +| **インフラ一時障害** | `gh run rerun $RUN_ID` を先に試す | -### review指摘との統合 +review 指摘と CI エラーは**同じ PR で一緒に修正**する。同じファイル・機能に関するものは +1 コミットにまとめ、独立しているなら別コミットに分離する。 -review指摘とCIエラーは**同じPRで一緒に修正**する: -- 同じファイル・機能に関する指摘とCIエラーは1コミットにまとめる -- 独立しているなら別コミットに分離(git log で追いやすい) +## 返信と Resolve -## ghコマンド例 +### 返信の書き分け -### PR コメント一括取得 (3 ソース) - -```bash -# インラインコメント / レビュー body / PR レベルコメントを一括取得 -FETCH_SCRIPT="${PLUGIN_ROOT:-plugins/ndf-kiro}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" -``` - -### コメントへの返信 +| 状況 | 返信の型 | +|---|---| +| 修正した | `対応しました — <ファイル>:<行> で〇〇 (commit )` | +| 別 PR で対応 | `別 PR で対応予定です。PR 説明の「やらないこと」に記載のとおり、<理由>` | +| deferred | `[deferred / nit] 後続 PR で対応予定` | +| rejected | `bot 指摘は誤読です — 理由: ...` | +| 対応不要 | `確認しました。<対応不要と判断した理由>` | ```bash -# PRのレビューコメント一覧を取得 (インラインコメントのみ) -gh api repos/{owner}/{repo}/pulls/{pr_number}/comments - -# 特定のコメントに返信(in_reply_to にコメントIDを指定) +# 特定のコメントに返信(in_reply_to にコメント ID を指定) gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ - -f body="修正しました。" \ - -F in_reply_to={comment_id} + -f body="対応しました。" -F in_reply_to={comment_id} ``` ### Resolve Conversation -```bash -# GraphQL APIでスレッドをresolveする -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: "{thread_node_id}"}) { - thread { isResolved } - } - } -' -``` +**修正済みのスレッドのみ** Resolve する。`deferred` / `rejected` は次ラウンドで再評価する +ため Resolve しない。 -### thread_node_idの取得方法 +`resolveReviewThread` が要求するのは **review thread** の ID(`PRRT_...`)であり、 +レビューコメントの `node_id`(`PRRT_` ではなく `PRRC_...`)ではない。 +`repos/{owner}/{repo}/pulls/comments/` から引ける `node_id` はコメント側の ID +なので **Resolve には使えない**。必ず下記 query の `nodes[].id` を使い、 +`comments.nodes[].databaseId`(返信に使ったコメント ID)または本文と突き合わせて特定する。 ```bash -# PRのレビュースレッド一覧を取得(node_id含む) +# スレッド一覧を thread ID (PRRT_...) 付きで取得 gh api graphql -f query=' query { repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {pr_number}) { reviewThreads(first: 100) { nodes { - id - isResolved - comments(first: 1) { - nodes { body } - } + id isResolved path line + comments(first: 1) { nodes { databaseId body } } } } } } - } -' + }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] + | select(.isResolved == false) + | {thread_id: .id, path, line, comment_id: .comments.nodes[0].databaseId}' + +# 上で得た thread_id(PRRT_...)を THREAD_ID に入れて Resolve +gh api graphql -f query=' + mutation($id: ID!) { + resolveReviewThread(input: {threadId: $id}) { thread { isResolved } } + }' -f id="$THREAD_ID" ``` -**方針**: -- 品質・可読性・セキュリティ向上、既存機能影響なし -- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断すること -- 未対応の場合はその理由をコメントに書き込む +### PR レベル Summary コメント(必須) + +インラインへの返信と Resolve **だけでは不十分**。PR ページの Conversation タブに +まとめが出ないと、レビュアー視点で見落とされる。 + +```bash +gh pr comment --body "$(cat <<'EOMD' +## 🔧 /ndf:fix サマリ + +対応件数: critical=X / major=Y / minor=Z (合計 N 件) +deferred: D 件 / rejected: R 件 +commit: +CI: SUCCESS | FAILURE | NONE + +### 詳細 +- 各 thread の対応概要(行リンク付き) +EOMD +)" +``` ## 戻り値フォーマット(必須) -サブエージェント呼び出し時の context 節約のため、**実行結果は `/tmp/fix-pr<番号>-result.json` に書き出す**: +サブエージェント呼び出し時の context 節約のため、**実行結果を +`$TMP_DIR/fix-pr<番号>-result.json` に書き出す**(`$TMP_DIR` は環境変数 +`CROSS_REVIEW_TMP_DIR` があればそれ、なければ `/tmp`)。 ```json { "pr": 67, "fix_commit": "abc1234", - "ci_status": "SUCCESS" | "FAILURE" | "PENDING" | "NONE", + "ci_status": "SUCCESS", "ci_failed_checks": [], "ci_note": null, "fixed_count": 5, "by_severity": {"critical": 1, "major": 2, "minor": 2, "nit": 0}, "resolved_threads": [ - { - "thread_id": "PRRT_...", - "comment_id": 3222849090, - "path": "src/foo.py", - "line": 42 - } + {"thread_id": "PRRT_...", "comment_id": 3222849090, "path": "src/foo.py", "line": 42} ], "deferred": [ - { - "comment_id": 3222849090, - "thread_id": "PRRT_...", - "path": "src/foo.py", - "line": 42, - "severity": "nit", - "category": "style", - "summary": "末尾セミコロンの有無", - "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし" - } + {"comment_id": 3222849090, "thread_id": "PRRT_...", "path": "src/foo.py", "line": 42, + "severity": "nit", "category": "style", "summary": "末尾セミコロンの有無", + "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし"} ], "rejected": [ - { - "comment_id": 3222849090, - "summary": "heredoc を <<'JSON' にせよ", - "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる" - } + {"comment_id": 3222849090, "summary": "heredoc を <<'JSON' にせよ", + "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる"} ], "summary_comment_url": "https://github.com/.../pull/67#issuecomment-..." } ``` -**フィールド説明**: +- `resolved_threads` / `deferred` / `rejected` は **必ず配列**で返す(件数の int は誤り)。 + 該当が無ければ空配列 +- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。 + `/ndf:cross-review` 側で code-related(`pint` / `larastan` / `test` / `build` / `lint` / + `type`)と meta-only(`check_pr_requirements` / `assignees` / `reviewers` / `labels`)を + 分類し、メタチェックのみ失敗ならループを継続する +- `ci_note` — code-related ではない CI 失敗の補足 -- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。`/ndf:cross-review` 側で code-related (`pint/larastan/test/build/lint/type`) と meta-only (`check_pr_requirements/assignees/reviewers/labels`) を分類し、メタチェックのみ失敗ならループ継続する -- `ci_note` — code-related ではない CI 失敗の補足。例: `"メタチェックのみ失敗: check_pr_requirements — Assignees 未設定"` -- `resolved_threads` — 手順 11 で `resolveReviewThread` mutation を実行したスレッド一覧。`deferred` / `rejected` の thread は **Resolve しない**(再評価のため) +## 方針 -サブエージェントとして起動された場合は、この JSON をメインに返すサマリの基礎とする。 +- 品質・可読性・セキュリティ向上を目的とし、既存機能に影響を与えない +- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断する +- 未対応の場合はその理由をコメントに書き込む ## 作業完了報告(必須) -メイン or PR への報告内容(戻り値ファイルから抽出): -- 対応した指摘の件数(重要度別: critical/major/minor/nit) -- **deferred 件数**(主に nit、最後にユーザ問い合わせ予定) -- **rejected 件数**(bot 指摘が不適切で修正しなかった件、各々理由付き) -- **対応したCIエラーの一覧**(ジョブ名、エラー内容、修正方法) -- **対応した flaky テストの一覧**(PR範囲外も含む) -- 修正コミット SHA / 修正ファイル一覧 -- 戻り値ファイルパス: `/tmp/fix-pr<番号>-result.json` -- **PR URL を最後に必ず記載**(例: `https://github.com///pull/<番号>`) +- 対応した指摘の件数(重要度別)/ deferred 件数 / rejected 件数(各々理由付き) +- 対応した CI エラーの一覧(ジョブ名、エラー内容、修正方法) +- 対応した flaky テストの一覧(PR 範囲外も含む) +- 修正コミット SHA / 修正ファイル一覧 / 戻り値ファイルパス +- **PR URL を最後に必ず記載** + +## 関連 + +- `/ndf:review` — PR / ブランチのレビュー(Approve / Request Changes 判定) +- `/ndf:cross-review` — codex + gemini の収束レビュー。内部からこの Skill を呼ぶ diff --git a/plugins/ndf-kiro/skills/issue-plan-strategy/SKILL.md b/plugins/ndf-kiro/skills/issue-plan-strategy/SKILL.md index add1e621..175939ce 100644 --- a/plugins/ndf-kiro/skills/issue-plan-strategy/SKILL.md +++ b/plugins/ndf-kiro/skills/issue-plan-strategy/SKILL.md @@ -232,7 +232,7 @@ git worktree add ../--ui feature/-ui | 用途 | コマンド | 位置づけ | |---|---|---| -| PR 作成前のセルフレビュー | `/ndf:review-branch` | push / PR 化の前段。cross-review の代替にはしない | +| PR 作成前のセルフレビュー | `/ndf:review --branch` | push / PR 化の前段。cross-review の代替にはしない | | 個別 PR の収束レビュー (原則必須) | `/ndf:cross-review ` | codex + gemini 両方の APPROVE 収束を確認する本線 | | GitHub 上の例外的な単発確認 | `/ndf:review ` | ごく軽微な差分の単発確認に限定。cross-review の代替にはしない | | 指摘の修正 | `/ndf:fix ` | cross-review ループ内・後で自動起動される | @@ -353,6 +353,6 @@ git checkout release/ - `/ndf:branch-fix-strategy` — ブランチ汚染を避ける原則 - `/ndf:pr` — 通常の PR 作成 / 更新 - `/ndf:cherry-pick-pr` — 検証ブランチへの cherry-pick PR -- `/ndf:review` / `/ndf:review-branch` / `/ndf:cross-review` — レビュー -- `/ndf:fix` / `/ndf:resolve-pr-comments` — コメント対応 +- `/ndf:review` / `/ndf:cross-review` — レビュー(`--branch` で PR 前のセルフレビュー) +- `/ndf:fix` — コメントの分類・修正・返信・Resolve - `/ndf:playwright-planning` — release ブランチでの E2E 結合テスト diff --git a/plugins/ndf-kiro/skills/playwright-authoring/SKILL.md b/plugins/ndf-kiro/skills/playwright-authoring/SKILL.md index 32754982..3742e685 100644 --- a/plugins/ndf-kiro/skills/playwright-authoring/SKILL.md +++ b/plugins/ndf-kiro/skills/playwright-authoring/SKILL.md @@ -243,7 +243,7 @@ Chrome DevTools MCP の利用可能な方を自動選択する。どちらも使 - `/ndf:playwright-evidence` — 証跡とレポート (後段) - `/ndf:playwright-kit-ops` — 実行環境の運用 (init_project / codegen / スキャン) - `/ndf:docker-container-access` — Docker コンテナアクセス一般 -- `/ndf:review-branch` — 変更差分のコードレビュー +- `/ndf:review --branch` — 変更差分のコードレビュー - `/ndf:pr-tests` — PR Test Plan の自動実行 > `playwright-planning` / `playwright-evidence` / `playwright-kit-ops` は Codex 公開セットに同梱される。 diff --git a/plugins/ndf-kiro/skills/resolve-pr-comments/SKILL.md b/plugins/ndf-kiro/skills/resolve-pr-comments/SKILL.md deleted file mode 100644 index 433a72d6..00000000 --- a/plugins/ndf-kiro/skills/resolve-pr-comments/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: resolve-pr-comments -description: "Reply to and resolve fixed PR comments." -argument-hint: "[PR番号]" -disable-model-invocation: true -allowed-tools: - - Bash - - Read ---- - -# PRコメントResolveコマンド - -対応済みのPRコメント全てに返信し、スレッドを resolved にする。`/ndf:fix` で修正完了後に呼び出す**クロージング専用**コマンド。 - -## 使用方法 - -``` -/ndf:resolve-pr-comments # 現在のブランチのPRを対象 -/ndf:resolve-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | fix | resolve-pr-comments | -|---|---|---| -| 動作 | コード修正+commit+push | 返信+スレッドresolve | -| 前提 | レビュー後、修正が必要 | 修正済み、クロージングのみ | -| 推奨順序 | 先に実行 | fix後の最後に実行 | - -## 処理フロー - -### 1. PR情報の取得 - -```bash -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 - -GitHub API でレビューコメントを取得: - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" -``` - -### 3. 対応状況の確認 - -各コメントについて、対応済みかどうかを確認する: -- コードの変更履歴(`git log`, `git diff`)と照合 -- 指摘された問題が修正されているか確認 -- PR body の「やらないこと」セクションで別PR対応と明記されているか確認 - -### 4. コメントへの返信 - -対応済みのコメントに対して、内容に応じた返信を投稿する: - -#### 修正対応した場合 -``` -対応しました。 - -{修正内容の簡潔な説明} -``` - -#### 別PRで対応予定の場合 -``` -別PRで対応予定です。 - -PR説明の「やらないこと」に記載の通り、{理由}のため別PRで対応します。 -``` - -#### 対応不要と判断した場合 -``` -確認しました。 - -{対応不要と判断した理由} -``` - -### 5. gh CLI コマンド - -#### レビューコメントに返信(スレッド内) - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" \ - -f body="返信メッセージ" \ - -f in_reply_to= -``` - -#### スレッドをResolve(GraphQL) - -まず Thread Node ID を取得: - -```bash -gh api "repos/:owner/:repo/pulls/comments/" --jq '.node_id' -``` - -その上でResolve: - -```bash -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: ""}) { - thread { isResolved } - } - } -' -``` - -### 6. 実行フロー - -各コメントに対して以下を順次実行: - -1. コメントの内容と対応状況を確認 -2. 適切な返信メッセージを生成 -3. 返信を投稿 -4. スレッドをresolve -5. 結果を報告 - -### 7. 出力フォーマット - -```markdown -## PR #XXXX コメント対応結果 - -### 処理結果 -| # | コメント | 返信内容 | Resolve | -|---|---------|---------|---------| -| 1 | {指摘要約} | 対応しました | ✅ | -| 2 | {指摘要約} | 別PRで対応予定 | ✅ | - -### サマリー -- 処理済み: X件 -- Resolved: X件 -- エラー: X件 -``` - -## 重要ルール - -- **確認してから実行**: 各コメントの対応状況を必ず確認してから返信 -- **コード修正はしない**: 修正は `/ndf:fix` の責務。このコマンドはクロージングのみ -- **適切な返信**: 対応内容に応じた適切な返信メッセージを使用 -- **エラーハンドリング**: API エラー発生時は報告して継続 -- **ユーザー確認**: 判断に迷う場合はユーザーに確認を求める - -## 関連 - -- `/ndf:review-pr-comments` — コメント分類・優先度判定 (READ-ONLY) -- `/ndf:fix` — コメント対応の修正を実施 diff --git a/plugins/ndf-kiro/skills/review-branch/SKILL.md b/plugins/ndf-kiro/skills/review-branch/SKILL.md deleted file mode 100644 index 951e5ea1..00000000 --- a/plugins/ndf-kiro/skills/review-branch/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: review-branch -description: "Review the current branch before opening a PR." -when_to_use: "PR作成前にローカルブランチの実装をセルフレビューしたいとき。Triggers: 'ブランチをレビュー', 'PR前にレビュー', 'セルフレビュー', 'review my branch', 'review before PR', 'self review', 'pre-PR review'" -argument-hint: "[focus-area] (例: security, performance, tests)" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# ブランチ実装レビューコマンド - -現在のブランチで実装された変更を**PR作成前に**コードレビューする。mainブランチとの差分を分析し、コード品質・セキュリティ・パフォーマンスの観点でフィードバックを返す。 - -## `/ndf:review` との使い分け - -| 観点 | review-branch | review | -|---|---|---| -| 対象 | ローカルブランチの差分(PR前) | GitHub上の既存PR | -| 判定 | フィードバックを返す | Approve / Request Changes を判定 | -| 用途 | PR作成前のセルフレビュー | PR作成後のレビュー | - -## 使用方法 - -``` -/ndf:review-branch # 全般レビュー -/ndf:review-branch security # セキュリティに焦点 -/ndf:review-branch performance # パフォーマンスに焦点 -/ndf:review-branch tests # テスト網羅性に焦点 -/ndf:review-branch "ビジネスロジック" # 任意のフォーカス -``` - -## レビュー手順 - -### 1. 変更の把握 - -```bash -git diff main --name-only # 変更ファイル一覧 -git diff main --stat # 差分の統計 -git log main..HEAD --oneline # コミット履歴 -``` - -### 2. 変更内容の分析 - -各変更ファイルに対して以下を確認: - -- **追加・変更されたロジック**: 意図が明確か、正しく実装されているか -- **テストカバレッジ**: 適切なテストが追加されているか -- **コーディング規約**: プロジェクトの規約に準拠しているか - -### 3. 品質チェック観点 - -#### コード品質 -- 命名規則の一貫性 -- 関数/メソッドの責務(単一責任原則) -- DRY原則(重複コードの排除) -- 可読性・保守性 -- 過剰な抽象化がないか(YAGNI) - -#### セキュリティ -- SQLインジェクション対策 -- XSS対策 -- CSRF対策 -- 入力値バリデーション -- 認証・認可の適切性 -- 機密情報(トークン、キー、PII)の取り扱い - -#### パフォーマンス -- N+1 クエリの有無 -- 不要なデータベースアクセス -- メモリ使用量 -- インデックスの活用 - -#### エラーハンドリング -- 例外が適切に捕捉されているか -- ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) -- リトライ/タイムアウトの設計 - -### 4. レビュー結果の報告 - -```markdown -## レビュー結果 - -### 概要 -- 変更ファイル数: X -- 追加行数: +XXX -- 削除行数: -XXX - -### Good(良い点) -- ... - -### Suggestions(改善提案) -- `path/to/file.ext:123` — 提案内容 - -### Issues(要修正) -- `path/to/file.ext:456` — 問題点と修正方針 -``` - -## 使用例 - -```bash -# 全般的なレビュー -/ndf:review-branch - -# セキュリティ重視(認証系変更など) -/ndf:review-branch security - -# N+1クエリ等のパフォーマンス問題に焦点 -/ndf:review-branch performance - -# テストの網羅性を確認 -/ndf:review-branch tests -``` - -## 注意事項 - -- 大量の変更がある場合、重要な変更から優先的にレビューする -- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする -- レビュー結果は提案であり、最終判断は開発者が行う -- **コード修正は行わない**(分析とフィードバックのみ。修正は `/ndf:fix` で別途実行) - -## 関連 - -- `/ndf:review` — PR単位レビュー (Approve/Request Changes判定) -- `/ndf:review-pr-comments` — 既存PRコメントの分類 -- `/ndf:fix` — PRレビューコメントの修正対応 -- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-kiro/skills/review-pr-comments/SKILL.md b/plugins/ndf-kiro/skills/review-pr-comments/SKILL.md deleted file mode 100644 index 96924dc7..00000000 --- a/plugins/ndf-kiro/skills/review-pr-comments/SKILL.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: review-pr-comments -description: "Classify existing PR comments before fixing." -when_to_use: "既存PRのレビューコメントを分類・優先度判定したいとき (修正前)。Triggers: 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR comments review', 'classify PR comments', 'PRレビュー結果を見て'" -argument-hint: "[PR番号]" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# PRコメント分析コマンド (READ-ONLY) - -GitHub PRのレビューコメントを全て確認し、対応可否を判定する。**修正は一切行わない。分析・判定のみ**。 - -## 使用方法 - -``` -/ndf:review-pr-comments # 現在のブランチのPRを対象 -/ndf:review-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | review-pr-comments | fix | -|---|---|---| -| 動作 | 分類・優先度判定のみ | 実際にコード修正 | -| 出力 | 分類テーブル+推奨アクション | 修正差分+commit | -| 推奨順序 | 最初に実行 | review-pr-commentsの結果を見て実行 | - -「まず全体像を把握 → 優先度を決めてから修正」という流れに使う。 - -## 処理フロー - -### 1. PR情報の取得 - -引数でPR番号が指定されていればそれを使用、なければ現在のブランチから取得。 - -```bash -CURRENT_BRANCH=$(git branch --show-current) -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 (3 ソース) - -fix skill の共有スクリプトで インラインコメント / レビュー body / PR レベルコメントを一括取得: - -```bash -FETCH_SCRIPT="${PLUGIN_ROOT:-plugins/ndf-kiro}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" -``` - -補助情報 (reviewDecision 等): - -```bash -gh pr view "$PR_NUMBER" --json reviewDecision -``` - -GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用。 - -### 3. コメント分析・分類 - -各コメントを以下のカテゴリに分類する: - -| カテゴリ | 説明 | 対応判断 | -|---------|------|---------| -| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | -| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | -| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | -| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | -| 🔵 別PR対応 | 別PRで対応予定と明記されている内容 | **対応不要** | - -### 4. 出力フォーマット - -```markdown -## PR #XXXX コメントレビュー結果 - -### サマリー -- 総コメント数: X件 -- 対応必須: X件 -- 対応推奨: X件 -- 対応すべき: X件 -- 対応任意/不要: X件 - -### 詳細 - -| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | -|---|---------|----|---------|----|---------| -| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | -| 2 | ... | ... | ... | ... | ... | - -### 推奨アクション -1. まず対応すべき項目(重大+軽微) -2. 次に対応推奨項目 -3. 別PRで対応(コメントで返信推奨) -``` - -## 重要ルール - -- **READ-ONLY**: コードの修正は一切行わない -- **PR説明文を確認**: 「やらないこと」「別PR対応」セクションに記載されている内容は「🔵 別PR対応」として分類 -- **コンテキスト理解**: コメントが指摘している問題の本質を理解して分類 -- **判断根拠**: なぜその分類になったかの理由を簡潔に説明 - -## 関連 - -- `/ndf:fix` — 分類結果を踏まえてコード修正を実施 -- `/ndf:resolve-pr-comments` — 修正完了後の返信+Resolve -- `/ndf:review` — PRを新規にレビューする (Approve/Request Changes判定) diff --git a/plugins/ndf-kiro/skills/review/SKILL.md b/plugins/ndf-kiro/skills/review/SKILL.md index 5dfeb4a8..983c4e4a 100644 --- a/plugins/ndf-kiro/skills/review/SKILL.md +++ b/plugins/ndf-kiro/skills/review/SKILL.md @@ -1,7 +1,8 @@ --- name: review -description: "Review PRs and post approve or changes verdicts." -argument-hint: "[PR番号] [AIエージェント(codex|gemini)]" +description: "Review a PR diff, or the current branch diff with --branch, and post an approve or request-changes verdict." +when_to_use: "PR をレビューするとき、および PR 作成前にローカルブランチをセルフレビューするとき (--branch)。Triggers: 'レビューして', 'PRレビュー', 'マージ前チェック', 'ブランチをレビュー', 'セルフレビュー', 'PR前にレビュー', 'review my branch', 'self review', 'pre-PR review'" +argument-hint: "[PR番号 | --branch] [AIエージェント(codex|gemini)] [--focus AREA]" disable-model-invocation: true allowed-tools: - Bash @@ -10,52 +11,115 @@ allowed-tools: - Grep --- -# PRレビューコマンド +# コードレビューコマンド -直前PR、または引数で指定されたPRを専門家としてレビュー。 +PR 差分、または `--branch` 指定時は現在のブランチの差分を、専門家としてレビューする。 ## 引数 -- 第一引数 `[PR番号]`: レビュー対象のPR番号(省略時は直前のPR) -- 第二引数 `[AIエージェント]`: レビュー実行者(任意) - - 省略時: Claude(自身)でレビュー - - `codex`: Codex CLI に委譲 - - `gemini`: Gemini CLI に委譲 +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | レビュー対象の PR | 直前の PR | +| `--branch` | PR ではなく **ローカルブランチの差分**をレビューする(PR 作成前のセルフレビュー) | OFF | +| `[AIエージェント]` | `codex` / `gemini` に委譲。省略時は Claude 自身 | Claude | +| `--focus AREA` | 重点観点(`security` / `performance` / `tests` / 任意の文字列) | なし | + +``` +/ndf:review # 直前 PR をレビュー +/ndf:review 9352 # PR 番号を指定 +/ndf:review 9352 codex # Codex CLI に委譲 +/ndf:review --branch # ローカルブランチをセルフレビュー +/ndf:review --branch security # セキュリティに焦点を当ててセルフレビュー +``` + +## 2 つのモード -## 実行 +| 観点 | PR モード(既定) | `--branch` モード | +|---|---|---| +| 対象 | GitHub 上の PR 差分 | `git diff <既定ブランチ>` の差分 | +| 出力先 | **PR 上にインラインコメント + 総評を投稿** | セッション上の報告のみ(投稿しない) | +| 判定 | `APPROVE` / `REQUEST_CHANGES` | 判定を出さず改善提案を返す | +| 用途 | PR 作成後のレビュー | PR 作成前のセルフレビュー | -- 問題点・改善点あり → 「Request Changes」 -- 指摘なし → 「Approve」 -- **レビュー結果は必ず GitHub PR 上に投稿する**(後述「レビュー結果の投稿」参照) - - 指摘は可能な限り **コード行に紐付くインラインコメント** として書く - - ファイル横断・設計レベルの所見のみ review body(総評)に書く +**どちらのモードでもコード修正は行わない**(分析と指摘のみ。修正は `/ndf:fix`)。 ## 観点 -言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ -- 上から順に優先して指摘 +言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ。 +上から順に優先して指摘する。 ### 具体的なチェックポイント - **その言語らしい記述方式**: イディオム・標準ライブラリ・言語機能の活用 -- **メモリ効率・演算性能を意識したコード** - - キャッシュ利用 +- **メモリ効率・演算性能** + - キャッシュ利用、不要なループ・コピーの排除 - Python: numpy 利用、内包表記、ジェネレータ - PHP: switch 文の map(連想配列)化 - - 不要なループ・コピーの排除 + - N+1 クエリ、不要なデータベースアクセス、インデックスの活用 - **関数・メソッド・ファイル行数の適正化** - - 目安: 関数/メソッド 50 行、ファイル 300 行 - - ただしプロジェクトの慣例に従う + - 目安: 関数/メソッド 50 行、ファイル 300 行。ただしプロジェクトの慣例に従う + - 単一責任原則から外れていないか - **重複・冗長コードの排除** - PR 範囲にこだわらず積極的にまとめるよう指摘 + - 逆に過剰な抽象化(YAGNI 違反)も指摘する - **柔軟性を損なう定数化の排除** - 数字をそのまま定数にするような硬直化を避ける - 定数よりも DB の master テーブル、または json/yaml による外部化を検討 +- **セキュリティ** + - SQL インジェクション / XSS / CSRF 対策、入力値バリデーション + - 認証・認可の適切性、機密情報(トークン、キー、個人情報)の取り扱い +- **エラーハンドリング** + - 例外が適切に捕捉されているか、リトライ / タイムアウトの設計 + - ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) + +`--focus` が指定された場合は、該当する観点を優先し、他の観点は重大なもののみ指摘する。 + +## `--branch` モードの手順 -## レビュー結果の投稿 +### 1. 変更の把握 + +```bash +git diff main --name-only # 変更ファイル一覧 +git diff main --stat # 差分の統計 +git log main..HEAD --oneline # コミット履歴 +``` + +### 2. 分析 + +各変更ファイルについて、追加・変更されたロジックの意図が明確か、テストが追加されて +いるか、プロジェクトの規約に準拠しているかを、上記「観点」に沿って確認する。 + +### 3. 報告 + +```markdown +## レビュー結果 + +### 概要 +- 変更ファイル数 / 追加行数 / 削除行数 + +### Issues(要修正) +- `path/to/file.ext:456` — 問題点と修正方針 + +### Suggestions(改善提案) +- `path/to/file.ext:123` — 提案内容 +``` + +指摘は重要度の高いものから並べる。良い点の列挙は行わない。 + +### 注意事項 + +- 大量の変更がある場合、重要な変更から優先的にレビューする +- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする +- レビュー結果は提案であり、最終判断は開発者が行う + +## PR モードの手順 レビュー結果は **GitHub の PR レビュー機能** を使って必ず PR 上に書き込む。 -個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ書くのは避ける。 +個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ +書くのは避ける。 + +- 問題点・改善点あり → `REQUEST_CHANGES` +- 指摘なし → `APPROVE` ### 指摘の振り分け @@ -68,17 +132,16 @@ allowed-tools: ### 投稿フロー(推奨: 1 リクエストで一括投稿) -`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を 1 回で送信** する。 +`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を +1 回で送信** する。 ```bash PR= OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) SHA=$(gh pr view "$PR" --json headRefOid -q .headRefOid) -# 1. インラインコメントを JSON 配列で組み立て -# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) -# -# ▼ 推奨: jq -n でシェル変数を安全に流し込む(特殊文字混入時の JSON 破損を防ぐ) +# インラインコメントを JSON 配列で組み立て +# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) SUMMARY=$'## 総評\n\n... 全体所見をここに ...' jq -n \ --arg sha "$SHA" \ @@ -96,13 +159,13 @@ jq -n \ ] }' > /tmp/review-payload.json -# 2. Reviews API に POST gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload.json ``` -> 💡 **JSON 組み立てに heredoc (`< JSON が壊れる(あるいはクオート未エスケープで JSON injection になる)。`jq -n --arg` 経由なら値が自動で -> JSON エスケープされるため安全。クオート付き heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 +> 💡 **JSON 組み立てに heredoc (`< 特殊文字が混入した場合 JSON が壊れる(あるいはクオート未エスケープで JSON injection に +> なる)。`jq -n --arg` 経由なら値が自動で JSON エスケープされるため安全。クオート付き +> heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 **`event` の値**: - `APPROVE` — 指摘なし @@ -120,18 +183,22 @@ gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload [nit / スタイル] スペースが揃っていない。 ``` -重要度の目安: -- `critical` — セキュリティ・データ破損・本番障害につながる -- `major` — 保守性 / 性能 / 仕様逸脱の重要問題 -- `minor` — 改善推奨だがブロッカーではない -- `nit` — 好み・スタイル +### 重要度の運用ガイド(auto-fix 判定に直結) + +| 重要度 | 定義 | 後段(`/ndf:fix`)の扱い | +|---|---|---| +| `critical` | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | +| `major` | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | +| `minor` | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | +| `nit` | 好み・スタイル | **修正しない**、最後にユーザ判断にまとめる | + +過剰な nit 量産は避ける。critical / major で対応すべき真の問題に集中すること。 ### 既存コメントがある場合の重複防止 同じ箇所への二重指摘を避けるため、投稿前に既存コメントを確認する: ```bash -# 既存のレビューコメント一覧 gh api "repos/$OWNER_REPO/pulls/$PR/comments" --paginate \ | jq -r '.[] | "\(.path):\(.line) \(.body | split("\n")[0])"' ``` @@ -150,153 +217,102 @@ gh pr comment "$PR" --body "..." # 1 件だけインラインコメントを追加(既存 review に含めない) gh api -X POST "repos/$OWNER_REPO/pulls/$PR/comments" \ - -F commit_id="$SHA" \ - -F path="src/foo.py" \ - -F line=42 -F side=RIGHT \ - -F body="..." + -F commit_id="$SHA" -F path="src/foo.py" -F line=42 -F side=RIGHT -F body="..." ``` -## 外部AIへの委譲手順 +## 外部 AI への委譲 -第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」の内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 +第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「PR モードの手順」の +内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 -### 共通: プロンプト組み立て +呼び出し手順の詳細は、利用 runtime に `/ndf:codex` / `/ndf:gemini` skill が同梱されて +いる場合はその skill に従う。同梱されていない runtime では以下の要点に従う。 -1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` で PR メタ情報を取得 -2. `gh pr diff ` で差分を取得(または変更ファイル一覧 + 必要箇所を `gh pr view --json files` 経由で抽出) -3. 上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」セクションをそのままプロンプトに転記 -4. PR タイトル・URL・差分を **対象情報** として明記 -5. **出力は GitHub Reviews API のペイロード形式(JSON)で出させる**(後述「外部AIに必須化する出力形式」参照) - -### 外部AIに必須化する出力形式と直接投稿 +**`codex` 指定時** -**外部AIは Reviews API ペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する**。 -(旧版では生成した JSON をメインに返してメインが投稿していたが、メイン context 消費と往復回数が無駄なので削除) +- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し +- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** +- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 +- `grep -q '^tokens used$' err` で完了検知 +- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 -メインに返すのは「投稿が成功したか」「最終 verdict (event)」「review URL」「件数」の小さな結果サマリのみ。 +> ⚠️ `--dangerously-bypass-approvals-and-sandbox` は codex のサンドボックスを完全に無効化し、 +> 任意のシェル実行・ファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の +> 外部隔離環境内** でのみ使用すること。ホスト直接実行や本番リポジトリでは使わない。 -#### プロンプトに必ず含める指示(テンプレート) +**`gemini` 指定時** -```markdown -## 出力形式と投稿手順(必須) +- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し +- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) +- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示する +- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 +- `kill -0 $PID` ポーリングで完了検知(codex と異なり sentinel 不要 / プロセス exit を見る) +- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 -レビュー結果は以下の手順で **あなた自身が PR に投稿** してください。 -メイン側に返すのは投稿結果サマリだけです。 +> ⚠️ `--yolo` も同様に外部隔離環境内でのみ実行する。プロンプトでの「リポジトリ編集禁止」明示は必須だが、 +> sandbox の代替にはならない。 -### 1. ペイロード組み立て +### プロンプト組み立て -以下の JSON を `/tmp/-review-pr<番号>-payload.json` に書き出す -(codex なら `apply_patch`、gemini なら `write_file` を使用): +1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` でメタ情報を取得 +2. `gh pr diff ` で差分を取得 +3. 上記「観点」「PR モードの手順」をそのままプロンプトに転記 +4. PR タイトル・URL・差分を **対象情報** として明記 +5. **出力は Reviews API のペイロード形式(JSON)で出させ、外部 AI 自身に投稿させる** -\`\`\`json -{ - "commit_id": "", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "body": "## 総評\n\n...(設計レベル・PR全体所見のみ)...", - "comments": [ - { - "path": "src/foo.py", - "line": 42, - "side": "RIGHT", - "body": "[major / 可読性] ..." - } - ] -} -\`\`\` - -ルール: -- 個別指摘は必ず `comments[]` のインラインコメントにすること(行を絞れない場合はファイル代表行) -- `body` (総評) には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 -- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける(critical/major/minor/nit) -- `path` は **PR差分に登場するファイルのみ**(事前に `gh pr diff --name-only` で取得した一覧から選ぶ) -- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` がデフォルト -- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +### 外部 AI に必須化する出力形式と直接投稿 -### 2. 投稿 +**外部 AI はペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する。** +メインに返すのは「投稿が成功したか」「最終 verdict」「review URL」「件数」の小さな +結果サマリのみ。 -\`\`\`bash -OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) -gh api -X POST "repos/$OWNER_REPO/pulls//reviews" \ - --input /tmp/-review-pr<番号>-payload.json \ - > /tmp/-review-pr<番号>-response.json -\`\`\` +プロンプトに必ず含める指示: -### 3. 結果サマリの書き出し(メインが読む) +- 個別指摘は必ず `comments[]` のインラインコメントにする(行を絞れない場合はファイル代表行) +- `body`(総評)には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 +- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける +- `path` は **PR 差分に登場するファイルのみ**(`gh pr diff --name-only` の一覧から選ぶ) +- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` が既定 +- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +- 投稿後 `/tmp/-review-pr<番号>-result.json` に結果サマリを書き出す -`/tmp/-review-pr<番号>-result.json` に投稿結果を書き出す: +結果サマリの形式: -\`\`\`json +```json { - "status": "posted" | "failed", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "posted_as": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", + "status": "posted", + "event": "REQUEST_CHANGES", + "posted_as": "COMMENT", "review_url": "https://github.com/.../pull/#pullrequestreview-...", "comments_count": 5, "by_severity": {"critical": 0, "major": 2, "minor": 2, "nit": 1}, "payload_path": "/tmp/-review-pr<番号>-payload.json", "error": null } -\`\`\` +``` -投稿失敗時は `status: "failed"`、`error` にエラーメッセージ、`payload_path` で payload は残す -(メイン側のフォールバック投稿で使う)。 +投稿失敗時は `status: "failed"`、`error` にエラーメッセージを入れ、`payload_path` に +payload を残す(メイン側のフォールバック投稿で使う)。 -**`event` と `posted_as` の使い分け**: +### `event` と `posted_as` の使い分け - `event` — **AI 本来の判定 (intent)**。ループ収束判定(`/ndf:cross-review`)はこれを見る -- `posted_as` — **GitHub に実際投稿した event**。`event` と同じ値がデフォルト +- `posted_as` — **GitHub に実際投稿した event**。既定は `event` と同じ値 -GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない**(`HTTP 422: Can not request changes on your own pull request`)。自分 PR レビューの場合は以下のダウングレードを行う: +GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない** +(`HTTP 422: Can not request changes on your own pull request`)。自分の PR をレビュー +する場合は次のダウングレードを行う。 - `event = "REQUEST_CHANGES"` のままにしておく(intent 保持) - ペイロードの `event` だけ `"COMMENT"` にして投稿 - `posted_as = "COMMENT"` を結果サマリに記録 -これにより、後段のループ判定で「本当は REQ なので継続が必要」と判断できる。判定にあたっては事前に `gh api user --jq .login` と `gh pr view --json author --jq .author.login` を比較すること。 - -### 4. 重要度の運用ガイド(auto-fix 判定に直結) - -| 重要度 | 定義 | 後段の扱い | -|---|---|---| -| critical | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | -| major | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | -| minor | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | -| nit | 好み・スタイル | **修正しない、最後にユーザ判断にまとめる** | - -過剰な nit 量産は避ける。critical/major で対応すべき真の問題に集中すること。 -``` - -### `codex` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:codex` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し -- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** -- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 -- `grep -q '^tokens used$' err` で完了検知 -- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 - -> ⚠️ **`--dangerously-bypass-approvals-and-sandbox` のセキュリティ注意**: このフラグは codex の bwrap サンドボックスを完全に無効化し、 -> 任意のシェル実行・任意のファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の外部隔離環境内** でのみ使用すること。 -> ホスト直接実行や本番リポジトリでは使わない。詳細な背景・代替策(`unprivileged_userns_clone` 有効化など)は `/ndf:codex` skill の -> 「サンドボックス制約」節を参照。 - -### `gemini` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:gemini` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し -- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) -- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示することで `--yolo` のリスクを抑える -- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 -- `kill -0 $PID` ポーリングで完了検知(Codex と異なり sentinel 不要 / プロセス exit を見る) -- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 - -> ⚠️ **`--yolo` の制約は依然有効**: `/ndf:gemini` skill のセキュリティ警告通り、必ず外部隔離環境内でのみ実行する。プロンプトで「リポジトリ編集禁止」を明示することは必須だが、それは sandbox の代替にはならない。 +判定にあたっては事前に `gh api user --jq .login` と +`gh pr view --json author --jq .author.login` を比較する。 ### メイン側の検証とフォールバック -メインエージェントの責務は **結果サマリ読み込みと検証のみ**: +メインエージェントの責務は **結果サマリの読み込みと検証のみ**。 ```bash AGENT=codex # or gemini @@ -307,10 +323,7 @@ if [ ! -s "$RESULT" ]; then exit 1 fi -STATUS=$(jq -r '.status' "$RESULT") -EVENT=$(jq -r '.event // empty' "$RESULT") - -if [ "$STATUS" = "failed" ]; then +if [ "$(jq -r '.status' "$RESULT")" = "failed" ]; then echo "⚠️ $AGENT: 投稿失敗。payload からメインがフォールバック投稿します" >&2 PAYLOAD=$(jq -r '.payload_path' "$RESULT") OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) @@ -318,20 +331,26 @@ if [ "$STATUS" = "failed" ]; then jq --arg sha "$SHA" '.commit_id = $sha' "$PAYLOAD" > /tmp/review-fallback.json gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-fallback.json fi - -echo "$AGENT: event=$EVENT url=$(jq -r .review_url $RESULT)" ``` -**Claude 自身による追加判定は行わず**、外部AIの判定(`event`)と指摘内容をそのまま採用する。 +**Claude 自身による追加判定は行わず**、外部 AI の判定(`event`)と指摘内容をそのまま採用する。 ## 作業完了報告(必須) -レビュー結果は **PR 上に投稿済み** であることが前提。ユーザーへの報告は以下に絞る: +PR モードではレビュー結果が **PR 上に投稿済み** であることが前提。報告は以下に絞る。 -- 利用エージェント(claude / codex / gemini のいずれか) -- 投稿結果(review URL、event = APPROVE / REQUEST_CHANGES / COMMENT) +- 利用エージェント(claude / codex / gemini) +- 投稿結果(review URL、event) - 件数サマリ(インラインコメント数、重要度別内訳) -- 総評(review body)の要約 -- PR URL +- 総評の要約 / PR URL + +詳細な指摘内容は PR 上のインラインコメントに残っているため、報告では繰り返さない。 +`--branch` モードでは投稿先がないため、上記「報告」の書式でセッション上に出力する。 + +## 関連 -詳細な指摘内容は PR 上のインラインコメントに残っているため、ユーザー宛報告では繰り返さない。 +- `/ndf:fix` — レビュー指摘の分類と修正対応 +- `/ndf:cross-review` — codex + gemini の収束レビュー +- `/ndf:codex` — Codex CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:gemini` — Gemini CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-shared/manifests/claude-skills.txt b/plugins/ndf-shared/manifests/claude-skills.txt index 1be1ab6c..a3e3ca80 100644 --- a/plugins/ndf-shared/manifests/claude-skills.txt +++ b/plugins/ndf-shared/manifests/claude-skills.txt @@ -16,9 +16,6 @@ logging-guidelines sync-main cherry-pick-pr deploy -review-branch -review-pr-comments -resolve-pr-comments playwright-authoring codex gemini diff --git a/plugins/ndf-shared/manifests/codex-skills.txt b/plugins/ndf-shared/manifests/codex-skills.txt index 2d710ca5..f719a1a6 100644 --- a/plugins/ndf-shared/manifests/codex-skills.txt +++ b/plugins/ndf-shared/manifests/codex-skills.txt @@ -20,8 +20,5 @@ playwright-planning pr pr-tests problem-solving -resolve-pr-comments review -review-branch -review-pr-comments sync-main diff --git a/plugins/ndf-shared/manifests/kiro-skills.txt b/plugins/ndf-shared/manifests/kiro-skills.txt index d8e05e2c..337d12f7 100644 --- a/plugins/ndf-shared/manifests/kiro-skills.txt +++ b/plugins/ndf-shared/manifests/kiro-skills.txt @@ -16,9 +16,6 @@ logging-guidelines sync-main cherry-pick-pr deploy -review-branch -review-pr-comments -resolve-pr-comments playwright-authoring codex statusline diff --git a/plugins/ndf-shared/skills/cross-review/SKILL.md b/plugins/ndf-shared/skills/cross-review/SKILL.md index 034dae4f..21223ddd 100644 --- a/plugins/ndf-shared/skills/cross-review/SKILL.md +++ b/plugins/ndf-shared/skills/cross-review/SKILL.md @@ -468,10 +468,9 @@ pint / larastan / test / build などは **中断** を原則とする。 ## 関連 - `/ndf:review` — 単発レビュー(AI 直接投稿対応) -- `/ndf:fix` — 修正対応(サブエージェント起動対応) +- `/ndf:fix` — 指摘の分類・修正・返信・Resolve(サブエージェント起動対応) - `/ndf:codex` — codex CLI 呼び出し手順 - `/ndf:gemini` — gemini CLI 呼び出し手順 -- `/ndf:resolve-pr-comments` — Resolve Conversation の詳細 - `/ndf:issue-plan-strategy` — multi-PR ワークフローでは **個別 PR ごとに本 cross-review が原則必須**。 `/ndf:review` 単発や Claude Code の `code-reviewer` は代替にせず、release ブランチへ merge する前に codex + gemini の APPROVE 収束を確認する (Step 6) diff --git a/plugins/ndf-shared/skills/fix/SKILL.md b/plugins/ndf-shared/skills/fix/SKILL.md index 92471ddd..e6c85ee3 100644 --- a/plugins/ndf-shared/skills/fix/SKILL.md +++ b/plugins/ndf-shared/skills/fix/SKILL.md @@ -1,8 +1,8 @@ --- name: fix -description: "Fix actionable PR review comments." -when_to_use: "PRレビューコメント (codex/gemini/人間) の指摘を実際にコード修正で対応したいとき。review-pr-comments で分類した後の修正フェーズに使う。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PR fix', 'review feedback fix', 'コメントに対応して修正'" -argument-hint: "[PR番号] [--defer-nit] [--severity-min critical|major|minor]" +description: "Classify PR review comments, fix the actionable ones, then reply and resolve each thread. Use when responding to PR review feedback from codex, gemini, bots, or humans." +when_to_use: "PR レビューコメントへの対応全般。分類だけしたいときは --classify-only。Triggers: 'PRコメント対応', 'PRレビュー修正', 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR fix', 'classify PR comments', 'コメントに対応して修正', 'Resolveして'" +argument-hint: "[PR番号] [--classify-only] [--defer-nit] [--severity-min critical|major|minor]" allowed-tools: - Bash - Read @@ -12,17 +12,37 @@ allowed-tools: - Grep --- -# PR修正コマンド +# PR コメント対応コマンド -直前PR、または引数で指定されたPRのreview comment確認・修正対応実行。 +指定 PR(省略時は直前 PR)のレビューコメントを **分類 → 修正 → 返信 → Resolve** まで +一貫して処理する。 + +## 引数 + +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | 対象 PR | 直前 PR | +| `--classify-only` | **分類・優先度判定のみ**で終了する(読み取り専用)。修正・返信・Resolve は行わない | OFF | +| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | +| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` | + +``` +/ndf:fix # 直前 PR のコメントに対応 +/ndf:fix 9352 # PR 番号を指定 +/ndf:fix 9352 --classify-only # まず全体像を把握したいとき +/ndf:fix 9352 --defer-nit # nit を残して critical/major/minor だけ修正 +``` + +大量のコメントがある PR では、`--classify-only` で全体像と優先度を確認してから修正へ +進むと、修正範囲の判断を誤りにくい。 ## 起動モード -このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** の両方に対応する。 -長丁場のクロスレビューループ(`/ndf:cross-review`)からは **必ずサブエージェント経由で起動** されることを想定: +このスキルは **メインセッション直接実行** と **サブエージェント (`general-purpose`) 起動** +の両方に対応する。長丁場のクロスレビューループ(`/ndf:cross-review`)からは +**必ずサブエージェント経由で起動** されることを想定する。 ```python -# メインからの起動例(cross-review が内部でこれを行う) Agent( subagent_type="general-purpose", description="Fix PR review comments (sub-agent)", @@ -41,263 +61,284 @@ PR: **修正 → コミット → push → reply → Resolve Conversation** まで実行する。 メインへの戻り値は最小限のサマリのみ。 -## 引数 +## コメントの取得(3 ソース) -| 引数 | 意味 | 既定 | -|---|---|---| -| `[PR番号]` | 対象 PR | 直前 PR | -| `--defer-nit` | nit 指摘は修正せず deferred としてリスト出力 | OFF | -| `--severity-min LEVEL` | 指定重要度未満は無視(`critical` / `major` / `minor`) | `minor` (= minor 以上を修正) | +インラインコメント / レビュー body / PR レベルコメントを一括取得する。 +どれか 1 つでも欠けると指摘を取りこぼす。 + +`$ARGUMENTS` には PR 番号とオプションが混在するため、**そのまま PR 番号として扱わない**。 +数値トークンだけを PR 番号として取り出し、`--` で始まるトークンはオプションとして解釈する。 -## 重要度ベースの自動修正ポリシー +```bash +# PR 番号 = 最初の数値トークン。無ければ直前 PR +PR_NUMBER=$(printf '%s\n' "$ARGUMENTS" | tr ' ' '\n' | grep -m1 -E '^[0-9]+$' || true) +PR_NUMBER="${PR_NUMBER:-$(gh pr view --json number --jq .number)}" + +# オプションは $ARGUMENTS から個別に判定する +case " $ARGUMENTS " in *" --classify-only "*) CLASSIFY_ONLY=1 ;; esac +case " $ARGUMENTS " in *" --defer-nit "*) DEFER_NIT=1 ;; esac +SEVERITY_MIN=$(printf '%s\n' "$ARGUMENTS" | sed -n 's/.*--severity-min[ =]\([a-z]*\).*/\1/p') +SEVERITY_MIN="${SEVERITY_MIN:-minor}" + +FETCH_SCRIPT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh" +"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" + +# 補助情報 +gh pr view "$PR_NUMBER" --json reviewDecision,body +``` + +GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用する。 + +**PR 本文を必ず読む**。「やらないこと」「別 PR 対応」セクションに記載された内容への +指摘は、この PR では対応しない(分類は「別 PR 対応」)。 + +## 重要度の判定 -`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` 出力規約)で分類。 -**ただし重要度ラベルを鵜呑みにしない** — 各指摘ごとにコード/仕様を独自に調査し、 -本来の重要度を判定し直してから下表の動作を適用する(bot のラベリングは参考値に過ぎない)。 +`[重要度 / カテゴリ]` プレフィックス(`/ndf:review` の出力規約)を手がかりにするが、 +**重要度ラベルを鵜呑みにしない**。各指摘ごとにコード・仕様を独自に調査し、本来の重要度を +判定し直してから下表の動作を適用する。bot のラベリングは参考値に過ぎない。 | 重要度 | 動作 | ユーザ問い合わせ | |---|---|---| | `critical` | **必ず自動修正** | なし | | `major` | **必ず自動修正** | なし | -| `minor` / `nit` (パフォーマンス・可読性・重複コード排除) | **このPRで修正対応**。特にトータル行数が減る方向の修正は積極的に実施 | なし | -| `minor` / `nit` (上記カテゴリ、修正範囲が +30 行を超えそう) | ユーザ問い合わせ | あり | -| `minor` (その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred 扱い | なし | -| `nit` (その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加。最後にまとめてユーザ問い合わせ | あり(最後に1回) | +| `minor` / `nit`(パフォーマンス・可読性・重複コード排除) | **この PR で修正**。特にトータル行数が減る方向の修正は積極的に実施 | なし | +| `minor` / `nit`(上記カテゴリ、修正範囲が +30 行を超えそう) | deferred | あり | +| `minor`(その他) | 自動修正(明らかな改善のみ)。判断が割れるなら `nit` として deferred | なし | +| `nit`(その他) | `--defer-nit` 指定時は **修正せず deferred リスト** に追加 | あり(最後に 1 回) | **重要度の独自判定**: -- AI agent (CodeRabbit / Copilot 等) が `nit` と付けていても、実体がパフォーマンス改善や重複排除なら **minor/nit カテゴリ修正対象** として扱う -- 逆に AI agent が `critical` と付けていても、実害がないスタイル指摘なら `nit` 相当に格下げして deferred 化してよい -- 重要度はカテゴリ(performance/readability/duplication/security/style/etc)と合わせて、コード本体を読んだ上で判定する +- AI agent(CodeRabbit / Copilot 等)が `nit` と付けていても、実体がパフォーマンス改善や + 重複排除なら修正対象として扱う +- 逆に `critical` と付いていても、実害がないスタイル指摘なら `nit` 相当に格下げしてよい +- 重要度はカテゴリ(performance / readability / duplication / security / style 等)と + 合わせて、コード本体を読んだ上で判定する **指摘の正否判断**: -- ロジック・仕様逸脱・セキュリティ: コード/仕様を確認してから修正可否判断 -- bot 指摘で **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘する等): 修正しない、reply で理由説明 -- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象(critical でもエスカレーション) - -**自動判断できない場合の取り扱い** (context 節約のため安易に user に投げない): -- 仕様文書(docs/, README)を読んで判断する -- 既存テストを読んで挙動を確認する -- 関連する他コードの慣例を確認する -- それでも不明なら deferred リストに「要ユーザ判断」として記録、最後にまとめて問い合わせ - -## 手順 - -1. review comment取得 + 重要度を**独自に再判定**(AI agent のラベルは参考値) -2. **CIエラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) - - **完了待ちはしない**。実行中(PENDING/IN_PROGRESS)のチェックは無視して次ステップへ進む - - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む -3. 修正対象を確定: - - `critical` / `major` → 全件修正対象 - - `minor` / `nit` (パフォーマンス・可読性・重複排除) → 修正対象。+30行超なら **deferred + ユーザ問い合わせ** - - `minor` (その他) → 修正対象(明らかでないものは `deferred[]` へ) - - `nit` (その他、`--defer-nit` 時) → `deferred[]` のみ、修正しない - - CIエラー → 全件修正対象(PRテスト範囲外の **flaky テストも見つけ次第修正**) -4. 問題点修正 - - **コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去 等) -5. **コミット前の再確認**(修正作業中に状況が変わっている可能性への対応) - - **review comment再取得**: 作業中に新しいコメントが追加されていないか確認 - - **CI状態再確認**: 現時点の状態だけ確認(完了待ちはしない)。新しい失敗が出ていれば対象に取り込む - - 新しい指摘/失敗があれば手順3に戻る -6. コミット・プッシュ -7. PRにSummaryコメントを追加(対応した件数 + deferred 件数を明記) -8. 対応したインラインコメントに個別に返信 -9. **deferred スレッドには `[deferred / nit]` のラベル付き返信** を投稿(resolve はしない) -10. reviewerに再レビューを依頼 -11. 対応完了したインラインコメントを「Resolve Conversation」にする(`resolveReviewThread` mutation) - - resolve した thread_id / comment_id / path / line を `resolved_threads[]` に記録 - - `deferred` / `rejected` の thread は Resolve しない(次ラウンドで再評価するため) -12. **戻り値ファイルを書き出す**: `/tmp/fix-pr<番号>-result.json` (後述「戻り値フォーマット」参照) - - `ci_failed_checks` には `gh pr checks --json name,state` から `state=FAILURE` の name を抽出して列挙 - - push 直後の CI 再実行結果は**待たない**ため、戻り値の `ci_status` は push 時点での既知失敗のみを反映する +- ロジック・仕様逸脱・セキュリティ: コード / 仕様を確認してから修正可否を判断 +- bot 指摘が **明らかに誤読** している場合(例: 意図的な変数展開を「クオート不足」と指摘): + 修正せず reply で理由を説明(`rejected` として記録、Resolve しない) +- 仕様判断が必要な指摘(API 変更、互換性破壊など): ユーザ問い合わせ対象 -- 4〜6はgit、1〜2/5と7以降はgithub mcpまたはghを利用 +**自動判断できない場合**(context 節約のため安易にユーザへ投げない): +仕様文書(`docs/`, `README`)を読む → 既存テストを読んで挙動を確認する → 関連する他コードの +慣例を確認する。それでも不明なら deferred リストに「要ユーザ判断」として記録し、最後に +まとめて問い合わせる。 -**flakyテストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第このPRで修正する。 -flaky を放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれるため。 +## `--classify-only` の出力 -## CIエラーチェック +修正は一切行わず、次の形式で分類結果だけを報告する。 -### 失敗ジョブの検出 +| カテゴリ | 説明 | 対応判断 | +|---|---|---| +| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | +| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | +| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | +| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | +| 🔵 別 PR 対応 | PR 本文で別 PR 対応と明記されている内容 | **対応不要** | + +```markdown +## PR #XXXX コメント分類結果 + +### サマリー +- 総コメント数 / 対応必須 / 対応推奨 / 対応すべき / 対応任意・不要 + +### 詳細 +| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | +|---|---|---|---|---|---| +| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | + +### 推奨アクション +1. 対応すべき項目(重大 + 軽微) +2. 対応推奨項目 +3. 別 PR で対応(コメントで返信推奨) +``` -```bash -# PRの全チェック状態を確認(FAIL/PASS/PENDING) -gh pr checks +分類の根拠(なぜその分類になったか)を簡潔に添える。 -# JSON形式で詳細取得 -gh pr checks --json name,state,link,completedAt +## 修正手順 -# 失敗ジョブのみ抽出 -gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" +1. コメント取得(上記 3 ソース)+ 重要度を**独自に再判定** +2. **CI エラー確認**(`gh pr checks ` で **現時点の** 失敗ジョブを検出) + - **完了待ちはしない**。実行中(PENDING / IN_PROGRESS)は無視して次へ進む + - 直近で失敗(FAILURE)状態のジョブのみを修正対象に取り込む +3. 修正対象を確定(「重要度の判定」の表に従う)。CI エラーは全件修正対象 +4. 問題点を修正。**コード行数が減る方向の修正は積極的に実施**(重複排除、不要分岐除去) +5. **コミット前の再確認** — 作業中に新しいコメントが追加されていないか再取得し、CI 状態も + 現時点だけ確認する(完了待ちはしない)。新しい指摘・失敗があれば手順 3 に戻る +6. コミット・プッシュ +7. **PR レベルの Summary コメントを投稿**(対応件数 + deferred 件数を明記) +8. 対応したインラインコメントに個別に返信 +9. **deferred スレッドには `[deferred / nit]` ラベル付き返信** を投稿(Resolve はしない) +10. reviewer に再レビューを依頼 +11. 対応完了したスレッドを **Resolve Conversation** にする +12. **戻り値ファイルを書き出す**(後述) + +**flaky テストの扱い**: PR の変更範囲外で発生している flaky テストも、見つけ次第この PR で +修正する。放置するとリポジトリ全体のコード品質が下がり、後続 PR の CI 信頼性も損なわれる。 + +## CI エラーチェック -# 実行中ジョブのみ抽出(状態スナップショット用。完了は待たない) +```bash +gh pr checks # 全チェック状態 +gh pr checks --json name,state,link # JSON 形式 gh pr checks --json name,state | \ - python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state'] in ('PENDING','IN_PROGRESS','QUEUED')]" + python3 -c "import json,sys; [print(c['name']) for c in json.load(sys.stdin) if c['state']=='FAILURE']" ``` -### CI完了待ちはしない +**CI 完了待ちはしない**(`gh pr checks --watch` 等は使わない)。各チェックポイントでは +「現時点で FAILURE のジョブ」のみを取り込む。push 後の CI 再実行結果も待たない。 +ただし状態スナップショットの取得は行い、戻り値の `ci_status` / `ci_failed_checks` に反映する。 -このスキルでは **CI 完了待ちは行わない**(`gh pr checks --watch` 等は使わない)。 -- 各チェックポイントでは「現時点で FAILURE のジョブ」のみを取り込んで修正する -- push 後の CI 再実行結果も待たない(待機中に context を消費しないため) -- ただし `gh pr checks --json name,state` での **状態スナップショット取得は実施** - し、戻り値の `ci_status` / `ci_failed_checks` に反映する - -### 失敗ログの取得 +失敗ログの取得: ```bash -# ワークフロー実行ID取得 RUN_ID=$(gh run list --branch --limit 1 --json databaseId --jq '.[0].databaseId // empty') [ -z "$RUN_ID" ] && { echo "No CI run found for this branch"; exit 0; } - -# 失敗ステップのログだけ表示(効率的) -gh run view $RUN_ID --log-failed - -# 特定ジョブのログ -gh run view $RUN_ID --job --log +gh run view $RUN_ID --log-failed # 失敗ステップのログだけ ``` -### CIエラーの分類と対応方針 - | エラー種別 | 対応方針 | |---|---| | **lint/format** | 自動修正ツール実行(`ruff`, `prettier`, `eslint --fix` 等)→ コミット | | **型チェック** | 型定義・アノテーションを修正。無視コメントは原則禁止(根本対応) | -| **テスト失敗** | 失敗テストを読み、実装/テストどちらが正しいか判断してから修正。テスト側の問題なら仕様確認 | +| **テスト失敗** | 失敗テストを読み、実装 / テストどちらが正しいか判断してから修正 | | **ビルドエラー** | 依存関係・構文・設定ファイルを確認 | | **依存脆弱性** | 可能ならバージョン更新、無理なら除外ルール追加(理由明記) | -| **タイムアウト/flaky** | retry設定、テスト分割、リトライ追加。**PR範囲外の flaky も見つけ次第修正**(放置でリポジトリ全体の品質劣化を招くため) | -| **インフラ一時障害** | 再実行で解消することがあるため `gh run rerun $RUN_ID` を先に試す | +| **タイムアウト/flaky** | retry 設定、テスト分割。**PR 範囲外の flaky も見つけ次第修正** | +| **インフラ一時障害** | `gh run rerun $RUN_ID` を先に試す | -### review指摘との統合 +review 指摘と CI エラーは**同じ PR で一緒に修正**する。同じファイル・機能に関するものは +1 コミットにまとめ、独立しているなら別コミットに分離する。 -review指摘とCIエラーは**同じPRで一緒に修正**する: -- 同じファイル・機能に関する指摘とCIエラーは1コミットにまとめる -- 独立しているなら別コミットに分離(git log で追いやすい) +## 返信と Resolve -## ghコマンド例 +### 返信の書き分け -### PR コメント一括取得 (3 ソース) - -```bash -# インラインコメント / レビュー body / PR レベルコメントを一括取得 -FETCH_SCRIPT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" -``` - -### コメントへの返信 +| 状況 | 返信の型 | +|---|---| +| 修正した | `対応しました — <ファイル>:<行> で〇〇 (commit )` | +| 別 PR で対応 | `別 PR で対応予定です。PR 説明の「やらないこと」に記載のとおり、<理由>` | +| deferred | `[deferred / nit] 後続 PR で対応予定` | +| rejected | `bot 指摘は誤読です — 理由: ...` | +| 対応不要 | `確認しました。<対応不要と判断した理由>` | ```bash -# PRのレビューコメント一覧を取得 (インラインコメントのみ) -gh api repos/{owner}/{repo}/pulls/{pr_number}/comments - -# 特定のコメントに返信(in_reply_to にコメントIDを指定) +# 特定のコメントに返信(in_reply_to にコメント ID を指定) gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \ - -f body="修正しました。" \ - -F in_reply_to={comment_id} + -f body="対応しました。" -F in_reply_to={comment_id} ``` ### Resolve Conversation -```bash -# GraphQL APIでスレッドをresolveする -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: "{thread_node_id}"}) { - thread { isResolved } - } - } -' -``` +**修正済みのスレッドのみ** Resolve する。`deferred` / `rejected` は次ラウンドで再評価する +ため Resolve しない。 -### thread_node_idの取得方法 +`resolveReviewThread` が要求するのは **review thread** の ID(`PRRT_...`)であり、 +レビューコメントの `node_id`(`PRRT_` ではなく `PRRC_...`)ではない。 +`repos/{owner}/{repo}/pulls/comments/` から引ける `node_id` はコメント側の ID +なので **Resolve には使えない**。必ず下記 query の `nodes[].id` を使い、 +`comments.nodes[].databaseId`(返信に使ったコメント ID)または本文と突き合わせて特定する。 ```bash -# PRのレビュースレッド一覧を取得(node_id含む) +# スレッド一覧を thread ID (PRRT_...) 付きで取得 gh api graphql -f query=' query { repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {pr_number}) { reviewThreads(first: 100) { nodes { - id - isResolved - comments(first: 1) { - nodes { body } - } + id isResolved path line + comments(first: 1) { nodes { databaseId body } } } } } } - } -' + }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] + | select(.isResolved == false) + | {thread_id: .id, path, line, comment_id: .comments.nodes[0].databaseId}' + +# 上で得た thread_id(PRRT_...)を THREAD_ID に入れて Resolve +gh api graphql -f query=' + mutation($id: ID!) { + resolveReviewThread(input: {threadId: $id}) { thread { isResolved } } + }' -f id="$THREAD_ID" ``` -**方針**: -- 品質・可読性・セキュリティ向上、既存機能影響なし -- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断すること -- 未対応の場合はその理由をコメントに書き込む +### PR レベル Summary コメント(必須) + +インラインへの返信と Resolve **だけでは不十分**。PR ページの Conversation タブに +まとめが出ないと、レビュアー視点で見落とされる。 + +```bash +gh pr comment --body "$(cat <<'EOMD' +## 🔧 /ndf:fix サマリ + +対応件数: critical=X / major=Y / minor=Z (合計 N 件) +deferred: D 件 / rejected: R 件 +commit: +CI: SUCCESS | FAILURE | NONE + +### 詳細 +- 各 thread の対応概要(行リンク付き) +EOMD +)" +``` ## 戻り値フォーマット(必須) -サブエージェント呼び出し時の context 節約のため、**実行結果は `/tmp/fix-pr<番号>-result.json` に書き出す**: +サブエージェント呼び出し時の context 節約のため、**実行結果を +`$TMP_DIR/fix-pr<番号>-result.json` に書き出す**(`$TMP_DIR` は環境変数 +`CROSS_REVIEW_TMP_DIR` があればそれ、なければ `/tmp`)。 ```json { "pr": 67, "fix_commit": "abc1234", - "ci_status": "SUCCESS" | "FAILURE" | "PENDING" | "NONE", + "ci_status": "SUCCESS", "ci_failed_checks": [], "ci_note": null, "fixed_count": 5, "by_severity": {"critical": 1, "major": 2, "minor": 2, "nit": 0}, "resolved_threads": [ - { - "thread_id": "PRRT_...", - "comment_id": 3222849090, - "path": "src/foo.py", - "line": 42 - } + {"thread_id": "PRRT_...", "comment_id": 3222849090, "path": "src/foo.py", "line": 42} ], "deferred": [ - { - "comment_id": 3222849090, - "thread_id": "PRRT_...", - "path": "src/foo.py", - "line": 42, - "severity": "nit", - "category": "style", - "summary": "末尾セミコロンの有無", - "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし" - } + {"comment_id": 3222849090, "thread_id": "PRRT_...", "path": "src/foo.py", "line": 42, + "severity": "nit", "category": "style", "summary": "末尾セミコロンの有無", + "reason_for_deferral": "好みの範囲。プロジェクト規約と齟齬なし"} ], "rejected": [ - { - "comment_id": 3222849090, - "summary": "heredoc を <<'JSON' にせよ", - "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる" - } + {"comment_id": 3222849090, "summary": "heredoc を <<'JSON' にせよ", + "reason_for_rejection": "$SHA を意図的に展開する必要があり、クオート化すると逆に壊れる"} ], "summary_comment_url": "https://github.com/.../pull/67#issuecomment-..." } ``` -**フィールド説明**: +- `resolved_threads` / `deferred` / `rejected` は **必ず配列**で返す(件数の int は誤り)。 + 該当が無ければ空配列 +- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。 + `/ndf:cross-review` 側で code-related(`pint` / `larastan` / `test` / `build` / `lint` / + `type`)と meta-only(`check_pr_requirements` / `assignees` / `reviewers` / `labels`)を + 分類し、メタチェックのみ失敗ならループを継続する +- `ci_note` — code-related ではない CI 失敗の補足 -- `ci_failed_checks` — `ci_status = FAILURE` のとき、失敗した check 名の配列。`/ndf:cross-review` 側で code-related (`pint/larastan/test/build/lint/type`) と meta-only (`check_pr_requirements/assignees/reviewers/labels`) を分類し、メタチェックのみ失敗ならループ継続する -- `ci_note` — code-related ではない CI 失敗の補足。例: `"メタチェックのみ失敗: check_pr_requirements — Assignees 未設定"` -- `resolved_threads` — 手順 11 で `resolveReviewThread` mutation を実行したスレッド一覧。`deferred` / `rejected` の thread は **Resolve しない**(再評価のため) +## 方針 -サブエージェントとして起動された場合は、この JSON をメインに返すサマリの基礎とする。 +- 品質・可読性・セキュリティ向上を目的とし、既存機能に影響を与えない +- 指摘がすべて正しいとは限らない。修正前に仕様を調査し、実施の可否を判断する +- 未対応の場合はその理由をコメントに書き込む ## 作業完了報告(必須) -メイン or PR への報告内容(戻り値ファイルから抽出): -- 対応した指摘の件数(重要度別: critical/major/minor/nit) -- **deferred 件数**(主に nit、最後にユーザ問い合わせ予定) -- **rejected 件数**(bot 指摘が不適切で修正しなかった件、各々理由付き) -- **対応したCIエラーの一覧**(ジョブ名、エラー内容、修正方法) -- **対応した flaky テストの一覧**(PR範囲外も含む) -- 修正コミット SHA / 修正ファイル一覧 -- 戻り値ファイルパス: `/tmp/fix-pr<番号>-result.json` -- **PR URL を最後に必ず記載**(例: `https://github.com///pull/<番号>`) +- 対応した指摘の件数(重要度別)/ deferred 件数 / rejected 件数(各々理由付き) +- 対応した CI エラーの一覧(ジョブ名、エラー内容、修正方法) +- 対応した flaky テストの一覧(PR 範囲外も含む) +- 修正コミット SHA / 修正ファイル一覧 / 戻り値ファイルパス +- **PR URL を最後に必ず記載** + +## 関連 + +- `/ndf:review` — PR / ブランチのレビュー(Approve / Request Changes 判定) +- `/ndf:cross-review` — codex + gemini の収束レビュー。内部からこの Skill を呼ぶ diff --git a/plugins/ndf-shared/skills/issue-plan-strategy/SKILL.md b/plugins/ndf-shared/skills/issue-plan-strategy/SKILL.md index add1e621..175939ce 100644 --- a/plugins/ndf-shared/skills/issue-plan-strategy/SKILL.md +++ b/plugins/ndf-shared/skills/issue-plan-strategy/SKILL.md @@ -232,7 +232,7 @@ git worktree add ../--ui feature/-ui | 用途 | コマンド | 位置づけ | |---|---|---| -| PR 作成前のセルフレビュー | `/ndf:review-branch` | push / PR 化の前段。cross-review の代替にはしない | +| PR 作成前のセルフレビュー | `/ndf:review --branch` | push / PR 化の前段。cross-review の代替にはしない | | 個別 PR の収束レビュー (原則必須) | `/ndf:cross-review ` | codex + gemini 両方の APPROVE 収束を確認する本線 | | GitHub 上の例外的な単発確認 | `/ndf:review ` | ごく軽微な差分の単発確認に限定。cross-review の代替にはしない | | 指摘の修正 | `/ndf:fix ` | cross-review ループ内・後で自動起動される | @@ -353,6 +353,6 @@ git checkout release/ - `/ndf:branch-fix-strategy` — ブランチ汚染を避ける原則 - `/ndf:pr` — 通常の PR 作成 / 更新 - `/ndf:cherry-pick-pr` — 検証ブランチへの cherry-pick PR -- `/ndf:review` / `/ndf:review-branch` / `/ndf:cross-review` — レビュー -- `/ndf:fix` / `/ndf:resolve-pr-comments` — コメント対応 +- `/ndf:review` / `/ndf:cross-review` — レビュー(`--branch` で PR 前のセルフレビュー) +- `/ndf:fix` — コメントの分類・修正・返信・Resolve - `/ndf:playwright-planning` — release ブランチでの E2E 結合テスト diff --git a/plugins/ndf-shared/skills/playwright-authoring/SKILL.md b/plugins/ndf-shared/skills/playwright-authoring/SKILL.md index 32754982..3742e685 100644 --- a/plugins/ndf-shared/skills/playwright-authoring/SKILL.md +++ b/plugins/ndf-shared/skills/playwright-authoring/SKILL.md @@ -243,7 +243,7 @@ Chrome DevTools MCP の利用可能な方を自動選択する。どちらも使 - `/ndf:playwright-evidence` — 証跡とレポート (後段) - `/ndf:playwright-kit-ops` — 実行環境の運用 (init_project / codegen / スキャン) - `/ndf:docker-container-access` — Docker コンテナアクセス一般 -- `/ndf:review-branch` — 変更差分のコードレビュー +- `/ndf:review --branch` — 変更差分のコードレビュー - `/ndf:pr-tests` — PR Test Plan の自動実行 > `playwright-planning` / `playwright-evidence` / `playwright-kit-ops` は Codex 公開セットに同梱される。 diff --git a/plugins/ndf-shared/skills/resolve-pr-comments/SKILL.md b/plugins/ndf-shared/skills/resolve-pr-comments/SKILL.md deleted file mode 100644 index 433a72d6..00000000 --- a/plugins/ndf-shared/skills/resolve-pr-comments/SKILL.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -name: resolve-pr-comments -description: "Reply to and resolve fixed PR comments." -argument-hint: "[PR番号]" -disable-model-invocation: true -allowed-tools: - - Bash - - Read ---- - -# PRコメントResolveコマンド - -対応済みのPRコメント全てに返信し、スレッドを resolved にする。`/ndf:fix` で修正完了後に呼び出す**クロージング専用**コマンド。 - -## 使用方法 - -``` -/ndf:resolve-pr-comments # 現在のブランチのPRを対象 -/ndf:resolve-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | fix | resolve-pr-comments | -|---|---|---| -| 動作 | コード修正+commit+push | 返信+スレッドresolve | -| 前提 | レビュー後、修正が必要 | 修正済み、クロージングのみ | -| 推奨順序 | 先に実行 | fix後の最後に実行 | - -## 処理フロー - -### 1. PR情報の取得 - -```bash -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 - -GitHub API でレビューコメントを取得: - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" -``` - -### 3. 対応状況の確認 - -各コメントについて、対応済みかどうかを確認する: -- コードの変更履歴(`git log`, `git diff`)と照合 -- 指摘された問題が修正されているか確認 -- PR body の「やらないこと」セクションで別PR対応と明記されているか確認 - -### 4. コメントへの返信 - -対応済みのコメントに対して、内容に応じた返信を投稿する: - -#### 修正対応した場合 -``` -対応しました。 - -{修正内容の簡潔な説明} -``` - -#### 別PRで対応予定の場合 -``` -別PRで対応予定です。 - -PR説明の「やらないこと」に記載の通り、{理由}のため別PRで対応します。 -``` - -#### 対応不要と判断した場合 -``` -確認しました。 - -{対応不要と判断した理由} -``` - -### 5. gh CLI コマンド - -#### レビューコメントに返信(スレッド内) - -```bash -gh api "repos/:owner/:repo/pulls/$PR_NUMBER/comments" \ - -f body="返信メッセージ" \ - -f in_reply_to= -``` - -#### スレッドをResolve(GraphQL) - -まず Thread Node ID を取得: - -```bash -gh api "repos/:owner/:repo/pulls/comments/" --jq '.node_id' -``` - -その上でResolve: - -```bash -gh api graphql -f query=' - mutation { - resolveReviewThread(input: {threadId: ""}) { - thread { isResolved } - } - } -' -``` - -### 6. 実行フロー - -各コメントに対して以下を順次実行: - -1. コメントの内容と対応状況を確認 -2. 適切な返信メッセージを生成 -3. 返信を投稿 -4. スレッドをresolve -5. 結果を報告 - -### 7. 出力フォーマット - -```markdown -## PR #XXXX コメント対応結果 - -### 処理結果 -| # | コメント | 返信内容 | Resolve | -|---|---------|---------|---------| -| 1 | {指摘要約} | 対応しました | ✅ | -| 2 | {指摘要約} | 別PRで対応予定 | ✅ | - -### サマリー -- 処理済み: X件 -- Resolved: X件 -- エラー: X件 -``` - -## 重要ルール - -- **確認してから実行**: 各コメントの対応状況を必ず確認してから返信 -- **コード修正はしない**: 修正は `/ndf:fix` の責務。このコマンドはクロージングのみ -- **適切な返信**: 対応内容に応じた適切な返信メッセージを使用 -- **エラーハンドリング**: API エラー発生時は報告して継続 -- **ユーザー確認**: 判断に迷う場合はユーザーに確認を求める - -## 関連 - -- `/ndf:review-pr-comments` — コメント分類・優先度判定 (READ-ONLY) -- `/ndf:fix` — コメント対応の修正を実施 diff --git a/plugins/ndf-shared/skills/review-branch/SKILL.md b/plugins/ndf-shared/skills/review-branch/SKILL.md deleted file mode 100644 index 951e5ea1..00000000 --- a/plugins/ndf-shared/skills/review-branch/SKILL.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -name: review-branch -description: "Review the current branch before opening a PR." -when_to_use: "PR作成前にローカルブランチの実装をセルフレビューしたいとき。Triggers: 'ブランチをレビュー', 'PR前にレビュー', 'セルフレビュー', 'review my branch', 'review before PR', 'self review', 'pre-PR review'" -argument-hint: "[focus-area] (例: security, performance, tests)" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# ブランチ実装レビューコマンド - -現在のブランチで実装された変更を**PR作成前に**コードレビューする。mainブランチとの差分を分析し、コード品質・セキュリティ・パフォーマンスの観点でフィードバックを返す。 - -## `/ndf:review` との使い分け - -| 観点 | review-branch | review | -|---|---|---| -| 対象 | ローカルブランチの差分(PR前) | GitHub上の既存PR | -| 判定 | フィードバックを返す | Approve / Request Changes を判定 | -| 用途 | PR作成前のセルフレビュー | PR作成後のレビュー | - -## 使用方法 - -``` -/ndf:review-branch # 全般レビュー -/ndf:review-branch security # セキュリティに焦点 -/ndf:review-branch performance # パフォーマンスに焦点 -/ndf:review-branch tests # テスト網羅性に焦点 -/ndf:review-branch "ビジネスロジック" # 任意のフォーカス -``` - -## レビュー手順 - -### 1. 変更の把握 - -```bash -git diff main --name-only # 変更ファイル一覧 -git diff main --stat # 差分の統計 -git log main..HEAD --oneline # コミット履歴 -``` - -### 2. 変更内容の分析 - -各変更ファイルに対して以下を確認: - -- **追加・変更されたロジック**: 意図が明確か、正しく実装されているか -- **テストカバレッジ**: 適切なテストが追加されているか -- **コーディング規約**: プロジェクトの規約に準拠しているか - -### 3. 品質チェック観点 - -#### コード品質 -- 命名規則の一貫性 -- 関数/メソッドの責務(単一責任原則) -- DRY原則(重複コードの排除) -- 可読性・保守性 -- 過剰な抽象化がないか(YAGNI) - -#### セキュリティ -- SQLインジェクション対策 -- XSS対策 -- CSRF対策 -- 入力値バリデーション -- 認証・認可の適切性 -- 機密情報(トークン、キー、PII)の取り扱い - -#### パフォーマンス -- N+1 クエリの有無 -- 不要なデータベースアクセス -- メモリ使用量 -- インデックスの活用 - -#### エラーハンドリング -- 例外が適切に捕捉されているか -- ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) -- リトライ/タイムアウトの設計 - -### 4. レビュー結果の報告 - -```markdown -## レビュー結果 - -### 概要 -- 変更ファイル数: X -- 追加行数: +XXX -- 削除行数: -XXX - -### Good(良い点) -- ... - -### Suggestions(改善提案) -- `path/to/file.ext:123` — 提案内容 - -### Issues(要修正) -- `path/to/file.ext:456` — 問題点と修正方針 -``` - -## 使用例 - -```bash -# 全般的なレビュー -/ndf:review-branch - -# セキュリティ重視(認証系変更など) -/ndf:review-branch security - -# N+1クエリ等のパフォーマンス問題に焦点 -/ndf:review-branch performance - -# テストの網羅性を確認 -/ndf:review-branch tests -``` - -## 注意事項 - -- 大量の変更がある場合、重要な変更から優先的にレビューする -- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする -- レビュー結果は提案であり、最終判断は開発者が行う -- **コード修正は行わない**(分析とフィードバックのみ。修正は `/ndf:fix` で別途実行) - -## 関連 - -- `/ndf:review` — PR単位レビュー (Approve/Request Changes判定) -- `/ndf:review-pr-comments` — 既存PRコメントの分類 -- `/ndf:fix` — PRレビューコメントの修正対応 -- `/ndf:logging-guidelines` — ログ設計 diff --git a/plugins/ndf-shared/skills/review-pr-comments/SKILL.md b/plugins/ndf-shared/skills/review-pr-comments/SKILL.md deleted file mode 100644 index 1b51139d..00000000 --- a/plugins/ndf-shared/skills/review-pr-comments/SKILL.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -name: review-pr-comments -description: "Classify existing PR comments before fixing." -when_to_use: "既存PRのレビューコメントを分類・優先度判定したいとき (修正前)。Triggers: 'PRコメントを確認', 'PRコメントを分類', 'コメント対応の優先度', 'PR comments review', 'classify PR comments', 'PRレビュー結果を見て'" -argument-hint: "[PR番号]" -allowed-tools: - - Bash - - Read - - Glob - - Grep ---- - -# PRコメント分析コマンド (READ-ONLY) - -GitHub PRのレビューコメントを全て確認し、対応可否を判定する。**修正は一切行わない。分析・判定のみ**。 - -## 使用方法 - -``` -/ndf:review-pr-comments # 現在のブランチのPRを対象 -/ndf:review-pr-comments 9352 # PR番号を指定 -``` - -## `/ndf:fix` との使い分け - -| 観点 | review-pr-comments | fix | -|---|---|---| -| 動作 | 分類・優先度判定のみ | 実際にコード修正 | -| 出力 | 分類テーブル+推奨アクション | 修正差分+commit | -| 推奨順序 | 最初に実行 | review-pr-commentsの結果を見て実行 | - -「まず全体像を把握 → 優先度を決めてから修正」という流れに使う。 - -## 処理フロー - -### 1. PR情報の取得 - -引数でPR番号が指定されていればそれを使用、なければ現在のブランチから取得。 - -```bash -CURRENT_BRANCH=$(git branch --show-current) -PR_NUMBER="${ARGUMENTS:-$(gh pr view --json number --jq .number)}" -``` - -### 2. PRコメント取得 (3 ソース) - -fix skill の共有スクリプトで インラインコメント / レビュー body / PR レベルコメントを一括取得: - -```bash -FETCH_SCRIPT="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh" -"$FETCH_SCRIPT" "$(gh repo view --json nameWithOwner -q .nameWithOwner)" "$PR_NUMBER" -``` - -補助情報 (reviewDecision 等): - -```bash -gh pr view "$PR_NUMBER" --json reviewDecision -``` - -GitHub MCP を使う場合は `mcp__github__get_pull_request_comments` を利用。 - -### 3. コメント分析・分類 - -各コメントを以下のカテゴリに分類する: - -| カテゴリ | 説明 | 対応判断 | -|---------|------|---------| -| 🔴 重大 | セキュリティ、データ整合性、クラッシュの可能性 | **対応必須** | -| 🟡 改善推奨 | コード品質、保守性、ベストプラクティス | **対応推奨** | -| 🟢 軽微 | タイポ、フォーマット、命名規則 | **対応すべき** | -| ⚪ 参考 | 提案、質問、情報共有 | **対応任意** | -| 🔵 別PR対応 | 別PRで対応予定と明記されている内容 | **対応不要** | - -### 4. 出力フォーマット - -```markdown -## PR #XXXX コメントレビュー結果 - -### サマリー -- 総コメント数: X件 -- 対応必須: X件 -- 対応推奨: X件 -- 対応すべき: X件 -- 対応任意/不要: X件 - -### 詳細 - -| # | ファイル | 行 | 指摘内容 | 分類 | 対応判断 | -|---|---------|----|---------|----|---------| -| 1 | path/to/file.ext | 123 | 指摘の要約 | 🔴 重大 | **対応必須** | -| 2 | ... | ... | ... | ... | ... | - -### 推奨アクション -1. まず対応すべき項目(重大+軽微) -2. 次に対応推奨項目 -3. 別PRで対応(コメントで返信推奨) -``` - -## 重要ルール - -- **READ-ONLY**: コードの修正は一切行わない -- **PR説明文を確認**: 「やらないこと」「別PR対応」セクションに記載されている内容は「🔵 別PR対応」として分類 -- **コンテキスト理解**: コメントが指摘している問題の本質を理解して分類 -- **判断根拠**: なぜその分類になったかの理由を簡潔に説明 - -## 関連 - -- `/ndf:fix` — 分類結果を踏まえてコード修正を実施 -- `/ndf:resolve-pr-comments` — 修正完了後の返信+Resolve -- `/ndf:review` — PRを新規にレビューする (Approve/Request Changes判定) diff --git a/plugins/ndf-shared/skills/review/SKILL.md b/plugins/ndf-shared/skills/review/SKILL.md index 5dfeb4a8..983c4e4a 100644 --- a/plugins/ndf-shared/skills/review/SKILL.md +++ b/plugins/ndf-shared/skills/review/SKILL.md @@ -1,7 +1,8 @@ --- name: review -description: "Review PRs and post approve or changes verdicts." -argument-hint: "[PR番号] [AIエージェント(codex|gemini)]" +description: "Review a PR diff, or the current branch diff with --branch, and post an approve or request-changes verdict." +when_to_use: "PR をレビューするとき、および PR 作成前にローカルブランチをセルフレビューするとき (--branch)。Triggers: 'レビューして', 'PRレビュー', 'マージ前チェック', 'ブランチをレビュー', 'セルフレビュー', 'PR前にレビュー', 'review my branch', 'self review', 'pre-PR review'" +argument-hint: "[PR番号 | --branch] [AIエージェント(codex|gemini)] [--focus AREA]" disable-model-invocation: true allowed-tools: - Bash @@ -10,52 +11,115 @@ allowed-tools: - Grep --- -# PRレビューコマンド +# コードレビューコマンド -直前PR、または引数で指定されたPRを専門家としてレビュー。 +PR 差分、または `--branch` 指定時は現在のブランチの差分を、専門家としてレビューする。 ## 引数 -- 第一引数 `[PR番号]`: レビュー対象のPR番号(省略時は直前のPR) -- 第二引数 `[AIエージェント]`: レビュー実行者(任意) - - 省略時: Claude(自身)でレビュー - - `codex`: Codex CLI に委譲 - - `gemini`: Gemini CLI に委譲 +| 引数 | 意味 | 既定 | +|---|---|---| +| `[PR番号]` | レビュー対象の PR | 直前の PR | +| `--branch` | PR ではなく **ローカルブランチの差分**をレビューする(PR 作成前のセルフレビュー) | OFF | +| `[AIエージェント]` | `codex` / `gemini` に委譲。省略時は Claude 自身 | Claude | +| `--focus AREA` | 重点観点(`security` / `performance` / `tests` / 任意の文字列) | なし | + +``` +/ndf:review # 直前 PR をレビュー +/ndf:review 9352 # PR 番号を指定 +/ndf:review 9352 codex # Codex CLI に委譲 +/ndf:review --branch # ローカルブランチをセルフレビュー +/ndf:review --branch security # セキュリティに焦点を当ててセルフレビュー +``` + +## 2 つのモード -## 実行 +| 観点 | PR モード(既定) | `--branch` モード | +|---|---|---| +| 対象 | GitHub 上の PR 差分 | `git diff <既定ブランチ>` の差分 | +| 出力先 | **PR 上にインラインコメント + 総評を投稿** | セッション上の報告のみ(投稿しない) | +| 判定 | `APPROVE` / `REQUEST_CHANGES` | 判定を出さず改善提案を返す | +| 用途 | PR 作成後のレビュー | PR 作成前のセルフレビュー | -- 問題点・改善点あり → 「Request Changes」 -- 指摘なし → 「Approve」 -- **レビュー結果は必ず GitHub PR 上に投稿する**(後述「レビュー結果の投稿」参照) - - 指摘は可能な限り **コード行に紐付くインラインコメント** として書く - - ファイル横断・設計レベルの所見のみ review body(総評)に書く +**どちらのモードでもコード修正は行わない**(分析と指摘のみ。修正は `/ndf:fix`)。 ## 観点 -言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ -- 上から順に優先して指摘 +言語慣用性(Idiomatic)・可読性・コード品質・保守性・セキュリティ・テストカバレッジ。 +上から順に優先して指摘する。 ### 具体的なチェックポイント - **その言語らしい記述方式**: イディオム・標準ライブラリ・言語機能の活用 -- **メモリ効率・演算性能を意識したコード** - - キャッシュ利用 +- **メモリ効率・演算性能** + - キャッシュ利用、不要なループ・コピーの排除 - Python: numpy 利用、内包表記、ジェネレータ - PHP: switch 文の map(連想配列)化 - - 不要なループ・コピーの排除 + - N+1 クエリ、不要なデータベースアクセス、インデックスの活用 - **関数・メソッド・ファイル行数の適正化** - - 目安: 関数/メソッド 50 行、ファイル 300 行 - - ただしプロジェクトの慣例に従う + - 目安: 関数/メソッド 50 行、ファイル 300 行。ただしプロジェクトの慣例に従う + - 単一責任原則から外れていないか - **重複・冗長コードの排除** - PR 範囲にこだわらず積極的にまとめるよう指摘 + - 逆に過剰な抽象化(YAGNI 違反)も指摘する - **柔軟性を損なう定数化の排除** - 数字をそのまま定数にするような硬直化を避ける - 定数よりも DB の master テーブル、または json/yaml による外部化を検討 +- **セキュリティ** + - SQL インジェクション / XSS / CSRF 対策、入力値バリデーション + - 認証・認可の適切性、機密情報(トークン、キー、個人情報)の取り扱い +- **エラーハンドリング** + - 例外が適切に捕捉されているか、リトライ / タイムアウトの設計 + - ログ出力の妥当性(詳細は `/ndf:logging-guidelines`) + +`--focus` が指定された場合は、該当する観点を優先し、他の観点は重大なもののみ指摘する。 + +## `--branch` モードの手順 -## レビュー結果の投稿 +### 1. 変更の把握 + +```bash +git diff main --name-only # 変更ファイル一覧 +git diff main --stat # 差分の統計 +git log main..HEAD --oneline # コミット履歴 +``` + +### 2. 分析 + +各変更ファイルについて、追加・変更されたロジックの意図が明確か、テストが追加されて +いるか、プロジェクトの規約に準拠しているかを、上記「観点」に沿って確認する。 + +### 3. 報告 + +```markdown +## レビュー結果 + +### 概要 +- 変更ファイル数 / 追加行数 / 削除行数 + +### Issues(要修正) +- `path/to/file.ext:456` — 問題点と修正方針 + +### Suggestions(改善提案) +- `path/to/file.ext:123` — 提案内容 +``` + +指摘は重要度の高いものから並べる。良い点の列挙は行わない。 + +### 注意事項 + +- 大量の変更がある場合、重要な変更から優先的にレビューする +- 自動品質チェック(linter, formatter, type checker)は事前実行済みを前提とする +- レビュー結果は提案であり、最終判断は開発者が行う + +## PR モードの手順 レビュー結果は **GitHub の PR レビュー機能** を使って必ず PR 上に書き込む。 -個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ書くのは避ける。 +個別指摘は **コード行に紐付くインラインコメント** が原則。総評(review body)にだけ +書くのは避ける。 + +- 問題点・改善点あり → `REQUEST_CHANGES` +- 指摘なし → `APPROVE` ### 指摘の振り分け @@ -68,17 +132,16 @@ allowed-tools: ### 投稿フロー(推奨: 1 リクエストで一括投稿) -`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を 1 回で送信** する。 +`gh api` の Reviews API を使い、**総評 + 複数のインラインコメント + 判定(event)を +1 回で送信** する。 ```bash PR= OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) SHA=$(gh pr view "$PR" --json headRefOid -q .headRefOid) -# 1. インラインコメントを JSON 配列で組み立て -# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) -# -# ▼ 推奨: jq -n でシェル変数を安全に流し込む(特殊文字混入時の JSON 破損を防ぐ) +# インラインコメントを JSON 配列で組み立て +# (path / line / side / body の 4 つが必須。複数行レンジは start_line を併用) SUMMARY=$'## 総評\n\n... 全体所見をここに ...' jq -n \ --arg sha "$SHA" \ @@ -96,13 +159,13 @@ jq -n \ ] }' > /tmp/review-payload.json -# 2. Reviews API に POST gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload.json ``` -> 💡 **JSON 組み立てに heredoc (`< JSON が壊れる(あるいはクオート未エスケープで JSON injection になる)。`jq -n --arg` 経由なら値が自動で -> JSON エスケープされるため安全。クオート付き heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 +> 💡 **JSON 組み立てに heredoc (`< 特殊文字が混入した場合 JSON が壊れる(あるいはクオート未エスケープで JSON injection に +> なる)。`jq -n --arg` 経由なら値が自動で JSON エスケープされるため安全。クオート付き +> heredoc (`<<'JSON'`) は逆に `$SHA` が展開されず使えない。 **`event` の値**: - `APPROVE` — 指摘なし @@ -120,18 +183,22 @@ gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-payload [nit / スタイル] スペースが揃っていない。 ``` -重要度の目安: -- `critical` — セキュリティ・データ破損・本番障害につながる -- `major` — 保守性 / 性能 / 仕様逸脱の重要問題 -- `minor` — 改善推奨だがブロッカーではない -- `nit` — 好み・スタイル +### 重要度の運用ガイド(auto-fix 判定に直結) + +| 重要度 | 定義 | 後段(`/ndf:fix`)の扱い | +|---|---|---| +| `critical` | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | +| `major` | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | +| `minor` | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | +| `nit` | 好み・スタイル | **修正しない**、最後にユーザ判断にまとめる | + +過剰な nit 量産は避ける。critical / major で対応すべき真の問題に集中すること。 ### 既存コメントがある場合の重複防止 同じ箇所への二重指摘を避けるため、投稿前に既存コメントを確認する: ```bash -# 既存のレビューコメント一覧 gh api "repos/$OWNER_REPO/pulls/$PR/comments" --paginate \ | jq -r '.[] | "\(.path):\(.line) \(.body | split("\n")[0])"' ``` @@ -150,153 +217,102 @@ gh pr comment "$PR" --body "..." # 1 件だけインラインコメントを追加(既存 review に含めない) gh api -X POST "repos/$OWNER_REPO/pulls/$PR/comments" \ - -F commit_id="$SHA" \ - -F path="src/foo.py" \ - -F line=42 -F side=RIGHT \ - -F body="..." + -F commit_id="$SHA" -F path="src/foo.py" -F line=42 -F side=RIGHT -F body="..." ``` -## 外部AIへの委譲手順 +## 外部 AI への委譲 -第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」の内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 +第二引数が指定された場合、上記「観点」「具体的なチェックポイント」「PR モードの手順」の +内容を **レビュー指示プロンプト** として組み立て、指定された CLI に渡す。 -### 共通: プロンプト組み立て +呼び出し手順の詳細は、利用 runtime に `/ndf:codex` / `/ndf:gemini` skill が同梱されて +いる場合はその skill に従う。同梱されていない runtime では以下の要点に従う。 -1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` で PR メタ情報を取得 -2. `gh pr diff ` で差分を取得(または変更ファイル一覧 + 必要箇所を `gh pr view --json files` 経由で抽出) -3. 上記「観点」「具体的なチェックポイント」「レビュー結果の投稿」セクションをそのままプロンプトに転記 -4. PR タイトル・URL・差分を **対象情報** として明記 -5. **出力は GitHub Reviews API のペイロード形式(JSON)で出させる**(後述「外部AIに必須化する出力形式」参照) - -### 外部AIに必須化する出力形式と直接投稿 +**`codex` 指定時** -**外部AIは Reviews API ペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する**。 -(旧版では生成した JSON をメインに返してメインが投稿していたが、メイン context 消費と往復回数が無駄なので削除) +- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し +- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** +- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 +- `grep -q '^tokens used$' err` で完了検知 +- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 -メインに返すのは「投稿が成功したか」「最終 verdict (event)」「review URL」「件数」の小さな結果サマリのみ。 +> ⚠️ `--dangerously-bypass-approvals-and-sandbox` は codex のサンドボックスを完全に無効化し、 +> 任意のシェル実行・ファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の +> 外部隔離環境内** でのみ使用すること。ホスト直接実行や本番リポジトリでは使わない。 -#### プロンプトに必ず含める指示(テンプレート) +**`gemini` 指定時** -```markdown -## 出力形式と投稿手順(必須) +- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し +- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) +- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示する +- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 +- `kill -0 $PID` ポーリングで完了検知(codex と異なり sentinel 不要 / プロセス exit を見る) +- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 -レビュー結果は以下の手順で **あなた自身が PR に投稿** してください。 -メイン側に返すのは投稿結果サマリだけです。 +> ⚠️ `--yolo` も同様に外部隔離環境内でのみ実行する。プロンプトでの「リポジトリ編集禁止」明示は必須だが、 +> sandbox の代替にはならない。 -### 1. ペイロード組み立て +### プロンプト組み立て -以下の JSON を `/tmp/-review-pr<番号>-payload.json` に書き出す -(codex なら `apply_patch`、gemini なら `write_file` を使用): +1. `gh pr view --json title,body,baseRefName,headRefName,url,headRefOid` でメタ情報を取得 +2. `gh pr diff ` で差分を取得 +3. 上記「観点」「PR モードの手順」をそのままプロンプトに転記 +4. PR タイトル・URL・差分を **対象情報** として明記 +5. **出力は Reviews API のペイロード形式(JSON)で出させ、外部 AI 自身に投稿させる** -\`\`\`json -{ - "commit_id": "", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "body": "## 総評\n\n...(設計レベル・PR全体所見のみ)...", - "comments": [ - { - "path": "src/foo.py", - "line": 42, - "side": "RIGHT", - "body": "[major / 可読性] ..." - } - ] -} -\`\`\` - -ルール: -- 個別指摘は必ず `comments[]` のインラインコメントにすること(行を絞れない場合はファイル代表行) -- `body` (総評) には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 -- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける(critical/major/minor/nit) -- `path` は **PR差分に登場するファイルのみ**(事前に `gh pr diff --name-only` で取得した一覧から選ぶ) -- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` がデフォルト -- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +### 外部 AI に必須化する出力形式と直接投稿 -### 2. 投稿 +**外部 AI はペイロードを組み立てた後、自分自身で `gh api` を呼んで PR に投稿する。** +メインに返すのは「投稿が成功したか」「最終 verdict」「review URL」「件数」の小さな +結果サマリのみ。 -\`\`\`bash -OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) -gh api -X POST "repos/$OWNER_REPO/pulls//reviews" \ - --input /tmp/-review-pr<番号>-payload.json \ - > /tmp/-review-pr<番号>-response.json -\`\`\` +プロンプトに必ず含める指示: -### 3. 結果サマリの書き出し(メインが読む) +- 個別指摘は必ず `comments[]` のインラインコメントにする(行を絞れない場合はファイル代表行) +- `body`(総評)には設計・横断的な所見のみ書く。個別指摘の繰り返しは禁止 +- 各 `comments[].body` の先頭に `[重要度 / カテゴリ]` を付ける +- `path` は **PR 差分に登場するファイルのみ**(`gh pr diff --name-only` の一覧から選ぶ) +- `line` は **差分に含まれる行**(追加行・コンテキスト行)に限る。`side=RIGHT` が既定 +- `commit_id` は `gh pr view --json headRefOid -q .headRefOid` の値を使う +- 投稿後 `/tmp/-review-pr<番号>-result.json` に結果サマリを書き出す -`/tmp/-review-pr<番号>-result.json` に投稿結果を書き出す: +結果サマリの形式: -\`\`\`json +```json { - "status": "posted" | "failed", - "event": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", - "posted_as": "REQUEST_CHANGES" | "APPROVE" | "COMMENT", + "status": "posted", + "event": "REQUEST_CHANGES", + "posted_as": "COMMENT", "review_url": "https://github.com/.../pull/#pullrequestreview-...", "comments_count": 5, "by_severity": {"critical": 0, "major": 2, "minor": 2, "nit": 1}, "payload_path": "/tmp/-review-pr<番号>-payload.json", "error": null } -\`\`\` +``` -投稿失敗時は `status: "failed"`、`error` にエラーメッセージ、`payload_path` で payload は残す -(メイン側のフォールバック投稿で使う)。 +投稿失敗時は `status: "failed"`、`error` にエラーメッセージを入れ、`payload_path` に +payload を残す(メイン側のフォールバック投稿で使う)。 -**`event` と `posted_as` の使い分け**: +### `event` と `posted_as` の使い分け - `event` — **AI 本来の判定 (intent)**。ループ収束判定(`/ndf:cross-review`)はこれを見る -- `posted_as` — **GitHub に実際投稿した event**。`event` と同じ値がデフォルト +- `posted_as` — **GitHub に実際投稿した event**。既定は `event` と同じ値 -GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない**(`HTTP 422: Can not request changes on your own pull request`)。自分 PR レビューの場合は以下のダウングレードを行う: +GitHub は **自分の PR には `REQUEST_CHANGES` で投稿できない** +(`HTTP 422: Can not request changes on your own pull request`)。自分の PR をレビュー +する場合は次のダウングレードを行う。 - `event = "REQUEST_CHANGES"` のままにしておく(intent 保持) - ペイロードの `event` だけ `"COMMENT"` にして投稿 - `posted_as = "COMMENT"` を結果サマリに記録 -これにより、後段のループ判定で「本当は REQ なので継続が必要」と判断できる。判定にあたっては事前に `gh api user --jq .login` と `gh pr view --json author --jq .author.login` を比較すること。 - -### 4. 重要度の運用ガイド(auto-fix 判定に直結) - -| 重要度 | 定義 | 後段の扱い | -|---|---|---| -| critical | セキュリティ・データ破損・本番障害につながる | **必ず自動修正** | -| major | 保守性・性能・仕様逸脱の重要問題 | **必ず自動修正** | -| minor | 改善推奨だがブロッカーではない | **自動修正対象**(明らかな改善のみ。判断要なら nit に格下げ) | -| nit | 好み・スタイル | **修正しない、最後にユーザ判断にまとめる** | - -過剰な nit 量産は避ける。critical/major で対応すべき真の問題に集中すること。 -``` - -### `codex` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:codex` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/codex-review-pr<番号>-prompt.md` に書き出し -- 出力先ファイルを `/tmp/codex-output-review-pr<番号>.md` として **プロンプト内で `apply_patch` 書き出しを必須化** -- `codex exec --dangerously-bypass-approvals-and-sandbox --config reasoning.effort=medium -C "$PWD" < prompt > stdout 2> err &` でバックグラウンド起動 -- `grep -q '^tokens used$' err` で完了検知 -- 「ファイル → stdout → stderr」三段フォールバックで成果物を回収 - -> ⚠️ **`--dangerously-bypass-approvals-and-sandbox` のセキュリティ注意**: このフラグは codex の bwrap サンドボックスを完全に無効化し、 -> 任意のシェル実行・任意のファイル編集を無確認で許可する。**必ず Docker / devcontainer / VM / CI ランナー等の外部隔離環境内** でのみ使用すること。 -> ホスト直接実行や本番リポジトリでは使わない。詳細な背景・代替策(`unprivileged_userns_clone` 有効化など)は `/ndf:codex` skill の -> 「サンドボックス制約」節を参照。 - -### `gemini` 指定時 - -呼び出し手順の詳細は、利用 runtime に `/ndf:gemini` skill が同梱されている場合はその skill に従う。要点: - -- プロンプトを `/tmp/gemini-review-pr<番号>-prompt.md` に書き出し -- **AI 直接投稿フローでは `--yolo` 必須**(`gh api -X POST` がシェル実行のため、`plan` / `auto_edit` だとブロックされる) -- プロンプト側で **「リポジトリ内ファイルを編集してはならない。`gh api` で投稿するだけ」** を強く明示することで `--yolo` のリスクを抑える -- `gemini --yolo --output-format text -p "$(cat prompt.md)" > stdout 2> err &` でバックグラウンド起動 -- `kill -0 $PID` ポーリングで完了検知(Codex と異なり sentinel 不要 / プロセス exit を見る) -- 成果物は stdout サマリ + `/tmp/gemini-review-pr<番号>-result.json` で回収 - -> ⚠️ **`--yolo` の制約は依然有効**: `/ndf:gemini` skill のセキュリティ警告通り、必ず外部隔離環境内でのみ実行する。プロンプトで「リポジトリ編集禁止」を明示することは必須だが、それは sandbox の代替にはならない。 +判定にあたっては事前に `gh api user --jq .login` と +`gh pr view --json author --jq .author.login` を比較する。 ### メイン側の検証とフォールバック -メインエージェントの責務は **結果サマリ読み込みと検証のみ**: +メインエージェントの責務は **結果サマリの読み込みと検証のみ**。 ```bash AGENT=codex # or gemini @@ -307,10 +323,7 @@ if [ ! -s "$RESULT" ]; then exit 1 fi -STATUS=$(jq -r '.status' "$RESULT") -EVENT=$(jq -r '.event // empty' "$RESULT") - -if [ "$STATUS" = "failed" ]; then +if [ "$(jq -r '.status' "$RESULT")" = "failed" ]; then echo "⚠️ $AGENT: 投稿失敗。payload からメインがフォールバック投稿します" >&2 PAYLOAD=$(jq -r '.payload_path' "$RESULT") OWNER_REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) @@ -318,20 +331,26 @@ if [ "$STATUS" = "failed" ]; then jq --arg sha "$SHA" '.commit_id = $sha' "$PAYLOAD" > /tmp/review-fallback.json gh api -X POST "repos/$OWNER_REPO/pulls/$PR/reviews" --input /tmp/review-fallback.json fi - -echo "$AGENT: event=$EVENT url=$(jq -r .review_url $RESULT)" ``` -**Claude 自身による追加判定は行わず**、外部AIの判定(`event`)と指摘内容をそのまま採用する。 +**Claude 自身による追加判定は行わず**、外部 AI の判定(`event`)と指摘内容をそのまま採用する。 ## 作業完了報告(必須) -レビュー結果は **PR 上に投稿済み** であることが前提。ユーザーへの報告は以下に絞る: +PR モードではレビュー結果が **PR 上に投稿済み** であることが前提。報告は以下に絞る。 -- 利用エージェント(claude / codex / gemini のいずれか) -- 投稿結果(review URL、event = APPROVE / REQUEST_CHANGES / COMMENT) +- 利用エージェント(claude / codex / gemini) +- 投稿結果(review URL、event) - 件数サマリ(インラインコメント数、重要度別内訳) -- 総評(review body)の要約 -- PR URL +- 総評の要約 / PR URL + +詳細な指摘内容は PR 上のインラインコメントに残っているため、報告では繰り返さない。 +`--branch` モードでは投稿先がないため、上記「報告」の書式でセッション上に出力する。 + +## 関連 -詳細な指摘内容は PR 上のインラインコメントに残っているため、ユーザー宛報告では繰り返さない。 +- `/ndf:fix` — レビュー指摘の分類と修正対応 +- `/ndf:cross-review` — codex + gemini の収束レビュー +- `/ndf:codex` — Codex CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:gemini` — Gemini CLI の呼び出し手順(同梱 runtime のみ) +- `/ndf:logging-guidelines` — ログ設計 diff --git a/scripts/build-runtime-plugins.sh b/scripts/build-runtime-plugins.sh index c7fd6471..b3c895eb 100755 --- a/scripts/build-runtime-plugins.sh +++ b/scripts/build-runtime-plugins.sh @@ -78,8 +78,7 @@ rewrite_codex_skill_paths() { local file for file in \ - "$skills_dir/fix/SKILL.md" \ - "$skills_dir/review-pr-comments/SKILL.md" + "$skills_dir/fix/SKILL.md" do [ -f "$file" ] || continue sed "s#\${PLUGIN_ROOT:-\${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh#\${PLUGIN_ROOT:-\${CODEX_PLUGIN_ROOT:-\${CLAUDE_PLUGIN_ROOT}}}/$script_dir/fix/scripts/fetch-pr-comments.sh#g" \ @@ -105,8 +104,7 @@ rewrite_kiro_skill_paths() { local file for file in \ - "$skills_dir/fix/SKILL.md" \ - "$skills_dir/review-pr-comments/SKILL.md" + "$skills_dir/fix/SKILL.md" do [ -f "$file" ] || continue sed 's#${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/skills/fix/scripts/fetch-pr-comments.sh#${PLUGIN_ROOT:-plugins/ndf-kiro}/skills/fix/scripts/fetch-pr-comments.sh#g' \