From b26ef6c9488a06803122dd2220fe045479575478 Mon Sep 17 00:00:00 2001 From: agent Date: Wed, 1 Jul 2026 12:37:38 +0000 Subject: [PATCH] Unify OpenCode PR review output to a single opencode-agent[bot] comment --- .github/workflows/opencode.yml | 4 +- .opencode/commands/review-pr.md | 107 +++++++++------------------- .opencode/skills/review-pr/SKILL.md | 83 +++++++++------------ README.md | 14 ++-- 4 files changed, 77 insertions(+), 131 deletions(-) diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml index 64cda44..f1ecb7b 100644 --- a/.github/workflows/opencode.yml +++ b/.github/workflows/opencode.yml @@ -30,8 +30,8 @@ jobs: && (! startsWith(github.head_ref, 'renovate/')) permissions: contents: read - pull-requests: write - issues: write + pull-requests: read + issues: read id-token: write actions: read runs-on: ubuntu-latest diff --git a/.opencode/commands/review-pr.md b/.opencode/commands/review-pr.md index c3a0edc..f9282ef 100644 --- a/.opencode/commands/review-pr.md +++ b/.opencode/commands/review-pr.md @@ -1,11 +1,11 @@ --- -description: Comprehensive GitHub PR review — gathers the PR via gh, runs specialized review subagents in parallel, normalizes and deduplicates findings, validates inline comment anchoring, and posts a single review with inline and summary comments back to the PR. +description: Comprehensive GitHub PR review — gathers the PR via gh, runs specialized review subagents in parallel, normalizes and deduplicates findings, validates file:line references, and returns a single concise markdown review response. The surrounding `opencode github run` integration posts the returned response to the PR as `opencode-agent[bot]`. agent: general --- # Comprehensive PR Review -Perform a comprehensive pull request review by orchestrating specialized review subagents in parallel. Each subagent returns only noteworthy findings in a normalized format. You then deduplicate and filter across agents, validate that findings can be anchored to the diff, and post a single review back to the PR. +Perform a comprehensive pull request review by orchestrating specialized review subagents in parallel. Each subagent returns only noteworthy findings in a normalized format. You then deduplicate and filter across agents, validate `file:line` references against the diff, and **return a single concise markdown review response**. Do **not** post anything to GitHub yourself — the surrounding `opencode github run` integration is responsible for posting the final response to the PR as `opencode-agent[bot]`. **Requested review aspects (optional):** "$ARGUMENTS" @@ -32,8 +32,8 @@ fi ``` - If `PR_NUMBER` is set, run `gh pr view "$PR_NUMBER" --json number,title,body,baseRefName,headRefName,files,url` to confirm a PR is available. - - If it succeeds, you are in **PR mode**: post results back with `gh` (step 7). - - If it fails (no PR or not in CI), fall back to **local mode**: review `git diff` and `git status`, and report findings directly to the user without posting anything to GitHub. + - If it succeeds, you are in **PR mode**: use read-only `gh` calls to gather the diff (steps 2 and 6), and return the review response (step 7) for `opencode github run` to post. + - If it fails (no PR or not in CI), fall back to **local mode**: review `git diff` and `git status`, and return findings directly to the user. - Do not rely on the current git branch to identify the PR. GitHub Actions pull request workflows usually check out a detached merge ref. ## 2. Gather the diff @@ -56,7 +56,7 @@ Parse `$ARGUMENTS` (the requested aspects). Supported aspect keywords: - `comments` → `comment-analyzer` - `errors` → `silent-failure-hunter` - `types` → `type-design-analyzer` -- `simplify` → run `code-simplifier` as a refinement step only; **do not post a review**; stop after simplification +- `simplify` → run `code-simplifier` as a refinement step only; **do not return a review**; stop after simplification - `all` or no argument → run all applicable reviewers (see below) ### Deterministic reviewer set for `all` @@ -106,7 +106,7 @@ Instruct every subagent to: - If no noteworthy findings exist, return an empty list and a one-line "no issues" note. -Do **not** let subagents post comments themselves. The orchestrator is the only one that posts. +Do **not** let subagents post or return anything beyond their structured findings. The orchestrator is the only one that assembles the final response. ## 5. Normalize, filter, and aggregate findings @@ -118,9 +118,9 @@ Collect all findings from all subagents. Each finding must have `file`, `line`, 1. **Drop praise-only items**: remove any entry whose message is only positive (no actionable issue). 2. **Drop nitpicks**: remove cosmetic preferences, style-only feedback, or issues with no real-world impact. -3. **Drop findings not supported by the diff**: if the file referenced is not in the changed-file set, drop the finding. Do **not** compare `line` against the changed-file set — it contains paths, not line numbers. Leave line validation to the diff-anchoring step (step 6). +3. **Drop findings not supported by the diff**: if the file referenced is not in the changed-file set, drop the finding. Do **not** compare `line` against the changed-file set — it contains paths, not line numbers. Leave line validation to the `file:line` reference validation step (step 6). 4. **Deduplicate across agents**: if two or more agents report substantially the same issue at the same location, keep the most specific one (usually from the specialized agent) and discard the duplicate. -5. **Aggregate by root cause**: when several findings share the same underlying root cause (for example, the same inconsistency repeated across README, SKILL.md, and command files), keep **one representative finding** as an inline comment and collapse the remaining occurrences into the summary body. Prefer root-cause aggregation over line-by-line repetition. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated at each affected location. +5. **Aggregate by root cause**: when several findings share the same underlying root cause (for example, the same inconsistency repeated across README, SKILL.md, and command files), keep **one representative finding** as a `file:line` reference and collapse the remaining occurrences into the review body. Prefer root-cause aggregation over line-by-line repetition. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated at each affected location. 6. **Orchestrator second filter**: review every remaining finding yourself and remove any you do not also deem noteworthy. This filter keeps the signal high. ### Grouping @@ -131,58 +131,26 @@ Group surviving findings by severity: - **Important** — should fix - **Suggestions** — optional improvements -Prefer fewer, higher-signal comments over exhaustive lists. Optional guardrail suggestions (such as adding tests for agent frontmatter or reference validation) should be downgraded to `suggestion` severity at most. +Prefer fewer, higher-signal references over exhaustive lists. Optional guardrail suggestions (such as adding tests for agent frontmatter or reference validation) should be downgraded to `suggestion` severity at most. -## 6. Validate inline comment anchoring +## 6. Validate file:line references -Before building the review payload, validate every finding against the PR diff. +Before assembling the final response, validate every finding against the PR diff so each `file:line` reference points at a real changed location. -### Anchoring rules +### Validation rules -- Obtain the diff hunk list from `gh pr diff "$PR_NUMBER"` (already gathered in step 2). +- Obtain the diff hunk list from `gh pr diff "$PR_NUMBER"` (already gathered in step 2) in PR mode, or `git diff` in local mode. - For each finding, check whether its `line` appears in the diff or diff context for `file`. - - A line is anchored if: it falls within a `+` hunk in the diff for the given file, or within the surrounding unchanged-context lines of that hunk. - - Use `side: "RIGHT"` and the head-file line number for every inline comment. -- If a finding's line **cannot be safely anchored** to the diff, move it to the summary body as a `file:line` reference instead of an inline comment. Do **not** drop it — the file is a changed file, only the line is unanchorable. -- Never fail the entire review because one comment is unanchorable. Move it and continue. + - A `file:line` reference is valid if: it falls within a `+` hunk in the diff for the given file, or within the surrounding unchanged-context lines of that hunk. + - Use the head-file line number for every `file:line` reference. +- If a finding's line **cannot be safely validated** against the diff, keep it in the review body as a `file`-only reference (drop the unverified `:line`) instead of a `file:line` reference. Do **not** drop the finding — the file is a changed file, only the line is unverifiable. +- Never fail the entire review because one `file:line` reference is unverifiable. Adjust it and continue. -## 7. Post the results +## 7. Return the results -### PR mode +**Return a single concise markdown review response only.** Do **not** call `gh api`, `gh pr review`, or `gh pr comment`. The surrounding `opencode github run` integration posts the returned response to the PR as `opencode-agent[bot]`. -Post a **single review** via: - -```bash -gh api -X POST repos/{owner}/{repo}/pulls/$PR_NUMBER/reviews --input - <<'EOF' -{ - "event": "COMMENT", - "body": "", - "comments": [ - {"path": "src/foo.ts", "line": 42, "side": "RIGHT", "body": "**important**: ..."} - ] -} -EOF -``` - -Use `{owner}` and `{repo}` from the git remote. Use the explicit `PR_NUMBER` from step 1. - -**Review event policy:** - -- Use `event: "COMMENT"` for normal reviews. -- Use `event: "REQUEST_CHANGES"` only when there are critical findings that block merge. - -**Posting policy:** - -- **Anchored findings** → inline comments on the specific representative line. -- **Unanchorable findings** (changed file but no safe diff line) → summary body as `file:line` references. -- **Duplicated root causes** → one representative inline comment plus a summary-body entry listing all affected files. -- Reserve inline comments for issues tied to a specific representative line. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated across every affected file. - -**Inline comment format:** - -Each inline comment body should begin with the severity tag: `**critical**:`, `**important**:`, or `**suggestion**:`, followed by the finding message. - -**Summary body format:** +### Response format ```markdown ## OpenCode PR Review @@ -191,48 +159,39 @@ Reviewed files across areas: . ### Critical () -- `file:line` — issue (unanchorable findings and aggregated root-cause occurrences; anchored ones appear inline) +- `file:line` — issue (unverifiable-line findings and aggregated root-cause occurrences use `file`-only references) ### Important () -- `file:line` — issue (unanchorable findings and aggregated root-cause occurrences) +- `file:line` — issue (unverifiable-line findings and aggregated root-cause occurrences) ### Suggestions () -- `file:line` — issue (unanchorable findings and aggregated root-cause occurrences) -``` - -When a root cause affects multiple files, list the representative inline comment once and add a single summary entry naming all affected files (e.g. `Same inconsistency across README.md, SKILL.md, review-pr.md — see inline comment on README.md:42`). - -If there are **no findings at all**, post: - -```text -No noteworthy issues found. +- `file:line` — issue (unverifiable-line findings and aggregated root-cause occurrences) ``` -Do not spam praise or padding. One concise confirmation is sufficient. +When a root cause affects multiple files, add a single entry naming all affected files (e.g. `Same inconsistency across README.md, SKILL.md, review-pr.md — see representative entry on README.md:42`). -### Failure fallback +Each finding entry should begin with the severity tag: `**critical**:`, `**important**:`, or `**suggestion**:`, followed by the finding message. -If `gh api .../reviews` fails: +### No findings -1. **Retry without invalid inline comments**: if the error message identifies a specific invalid comment, remove it (move that finding to the summary body) and retry once. -2. **Fall back to top-level comment**: if still failing, post a single top-level comment with the full summary plus all findings as `file:line` references: +If there are **no findings at all**, return only: -```bash -gh pr comment "$PR_NUMBER" --body "$SUMMARY" +```text +No noteworthy issues found. ``` -Never leave the user with no feedback. +Do not include praise, padding, duplicate summaries, or status logs. One concise confirmation is sufficient. ### Local mode -Print the same summary to the user. Do not call `gh`. +Return the same response to the user. Do not call `gh`. ## 8. Notes - Keep feedback concise. A short review with real signal beats a long review with padding. -- Never post secrets, tokens, or full file contents in comments. -- The workflow grants `pull-requests: write`, so `GH_TOKEN` or `GITHUB_TOKEN` can post reviews when passed to the OpenCode step. Do not attempt to push commits or merge. +- Never include secrets, tokens, or full file contents in the response. +- The workflow grants only read access to pull requests and issues, so `GH_TOKEN` or `GITHUB_TOKEN` cannot post reviews. Do **not** attempt to call `gh api`, `gh pr review`, `gh pr comment`, push commits, or merge. The OpenCode App integration handles all PR-visible posting as `opencode-agent[bot]`. - If `$ARGUMENTS` lists specific aspects, respect them and skip the rest. - Re-run after fixes to verify issues are resolved. diff --git a/.opencode/skills/review-pr/SKILL.md b/.opencode/skills/review-pr/SKILL.md index 10aaf64..0694d42 100644 --- a/.opencode/skills/review-pr/SKILL.md +++ b/.opencode/skills/review-pr/SKILL.md @@ -1,11 +1,11 @@ --- name: review-pr -description: Run a comprehensive pull request review across changed files using Claude Code Action-compatible core reviewers and pr-review-toolkit specialty agents. Gathers the PR via gh, runs agents in parallel, normalizes and deduplicates findings, validates inline comment anchoring, and posts a single review with inline and summary comments back to the PR. Use when reviewing a PR before merge, before requesting review, after addressing feedback, or when the user asks to review a diff or recent changes. +description: Run a comprehensive pull request review across changed files using Claude Code Action-compatible core reviewers and pr-review-toolkit specialty agents. Gathers the PR via gh, runs agents in parallel, normalizes and deduplicates findings, validates file:line references, and returns a single concise markdown review response. The surrounding `opencode github run` integration posts the returned response to the PR as `opencode-agent[bot]`. Use when reviewing a PR before merge, before requesting review, after addressing feedback, or when the user asks to review a diff or recent changes. --- # Comprehensive PR Review -Run a comprehensive pull request review by orchestrating specialized review agents, each focusing on one aspect of code quality. The orchestrator gathers the PR, spawns agents as subagents via the `task` tool, normalizes and deduplicates findings, validates inline comment anchoring, and posts the results back to the PR. +Run a comprehensive pull request review by orchestrating specialized review agents, each focusing on one aspect of code quality. The orchestrator gathers the PR, spawns agents as subagents via the `task` tool, normalizes and deduplicates findings, validates `file:line` references against the diff, and **returns a single concise markdown review response**. The surrounding `opencode github run` integration posts that response to the PR as `opencode-agent[bot]`. ## When to Use @@ -35,7 +35,7 @@ If no aspects are specified, run all applicable reviews. | `comments` | `comment-analyzer` | Code comment accuracy and maintainability | | `errors` | `silent-failure-hunter` | Silent failures, broad catch blocks, error handling | | `types` | `type-design-analyzer` | Type design and invariant expression | -| `simplify` | `code-simplifier` | Refinement only — does not post a review | +| `simplify` | `code-simplifier` | Refinement only — does not return a review | | `all` (default) | All applicable (see below) | Deterministic full review | ## Deterministic `all` Behavior @@ -100,58 +100,41 @@ Every subagent returns findings in this normalized structure: message: ``` -### Filtering rules applied before posting +### Filtering rules applied before assembling the response 1. Drop praise-only items (no actionable issue). 2. Drop nitpicks (cosmetic preferences, no real-world impact). -3. Drop findings not supported by the diff — check **file membership only**; the changed-file set contains paths, not line numbers. Leave line validation to the anchoring step. +3. Drop findings not supported by the diff — check **file membership only**; the changed-file set contains paths, not line numbers. Leave line validation to the `file:line` reference validation step. 4. Deduplicate across agents (keep the most specific finding when two agents report the same issue at the same location). -5. **Aggregate by root cause**: when several findings share the same underlying root cause (e.g. the same inconsistency repeated across README, SKILL.md, and command files), keep one representative finding as an inline comment and collapse the rest into the summary body. Prefer root-cause aggregation over line-by-line repetition. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated at each affected location. +5. **Aggregate by root cause**: when several findings share the same underlying root cause (e.g. the same inconsistency repeated across README, SKILL.md, and command files), keep one representative finding as a `file:line` reference and collapse the rest into the review body. Prefer root-cause aggregation over line-by-line repetition. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated at each affected location. 6. Orchestrator second filter: the orchestrator reviews every remaining finding and discards any it does not also deem noteworthy. -Prefer fewer, higher-signal comments over exhaustive lists. Optional guardrail suggestions (such as adding tests for agent frontmatter or reference validation) should be downgraded to `suggestion` severity at most. +Prefer fewer, higher-signal references over exhaustive lists. Optional guardrail suggestions (such as adding tests for agent frontmatter or reference validation) should be downgraded to `suggestion` severity at most. -## Inline Comment Anchoring +## file:line Reference Validation -Before building the review payload, every finding is validated against the PR diff: +Before assembling the response, every finding is validated against the PR diff: -- Inline comments use `side: "RIGHT"` and the head-file line number. -- A line is anchored if it falls within a `+` hunk or surrounding unchanged-context lines of that hunk for the given file. -- Findings whose line cannot be safely anchored are **moved to the summary body** as `file:line` references — not dropped, since the file is a changed file and only the line is unanchorable. -- One invalid comment never fails the entire review. +- Use the head-file line number for every `file:line` reference. +- A `file:line` reference is valid if the line falls within a `+` hunk or surrounding unchanged-context lines of that hunk for the given file. +- Findings whose line cannot be safely validated are **kept in the review body as `file`-only references** (drop the unverified `:line`) — not dropped, since the file is a changed file and only the line is unverifiable. +- One unverifiable `file:line` reference never fails the entire review. -## Review Posting Policy +## Review Output Policy -Post one review via `gh api -X POST repos/{owner}/{repo}/pulls/$PR_NUMBER/reviews`. - -- `event: "COMMENT"` — normal reviews. -- `event: "REQUEST_CHANGES"` — only when critical findings block merge. - -**Posting policy:** - -- **Anchored findings** → inline comments on the specific representative line. -- **Unanchorable findings** (changed file but no safe diff line) → summary body as `file:line` references. -- **Duplicated root causes** → one representative inline comment plus a summary-body entry listing all affected files. -- Reserve inline comments for issues tied to a specific representative line. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated across every affected file. - -Use the review body for: - -- Concise summary of areas reviewed -- Unanchorable findings -- Aggregated root-cause occurrences and their affected files -- General observations -- No-finding confirmation - -If no findings: post `No noteworthy issues found.` — one line, no padding. - -## Fallback Behavior - -If the reviews API call fails: - -1. Retry once after removing the invalid inline comment (move it to the summary body). -2. If still failing, fall back to one top-level `gh pr comment "$PR_NUMBER" --body "$SUMMARY"`. - -Never leave the user with no feedback. +- Return **one final markdown response only**. Do not split it into multiple posts. +- Do **not** call `gh api`, `gh pr review`, or `gh pr comment`. Do **not** post a GitHub Review or inline review comments. +- The surrounding `opencode github run` integration posts the returned response to the PR as `opencode-agent[bot]`. +- The orchestrator never writes to GitHub; it only assembles and returns the review. +- Group findings by severity in the response: + - **Critical** — must fix before merge + - **Important** — should fix + - **Suggestions** — optional improvements +- Each finding entry begins with its severity tag (`**critical**:`, `**important**:`, or `**suggestion**:`) followed by the message and an actionable `file:line` reference. +- **Unverifiable-line findings** (changed file but no safe diff line) → review body as `file`-only references. +- **Duplicated root causes** → one representative `file:line` entry plus a body entry listing all affected files. +- Reserve `file:line` references for issues tied to a specific representative line. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated across every affected file. +- If there are no findings, return only `No noteworthy issues found.` — one line, no padding, no praise, no status logs. ## Workflow @@ -160,8 +143,8 @@ Never leave the user with no feedback. 3. **Choose reviewers** — based on `$ARGUMENTS` and diff content. 4. **Launch subagents in parallel** — pass diff, files, and PR metadata. 5. **Normalize, filter, and aggregate** — apply filtering rules, root-cause aggregation, and orchestrator second filter. -6. **Validate anchoring** — check each finding against the diff; move unanchored findings to summary (do not drop them). -7. **Post** — single review in PR mode; print summary in local mode. +6. **Validate `file:line` references** — check each finding against the diff; demote unverified findings to `file`-only references (do not drop them). +7. **Return response** — single markdown review in both PR and local mode. `opencode github run` posts it to the PR as `opencode-agent[bot]` in PR mode. ## Workflow Integration @@ -183,8 +166,9 @@ Never leave the user with no feedback. **In GitHub Actions:** 1. The `opencode.yml` workflow runs `/review-pr` on PR open / ready for review. -2. The orchestrator gathers the PR via `gh`, runs the agents, and posts a review with inline comments. -3. Re-run by commenting `/opencode` or `/oc` on the PR. +2. The orchestrator gathers the PR via read-only `gh` calls, runs the agents, and returns one review response. +3. `opencode github run` posts that response to the PR as a single `opencode-agent[bot]` comment. The orchestrator does **not** post a GitHub Review or inline comments. +4. Re-run by commenting `/opencode` or `/oc` on the PR. **After PR feedback:** @@ -198,4 +182,5 @@ Never leave the user with no feedback. - Agents run autonomously and return structured findings. - Each agent focuses on its specialty for deep analysis. - Results are actionable with specific `file:line` references. -- Never post secrets, tokens, or full file contents in review comments. +- Never include secrets, tokens, or full file contents in the response. +- The only PR-visible review output from an automated OpenCode review run is the final response posted by `opencode-agent[bot]`. `github-actions[bot]` does not post a review. diff --git a/README.md b/README.md index efcd430..3ffaf12 100644 --- a/README.md +++ b/README.md @@ -80,11 +80,13 @@ When `use-github-token: true`, pass `GITHUB_TOKEN` in `env` and grant the workfl ## Pull Request Reviews -The bundled `/review-pr` command posts reviews back to GitHub with `gh`. Workflows that invoke it must provide: +The bundled `/review-pr` command returns a single concise markdown review response. The surrounding `opencode github run` integration posts that response to the PR as a single `opencode-agent[bot]` comment. `/review-pr` does **not** post a GitHub Review or inline review comments directly, so no `pull-requests: write` or `issues: write` permission is required for the review workflow. -- `pull-requests: write` -- `issues: write` when falling back to `gh pr comment` -- `GH_TOKEN: ${{ github.token }}` or `GITHUB_TOKEN: ${{ github.token }}` +Workflows that invoke `/review-pr` must provide: + +- `pull-requests: read` (for `gh pr diff` / `gh pr view`) +- `id-token: write` (for the OpenCode App token exchange) +- `GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}` or `GITHUB_TOKEN: ${{ github.token }}` with at least read access to pull requests - A valid API key for the selected model provider with available credits or quota Example OpenCode step: @@ -116,7 +118,7 @@ The bundled toolkit combines Claude Code Action-style core reviewers with `pr-re | `/review-pr errors` | `silent-failure-hunter` | | `/review-pr comments` | `comment-analyzer` | | `/review-pr types` | `type-design-analyzer` | -| `/review-pr simplify` | `code-simplifier` — refinement only, does not post a review | +| `/review-pr simplify` | `code-simplifier` — refinement only, does not return a review | #### Core reviewers (Claude Code Action-compatible) @@ -134,7 +136,7 @@ The bundled toolkit combines Claude Code Action-style core reviewers with `pr-re - **`comment-analyzer`** — comment accuracy, completeness, and comment rot - **`type-design-analyzer`** — type invariants, encapsulation, and design quality -Findings are normalized, deduplicated across agents, and validated against the PR diff before posting. **Posting policy:** anchored findings become inline comments on the specific representative line; unanchorable findings (changed file but no safe diff line) move to the summary body as `file:line` references; duplicated root causes produce one representative inline comment plus a summary-body entry listing all affected files. Cross-document or cross-file consistency problems are summarized once in the review body instead of repeated at each location. If the reviews API call fails, the skill falls back to a single top-level PR comment. +Findings are normalized, deduplicated across agents, and validated against the PR diff before the response is assembled. **Output policy:** the orchestrator returns a single markdown response grouped by severity; each finding includes an actionable `file:line` reference (demoted to a `file`-only reference when the line cannot be validated against the diff); duplicated root causes produce one representative `file:line` entry plus a body entry listing all affected files; cross-document or cross-file consistency problems are summarized once in the review body instead of repeated at each location. `opencode github run` posts that response to the PR as a single `opencode-agent[bot]` comment. `github-actions[bot]` does not post a review. ## Examples