@vintasoftware/pr-review-canvas 0.1.0 → 0.3.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 (98) hide show
  1. package/README.md +30 -28
  2. package/docs/reference.md +142 -98
  3. package/package.json +12 -3
  4. package/pr-review.config.example.yml +12 -31
  5. package/prompts/generation-format.md +4 -4
  6. package/prompts/layering-guidance.md +18 -0
  7. package/skills/pr-review-canvas/SKILL.md +8 -1
  8. package/src/acpx/acpx.ts +21 -4
  9. package/src/acpx/events.ts +5 -1
  10. package/src/acpx/ndjson.ts +3 -1
  11. package/src/acpx/preflight.ts +5 -1
  12. package/src/canvas/export.ts +11 -2
  13. package/src/canvas/name.ts +13 -13
  14. package/src/canvas/zip.ts +4 -1
  15. package/src/chat/chat-manager.ts +16 -3
  16. package/src/chat/context.ts +10 -3
  17. package/src/chat/seed.ts +3 -1
  18. package/src/cli.ts +16 -13
  19. package/src/commands.ts +41 -11
  20. package/src/config.ts +15 -3
  21. package/src/contract/comments.ts +3 -1
  22. package/src/contract/generation-context.ts +3 -1
  23. package/src/contract/review-artifact.ts +14 -8
  24. package/src/contract/state.ts +3 -1
  25. package/src/git/diff-collector.ts +2 -1
  26. package/src/git/git.ts +9 -4
  27. package/src/github/attachments.ts +3 -3
  28. package/src/github/capabilities.ts +5 -1
  29. package/src/github/comments.ts +6 -3
  30. package/src/github/gh.ts +18 -3
  31. package/src/github/post-comment.ts +4 -1
  32. package/src/github/pr.ts +4 -1
  33. package/src/github/threads.ts +5 -1
  34. package/src/project-config.ts +14 -54
  35. package/src/prompt-files.ts +4 -3
  36. package/src/review/doctor.ts +38 -10
  37. package/src/review/install-skill.ts +24 -28
  38. package/src/review/normalize.ts +3 -1
  39. package/src/review/prepare.ts +24 -8
  40. package/src/review/prompt.ts +17 -11
  41. package/src/review/publish.ts +15 -3
  42. package/src/review/skill-content.ts +20 -0
  43. package/src/review/trim-caps.ts +10 -6
  44. package/src/review/validate.ts +65 -13
  45. package/src/server/app.ts +12 -4
  46. package/src/server/bundle.ts +17 -4
  47. package/src/server/context.ts +14 -2
  48. package/src/server/errors.ts +26 -2
  49. package/src/server/html.ts +2 -2
  50. package/src/server/node-server.ts +4 -2
  51. package/src/server/routes/api.ts +29 -5
  52. package/src/server/routes/chat-routes.ts +30 -9
  53. package/src/server/routes/pages.ts +3 -1
  54. package/src/server/routes/review-routes.ts +19 -4
  55. package/src/server/sse.ts +3 -1
  56. package/src/store/atomic-json.ts +5 -1
  57. package/src/store/canvas-store.ts +20 -6
  58. package/src/store/derived-store.ts +5 -1
  59. package/src/store/pr-store.ts +2 -1
  60. package/src/store/state-store.ts +2 -1
  61. package/static/brand.svg +19 -0
  62. package/static/js/api.js +15 -3
  63. package/static/js/app.js +8 -2
  64. package/static/js/chat-panel.js +93 -0
  65. package/static/js/chat.js +38 -15
  66. package/static/js/composer.js +6 -3
  67. package/static/js/diagram.js +2 -1
  68. package/static/js/diff-decorations.js +5 -3
  69. package/static/js/diff-renderer.js +6 -1
  70. package/static/js/dom.js +5 -7
  71. package/static/js/empty-state.js +3 -1
  72. package/static/js/header.js +1 -1
  73. package/static/js/interactions.js +55 -15
  74. package/static/js/keyboard.js +7 -2
  75. package/static/js/layers.js +23 -11
  76. package/static/js/links.js +8 -2
  77. package/static/js/nav.js +5 -2
  78. package/static/js/overview.js +32 -4
  79. package/static/js/points.js +3 -2
  80. package/static/js/progress.js +2 -1
  81. package/static/js/proposed-comment.js +4 -1
  82. package/static/js/quick-questions.js +2 -1
  83. package/static/js/regenerate.js +4 -1
  84. package/static/js/settings.js +1 -1
  85. package/static/js/signoff.js +6 -2
  86. package/static/styles/base.css +16 -6
  87. package/static/styles/chat-panel.css +81 -0
  88. package/static/styles/chat-tools.css +28 -0
  89. package/static/styles/chat.css +1 -1
  90. package/static/styles/commands.css +4 -4
  91. package/static/styles/diff.css +1 -1
  92. package/static/styles/header.css +18 -4
  93. package/static/styles/layout.css +4 -4
  94. package/static/styles/responsive.css +1 -15
  95. package/static/styles/review.css +24 -3
  96. package/static/styles/skin-github.css +93 -100
  97. package/static/styles.css +13 -12
  98. package/prompts/layers-default.md +0 -13
