@zephyrdeng/pi-review 0.7.1 → 0.8.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 +37 -8
- package/README.zh-CN.md +31 -5
- package/dist/args.d.ts +4 -0
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +61 -4
- package/dist/args.js.map +1 -1
- package/dist/args.test.js +62 -1
- package/dist/args.test.js.map +1 -1
- package/dist/child-process.d.ts +3 -0
- package/dist/child-process.d.ts.map +1 -1
- package/dist/child-process.js +27 -5
- package/dist/child-process.js.map +1 -1
- package/dist/child-process.test.js +42 -1
- package/dist/child-process.test.js.map +1 -1
- package/dist/cli-exit.test.js +14 -5
- package/dist/cli-exit.test.js.map +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/install-args.test.js +1 -1
- package/dist/install-args.test.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +2 -3
- package/dist/install.js.map +1 -1
- package/dist/json-events.d.ts +6 -0
- package/dist/json-events.d.ts.map +1 -1
- package/dist/json-events.js +48 -6
- package/dist/json-events.js.map +1 -1
- package/dist/json-events.test.js +20 -1
- package/dist/json-events.test.js.map +1 -1
- package/dist/loop.d.ts +28 -2
- package/dist/loop.d.ts.map +1 -1
- package/dist/loop.js +45 -3
- package/dist/loop.js.map +1 -1
- package/dist/loop.test.js +24 -1
- package/dist/loop.test.js.map +1 -1
- package/dist/matcher.test.js +1 -1
- package/dist/matcher.test.js.map +1 -1
- package/dist/meta-footer.d.ts +4 -8
- package/dist/meta-footer.d.ts.map +1 -1
- package/dist/meta-footer.js +19 -5
- package/dist/meta-footer.js.map +1 -1
- package/dist/meta-footer.test.js +11 -4
- package/dist/meta-footer.test.js.map +1 -1
- package/dist/panel-aggregate.test.js +1 -1
- package/dist/panel-aggregate.test.js.map +1 -1
- package/dist/panel-cancellation.test.js +33 -2
- package/dist/panel-cancellation.test.js.map +1 -1
- package/dist/panel-cli-ui.test.d.ts +2 -0
- package/dist/panel-cli-ui.test.d.ts.map +1 -0
- package/dist/panel-cli-ui.test.js +91 -0
- package/dist/panel-cli-ui.test.js.map +1 -0
- package/dist/panel-cli.test.js +37 -39
- package/dist/panel-cli.test.js.map +1 -1
- package/dist/panel-config.d.ts +38 -0
- package/dist/panel-config.d.ts.map +1 -1
- package/dist/panel-config.js +135 -2
- package/dist/panel-config.js.map +1 -1
- package/dist/panel-config.test.js +79 -2
- package/dist/panel-config.test.js.map +1 -1
- package/dist/panel-loop.test.js +1 -1
- package/dist/panel-loop.test.js.map +1 -1
- package/dist/panel-tools.test.js +1 -1
- package/dist/panel-tools.test.js.map +1 -1
- package/dist/panel-ui.d.ts +20 -0
- package/dist/panel-ui.d.ts.map +1 -0
- package/dist/panel-ui.js +84 -0
- package/dist/panel-ui.js.map +1 -0
- package/dist/panel-ui.test.d.ts +2 -0
- package/dist/panel-ui.test.d.ts.map +1 -0
- package/dist/panel-ui.test.js +122 -0
- package/dist/panel-ui.test.js.map +1 -0
- package/dist/panel-view.d.ts +1 -0
- package/dist/panel-view.d.ts.map +1 -1
- package/dist/panel-view.js +40 -6
- package/dist/panel-view.js.map +1 -1
- package/dist/panel-view.test.js +68 -1
- package/dist/panel-view.test.js.map +1 -1
- package/dist/panel.d.ts +11 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +67 -21
- package/dist/panel.js.map +1 -1
- package/dist/prompt.d.ts +2 -0
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +34 -3
- package/dist/prompt.js.map +1 -1
- package/dist/prompt.test.js +21 -2
- package/dist/prompt.test.js.map +1 -1
- package/dist/review-events.test.js +1 -1
- package/dist/review-events.test.js.map +1 -1
- package/dist/review-result.test.js +1 -1
- package/dist/review-result.test.js.map +1 -1
- package/dist/review.js +3 -3
- package/dist/review.js.map +1 -1
- package/dist/review.meta.test.js +1 -1
- package/dist/review.meta.test.js.map +1 -1
- package/dist/skill-protocol.test.js +1 -1
- package/dist/skill-protocol.test.js.map +1 -1
- package/dist/skill-update.test.d.ts +2 -0
- package/dist/skill-update.test.d.ts.map +1 -0
- package/dist/skill-update.test.js +23 -0
- package/dist/skill-update.test.js.map +1 -0
- package/dist/skill.d.ts +22 -0
- package/dist/skill.d.ts.map +1 -1
- package/dist/skill.js +109 -22
- package/dist/skill.js.map +1 -1
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/ui-client.d.ts +13 -0
- package/dist/ui-client.d.ts.map +1 -0
- package/dist/ui-client.js +161 -0
- package/dist/ui-client.js.map +1 -0
- package/dist/ui-client.test.d.ts +2 -0
- package/dist/ui-client.test.d.ts.map +1 -0
- package/dist/ui-client.test.js +48 -0
- package/dist/ui-client.test.js.map +1 -0
- package/dist/ui-html.d.ts +7 -0
- package/dist/ui-html.d.ts.map +1 -0
- package/dist/ui-html.js +52 -0
- package/dist/ui-html.js.map +1 -0
- package/dist/ui-html.test.d.ts +2 -0
- package/dist/ui-html.test.d.ts.map +1 -0
- package/dist/ui-html.test.js +26 -0
- package/dist/ui-html.test.js.map +1 -0
- package/dist/ui-server-main.d.ts +3 -0
- package/dist/ui-server-main.d.ts.map +1 -0
- package/dist/ui-server-main.js +128 -0
- package/dist/ui-server-main.js.map +1 -0
- package/dist/ui-server-main.test.d.ts +2 -0
- package/dist/ui-server-main.test.d.ts.map +1 -0
- package/dist/ui-server-main.test.js +123 -0
- package/dist/ui-server-main.test.js.map +1 -0
- package/dist/ui-server.d.ts +42 -0
- package/dist/ui-server.d.ts.map +1 -0
- package/dist/ui-server.js +233 -0
- package/dist/ui-server.js.map +1 -0
- package/dist/ui-server.test.d.ts +2 -0
- package/dist/ui-server.test.d.ts.map +1 -0
- package/dist/ui-server.test.js +236 -0
- package/dist/ui-server.test.js.map +1 -0
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +48 -19
- package/dist/update.js.map +1 -1
- package/extensions/panel-tool.test.ts +366 -8
- package/extensions/panel-tool.ts +289 -68
- package/extensions/review.test.ts +79 -0
- package/extensions/review.ts +188 -44
- package/extensions/rv-completions.test.ts +177 -18
- package/extensions/rv-completions.ts +490 -60
- package/extensions/rv-interactive.test.ts +562 -0
- package/extensions/rv-interactive.ts +616 -0
- package/extensions/rv-locale.test.ts +12 -4
- package/extensions/rv-locale.ts +44 -11
- package/extensions/rv-model-picker.test.ts +172 -0
- package/extensions/rv-model-picker.ts +313 -0
- package/extensions/rv-model-priorities.test.ts +29 -9
- package/extensions/rv-model-priorities.ts +23 -8
- package/extensions/rv-prompts.test.ts +274 -2
- package/extensions/rv-prompts.ts +479 -33
- package/extensions/rv-resolve.test.ts +189 -0
- package/extensions/rv-resolve.ts +313 -0
- package/extensions/rv-semantic.test.ts +1 -1
- package/extensions/rv-semantic.ts +38 -4
- package/package.json +7 -4
- package/resources/rv-model-priorities.json +18 -9
- package/skills/pi-review/SKILL.md +84 -60
- package/skills/pi-review/references/codex-tools.md +18 -11
- package/skills/pi-review/references/model-selection.md +49 -28
- package/dist/extensions/review.d.ts +0 -2
- package/dist/extensions/review.js +0 -22
- package/dist/extensions/rv-prompts.d.ts +0 -19
- package/dist/extensions/rv-prompts.js +0 -132
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { describe, it } from "
|
|
2
|
+
import { describe, it } from "vitest";
|
|
3
3
|
import {
|
|
4
4
|
buildPiReviewArgv,
|
|
5
|
+
buildPiReviewToolCallInstruction,
|
|
5
6
|
buildRvOrchestrationPrompt,
|
|
7
|
+
formatPiReviewCommandLine,
|
|
6
8
|
orchestrationLocaleNote,
|
|
7
9
|
parseRvArgs,
|
|
10
|
+
shellQuote,
|
|
8
11
|
validateRvParsed,
|
|
9
12
|
} from "./rv-prompts.js";
|
|
10
13
|
|
|
@@ -75,9 +78,278 @@ describe("parseRvArgs / validateRvParsed", () => {
|
|
|
75
78
|
assert.doesNotMatch(prompt, /PI_REVIEW_META:/);
|
|
76
79
|
});
|
|
77
80
|
|
|
81
|
+
it("new /rv runs pass the user target as natural-language text without expanding paths", () => {
|
|
82
|
+
const prompt = buildRvOrchestrationPrompt(parseRvArgs("@src"));
|
|
83
|
+
assert.match(prompt, /Call pi_review with target="@src"/);
|
|
84
|
+
assert.match(prompt, /natural-language review request/);
|
|
85
|
+
assert.match(prompt, /Do not expand directory targets into multi-file lists/);
|
|
86
|
+
assert.match(prompt, /panel="code-experts"/);
|
|
87
|
+
assert.match(prompt, /Do not drop panel\/reviewers\/reviewerModels\/consensus fields/);
|
|
88
|
+
assert.match(prompt, /Slash commands select strategy only/);
|
|
89
|
+
assert.doesNotMatch(prompt, /@src\/panel\.ts|@src\/json-events\.ts/);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("panel orchestration preserves reviewers/consensus/reviewerModels for pi_review", () => {
|
|
93
|
+
const parsed = parseRvArgs(
|
|
94
|
+
"--reviewers 3 --consensus quorum --min-agree 2 --reviewer-model r1=openai-codex/gpt-5.6-sol @src",
|
|
95
|
+
);
|
|
96
|
+
const instruction = buildPiReviewToolCallInstruction(parsed, "@src");
|
|
97
|
+
assert.match(instruction, /reviewers=3/);
|
|
98
|
+
assert.match(instruction, /consensus="quorum"/);
|
|
99
|
+
assert.match(instruction, /minAgree=2/);
|
|
100
|
+
assert.match(instruction, /reviewerModels=\["r1=openai-codex\/gpt-5\.6-sol"\]/);
|
|
101
|
+
assert.doesNotMatch(instruction, /panel="code-experts"/);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("explicit reviewers=1 uses the shell single-review path, never default code-experts", () => {
|
|
105
|
+
const parsed = parseRvArgs("--reviewers 1 @src", "panel");
|
|
106
|
+
const prompt = buildRvOrchestrationPrompt(parsed);
|
|
107
|
+
assert.match(prompt, /single-reviewer|single review/i);
|
|
108
|
+
assert.match(prompt, /pi-review --reviewers 1 -- @src/);
|
|
109
|
+
assert.doesNotMatch(prompt, /Call pi_review/);
|
|
110
|
+
assert.doesNotMatch(prompt, /panel="code-experts"/);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("shell command lines quote hostile natural-language targets", () => {
|
|
114
|
+
assert.equal(shellQuote("safe@src"), "safe@src");
|
|
115
|
+
assert.match(shellQuote("foo; rm -rf /"), /^'foo; rm -rf \/'$/);
|
|
116
|
+
const parsed = parseRvArgs("loop-target", "loop");
|
|
117
|
+
// Force a hostile target through the formatter.
|
|
118
|
+
const line = formatPiReviewCommandLine({ ...parsed, target: "x; rm -rf /tmp/pwned" }, "x; rm -rf /tmp/pwned");
|
|
119
|
+
assert.match(line, /'x; rm -rf \/tmp\/pwned'/);
|
|
120
|
+
assert.doesNotMatch(line, /rm -rf \/tmp\/pwned(?!')/);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("/rv-loop selects the loop strategy while keeping the target as natural language", () => {
|
|
124
|
+
const parsed = parseRvArgs("@src", "loop");
|
|
125
|
+
assert.equal(parsed.strategy, "loop");
|
|
126
|
+
assert.equal(parsed.target, "@src");
|
|
127
|
+
assert.deepEqual(buildPiReviewArgv(parsed, "@src"), ["pi-review", "loop", "--max-rounds", "1", "--", "@src"]);
|
|
128
|
+
const prompt = buildRvOrchestrationPrompt(parsed);
|
|
129
|
+
assert.match(prompt, /Strategy: loop closeout/);
|
|
130
|
+
assert.match(prompt, /Execute exactly \(already shell-quoted; do not re-quote or drop flags\):\npi-review loop --max-rounds 1 -- @src/);
|
|
131
|
+
assert.doesNotMatch(prompt, /Call pi_review with target/);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("/rv-loop --max-rounds uses strict positive safe integers", () => {
|
|
135
|
+
for (const bad of ["0", "1.5", "many", "9007199254740992"]) {
|
|
136
|
+
const parsed = parseRvArgs(`--max-rounds ${bad} @src`, "loop");
|
|
137
|
+
const validation = validateRvParsed(parsed);
|
|
138
|
+
assert.equal(validation.ok, false, bad);
|
|
139
|
+
if (!validation.ok) assert.match(validation.message, /positive integer|safe positive integer/);
|
|
140
|
+
}
|
|
141
|
+
const ok = parseRvArgs("--max-rounds 2 @src", "loop");
|
|
142
|
+
assert.equal(validateRvParsed(ok).ok, true);
|
|
143
|
+
assert.equal(ok.maxRounds, 2);
|
|
144
|
+
assert.deepEqual(buildPiReviewArgv(ok, "@src"), ["pi-review", "loop", "--max-rounds", "2", "--", "@src"]);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("/rv-loop defaults argv max-rounds to the host fix-point budget of 1", () => {
|
|
148
|
+
const parsed = parseRvArgs("fix until clean @src", "loop");
|
|
149
|
+
assert.equal(parsed.maxRounds, undefined);
|
|
150
|
+
assert.equal(parsed.until, undefined);
|
|
151
|
+
assert.deepEqual(buildPiReviewArgv(parsed, parsed.target), [
|
|
152
|
+
"pi-review",
|
|
153
|
+
"loop",
|
|
154
|
+
"--max-rounds",
|
|
155
|
+
"1",
|
|
156
|
+
"--",
|
|
157
|
+
"fix until clean @src",
|
|
158
|
+
]);
|
|
159
|
+
const prompt = buildRvOrchestrationPrompt(parsed);
|
|
160
|
+
assert.match(prompt, /defaults to --max-rounds 1/);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("/rv-loop --until clean declares the clean goal and a hard budget", () => {
|
|
164
|
+
const parsed = parseRvArgs("--until clean @src", "loop");
|
|
165
|
+
assert.equal(validateRvParsed(parsed).ok, true);
|
|
166
|
+
assert.equal(parsed.until, "clean");
|
|
167
|
+
assert.deepEqual(buildPiReviewArgv(parsed, "@src"), [
|
|
168
|
+
"pi-review",
|
|
169
|
+
"loop",
|
|
170
|
+
"--until",
|
|
171
|
+
"clean",
|
|
172
|
+
"--max-rounds",
|
|
173
|
+
"10",
|
|
174
|
+
"--",
|
|
175
|
+
"@src",
|
|
176
|
+
]);
|
|
177
|
+
const prompt = buildRvOrchestrationPrompt(parsed);
|
|
178
|
+
assert.match(prompt, /until-clean closeout|until clean/i);
|
|
179
|
+
assert.match(prompt, /no gate-blocking findings/);
|
|
180
|
+
assert.match(prompt, /Host until-clean cycle/);
|
|
181
|
+
assert.match(prompt, /--until clean --max-rounds 10/);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("/rv-loop --until clean keeps an explicit max-rounds budget", () => {
|
|
185
|
+
const parsed = parseRvArgs("--until clean --max-rounds 4 @src", "loop");
|
|
186
|
+
assert.equal(parsed.until, "clean");
|
|
187
|
+
assert.equal(parsed.maxRounds, 4);
|
|
188
|
+
assert.deepEqual(buildPiReviewArgv(parsed, "@src"), [
|
|
189
|
+
"pi-review",
|
|
190
|
+
"loop",
|
|
191
|
+
"--until",
|
|
192
|
+
"clean",
|
|
193
|
+
"--max-rounds",
|
|
194
|
+
"4",
|
|
195
|
+
"--",
|
|
196
|
+
"@src",
|
|
197
|
+
]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("parses panel strategy flags for /rv and /rv-loop", () => {
|
|
201
|
+
const loop = parseRvArgs("--reviewers 3 --consensus quorum --min-agree 2 --concurrency 2 @src", "loop");
|
|
202
|
+
assert.equal(loop.reviewers, 3);
|
|
203
|
+
assert.equal(loop.consensus, "quorum");
|
|
204
|
+
assert.equal(loop.minAgree, 2);
|
|
205
|
+
assert.equal(loop.concurrency, 2);
|
|
206
|
+
assert.equal(validateRvParsed(loop).ok, true);
|
|
207
|
+
assert.deepEqual(buildPiReviewArgv(loop, "@src"), [
|
|
208
|
+
"pi-review",
|
|
209
|
+
"loop",
|
|
210
|
+
"--max-rounds",
|
|
211
|
+
"1",
|
|
212
|
+
"--reviewers",
|
|
213
|
+
"3",
|
|
214
|
+
"--consensus",
|
|
215
|
+
"quorum",
|
|
216
|
+
"--min-agree",
|
|
217
|
+
"2",
|
|
218
|
+
"--concurrency",
|
|
219
|
+
"2",
|
|
220
|
+
"--",
|
|
221
|
+
"@src",
|
|
222
|
+
]);
|
|
223
|
+
|
|
224
|
+
const panel = parseRvArgs("--panel code-experts --consensus majority @src");
|
|
225
|
+
assert.equal(panel.panel, "code-experts");
|
|
226
|
+
assert.equal(panel.consensus, "majority");
|
|
227
|
+
assert.deepEqual(buildPiReviewArgv(panel, "@src"), [
|
|
228
|
+
"pi-review",
|
|
229
|
+
"--panel",
|
|
230
|
+
"code-experts",
|
|
231
|
+
"--consensus",
|
|
232
|
+
"majority",
|
|
233
|
+
"--",
|
|
234
|
+
"@src",
|
|
235
|
+
]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("rejects incompatible panel strategy combinations", () => {
|
|
239
|
+
const both = parseRvArgs("--reviewers 3 --panel code-experts @src", "loop");
|
|
240
|
+
assert.equal(validateRvParsed(both).ok, false);
|
|
241
|
+
|
|
242
|
+
const badConsensus = parseRvArgs("--reviewers 3 --consensus nope @src", "loop");
|
|
243
|
+
assert.equal(validateRvParsed(badConsensus).ok, false);
|
|
244
|
+
|
|
245
|
+
const minAgreeTooHigh = parseRvArgs("--reviewers 2 --consensus quorum --min-agree 3 @src", "loop");
|
|
246
|
+
assert.equal(validateRvParsed(minAgreeTooHigh).ok, false);
|
|
247
|
+
|
|
248
|
+
const concurrencyTooHigh = parseRvArgs("--reviewers 2 --concurrency 5 @src", "loop");
|
|
249
|
+
assert.equal(validateRvParsed(concurrencyTooHigh).ok, false);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("rejects missing flag values even when a natural-language target follows", () => {
|
|
253
|
+
const allValueFlags = [
|
|
254
|
+
"--mode",
|
|
255
|
+
"--model",
|
|
256
|
+
"--thinking",
|
|
257
|
+
"--continue",
|
|
258
|
+
"--max-rounds",
|
|
259
|
+
"--until",
|
|
260
|
+
"--reviewers",
|
|
261
|
+
"--panel",
|
|
262
|
+
"--reviewer-model",
|
|
263
|
+
"--consensus",
|
|
264
|
+
"--min-agree",
|
|
265
|
+
"--consensus-model",
|
|
266
|
+
"--concurrency",
|
|
267
|
+
] as const;
|
|
268
|
+
const cases: ReadonlyArray<readonly [string, string]> = [
|
|
269
|
+
["--model --thinking high @src", "--model"],
|
|
270
|
+
["--reviewers --panel code-experts @src", "--reviewers"],
|
|
271
|
+
...allValueFlags.map((flag) => [`${flag} @src`, flag] as const),
|
|
272
|
+
];
|
|
273
|
+
for (const [raw, flag] of cases) {
|
|
274
|
+
const parsed = parseRvArgs(raw, "loop");
|
|
275
|
+
const validation = validateRvParsed(parsed);
|
|
276
|
+
assert.equal(validation.ok, false, raw);
|
|
277
|
+
if (!validation.ok) assert.match(validation.message, new RegExp(`Missing value for ${flag}`));
|
|
278
|
+
assert.doesNotMatch(parsed.target, new RegExp(flag));
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("keeps target text after an explicit -- separator when a preceding flag is missing", () => {
|
|
283
|
+
const parsed = parseRvArgs("--model -- @src", "panel");
|
|
284
|
+
const validation = validateRvParsed(parsed);
|
|
285
|
+
assert.equal(validation.ok, false);
|
|
286
|
+
if (!validation.ok) assert.match(validation.message, /Missing value for --model/);
|
|
287
|
+
assert.equal(parsed.target, "@src");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("rejects panel-only options for explicit single-reviewer mode", () => {
|
|
291
|
+
for (const raw of [
|
|
292
|
+
"--reviewers 1 --consensus quorum @src",
|
|
293
|
+
"--reviewers 1 --min-agree 1 @src",
|
|
294
|
+
"--reviewers 1 --reviewer-model r1=openai/gpt-5.5 @src",
|
|
295
|
+
"--reviewers 1 --consensus-model openai/gpt-5.5 @src",
|
|
296
|
+
"--reviewers 1 --concurrency 1 @src",
|
|
297
|
+
]) {
|
|
298
|
+
const validation = validateRvParsed(parseRvArgs(raw, "panel"));
|
|
299
|
+
assert.equal(validation.ok, false, raw);
|
|
300
|
+
if (!validation.ok) assert.match(validation.message, /panel options require --reviewers > 1 or --panel/);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("parses repeatable --reviewer-model mappings into argv", () => {
|
|
305
|
+
const parsed = parseRvArgs(
|
|
306
|
+
"--reviewers 3 --reviewer-model r1=openai-codex/gpt-5.6-sol --reviewer-model r2=anthropic/claude-sonnet-4-5 @src",
|
|
307
|
+
"loop",
|
|
308
|
+
);
|
|
309
|
+
assert.deepEqual(parsed.reviewerModels, [
|
|
310
|
+
"r1=openai-codex/gpt-5.6-sol",
|
|
311
|
+
"r2=anthropic/claude-sonnet-4-5",
|
|
312
|
+
]);
|
|
313
|
+
assert.equal(validateRvParsed(parsed).ok, true);
|
|
314
|
+
assert.deepEqual(buildPiReviewArgv(parsed, "@src"), [
|
|
315
|
+
"pi-review",
|
|
316
|
+
"loop",
|
|
317
|
+
"--max-rounds",
|
|
318
|
+
"1",
|
|
319
|
+
"--reviewers",
|
|
320
|
+
"3",
|
|
321
|
+
"--reviewer-model",
|
|
322
|
+
"r1=openai-codex/gpt-5.6-sol",
|
|
323
|
+
"--reviewer-model",
|
|
324
|
+
"r2=anthropic/claude-sonnet-4-5",
|
|
325
|
+
"--",
|
|
326
|
+
"@src",
|
|
327
|
+
]);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it("/rv-models selects the models strategy", () => {
|
|
331
|
+
const parsed = parseRvArgs("", "models");
|
|
332
|
+
assert.equal(parsed.strategy, "models");
|
|
333
|
+
assert.equal(parsed.modelsOnly, true);
|
|
334
|
+
const prompt = buildRvOrchestrationPrompt(parsed);
|
|
335
|
+
assert.match(prompt, /Execute: pi-review models/);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it("orchestration includes catalog resolution notes when provided", () => {
|
|
339
|
+
const prompt = buildRvOrchestrationPrompt(
|
|
340
|
+
parseRvArgs("--model openai-codex/gpt-5.5 @src"),
|
|
341
|
+
"en",
|
|
342
|
+
["model gpt-5.5 → openai-codex/gpt-5.5", "thinking 最高 → xhigh"],
|
|
343
|
+
);
|
|
344
|
+
assert.match(prompt, /Resolved user shortcuts against the live model catalog/);
|
|
345
|
+
assert.match(prompt, /model gpt-5\.5 → openai-codex\/gpt-5\.5/);
|
|
346
|
+
assert.match(prompt, /thinking 最高 → xhigh/);
|
|
347
|
+
assert.match(prompt, /Use model exactly as resolved: openai-codex\/gpt-5\.5/);
|
|
348
|
+
});
|
|
349
|
+
|
|
78
350
|
it("continuations retain the session-aware CLI path", () => {
|
|
79
351
|
const prompt = buildRvOrchestrationPrompt(parseRvArgs("--continue /tmp/review.jsonl @src/foo.ts"));
|
|
80
|
-
assert.match(prompt, /Execute:\npi-review --continue \/tmp\/review\.jsonl -- @src\/foo\.ts/);
|
|
352
|
+
assert.match(prompt, /Execute exactly \(already shell-quoted; do not re-quote or drop flags\):\npi-review --continue \/tmp\/review\.jsonl -- @src\/foo\.ts/);
|
|
81
353
|
assert.doesNotMatch(prompt, /Call pi_review with target/);
|
|
82
354
|
});
|
|
83
355
|
|