pi-pr-review 1.6.1 → 1.6.3

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.
@@ -0,0 +1,52 @@
1
+ name: Pull Request
2
+
3
+ on:
4
+ pull_request:
5
+ types:
6
+ - opened
7
+ - edited
8
+ - synchronize
9
+ - reopened
10
+ - ready_for_review
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ title:
17
+ name: Validate PR title
18
+ runs-on: ubuntu-latest
19
+ timeout-minutes: 5
20
+ steps:
21
+ - name: Check Conventional Commit format
22
+ env:
23
+ PR_TITLE: ${{ github.event.pull_request.title }}
24
+ run: |
25
+ node <<'NODE'
26
+ const title = process.env.PR_TITLE ?? "";
27
+ const conventionalTitle = /^(feat|fix|perf|revert|docs|style|refactor|test|chore)(\([a-z0-9][a-z0-9._/-]*\))?!?: \S.*$/;
28
+
29
+ if (!conventionalTitle.test(title)) {
30
+ console.error(`Invalid PR title: ${title}`);
31
+ console.error("Use: <type>(optional-scope): description");
32
+ console.error("Allowed types: feat, fix, perf, revert, docs, style, refactor, test, chore");
33
+ console.error("Add ! before : for a breaking change, for example feat!: description");
34
+ process.exit(1);
35
+ }
36
+ NODE
37
+
38
+ test:
39
+ name: Test
40
+ runs-on: ubuntu-latest
41
+ timeout-minutes: 20
42
+ steps:
43
+ - name: Check out repository
44
+ uses: actions/checkout@v4
45
+
46
+ - name: Set up Bun
47
+ uses: oven-sh/setup-bun@v2
48
+ with:
49
+ bun-version: 1.2.15
50
+
51
+ - name: Run tests
52
+ run: bun test
@@ -0,0 +1,69 @@
1
+ name: Release Please
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: release-please-${{ github.ref }}
11
+ cancel-in-progress: false
12
+
13
+ jobs:
14
+ release:
15
+ name: Create release PR or GitHub release
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 10
18
+ permissions:
19
+ contents: read
20
+ outputs:
21
+ release_created: ${{ steps.release.outputs.release_created }}
22
+ steps:
23
+ - name: Create nerv-ops installation token
24
+ id: app-token
25
+ uses: actions/create-github-app-token@v2
26
+ with:
27
+ app-id: ${{ vars.NERV_OPS_APP_ID }}
28
+ private-key: ${{ secrets.NERV_OPS_PRIVATE_KEY }}
29
+
30
+ - name: Run Release Please
31
+ id: release
32
+ uses: googleapis/release-please-action@v4
33
+ with:
34
+ config-file: release-please-config.json
35
+ manifest-file: .release-please-manifest.json
36
+ token: ${{ steps.app-token.outputs.token }}
37
+
38
+ publish:
39
+ name: Test and publish to npm
40
+ needs: release
41
+ if: ${{ needs.release.outputs.release_created == 'true' }}
42
+ runs-on: ubuntu-latest
43
+ timeout-minutes: 20
44
+ permissions:
45
+ contents: read
46
+ id-token: write
47
+ steps:
48
+ - name: Check out release commit
49
+ uses: actions/checkout@v4
50
+
51
+ - name: Set up Node.js
52
+ uses: actions/setup-node@v4
53
+ with:
54
+ node-version: 22
55
+ registry-url: https://registry.npmjs.org
56
+
57
+ - name: Set up Bun
58
+ uses: oven-sh/setup-bun@v2
59
+ with:
60
+ bun-version: 1.2.15
61
+
62
+ - name: Install npm with trusted publishing support
63
+ run: npm install --global npm@11.5.1
64
+
65
+ - name: Test
66
+ run: bun test
67
+
68
+ - name: Publish to npm
69
+ run: npm publish --access public --provenance
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "1.6.3"
3
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## [1.6.3](https://github.com/10ego/pi-pr-review/compare/v1.6.2...v1.6.3) (2026-07-13)
4
+
5
+
6
+ ### Performance Improvements
7
+
8
+ * **review:** optimize parallel review execution ([#5](https://github.com/10ego/pi-pr-review/issues/5)) ([4ea1a76](https://github.com/10ego/pi-pr-review/commit/4ea1a7627f5c5fb7a8022a97fe2c24bb44643d2a))
9
+
10
+ ## [1.6.2](https://github.com/10ego/pi-pr-review/compare/v1.6.1...v1.6.2) (2026-07-11)
11
+
12
+
13
+ ### Miscellaneous Chores
14
+
15
+ * **release:** automate versioning and npm publishing ([585e961](https://github.com/10ego/pi-pr-review/commit/585e9616a85153a8edb03ec66acb7b75739706b0))
16
+ * **release:** version every conventional PR ([be175e8](https://github.com/10ego/pi-pr-review/commit/be175e811bca1a0e74bb8e56d5148da80d2207b0))
package/README.md CHANGED
@@ -6,11 +6,11 @@ Pass a PR number and pi will:
6
6
 
7
7
  1. Resolve the PR in the **current directory's git repo** via `gh`.
8
8
  2. Derive the **base branch** and **head (merging) branch** automatically from the PR.
9
- 3. Review the base↔head diff with disciplined passes (overview, convention compliance, bugs, security/perf, readability), optional trusted user-level named baseline verification, then validate each candidate.
10
- 4. Return a **full structured review**: overview, strengths, verification, findings at **every** severity (`nit P3 P2 → P1 → P0`) with a blocking flag, correctness/security/performance notes, and a verdict.
9
+ 3. Review the base↔head diff with four focused heavy lenses plus a light overview/minor scan, optional trusted user-level named baseline verification, then validate each candidate. Use `--full` to add convention/maintainability review.
10
+ 4. Return a **structured review**: overview, strengths, verification, P0–P2 findings plus at most three direct-diff P3/nits by default, correctness/security/performance notes, and a verdict. `--full` reports every qualifying severity (`nit → P0`).
11
11
  5. Optionally publish one formal GitHub `COMMENT` review with a top-level body and associated inline comments.
12
12
 
13
- **Captures everything, then ranks it.** Unlike a high-signal-only reviewer, it does not discard minor issues nits, style, naming, missing edge cases, and "worth confirming" observations are all reported as low-severity findings. The **verdict** depends only on *blocking* (P0/P1) findings, so a clean PR is still approved while its nits are still recorded.
13
+ **Major coverage by default, exhaustive minors on demand.** The default runs four independent heavy P0–P2 lenses and permits at most three direct-diff P3/nits from the light overview, reducing model and validation work without dropping lifecycle, contracts, security, or resource coverage. Use `--full` for exhaustive conventions, maintainability, style, naming, and minor findings. The **verdict** always depends only on blocking P0/P1 findings.
14
14
 
15
15
  No model name is hardcoded anywhere. The package ships an extension that adds **tiered review subagents** — `light` / `medium` / `heavy` — that you map to whatever models you like. Independent review passes fan out through a batch tool so overview, conventions/maintainability, correctness, and security/performance can run in parallel. If the extension isn't loaded, the same prompt runs every pass inline on your current session model, so it always works.
16
16
 
@@ -35,6 +35,8 @@ pi install -l npm:pi-pr-review
35
35
 
36
36
  For local development only, you can point pi at a checkout with `pi install ./pi-pr-review` (add `-l` for project scope).
37
37
 
38
+ Releases are versioned from conventional squash-merged PR titles and published automatically through npm trusted publishing. See [RELEASING.md](RELEASING.md) for the release and merge policy.
39
+
38
40
  ### Alternative: use the template without packaging
39
41
 
40
42
  The prompt is a plain template — just copy it into a prompts directory pi already scans:
@@ -57,7 +59,7 @@ The `/pr-review-config` command maps three labels to models:
57
59
  | Tier | Used for | Pick a model that is… |
58
60
  |------|----------|----------------------|
59
61
  | `light` | overview / strengths / high-level risk scan | fast + cheap |
60
- | `medium` | convention compliance + readability / maintainability | balanced |
62
+ | `medium` | `--full` convention compliance + readability / maintainability | balanced |
61
63
  | `heavy` | bug + security/logic review | strongest |
62
64
 
63
65
  ```
@@ -151,9 +153,9 @@ Example `pr-review.json`:
151
153
  }
152
154
  ```
153
155
 
154
- Each tier runs in an **isolated `pi` subprocess** on its configured model. The `review_subagents` batch tool runs independent passes concurrently (default `max_parallel: 4`, capped at 6) and returns ordered per-pass results; the older single-pass `review_subagent` tool remains available as a compatibility fallback. If a tier model fails with a retryable quota/rate-limit/capacity error, the subprocess retries that tier's configured `fallbacks` in order. Non-quota failures do not blindly cycle through fallbacks. If a tier is unset, that subagent falls back to the nearest configured tier, then to your pi default model.
156
+ Each tier runs in an **isolated `pi` subprocess** on its configured model. The `review_subagents` batch tool runs independent passes concurrently (default `max_parallel: 4`, capped at 18) and returns ordered per-pass results. `/pr-review` defaults to 5 slots for overview, two focused correctness specialists, security, and performance; at 200–399 KB it uses two balanced whole-file shards (10 concurrent passes), and at 400 KB or larger it uses three (15 concurrent passes). `--full` adds conventions/maintainability and uses 6/12/18 slots. When a caller requests a lower cap and passes must queue, heavy specialists dispatch before medium/light work while results remain in deterministic request order. The complete diff is captured once in a mode-0600 temporary file and loaded by the extension through `context_file`; the assembled child task is piped over stdin instead of expanded into process argv, keeping large diffs out of the parent conversation, tool arguments, and platform argument-size limits. Ordinary passes receive the full diff; sharded passes collectively cover every changed file, and configured specialists can inspect the full path for concrete cross-shard interactions. The two correctness specialists preserve cross-file analysis while narrowing their objectives to reduce critical-path reasoning; error propagation belongs to contracts/data, while ownership/cleanup belongs to the resource specialist and remains correctness-significant. The older single-pass `review_subagent` tool remains available as a compatibility fallback. If a tier model fails with a retryable quota/rate-limit/capacity error, the subprocess retries that tier's configured `fallbacks` in order. Non-quota failures do not blindly cycle through fallbacks. If a tier is unset, that subagent falls back to the nearest configured tier, then to your pi default model.
155
157
 
156
- Thinking resolution and tool policy are independent. For thinking, a supported model-spec `:thinking` suffix wins; otherwise `thinkingLevels[tier]` is passed to the child process, and an unset tier inherits the ambient pi default. Tool policy remains additive and backward compatible: `none` emits Pi's explicit `--no-tools`; `configured` uses the existing `tools` allowlist. A tool call's optional `tool_policy` overrides `toolPolicies[tier]`, which in turn falls back to legacy `configured` behavior. The shipped `/pr-review` prompt explicitly uses `none` only for overview because its complete evidence is supplied in context. Conventions/maintainability and both heavy specialist passes use `configured` repository-context tools so they can inspect surrounding files when needed. Fallback model attempts keep the original pass policy.
158
+ Thinking resolution and tool policy are independent. For thinking, a supported model-spec `:thinking` suffix wins; otherwise `thinkingLevels[tier]` is passed to the child process, and an unset tier inherits the ambient pi default. Tool policy remains additive and backward compatible: `none` emits Pi's explicit `--no-tools`; `configured` uses the existing `tools` allowlist. A tool call's optional `tool_policy` overrides `toolPolicies[tier]`, which in turn falls back to legacy `configured` behavior. The shipped `/pr-review` prompt explicitly uses `none` only for overview because its complete evidence is supplied in context. The `--full` conventions/maintainability pass and all heavy specialist passes use `configured` repository-context tools so they can inspect surrounding files when needed. Fallback model attempts keep the original pass policy.
157
159
 
158
160
  ### Optional trusted verification baselines
159
161
 
@@ -181,9 +183,12 @@ The orchestrator (which fetches the PR, merges findings, and emits the JSON) and
181
183
  Type `/` in the pi editor and pick `pr-review`, or:
182
184
 
183
185
  ```
184
- /pr-review 123 # use autoPostReviews (false by default)
186
+ /pr-review 123 # balanced default: P0-P2 plus up to three P3/nits
187
+ /pr-review 123 --full # comprehensive six-pass, all-severity review
185
188
  /pr-review 123 --comment # force one COMMENT review for this run
186
189
  /pr-review 123 --no-comment # suppress posting for this run
190
+ /pr-review 123 --major-only # P0-P2 only; omits style/nit discovery
191
+ /pr-review 123 --balanced # explicit alias for the balanced default
187
192
  /pr-review 123 --include-closed # review a closed/merged PR without a confirmation prompt
188
193
  /pr-review 123 --review-closed --comment # review and attempt a body-only COMMENT review
189
194
  /pr-review-publish 123 # publish the completed review cached in this session
@@ -192,6 +197,8 @@ Type `/` in the pi editor and pick `pr-review`, or:
192
197
 
193
198
  `123` is the PR number in the current repo.
194
199
 
200
+ The no-flag default retains four independent heavy full-diff lenses (lifecycle, contracts, security, and resources), configured repository tools, model/thinking settings, and source-grounded validation. Heavy passes report P0–P2, while the light overview may contribute at most three direct-diff P3/nits. `--balanced` is an explicit backward-compatible alias for this default. `--major-only` removes minor discovery entirely. `--full` adds the conventions/maintainability pass and exhaustive all-severity reporting. These three flags are mutually exclusive.
201
+
195
202
  ### Closed or merged PRs
196
203
 
197
204
  Closed/merged PRs no longer hard-skip. If you run `/pr-review 123` on a non-open PR, the prompt asks whether to continue before producing a review. Use `--include-closed` or `--review-closed` to proceed non-interactively. When publication is enabled, the extension preemptively folds inline findings into one body-only formal `COMMENT` review; if GitHub rejects it, publication fails explicitly without creating an issue comment.
@@ -285,8 +292,8 @@ pi-pr-review/
285
292
 
286
293
  ### Concurrent review and verification
287
294
 
288
- - The four independent review lenses remain intact. Only overview runs context-only with `--no-tools`; medium and both heavy specialists retain configured tools for surrounding-file validation. All subprocesses use `--no-context-files` because the orchestrator supplies the base review context explicitly, and convention excerpts are sent only to the medium pass instead of every model.
289
- - After gathering PR metadata, the complete diff, and applicable conventions, the orchestrator uses `pr_review_verify` `action=list` to discover zero or more applicable **user-level** names, then selects at most one. Missing config means verification is disabled; project-local profiles are ignored. The model never supplies argv or a timeout.
295
+ - The four independent major-defect lenses remain intact. The default executes five focused base passes: overview/minor hygiene, state/lifecycle correctness, contracts/data correctness, security, and performance. Diffs from 200–399 KB with multiple changed files run every base pass over two whole-file-balanced shards (10 concurrent passes); diffs at least 400 KB use three shards (15 concurrent passes). `--full` adds conventions/maintainability and expands those counts to 6/12/18. Smaller or single-file diffs remain unsharded. The orchestrator captures the diff once without dumping it into its conversation, removes it on every early exit or confirmation pause, and performs final cleanup after validation. The extension appends the bounded regular `context_file` internally for every full-diff pass and pipes the assembled task to child stdin rather than argv; the orchestrator later reads only candidate-specific hunks for independent validation. Only overview runs context-only with `--no-tools`; all heavy specialists and the optional `--full` medium pass retain configured tools for surrounding-file validation. Unsharded correctness specialists receive the complete diff; in sharded reviews every correctness lens covers every shard, and configured passes can inspect the full captured path to validate concrete cross-shard defects. Specialists start from that diff, batch independent evidence reads/checks for concrete candidates, and allow one evidence-driven follow-up instead of serially browsing the repository; every reported finding still requires substantiation. All subprocesses use `--no-context-files`, `--no-skills`, `--no-prompt-templates`, and `--no-themes` because the orchestrator supplies the complete review task explicitly; extension discovery and configured tools remain enabled. In `--full`, convention excerpts are sent only to the medium pass instead of every model.
296
+ - The orchestrator gathers independent PR metadata, diff, identity, convention paths, and `pr_review_verify` `action=list` discovery in one concurrent initial tool turn, then reads only applicable convention files. It selects at most one applicable **user-level** verification name. Missing config means verification is disabled; project-local profiles are ignored. The model never supplies argv or a timeout.
290
297
  - When a profile is selected, the review batch and `action=run` are emitted in the **same assistant turn**. Run accepts only `pr_number`, exact `head_sha`, and `baseline_name`. Before PR-code setup, the extension resolves canonical Git/gh from its startup PATH, uses trusted `gh` metadata to revalidate the exact head, and rejects cross-repository PRs unless `allowForks` is true.
291
298
  - The sole network fetch is isolated in a fresh extension-owned bare staging repository with config and hooks absent. Authentication and askpass exist only during that staging fetch, whose output is fully suppressed and accounted. After exact staged-SHA verification, a secret-free local-path fetch imports the ref into the original repository with `--no-write-fetch-head`, followed by a second exact-SHA check. Original hooks/URL rewrites never see the token. Unauthenticated timeout/abort paths retain bounded diagnostics and byte accounting.
292
299
  - The fixed argv runs without a shell/stdin, with a minimal secret-scrubbed environment and temporary HOME/cache. `totalTimeoutMs` bounds the normal setup+command+termination+reserved-cleanup lifecycle; a fixed 2-second emergency cleanup allowance is unconditionally available to bounded cleanup beyond it. Output uses a shared raw-byte cap, UTF-8/control sanitization, exact dropped-byte counts, and a final serialized cap. Timeout/abort or residual members of the original process group trigger group TERM, then unconditional group KILL after grace, followed by bounded drain. `primaryOutcome`, `terminationOutcome`, and `cleanupOutcome` remain independent.
@@ -294,7 +301,7 @@ pi-pr-review/
294
301
 
295
302
  ### Performance telemetry
296
303
 
297
- Review-tool results expose the effective `toolPolicy`, monotonic `elapsedMs`, per-attempt timing, and observable batch scheduling offsets. In addition, when an accepted `/pr-review` reaches a recorded terminal, cleared, or replaced boundary, it appends a durable `pr-review-telemetry` session entry with these fields:
304
+ Review-tool results expose the effective `toolPolicy`, monotonic `elapsedMs`, per-attempt timing, observable batch scheduling offsets, and child phase diagnostics: `firstEventMs`, `firstAssistantMs`, and overlap-aware `toolElapsedMs`. In addition, when an accepted `/pr-review` reaches a recorded terminal, cleared, or replaced boundary, it appends a durable `pr-review-telemetry` session entry with these fields:
298
305
 
299
306
  - `schemaVersion` (currently `2`), `clock`, `prNumber`, and `completion` identify the schema, monotonic clock, PR, and terminal boundary (`terminal_response`, `cleared`, or `replaced`).
300
307
  - `totalWallMs` is measured directly from accepted input to that boundary and includes any human-confirmation wait. Publication occurs afterward and is excluded.
@@ -302,10 +309,10 @@ Review-tool results expose the effective `toolPolicy`, monotonic `elapsedMs`, pe
302
309
  - `phases.humanConfirmationWait.elapsedMs` reports time paused after the one-shot question for a non-open PR until affirmative input resumes the review or the invocation reaches its recorded completion. This wait is also removed from active interval offsets rather than attributed to model or orchestration time.
303
310
  - `phases.reviewSubagentTools` and `phases.baselineVerificationTool` report interval-unioned `elapsedMs` plus observed tool intervals. Baseline timing is attributed only to `pr_review_verify` calls with `action=run`; `action=list` discovery and bash calls remain aggregate orchestration. Each interval contains `toolCallId`, `toolName`, `startOffsetMs`, `endOffsetMs`, `elapsedMs`, and `endObserved` on the active timeline.
304
311
  - `phases.overlapMs` is the intersection of those two phase interval sets. `phases.observableToolWallMs` is their union, so concurrent work is not double-counted.
305
- - `phases.aggregateOrchestration.elapsedMs` is the remaining active time. It intentionally groups metadata/context gathering, model orchestration, targeted checks, and final validation because their individual lifecycle boundaries are not directly observed; it is not a model-only timing claim.
312
+ - `phases.aggregateOrchestration.elapsedMs` is the remaining active time. It intentionally groups metadata/context gathering, model orchestration, targeted checks, and final validation because their individual lifecycle boundaries are not directly observed; it is not a model-only timing claim. The prompt schedules independent initial gathering together and batches known candidate-validation reads/checks into one parallel wave (plus at most one evidence-driven follow-up) without weakening the requirement to confirm every surviving finding.
306
313
  - `notes` records these accounting boundaries in the durable entry so downstream consumers do not have to infer them.
307
314
 
308
- These measurements describe observed execution and do not guarantee speed. Lower defaults, cache reordering, sharding, and further context/tool reduction remain deferred pending evidence that review quality is preserved. Restore tools for a custom pass with `tool_policy: "configured"`; omitted policy retains legacy behavior unless `toolPolicies` config says otherwise.
315
+ These measurements describe observed execution and do not guarantee speed. The balanced five-pass topology is the default; use `--full` when exhaustive convention/minor coverage justifies the additional work. Cache reordering and further context/tool reduction remain deferred pending evidence that review quality is preserved. Restore tools for a custom pass with `tool_policy: "configured"`; omitted policy retains legacy behavior unless `toolPolicies` config says otherwise.
309
316
 
310
317
  ### Security, cost, and publishing
311
318
 
@@ -317,7 +324,7 @@ These measurements describe observed execution and do not guarantee speed. Lower
317
324
 
318
325
  ## Design notes
319
326
 
320
- - **Process** is PR-number driven: confirm non-open PRs, skip draft/same-head-already-reviewed work, fan out four review lenses, verify, validate/classify, emit JSON, then optionally publish one extension-owned formal `COMMENT` review.
321
- - **Captures every severity** (`nit P0`) with a `blocking` flag; the verdict depends only on blocking findings, so nothing minor is lost but a clean PR still gets approved.
327
+ - **Process** is PR-number driven: confirm non-open PRs, skip draft/same-head-already-reviewed work, fan out four major-defect lenses as five focused default passes (10/15 passes for adaptive large-diff shards), verify, validate/classify, emit JSON, then optionally publish one extension-owned formal `COMMENT` review. `--full` uses 6/12/18 passes.
328
+ - **Bounds minor work by default:** retain every validated P0–P2 plus at most three direct-diff P3/nits. `--full` captures every qualifying severity (`nit P0`). The verdict depends only on blocking findings.
322
329
  - **Verification is non-destructive to Git state:** a selected user-level named baseline runs through `pr_review_verify` in an extension-owned worktree pinned to the captured full PR SHA. Staging and local import use `--no-write-fetch-head`; cleanup reports worktree/ref/temp removal separately. The prompt never owns cleanup and never checks out, commits, or pushes in your working tree. Verification is nevertheless unsandboxed PR-code execution, so it is disabled by default and requires explicit user acknowledgement plus an external sandbox/container wrapper when the PR is untrusted.
323
330
  - pi has no built-in sub-agents, so tiering is implemented as an extension that spawns isolated `pi` subprocesses per tier; the batch tool gives deterministic parallelism, and the prompt degrades gracefully to single-pass or inline review when the extension is absent.
package/RELEASING.md ADDED
@@ -0,0 +1,26 @@
1
+ # Releasing
2
+
3
+ [Release Please](https://github.com/googleapis/release-please) watches conventional commits merged into `main`. It opens or updates a release PR containing the calculated version change, `CHANGELOG.md`, and release manifest. Merging that release PR creates a GitHub release and, after the test suite passes, publishes `pi-pr-review` to npm with signed provenance.
4
+
5
+ ## Semver
6
+
7
+ The squash-merged PR title becomes the commit Release Please evaluates:
8
+
9
+ - `feat: ...` creates a minor release.
10
+ - `feat!: ...`, `fix!: ...`, or a `BREAKING CHANGE:` footer creates a major release.
11
+ - Every other allowed type—`fix:`, `perf:`, `revert:`, `chore:`, `docs:`, `refactor:`, `style:`, and `test:`—creates a patch release.
12
+
13
+ All changes to `main` must go through a pull request and use squash merging. The required `Validate PR title` check enforces the conventional title, and the required `Test` check runs the Bun test suite. Direct pushes, force pushes, branch deletion, and administrator bypass are disabled.
14
+
15
+ ## One-time setup
16
+
17
+ 1. Install the private [`nerv-ops`](https://github.com/settings/apps/nerv-ops) GitHub App on this repository with **Contents: read and write** and **Pull requests: read and write** permissions.
18
+ 2. Add the App ID as the repository Actions variable `NERV_OPS_APP_ID`, and add a generated PEM private key as the repository Actions secret `NERV_OPS_PRIVATE_KEY`.
19
+ 3. In the npm settings for [`pi-pr-review`](https://www.npmjs.com/package/pi-pr-review), add a GitHub Actions trusted publisher with:
20
+ - organization/user: `10ego`
21
+ - repository: `pi-pr-review`
22
+ - workflow filename: `release-please.yml`
23
+ - environment: leave blank
24
+ 4. Use conventional titles for squash-merged PRs.
25
+
26
+ No npm token is stored in GitHub. The workflow exchanges the App credentials for a short-lived repository installation token and uses npm trusted publishing through GitHub OIDC.