package/README.md CHANGED
@@ -43,8 +43,6 @@ Install the command globally once, for use in any project:
43
43
  npm install -g @vintasoftware/pr-review-canvas
44
44
  ```
45
45
 
46
- The npm installation command will be available after the first release.
47
-
48
46
  ## Set up a project
49
47
 
50
48
  ```bash
@@ -54,15 +52,19 @@ pr-review doctor --all-checks
54
52
  ```
55
53
 
56
54
  `install-skill` sets up **both Claude Code and Codex** in one command: `.claude/skills/pr-review-canvas`
57
- and `.agents/skills/pr-review-canvas`, respectively. It also adds `.pr-review/settings.yml` to the
55
+ and `.agents/skills/pr-review-canvas`, respectively. These are portable copies you can commit to Git.
56
+ Re-run `pr-review install-skill` after upgrading the CLI to refresh them. It also adds `.pr-review/settings.yml` to the
58
57
  project's `.gitignore`. Restart your coding agent if the skill
59
58
  does not appear. Repeat this setup for each project you want to review.
60
59
 
61
60
  `doctor` checks Git, your GitHub remote, the GitHub CLI and its login, write access to the local
62
- canvas directory, and whether the skill is installed. It prints a JSON report with a result for
61
+ canvas directory, and whether installed skills match the current package. It prints a JSON report with a result for
63
62
  each check and suggested fixes for failures. `doctor --all-checks` also checks that `acpx` runs and
64
63
  reports its version. Exit code `0` means all checks passed.
65
64
 
65
+ `serve` automatically runs the skill check and warns on stderr if a skill is missing, outdated,
66
+ or modified. The warning includes the reinstall command and does not block startup.
67
+
66
68
  ### Optional: AI Chat install
67
69
 
68
70
  To ask questions about a PR inside the canvas, install `acpx` globally:
@@ -131,45 +133,34 @@ Canvas generation follows the [skill's model rules](skills/pr-review-canvas/SKIL
131
133
 
132
134
  ### Project prompt templates
133
135
 
134
- A global install reads `pr-review.config.yml` from the project root. Use its `prompts`
135
- map to replace individual templates with files you keep in the project's Git repository:
136
+ Customize generation and AI Chat prompts with the `prompts` map in your project's
137
+ `pr-review.config.yml`:
136
138
 
137
139
  ```yaml
138
140
  prompts:
139
- generation-format.md: review-prompts/generation-format.md
140
- generation-surfacing.md: review-prompts/generation-surfacing.md
141
- chat-seed.md: review-prompts/chat-seed.md
141
+ generation-format.md: review-prompts/generation-format.md
142
+ generation-surfacing.md: review-prompts/generation-surfacing.md
143
+ chat-seed.md: review-prompts/chat-seed.md
142
144
  ```
143
145
 
144
- To start from the installed templates (for an npm global install):
146
+ Copy the installed templates to start editing (for an npm global install):
145
147
 
146
148
  ```bash
147
149
  mkdir -p review-prompts
148
150
  cp "$(npm root -g)/@vintasoftware/pr-review-canvas/prompts/"*.md review-prompts/
