Skip to content

feat(review): support reviewing GitHub PRs via --pr / focus auto-detect#2

Merged
JohnnyVicious merged 1 commit intomainfrom
fix/pr-fetch
Apr 12, 2026
Merged

feat(review): support reviewing GitHub PRs via --pr / focus auto-detect#2
JohnnyVicious merged 1 commit intomainfrom
fix/pr-fetch

Conversation

@JohnnyVicious
Copy link
Copy Markdown
Owner

Summary

  • Adds a real PR-fetch path to /opencode:review and /opencode:adversarial-review. Before this change, asking the reviewer to "review PR #390" silently fell back to a local working-tree review and treated the PR reference as focus text.
  • New lib/git.mjs helpers getPrInfo and getPrDiff shell out to gh pr view --json and gh pr diff, with an actionable error if gh is missing, unauthenticated, or pointed at the wrong remote.
  • buildReviewPrompt accepts opts.pr; when set it sources the diff and changed-file list from gh instead of git, swaps the target label to Pull request #N "title" (head -> base), and emits a <pr_metadata> block so the reviewer sees branch refs, URL, and stat counts.
  • Both review handlers accept --pr <N>. The adversarial handler additionally auto-detects PR #N / pr N (case-insensitive) inside the focus text via detectPrReference and strips the matched substring so it doesn't end up in the prompt. Explicit --pr always wins over auto-detection.
  • Command markdown updated to document the new flag, the gh requirement, and a PR-size estimation rule (gh pr view --json additions,deletions,changedFiles) for the orchestrator.
  • Apache 2.0 §4(b) modification notices added to the modified scripts.

Conflict note

This branch and #1 (fix/model-passthrough) both touch the valueOptions array in handleReview / handleAdversarialReview. The second-merged branch will need a trivial conflict resolution: merge "model" and "pr" into the same array.

Test plan

  • node --check passes for opencode-companion.mjs, lib/git.mjs, lib/prompts.mjs
  • detectPrReference smoke-tested against 10 input variants (positive: PR #390, pr 390, embedded references; negative: fix #123, plain text, empty/null)
  • Focus-text strip confirmed: "on PR #390" -> pr=390, focus "on"; "review PR #42 for security issues" -> pr=42, focus "review for security issues"
  • Manual: /opencode:adversarial-review --wait --pr 390 against a repo whose origin is on GitHub returns a review of the PR diff (not the local working tree)
  • Manual: /opencode:adversarial-review --wait on PR #390 triggers the same PR fetch via auto-detection
  • Manual: /opencode:adversarial-review --wait --pr 999999 (nonexistent PR) surfaces the gh pr view error cleanly
  • Manual: /opencode:adversarial-review --wait some focus text (no PR ref) still reviews the working tree (regression check)

Previously, /opencode:review and /opencode:adversarial-review could only
review the local working tree or a base-branch diff. A request like
"/opencode:adversarial-review on PR #390" was silently misrouted: the
companion still ran git diff against the local working tree, and the
"on PR #390" string only entered the prompt as focus text. The reviewer
ended up commenting on whatever happened to be in the local checkout.

This change adds a real PR-fetch path:

* `lib/git.mjs` gains `detectPrReference`, `getPrInfo`, and `getPrDiff`
  helpers that shell out to `gh pr view --json` and `gh pr diff`. They
  surface a clear error if `gh` is missing, unauthenticated, or pointed
  at the wrong remote.

* `lib/prompts.mjs#buildReviewPrompt` accepts `opts.pr`. When set, it
  fetches PR metadata + diff via `gh` instead of reading the local
  working tree, swaps the target label to "Pull request #N (title)", and
  emits a `<pr_metadata>` block in the review context so the reviewer
  knows the base/head refs and stat counts.

* `handleReview` and `handleAdversarialReview` accept `--pr <N>`. The
  adversarial handler additionally auto-detects "PR #N" / "PR N" / "pr
  #N" / "pr N" inside the focus text (case-insensitive) and strips the
  matched substring so it does not pollute the prompt. Explicit `--pr`
  always wins over auto-detection.

* Both command markdown files document the new flag, mention the `gh`
  requirement, and add a PR-size estimation rule for the orchestrator.

Apache License 2.0 §4(b) modification notices added to all three
modified script files.

Note: this branch and `fix/model-passthrough` both touch `valueOptions`
in `handleReview`/`handleAdversarialReview`, so the second-merged branch
will need a trivial conflict resolution (merge the two arrays).
@JohnnyVicious JohnnyVicious merged commit c030102 into main Apr 12, 2026
@JohnnyVicious JohnnyVicious deleted the fix/pr-fetch branch April 12, 2026 12:47
JohnnyVicious added a commit that referenced this pull request Apr 12, 2026
`/opencode:adversarial-review on PR #389` was silently misrouted to a
working-tree review because bash strips unquoted `#389` tokens as
comments before they reach the companion script. The fix in PR #2
(detectPrReference + focus auto-detect in handleAdversarialReview)
was correct in isolation but never ran — by the time the companion
script saw argv, the `#389` had already been removed at the shell
boundary, so the regex had nothing to match.

The fix has to live at the slash-command markdown level, because that
is where Claude reads the instructions about how to construct the bash
command. Two complementary defenses:

1. **PR reference extraction (REQUIRED)**. New rule in both
   adversarial-review.md and review.md telling Claude to recognise
   `PR #N` / `pr #N` / `PR N` patterns in the user's input, extract
   the number, pass it as `--pr N`, and strip the matched phrase from
   any focus text. Includes a worked transformation example showing
   the wrong (bash-eats-the-comment) vs right (--pr extracted) form.

2. **Focus text quoting (REQUIRED, adversarial only)**. New rule in
   adversarial-review.md telling Claude to wrap focus text in single
   quotes when invoking bash, so other shell metacharacters
   (`*`, `$`, `;`, `&`, `|`, `<`, `>`, parens, backticks) survive.
   Includes guidance on the `'\''` escape for apostrophes.

3. Updated the foreground/background flow examples to stop showing
   `$ARGUMENTS` literally (which trained Claude to invoke bash without
   any of the above transformations) and instead show the
   illustrative shape `<flags> [--pr N] ['<quoted focus>']` with an
   explicit "transform $ARGUMENTS first" instruction.

The companion script's focus-text PR auto-detect (detectPrReference)
is intentionally kept as a fallback for cases where focus text reaches
the script intact (e.g. someone calling the companion directly via
bash with proper quoting, bypassing the slash command).

No code or test changes — these are slash-command instructions read by
Claude, not executed by node.
JohnnyVicious added a commit that referenced this pull request Apr 12, 2026
)

`/opencode:adversarial-review on PR #389` was silently misrouted to a
working-tree review because bash strips unquoted `#389` tokens as
comments before they reach the companion script. The fix in PR #2
(detectPrReference + focus auto-detect in handleAdversarialReview)
was correct in isolation but never ran — by the time the companion
script saw argv, the `#389` had already been removed at the shell
boundary, so the regex had nothing to match.

The fix has to live at the slash-command markdown level, because that
is where Claude reads the instructions about how to construct the bash
command. Two complementary defenses:

1. **PR reference extraction (REQUIRED)**. New rule in both
   adversarial-review.md and review.md telling Claude to recognise
   `PR #N` / `pr #N` / `PR N` patterns in the user's input, extract
   the number, pass it as `--pr N`, and strip the matched phrase from
   any focus text. Includes a worked transformation example showing
   the wrong (bash-eats-the-comment) vs right (--pr extracted) form.

2. **Focus text quoting (REQUIRED, adversarial only)**. New rule in
   adversarial-review.md telling Claude to wrap focus text in single
   quotes when invoking bash, so other shell metacharacters
   (`*`, `$`, `;`, `&`, `|`, `<`, `>`, parens, backticks) survive.
   Includes guidance on the `'\''` escape for apostrophes.

3. Updated the foreground/background flow examples to stop showing
   `$ARGUMENTS` literally (which trained Claude to invoke bash without
   any of the above transformations) and instead show the
   illustrative shape `<flags> [--pr N] ['<quoted focus>']` with an
   explicit "transform $ARGUMENTS first" instruction.

The companion script's focus-text PR auto-detect (detectPrReference)
is intentionally kept as a fallback for cases where focus text reaches
the script intact (e.g. someone calling the companion directly via
bash with proper quoting, bypassing the slash command).

No code or test changes — these are slash-command instructions read by
Claude, not executed by node.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant