@vintasoftware/pr-review-canvas 0.1.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/LICENSE +202 -0
- package/README.md +192 -0
- package/bin/pr-review.mjs +5 -0
- package/docs/reference.md +340 -0
- package/package.json +74 -0
- package/pr-review.config.example.yml +68 -0
- package/prompts/chat-seed.md +64 -0
- package/prompts/generation-format.md +255 -0
- package/prompts/generation-strict.md +34 -0
- package/prompts/generation-surfacing.md +67 -0
- package/prompts/layers-default.md +13 -0
- package/prompts/quality-standards.md +32 -0
- package/skills/pr-review-canvas/SKILL.md +177 -0
- package/src/acpx/acpx.ts +530 -0
- package/src/acpx/agents.ts +85 -0
- package/src/acpx/events.ts +216 -0
- package/src/acpx/ndjson.ts +69 -0
- package/src/acpx/preflight.ts +44 -0
- package/src/canvas/export.ts +95 -0
- package/src/canvas/import.ts +138 -0
- package/src/canvas/name.ts +55 -0
- package/src/canvas/zip.ts +123 -0
- package/src/chat/chat-manager.ts +389 -0
- package/src/chat/context.ts +160 -0
- package/src/chat/seed.ts +71 -0
- package/src/chat/threads.ts +114 -0
- package/src/cli.ts +199 -0
- package/src/commands.ts +424 -0
- package/src/config.ts +142 -0
- package/src/contract/api.ts +190 -0
- package/src/contract/canvas-manifest.ts +29 -0
- package/src/contract/chat.ts +76 -0
- package/src/contract/comments.ts +96 -0
- package/src/contract/discovery.ts +20 -0
- package/src/contract/generation-context.ts +77 -0
- package/src/contract/keys.ts +14 -0
- package/src/contract/links.ts +5 -0
- package/src/contract/mermaid-fences.ts +4 -0
- package/src/contract/review-artifact.ts +324 -0
- package/src/contract/settings.ts +144 -0
- package/src/contract/state.ts +46 -0
- package/src/contract/validation.ts +43 -0
- package/src/git/diff-collector.ts +151 -0
- package/src/git/git.ts +115 -0
- package/src/git/lang.ts +1 -0
- package/src/git/materialize.ts +79 -0
- package/src/git/patch-lines.ts +60 -0
- package/src/github/attachments.ts +288 -0
- package/src/github/capabilities.ts +112 -0
- package/src/github/comments.ts +132 -0
- package/src/github/gh.ts +196 -0
- package/src/github/post-comment.ts +104 -0
- package/src/github/post-review.ts +44 -0
- package/src/github/pr.ts +133 -0
- package/src/github/review-body.ts +72 -0
- package/src/github/threads.ts +63 -0
- package/src/paths.ts +10 -0
- package/src/project-config.ts +219 -0
- package/src/prompt-files.ts +26 -0
- package/src/review/diagram-nodes.ts +227 -0
- package/src/review/doctor.ts +139 -0
- package/src/review/glob.ts +33 -0
- package/src/review/install-skill.ts +107 -0
- package/src/review/normalize.ts +209 -0
- package/src/review/prepare.ts +165 -0
- package/src/review/prompt.ts +233 -0
- package/src/review/publish.ts +209 -0
- package/src/review/skill-command.ts +4 -0
- package/src/review/test-paths.ts +32 -0
- package/src/review/text-length.ts +15 -0
- package/src/review/trim-caps.ts +114 -0
- package/src/review/validate-folds.ts +110 -0
- package/src/review/validate.ts +520 -0
- package/src/server/app.ts +46 -0
- package/src/server/bundle.ts +266 -0
- package/src/server/capped-body.ts +62 -0
- package/src/server/context.ts +174 -0
- package/src/server/env.ts +7 -0
- package/src/server/errors.ts +65 -0
- package/src/server/html.ts +140 -0
- package/src/server/node-server.ts +42 -0
- package/src/server/routes/api.ts +256 -0
- package/src/server/routes/chat-routes.ts +221 -0
- package/src/server/routes/pages.ts +64 -0
- package/src/server/routes/review-routes.ts +245 -0
- package/src/server/routes/static.ts +114 -0
- package/src/server/security.ts +104 -0
- package/src/server/sse.ts +67 -0
- package/src/store/atomic-json.ts +68 -0
- package/src/store/canvas-store.ts +120 -0
- package/src/store/data-dir.ts +29 -0
- package/src/store/derived-store.ts +93 -0
- package/src/store/pr-store.ts +69 -0
- package/src/store/settings-store.ts +152 -0
- package/src/store/state-store.ts +121 -0
- package/static/js/anchors.js +141 -0
- package/static/js/api.js +542 -0
- package/static/js/app.js +418 -0
- package/static/js/ask.js +35 -0
- package/static/js/chat-context.js +137 -0
- package/static/js/chat-scroll.js +114 -0
- package/static/js/chat.js +843 -0
- package/static/js/code-folds.js +200 -0
- package/static/js/commands.js +110 -0
- package/static/js/comment-link.js +37 -0
- package/static/js/composer.js +241 -0
- package/static/js/contract-types.d.ts +59 -0
- package/static/js/deep-link.js +160 -0
- package/static/js/diagram.js +582 -0
- package/static/js/diff-decorations.js +204 -0
- package/static/js/diff-renderer.js +860 -0
- package/static/js/dom.js +145 -0
- package/static/js/download.js +52 -0
- package/static/js/empty-state.js +161 -0
- package/static/js/errors.js +135 -0
- package/static/js/fences.js +90 -0
- package/static/js/header.js +134 -0
- package/static/js/hunks.js +62 -0
- package/static/js/import-zone.js +95 -0
- package/static/js/interactions.js +952 -0
- package/static/js/keyboard.js +131 -0
- package/static/js/keys.js +97 -0
- package/static/js/lang.js +54 -0
- package/static/js/layers.js +596 -0
- package/static/js/links.js +150 -0
- package/static/js/markdown.js +232 -0
- package/static/js/mermaid-fences.js +55 -0
- package/static/js/nav.js +91 -0
- package/static/js/overview.js +85 -0
- package/static/js/points.js +247 -0
- package/static/js/progress.js +49 -0
- package/static/js/proposed-comment.js +133 -0
- package/static/js/quick-questions.js +216 -0
- package/static/js/regenerate.js +69 -0
- package/static/js/review-session.js +257 -0
- package/static/js/scroll-spy.js +66 -0
- package/static/js/selection.js +193 -0
- package/static/js/settings.js +206 -0
- package/static/js/signoff.js +171 -0
- package/static/js/skin.js +56 -0
- package/static/js/store.js +35 -0
- package/static/js/theme.js +56 -0
- package/static/js/threads.js +78 -0
- package/static/js/vendor.d.ts +15 -0
- package/static/styles/base.css +223 -0
- package/static/styles/chat-tools.css +130 -0
- package/static/styles/chat.css +140 -0
- package/static/styles/commands.css +156 -0
- package/static/styles/diff.css +258 -0
- package/static/styles/header.css +114 -0
- package/static/styles/layout.css +123 -0
- package/static/styles/panels.css +152 -0
- package/static/styles/responsive.css +80 -0
- package/static/styles/review-actions.css +124 -0
- package/static/styles/review.css +473 -0
- package/static/styles/skin-github.css +356 -0
- package/static/styles.css +14 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# CLI and configuration reference
|
|
2
|
+
|
|
3
|
+
For installation, the author/reviewer workflow, and basic settings, start with the
|
|
4
|
+
[README](../README.md). This reference covers command options, configuration values, and behavior
|
|
5
|
+
that matters when customizing or troubleshooting a review.
|
|
6
|
+
|
|
7
|
+
- [CLI options](#cli-options)
|
|
8
|
+
- [Project config](#project-config)
|
|
9
|
+
- [Local settings and storage](#local-settings-and-storage)
|
|
10
|
+
- [Review controls](#review-controls)
|
|
11
|
+
- [AI Chat](#ai-chat)
|
|
12
|
+
- [Network access and permissions](#network-access-and-permissions)
|
|
13
|
+
- [Troubleshooting](#troubleshooting)
|
|
14
|
+
|
|
15
|
+
## CLI options
|
|
16
|
+
|
|
17
|
+
### Repository and runtime options
|
|
18
|
+
|
|
19
|
+
| Option | Applies to | Default and behavior |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `--repo <dir>` | All commands | Uses the current directory when omitted; resolves the repository root from there |
|
|
22
|
+
| `--data-dir <dir>` | All except `install-skill` | Overrides `PR_REVIEW_DATA_DIR`, then the default `<main checkout>/.pr-review` |
|
|
23
|
+
| `--port <n>` | `serve` | Overrides `PR_REVIEW_PORT`, then `3010`; accepts 1–65535 |
|
|
24
|
+
| `--agent claude\|codex` | `serve` | Overrides the saved chat agent for this run |
|
|
25
|
+
| `--model <id>` | `serve` | Overrides the saved chat model for this run |
|
|
26
|
+
| `--fixture-canvas <review.json>` | `serve` | Development preview: uses the supplied canvas for every requested PR, with its head replaced by the live PR head |
|
|
27
|
+
|
|
28
|
+
Repository operations require an `origin` remote on **github.com**. GitHub Enterprise Server
|
|
29
|
+
hosts are not supported. Fetching a PR does not check out its branch.
|
|
30
|
+
|
|
31
|
+
### Prepare, validate, and publish
|
|
32
|
+
|
|
33
|
+
These commands support custom generation workflows. The bundled
|
|
34
|
+
[generation skill](../skills/pr-review-canvas/SKILL.md) describes the complete sequence and model rules.
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
pr-review prepare (--pr <n> | --base <ref> --head <ref>) [--force]
|
|
38
|
+
pr-review validate <model.json|review.json> --canvas <dir> [--human] [--fix]
|
|
39
|
+
pr-review publish <canvasDir> --agent <id> [--model <id>] --harness claude-code|codex|other [--allow-stale]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`prepare` returns `canvasDir`, `headSha`, `mergeBaseSha`, `promptPath`, `contextPath`, and `status`.
|
|
43
|
+
A status of `exists` means that head already has a canvas. With `--force`, preparation clears the
|
|
44
|
+
previous generation's working files while keeping the published canvas available until a new
|
|
45
|
+
publish succeeds.
|
|
46
|
+
|
|
47
|
+
For a comparison before a PR exists, use local refs:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pr-review prepare --base origin/main --head HEAD
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`validate` checks the supplied file against the context in `--canvas`. By default it returns
|
|
54
|
+
`{ ok, errors }`; `--human` prints readable diagnostics. `--fix` edits overlong titles by removing
|
|
55
|
+
the explanation after the first `:` or `—` and reports the changes. Titles that still exceed the
|
|
56
|
+
limit and overlong prose require rewriting.
|
|
57
|
+
|
|
58
|
+
`publish` returns `status`, `headSha`, `reviewJsonPath`, `attempts`, and a `reviewUrl` for PR runs.
|
|
59
|
+
Its `--agent`, `--model`, and `--harness` describe who generated the canvas; they do not launch or
|
|
60
|
+
select an agent. `--allow-stale` permits publishing for the prepared commit after the PR head has
|
|
61
|
+
moved. Use it only when that older commit is the intended review target.
|
|
62
|
+
|
|
63
|
+
For more than 400 changed files or 50,000 added/deleted lines, preparation leaves diffs out of the
|
|
64
|
+
prompt and directs the generator to read patch files individually. Smaller diffs are inlined up
|
|
65
|
+
to `generation.inlineDiffMaxLines`.
|
|
66
|
+
|
|
67
|
+
### Export and import options
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
pr-review export (--pr <n> | --head <ref|sha>) [--out <file|dir>]
|
|
71
|
+
pr-review import <zip> [--pr <n>] [--force]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- `export --head` selects a specific commit. With both `--head` and `--pr`, the PR number labels
|
|
75
|
+
the archive; it does not select the commit.
|
|
76
|
+
- `--out` defaults to the data directory's `exports/` folder. Supply an existing directory to
|
|
77
|
+
keep the generated filename, or a full `.zip` file path to choose a name.
|
|
78
|
+
- Export returns `status`, `path`, `name`, `headSha`, and `prNumber` when supplied or stored.
|
|
79
|
+
- `import --pr` compares the imported canvas with that PR's current head. Without it, import does
|
|
80
|
+
not check against a live PR.
|
|
81
|
+
- Import returns `ready`, `stale`, or `exists`, plus commit information and warnings. `exists`
|
|
82
|
+
keeps a stored canvas generated at the same time or later. `derivable: false` means the canvas
|
|
83
|
+
was accepted but its source diffs could not be rebuilt from Git.
|
|
84
|
+
- `import --force` allows a canvas from another repository. It does not force an older canvas to
|
|
85
|
+
replace a newer one.
|
|
86
|
+
|
|
87
|
+
Imports accept archives up to **20 MiB**. The required `manifest.json` and `review.json` entries
|
|
88
|
+
must be at the archive root and pass format validation. If the necessary commits are missing,
|
|
89
|
+
the tool attempts to fetch them; a failed fetch can leave the notes available without diffs.
|
|
90
|
+
|
|
91
|
+
### Skill installation options
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
pr-review install-skill [--claude-dir <dir>] [--codex-dir <dir>] [--force]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Custom directories replace the destination for the named host; both hosts are still installed.
|
|
98
|
+
Relative custom paths resolve from the command's working directory. For example:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pr-review install-skill --codex-dir ~/.codex/skills
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Installation uses relative symlinks on Linux and macOS and copies on Windows. Re-running it
|
|
105
|
+
refreshes its own installation. A customized directory requires `--force` to replace it.
|
|
106
|
+
The `.gitignore` update always applies to the selected repository root, even with custom skill
|
|
107
|
+
directories.
|
|
108
|
+
|
|
109
|
+
### Output and exit codes
|
|
110
|
+
|
|
111
|
+
One-shot commands normally print a JSON result on stdout. Preparation progress goes to stderr.
|
|
112
|
+
`validate --human` prints text, and a failed `publish` prints validation diagnostics before its
|
|
113
|
+
JSON error. `serve` stays running and writes its startup message to stderr.
|
|
114
|
+
|
|
115
|
+
Command failures use `{ "error": { "code", "message", "hint" } }`, with `hint` optional.
|
|
116
|
+
Validation failures from `validate` use its report format instead.
|
|
117
|
+
|
|
118
|
+
| Exit code | Meaning |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `0` | Success |
|
|
121
|
+
| `1` | Error, including a failed `doctor` check |
|
|
122
|
+
| `2` | Command usage error, such as an unknown command or missing required flag |
|
|
123
|
+
| `4` | GitHub CLI missing or unauthenticated |
|
|
124
|
+
| `5` | Validation failed in `validate` or `publish` |
|
|
125
|
+
|
|
126
|
+
`doctor` reports failed checks with exit `1`, including authentication failures.
|
|
127
|
+
|
|
128
|
+
## Project config
|
|
129
|
+
|
|
130
|
+
All keys are optional. See the [example configuration](../pr-review.config.example.yml) for a
|
|
131
|
+
starting file. Invalid YAML or invalid values produce a warning and fall back to the defaults.
|
|
132
|
+
Lists you supply replace their defaults.
|
|
133
|
+
|
|
134
|
+
Path patterns match repository-relative paths. `**` crosses directories; `*` and `?` match
|
|
135
|
+
within one path segment.
|
|
136
|
+
|
|
137
|
+
| Key | Default | Details |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `version` | `1` | The only supported configuration version |
|
|
140
|
+
| `rulebook` | Unset | Path to a Markdown file of project code standards, resolved from the repository root; these standards take precedence over bundled standards |
|
|
141
|
+
| `layers` | Eight architecture groups | Suggested review groups; each entry has `id`, `title`, `description`, and optional `paths` patterns. The generator may split or reorder groups |
|
|
142
|
+
| `highRisk` | `[]` | Entries with a `pattern` glob and `label`; matching changes receive risk labels and cannot go in the Other layer |
|
|
143
|
+
| `generation.mode` | `strict` | See [generation modes](#generation-modes) |
|
|
144
|
+
| `generation.maxRepairRounds` | `3` | Failed validation rounds allowed by the generation skill |
|
|
145
|
+
| `generation.inlineDiffMaxLines` | `1500` | Maximum diff length to include directly in the generation prompt |
|
|
146
|
+
| `generation.smallPrHunks` | `10` | At or below this hunk count, the prompt asks for one layer unless concerns differ |
|
|
147
|
+
| `generation.caps` | See below | Overrides individual text limits |
|
|
148
|
+
| `tests.patterns` | `['**/*.test.*', '**/*.spec.*', '**/__tests__/**']` | Paths treated as tests for review ordering and labels |
|
|
149
|
+
| `chat.enabled` | `true` | Set to `false` to disable AI Chat |
|
|
150
|
+
| `prompts` | Bundled templates | See [prompt customization](../README.md#project-prompt-templates) for supported keys and setup |
|
|
151
|
+
|
|
152
|
+
Generation's numeric options and text caps must be positive integers. An empty `layers` list
|
|
153
|
+
provides no suggested groups; an empty `tests.patterns` list recognizes no files as tests.
|
|
154
|
+
|
|
155
|
+
Preparation saves the rules used to validate that generation. Changes to the configuration do
|
|
156
|
+
not change an already prepared generation or an existing canvas.
|
|
157
|
+
|
|
158
|
+
### Generation modes
|
|
159
|
+
|
|
160
|
+
- **`strict`** focuses on code-quality findings.
|
|
161
|
+
- **`surfacing`** provides a walkthrough of decisions, trade-offs, and maintenance concerns,
|
|
162
|
+
with code-quality findings included.
|
|
163
|
+
|
|
164
|
+
Both modes read the project rulebook and use the same validation and review controls. The mode
|
|
165
|
+
affects canvas generation; chat answers the reviewer's selected question.
|
|
166
|
+
|
|
167
|
+
### Text limits
|
|
168
|
+
|
|
169
|
+
Set any of these keys under `generation.caps`. Prose limits count visible characters, so Markdown
|
|
170
|
+
link targets do not count. `diagram` counts raw Mermaid source characters.
|
|
171
|
+
|
|
172
|
+
| Key | Default |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `summary` | 1200 |
|
|
175
|
+
| `layerTitle` | 60 |
|
|
176
|
+
| `rationale` | 300 |
|
|
177
|
+
| `decisions` | 600 |
|
|
178
|
+
| `checkByHand` | 400 |
|
|
179
|
+
| `annotation` | 240 |
|
|
180
|
+
| `pointTitle` | 90 |
|
|
181
|
+
| `pointBody` | 600 |
|
|
182
|
+
| `testBehavior` | 120 |
|
|
183
|
+
| `diagram` | 1500 |
|
|
184
|
+
|
|
185
|
+
The canvas has a separate limit of 12 attention points, including entries generated from missing
|
|
186
|
+
tests. Increasing text caps does not increase that limit.
|
|
187
|
+
|
|
188
|
+
### Test conventions
|
|
189
|
+
|
|
190
|
+
Custom patterns replace the JavaScript/TypeScript defaults. For example, a Python project can use:
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
tests:
|
|
194
|
+
patterns: ['**/test_*.py', '**/tests/**']
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Test recognition controls ordering, but matching a test to its source file currently follows
|
|
198
|
+
`.test`, `.spec`, and `__tests__` naming. With other conventions, validation may miss a test
|
|
199
|
+
placed in Other while its source is in a regular layer.
|
|
200
|
+
|
|
201
|
+
## Local settings and storage
|
|
202
|
+
|
|
203
|
+
See the [README's settings overview](../README.md#user-local-preferences) for editing preferences
|
|
204
|
+
through the UI. These are the file keys and accepted values:
|
|
205
|
+
|
|
206
|
+
| Key | Default | Accepted values |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `version` | `1` | `1` |
|
|
209
|
+
| `skin` | `terminal` | `terminal`, `github` |
|
|
210
|
+
| `theme` | `auto` | `auto`, `light`, `dark` |
|
|
211
|
+
| `agent` | `claude` | `claude`, `codex` |
|
|
212
|
+
| `model` | `null` | A model ID, or `null` for the agent's default |
|
|
213
|
+
| `chatTimeoutSec` | `600` | Integer seconds, 30–3600 |
|
|
214
|
+
| `maxTurns` | `null` | Integer 1–100, or `null` for the agent's default |
|
|
215
|
+
|
|
216
|
+
Invalid settings fall back to defaults. URL parameters `?skin=github&theme=light` can override
|
|
217
|
+
appearance for one page load without saving it.
|
|
218
|
+
|
|
219
|
+
By default, Git worktrees of the same clone share the main checkout's data directory. Separate
|
|
220
|
+
clones have separate data. An explicit data-directory override also relocates `settings.yml`,
|
|
221
|
+
canvases, review progress, and chat history.
|
|
222
|
+
|
|
223
|
+
The data directory contains exported archives, saved canvases, generation inputs, cached GitHub
|
|
224
|
+
data, source diffs, and personal review progress. Its own `.gitignore` excludes its contents.
|
|
225
|
+
Deleting the directory loses saved preferences, canvases, progress, and chat history.
|
|
226
|
+
|
|
227
|
+
## Review controls
|
|
228
|
+
|
|
229
|
+
### Links to specific code
|
|
230
|
+
|
|
231
|
+
Append a fragment to `/review/<pr-number>`:
|
|
232
|
+
|
|
233
|
+
| Target | Fragment example |
|
|
234
|
+
|---|---|
|
|
235
|
+
| Layer | `#layer:data-access` |
|
|
236
|
+
| File | `#file:src/store.ts` |
|
|
237
|
+
| Hunk | `#hunk:src/store.ts#2` |
|
|
238
|
+
| New-side line range | `#line:src/store.ts:40-52` |
|
|
239
|
+
| Old-side line | `#line:src/store.ts:40:old` |
|
|
240
|
+
|
|
241
|
+
Use the layer key and file path from the canvas. Links open the target file when needed; if a
|
|
242
|
+
line is unavailable, navigation uses the nearest visible row. Recipients need their own running
|
|
243
|
+
server and the corresponding canvas to use a localhost link.
|
|
244
|
+
|
|
245
|
+
### Collapsed diffs
|
|
246
|
+
|
|
247
|
+
Import-only changes, whitespace changes, moved code, and ranges selected by the generator may
|
|
248
|
+
start collapsed. Click the summary to expand them. Moves are detected within a file; moves
|
|
249
|
+
between files appear as deletions and additions. Edited moves keep their changed text visible.
|
|
250
|
+
Collapsing content does not mark it reviewed.
|
|
251
|
+
|
|
252
|
+
Files with patches longer than 2,000 lines wait behind **show diff**. A link into the file opens
|
|
253
|
+
it automatically.
|
|
254
|
+
|
|
255
|
+
### Finding shared canvases
|
|
256
|
+
|
|
257
|
+
Discovery checks the PR description and comments for canvas ZIP links. It prefers a filename
|
|
258
|
+
matching the current head, then the PR number, then the most recently edited source text.
|
|
259
|
+
If a download fails, it tries other matching attachments. Keep the exported filename so the
|
|
260
|
+
canvas can be recognized.
|
|
261
|
+
|
|
262
|
+
When automatic download fails, download the archive in GitHub's UI and use the page's drop zone
|
|
263
|
+
or `pr-review import <zip> --pr <n>`.
|
|
264
|
+
|
|
265
|
+
### Comments and sign-off
|
|
266
|
+
|
|
267
|
+
You can post inline comments, replies, PR-level comments, and attention points. Inline comments
|
|
268
|
+
must target lines in the diff. Posting uses your GitHub CLI account and remains subject to its
|
|
269
|
+
repository permissions.
|
|
270
|
+
|
|
271
|
+
The sign-off dialog previews an editable review body summarizing reviewed layers, dismissed
|
|
272
|
+
attention points, and comments posted from the canvas. Approval requires every layer except
|
|
273
|
+
**Other changes** to be reviewed for the current head. Requesting changes does not require that
|
|
274
|
+
completion. If the head moves before submission, reload and review the current commit.
|
|
275
|
+
|
|
276
|
+
## AI Chat
|
|
277
|
+
|
|
278
|
+
**Ask** on a layer, file, attention point, or line selection chooses the context for your message.
|
|
279
|
+
Choosing another target replaces it; **clear** returns to the whole PR. The `a` key asks about
|
|
280
|
+
the focused target, and `/` focuses the message box.
|
|
281
|
+
|
|
282
|
+
Chat can propose an inline GitHub comment. A valid proposal appears with controls to post, edit,
|
|
283
|
+
or copy it. A proposal outside the current diff remains text with an explanation.
|
|
284
|
+
|
|
285
|
+
Use **stop** to interrupt a reply. Only one chat turn can run per PR at a time. A timeout or
|
|
286
|
+
incomplete answer can be retried; increase `chatTimeoutSec` if replies need more time.
|
|
287
|
+
|
|
288
|
+
## Network access and permissions
|
|
289
|
+
|
|
290
|
+
The server binds to `127.0.0.1` and rejects browser writes from other origins. It is intended for
|
|
291
|
+
local use with your GitHub login.
|
|
292
|
+
|
|
293
|
+
GitHub requests fetch PR data and attachments and submit the comments or reviews you choose to
|
|
294
|
+
post. Rendered Markdown can load images from HTTPS hosts. Generation and chat send review
|
|
295
|
+
context to the selected coding agent and its configured provider.
|
|
296
|
+
|
|
297
|
+
Chat is instructed to read code without changing it, but the tool does not provide a filesystem
|
|
298
|
+
sandbox for the agent. Its access also depends on the agent's own permissions. Disable chat with
|
|
299
|
+
`chat.enabled: false` if those permissions are unsuitable for the project.
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
| Symptom or code | Next step |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `NOT_A_REPO` | Run inside a Git clone or pass `--repo <dir>` |
|
|
306
|
+
| `NO_ORIGIN` | Check that `origin` points to a repository on github.com |
|
|
307
|
+
| `GH_MISSING` / `GH_UNAUTHENTICATED` | Follow the [GitHub CLI setup](../README.md#install); check authentication in the same environment that runs the server |
|
|
308
|
+
| `GITHUB_API_ERROR` | Read the underlying error for permissions, rate limits, connectivity, or GitHub service problems |
|
|
309
|
+
| `PR_NOT_FOUND` | Check the PR number, repository, and your access |
|
|
310
|
+
| `CANVAS_NOT_FOUND` | Generate or import a canvas for the requested commit |
|
|
311
|
+
| `CANVAS_INVALID` | Read the format errors; re-export or regenerate the canvas |
|
|
312
|
+
| `CANVAS_REPO_MISMATCH` | Check which clone is open; use `import --force` only when importing from the other repository is intentional |
|
|
313
|
+
| `CANVAS_TOO_LARGE` | The archive exceeds the 20 MiB import limit |
|
|
314
|
+
| `CANVAS_STALE` | The PR head moved; prepare again for the current commit |
|
|
315
|
+
| `MODEL_INVALID` | Fix the reported problems in `model.json`, validate, then publish again |
|
|
316
|
+
| `SKILL_DIR_EXISTS` | The destination contains a customized directory; preserve it elsewhere before replacing it with `--force` |
|
|
317
|
+
| `CHAT_BUSY` | Wait for the running reply or press **stop** |
|
|
318
|
+
| `AGENT_AUTH_REQUIRED` | Sign in through the selected agent's CLI, then retry |
|
|
319
|
+
| `AGENT_MISSING` or missing chat pane | Check the [chat setup](../README.md#optional-ai-chat-install), `chat.enabled`, and that the server can find the installed executables |
|
|
320
|
+
| `AGENT_INCOMPLETE` | Retry the message or increase the chat timeout |
|
|
321
|
+
| `COMMENT_FORBIDDEN` | Check the GitHub account's repository access and token permissions |
|
|
322
|
+
| `COMMENT_LINE_NOT_IN_DIFF` | Choose a line shown in the current diff |
|
|
323
|
+
| `SIGNOFF_INCOMPLETE` | Mark every layer except Other reviewed for this head |
|
|
324
|
+
| `FORBIDDEN_HOST` / `CROSS_ORIGIN` | Open the local server using `localhost` or `127.0.0.1` and submit actions from that page |
|
|
325
|
+
|
|
326
|
+
### Validation diagnostics
|
|
327
|
+
|
|
328
|
+
Validation reports name the field, file, hunk, or line to fix. Common groups are:
|
|
329
|
+
|
|
330
|
+
| Codes | What to check |
|
|
331
|
+
|---|---|
|
|
332
|
+
| `SCHEMA`, `TEXT_TOO_LONG` | Required fields, types, and text limits |
|
|
333
|
+
| `HUNK_UNASSIGNED`, `HUNK_DUPLICATE`, `HUNK_UNKNOWN` | Each known hunk belongs to exactly one layer |
|
|
334
|
+
| `PATH_UNKNOWN`, `TEST_PATH_UNKNOWN` | Referenced files exist in the relevant diff or PR head |
|
|
335
|
+
| `LAYER_EMPTY`, `LAYER_KEY_DUPLICATE` | Layers contain hunks and have unique keys |
|
|
336
|
+
| `OTHER_DUPLICATE`, `OTHER_NOT_LAST`, `RISK_IN_OTHER` | At most one Other layer, last, without risk-tagged changes |
|
|
337
|
+
| `TEST_NOT_LAST`, `TEST_IN_OTHER` | Tests follow the code they cover and use the appropriate layer |
|
|
338
|
+
| `ANNOTATION_OUTSIDE_HUNK`, `POINT_OUTSIDE_DIFF`, `FOLD_INVALID` | Locations and fold ranges fit the assigned diff |
|
|
339
|
+
| `TOO_MANY_POINTS` | Count explicit points and missing-test entries together |
|
|
340
|
+
| `LINK_UNRESOLVED`, `DIAGRAM_NODE_UNKNOWN`, `DIAGRAM_LIMIT` | Link targets, diagram node IDs, and diagram counts |
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vintasoftware/pr-review-canvas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Localhost PR review canvas: layered diffs, attention points, and GitHub comments for one PR",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pr-review": "./bin/pr-review.mjs"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "tsx watch --clear-screen=false --ignore '**/.pr-review/**' src/cli.ts serve",
|
|
11
|
+
"start": "tsx src/cli.ts serve",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:watch": "vitest",
|
|
14
|
+
"test:browser": "playwright test",
|
|
15
|
+
"coverage": "vitest run --coverage",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test:package": "node scripts/test-package.mjs",
|
|
18
|
+
"verify": "pnpm typecheck && pnpm coverage && pnpm test:browser --workers=2 && pnpm test:package",
|
|
19
|
+
"prepublishOnly": "pnpm verify"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@highlightjs/cdn-assets": "^11.12.0",
|
|
23
|
+
"@hono/node-server": "^2.1.0",
|
|
24
|
+
"diff": "^9.0.0",
|
|
25
|
+
"dompurify": "^3.4.14",
|
|
26
|
+
"fflate": "^0.8.3",
|
|
27
|
+
"hono": "^4.13.1",
|
|
28
|
+
"marked": "^18.0.11",
|
|
29
|
+
"mermaid": "^11.17.2",
|
|
30
|
+
"tsx": "^4.23.12",
|
|
31
|
+
"yaml": "^2.9.0",
|
|
32
|
+
"zod": "^4.4.3"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@playwright/test": "1.62.1",
|
|
36
|
+
"@types/node": "^24.13.3",
|
|
37
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
38
|
+
"happy-dom": "20.11.2",
|
|
39
|
+
"typescript": "^5.9.3",
|
|
40
|
+
"vite": "~8.0.16",
|
|
41
|
+
"vitest": "^4.1.10"
|
|
42
|
+
},
|
|
43
|
+
"packageManager": "pnpm@10.33.0",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"bin/",
|
|
49
|
+
"src/",
|
|
50
|
+
"static/",
|
|
51
|
+
"prompts/",
|
|
52
|
+
"skills/",
|
|
53
|
+
"pr-review.config.example.yml",
|
|
54
|
+
"docs/reference.md",
|
|
55
|
+
"!src/**/*.test.ts",
|
|
56
|
+
"!src/__tests__/**",
|
|
57
|
+
"!src/testing/**",
|
|
58
|
+
"!static/**/*.test.js",
|
|
59
|
+
"!static/**/__fixtures__/**"
|
|
60
|
+
],
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/vintasoftware/pr-review-canvas.git"
|
|
64
|
+
},
|
|
65
|
+
"license": "Apache-2.0",
|
|
66
|
+
"homepage": "https://github.com/vintasoftware/pr-review-canvas#readme",
|
|
67
|
+
"bugs": {
|
|
68
|
+
"url": "https://github.com/vintasoftware/pr-review-canvas/issues"
|
|
69
|
+
},
|
|
70
|
+
"publishConfig": {
|
|
71
|
+
"access": "public",
|
|
72
|
+
"registry": "https://registry.npmjs.org/"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Copy to <repo root>/pr-review.config.yml. Every key is optional.
|
|
2
|
+
version: 1
|
|
3
|
+
|
|
4
|
+
# Markdown reference for project standards. The generation mode controls how the generator uses it.
|
|
5
|
+
# rulebook: docs/CODE_REVIEW.md
|
|
6
|
+
|
|
7
|
+
# Optional full-template replacements, resolved from this project's root.
|
|
8
|
+
# Commit these files with this config. Omitted entries use the installed defaults.
|
|
9
|
+
# prompts:
|
|
10
|
+
# generation-format.md: review-prompts/generation-format.md
|
|
11
|
+
# generation-strict.md: review-prompts/generation-strict.md
|
|
12
|
+
# generation-surfacing.md: review-prompts/generation-surfacing.md
|
|
13
|
+
# quality-standards.md: review-prompts/quality-standards.md
|
|
14
|
+
# layers-default.md: review-prompts/layers-default.md
|
|
15
|
+
# chat-seed.md: review-prompts/chat-seed.md
|
|
16
|
+
|
|
17
|
+
# Default layer taxonomy, in review order. Ids are referenced by `defaultLayerId` in a canvas.
|
|
18
|
+
layers:
|
|
19
|
+
- id: contracts
|
|
20
|
+
title: Contracts and schemas
|
|
21
|
+
description: Types, schemas, and the shapes two modules must agree on.
|
|
22
|
+
- id: data-access
|
|
23
|
+
title: Data access
|
|
24
|
+
description: Queries, repositories, migrations, storage.
|
|
25
|
+
- id: mappers
|
|
26
|
+
title: Mappers and DTOs
|
|
27
|
+
description: Code that turns records into view models and back.
|
|
28
|
+
- id: hooks-state
|
|
29
|
+
title: Hooks and state
|
|
30
|
+
description: Hooks, query definitions, stores, state machines.
|
|
31
|
+
- id: views
|
|
32
|
+
title: Views
|
|
33
|
+
description: Components, screens, styles, copy.
|
|
34
|
+
- id: routes-wiring
|
|
35
|
+
title: Routes and wiring
|
|
36
|
+
description: Route files, providers, shells, entry points.
|
|
37
|
+
- id: policy-config
|
|
38
|
+
title: Policy and config
|
|
39
|
+
description: Access policies, environment variables, feature flags, CI, deployment, docs.
|
|
40
|
+
- id: mechanical
|
|
41
|
+
title: Mechanical changes
|
|
42
|
+
description: Renames, lockfiles, generated files, formatting, moved code.
|
|
43
|
+
|
|
44
|
+
# Blast radius tags. Glob patterns against changed paths; the label shows in the header and the rail.
|
|
45
|
+
highRisk:
|
|
46
|
+
- pattern: '**/migrations/**'
|
|
47
|
+
label: schema
|
|
48
|
+
- pattern: '**/*auth*'
|
|
49
|
+
label: auth
|
|
50
|
+
|
|
51
|
+
generation:
|
|
52
|
+
mode: strict # strict: quality review; surfacing: walkthrough that audits as it reads
|
|
53
|
+
maxRepairRounds: 3 # publish retries the skill may make after a failed validation
|
|
54
|
+
inlineDiffMaxLines: 1500 # diffs longer than this are read per file instead of inlined in the prompt
|
|
55
|
+
smallPrHunks: 10 # at most this many hunks: one layer unless concerns differ, fewer annotations
|
|
56
|
+
# caps: # override the text caps (characters)
|
|
57
|
+
# summary: 1800
|
|
58
|
+
# rationale: 300
|
|
59
|
+
# diagram: 1500 # mermaid source, counted raw
|
|
60
|
+
|
|
61
|
+
# Which paths count as tests, for the layering rules and the `test` pill on a file card.
|
|
62
|
+
# Defaults to the JavaScript and TypeScript conventions below; name your own for other languages
|
|
63
|
+
# (Python: '**/test_*.py', '**/tests/**'; Go: '**/*_test.go').
|
|
64
|
+
tests:
|
|
65
|
+
patterns: ['**/*.test.*', '**/*.spec.*', '**/__tests__/**']
|
|
66
|
+
|
|
67
|
+
chat:
|
|
68
|
+
enabled: true # false removes the chat pane and its routes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Reviewing a pull request with a human
|
|
2
|
+
|
|
3
|
+
You are answering questions from an engineer who is reviewing this pull request in a local review
|
|
4
|
+
tool. Your job here is to read code and answer: do not edit files, run builds, or change anything,
|
|
5
|
+
even if asked. Permission prompts are denied without a human to answer them, so stay on reads and
|
|
6
|
+
searches and say plainly when a gap in what you can see changes your answer.
|
|
7
|
+
|
|
8
|
+
## Length and shape
|
|
9
|
+
|
|
10
|
+
At most six sentences. No headings unless the reader asks for more. Markdown is fine: inline code,
|
|
11
|
+
short lists, `path:line` references. Do not restate the question. Do not summarize the whole PR
|
|
12
|
+
when the reader asked about one file.
|
|
13
|
+
|
|
14
|
+
## Answer protocol
|
|
15
|
+
|
|
16
|
+
For any "is this fine / covered / needed / safe?" question, the verdict comes first, in one of
|
|
17
|
+
these three forms:
|
|
18
|
+
|
|
19
|
+
- `Yes.`
|
|
20
|
+
- `No, and that is fine because …`
|
|
21
|
+
- `No, and it should be.`
|
|
22
|
+
|
|
23
|
+
Then one or two sentences of evidence, each naming a `path:line`. Then, **only when you are
|
|
24
|
+
recommending a change**, a proposed comment: a fenced block tagged `comment` whose body is JSON.
|
|
25
|
+
|
|
26
|
+
````
|
|
27
|
+
```comment
|
|
28
|
+
{ "path": "packages/x/src/y.ts", "line": 42, "side": "new", "body": "The markdown of the comment." }
|
|
29
|
+
```
|
|
30
|
+
````
|
|
31
|
+
|
|
32
|
+
`path` must be a file in this pull request and `line` a line of the diff on that side. `side` is
|
|
33
|
+
`"new"` or `"old"` and defaults to `"new"`; add `"startLine"` for a range. Write at most one
|
|
34
|
+
proposed comment per answer, and only when a human should post it.
|
|
35
|
+
|
|
36
|
+
Defend code that is already good. Do not invent problems to look useful. When the answer is
|
|
37
|
+
"yes", stop there.
|
|
38
|
+
|
|
39
|
+
## This pull request
|
|
40
|
+
|
|
41
|
+
{{PR_META}}
|
|
42
|
+
|
|
43
|
+
## Layers of the review canvas
|
|
44
|
+
|
|
45
|
+
{{LAYERS}}
|
|
46
|
+
|
|
47
|
+
## Attention points already raised
|
|
48
|
+
|
|
49
|
+
{{POINTS}}
|
|
50
|
+
|
|
51
|
+
## Test map
|
|
52
|
+
|
|
53
|
+
{{TESTS}}
|
|
54
|
+
|
|
55
|
+
## Where the code is
|
|
56
|
+
|
|
57
|
+
The pull request's files are materialized on disk, so you can read either side without git:
|
|
58
|
+
|
|
59
|
+
- head (the pull request's version): `{{HEAD_DIR}}`
|
|
60
|
+
- base (the merge base): `{{BASE_DIR}}`
|
|
61
|
+
- per-file patches: `{{PATCH_DIR}}`
|
|
62
|
+
|
|
63
|
+
The working tree at `{{REPO_ROOT}}` is the reader's own checkout, which may be on another branch.
|
|
64
|
+
Prefer the materialized head when you want the pull request's version of a file.
|