@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.
Files changed (157) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +192 -0
  3. package/bin/pr-review.mjs +5 -0
  4. package/docs/reference.md +340 -0
  5. package/package.json +74 -0
  6. package/pr-review.config.example.yml +68 -0
  7. package/prompts/chat-seed.md +64 -0
  8. package/prompts/generation-format.md +255 -0
  9. package/prompts/generation-strict.md +34 -0
  10. package/prompts/generation-surfacing.md +67 -0
  11. package/prompts/layers-default.md +13 -0
  12. package/prompts/quality-standards.md +32 -0
  13. package/skills/pr-review-canvas/SKILL.md +177 -0
  14. package/src/acpx/acpx.ts +530 -0
  15. package/src/acpx/agents.ts +85 -0
  16. package/src/acpx/events.ts +216 -0
  17. package/src/acpx/ndjson.ts +69 -0
  18. package/src/acpx/preflight.ts +44 -0
  19. package/src/canvas/export.ts +95 -0
  20. package/src/canvas/import.ts +138 -0
  21. package/src/canvas/name.ts +55 -0
  22. package/src/canvas/zip.ts +123 -0
  23. package/src/chat/chat-manager.ts +389 -0
  24. package/src/chat/context.ts +160 -0
  25. package/src/chat/seed.ts +71 -0
  26. package/src/chat/threads.ts +114 -0
  27. package/src/cli.ts +199 -0
  28. package/src/commands.ts +424 -0
  29. package/src/config.ts +142 -0
  30. package/src/contract/api.ts +190 -0
  31. package/src/contract/canvas-manifest.ts +29 -0
  32. package/src/contract/chat.ts +76 -0
  33. package/src/contract/comments.ts +96 -0
  34. package/src/contract/discovery.ts +20 -0
  35. package/src/contract/generation-context.ts +77 -0
  36. package/src/contract/keys.ts +14 -0
  37. package/src/contract/links.ts +5 -0
  38. package/src/contract/mermaid-fences.ts +4 -0
  39. package/src/contract/review-artifact.ts +324 -0
  40. package/src/contract/settings.ts +144 -0
  41. package/src/contract/state.ts +46 -0
  42. package/src/contract/validation.ts +43 -0
  43. package/src/git/diff-collector.ts +151 -0
  44. package/src/git/git.ts +115 -0
  45. package/src/git/lang.ts +1 -0
  46. package/src/git/materialize.ts +79 -0
  47. package/src/git/patch-lines.ts +60 -0
  48. package/src/github/attachments.ts +288 -0
  49. package/src/github/capabilities.ts +112 -0
  50. package/src/github/comments.ts +132 -0
  51. package/src/github/gh.ts +196 -0
  52. package/src/github/post-comment.ts +104 -0
  53. package/src/github/post-review.ts +44 -0
  54. package/src/github/pr.ts +133 -0
  55. package/src/github/review-body.ts +72 -0
  56. package/src/github/threads.ts +63 -0
  57. package/src/paths.ts +10 -0
  58. package/src/project-config.ts +219 -0
  59. package/src/prompt-files.ts +26 -0
  60. package/src/review/diagram-nodes.ts +227 -0
  61. package/src/review/doctor.ts +139 -0
  62. package/src/review/glob.ts +33 -0
  63. package/src/review/install-skill.ts +107 -0
  64. package/src/review/normalize.ts +209 -0
  65. package/src/review/prepare.ts +165 -0
  66. package/src/review/prompt.ts +233 -0
  67. package/src/review/publish.ts +209 -0
  68. package/src/review/skill-command.ts +4 -0
  69. package/src/review/test-paths.ts +32 -0
  70. package/src/review/text-length.ts +15 -0
  71. package/src/review/trim-caps.ts +114 -0
  72. package/src/review/validate-folds.ts +110 -0
  73. package/src/review/validate.ts +520 -0
  74. package/src/server/app.ts +46 -0
  75. package/src/server/bundle.ts +266 -0
  76. package/src/server/capped-body.ts +62 -0
  77. package/src/server/context.ts +174 -0
  78. package/src/server/env.ts +7 -0
  79. package/src/server/errors.ts +65 -0
  80. package/src/server/html.ts +140 -0
  81. package/src/server/node-server.ts +42 -0
  82. package/src/server/routes/api.ts +256 -0
  83. package/src/server/routes/chat-routes.ts +221 -0
  84. package/src/server/routes/pages.ts +64 -0
  85. package/src/server/routes/review-routes.ts +245 -0
  86. package/src/server/routes/static.ts +114 -0
  87. package/src/server/security.ts +104 -0
  88. package/src/server/sse.ts +67 -0
  89. package/src/store/atomic-json.ts +68 -0
  90. package/src/store/canvas-store.ts +120 -0
  91. package/src/store/data-dir.ts +29 -0
  92. package/src/store/derived-store.ts +93 -0
  93. package/src/store/pr-store.ts +69 -0
  94. package/src/store/settings-store.ts +152 -0
  95. package/src/store/state-store.ts +121 -0
  96. package/static/js/anchors.js +141 -0
  97. package/static/js/api.js +542 -0
  98. package/static/js/app.js +418 -0
  99. package/static/js/ask.js +35 -0
  100. package/static/js/chat-context.js +137 -0
  101. package/static/js/chat-scroll.js +114 -0
  102. package/static/js/chat.js +843 -0
  103. package/static/js/code-folds.js +200 -0
  104. package/static/js/commands.js +110 -0
  105. package/static/js/comment-link.js +37 -0
  106. package/static/js/composer.js +241 -0
  107. package/static/js/contract-types.d.ts +59 -0
  108. package/static/js/deep-link.js +160 -0
  109. package/static/js/diagram.js +582 -0
  110. package/static/js/diff-decorations.js +204 -0
  111. package/static/js/diff-renderer.js +860 -0
  112. package/static/js/dom.js +145 -0
  113. package/static/js/download.js +52 -0
  114. package/static/js/empty-state.js +161 -0
  115. package/static/js/errors.js +135 -0
  116. package/static/js/fences.js +90 -0
  117. package/static/js/header.js +134 -0
  118. package/static/js/hunks.js +62 -0
  119. package/static/js/import-zone.js +95 -0
  120. package/static/js/interactions.js +952 -0
  121. package/static/js/keyboard.js +131 -0
  122. package/static/js/keys.js +97 -0
  123. package/static/js/lang.js +54 -0
  124. package/static/js/layers.js +596 -0
  125. package/static/js/links.js +150 -0
  126. package/static/js/markdown.js +232 -0
  127. package/static/js/mermaid-fences.js +55 -0
  128. package/static/js/nav.js +91 -0
  129. package/static/js/overview.js +85 -0
  130. package/static/js/points.js +247 -0
  131. package/static/js/progress.js +49 -0
  132. package/static/js/proposed-comment.js +133 -0
  133. package/static/js/quick-questions.js +216 -0
  134. package/static/js/regenerate.js +69 -0
  135. package/static/js/review-session.js +257 -0
  136. package/static/js/scroll-spy.js +66 -0
  137. package/static/js/selection.js +193 -0
  138. package/static/js/settings.js +206 -0
  139. package/static/js/signoff.js +171 -0
  140. package/static/js/skin.js +56 -0
  141. package/static/js/store.js +35 -0
  142. package/static/js/theme.js +56 -0
  143. package/static/js/threads.js +78 -0
  144. package/static/js/vendor.d.ts +15 -0
  145. package/static/styles/base.css +223 -0
  146. package/static/styles/chat-tools.css +130 -0
  147. package/static/styles/chat.css +140 -0
  148. package/static/styles/commands.css +156 -0
  149. package/static/styles/diff.css +258 -0
  150. package/static/styles/header.css +114 -0
  151. package/static/styles/layout.css +123 -0
  152. package/static/styles/panels.css +152 -0
  153. package/static/styles/responsive.css +80 -0
  154. package/static/styles/review-actions.css +124 -0
  155. package/static/styles/review.css +473 -0
  156. package/static/styles/skin-github.css +356 -0
  157. 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.