@vintasoftware/pr-review-canvas 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -23
- package/docs/reference.md +154 -44
- package/package.json +9 -4
- package/pr-review.config.example.yml +6 -0
- package/prompts/chat-seed.md +3 -0
- package/prompts/generation-format.md +3 -0
- package/skills/pr-review-canvas/SKILL.md +69 -39
- package/src/canvas/comment.ts +24 -0
- package/src/canvas/import.ts +30 -9
- package/src/canvas/name.ts +1 -0
- package/src/canvas/zip.ts +21 -1
- package/src/chat/chat-manager.ts +40 -39
- package/src/chat/threads.ts +27 -26
- package/src/cli.ts +12 -7
- package/src/commands.ts +45 -16
- package/src/config.ts +14 -26
- package/src/contract/api.ts +32 -1
- package/src/contract/canvas-manifest.ts +2 -0
- package/src/contract/comments.ts +5 -0
- package/src/contract/discovery.ts +5 -2
- package/src/contract/generation-context.ts +24 -1
- package/src/contract/review-key.ts +51 -0
- package/src/contract/reviews.ts +17 -0
- package/src/contract/settings.ts +2 -0
- package/src/contract/state.ts +41 -21
- package/src/git/environment.mjs +27 -0
- package/src/git/git.ts +109 -9
- package/src/git/local-target.ts +138 -0
- package/src/git/patch-lines.ts +34 -2
- package/src/git/pr-refs.ts +36 -0
- package/src/github/attachments.ts +9 -257
- package/src/github/canvas-comment.ts +22 -0
- package/src/github/capabilities.ts +3 -41
- package/src/github/comments.ts +3 -24
- package/src/github/post-comment.ts +3 -36
- package/src/github/post-review.ts +4 -19
- package/src/github/pr.ts +6 -87
- package/src/github/threads.ts +2 -2
- package/src/gitlab/attachments.ts +40 -0
- package/src/gitlab/canvas-comment.ts +26 -0
- package/src/gitlab/capabilities.ts +64 -0
- package/src/gitlab/comments.ts +164 -0
- package/src/gitlab/mr.ts +115 -0
- package/src/gitlab/post-comment.ts +111 -0
- package/src/gitlab/post-review.ts +54 -0
- package/src/gitlab/project.ts +13 -0
- package/src/host/attachments.ts +293 -0
- package/src/host/capabilities.ts +38 -0
- package/src/host/client.ts +245 -0
- package/src/host/host.ts +136 -0
- package/src/host/pr.ts +51 -0
- package/src/host/remote.ts +42 -0
- package/src/project-config.ts +13 -0
- package/src/review/carry-over.ts +79 -0
- package/src/review/doctor.ts +22 -12
- package/src/review/prepare.ts +64 -10
- package/src/review/publish.ts +61 -10
- package/src/{github → review}/review-body.ts +17 -5
- package/src/review/skill-command.ts +5 -3
- package/src/review/validate-folds.ts +2 -2
- package/src/review/validate.ts +4 -4
- package/src/server/bundle.ts +312 -111
- package/src/server/context.ts +10 -8
- package/src/server/errors.ts +30 -8
- package/src/server/html.ts +34 -10
- package/src/server/routes/api.ts +63 -26
- package/src/server/routes/chat-routes.ts +76 -38
- package/src/server/routes/pages.ts +22 -8
- package/src/server/routes/review-routes.ts +84 -33
- package/src/store/canvas-store.ts +90 -55
- package/src/store/data-dir.ts +2 -1
- package/src/store/derived-store.ts +41 -27
- package/src/store/pr-store.ts +23 -14
- package/src/store/state-store.ts +40 -36
- package/static/js/api.js +32 -24
- package/static/js/app.js +24 -10
- package/static/js/chat.js +3 -2
- package/static/js/composer.js +24 -14
- package/static/js/contract-types.d.ts +3 -0
- package/static/js/diff-renderer.js +1 -1
- package/static/js/download.js +1 -1
- package/static/js/empty-state.js +85 -18
- package/static/js/errors.js +22 -6
- package/static/js/header.js +31 -8
- package/static/js/host.js +40 -0
- package/static/js/import-zone.js +1 -1
- package/static/js/interactions.js +1 -2
- package/static/js/layers.js +3 -3
- package/static/js/links.js +3 -3
- package/static/js/markdown.js +28 -1
- package/static/js/points.js +2 -1
- package/static/js/review-session.js +7 -2
- package/static/js/settings.js +2 -1
- package/static/js/signoff.js +6 -7
- package/static/styles/commands.css +6 -0
- package/static/styles/panels.css +4 -0
- package/static/styles/review-actions.css +1 -0
- package/static/styles/skin-github.css +7 -1
- package/src/github/gh.ts +0 -211
package/README.md
CHANGED
|
@@ -1,25 +1,42 @@
|
|
|
1
1
|
# PR Review Canvas
|
|
2
2
|
|
|
3
|
-
Review a GitHub pull request canvas: layers by topic, with grouped diffs,
|
|
4
|
-
and an optional AI chat. Everything runs locally at **http://localhost:3010**.
|
|
3
|
+
Review a GitHub pull request or GitLab merge request canvas: layers by topic, with grouped diffs,
|
|
4
|
+
attention points, comments, and an optional AI chat. Everything runs locally at **http://localhost:3010**.
|
|
5
5
|
|
|
6
6
|
## Quick start: author generates, reviewers review
|
|
7
7
|
|
|
8
8
|
### Author side
|
|
9
9
|
|
|
10
|
-
Each PR author
|
|
11
|
-
|
|
10
|
+
Each PR author generates a canvas before requesting review. The skill shares it automatically
|
|
11
|
+
in a comment on the GitHub PR or GitLab MR. After the project setup below, run the installed skill in Claude Code or Codex:
|
|
12
12
|
|
|
13
13
|
```text
|
|
14
14
|
/pr-review-canvas 123
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Replace **123** with your PR number. The skill reads the PR, generates and validates the canvas,
|
|
18
|
-
|
|
17
|
+
Replace **123** with your PR number. The skill reads the PR, generates and validates the canvas, then publishes a compressed canvas
|
|
18
|
+
comment using your `gh` or `glab` login. It returns a local review URL and the comment link.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
If automatic sharing fails (including a canvas too large for one comment), the skill warns you
|
|
21
|
+
and gives you a ZIP path. Drag that ZIP into the PR or MR description, wait for the upload, and
|
|
22
|
+
save. This manual upload is only a fallback.
|
|
23
|
+
|
|
24
|
+
### Before you open the pull request
|
|
25
|
+
|
|
26
|
+
To read your own change the way a reviewer will, generate a canvas for the work in your clone:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
/pr-review-canvas branch # the current branch against the default branch
|
|
30
|
+
/pr-review-canvas uncommitted # the same, with your working-tree edits and new files on top
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Start `pr-review serve` and open **http://localhost:3010/review/branch** or
|
|
34
|
+
**/review/uncommitted**. The two are separate reviews, so generating one leaves the other alone.
|
|
35
|
+
|
|
36
|
+
Nothing is posted anywhere: local work has no pull request, so the comment and sign-off commands
|
|
37
|
+
stay off. Add `--base <ref>` to compare against another branch. Committing after `branch`, or
|
|
38
|
+
editing a file after `uncommitted`, moves the head: the next time you open the page or press
|
|
39
|
+
refresh, the canvas is marked outdated and the page offers to generate it again.
|
|
23
40
|
|
|
24
41
|
### Review side
|
|
25
42
|
|
|
@@ -29,13 +46,16 @@ Start the canvas server from the project you want to review:
|
|
|
29
46
|
pr-review serve
|
|
30
47
|
```
|
|
31
48
|
|
|
32
|
-
Open **http://localhost:3010**, enter a PR number
|
|
33
|
-
review. Stop the server with **Ctrl+C**. To use another port, run `pr-review serve --port 3011`.
|
|
49
|
+
Open **http://localhost:3010**, enter a PR number (or follow a link to a local review), and
|
|
50
|
+
leave the terminal running while you review. Stop the server with **Ctrl+C**. To use another port, run `pr-review serve --port 3011`.
|
|
34
51
|
|
|
35
52
|
## Install
|
|
36
53
|
|
|
37
|
-
You need Node.js 22+, npm, Git, and
|
|
38
|
-
|
|
54
|
+
You need Node.js 22+, npm, Git, and the CLI for your host:
|
|
55
|
+
|
|
56
|
+
- GitHub: [GitHub CLI](https://cli.github.com). Sign in with `gh auth login`.
|
|
57
|
+
- GitLab: [GitLab CLI (glab)](https://gitlab.com/gitlab-org/cli). Sign in with `glab auth login`.
|
|
58
|
+
Self-hosted GitLab whose hostname does not contain `gitlab` needs `PR_REVIEW_HOST=gitlab`.
|
|
39
59
|
|
|
40
60
|
Install the command globally once, for use in any project:
|
|
41
61
|
|
|
@@ -57,10 +77,11 @@ Re-run `pr-review install-skill` after upgrading the CLI to refresh them. It als
|
|
|
57
77
|
project's `.gitignore`. Restart your coding agent if the skill
|
|
58
78
|
does not appear. Repeat this setup for each project you want to review.
|
|
59
79
|
|
|
60
|
-
`doctor` checks Git, your GitHub remote, the
|
|
61
|
-
canvas directory, and whether installed skills match the current package.
|
|
62
|
-
each check and suggested fixes for failures.
|
|
63
|
-
reports its version. Exit code `0` means all
|
|
80
|
+
`doctor` checks Git, your GitHub or GitLab remote, the matching CLI (`gh` or `glab`) and its login,
|
|
81
|
+
write access to the local canvas directory, and whether installed skills match the current package.
|
|
82
|
+
It prints a JSON report with a result for each check and suggested fixes for failures.
|
|
83
|
+
`doctor --all-checks` also checks that `acpx` runs and reports its version. Exit code `0` means all
|
|
84
|
+
checks passed.
|
|
64
85
|
|
|
65
86
|
`serve` automatically runs the skill check and warns on stderr if a skill is missing, outdated,
|
|
66
87
|
or modified. The warning includes the reinstall command and does not block startup.
|
|
@@ -89,22 +110,26 @@ See the [CLI and configuration reference](docs/reference.md) for detailed option
|
|
|
89
110
|
pr-review export --pr 123
|
|
90
111
|
```
|
|
91
112
|
|
|
92
|
-
The command prints the zip's absolute path.
|
|
93
|
-
|
|
113
|
+
The command prints the zip's absolute path. `export` saves locally; `publish` also shares PR/MR
|
|
114
|
+
canvases automatically as compressed comments.
|
|
94
115
|
|
|
95
116
|
The zip contains `manifest.json` and `review.json`: the PR description, file/hunk metadata,
|
|
96
|
-
and generated review notes.
|
|
97
|
-
information. Each reviewer gets source diffs from their own clone; chat history stays local.
|
|
117
|
+
and generated review notes. Publishing shares this information with everyone who can read the PR/MR. Each reviewer gets source diffs from their own clone; chat history stays local.
|
|
98
118
|
|
|
99
119
|
### Update an outdated canvas
|
|
100
120
|
|
|
101
121
|
After pushing new commits, run `/pr-review-canvas 123` again. To rewrite a canvas for the
|
|
102
|
-
same commit, run `/pr-review-canvas 123 --force`.
|
|
122
|
+
same commit, run `/pr-review-canvas 123 --force`. Publishing updates your canvas comment automatically.
|
|
103
123
|
Reviewers click **refresh**.
|
|
104
124
|
|
|
105
125
|
When the saved canvas describes a different PR head, **Canvas is outdated** appears at
|
|
106
126
|
the top. You can still read the older canvas, with its commit and distance shown; posting
|
|
107
|
-
from that view is disabled. Click **refresh** to check GitHub for changes and a newer
|
|
127
|
+
from that view is disabled. Click **refresh** to check GitHub or GitLab for changes and a newer canvas.
|
|
128
|
+
|
|
129
|
+
A head whose diff is identical to the canvas's does not outdate it: after **Update branch**
|
|
130
|
+
merged `main` in without touching the changed files, for example, the canvas still applies
|
|
131
|
+
and the page says so. Set `canvas.keepForIdenticalDiff: false` in the project config to treat
|
|
132
|
+
every commit as a new head.
|
|
108
133
|
|
|
109
134
|
## Configuration
|
|
110
135
|
|
|
@@ -161,6 +186,10 @@ Restart the server after changing the config; chat template edits apply to new t
|
|
|
161
186
|
See the [prompt template reference](docs/reference.md#prompt-templates) for supported keys,
|
|
162
187
|
path rules, validation, and upgrades.
|
|
163
188
|
|
|
189
|
+
## Website
|
|
190
|
+
|
|
191
|
+
The [project website](https://vintasoftware.github.io/pr-review-canvas/) introduces the review workflow with a real PR walkthrough. See [website development and publishing](docs/website.md) for local preview commands and the GitHub Pages deployment workflow.
|
|
192
|
+
|
|
164
193
|
## Contributing
|
|
165
194
|
|
|
166
195
|
In a clone of this tool, use pnpm for the shared lockfile and development checks:
|
package/docs/reference.md
CHANGED
|
@@ -23,9 +23,12 @@ For setup and the basic review workflow, see the [README](../README.md).
|
|
|
23
23
|
| `--agent claude\|codex` | `serve` | Overrides the saved chat agent for this run |
|
|
24
24
|
| `--model <id>` | `serve` | Overrides the saved chat model for this run |
|
|
25
25
|
| `--fixture-canvas <review.json>` | `serve` | Development preview: uses the supplied canvas for every requested PR, with its head replaced by the live PR head |
|
|
26
|
+
| `PR_REVIEW_HOST=gitlab` | Environment | Treats a non-github.com origin as GitLab (self-hosted hosts whose name does not contain `gitlab`) |
|
|
26
27
|
|
|
27
|
-
Repository operations require an `origin` remote on **github.com
|
|
28
|
-
|
|
28
|
+
Repository operations require an `origin` remote on **github.com** or **GitLab** (gitlab.com, a
|
|
29
|
+
hostname that contains `gitlab`, or any host with `PR_REVIEW_HOST=gitlab`). GitHub Enterprise Server
|
|
30
|
+
hosts are not supported. Fetching a PR or merge request does not check out its branch. Use `--pr`
|
|
31
|
+
for both GitHub pull request numbers and GitLab merge request IIDs.
|
|
29
32
|
|
|
30
33
|
### Prepare, validate, and publish
|
|
31
34
|
|
|
@@ -33,7 +36,7 @@ These commands support custom generation workflows. The bundled
|
|
|
33
36
|
[generation skill](../skills/pr-review-canvas/SKILL.md) describes the complete sequence and model rules.
|
|
34
37
|
|
|
35
38
|
```text
|
|
36
|
-
pr-review prepare (--pr <n> | --base <ref> --head <ref>) [--force]
|
|
39
|
+
pr-review prepare (--pr <n> | --branch | --uncommitted | --base <ref> --head <ref>) [--base <ref>] [--force]
|
|
37
40
|
pr-review validate <model.json|review.json> --canvas <dir> [--human] [--fix]
|
|
38
41
|
pr-review publish <canvasDir> --agent <id> [--model <id>] --harness claude-code|codex|other [--allow-stale]
|
|
39
42
|
```
|
|
@@ -43,7 +46,45 @@ A status of `exists` means that head already has a canvas. With `--force`, prepa
|
|
|
43
46
|
previous generation's working files while keeping the published canvas available until a new
|
|
44
47
|
publish succeeds.
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
### Reviewing before the pull request exists
|
|
50
|
+
|
|
51
|
+
There are two reviews of the work in a clone, and they are separate targets:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pr-review prepare --branch # served at /review/branch
|
|
55
|
+
pr-review prepare --uncommitted # served at /review/uncommitted
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`--branch` describes the tip of the current branch. `--uncommitted` describes the working tree as
|
|
59
|
+
it stands, with the edits and the untracked files on top of that tip; with a clean tree the two
|
|
60
|
+
build the same canvas. Each keeps its own canvas, review progress and chat threads, so preparing
|
|
61
|
+
one never disturbs the other.
|
|
62
|
+
|
|
63
|
+
- **Base.** Both compare against the repository's default branch, resolved from `origin/HEAD` and
|
|
64
|
+
falling back to `origin/main`, `origin/master`, `main`, then `master`. `--base <ref>` overrides
|
|
65
|
+
it. Preparation fails with a hint when none of them resolve.
|
|
66
|
+
- **Uncommitted work.** `--uncommitted` stages the working tree into an index of its own and
|
|
67
|
+
writes a commit from it, so the diff covers files that are not committed yet. Nothing the user
|
|
68
|
+
staged is touched, ignored files stay out, and the commit is anchored at
|
|
69
|
+
`refs/worktree/pr-review-snapshot` so `git gc` cannot collect it before `publish`. Publishing
|
|
70
|
+
gives that canvas an anchor of its own under `refs/worktree/pr-review-canvas/`, so a later
|
|
71
|
+
snapshot cannot leave it collectable. The same working tree always hashes to the same commit.
|
|
72
|
+
- **Staleness.** Committing after `--branch`, or editing a file after `--uncommitted`, moves the
|
|
73
|
+
head, so `publish` answers `CANVAS_STALE`, exactly as a push does for a pull request. The page
|
|
74
|
+
reads the head again when it is opened and when `refresh` is pressed, and offers to regenerate.
|
|
75
|
+
Its background polls answer about that same head, so they never contradict what the page shows;
|
|
76
|
+
they read the work again only once a new canvas has been prepared.
|
|
77
|
+
- **Worktrees.** The snapshot index and its anchor are per worktree, so two worktrees of one clone
|
|
78
|
+
never overwrite each other's snapshot. The review targets are not: `branch` and `uncommitted`
|
|
79
|
+
name one review per clone, so worktrees share their canvas, review progress and chat threads.
|
|
80
|
+
Review local work from one worktree at a time.
|
|
81
|
+
- **No forge side.** A local canvas posts nothing: comments, sign-off, canvas import, and
|
|
82
|
+
attachment discovery are refused for it. The page draws no import drop zone and no shared-canvas
|
|
83
|
+
callout, and the comment and sign-off commands stay disabled with the reason. A canvas of a working-tree
|
|
84
|
+
snapshot is never offered as a pull request's canvas, or as the branch review's, because its
|
|
85
|
+
commit is on no branch.
|
|
86
|
+
|
|
87
|
+
For a comparison between two commits that both exist, name them instead:
|
|
47
88
|
|
|
48
89
|
```bash
|
|
49
90
|
pr-review prepare --base origin/main --head HEAD
|
|
@@ -54,7 +95,8 @@ pr-review prepare --base origin/main --head HEAD
|
|
|
54
95
|
the explanation after the first `:` or `—` and reports the changes. Titles that still exceed the
|
|
55
96
|
limit and overlong prose require rewriting.
|
|
56
97
|
|
|
57
|
-
`publish` returns `status`, `headSha`, `reviewJsonPath`, `attempts`, and a `reviewUrl`
|
|
98
|
+
`publish` returns `status`, `headSha`, `reviewJsonPath`, `attempts`, `sharing`, and a `reviewUrl`
|
|
99
|
+
for PR and local runs.
|
|
58
100
|
Its `--agent`, `--model`, and `--harness` describe who generated the canvas; they do not launch or
|
|
59
101
|
select an agent. `--allow-stale` permits publishing for the prepared commit after the PR head has
|
|
60
102
|
moved. Use it only when that older commit is the intended review target.
|
|
@@ -63,6 +105,35 @@ For more than 400 changed files or 50,000 added/deleted lines, preparation leave
|
|
|
63
105
|
prompt and directs the generator to read patch files individually. Smaller diffs are inlined up
|
|
64
106
|
to `generation.inlineDiffMaxLines`.
|
|
65
107
|
|
|
108
|
+
### Automatic sharing and ZIP fallback
|
|
109
|
+
|
|
110
|
+
For PR/MR targets, `publish` saves the validated canvas locally, then posts its compressed ZIP
|
|
111
|
+
as base64 inside a hidden HTML comment on GitHub or GitLab. The visible comment identifies the
|
|
112
|
+
commit and explains how to open the canvas. Publishing again updates the existing canvas comment
|
|
113
|
+
owned by the current CLI account; another author's comment is left alone. The payload contains
|
|
114
|
+
the same `manifest.json` and `review.json` as an export, including the PR/MR description and review
|
|
115
|
+
notes. Hidden markup is not private: anyone who can read the comment can retrieve the payload.
|
|
116
|
+
No generated files enter Git history and no storage service or CI workflow is required.
|
|
117
|
+
|
|
118
|
+
Check the `sharing` result even when the process exits successfully:
|
|
119
|
+
|
|
120
|
+
- `{ "status": "shared", "url": "..." }`: the host accepted the comment.
|
|
121
|
+
- `{ "status": "failed", "warning": "...", "zipPath": "..." }`: the canvas is saved locally,
|
|
122
|
+
but automatic sharing failed. The CLI also prints a warning to stderr and exports a fallback ZIP.
|
|
123
|
+
Upload that ZIP into the PR/MR description in the browser and save; replace an older attachment
|
|
124
|
+
link if present. A host failure can have an uncertain outcome, so check the comment before retrying.
|
|
125
|
+
- `{ "status": "local" }`: a refs-only target has no PR/MR to publish to.
|
|
126
|
+
|
|
127
|
+
The entire comment must fit the host limit: 65,536 characters on GitHub and 1,000,000 on GitLab.
|
|
128
|
+
Base64 uses roughly four characters per three compressed bytes, leaving slightly under 48 KiB
|
|
129
|
+
for a GitHub ZIP after the envelope and visible text. Oversize canvases are never split or truncated.
|
|
130
|
+
Permission, login, network, and host-policy errors use the same ZIP fallback. A sharing failure
|
|
131
|
+
keeps exit code 0 because local publication succeeded; validation errors still exit 5.
|
|
132
|
+
The generation skill must report the warning and manual-upload instructions on sharing failure.
|
|
133
|
+
|
|
134
|
+
`export` remains a local-only command for backups and manual sharing. For refs-only canvases,
|
|
135
|
+
export with `--head <sha> --pr <n>` once the PR exists, or regenerate for the PR to share automatically.
|
|
136
|
+
|
|
66
137
|
### Export and import options
|
|
67
138
|
|
|
68
139
|
```text
|
|
@@ -79,16 +150,21 @@ pr-review import <zip> [--pr <n>] [--force]
|
|
|
79
150
|
canvas generation time in UTC, to seconds, so exports sort chronologically within each PR.
|
|
80
151
|
Before a PR exists, `ref-` replaces `pr-<number>-`. Re-exporting the same canvas keeps its name.
|
|
81
152
|
- Export returns `status`, `path`, `name`, `headSha`, and `prNumber` when supplied or stored.
|
|
82
|
-
- `import --pr` compares the imported canvas with that PR's current head
|
|
83
|
-
|
|
153
|
+
- `import --pr` compares the imported canvas with that PR's current head, and refuses a canvas
|
|
154
|
+
exported for a different pull request with `CANVAS_PR_MISMATCH`. `--force` does not lift that
|
|
155
|
+
refusal: a canvas is stored under the pull request it names, so importing the same ZIP without
|
|
156
|
+
`--pr` stores it under its own PR instead. Without `--pr`, import does not check against a live
|
|
157
|
+
PR. A canvas generated before the PR existed names none and joins the pull request it is
|
|
158
|
+
imported for.
|
|
84
159
|
- Import returns `ready`, `stale`, or `exists`, plus commit information and warnings. `exists`
|
|
85
160
|
keeps a stored canvas generated at the same time or later. `derivable: false` means the canvas
|
|
86
161
|
was accepted but its source diffs could not be rebuilt from Git.
|
|
87
162
|
- `import --force` allows a canvas from another repository. It does not force an older canvas to
|
|
88
|
-
replace a newer one.
|
|
163
|
+
replace a newer one, and does not allow a canvas of another pull request.
|
|
89
164
|
|
|
90
165
|
Imports accept archives up to **20 MiB**. The required `manifest.json` and `review.json` entries
|
|
91
|
-
must be at the archive root
|
|
166
|
+
must be at the archive root, pass format validation, and agree on the commit and the pull request
|
|
167
|
+
they describe. If the necessary commits are missing,
|
|
92
168
|
the tool attempts to fetch them; a failed fetch can leave the notes available without diffs.
|
|
93
169
|
|
|
94
170
|
### Skill installation options
|
|
@@ -134,7 +210,7 @@ Validation failures from `validate` use its report format instead.
|
|
|
134
210
|
| `0` | Success |
|
|
135
211
|
| `1` | Error, including a failed `doctor` check |
|
|
136
212
|
| `2` | Command usage error, such as an unknown command or missing required flag |
|
|
137
|
-
| `4` | GitHub CLI missing or unauthenticated
|
|
213
|
+
| `4` | GitHub CLI (`gh`) or GitLab CLI (`glab`) missing or unauthenticated |
|
|
138
214
|
| `5` | Validation failed in `validate` or `publish` |
|
|
139
215
|
|
|
140
216
|
`doctor` reports failed checks with exit `1`, including authentication failures.
|
|
@@ -161,6 +237,7 @@ within one path segment.
|
|
|
161
237
|
| `generation.caps` | See below | Overrides individual text limits |
|
|
162
238
|
| `tests.patterns` | `['**/*.test.*', '**/*.spec.*', '**/__tests__/**']` | Paths treated as tests for review ordering and labels |
|
|
163
239
|
| `chat.enabled` | `true` | Set to `false` to disable AI Chat |
|
|
240
|
+
| `canvas.keepForIdenticalDiff` | `true` | Keep the canvas current for a later head whose diff is identical to the canvas's; see [outdated canvases](#outdated-canvases). Set to `false` to mark it outdated on every commit |
|
|
164
241
|
| `prompts` | Bundled templates | See [prompt templates](#prompt-templates) for supported keys and behavior |
|
|
165
242
|
|
|
166
243
|
Generation's numeric options and text caps must be positive integers. An empty `layers` list
|
|
@@ -264,8 +341,8 @@ By default, Git worktrees of the same clone share the main checkout's data direc
|
|
|
264
341
|
clones have separate data. An explicit data-directory override also relocates `settings.yml`,
|
|
265
342
|
canvases, review progress, and chat history.
|
|
266
343
|
|
|
267
|
-
The data directory contains exported archives, saved canvases, generation inputs, cached GitHub
|
|
268
|
-
data, source diffs, and personal review progress. Its own `.gitignore` excludes its contents.
|
|
344
|
+
The data directory contains exported archives, saved canvases, generation inputs, cached GitHub or
|
|
345
|
+
GitLab data, source diffs, and personal review progress. Its own `.gitignore` excludes its contents.
|
|
269
346
|
Deleting the directory loses saved preferences, canvases, progress, and chat history.
|
|
270
347
|
|
|
271
348
|
## Review controls
|
|
@@ -298,32 +375,61 @@ it automatically.
|
|
|
298
375
|
|
|
299
376
|
### Finding shared canvases
|
|
300
377
|
|
|
301
|
-
Discovery checks the PR description and comments for
|
|
378
|
+
Discovery reads compressed canvas comments and checks the PR description and comments for legacy
|
|
379
|
+
canvas ZIP links. Both use the same ZIP validation and import path. It prefers a filename
|
|
302
380
|
matching the current head, then the PR number, then the most recently edited source text.
|
|
303
|
-
If a
|
|
304
|
-
canvas can be recognized.
|
|
381
|
+
If a candidate fails, it tries other matching canvases. Keep the exported filename so the
|
|
382
|
+
canvas can be recognized. **Refresh** also checks for regenerated canvases at the same head commit.
|
|
383
|
+
|
|
384
|
+
An attachment exported for a different pull request is reported rather than imported, and is not
|
|
385
|
+
downloaded at all when its filename already names the other PR. The page says so and offers the
|
|
386
|
+
drop zone, which applies the same check: a ZIP whose name or manifest belongs to another PR is
|
|
387
|
+
refused.
|
|
305
388
|
|
|
306
|
-
When automatic download fails, download the archive in GitHub
|
|
307
|
-
or `pr-review import <zip> --pr <n>`.
|
|
389
|
+
When automatic download fails, download the archive in GitHub or GitLab and use the page's drop
|
|
390
|
+
zone or `pr-review import <zip> --pr <n>`.
|
|
308
391
|
|
|
309
392
|
### Comments and sign-off
|
|
310
393
|
|
|
311
394
|
You can post inline comments, replies, PR-level comments, and attention points. Inline comments
|
|
312
|
-
must target lines in the diff. Posting uses your
|
|
313
|
-
repository permissions.
|
|
395
|
+
must target lines in the diff. Posting uses your `gh` or `glab` account and remains subject to its
|
|
396
|
+
repository permissions. On GitLab, **request changes** posts the review body as a merge request
|
|
397
|
+
note; **approve** calls GitLab's approve API.
|
|
314
398
|
|
|
315
399
|
The sign-off dialog previews an editable review body summarizing reviewed layers, dismissed
|
|
316
400
|
attention points, and comments posted from the canvas. Approval requires every layer except
|
|
317
401
|
**Other changes** to be reviewed for the current head. Requesting changes does not require that
|
|
318
402
|
completion. If the head moves before submission, reload and review the current commit.
|
|
319
403
|
|
|
404
|
+
### Outdated canvases
|
|
405
|
+
|
|
406
|
+
A canvas describes one head commit. When the pull request moves to another commit, the page
|
|
407
|
+
shows **Canvas is outdated**, offers the older canvas read-only, and disables posting from it.
|
|
408
|
+
|
|
409
|
+
An identical diff is the exception. When the head's diff against its merge base is the same as
|
|
410
|
+
the canvas commit's diff against its own, file by file and byte for byte, the canvas is carried
|
|
411
|
+
over: the page shows it under a **Canvas still applies** note, review progress carries over, and
|
|
412
|
+
sign-off, comments, and AI Chat keep working. The note says how many commits later the head is,
|
|
413
|
+
when the head was built on the canvas's commit. Merging the base branch in (**Update branch**) keeps
|
|
414
|
+
the diff identical as long as the base did not touch the changed files. The rule does not care how
|
|
415
|
+
the head reached that diff, only that it did; a diff that differs anywhere, even a hunk moved down
|
|
416
|
+
by a base change, marks the canvas outdated as before, because the canvas's layers, hunk ids, and
|
|
417
|
+
attention points describe the diff it was generated from. It needs `canvas.keepForIdenticalDiff`
|
|
418
|
+
(the default) and both commits in the local clone: the canvas's own commit has to be there for its
|
|
419
|
+
diff to be rebuilt, and without that diff there is nothing to compare, so the canvas reads outdated.
|
|
420
|
+
Two empty change sets are not compared either. `pr-review publish` and `pr-review import` apply the
|
|
421
|
+
same rule, so the CLI never calls a canvas stale that the page shows as current.
|
|
422
|
+
|
|
423
|
+
AI Chat also answers on an outdated canvas: it quotes the diff of the canvas's own commit, the
|
|
424
|
+
one on screen.
|
|
425
|
+
|
|
320
426
|
## AI Chat
|
|
321
427
|
|
|
322
428
|
**Ask** on a layer, file, attention point, or line selection chooses the context for your message.
|
|
323
429
|
Choosing another target replaces it; **clear** returns to the whole PR. The `a` key asks about
|
|
324
430
|
the focused target, and `/` focuses the message box.
|
|
325
431
|
|
|
326
|
-
Chat can propose an inline
|
|
432
|
+
Chat can propose an inline comment. A valid proposal appears with controls to post, edit,
|
|
327
433
|
or copy it. A proposal outside the current diff remains text with an explanation.
|
|
328
434
|
|
|
329
435
|
Use **stop** to interrupt a reply. Only one chat turn can run per PR at a time. A timeout or
|
|
@@ -332,9 +438,10 @@ incomplete answer can be retried; increase `chatTimeoutSec` if replies need more
|
|
|
332
438
|
## Network access and permissions
|
|
333
439
|
|
|
334
440
|
The server binds to `127.0.0.1` and rejects browser writes from other origins. It is intended for
|
|
335
|
-
local use with your GitHub login.
|
|
441
|
+
local use with your GitHub or GitLab login.
|
|
336
442
|
|
|
337
|
-
|
|
443
|
+
Publishing sends the canvas as a PR/MR comment. Host requests also fetch PR or MR data and
|
|
444
|
+
attachments and submit the comments or reviews you choose to
|
|
338
445
|
post. Rendered Markdown can load images from HTTPS hosts. Generation and chat send review
|
|
339
446
|
context to the selected coding agent and its configured provider.
|
|
340
447
|
|
|
@@ -344,28 +451,31 @@ sandbox for the agent. Its access also depends on the agent's own permissions. D
|
|
|
344
451
|
|
|
345
452
|
## Troubleshooting
|
|
346
453
|
|
|
347
|
-
| Symptom or code
|
|
348
|
-
|
|
|
349
|
-
| `NOT_A_REPO`
|
|
350
|
-
| `NO_ORIGIN`
|
|
351
|
-
| `GH_MISSING` / `GH_UNAUTHENTICATED`
|
|
352
|
-
| `GITHUB_API_ERROR`
|
|
353
|
-
| `
|
|
354
|
-
| `
|
|
355
|
-
| `
|
|
356
|
-
| `
|
|
357
|
-
| `
|
|
358
|
-
| `
|
|
359
|
-
| `
|
|
360
|
-
| `
|
|
361
|
-
| `
|
|
362
|
-
| `
|
|
363
|
-
| `
|
|
364
|
-
| `
|
|
365
|
-
| `
|
|
366
|
-
| `
|
|
367
|
-
| `
|
|
368
|
-
| `
|
|
454
|
+
| Symptom or code | Next step |
|
|
455
|
+
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
456
|
+
| `NOT_A_REPO` | Run inside a Git clone or pass `--repo <dir>` |
|
|
457
|
+
| `NO_ORIGIN` | Check that `origin` points to github.com or GitLab; for self-hosted GitLab set `PR_REVIEW_HOST=gitlab` |
|
|
458
|
+
| `GH_MISSING` / `GH_UNAUTHENTICATED` | Install [GitHub CLI](https://cli.github.com), run `gh auth login`, and check authentication in the same environment that runs the server |
|
|
459
|
+
| `GITHUB_API_ERROR` | Read the underlying error for permissions, rate limits, connectivity, or GitHub service problems |
|
|
460
|
+
| `GLAB_MISSING` / `GLAB_UNAUTHENTICATED` | Install [GitLab CLI](https://gitlab.com/gitlab-org/cli), run `glab auth login`, and check authentication in the same environment that runs the server |
|
|
461
|
+
| `GITLAB_API_ERROR` | Read the underlying error for permissions, rate limits, connectivity, or GitLab service problems |
|
|
462
|
+
| `PR_NOT_FOUND` | Check the PR number, repository, and your access |
|
|
463
|
+
| `CANVAS_NOT_FOUND` | Generate or import a canvas for the requested commit |
|
|
464
|
+
| `CANVAS_INVALID` | Read the format errors; re-export or regenerate the canvas |
|
|
465
|
+
| `CANVAS_REPO_MISMATCH` | Check which clone is open; use `import --force` only when importing from the other repository is intentional |
|
|
466
|
+
| `CANVAS_PR_MISMATCH` | The ZIP was exported for another pull request; import the canvas of this PR, or import that ZIP without `--pr` to store it under its own |
|
|
467
|
+
| `CANVAS_TOO_LARGE` | The archive exceeds the 20 MiB import limit |
|
|
468
|
+
| `CANVAS_STALE` | The PR head moved; prepare again for the current commit |
|
|
469
|
+
| `MODEL_INVALID` | Fix the reported problems in `model.json`, validate, then publish again |
|
|
470
|
+
| `SKILL_DIR_EXISTS` | The destination contains a customized directory; preserve it elsewhere before replacing it with `--force` |
|
|
471
|
+
| `CHAT_BUSY` | Wait for the running reply or press **stop** |
|
|
472
|
+
| `AGENT_AUTH_REQUIRED` | Sign in through the selected agent's CLI, then retry |
|
|
473
|
+
| `AGENT_MISSING` or missing chat pane | Check `chat.enabled` and confirm the server can find `acpx` and the selected agent; run `pr-review doctor --all-checks` |
|
|
474
|
+
| `AGENT_INCOMPLETE` | Retry the message or increase the chat timeout |
|
|
475
|
+
| `COMMENT_FORBIDDEN` | Check the GitHub or GitLab account's repository access and token permissions |
|
|
476
|
+
| `COMMENT_LINE_NOT_IN_DIFF` | Choose a line shown in the current diff |
|
|
477
|
+
| `SIGNOFF_INCOMPLETE` | Mark every layer except Other reviewed for this head |
|
|
478
|
+
| `FORBIDDEN_HOST` / `CROSS_ORIGIN` | Open the local server using `localhost` or `127.0.0.1` and submit actions from that page |
|
|
369
479
|
|
|
370
480
|
### Validation diagnostics
|
|
371
481
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vintasoftware/pr-review-canvas",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Localhost PR review canvas: layered diffs, attention points, and GitHub comments for one PR",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Localhost PR review canvas: layered diffs, attention points, and GitHub or GitLab comments for one PR",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"pr-review": "./bin/pr-review.mjs"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"dev": "tsx watch --clear-screen=false --ignore '**/.pr-review/**' src/cli.ts serve",
|
|
11
11
|
"start": "tsx src/cli.ts serve",
|
|
12
12
|
"test": "vitest run",
|
|
13
|
-
"hooks:install": "git config core.hooksPath
|
|
13
|
+
"hooks:install": "git config core.hooksPath \"$(git rev-parse --show-toplevel)/.githooks\"",
|
|
14
14
|
"test:watch": "vitest",
|
|
15
15
|
"test:browser": "playwright test",
|
|
16
16
|
"coverage": "vitest run --coverage",
|
|
@@ -23,7 +23,12 @@
|
|
|
23
23
|
"format": "oxfmt --write",
|
|
24
24
|
"format:check": "oxfmt --check",
|
|
25
25
|
"check": "pnpm lint && pnpm format:check && pnpm typecheck",
|
|
26
|
-
"precommit": "pnpm check && pnpm test"
|
|
26
|
+
"precommit": "pnpm check && pnpm test",
|
|
27
|
+
"site:dev": "vite --config site/vite.config.js",
|
|
28
|
+
"site:image": "node scripts/render-social-preview.mjs",
|
|
29
|
+
"site:build": "vite build --config site/vite.config.js",
|
|
30
|
+
"site:preview": "vite preview --config site/vite.config.js",
|
|
31
|
+
"site:test": "playwright test --config site/playwright.config.js"
|
|
27
32
|
},
|
|
28
33
|
"dependencies": {
|
|
29
34
|
"@highlightjs/cdn-assets": "^11.12.0",
|
|
@@ -47,3 +47,9 @@ tests:
|
|
|
47
47
|
|
|
48
48
|
chat:
|
|
49
49
|
enabled: true # false removes the chat pane and its routes
|
|
50
|
+
|
|
51
|
+
canvas:
|
|
52
|
+
# A canvas stays current for a later head whose diff is identical to the one it was generated
|
|
53
|
+
# from, as after merging the base branch in. Set false to mark the canvas outdated on every new
|
|
54
|
+
# commit.
|
|
55
|
+
keepForIdenticalDiff: true
|
package/prompts/chat-seed.md
CHANGED
|
@@ -11,6 +11,9 @@ At most six sentences. No headings unless the reader asks for more. Markdown is
|
|
|
11
11
|
short lists, `path:line` references. Do not restate the question. Do not summarize the whole PR
|
|
12
12
|
when the reader asked about one file.
|
|
13
13
|
|
|
14
|
+
Call diff sections **chunks** in answers and proposed comments. Keep code identifiers and
|
|
15
|
+
`#hunk:` link targets unchanged.
|
|
16
|
+
|
|
14
17
|
## Answer protocol
|
|
15
18
|
|
|
16
19
|
For any "is this fine / covered / needed / safe?" question, the verdict comes first, in one of
|
|
@@ -39,6 +39,9 @@ hunk in that file's patch.
|
|
|
39
39
|
|
|
40
40
|
## Layering rules
|
|
41
41
|
|
|
42
|
+
In reader-facing prose, call diff sections **chunks**. Keep the schema field `hunks` and
|
|
43
|
+
`#hunk:` link targets exactly as specified.
|
|
44
|
+
|
|
42
45
|
Project-configured layers (optional guidance):
|
|
43
46
|
|
|
44
47
|
{{CONFIGURED_LAYERS}}
|