@zephyrdeng/pi-review 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/json-events.d.ts +1 -0
- package/dist/json-events.d.ts.map +1 -1
- package/dist/json-events.js +12 -2
- package/dist/json-events.js.map +1 -1
- package/dist/json-events.test.js +22 -0
- package/dist/json-events.test.js.map +1 -1
- package/dist/meta-footer.d.ts.map +1 -1
- package/dist/meta-footer.js +6 -1
- package/dist/meta-footer.js.map +1 -1
- package/dist/meta-footer.test.js +42 -1
- package/dist/meta-footer.test.js.map +1 -1
- package/dist/panel-aggregate.d.ts +7 -0
- package/dist/panel-aggregate.d.ts.map +1 -1
- package/dist/panel-aggregate.js +19 -1
- package/dist/panel-aggregate.js.map +1 -1
- package/dist/panel-aggregate.test.js +56 -1
- package/dist/panel-aggregate.test.js.map +1 -1
- package/dist/panel-cli.test.js +42 -0
- package/dist/panel-cli.test.js.map +1 -1
- package/dist/panel-view.d.ts.map +1 -1
- package/dist/panel-view.js +9 -3
- package/dist/panel-view.js.map +1 -1
- package/dist/panel-view.test.js +62 -0
- package/dist/panel-view.test.js.map +1 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +9 -4
- package/dist/panel.js.map +1 -1
- package/dist/review-events.d.ts +1 -0
- package/dist/review-events.d.ts.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui-client.js +1 -5
- package/dist/ui-client.js.map +1 -1
- package/dist/ui-server.d.ts +1 -1
- package/dist/ui-server.d.ts.map +1 -1
- package/extensions/panel-tool.test.ts +42 -0
- package/extensions/panel-tool.ts +3 -1
- package/extensions/rv-interactive.test.ts +179 -8
- package/extensions/rv-interactive.ts +64 -61
- package/package.json +1 -1
- package/skills/pi-review/SKILL.md +7 -6
- package/skills/pi-review/references/codex-tools.md +3 -3
- package/skills/pi-review/references/model-selection.md +2 -2
|
@@ -430,77 +430,60 @@ export async function runRvInteractiveWizard(
|
|
|
430
430
|
const labels = rankedModelLabels(models, mode);
|
|
431
431
|
|
|
432
432
|
if (ids.length > 0) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
433
|
+
// Branch on stable keys, not display-label substrings, so copy edits in
|
|
434
|
+
// either language can never silently reroute the wizard.
|
|
435
|
+
const assignmentOptions: Array<{ key: "per-reviewer" | "shared" | "pi-default"; label: string }> = [
|
|
436
|
+
{ key: "per-reviewer", label: zh ? "每位 reviewer 分别选择模型" : "Pick a model for each reviewer" },
|
|
437
|
+
{ key: "shared", label: zh ? "所有 reviewer 使用同一模型" : "Same model for all reviewers" },
|
|
438
|
+
{ key: "pi-default", label: zh ? "使用 Pi 默认模型(运行时解析实际模型)" : "Use Pi's default model (resolved at runtime)" },
|
|
439
|
+
];
|
|
440
|
+
const assignmentChoice = await mustSelect(
|
|
441
|
+
ui,
|
|
442
|
+
zh ? "模型分配方式" : "Model assignment",
|
|
443
|
+
assignmentOptions.map((option) => option.label),
|
|
438
444
|
);
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
zh ? `思考强度(${pick})` : `Thinking (${pick})`,
|
|
462
|
-
thinkingOptions(m, locale),
|
|
463
|
-
);
|
|
464
|
-
if (thinkingPick === CANCEL) return undefined;
|
|
465
|
-
const thinking = stripSkip(thinkingPick, locale);
|
|
466
|
-
const token = thinking ? `${pick}:${thinking}` : pick;
|
|
467
|
-
for (const id of ids) reviewerModels.push(`${id}=${token}`);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
445
|
+
if (assignmentChoice === CANCEL) return undefined;
|
|
446
|
+
const assignment = assignmentOptions.find((option) => option.label === assignmentChoice)?.key ?? "pi-default";
|
|
447
|
+
|
|
448
|
+
if (assignment === "per-reviewer") {
|
|
449
|
+
for (const id of ids) {
|
|
450
|
+
if (labels.length === 0) break;
|
|
451
|
+
const pick = await pickModelLabel(ui, models, mode, locale, zh ? `模型 · ${id}` : `Model · ${id}`, false);
|
|
452
|
+
if (pick === CANCEL) return undefined;
|
|
453
|
+
if (pick === undefined) continue; // defensive: allowSkip=false never returns undefined here
|
|
454
|
+
const m = modelByLabel(models, pick);
|
|
455
|
+
const thinkingPick = await mustSelect(
|
|
456
|
+
ui,
|
|
457
|
+
zh ? `思考强度 · ${id}` : `Thinking · ${id}`,
|
|
458
|
+
thinkingOptions(m, locale),
|
|
459
|
+
);
|
|
460
|
+
if (thinkingPick === CANCEL) return undefined;
|
|
461
|
+
const thinking = stripSkip(thinkingPick, locale);
|
|
462
|
+
reviewerModels.push(`${id}=${thinking ? `${pick}:${thinking}` : pick}`);
|
|
463
|
+
}
|
|
464
|
+
} else if (assignment === "shared") {
|
|
465
|
+
if (labels.length === 0) {
|
|
466
|
+
ui.notify(zh ? "当前没有可用模型目录,请先 /rv-models" : "No model catalog available; run /rv-models first", "warning");
|
|
470
467
|
} else {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
if (pick === CANCEL) return undefined;
|
|
475
|
-
if (pick === undefined) continue; // defensive: allowSkip=false never returns undefined here
|
|
468
|
+
const pick = await pickModelLabel(ui, models, mode, locale, zh ? "共用模型" : "Shared model", false);
|
|
469
|
+
if (pick === CANCEL) return undefined;
|
|
470
|
+
if (pick !== undefined) {
|
|
476
471
|
const m = modelByLabel(models, pick);
|
|
477
472
|
const thinkingPick = await mustSelect(
|
|
478
473
|
ui,
|
|
479
|
-
zh ?
|
|
474
|
+
zh ? `思考强度(${pick})` : `Thinking (${pick})`,
|
|
480
475
|
thinkingOptions(m, locale),
|
|
481
476
|
);
|
|
482
477
|
if (thinkingPick === CANCEL) return undefined;
|
|
483
478
|
const thinking = stripSkip(thinkingPick, locale);
|
|
484
|
-
|
|
479
|
+
const token = thinking ? `${pick}:${thinking}` : pick;
|
|
480
|
+
for (const id of ids) reviewerModels.push(`${id}=${token}`);
|
|
485
481
|
}
|
|
486
482
|
}
|
|
487
|
-
} else if (!seed.model && labels.length > 0) {
|
|
488
|
-
// Shared default model when not assigning per-reviewer
|
|
489
|
-
const pick = await pickModelLabel(ui, models, mode, locale, zh ? "默认模型(全体 reviewer)" : "Default model (all reviewers)", true);
|
|
490
|
-
if (pick === CANCEL) return undefined;
|
|
491
|
-
if (pick !== undefined) {
|
|
492
|
-
const m = modelByLabel(models, pick);
|
|
493
|
-
const thinkingPick = await mustSelect(
|
|
494
|
-
ui,
|
|
495
|
-
zh ? "默认思考强度" : "Default thinking",
|
|
496
|
-
thinkingOptions(m, locale),
|
|
497
|
-
);
|
|
498
|
-
if (thinkingPick === CANCEL) return undefined;
|
|
499
|
-
const thinking = stripSkip(thinkingPick, locale);
|
|
500
|
-
seed.model = pick;
|
|
501
|
-
if (thinking) seed.thinking = thinking;
|
|
502
|
-
}
|
|
503
483
|
}
|
|
484
|
+
// else: Pi default for every reviewer — no reviewerModels, no further prompt.
|
|
485
|
+
// The confirm summary below still shows each reviewer's resolved model
|
|
486
|
+
// (falling back to the shared --model flag, then a "Pi default" placeholder).
|
|
504
487
|
} else if (!seed.model && labels.length > 0) {
|
|
505
488
|
// Single-reviewer path
|
|
506
489
|
const pick = await pickModelLabel(ui, models, mode, locale, zh ? "模型" : "Model", true);
|
|
@@ -543,6 +526,23 @@ export async function runRvInteractiveWizard(
|
|
|
543
526
|
}
|
|
544
527
|
|
|
545
528
|
// 7) Confirm summary
|
|
529
|
+
// Per-reviewer effective model for the confirm summary: explicit override →
|
|
530
|
+
// shared --model (if set) → "Pi default" placeholder. Mirrors what the CLI
|
|
531
|
+
// actually resolves at runtime (resolveReviewerModelThinking).
|
|
532
|
+
const piDefaultLabel = zh ? "Pi 默认" : "Pi default";
|
|
533
|
+
const reviewerModelOverrides = new Map(
|
|
534
|
+
reviewerModels.map((entry) => {
|
|
535
|
+
const eq = entry.indexOf("=");
|
|
536
|
+
return [entry.slice(0, eq), entry.slice(eq + 1)] as const;
|
|
537
|
+
}),
|
|
538
|
+
);
|
|
539
|
+
const reviewerModelSummary = ids.map((id) => {
|
|
540
|
+
const override = reviewerModelOverrides.get(id);
|
|
541
|
+
if (override) return `${id}=${override}`;
|
|
542
|
+
if (seed.model) return `${id}=${seed.model}${seed.thinking ? `:${seed.thinking}` : ""}`;
|
|
543
|
+
return `${id}=${piDefaultLabel}`;
|
|
544
|
+
});
|
|
545
|
+
|
|
546
546
|
const summaryLines = [
|
|
547
547
|
`${zh ? "策略" : "Strategy"}: ${strategy}`,
|
|
548
548
|
`${zh ? "目标" : "Target"}: ${target}`,
|
|
@@ -559,8 +559,11 @@ export async function runRvInteractiveWizard(
|
|
|
559
559
|
: zh
|
|
560
560
|
? "单 reviewer"
|
|
561
561
|
: "single reviewer",
|
|
562
|
-
|
|
563
|
-
|
|
562
|
+
// Multi-reviewer paths show one resolved model per reviewer id; single-reviewer
|
|
563
|
+
// and shared-model paths keep the existing single `model:` line.
|
|
564
|
+
ids.length > 0
|
|
565
|
+
? `${zh ? "reviewer 模型" : "reviewer models"}: ${reviewerModelSummary.join(", ")}`
|
|
566
|
+
: `model: ${seed.model ? `${seed.model}${seed.thinking ? `:${seed.thinking}` : ""}` : piDefaultLabel}`,
|
|
564
567
|
consensus ? `consensus: ${consensus}${minAgree ? ` min-agree=${minAgree}` : ""}` : "",
|
|
565
568
|
].filter(Boolean);
|
|
566
569
|
|
package/package.json
CHANGED
|
@@ -27,12 +27,12 @@ node ../../bin/pi-review.js --help
|
|
|
27
27
|
|------|-------------------------|
|
|
28
28
|
| **Pi** (`/rv`) | New panel reviews call the native `pi_review` API tool, shown to users as **Pi Review Panel**, which launches the packaged CLI in event mode and renders live reviewer state. Continuations, kept sessions, `/rv-loop`, and explicit `--no-stream` use the shell CLI. |
|
|
29
29
|
| **Pi terminal** | Foreground `pi-review`; text deltas stream live by default. |
|
|
30
|
-
| **Claude Code / Codex / Cursor** and similar agent hosts | These hosts buffer a shell tool's output until the command exits, so a foreground run looks like a silent wait. **Panel review (`--reviewers`/`--panel`) default: `--ui web --ui-url-file <path>` + background run** —
|
|
30
|
+
| **Claude Code / Codex / Cursor** and similar agent hosts | These hosts buffer a shell tool's output until the command exits, so a foreground run looks like a silent wait. **Panel review (`--reviewers`/`--panel`) default: `--ui web --ui-url-file <path>` + background run** — get the dashboard in front of the user: on Claude Code the CLI auto-open lands in the system default browser; on Codex open the `--ui-url-file` URL in the host's built-in browser (the CLI cannot reach a GUI there); hand over the URL as fallback either way. **Single review / `loop` default: `--progress-log <path>` + background run + tail the log** (`--ui web` requires an active panel and rejects `loop`). See [references/codex-tools.md](./references/codex-tools.md). Map skill mentions of `Bash` to your host shell tool. |
|
|
31
31
|
| Scripts / CI | Foreground is fine; add `--no-stream` only when the caller must buffer until exit (cannot combine with `--progress-log`). |
|
|
32
32
|
|
|
33
33
|
`--progress-log <path>` tees the raw `--mode json` event stream to a file for outside observation and debugging; it is never a prerequisite for metrics. Token usage accumulates by default, and `pi-review` writes milestone notices (`pi-review: review started`, `pi-review: tool <name> started/finished`, `pi-review: review finished`) to stderr.
|
|
34
34
|
|
|
35
|
-
`--ui web` starts a loopback-only browser dashboard for panel review and auto-opens it in the default browser (`--no-ui-open` disables the auto-open); `--ui-url-file <path>` writes its URL atomically so a buffered-output host can read it without parsing stderr. After completion the page counts down 60s, then closes itself and stops the dashboard server (any interaction cancels the countdown). It never substitutes for panel semantics — findings, gate status, and exit code come from the same `PI_REVIEW_META_JSON` as always.
|
|
35
|
+
`--ui web` starts a loopback-only browser dashboard for panel review and auto-opens it in the default browser (`--no-ui-open` disables the auto-open); `--ui-url-file <path>` writes its URL atomically so a buffered-output host can read it without parsing stderr. Open the dashboard as wide as the host allows: Claude Code rides the auto-open (system default browser), Codex opens the url-file URL in its built-in browser, and Pi renders panels natively so `/rv` needs no `--ui web`. After completion the page counts down 60s, then closes itself and stops the dashboard server (any interaction cancels the countdown). It never substitutes for panel semantics — findings, gate status, and exit code come from the same `PI_REVIEW_META_JSON` as always.
|
|
36
36
|
|
|
37
37
|
## Run metrics
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ Quote metrics from the run output; never estimate or invent them.
|
|
|
40
40
|
|
|
41
41
|
- **ASCII footer** (the `── pi-review` / `── pi-review panel` block): Duration, Tokens as `in · out · cache · reason` plus total, and Cost — the provider-reported value, or `n/a` when the provider reports none. On Pi `/rv` the panel tool result is **plain text / ASCII only** (Pi does not render markdown in tool results) — same classic chrome as the CLI, no `###` headings or fenced code blocks.
|
|
42
42
|
- **Pi Review Panel**: each reviewer row shows **role persona · lifecycle · model · thinking · elapsed · tokens**. Lifecycle is `queued` / `running` / `completed` / `failed` / `cancelled`. Expanded view adds bounded activity, plain-text findings, and the ASCII footer.
|
|
43
|
-
- Machine output: parse `PI_REVIEW_META_JSON:` from **stderr** (or set `PI_REVIEW_META_STDOUT=1` to emit it on stdout). Show users the plain review text and ASCII footer, not raw JSON, unless they ask for machine output. Do **not** rewrap the tool result into markdown tables or `###` report sections.
|
|
43
|
+
- Machine output: parse `PI_REVIEW_META_JSON:` from **stderr** (or set `PI_REVIEW_META_STDOUT=1` to emit it on stdout). Show users the plain review text and ASCII footer, not raw JSON, unless they ask for machine output. Do **not** rewrap the tool result into markdown tables or `###` report sections. On panel runs the top-level `model` is the reviewers' shared effective model (configured, else provider-reported) or the literal sentinel `"mixed"` when reviewers ran on different models; per-reviewer entries carry their own `model`/`responseModel`.
|
|
44
44
|
|
|
45
45
|
## Pi host (`/rv*`)
|
|
46
46
|
|
|
@@ -185,11 +185,12 @@ pi-review --reviewers 3 --ui web --ui-url-file /tmp/pi-review-ui-url.txt -- @src
|
|
|
185
185
|
```
|
|
186
186
|
Rules:
|
|
187
187
|
- Run this before building the review command. **Never invent a `provider/model` id** — only ids from the catalog output.
|
|
188
|
-
-
|
|
188
|
+
- **Cross-model review**: identify the model this host session itself runs on (its id is in your session context), then prefer reviewer models from a different model family — same-family reviewers share the author model's blind spots. On a panel, keep the host's family to a minority of reviewers.
|
|
189
|
+
- Follow **[references/model-selection.md](./references/model-selection.md)** for everything else: profile inference (code / frontend / plan), priority lists, cross-model resolution, user-named-model resolution, and thinking aliases (`max`/`最高` → `xhigh`, with fallback to the nearest supported level).
|
|
189
190
|
- Ambiguous match across model families: show the top candidates and ask; do not guess.
|
|
190
|
-
-
|
|
191
|
+
- User named no model: propose 2–3 exact catalog ids (cross-model first, one line of why each, "Pi default" as an explicit option) and ask the user to pick before running.
|
|
191
192
|
- On **Claude Code / Codex / Cursor**, state the chosen model in one line (match the user's language) before running the review command.
|
|
192
|
-
Completion criterion: exact listed `provider/model[:thinking]` or
|
|
193
|
+
Completion criterion: an exact listed `provider/model[:thinking]` (or Pi default) that the user named or picked from your proposal; never invented ids.
|
|
193
194
|
|
|
194
195
|
2. Choose one mode:
|
|
195
196
|
- default `code` — code, diff, MR, file, or repository review.
|
|
@@ -8,7 +8,7 @@ Skills may use Claude Code tool names. On **Codex** or **Claude Code**, map them
|
|
|
8
8
|
| `Read`, `Write`, `Edit` | Native file tools |
|
|
9
9
|
| `Skill` | Load and follow the skill instructions directly |
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
This file is **pi-review–specific** and ships with the pi-review package.
|
|
12
12
|
|
|
13
13
|
## Long-running `pi-review` (default on Codex / Claude Code)
|
|
14
14
|
|
|
@@ -18,8 +18,8 @@ Native shell tools on these hosts **buffer stdout/stderr until the command exits
|
|
|
18
18
|
|
|
19
19
|
`--reviewers <n>` or `--panel <name>` activates panel review. On Codex, Claude Code, or Cursor, default to the dashboard instead of a tailed log:
|
|
20
20
|
|
|
21
|
-
1. Run `pi-review --reviewers <n> --ui web --ui-url-file <path> -- <target>` (or `--panel <name>`) in the **background**.
|
|
22
|
-
2. Read `<path>` shortly after launch — it is written atomically as soon as the dashboard server is ready, well before reviewers finish (poll a few times a second for a couple of seconds if the file is not there yet).
|
|
21
|
+
1. Run `pi-review --reviewers <n> --ui web --ui-url-file <path> -- <target>` (or `--panel <name>`) in the **background**. Pass `--no-ui-open` only when the user asked not to open a browser (CI, remote shells).
|
|
22
|
+
2. Read `<path>` shortly after launch — it is written atomically as soon as the dashboard server is ready, well before reviewers finish (poll a few times a second for a couple of seconds if the file is not there yet). Then get the dashboard in front of the user: on **Claude Code** the CLI auto-open already lands in the system default browser; on **Codex** the CLI cannot reach a GUI browser, so open the URL from `<path>` in the host's built-in browser yourself. Share the URL either way as a fallback: *"Dashboard opened in your browser (URL: `<url>`). I'll report back when the review completes."*
|
|
23
23
|
3. Wait for the background job. On exit, show the Markdown review body and ASCII `── pi-review` footer as usual (skill step 4) — the dashboard is a presentation layer only; findings, gate status, and exit code always come from `PI_REVIEW_META_JSON`.
|
|
24
24
|
4. `--ui web` requires an active panel and rejects `loop` — for a single review or a panel `loop`, fall back to the progress-log workflow below.
|
|
25
25
|
|
|
@@ -6,11 +6,11 @@ Use this after `pi-review models` (or `pi-review models <search>`). **Never inve
|
|
|
6
6
|
|
|
7
7
|
1. Run `pi-review models` (narrow with search if the user named a vendor or model family).
|
|
8
8
|
2. Infer **review profile** from the target (see table below).
|
|
9
|
-
3. Walk the **priority list** for that profile
|
|
9
|
+
3. **Cross-model review**: identify the host session's own model — the model that wrote or will fix the code under review; its id is in your own session context. Walk the **priority list** for that profile skipping rows in the host's model family, and pick the **first** remaining row whose `idContains` matches some listed model id (case-insensitive substring). Same-family reviewers share the author model's blind spots; return to the host's own family only when no other family matches the catalog. On a panel, spread reviewer models so the host's family stays a minority. If several ids match one row, prefer the **newest** id (higher version suffix, e.g. `2.7` over `2.5`, `4-8` over `4-6`).
|
|
10
10
|
4. Set `--model <exact-listed-provider/model>` from the catalog. Add `:thinking` only if that model supports it in Pi and the preset suggests it (see thinking column).
|
|
11
11
|
- User “max / 最高档” maps to Pi thinking `xhigh` when supported; otherwise fall back to the highest available level.
|
|
12
12
|
- User “low / off / medium / high” maps to that exact level when supported — **do not upgrade** a user-specified low/off to high/xhigh.
|
|
13
|
-
5.
|
|
13
|
+
5. When the user named no model, the walk above yields a **proposal, not a decision**: present 2–3 exact catalog ids (cross-model candidates first, one line of why each, plus “Pi default” as an explicit option) and ask the user to pick before running the review. A user-named model skips the ask and resolves per **User-named model** below. If **no** priority row matches anything in the catalog, propose the best **reasoning** models with a large context window from the list the same way.
|
|
14
14
|
|
|
15
15
|
## Profiles
|
|
16
16
|
|