149
151
  ```
150
152
 
151
- Edit the copies and add entries only for the templates you want to override. Commit
152
- `pr-review.config.yml` and the referenced files together. Paths resolve from the project
153
- root, including when running from a subdirectory or using `--repo`. Absolute paths also
154
- work for personal templates shared across projects. Omitted entries use the installed
155
- package's defaults; a configured file that cannot be read causes an error.
156
-
157
- The six supported keys are `generation-format.md` (schema and output rules),
158
- `generation-strict.md` and `generation-surfacing.md` (mode wrappers),
159
- `quality-standards.md` (bundled code standards), `layers-default.md` (taxonomy prose),
160
- and `chat-seed.md` (the opening AI Chat instructions). `generation.mode` still selects
161
- the wrapper. The rulebook still takes precedence over code standards, and configured
162
- layers and caps still supply the template data.
163
-
164
- Each file replaces a whole template. Preserve its `{{TOKENS}}`, including `{{FORMAT}}`
165
- in generation wrappers, to keep the generated context and output contract. Unknown
166
- generation tokens fail rendering. Chat leaves unknown tokens as written. Prompt edits
167
- do not change the output schema or validation rules enforced by the tool. Overrides
168
- remain yours across tool upgrades; compare them with new bundled templates when upgrading.
153
+ Edit the copies and configure only the templates you want to replace. Paths are relative
154
+ to the project root. Omitted entries use the bundled defaults. Keep each template's
155
+ `{{TOKENS}}`, including `{{FORMAT}}` in generation wrappers. Commit the config and
156
+ referenced files together.
169
157
 
170
158
  Run `prepare` again to apply generation edits (use `--force` for an existing canvas).
171
159
  Restart the server after changing the config; chat template edits apply to new threads.
172
160
 
161
+ See the [prompt template reference](docs/reference.md#prompt-templates) for supported keys,
162
+ path rules, validation, and upgrades.
163
+
173
164
  ## Contributing
174
165
 
175
166
  In a clone of this tool, use pnpm for the shared lockfile and development checks:
@@ -177,11 +168,22 @@ In a clone of this tool, use pnpm for the shared lockfile and development checks
177
168
  ```bash
178
169
  corepack pnpm --version
179
170
  corepack pnpm install --frozen-lockfile
171
+ corepack pnpm hooks:install
180
172
  corepack pnpm exec playwright install --with-deps chromium
181
173
  corepack pnpm verify
182
174
  corepack pnpm start --repo /path/to/your-project
183
175
  ```
184
176
 
177
+ The pre-commit hook runs `pnpm precommit`: lint, formatting, strict type checks, and tests.
178
+ Any failure blocks the commit. Run `pnpm hooks:install`
179
+ once per clone to enable it. Use `pnpm lint:fix` and `pnpm format` to apply automatic fixes.
180
+ CI runs the same checks through `pnpm verify`, with coverage executing the unit tests once.
181
+
182
+ Run the full `pnpm verify` before pushing. Keep branch coverage at least 96% when adding or
183
+ changing behavior, leaving a margin above CI's 95% minimum. Cover meaningful failure and boundary
184
+ cases rather than lowering thresholds. Each CI job uploads `coverage-node-<version>` with branch
185
+ locations and a summary; locally, these reports are in `coverage/` after `pnpm coverage`.
186
+
185
187
  Run `pr-review --help` for CLI commands. Local data goes in the project's `.pr-review/`
186
188
  directory; keep it out of Git.
187
189
 
package/docs/reference.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # CLI and configuration reference
2
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.
3
+ This reference covers command options, configuration, and troubleshooting for local PR reviews.
4
+ For setup and the basic review workflow, see the [README](../README.md).
6
5
 
7
6
  - [CLI options](#cli-options)
8
7
  - [Project config](#project-config)
@@ -16,14 +15,14 @@ that matters when customizing or troubleshooting a review.
16
15
 
17
16
  ### Repository and runtime options
18
17
 
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 |
18
+ | Option | Applies to | Default and behavior |
19
+ | -------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------- |
20
+ | `--repo <dir>` | All commands | Uses the current directory when omitted; resolves the repository root from there |
21
+ | `--data-dir <dir>` | All except `install-skill` | Overrides `PR_REVIEW_DATA_DIR`, then the default `<main checkout>/.pr-review` |
22
+ | `--port <n>` | `serve` | Overrides `PR_REVIEW_PORT`, then `3010`; accepts 1–65535 |
23
+ | `--agent claude\|codex` | `serve` | Overrides the saved chat agent for this run |
24
+ | `--model <id>` | `serve` | Overrides the saved chat model for this run |
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 |
27
26
 
28
27
  Repository operations require an `origin` remote on **github.com**. GitHub Enterprise Server
29
28
  hosts are not supported. Fetching a PR does not check out its branch.
@@ -75,6 +74,10 @@ pr-review import <zip> [--pr <n>] [--force]
75
74
  the archive; it does not select the commit.
76
75
  - `--out` defaults to the data directory's `exports/` folder. Supply an existing directory to
77
76
  keep the generated filename, or a full `.zip` file path to choose a name.
77
+ - Generated names follow `pr-<number>-<YYYYMMDDTHHmmssZ>-<sha8>-<owner>-<repo>-canvas.zip`,
78
+ for example `pr-42-20260910T110000Z-aaaaaaaa-acme-widgets-canvas.zip`. The timestamp is the
79
+ canvas generation time in UTC, to seconds, so exports sort chronologically within each PR.
80
+ Before a PR exists, `ref-` replaces `pr-<number>-`. Re-exporting the same canvas keeps its name.
78
81
  - Export returns `status`, `path`, `name`, `headSha`, and `prNumber` when supplied or stored.
79
82
  - `import --pr` compares the imported canvas with that PR's current head. Without it, import does
80
83
  not check against a live PR.
@@ -101,8 +104,19 @@ Relative custom paths resolve from the command's working directory. For example:
101
104
  pr-review install-skill --codex-dir ~/.codex/skills
102
105
  ```
