feat(review): review a unified diff file without a repository, plannotator review --patch-file (#1554)
* feat(review): support static patch files (PR #1331 base)
Applies backnotprop/plannotator#1331 onto 0.27.15: review-args gains
--patch-file with parse once-required path semantics folded into the
errors[] contract (hosts must surface rather than throw); the direct
`plannotator review` CLI reads a static unified diff from a file or `-`
(stdin) and opens a workspace-less session (diffType "static-patch").
Harness surfaces (pi command, opencode bridge) keep the PR's explicit
reject for now — generalized in the follow-up commit.
Co-Authored-By: Kimchi <noreply@kimchi.dev>
* feat(review): static patch review across harnesses (pi, opencode)
Generalizes #1331's CLI-only --patch-file to the in-process harnesses:
- pi: openCodeReview / startCodeReviewBrowserSession accept `patch`
(inline unified diff), `patchFile` (path read at call time, resolved
against the caller cwd), and `patchLabel`; static sessions open the
same review server with diffType "static-patch" and no workspace /
gitContext, so no repo is required. The shared `plannotator:request`
bus forwards the three fields on the `code-review` action, and
`/plannotator-review --patch-file <path>` now works inside pi instead
of erroring. patch* and prUrl remain mutually exclusive.
- opencode: the OpenCode bridge (opencode-review entrypoint) reads
`--patch-file <path>` itself — relative to PLANNOTATOR_CWD or the
process cwd — and starts the review in static-patch mode. `-` (stdin)
is rejected with guidance: the bridge's stdin carries the input JSON.
- docs: pi README documents the new code-review payload fields and the
command flag.
Tests: `bun test apps/pi-extension` (276 pass; the same 2 config tests
fail on a clean tree — env-dependent baseline), `bun test
apps/opencode-plugin`, `bun test apps/hook/server`,
`tsc -p apps/pi-extension/tsconfig.json` all green.
Co-Authored-By: Kimchi <noreply@kimchi.dev>
* Tighten static patch review: single parser validator, shared reader, drop unused options
- Move --patch-file conflict validation into parseReviewArgs (PR URL,
--base, --diff-type, --git/--gitbutler, explicit --local) so all three
runtimes reject in one place; delete the duplicated guards in the
direct CLI and OpenCode bridge branches.
- Extract readStaticPatch() shared by both Bun review entry paths;
reject empty patch content on the Bun path to match Pi.
- Remove the uncalled inline `patch` and `patchLabel` options from the
Pi session/event API.
- Document --patch-file in the plannotator knowledge skill.
Co-Authored-By: Kimchi <noreply@kimchi.dev>
* feat(review): advertise static-patch mode and refuse working-tree endpoints
A `--patch-file` session has no repo, no worktree and no VCS, but the
payload never said so: `diffType` was withheld (it is gated on local
access), so the browser stayed on its `uncommitted` default and rendered
Git Add buttons and "No uncommitted changes"; `repoInfo` advertised
whatever repo the server process happened to sit in.
Both runtimes now carry `sourceKind: "patch"` beside
`approvalNotesSupported` on every diff payload (absent reads as "vcs", so
an ordinary review's payload is byte-identical), serve `diffType` in patch
mode, and omit `repoInfo`.
`/api/git-add`, `/api/file-content` and `/api/open-in` answer 400, and
`/api/open-in/apps` advertises none: the patch's paths belong to whatever
tree produced it, so resolving them against this process's cwd would
stage, read, or open an unrelated same-named file.
* feat(review-editor): render static-patch sessions honestly
Reads the `sourceKind` advert and turns off every affordance that assumes
a repository:
- `canUseLiveWorkspaceActions` is false, which already gates open-in-app,
code navigation, token hover cards and editor annotations.
- Hunk-context expansion is skipped rather than firing `/api/file-content`
requests the server now 400s (`contextExpansionAvailable` on the review
state, threaded to both diff surfaces).
- Edit Mode is off: it reads and writes the file on disk.
- The freshness probe is off: the patch bytes cannot go stale.
- The header names the patch ("sample.diff · Patch") instead of falling
through to a bare "Review" beside an unrelated repo.
- The empty state says "The patch contains no changes." — or "could not be
parsed as a unified diff" when the bytes carry no diff headers — instead
of "No uncommitted changes to review."
Staging, the diff-type/base pickers, the Git status and Commits panels and
the fetch-base banner already self-hide once `diffType` is `static-patch`
and `gitContext` is absent.
* fix(review): treat --no-local as a --patch-file conflict; reject stdin on Pi
`--no-local` is a PR-review selector exactly like `--local`, and `useLocal`
defaults to true, so only flag PRESENCE can decide the conflict — it was
silently ignored next to `--patch-file`.
The Pi host has no stdin of its own (it is reached through an extension
event), so `--patch-file -` read a file literally named "-"; it now refuses
with a clear message. Drops the unreachable `if (options.prUrl) throw` in
the same branch: the enclosing `else if` already means prUrl is falsy.
* test(review): pin static-patch adverts and endpoint refusals in both runtimes
Boots a Bun and a Pi review server on a patch and asserts the payload
carries `sourceKind`/`diffType` and no `repoInfo`/`gitContext`, and that
git-add, file-content and open-in answer 400. A VCS session is checked
alongside so the guards stay keyed on patch mode and the advert stays
absent for an ordinary review.
* docs(review): document --patch-file and what it switches off
Adds the usage section to the code-review reference and keeps the
freshness-guarded plannotator skill in step, including the corrected
--local/--no-local conflict wording.
* chore(guides-show): repin the viewer manifest
AllFilesCodeView gained the context-expansion seam, and the portable
viewer bundles it.
* chore(guides-show): repin the viewer manifest after merging main
---------
Co-authored-by: Kimchi <noreply@kimchi.dev>
Co-authored-by: Michael Ramos <mdramos8@gmail.com> L
Linas N. committed
7de822c4d6cf030643a731c98db955418e2e3bb5
Parent: 309eb61
Committed by GitHub <noreply@github.com>
on 9/18/2026, 12:13:51 AM