From cc25e52d017a7b98f89288b464ab5485b46e3f99 Mon Sep 17 00:00:00 2001 From: dceoy <1938249+dceoy@users.noreply.github.com> Date: Mon, 13 Jul 2026 04:10:38 +0900 Subject: [PATCH] refactor /review-pr into a reusable pr-review skill Move the canonical PR review workflow from .opencode/commands/review-pr.md into .opencode/skills/pr-review/SKILL.md so agents can load it through the native skill tool. Keep /review-pr as a thin wrapper that forwards the requested aspects and loads the skill, allow the review-pr-orchestrator agent to load only the pr-review skill, and update the validation suite and documentation to track the new implementation source. Closes #32 Co-Authored-By: Claude Fable 5 --- .../local-qa/scripts/validate-opencode.bats | 48 ++++++++--- .opencode/agents/review-pr-orchestrator.md | 5 +- .opencode/commands/review-pr.md | 82 +----------------- .opencode/skills/pr-review/SKILL.md | 86 +++++++++++++++++++ AGENTS.md | 4 +- README.md | 2 +- 6 files changed, 132 insertions(+), 95 deletions(-) create mode 100644 .opencode/skills/pr-review/SKILL.md diff --git a/.agents/skills/local-qa/scripts/validate-opencode.bats b/.agents/skills/local-qa/scripts/validate-opencode.bats index 3bc421e..51f4d62 100644 --- a/.agents/skills/local-qa/scripts/validate-opencode.bats +++ b/.agents/skills/local-qa/scripts/validate-opencode.bats @@ -1,18 +1,20 @@ #!/usr/bin/env bats # Validate .opencode/ agent frontmatter, review-pr command/skill references, # that opencode.jsonc parses, and that its external_directory permission -# allow-lists the resolver path review-pr.md actually sources and the runtime -# review-state directory pattern. +# allow-lists the resolver path the pr-review skill actually sources and the +# runtime review-state directory pattern. setup() { repo_root="$(git -C "${BATS_TEST_DIRNAME}" rev-parse --show-toplevel)" agents_dir="${repo_root}/.opencode/agents" - review_pr_doc="${repo_root}/.opencode/commands/review-pr.md" + review_pr_command="${repo_root}/.opencode/commands/review-pr.md" + review_pr_doc="${repo_root}/.opencode/skills/pr-review/SKILL.md" + orchestrator="${agents_dir}/review-pr-orchestrator.md" opencode_jsonc="${repo_root}/.opencode/opencode.jsonc" required_keys=(name description mode permission) - # Backtick-quoted identifiers in review-pr.md that are skills, toolkits, or - # config inputs rather than agents. - non_agents=(pr-feedback-triage pr-review-toolkit use-github-token) + # Backtick-quoted identifiers in the review-pr command and pr-review skill + # that are skills, toolkits, or config inputs rather than agents. + non_agents=(pr-feedback-triage pr-review pr-review-toolkit use-github-token) } agent_files() { @@ -66,11 +68,11 @@ frontmatter() { } } -@test "every agent referenced in review-pr.md exists under .opencode/agents/" { +@test "every agent referenced in the review-pr command and pr-review skill exists under .opencode/agents/" { local bt pattern refs ref skip na missing=() bt=$(printf '\x60') pattern="${bt}[a-z][a-z0-9]+(-[a-z0-9]+)+${bt}" - mapfile -t refs < <(grep -hoE "${pattern}" "${review_pr_doc}" | tr -d "${bt}" | sort -u) + mapfile -t refs < <(grep -hoE "${pattern}" "${review_pr_command}" "${review_pr_doc}" | tr -d "${bt}" | sort -u) for ref in "${refs[@]}"; do skip=0 @@ -91,6 +93,30 @@ frontmatter() { sed -E 's#^[[:space:]]*//.*$##' "${opencode_jsonc}" | jq empty } +@test "review-pr command is a thin wrapper that loads the pr-review skill" { + local bt + bt=$(printf '\x60') + grep -Fq "${bt}pr-review${bt} skill" "${review_pr_command}" + # shellcheck disable=SC2016 + grep -Fq '$ARGUMENTS' "${review_pr_command}" + # The canonical workflow must not be duplicated in the command. + run grep -E 'review-pr-(submit|gh)\.sh|resolve-app-token\.sh|review-state' "${review_pr_command}" + [ "${status}" -eq 1 ] +} + +@test "pr-review skill frontmatter declares its name and description" { + local fm + fm="$(frontmatter "${review_pr_doc}")" + grep -qE '^name:[[:space:]]*pr-review$' <<<"${fm}" + grep -qE '^description:[[:space:]]*[^[:space:]]' <<<"${fm}" +} + +@test "review-pr orchestrator allows loading the pr-review skill" { + local fm + fm="$(frontmatter "${orchestrator}")" + grep -qE '^[[:space:]]+pr-review:[[:space:]]*allow$' <<<"${fm}" +} + @test "review-pr local fallback is limited to a missing trusted PR number" { # shellcheck disable=SC2016 grep -Fq 'If `context` reports `Trusted pull request number is unavailable.`, continue in local mode; for every other `context` failure, stop.' "${review_pr_doc}" @@ -102,12 +128,12 @@ opencode_jsonc_json() { sed -E 's#^[[:space:]]*//.*$##' "${opencode_jsonc}" } -@test "review-pr.md sources the resolver from a path opencode.jsonc allow-lists under external_directory" { +@test "pr-review skill sources the resolver from a path opencode.jsonc allow-lists under external_directory" { local resolver_suffix resolver_path default_action allow_patterns pattern expanded matched=0 resolver_suffix="$(grep -oE 'opencode_app_token_lib="\$\{HOME\}/[^"]+"' "${review_pr_doc}" | head -1 | sed -E 's/^opencode_app_token_lib="\$\{HOME\}\/(.*)"$/\1/')" [ -n "${resolver_suffix}" ] || { - echo "review-pr.md does not set opencode_app_token_lib to a \${HOME}-relative path" + echo "the pr-review skill does not set opencode_app_token_lib to a \${HOME}-relative path" return 1 } resolver_path="${HOME}/${resolver_suffix}" @@ -132,7 +158,7 @@ opencode_jsonc_json() { done [ "${matched}" -eq 1 ] || { - echo "no external_directory allow pattern (${allow_patterns[*]}) matches the resolver path ${resolver_path} that review-pr.md sources" + echo "no external_directory allow pattern (${allow_patterns[*]}) matches the resolver path ${resolver_path} that the pr-review skill sources" return 1 } } diff --git a/.opencode/agents/review-pr-orchestrator.md b/.opencode/agents/review-pr-orchestrator.md index c531078..effbe97 100644 --- a/.opencode/agents/review-pr-orchestrator.md +++ b/.opencode/agents/review-pr-orchestrator.md @@ -24,6 +24,9 @@ permission: "../*.config/opencode/review-state/update.json": allow glob: allow grep: allow + skill: + "*": deny + pr-review: allow bash: "*": deny "git status --short": allow @@ -51,4 +54,4 @@ permission: code-simplifier: allow --- -Coordinate a strictly read-only review. Never modify the checkout. Use only the exact argument-free helper commands, the two fixed review-state JSON files, and the approved reviewer agents. +Coordinate a strictly read-only review. The canonical workflow is the `pr-review` skill; load it and follow it exactly. Never modify the checkout. Use only the exact argument-free helper commands, the two fixed review-state JSON files, and the approved reviewer agents. diff --git a/.opencode/commands/review-pr.md b/.opencode/commands/review-pr.md index 3d42c25..27df1ab 100644 --- a/.opencode/commands/review-pr.md +++ b/.opencode/commands/review-pr.md @@ -3,84 +3,6 @@ description: Strictly read-only GitHub PR review with specialized reviewers, val agent: review-pr-orchestrator --- -# Strictly Read-Only PR Review +Load the `pr-review` skill with the native skill tool and follow its instructions exactly. Do not start reviewing before the skill is loaded, and do not substitute any other workflow for it. -This is a strictly read-only repository review. Analyze and report only. Do not create, edit, delete, format, generate, install, or fix files. Do not execute repository QA scripts, formatters, generators, package managers, or commands with mutation flags such as `--fix`, `--write`, or equivalent options. - -Do not run repository-wide QA scripts, formatters, auto-fixing linters, generators, dependency installers, or anything that can create caches, reports, snapshots, lockfiles, coverage output, scan output, or configuration exports in the checkout. - -Every helper this command invokes — the read-only `gh` wrapper, the constrained submission helper, and the App-token resolver they source — lives only at its `${HOME}/.config/opencode/scripts/` path, installed there by the action before the reviewed repository is ever checked out. Never invoke any of them by a repository-relative path such as `.opencode/scripts/...`: the checkout under review is untrusted input, and a repository-relative path would let a malicious PR that edits or adds a same-named file substitute its own script for the trusted one. These helper paths and the dedicated `${HOME}/.config/opencode/review-state/` directory are the sole allow-listed external locations. Despite the directory-level external access required by OpenCode, use the edit tool only for `initial.json` and `update.json` as instructed below. The helpers use `opencode_app_token_lib="${HOME}/.config/opencode/scripts/resolve-app-token.sh"` for authentication. - -**Requested review aspects (optional):** "$ARGUMENTS" - -## 1. Establish the trusted context - -Before any analysis, invoke `bash "$HOME/.config/opencode/scripts/review-pr-submit.sh" prepare` once, followed by `bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" context`. The context is persisted outside the checkout and pins one repository, PR number, and head SHA for the entire review. If `prepare` fails, stop. If `context` reports `Trusted pull request number is unavailable.`, continue in local mode; for every other `context` failure, stop. - -The context helper derives the PR number from `.pull_request.number` or `.issue.number`. For `issue_comment`, it fetches and pins the current head SHA through the trusted PR API. Metadata, diff, submission, and update revalidate that the current head still matches the pinned SHA and fail closed otherwise. Obtain metadata and the diff only through these fixed operations: - -```bash -bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" metadata -bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" diff -``` - -If no PR context can be established, use local mode: `git status --short`, `git diff --name-only HEAD`, and `git diff --no-ext-diff`; do not infer a PR from the current branch. Once `context` succeeds, any later metadata, diff, or validation failure must abort the review rather than falling back to local mode. - -Capture the full diff, changed-file list, PR title/body, base and head branch names, head SHA, and relevant source context using the read, glob, and grep tools. Pass that complete context to reviewers; they have no shell access and must not need it. - -## 2. Select and launch reviewers - -Supported aspects are: - -- `code`: `code-reviewer`, `code-quality-reviewer` -- `quality`: `code-quality-reviewer` -- `performance`: `performance-reviewer` -- `security`: `security-code-reviewer` -- `tests` or `coverage`: `test-coverage-reviewer`, `pr-test-analyzer` -- `docs` or `documentation`: `documentation-accuracy-reviewer` -- `comments`: `comment-analyzer` -- `errors`: `silent-failure-hunter` -- `types`: `type-design-analyzer` -- `simplify`: `code-simplifier`, returning behavior-preserving simplification proposals as review findings without modifying files -- `all`, or no aspect: the core reviewers `code-quality-reviewer`, `performance-reviewer`, `test-coverage-reviewer`, `documentation-accuracy-reviewer`, `security-code-reviewer`, and `code-reviewer`; include specialty reviewers when the supplied diff is relevant. Run `code-simplifier` only when `simplify` is explicitly requested; never include it in `all`. - -Launch only the explicitly permitted reviewer agents. For each, supply the captured diff, changed-file list, metadata, and relevant source context. Tell each reviewer to inspect changed lines and their containing functions only, return high-confidence findings only, and use: - -```yaml -- file: path/to/file - line: - severity: critical | important | suggestion - source: - message: -``` - -Do not let a reviewer post to GitHub. - -## 3. Normalize and anchor findings - -Drop praise, nitpicks, style-only feedback, findings outside the changed-file list, and duplicates. Keep the most specific actionable finding for each root cause. Classify every remaining finding as inline when its file and head-side changed line can be anchored in the captured diff; adjust only to a nearby relevant changed line. Put genuine but unanchorable findings in `summary_only` with a short reason. - -Before returning any top-level text in PR mode, including no-finding and summary-only fallback results, invoke `bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" validate`. If validation fails, stop. If there are no findings, then return exactly `No noteworthy issues found.` Do not post an empty review. - -For findings, the `prepare` and `context` operations in section 1 have already created the empty payload files and pinned the review context. Do not run them again. Use the edit tool only for `$HOME/.config/opencode/review-state/initial.json`, writing exactly `{body, comments}` with a nonempty body and inline comments array. The helper validates the payload and adds the trusted `commit_id` and `event` itself. Each inline body is `** · **: `. - -Every finding with a valid diff anchor must be included in the `comments` array and submitted as an inline review comment. Never return anchorable findings only as top-level assistant text. If structured submission fails, fail the run instead of emitting the findings as a top-level completion comment. - -When there are summary-only findings, the body begins `OpenCode PR Review: inline finding(s), summary-only finding(s).` and lists them. Otherwise it begins `OpenCode PR Review: inline finding(s).` Never use issue comments or `gh pr comment`. - -## 4. Submit through the constrained helper - -Use only these exact commands: - -```bash -bash "$HOME/.config/opencode/scripts/review-pr-submit.sh" submit-initial -bash "$HOME/.config/opencode/scripts/review-pr-submit.sh" update -``` - -After the single `prepare` in section 1, write the initial payload only to `$HOME/.config/opencode/review-state/initial.json`. Before `update`, write exactly `{body}` only to `$HOME/.config/opencode/review-state/update.json`. Never add arguments, redirections, pipelines, or process substitutions to helper commands. - -You never pass a repository, PR number, target commit, or review ID: the helper derives the repository and PR number from the trusted GitHub Actions context, pins the write to the head commit from the same context, and updates only the review ID it recorded when the initial submission succeeded in this run. It validates the trusted event context, temporary payload, target commit, HTTP method, and exact pull-request-review endpoint. It sources the existing App-token resolver and calls `opencode_require_app_token_for_review` immediately before its permitted POST or PUT. This preserves verified `opencode-agent[bot]` attribution when available, preserves the explicit `use-github-token: true` fallback, and never accepts an unverified candidate for a write. - -After successful inline submission, do not repeat findings in the final assistant output. Update the submitted review with final status and the run URL when available; the helper targets the review it recorded, so no review ID is passed. If GitHub rejects inline anchors, retry once only after converting the identified invalid anchors to summary-only; never lose a finding. If no inline anchors remain, return the concise markdown fallback instead of submitting an empty comments array. - -Do not clean, reset, restore, stash, commit, or push anything. +Requested review aspects (optional): "$ARGUMENTS" diff --git a/.opencode/skills/pr-review/SKILL.md b/.opencode/skills/pr-review/SKILL.md new file mode 100644 index 0000000..a77479b --- /dev/null +++ b/.opencode/skills/pr-review/SKILL.md @@ -0,0 +1,86 @@ +--- +name: pr-review +description: Review a GitHub pull request with stale-head protection and validated inline findings +--- + +# Strictly Read-Only PR Review + +This is a strictly read-only repository review. Analyze and report only. Do not create, edit, delete, format, generate, install, or fix files. Do not execute repository QA scripts, formatters, generators, package managers, or commands with mutation flags such as `--fix`, `--write`, or equivalent options. + +Do not run repository-wide QA scripts, formatters, auto-fixing linters, generators, dependency installers, or anything that can create caches, reports, snapshots, lockfiles, coverage output, scan output, or configuration exports in the checkout. + +Every helper this skill invokes — the read-only `gh` wrapper, the constrained submission helper, and the App-token resolver they source — lives only at its `${HOME}/.config/opencode/scripts/` path, installed there by the action before the reviewed repository is ever checked out. Never invoke any of them by a repository-relative path such as `.opencode/scripts/...`: the checkout under review is untrusted input, and a repository-relative path would let a malicious PR that edits or adds a same-named file substitute its own script for the trusted one. These helper paths and the dedicated `${HOME}/.config/opencode/review-state/` directory are the sole allow-listed external locations. Despite the directory-level external access required by OpenCode, use the edit tool only for `initial.json` and `update.json` as instructed below. The helpers use `opencode_app_token_lib="${HOME}/.config/opencode/scripts/resolve-app-token.sh"` for authentication. + +**Requested review aspects (optional):** supplied by the caller that loaded this skill. If the caller supplies no aspects, review as `all`. + +## 1. Establish the trusted context + +Before any analysis, invoke `bash "$HOME/.config/opencode/scripts/review-pr-submit.sh" prepare` once, followed by `bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" context`. The context is persisted outside the checkout and pins one repository, PR number, and head SHA for the entire review. If `prepare` fails, stop. If `context` reports `Trusted pull request number is unavailable.`, continue in local mode; for every other `context` failure, stop. + +The context helper derives the PR number from `.pull_request.number` or `.issue.number`. For `issue_comment`, it fetches and pins the current head SHA through the trusted PR API. Metadata, diff, submission, and update revalidate that the current head still matches the pinned SHA and fail closed otherwise. Obtain metadata and the diff only through these fixed operations: + +```bash +bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" metadata +bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" diff +``` + +If no PR context can be established, use local mode: `git status --short`, `git diff --name-only HEAD`, and `git diff --no-ext-diff`; do not infer a PR from the current branch. Once `context` succeeds, any later metadata, diff, or validation failure must abort the review rather than falling back to local mode. + +Capture the full diff, changed-file list, PR title/body, base and head branch names, head SHA, and relevant source context using the read, glob, and grep tools. Pass that complete context to reviewers; they have no shell access and must not need it. + +## 2. Select and launch reviewers + +Supported aspects are: + +- `code`: `code-reviewer`, `code-quality-reviewer` +- `quality`: `code-quality-reviewer` +- `performance`: `performance-reviewer` +- `security`: `security-code-reviewer` +- `tests` or `coverage`: `test-coverage-reviewer`, `pr-test-analyzer` +- `docs` or `documentation`: `documentation-accuracy-reviewer` +- `comments`: `comment-analyzer` +- `errors`: `silent-failure-hunter` +- `types`: `type-design-analyzer` +- `simplify`: `code-simplifier`, returning behavior-preserving simplification proposals as review findings without modifying files +- `all`, or no aspect: the core reviewers `code-quality-reviewer`, `performance-reviewer`, `test-coverage-reviewer`, `documentation-accuracy-reviewer`, `security-code-reviewer`, and `code-reviewer`; include specialty reviewers when the supplied diff is relevant. Run `code-simplifier` only when `simplify` is explicitly requested; never include it in `all`. + +Launch only the explicitly permitted reviewer agents. For each, supply the captured diff, changed-file list, metadata, and relevant source context. Tell each reviewer to inspect changed lines and their containing functions only, return high-confidence findings only, and use: + +```yaml +- file: path/to/file + line: + severity: critical | important | suggestion + source: + message: +``` + +Do not let a reviewer post to GitHub. + +## 3. Normalize and anchor findings + +Drop praise, nitpicks, style-only feedback, findings outside the changed-file list, and duplicates. Keep the most specific actionable finding for each root cause. Classify every remaining finding as inline when its file and head-side changed line can be anchored in the captured diff; adjust only to a nearby relevant changed line. Put genuine but unanchorable findings in `summary_only` with a short reason. + +Before returning any top-level text in PR mode, including no-finding and summary-only fallback results, invoke `bash "$HOME/.config/opencode/scripts/review-pr-gh.sh" validate`. If validation fails, stop. If there are no findings, then return exactly `No noteworthy issues found.` Do not post an empty review. + +For findings, the `prepare` and `context` operations in section 1 have already created the empty payload files and pinned the review context. Do not run them again. Use the edit tool only for `$HOME/.config/opencode/review-state/initial.json`, writing exactly `{body, comments}` with a nonempty body and inline comments array. The helper validates the payload and adds the trusted `commit_id` and `event` itself. Each inline body is `** · **: `. + +Every finding with a valid diff anchor must be included in the `comments` array and submitted as an inline review comment. Never return anchorable findings only as top-level assistant text. If structured submission fails, fail the run instead of emitting the findings as a top-level completion comment. + +When there are summary-only findings, the body begins `OpenCode PR Review: inline finding(s), summary-only finding(s).` and lists them. Otherwise it begins `OpenCode PR Review: inline finding(s).` Never use issue comments or `gh pr comment`. + +## 4. Submit through the constrained helper + +Use only these exact commands: + +```bash +bash "$HOME/.config/opencode/scripts/review-pr-submit.sh" submit-initial +bash "$HOME/.config/opencode/scripts/review-pr-submit.sh" update +``` + +After the single `prepare` in section 1, write the initial payload only to `$HOME/.config/opencode/review-state/initial.json`. Before `update`, write exactly `{body}` only to `$HOME/.config/opencode/review-state/update.json`. Never add arguments, redirections, pipelines, or process substitutions to helper commands. + +You never pass a repository, PR number, target commit, or review ID: the helper derives the repository and PR number from the trusted GitHub Actions context, pins the write to the head commit from the same context, and updates only the review ID it recorded when the initial submission succeeded in this run. It validates the trusted event context, temporary payload, target commit, HTTP method, and exact pull-request-review endpoint. It sources the existing App-token resolver and calls `opencode_require_app_token_for_review` immediately before its permitted POST or PUT. This preserves verified `opencode-agent[bot]` attribution when available, preserves the explicit `use-github-token: true` fallback, and never accepts an unverified candidate for a write. + +After successful inline submission, do not repeat findings in the final assistant output. Update the submitted review with final status and the run URL when available; the helper targets the review it recorded, so no review ID is passed. If GitHub rejects inline anchors, retry once only after converting the identified invalid anchors to summary-only; never lose a finding. If no inline anchors remain, return the concise markdown fallback instead of submitting an empty comments array. + +Do not clean, reset, restore, stash, commit, or push anything. diff --git a/AGENTS.md b/AGENTS.md index 10dc6fa..77ed7e2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## Project Structure & Module Organization -This repository publishes a composite GitHub Action for running OpenCode in GitHub Actions. The action contract, inputs, outputs, environment mappings, install steps, and `opencode github run` delegation live in `action.yml`. User-facing setup, examples, inputs, outputs, and secret requirements live in `README.md`. GitHub automation is under `.github/`, including `.github/workflows/ci.yml`, `.github/workflows/opencode.yml`, Dependabot, and Renovate configuration. Agent helper skills are under `.agents/skills/`. Bundled OpenCode agents/commands live under `.opencode/`, including `.opencode/scripts/resolve-app-token.sh`, a sourceable library the `/review-pr` command uses to resolve the OpenCode GitHub App token from git credential configuration, and `.opencode/opencode.jsonc`, which denies `external_directory` tool permission by default so a non-interactive CI run cannot hang on an unanswerable "ask" prompt, with a single narrow allow rule for `resolve-app-token.sh`'s own path so `/review-pr` can still source it from outside the checked-out repository once the toolkit is copied into a consumer's `~/.config/opencode` — both separate from the `.opencode/` tree that gets copied there. There is no package manager project or application source tree beyond these shell scripts. +This repository publishes a composite GitHub Action for running OpenCode in GitHub Actions. The action contract, inputs, outputs, environment mappings, install steps, and `opencode github run` delegation live in `action.yml`. User-facing setup, examples, inputs, outputs, and secret requirements live in `README.md`. GitHub automation is under `.github/`, including `.github/workflows/ci.yml`, `.github/workflows/opencode.yml`, Dependabot, and Renovate configuration. Agent helper skills are under `.agents/skills/`. Bundled OpenCode agents, commands, and skills live under `.opencode/`. The canonical PR review workflow is the `pr-review` skill in `.opencode/skills/pr-review/SKILL.md`; `.opencode/commands/review-pr.md` is a thin `/review-pr` wrapper that forwards its arguments and instructs the agent to load that skill. The tree also includes `.opencode/scripts/resolve-app-token.sh`, a sourceable library the review workflow uses to resolve the OpenCode GitHub App token from git credential configuration, and `.opencode/opencode.jsonc`, which denies `external_directory` tool permission by default so a non-interactive CI run cannot hang on an unanswerable "ask" prompt, with a single narrow allow rule for `resolve-app-token.sh`'s own path so `/review-pr` can still source it from outside the checked-out repository once the toolkit is copied into a consumer's `~/.config/opencode` — both separate from the `.opencode/` tree that gets copied there. There is no package manager project or application source tree beyond these shell scripts. ## Build, Test, and Development Commands @@ -12,7 +12,7 @@ There is no build step. Validate local changes with the repository QA script: .agents/skills/local-qa/scripts/qa.sh ``` -The script formats and lints the repository and mutates files in place: it runs `prettier --write` on markdown files, `yamllint` on tracked YAML, `shellcheck` on tracked shell scripts, `zizmor --fix=safe` and `actionlint` on `.github/workflows`, `checkov` across the repo, and every `bats` regression suite: `validate-opencode.bats` (validates `.opencode/` agent frontmatter, the agent references in `.opencode/commands/review-pr.md`, that `.opencode/opencode.jsonc` still parses once its `//` comments are stripped, and that its `external_directory` permission still allow-lists the exact resolver path `.opencode/commands/review-pr.md` sources behind a catch-all deny) and `test-resolve-app-token.bats` (App token candidate extraction from local, urlmatch, and includeIf/global-style git extraheader configurations with exact `github.com` host matching, `opencode-agent[bot]` identity verification via a stubbed `gh`, rejection of checkout-style/PAT-like credentials and malformed/non-JSON identity-probe responses that fail verification, resilience to a failing throwaway-review DELETE cleanup, fail-fast behavior when no token verifies, and preservation of the caller's explicit `use-github-token: true` workflow token — `opencode_prepare_gh_token` never overwrites it with an unverified candidate, and a verified `opencode-agent[bot]` candidate still takes precedence over it when one is found). Review the diff it produces before committing. For end-to-end testing, run the action from a temporary workflow or push a branch and reference it from a test repository workflow. +The script formats and lints the repository and mutates files in place: it runs `prettier --write` on markdown files, `yamllint` on tracked YAML, `shellcheck` on tracked shell scripts, `zizmor --fix=safe` and `actionlint` on `.github/workflows`, `checkov` across the repo, and every `bats` regression suite: `validate-opencode.bats` (validates `.opencode/` agent frontmatter, the agent references in the `/review-pr` command and the `pr-review` skill, that the command stays a thin wrapper around the skill, that `.opencode/opencode.jsonc` still parses once its `//` comments are stripped, and that its `external_directory` permission still allow-lists the exact resolver path `.opencode/skills/pr-review/SKILL.md` sources behind a catch-all deny) and `test-resolve-app-token.bats` (App token candidate extraction from local, urlmatch, and includeIf/global-style git extraheader configurations with exact `github.com` host matching, `opencode-agent[bot]` identity verification via a stubbed `gh`, rejection of checkout-style/PAT-like credentials and malformed/non-JSON identity-probe responses that fail verification, resilience to a failing throwaway-review DELETE cleanup, fail-fast behavior when no token verifies, and preservation of the caller's explicit `use-github-token: true` workflow token — `opencode_prepare_gh_token` never overwrites it with an unverified candidate, and a verified `opencode-agent[bot]` candidate still takes precedence over it when one is found). Review the diff it produces before committing. For end-to-end testing, run the action from a temporary workflow or push a branch and reference it from a test repository workflow. ## Coding Style & Naming Conventions diff --git a/README.md b/README.md index 3933af5..e36a256 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ When `use-github-token: true`, pass `GITHUB_TOKEN` in `env` and grant the workfl ## Pull Request Reviews -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. When there are no summary-only findings, the review body is a single line (`OpenCode PR Review: inline finding(s).`) with no empty "Summary-only findings" section. +The bundled review workflow is implemented as the `pr-review` OpenCode skill (`.opencode/skills/pr-review/SKILL.md`); the `/review-pr` command is a thin wrapper that forwards the requested aspects and loads that skill, so agents can also load `pr-review` directly through the native skill tool. The workflow 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. When there are no summary-only findings, the review body is a single line (`OpenCode PR Review: inline finding(s).`) with no empty "Summary-only findings" section. A successful structured review run produces one GitHub review summary (with its inline comments), which `/review-pr` updates in place with the run link. `/review-pr` never calls `gh pr comment` or the issue comment API itself. It may still return a short final assistant message after submitting the review; `opencode github run` posts that as a separate top-level completion comment, so a run can produce the review plus at most one additional completion comment — not necessarily exactly one top-level artifact.