103
106
 
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.
107
+ Installation copies the bundled skill on every platform. The copies and their `.pr-review-install`
108
+ marker files can be committed to Git. Re-running the command refreshes managed copies and replaces
109
+ legacy symlinks. An unmanaged directory requires `--force` to replace it.
110
+
111
+ Each installed `SKILL.md` records `metadata.body-sha256` in its YAML frontmatter. The SHA-256 hash
112
+ covers the body after the closing frontmatter delimiter, with CRLF normalized to LF. `doctor`
113
+ compares the recorded hash and actual body against the skill bundled with the running CLI. Any
114
+ outdated or modified copy in `.claude/skills` or `.agents/skills` fails the skill check, even if the
115
+ other copy is current. Refresh copies with `pr-review install-skill` (repeat any custom directory
116
+ flags used during installation). Automatic discovery checks the two default directories.
117
+
118
+ `serve` runs this skill check automatically and prints failures with a repair hint to stderr.
119
+ Warnings do not prevent the server from starting. Use `doctor --all-checks` for full diagnostics.
106
120
  The `.gitignore` update always applies to the selected repository root, even with custom skill
107
121
  directories.
108
122
 
@@ -115,13 +129,13 @@ JSON error. `serve` stays running and writes its startup message to stderr.
115
129
  Command failures use `{ "error": { "code", "message", "hint" } }`, with `hint` optional.
116
130
  Validation failures from `validate` use its report format instead.
117
131
 
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` |
132
+ | Exit code | Meaning |
133
+ | --------- | ------------------------------------------------------------------------ |
134
+ | `0` | Success |
135
+ | `1` | Error, including a failed `doctor` check |
136
+ | `2` | Command usage error, such as an unknown command or missing required flag |
137
+ | `4` | GitHub CLI missing or unauthenticated |
138
+ | `5` | Validation failed in `validate` or `publish` |
125
139
 
126
140
  `doctor` reports failed checks with exit `1`, including authentication failures.
127
141
 
@@ -134,20 +148,20 @@ Lists you supply replace their defaults.
134
148
  Path patterns match repository-relative paths. `**` crosses directories; `*` and `?` match
135
149
  within one path segment.
136
150
 
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
+ | Key | Default | Details |
152
+ | ------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
153
+ | `version` | `1` | The only supported configuration version |
154
+ | `rulebook` | Unset | Path to a Markdown file of project code standards, resolved from the repository root; these standards take precedence over bundled standards |
155
+ | `layers` | `[]` | Optional review guidance; each entry has `id`, `title`, `description`, and optional `paths` patterns. The agent may combine, split, or reorder groups. When omitted or empty, it chooses semantic sections from the change |
156
+ | `highRisk` | `[]` | Entries with a `pattern` glob and `label`; matching changes receive risk labels and cannot go in the Other layer |
157
+ | `generation.mode` | `strict` | See [generation modes](#generation-modes) |
158
+ | `generation.maxRepairRounds` | `3` | Failed validation rounds allowed by the generation skill |
159
+ | `generation.inlineDiffMaxLines` | `1500` | Maximum diff length to include directly in the generation prompt |
160
+ | `generation.smallPrHunks` | `10` | At or below this hunk count, the prompt asks for one layer unless concerns differ |
161
+ | `generation.caps` | See below | Overrides individual text limits |
162
+ | `tests.patterns` | `['**/*.test.*', '**/*.spec.*', '**/__tests__/**']` | Paths treated as tests for review ordering and labels |
163
+ | `chat.enabled` | `true` | Set to `false` to disable AI Chat |
164
+ | `prompts` | Bundled templates | See [prompt templates](#prompt-templates) for supported keys and behavior |
151
165
 
152
166
  Generation's numeric options and text caps must be positive integers. An empty `layers` list
153
167
  provides no suggested groups; an empty `tests.patterns` list recognizes no files as tests.
@@ -164,23 +178,54 @@ not change an already prepared generation or an existing canvas.
164
178
  Both modes read the project rulebook and use the same validation and review controls. The mode
165
179
  affects canvas generation; chat answers the reviewer's selected question.
166
180
 
181
+ ### Prompt templates
182
+
183
+ The `prompts` map in `pr-review.config.yml` accepts these keys:
184
+
185
+ | Key | Purpose |
186
+ | ------------------------- | ------------------------------------- |
187
+ | `generation-format.md` | Schema and output rules |
188
+ | `generation-strict.md` | Instructions for strict mode |
189
+ | `generation-surfacing.md` | Instructions for surfacing mode |
190
+ | `quality-standards.md` | Bundled code standards |
191
+ | `layering-guidance.md` | Guidance for grouping related changes |
192
+ | `chat-seed.md` | Opening AI Chat instructions |
193
+
194
+ Each configured file replaces a whole template. Paths resolve from the project root,
195
+ including when running from a subdirectory or using `--repo`. Absolute paths work for
196
+ personal templates shared across projects. Omitted entries use the installed package's
197
+ defaults. A configured file that cannot be read causes an error.
198
+
199
+ `generation.mode` selects the generation wrapper. The project rulebook takes precedence
200
+ over code standards. Configured layers and caps supply data to the templates.
201
+
202
+ Preserve `{{TOKENS}}`, including `{{FORMAT}}` in generation wrappers, so generated prompts
203
+ include the context and output requirements. Unknown generation tokens fail rendering;
204
+ chat leaves unknown tokens as written. Prompt edits do not change the output schema or
205
+ validation rules enforced by the tool.
206
+
207
+ Run `prepare` again to apply generation edits (use `--force` for an existing canvas).
208
+ Restart the server after changing the config; chat template edits apply to new threads.
209
+ Custom templates persist across tool upgrades. Compare them with the new bundled templates
210
+ when upgrading.
211
+
167
212
  ### Text limits
168
213
 
169
214
  Set any of these keys under `generation.caps`. Prose limits count visible characters, so Markdown
170
215
  link targets do not count. `diagram` counts raw Mermaid source characters.
171
216
 
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 |
217
+ | Key | Default |
218
+ | -------------- | ------- |
219
+ | `summary` | 1200 |
220
+ | `layerTitle` | 60 |
221
+ | `rationale` | 300 |
222
+ | `decisions` | 600 |
223
+ | `checkByHand` | 400 |
224
+ | `annotation` | 240 |
225
+ | `pointTitle` | 90 |
226
+ | `pointBody` | 600 |
227
+ | `testBehavior` | 120 |
228
+ | `diagram` | 1500 |
184
229
 
185
230
  The canvas has a separate limit of 12 attention points, including entries generated from missing
186
231
  tests. Increasing text caps does not increase that limit.
@@ -191,7 +236,7 @@ Custom patterns replace the JavaScript/TypeScript defaults. For example, a Pytho
191
236
 
192
237
  ```yaml
193
238
  tests:
194
- patterns: ['**/test_*.py', '**/tests/**']
239
+ patterns: ['**/test_*.py', '**/tests/**']
195
240
  ```
196
241
 
197
242
  Test recognition controls ordering, but matching a test to its source file currently follows
@@ -200,18 +245,17 @@ placed in Other while its source is in a regular layer.
200
245
 
201
246
  ## Local settings and storage
202
247
 
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:
248
+ The data directory's `settings.yml` accepts these keys and values:
205
249
 
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 |
250
+ | Key | Default | Accepted values |
251
+ | ---------------- | ---------- | ------------------------------------------------ |
252
+ | `version` | `1` | `1` |
253
+ | `skin` | `terminal` | `terminal`, `github` |
254
+ | `theme` | `auto` | `auto`, `light`, `dark` |
255
+ | `agent` | `claude` | `claude`, `codex` |
256
+ | `model` | `null` | A model ID, or `null` for the agent's default |
257
+ | `chatTimeoutSec` | `600` | Integer seconds, 30–3600 |
258
+ | `maxTurns` | `null` | Integer 1–100, or `null` for the agent's default |
215
259
 
216
260
  Invalid settings fall back to defaults. URL parameters `?skin=github&theme=light` can override
217
261
  appearance for one page load without saving it.
@@ -230,13 +274,13 @@ Deleting the directory loses saved preferences, canvases, progress, and chat his
230
274
 
231
275
  Append a fragment to `/review/<pr-number>`:
232
276
 
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` |
277
+ | Target | Fragment example |
278
+ | ------------------- | --------------------------- |
279
+ | Layer | `#layer:data-access` |
280
+ | File | `#file:src/store.ts` |
281
+ | Hunk | `#hunk:src/store.ts#2` |
282
+ | New-side line range | `#line:src/store.ts:40-52` |
283
+ | Old-side line | `#line:src/store.ts:40:old` |
240
284
 
241
285
  Use the layer key and file path from the canvas. Links open the target file when needed; if a
242
286
  line is unavailable, navigation uses the nearest visible row. Recipients need their own running
@@ -300,41 +344,41 @@ sandbox for the agent. Its access also depends on the agent's own permissions. D
300
344
 
301
345
  ## Troubleshooting
302
346
 
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 |
347
+ | Symptom or code | Next step |
348
+ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
349
+ | `NOT_A_REPO` | Run inside a Git clone or pass `--repo <dir>` |
350
+ | `NO_ORIGIN` | Check that `origin` points to a repository on github.com |
351
+ | `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 |
352
+ | `GITHUB_API_ERROR` | Read the underlying error for permissions, rate limits, connectivity, or GitHub service problems |
353
+ | `PR_NOT_FOUND` | Check the PR number, repository, and your access |
354
+ | `CANVAS_NOT_FOUND` | Generate or import a canvas for the requested commit |
355
+ | `CANVAS_INVALID` | Read the format errors; re-export or regenerate the canvas |
356
+ | `CANVAS_REPO_MISMATCH` | Check which clone is open; use `import --force` only when importing from the other repository is intentional |
357
+ | `CANVAS_TOO_LARGE` | The archive exceeds the 20 MiB import limit |
358
+ | `CANVAS_STALE` | The PR head moved; prepare again for the current commit |
359
+ | `MODEL_INVALID` | Fix the reported problems in `model.json`, validate, then publish again |
360
+ | `SKILL_DIR_EXISTS` | The destination contains a customized directory; preserve it elsewhere before replacing it with `--force` |
361
+ | `CHAT_BUSY` | Wait for the running reply or press **stop** |
362
+ | `AGENT_AUTH_REQUIRED` | Sign in through the selected agent's CLI, then retry |
363
+ | `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` |
364
+ | `AGENT_INCOMPLETE` | Retry the message or increase the chat timeout |
365
+ | `COMMENT_FORBIDDEN` | Check the GitHub account's repository access and token permissions |
366
+ | `COMMENT_LINE_NOT_IN_DIFF` | Choose a line shown in the current diff |
367
+ | `SIGNOFF_INCOMPLETE` | Mark every layer except Other reviewed for this head |
368
+ | `FORBIDDEN_HOST` / `CROSS_ORIGIN` | Open the local server using `localhost` or `127.0.0.1` and submit actions from that page |
325
369
 
326
370
  ### Validation diagnostics
327
371
 
328
372
  Validation reports name the field, file, hunk, or line to fix. Common groups are:
329
373
 
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 |
374
+ | Codes | What to check |
375
+ | --------------------------------------------------------------- | -------------------------------------------------------------- |
376
+ | `SCHEMA`, `TEXT_TOO_LONG` | Required fields, types, and text limits |
377
+ | `HUNK_UNASSIGNED`, `HUNK_DUPLICATE`, `HUNK_UNKNOWN` | Each known hunk belongs to exactly one layer |
378
+ | `PATH_UNKNOWN`, `TEST_PATH_UNKNOWN` | Referenced files exist in the relevant diff or PR head |
379
+ | `LAYER_EMPTY`, `LAYER_KEY_DUPLICATE` | Layers contain hunks and have unique keys |
380
+ | `OTHER_DUPLICATE`, `OTHER_NOT_LAST`, `RISK_IN_OTHER` | At most one Other layer, last, without risk-tagged changes |
381
+ | `TEST_NOT_LAST`, `TEST_IN_OTHER` | Tests follow the code they cover and use the appropriate layer |
382
+ | `ANNOTATION_OUTSIDE_HUNK`, `POINT_OUTSIDE_DIFF`, `FOLD_INVALID` | Locations and fold ranges fit the assigned diff |
383
+ | `TOO_MANY_POINTS` | Count explicit points and missing-test entries together |
384
+ | `LINK_UNRESOLVED`, `DIAGRAM_NODE_UNKNOWN`, `DIAGRAM_LIMIT` | Link targets, diagram node IDs, and diagram counts |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vintasoftware/pr-review-canvas",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Localhost PR review canvas: layered diffs, attention points, and GitHub comments for one PR",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,13 +10,20 @@
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 .githooks",
13
14
  "test:watch": "vitest",
14
15
  "test:browser": "playwright test",
15
16
  "coverage": "vitest run --coverage",
16
17
  "typecheck": "tsc --noEmit",
17
18
  "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"
19
+ "verify": "pnpm check && pnpm coverage && pnpm test:browser --workers=2 && pnpm test:package",
20
+ "prepublishOnly": "pnpm verify",
21
+ "lint": "oxlint --deny-warnings",
22
+ "lint:fix": "oxlint --fix --deny-warnings",
23
+ "format": "oxfmt --write",
24
+ "format:check": "oxfmt --check",
25
+ "check": "pnpm lint && pnpm format:check && pnpm typecheck",
26
+ "precommit": "pnpm check && pnpm test"
20
27
  },
21
28
  "dependencies": {
22
29
  "@highlightjs/cdn-assets": "^11.12.0",
@@ -36,6 +43,8 @@
36
43
  "@types/node": "^24.13.3",
37
44
  "@vitest/coverage-v8": "^4.1.10",
38
45
  "happy-dom": "20.11.2",
46
+ "oxfmt": "^0.68.0",
47
+ "oxlint": "^1.83.0",
39
48
  "typescript": "^5.9.3",
40
49
  "vite": "~8.0.16",
41
50
  "vitest": "^4.1.10"
@@ -11,35 +11,16 @@ version: 1
11
11
  # generation-strict.md: review-prompts/generation-strict.md
12
12
  # generation-surfacing.md: review-prompts/generation-surfacing.md
13
13
  # quality-standards.md: review-prompts/quality-standards.md
14
- # layers-default.md: review-prompts/layers-default.md
14
+ # layering-guidance.md: review-prompts/layering-guidance.md
15
15
  # chat-seed.md: review-prompts/chat-seed.md
16
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.
17
+ # Optional layer guidance. Omit or leave empty for agent-chosen semantic sections.
18
+ layers: []
19
+ # layers:
20
+ # - id: checkout
21
+ # title: Checkout
22
+ # description: Cart totals, payment processing, and order creation.
23
+ # paths: ['src/checkout/**']
43
24
 
44
25
  # Blast radius tags. Glob patterns against changed paths; the label shows in the header and the rail.
45
26
  highRisk:
@@ -49,10 +30,10 @@ highRisk:
49
30
  label: auth
50
31
 
51
32
  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
33
+ mode: strict # strict: quality review; surfacing: walkthrough that audits as it reads
34
+ maxRepairRounds: 3 # publish retries the skill may make after a failed validation
54
35
  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
36
+ smallPrHunks: 10 # at most this many hunks: one layer unless concerns differ, fewer annotations
56
37
  # caps: # override the text caps (characters)
57
38
  # summary: 1800
58
39
  # rationale: 300
@@ -65,4 +46,4 @@ tests:
65
46
  patterns: ['**/*.test.*', '**/*.spec.*', '**/__tests__/**']
66
47
 
67
48
  chat:
68
- enabled: true # false removes the chat pane and its routes
49
+ enabled: true # false removes the chat pane and its routes
@@ -39,11 +39,11 @@ hunk in that file's patch.
39
39
 
40
40
  ## Layering rules
41
41
 
42
- The project's default layers, in review order, are the default taxonomy:
42
+ Project-configured layers (optional guidance):
43
43
 
44
- {{DEFAULT_LAYERS}}
44
+ {{CONFIGURED_LAYERS}}
45
45
 
46
- {{LAYERS_DEFAULT}}
46
+ {{LAYERING_GUIDANCE}}
47
47
 
48
48
  - **Every hunk id must appear in exactly one layer.** The validator rejects an unassigned or
49
49
  duplicated hunk. A file's hunks may be spread over several layers.
@@ -55,7 +55,7 @@ The project's default layers, in review order, are the default taxonomy:
55
55
  - Test files go at the **end** of the layer whose code they cover, never in a layer of their own,
56
56
  and into Other only together with the code they cover. This project counts a file as a test when
57
57
  its path matches one of: {{TEST_PATTERNS}}.
58
- - No empty layers. Set `defaultLayerId` when a layer derives from a default; add, split, or reorder
58
+ - No empty layers. Set `defaultLayerId` only when a layer derives from a configured layer; add, split, or reorder
59
59
  layers when the {{TARGET_WORD}} reads better that way. Two to eight layers is typical for a
60
60
  {{TARGET_WORD}} of any size; see the size note below for a small one.
61
61
  - Each layer's `key` is a short lowercase slug (`auth-session`); links use it.
@@ -0,0 +1,18 @@
1
+ Choose semantic sections from the actual change: group hunks that explain one behavior, concern,
2
+ or decision, even when they span files or directories. Give each layer a specific title that tells
3
+ the reviewer what to understand.
4
+
5
+ When the project config lists layers, use their descriptions, path hints, and order as guidance.
6
+ Adapt, combine, split, or reorder them to fit the change. When no layers are configured, choose
7
+ sections yourself without assuming an architecture or a fixed list of categories.
8
+
9
+ Order sections by reviewer value. Lead with the main behavior changes, algorithms, state
10
+ transitions, or API changes. Follow with the integration and wiring that support them. Put
11
+ mechanical or low-importance hunks in Other at the end, subject to the eligibility rules below.
12
+ Bring a prerequisite earlier when it helps explain the main change. These priorities guide the
13
+ reading order; choose the number and names of sections to suit this diff.
14
+
15
+ Pair each test with its subject. A test file sits at the end of the layer whose code it covers,
16
+ never in a layer of its own. Match by stem: `lab-mapper.test.ts` covers `lab-mapper.ts`, and a
17
+ file under `__tests__/` covers the file with the same name one directory up. A test whose subject
18
+ is in Other may sit in Other; a test whose subject is in a real layer must sit in that layer.
@@ -39,7 +39,14 @@ pr-review prepare --base <ref> --head <ref> [--force]
39
39
  Progress goes to stderr. The last stdout line is JSON:
40
40
 
41
41
  ```json
42
- { "canvasDir": "...", "headSha": "...", "mergeBaseSha": "...", "promptPath": "...", "contextPath": "...", "status": "prepared" }
42
+ {
43
+ "canvasDir": "...",
44
+ "headSha": "...",
45
+ "mergeBaseSha": "...",
46
+ "promptPath": "...",
47
+ "contextPath": "...",
48
+ "status": "prepared"
49
+ }
43
50
  ```
44
51
 
45
52
  - `status: "exists"` means a canvas already exists for this head. Stop and tell the user: