diff --git a/.agents/skills/local-qa/scripts/validate-opencode.sh b/.agents/skills/local-qa/scripts/validate-opencode.sh index 8939622..b6e7f9c 100755 --- a/.agents/skills/local-qa/scripts/validate-opencode.sh +++ b/.agents/skills/local-qa/scripts/validate-opencode.sh @@ -6,8 +6,9 @@ cd "$(git rev-parse --show-toplevel)" agents_dir=".opencode/agents" docs=(.opencode/commands/review-pr.md .opencode/skills/review-pr/SKILL.md) required_keys=(name description mode permission) -# Backtick-quoted identifiers in the docs that are skills/toolkits, not agents. -non_agents=(pr-feedback-triage pr-review-toolkit) +# Backtick-quoted identifiers in the docs that are skills, toolkits, or config +# inputs rather than agents. +non_agents=(pr-feedback-triage pr-review-toolkit use-github-token) fail=0 warn() { echo "ERROR: $*" >&2; fail=1; } diff --git a/.opencode/commands/review-pr.md b/.opencode/commands/review-pr.md index 4cc8dc8..db029d8 100644 --- a/.opencode/commands/review-pr.md +++ b/.opencode/commands/review-pr.md @@ -1,11 +1,13 @@ --- -description: Comprehensive GitHub PR review — gathers the PR via gh, runs specialized review subagents in parallel, normalizes and deduplicates findings, validates file:line references against the diff, and returns a single review response for the OpenCode GitHub integration to post. +description: Comprehensive GitHub PR review — gathers the PR via gh, runs specialized review subagents in parallel, normalizes and deduplicates findings, validates diff anchors, and submits GitHub inline review comments when findings can be anchored. 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 file:line references against the diff, and return a single review response. The surrounding `opencode github run` integration posts that response to the PR as `opencode-agent[bot]`; do not post to GitHub yourself. +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 each finding against the PR diff, and submit a GitHub pull request review with inline comments for every finding that has a valid diff anchor. + +The surrounding `opencode github run` integration always posts your final text as a PR comment. Therefore, when you successfully submit GitHub review comments yourself, return only a short status message instead of a second full review body. **Requested review aspects (optional):** "$ARGUMENTS" @@ -14,6 +16,29 @@ Perform a comprehensive pull request review by orchestrating specialized review Determine whether you are reviewing a real GitHub PR (running in GitHub Actions) or working locally. - In GitHub Actions the environment provides `GITHUB_EVENT_NAME`, `GITHUB_REPOSITORY`, `GITHUB_REF` (e.g. `refs/pull/42/merge`), and `GITHUB_EVENT_PATH`. The `gh` CLI also requires `GH_TOKEN` or `GITHUB_TOKEN` to be available in the environment. +- Before using `gh`, prefer the OpenCode GitHub App token that `opencode github run` installs into the Git extraheader when `use-github-token` is false. This makes direct `gh api` review submissions appear as `opencode-agent[bot]` instead of `github-actions[bot]`. + +```bash +prepare_opencode_gh_token() { + local extraheader encoded decoded token + extraheader="$(git config --local --get http.https://github.com/.extraheader 2>/dev/null || true)" + if [[ "${extraheader}" =~ ^AUTHORIZATION:\ basic\ (.+)$ ]]; then + encoded="${BASH_REMATCH[1]}" + decoded="$(printf '%s' "${encoded}" | base64 --decode 2>/dev/null || true)" + token="${decoded#x-access-token:}" + if [[ -n "${token}" && "${token}" != "${decoded}" ]]; then + export GH_TOKEN="${token}" + export GITHUB_TOKEN="${token}" + return 0 + fi + fi + return 0 +} + +prepare_opencode_gh_token +``` + +- If no OpenCode App token is available in Git config, keep the existing `GH_TOKEN` or `GITHUB_TOKEN` fallback. This happens when the workflow uses `use-github-token: true` or when running locally. - Derive the PR number from the event payload first: ```bash @@ -31,8 +56,8 @@ if [[ -z "${PR_NUMBER}" && "${GITHUB_REF:-}" =~ ^refs/pull/([0-9]+)/merge$ ]]; t 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**: return a review response (step 7). +- If `PR_NUMBER` is set, run `gh pr view "$PR_NUMBER" --json number,title,body,baseRefName,headRefName,headRefOid,files,url` to confirm a PR is available. + - If it succeeds, you are in **PR mode**: submit a GitHub PR review when findings exist (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. - Do not rely on the current git branch to identify the PR. GitHub Actions pull request workflows usually check out a detached merge ref. @@ -41,7 +66,7 @@ fi - **PR mode:** run `gh pr diff "$PR_NUMBER"` for the full diff and use the `files` list from `gh pr view "$PR_NUMBER"` for the changed-file set. Prefer `gh pr diff "$PR_NUMBER"` over `git diff` because CI checkouts are shallow (`fetch-depth: 1`). - **Local mode:** run `git diff --name-only HEAD` plus untracked files from `git status --short` for the changed-file set, then `git diff` for content. -Capture the changed-file list, the full diff, and the PR metadata (title, body, base/head branch) to hand to the subagents. +Capture the changed-file list, the full diff, and the PR metadata (title, body, base/head branch, head SHA) to hand to the subagents and to build the final review payload. ## 3. Choose applicable reviewers based on $ARGUMENTS @@ -106,7 +131,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 returns the final response; the `opencode github run` integration posts it. +Do **not** let subagents post comments themselves. The orchestrator validates, deduplicates, and posts the final review. ## 5. Normalize, filter, and aggregate findings @@ -120,7 +145,7 @@ Collect all findings from all subagents. Each finding must have `file`, `line`, 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). 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 a `file:line` reference 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 only when it still preserves actionable anchors**: when several findings share the same underlying root cause, keep one representative inline comment at the best anchor and mention the other affected files briefly in that comment. Do not collapse anchored findings into a top-level-only summary when an inline anchor is available. 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 @@ -133,64 +158,116 @@ Group surviving findings by severity: 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. -## 6. Validate file:line references against the diff +## 6. Validate anchors and build inline review comments + +Before submitting a GitHub review, validate every finding against the PR diff and classify it as either `inline` or `summary_only`. -Before building the review response, validate every finding against the PR diff so the `file:line` references in the single OpenCode comment stay accurate. +### Inline-first contract -### Validation rules +- Every finding with a valid `file` and diff-anchorable `line` must become an inline review comment. +- Do not skip inline comments merely because the same finding is also listed in a summary. +- Do not convert all findings into a single top-level markdown response when one or more valid inline anchors exist. +- Summary-only findings are allowed only when the issue is real but cannot be safely anchored to the diff, such as a cross-file design issue or a stale/unavailable line. + +### Anchor validation rules - Obtain the diff hunk list from `gh pr diff "$PR_NUMBER"` (already gathered in step 2). -- For each finding, check whether its `line` appears in the diff or diff context for `file`. - - A line 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. -- If a finding's line **cannot be safely matched** to the diff, keep it in the summary body but reference the nearest valid anchor line (or the file alone) instead of an unverified line number. Do **not** drop it — the file is a changed file, only the line is unverifiable. -- Never fail the entire review because one finding's line is unverifiable. Adjust the reference and continue. +- For each finding, check whether its `line` is present in a hunk for `file` on the head side of the PR. +- Prefer anchoring to an added or modified line that directly caused the issue. +- If the reported line is not anchorable but the same finding has a nearby valid head-side diff line in the same file, adjust the anchor to that nearest relevant line and keep it inline. +- If no safe anchor exists, mark the finding `summary_only` with a short reason. Do not silently drop it. -## 7. Return the results +### Inline comment body format -### PR mode +Each inline comment body must be concise and self-contained: -Return a **single concise markdown review response**. Do **not** call `gh api`, `gh pr review`, or `gh pr comment` — the surrounding `opencode github run` integration is responsible for posting the final response to the PR as `opencode-agent[bot]`. Calling GitHub write APIs directly would create a duplicate `github-actions[bot]` posting. +```markdown +** · **: +``` -Include all findings (whether or not their line matched the diff) in the summary body as `file:line` references so the single top-level OpenCode comment stays actionable. +Avoid repeating the file path or line number inside the inline body because GitHub already displays the anchor. Keep each body one short paragraph unless a minimal code suggestion is genuinely useful. -**Summary body format:** +## 7. Submit the review in PR mode -```markdown -## OpenCode PR Review +### No findings -Reviewed files across areas: . +If there are no findings after filtering, return exactly: -### Critical () +```text +No noteworthy issues found. +``` + +Do not post a GitHub review with an empty comments array. + +### Findings with at least one inline anchor -- `file:line` — issue +Submit a single GitHub pull request review using the REST API via `gh api`. Do not use `gh pr review` for inline findings because it cannot submit a structured `comments` array for per-line anchors in this workflow. -### Important () +Before submission, call `prepare_opencode_gh_token` again. This ensures `gh api` uses the OpenCode GitHub App token when available, even if the workflow also provided a default `GITHUB_TOKEN`. -- `file:line` — issue +Build the review body from trusted strings and normalized findings. It must enumerate every summary-only item, including its fallback reason: -### Suggestions () +```markdown +OpenCode PR Review: inline finding(s), summary-only finding(s). -- `file:line` — issue +Summary-only findings: +- `` — : ``` -When a root cause affects multiple files, add a single summary entry naming all affected files (e.g. `Same inconsistency across README.md, SKILL.md, review-pr.md`). +Build the JSON payload with `jq`, not string interpolation, so PR-authored content cannot break JSON structure or inject fields. Write it to a private temporary file and always remove it after submission: -If there are **no findings at all**, return: +```bash +prepare_opencode_gh_token + +review_payload="$(mktemp "${TMPDIR:-/tmp}/opencode-pr-review.XXXXXX.json")" +chmod 600 "$review_payload" +trap 'rm -f "$review_payload"' EXIT + +jq -n \ + --arg commit_id "$head_oid" \ + --arg body "$review_body" \ + --argjson comments "$comments_json" \ + '{commit_id: $commit_id, event: "COMMENT", body: $body, comments: $comments}' \ + > "$review_payload" + +gh api \ + --method POST \ + "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" \ + --input "$review_payload" +``` + +Operational requirements: + +- Prefer the OpenCode GitHub App token from Git config for `gh` commands so inline review submissions are authored by `opencode-agent[bot]`. +- If no OpenCode App token is available, fall back to `GH_TOKEN` or `GITHUB_TOKEN`; this may make direct review submissions appear as `github-actions[bot]`. +- Use the PR head SHA from `gh pr view --json headRefOid` as `commit_id`. +- Include `summary_only` findings in the review `body`, not as fake inline comments. +- Handle only GitHub 422 anchor-validation failures with the inline-comment retry path. Inspect the response `errors[].field` values such as `comments[0].line` to map failures back to specific `comments[N]` entries. +- If GitHub rejects one or more inline anchors and the offending entries can be identified, move only those findings to `summary_only` with the rejection reason and retry once. +- If a 422 anchor error does not identify the offending `comments[N]` entry, move all inline findings from that failed attempt to `summary_only` before retrying or falling back so no finding is lost. +- If the error indicates the `commit_id` is stale or is no longer part of the pull request, refetch `headRefOid`, rebuild the payload with the new SHA, and retry once. If the refetched SHA still fails, use the fallback path. +- If the retry still fails, do not claim inline comments were posted. Return a concise failure report and convert every attempted inline finding into a summary-only fallback entry, including its file, line, severity, source, message, and failure reason. + +After a successful submission, return only a concise status for the surrounding OpenCode integration to post, for example: ```text -No noteworthy issues found. +Submitted OpenCode PR review with 3 inline comment(s) and 1 summary-only finding. ``` -Do not spam praise or padding. One concise confirmation is sufficient. +### Findings without inline anchors + +If all findings are valid but none can be safely anchored inline, return a concise markdown review body as a top-level fallback and explicitly state why inline comments were not used. -### Local mode +## 8. Local mode -Print the same summary to the user. Do not call `gh`. +Print the same normalized review summary to the user. Do not call `gh api`, `gh pr review`, or `gh pr comment`. -## 8. Notes +## 9. Notes - Keep feedback concise. A short review with real signal beats a long review with padding. -- Never include secrets, tokens, or full file contents in the review response. -- The `opencode github run` integration posts your final response to the PR as `opencode-agent[bot]`; do not call `gh api`, `gh pr review`, or `gh pr comment` yourself. The workflow may still grant `pull-requests: write` for the integration's posting, and `GH_TOKEN` or `GITHUB_TOKEN` is needed only for `gh pr diff` / `gh pr view` reads. Do not attempt to push commits or merge. +- Never include secrets, tokens, or full file contents in the review response or GitHub comments. +- Do not print tokens or decoded Git authentication headers in logs. +- Do not call `gh pr comment`; it creates top-level noise and bypasses inline review anchors. +- Use `gh api` only for the single final PR review submission after all findings are normalized, deduplicated, and anchor-validated. - 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 021c460..be1ded9 100644 --- a/.opencode/skills/review-pr/SKILL.md +++ b/.opencode/skills/review-pr/SKILL.md @@ -1,11 +1,13 @@ --- 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 file:line references against the diff, and returns a single review response for the OpenCode GitHub integration to post. 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 diff anchors, and submits GitHub inline review comments when findings can be anchored. 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 file:line references against the diff, and returns a single review response. The surrounding `opencode github run` integration posts that response to the PR as `opencode-agent[bot]`; the skill must not post to GitHub directly. +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 every finding against the PR diff, and submits GitHub inline review comments for every diff-anchorable finding. + +The surrounding `opencode github run` integration always posts the final assistant text to the PR. After a successful inline review submission, return only a short status message so the integration does not duplicate the full review as a top-level comment. ## When to Use @@ -22,6 +24,32 @@ Do not use this skill to triage existing review comments on a PR; use `pr-feedba If no aspects are specified, run all applicable reviews. +## GitHub Auth for Inline Reviews + +When `opencode github run` uses the default OpenCode GitHub App flow (`use-github-token: false`), OpenCode configures the Git remote extraheader with an `opencode-agent[bot]` App token before the agent runs. Before calling `gh`, prefer that App token over any workflow `GITHUB_TOKEN` so direct `gh api` review submissions are authored by `opencode-agent[bot]`. + +```bash +prepare_opencode_gh_token() { + local extraheader encoded decoded token + extraheader="$(git config --local --get http.https://github.com/.extraheader 2>/dev/null || true)" + if [[ "${extraheader}" =~ ^AUTHORIZATION:\ basic\ (.+)$ ]]; then + encoded="${BASH_REMATCH[1]}" + decoded="$(printf '%s' "${encoded}" | base64 --decode 2>/dev/null || true)" + token="${decoded#x-access-token:}" + if [[ -n "${token}" && "${token}" != "${decoded}" ]]; then + export GH_TOKEN="${token}" + export GITHUB_TOKEN="${token}" + return 0 + fi + fi + return 0 +} + +prepare_opencode_gh_token +``` + +If no OpenCode App token is available in Git config, keep the existing `GH_TOKEN` or `GITHUB_TOKEN` fallback. This happens when the workflow explicitly uses `use-github-token: true` or when running locally. Do not print tokens or decoded authentication headers. + ## Supported Aspects | Aspect | Agent(s) | Notes | @@ -100,55 +128,121 @@ Every subagent returns findings in this normalized structure: message: ``` -### Filtering rules applied before returning the response +### Filtering rules applied before posting the review 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. 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 a `file:line` reference 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 only when it still preserves an actionable inline anchor. If several findings share one root cause, keep one representative inline comment at the best anchor and mention the other affected files briefly in that comment. Do not collapse an anchorable finding into a top-level-only summary. 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. -## File:line Reference Validation +## Diff Anchor Validation + +Before submitting a GitHub review, classify every surviving finding as either inline or summary-only. + +### Inline comment requirements + +- Every finding with a valid `file` and diff-anchorable `line` must become an inline review comment. +- Do not skip inline comments merely because the same finding is also listed in a summary. +- Do not convert all findings into a single top-level markdown response when one or more valid inline anchors exist. +- Summary-only findings are allowed only when the issue is real but cannot be safely anchored to the diff, such as a cross-file design issue or a stale/unavailable line. -Before building the review response, every finding is validated against the PR diff so the `file:line` references in the single OpenCode comment stay accurate: +### Anchor validation rules -- A line is valid if it falls within a `+` hunk or surrounding unchanged-context lines of that hunk for the given file. -- Findings whose line cannot be safely matched are **kept in the summary body** with the nearest valid anchor line (or the file alone) instead of an unverified line number — not dropped, since the file is a changed file and only the line is unverifiable. +- Use the hunk list from `gh pr diff` in PR mode or `git diff` in local mode. +- A line is valid when it can be anchored on the head side of a hunk for the given file. +- Prefer an added or modified line that directly caused the issue. +- If the reported line is not anchorable but the same finding has a nearby valid head-side diff line in the same file, adjust to the nearest relevant line and keep it inline. +- If no safe anchor exists, mark the finding summary-only with a short reason. Do not silently drop it. - One unverifiable reference never fails the entire review. -## Review Output Policy +## Review Submission Policy + +### PR mode with no findings + +Return exactly: + +```text +No noteworthy issues found. +``` + +Do not submit an empty GitHub review. + +### PR mode with inline findings + +Submit one GitHub pull request review via `gh api` using a structured review payload with `comments` entries. Use `gh api` instead of `gh pr review` because this workflow needs explicit per-line anchors. -Return one final markdown review response. Do **not** call `gh api`, `gh pr review`, or `gh pr comment` — the surrounding `opencode github run` integration posts the response to the PR as `opencode-agent[bot]`. Posting directly would create a duplicate `github-actions[bot]` posting. +Before submission, call `prepare_opencode_gh_token` again. This ensures `gh api` uses the OpenCode GitHub App token when available, even if the workflow also provided a default `GITHUB_TOKEN`. -All findings (whether or not their line matched the diff) go in the summary body as `file:line` references so the single top-level OpenCode comment stays actionable. +The review body must enumerate every summary-only item, including its fallback reason: -**Output policy:** +```markdown +OpenCode PR Review: inline finding(s), summary-only finding(s). + +Summary-only findings: +- `` — : +``` + +Build the review payload with `jq`, not string interpolation, and write it to a private temporary file: + +```bash +prepare_opencode_gh_token + +review_payload="$(mktemp "${TMPDIR:-/tmp}/opencode-pr-review.XXXXXX.json")" +chmod 600 "$review_payload" +trap 'rm -f "$review_payload"' EXIT + +jq -n \ + --arg commit_id "$head_oid" \ + --arg body "$review_body" \ + --argjson comments "$comments_json" \ + '{commit_id: $commit_id, event: "COMMENT", body: $body, comments: $comments}' \ + > "$review_payload" + +gh api \ + --method POST \ + "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" \ + --input "$review_payload" +``` + +Operational requirements: + +- Prefer the OpenCode GitHub App token from Git config for `gh` commands so inline review submissions are authored by `opencode-agent[bot]`. +- If no OpenCode App token is available, fall back to `GH_TOKEN` or `GITHUB_TOKEN`; this may make direct review submissions appear as `github-actions[bot]`. +- Use the PR head SHA from `gh pr view --json headRefOid` as `commit_id`. +- Include `summary_only` findings in the review `body`, not as fake inline comments. +- Handle only GitHub 422 anchor-validation failures with the inline-comment retry path. Inspect `errors[].field` values such as `comments[0].line` to map failures back to specific `comments[N]` entries. +- If GitHub rejects one or more inline anchors and the offending entries can be identified, move only those findings to `summary_only` with the rejection reason and retry once. +- If a 422 anchor error does not identify the offending `comments[N]` entry, move all inline findings from that failed attempt to `summary_only` before retrying or falling back so no finding is lost. +- If the error indicates the `commit_id` is stale or is no longer part of the pull request, refetch `headRefOid`, rebuild the payload with the new SHA, and retry once. If the refetched SHA still fails, use the fallback path. +- If the retry still fails, do not claim inline comments were posted. Return a concise failure report and convert every attempted inline finding into a summary-only fallback entry, including its file, line, severity, source, message, and failure reason. + +After a successful submission, return only a concise status, for example: + +```text +Submitted OpenCode PR review with 3 inline comment(s) and 1 summary-only finding. +``` -- **Duplicated root causes** → one summary entry listing all affected files. -- Reserve `file:line` references for issues tied to a specific line. Cross-document or cross-file consistency problems should usually be summarized once in the review body instead of repeated across every affected file. +### PR mode without inline findings -Use the review body for: +If all findings are valid but none can be safely anchored inline, return a concise markdown review body as a top-level fallback and explicitly state why inline comments were not used. -- Concise summary of areas reviewed -- All findings as `file:line` references -- Aggregated root-cause occurrences and their affected files -- General observations -- No-finding confirmation +### Local mode -If no findings: return `No noteworthy issues found.` — one line, no padding. +Print the same normalized review summary to the user. Do not call `gh api`, `gh pr review`, or `gh pr comment`. ## Workflow -1. **Detect context** — GitHub Actions (PR mode) or local (local mode). +1. **Detect context** — GitHub Actions (PR mode) or local (local mode). Prefer the OpenCode App token from Git config for `gh` when available. 2. **Gather diff** — `gh pr diff` in PR mode; `git diff` in local mode. -3. **Choose reviewers** — based on `$ARGUMENTS` and diff content. +3. **Choose reviewers** — based on requested aspects 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 references** — check each finding against the diff; adjust unverifiable line references (do not drop them). -7. **Return** — single markdown review response in PR mode; print summary in local mode. The `opencode github run` integration posts the PR-mode response as `opencode-agent[bot]`. +6. **Validate anchors** — classify findings as inline or summary-only; adjust nearby anchors when safe. +7. **Submit or return** — submit an inline GitHub review in PR mode when anchors exist; otherwise use the documented fallback. In local mode, print the summary only. ## Workflow Integration @@ -170,7 +264,7 @@ If no findings: return `No noteworthy issues found.` — one line, no padding. **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 returns a single markdown review response. The `opencode github run` integration posts that response to the PR as `opencode-agent[bot]` — no separate `github-actions[bot]` review is produced. +2. The orchestrator gathers the PR via `gh`, runs the agents, validates anchors, and submits a GitHub review with inline comments for anchorable findings. Direct review submissions prefer the OpenCode App token from Git config, so they are authored by `opencode-agent[bot]` when the default App-token flow is used. The `opencode github run` integration then posts only a short status comment. 3. Re-run by commenting `/opencode` or `/oc` on the PR. **After PR feedback:** @@ -184,6 +278,7 @@ If no findings: return `No noteworthy issues found.` — one line, no padding. - Agents run autonomously and return structured findings. - Each agent focuses on its specialty for deep analysis. -- Results are actionable with specific `file:line` references. -- The skill returns one final markdown response; it never posts to GitHub directly. -- Never include secrets, tokens, or full file contents in the review response. +- Results are actionable with specific inline anchors whenever the diff supports them. +- The skill posts a GitHub review only in PR mode when inline anchors exist; otherwise it uses the documented fallback. +- Never include secrets, tokens, or full file contents in the review response or GitHub comments. +- Never print tokens or decoded authentication headers in logs. diff --git a/README.md b/README.md index 4843404..db007d7 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ jobs: uses: dceoy/opencode-action@v0 env: OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} with: model: opencode-go/glm-5.2 ``` @@ -66,7 +66,7 @@ Then comment `/opencode` or `/oc` on an issue, pull request, or pull request rev | Output | Description | | ------------------ | ----------------------------------------------- | -| `opencode-version` | OpenCode version resolved for the workflow run. | +| `opencode-version` | OpenCode version resolved for this run. | | `cache-hit` | Whether the OpenCode binary cache was restored. | ## Secrets @@ -82,9 +82,14 @@ When `use-github-token: true`, pass `GITHUB_TOKEN` in `env` and grant the workfl ## Pull Request Reviews -The bundled `/review-pr` command produces a single markdown review response that the OpenCode GitHub integration posts to the PR as `opencode-agent[bot]`. The command does not post to GitHub directly, so a review run yields one OpenCode PR comment rather than a separate `github-actions[bot]` review. Workflows that invoke it must provide: +The bundled `/review-pr` command submits a GitHub pull request review through `gh api`. It uses inline review comments for every finding that can be safely anchored to the PR diff, and includes only unanchorable findings in the review body as summary-only fallback items when at least one inline comment is submitted. If no finding can be anchored inline, `/review-pr` returns a top-level markdown fallback instead. The surrounding `opencode github run` integration still posts the command's final text to the PR, so the command returns only a short status message after a successful inline review submission. -- `GH_TOKEN: ${{ github.token }}` or `GITHUB_TOKEN: ${{ github.token }}` for `gh pr diff` / `gh pr view` reads +When the default OpenCode GitHub App flow is used (`use-github-token: false`), `/review-pr` restores the App token that OpenCode configured in the local Git extraheader and exports it for `gh`. Direct inline review submissions are therefore authored by `opencode-agent[bot]`. If the workflow explicitly opts into `use-github-token: true`, `/review-pr` falls back to the workflow token and direct review submissions may appear as `github-actions[bot]`. + +Workflows that invoke `/review-pr` must provide: + +- `pull-requests: write` permission +- `GH_TOKEN: ${{ github.token }}` or `GITHUB_TOKEN: ${{ github.token }}` for `gh pr diff`, `gh pr view`, and `gh api` review submission when using `use-github-token: true`; with the default App-token flow, `/review-pr` prefers the OpenCode App token from Git config for `gh api` - A valid API key for the selected model provider with available credits or quota Example OpenCode step: @@ -94,7 +99,6 @@ Example OpenCode step: uses: dceoy/opencode-action@v0 env: OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - GH_TOKEN: ${{ github.token }} with: model: openrouter/openrouter/free prompt: /review-pr @@ -134,7 +138,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 being returned. All findings go into a single markdown response as `file:line` references; duplicated root causes produce one summary entry listing all affected files, and cross-document or cross-file consistency problems are summarized once instead of repeated at each location. The surrounding `opencode github run` integration posts that response to the PR as `opencode-agent[bot]`. +Findings are normalized, deduplicated across agents, and validated against the PR diff before being posted. Diff-anchorable findings are submitted as GitHub inline review comments. When inline comments are submitted, findings that cannot be safely anchored remain in the GitHub review body with an explicit fallback reason. When no inline anchors are available, the command returns a top-level fallback response instead. ## Examples