@zephyrdeng/pi-review 0.6.1 → 0.7.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 +110 -13
- package/README.zh-CN.md +64 -3
- package/dist/args.d.ts +8 -0
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +147 -28
- package/dist/args.js.map +1 -1
- package/dist/args.test.d.ts +2 -0
- package/dist/args.test.d.ts.map +1 -0
- package/dist/args.test.js +115 -0
- package/dist/args.test.js.map +1 -0
- package/dist/cli-exit.test.d.ts +2 -0
- package/dist/cli-exit.test.d.ts.map +1 -0
- package/dist/cli-exit.test.js +84 -0
- package/dist/cli-exit.test.js.map +1 -0
- package/dist/cli.js +16 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/extensions/review.d.ts +2 -0
- package/dist/extensions/review.js +22 -0
- package/dist/extensions/rv-prompts.d.ts +19 -0
- package/dist/extensions/rv-prompts.js +132 -0
- package/dist/index.d.ts +17 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/index.js.map +1 -1
- package/dist/json-events.d.ts +45 -0
- package/dist/json-events.d.ts.map +1 -1
- package/dist/json-events.js +185 -0
- package/dist/json-events.js.map +1 -1
- package/dist/json-events.test.js +64 -1
- package/dist/json-events.test.js.map +1 -1
- package/dist/loop.d.ts +36 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +73 -0
- package/dist/loop.js.map +1 -0
- package/dist/loop.test.d.ts +2 -0
- package/dist/loop.test.d.ts.map +1 -0
- package/dist/loop.test.js +83 -0
- package/dist/loop.test.js.map +1 -0
- package/dist/matcher.d.ts +74 -0
- package/dist/matcher.d.ts.map +1 -0
- package/dist/matcher.js +202 -0
- package/dist/matcher.js.map +1 -0
- package/dist/matcher.test.d.ts +2 -0
- package/dist/matcher.test.d.ts.map +1 -0
- package/dist/matcher.test.js +161 -0
- package/dist/matcher.test.js.map +1 -0
- package/dist/meta-footer.d.ts +15 -1
- package/dist/meta-footer.d.ts.map +1 -1
- package/dist/meta-footer.js +108 -0
- package/dist/meta-footer.js.map +1 -1
- package/dist/meta-footer.test.js +43 -1
- package/dist/meta-footer.test.js.map +1 -1
- package/dist/panel-aggregate.d.ts +18 -0
- package/dist/panel-aggregate.d.ts.map +1 -0
- package/dist/panel-aggregate.js +247 -0
- package/dist/panel-aggregate.js.map +1 -0
- package/dist/panel-aggregate.test.d.ts +2 -0
- package/dist/panel-aggregate.test.d.ts.map +1 -0
- package/dist/panel-aggregate.test.js +461 -0
- package/dist/panel-aggregate.test.js.map +1 -0
- package/dist/panel-cli.test.d.ts +2 -0
- package/dist/panel-cli.test.d.ts.map +1 -0
- package/dist/panel-cli.test.js +188 -0
- package/dist/panel-cli.test.js.map +1 -0
- package/dist/panel-config.d.ts +19 -0
- package/dist/panel-config.d.ts.map +1 -0
- package/dist/panel-config.js +115 -0
- package/dist/panel-config.js.map +1 -0
- package/dist/panel-config.test.d.ts +2 -0
- package/dist/panel-config.test.d.ts.map +1 -0
- package/dist/panel-config.test.js +91 -0
- package/dist/panel-config.test.js.map +1 -0
- package/dist/panel-loop.test.d.ts +2 -0
- package/dist/panel-loop.test.d.ts.map +1 -0
- package/dist/panel-loop.test.js +118 -0
- package/dist/panel-loop.test.js.map +1 -0
- package/dist/panel.d.ts +10 -0
- package/dist/panel.d.ts.map +1 -0
- package/dist/panel.js +315 -0
- package/dist/panel.js.map +1 -0
- package/dist/presets.d.ts +2 -1
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +10 -0
- package/dist/presets.js.map +1 -1
- package/dist/prompt.d.ts +14 -1
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +61 -15
- package/dist/prompt.js.map +1 -1
- package/dist/prompt.test.d.ts +2 -0
- package/dist/prompt.test.d.ts.map +1 -0
- package/dist/prompt.test.js +37 -0
- package/dist/prompt.test.js.map +1 -0
- package/dist/review-result.d.ts +5 -0
- package/dist/review-result.d.ts.map +1 -0
- package/dist/review-result.js +98 -0
- package/dist/review-result.js.map +1 -0
- package/dist/review-result.test.d.ts +2 -0
- package/dist/review-result.test.d.ts.map +1 -0
- package/dist/review-result.test.js +196 -0
- package/dist/review-result.test.js.map +1 -0
- package/dist/review.d.ts +10 -4
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +82 -20
- package/dist/review.js.map +1 -1
- package/dist/review.meta.test.js +2 -2
- package/dist/review.meta.test.js.map +1 -1
- package/dist/skill-protocol.test.d.ts +2 -0
- package/dist/skill-protocol.test.d.ts.map +1 -0
- package/dist/skill-protocol.test.js +35 -0
- package/dist/skill-protocol.test.js.map +1 -0
- package/dist/types.d.ts +147 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -1
- package/extensions/rv-completions.test.ts +15 -0
- package/extensions/rv-completions.ts +7 -1
- package/package.json +3 -3
- package/resources/panel-presets.json +21 -0
- package/resources/system-prompt.md +11 -1
- package/skills/pi-review/SKILL.md +90 -12
- package/skills/pi-review/references/codex-tools.md +19 -6
package/dist/json-events.js
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
// Parses pi's `--mode json` event stream. That format is owned by the pi
|
|
2
2
|
// binary, not a contract pi-review guarantees, so parsing degrades
|
|
3
3
|
// gracefully (never throws) when lines are malformed or events are missing.
|
|
4
|
+
function num(value) {
|
|
5
|
+
const n = Number(value);
|
|
6
|
+
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
7
|
+
}
|
|
8
|
+
function accumulateUsage(into, usage) {
|
|
9
|
+
if (!usage)
|
|
10
|
+
return;
|
|
11
|
+
// input/cacheRead are prompt-scoped maxima (reported per message, not summed);
|
|
12
|
+
// output is additive across assistant turns.
|
|
13
|
+
into.input = Math.max(into.input, num(usage.input));
|
|
14
|
+
into.cacheRead = Math.max(into.cacheRead, num(usage.cacheRead));
|
|
15
|
+
into.cacheWrite = Math.max(into.cacheWrite, num(usage.cacheWrite));
|
|
16
|
+
into.output += num(usage.output);
|
|
17
|
+
into.reasoning = Math.max(into.reasoning, num(usage.reasoning));
|
|
18
|
+
into.totalTokens = Math.max(into.totalTokens, num(usage.totalTokens));
|
|
19
|
+
if (typeof usage.cost?.total === "number") {
|
|
20
|
+
into.costTotal = (into.costTotal ?? 0) + usage.cost.total;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
4
23
|
function textFromMessage(message) {
|
|
5
24
|
if (!message || !Array.isArray(message.content))
|
|
6
25
|
return "";
|
|
@@ -59,4 +78,170 @@ export function extractFinalText(jsonLinesText) {
|
|
|
59
78
|
}
|
|
60
79
|
return { text };
|
|
61
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Extract token usage and the response model from a pi `--mode json` event
|
|
83
|
+
* stream. Usage is accumulated from assistant message/turn/agent_end events.
|
|
84
|
+
* Degrades gracefully (returns undefined) when usage fields are absent.
|
|
85
|
+
*/
|
|
86
|
+
export function extractUsage(jsonLinesText) {
|
|
87
|
+
const usage = {
|
|
88
|
+
input: 0,
|
|
89
|
+
output: 0,
|
|
90
|
+
cacheRead: 0,
|
|
91
|
+
cacheWrite: 0,
|
|
92
|
+
reasoning: 0,
|
|
93
|
+
totalTokens: 0,
|
|
94
|
+
};
|
|
95
|
+
let sawAnyUsage = false;
|
|
96
|
+
let responseModel;
|
|
97
|
+
for (const line of jsonLinesText.split("\n")) {
|
|
98
|
+
if (!line.trim())
|
|
99
|
+
continue;
|
|
100
|
+
let event;
|
|
101
|
+
try {
|
|
102
|
+
event = JSON.parse(line);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const candidates = [];
|
|
108
|
+
if (event?.message?.usage)
|
|
109
|
+
candidates.push(event.message);
|
|
110
|
+
else if (event?.message?.responseModel || event?.message?.model)
|
|
111
|
+
candidates.push(event.message);
|
|
112
|
+
if (event?.type === "agent_end" && Array.isArray(event.messages)) {
|
|
113
|
+
for (const m of event.messages) {
|
|
114
|
+
if (m?.usage || m?.responseModel || m?.model)
|
|
115
|
+
candidates.push(m);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const c of candidates) {
|
|
119
|
+
if (c.usage) {
|
|
120
|
+
accumulateUsage(usage, c.usage);
|
|
121
|
+
sawAnyUsage = true;
|
|
122
|
+
}
|
|
123
|
+
if (c.responseModel)
|
|
124
|
+
responseModel = c.responseModel;
|
|
125
|
+
else if (c.model && !responseModel)
|
|
126
|
+
responseModel = c.model;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!sawAnyUsage)
|
|
130
|
+
return {};
|
|
131
|
+
const result = { usage };
|
|
132
|
+
if (responseModel)
|
|
133
|
+
result.responseModel = responseModel;
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Feed one chunk of stdout from pi --mode json. Splits on newlines, buffers
|
|
138
|
+
* partial lines, and emits text deltas + milestone notices + usage updates.
|
|
139
|
+
* Returns nothing; the caller reads final usage via `streamedUsage()`.
|
|
140
|
+
*/
|
|
141
|
+
export class JsonEventStream {
|
|
142
|
+
buffer = "";
|
|
143
|
+
emit;
|
|
144
|
+
accumulate;
|
|
145
|
+
sawAnyUsage = false;
|
|
146
|
+
responseModel;
|
|
147
|
+
turn = 0;
|
|
148
|
+
inAssistantTurn = false;
|
|
149
|
+
constructor(emit) {
|
|
150
|
+
this.emit = emit;
|
|
151
|
+
this.accumulate = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, reasoning: 0, totalTokens: 0 };
|
|
152
|
+
}
|
|
153
|
+
/** Feed a raw stdout chunk (may contain partial JSON lines). */
|
|
154
|
+
feed(chunk) {
|
|
155
|
+
this.buffer += chunk;
|
|
156
|
+
let nl;
|
|
157
|
+
while ((nl = this.buffer.indexOf("\n")) >= 0) {
|
|
158
|
+
const line = this.buffer.slice(0, nl);
|
|
159
|
+
this.buffer = this.buffer.slice(nl + 1);
|
|
160
|
+
this.processLine(line);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** Flush any trailing partial line (call at end of stream). */
|
|
164
|
+
flush() {
|
|
165
|
+
if (this.buffer.trim())
|
|
166
|
+
this.processLine(this.buffer);
|
|
167
|
+
this.buffer = "";
|
|
168
|
+
}
|
|
169
|
+
/** Final accumulated token usage (undefined if no usage seen). */
|
|
170
|
+
usage() {
|
|
171
|
+
if (!this.sawAnyUsage)
|
|
172
|
+
return {};
|
|
173
|
+
const result = { usage: this.accumulate };
|
|
174
|
+
if (this.responseModel)
|
|
175
|
+
result.responseModel = this.responseModel;
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
processLine(raw) {
|
|
179
|
+
if (!raw.trim())
|
|
180
|
+
return;
|
|
181
|
+
let event;
|
|
182
|
+
try {
|
|
183
|
+
event = JSON.parse(raw);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return; // unparseable lines are skipped gracefully
|
|
187
|
+
}
|
|
188
|
+
this.handle(event);
|
|
189
|
+
}
|
|
190
|
+
handle(event) {
|
|
191
|
+
const t = event.type;
|
|
192
|
+
// Accumulate usage from any message/turn/agent_end carrying it.
|
|
193
|
+
const usageSources = [];
|
|
194
|
+
if (event.message?.usage)
|
|
195
|
+
usageSources.push(event.message);
|
|
196
|
+
if (event.assistantMessageEvent?.partial?.usage)
|
|
197
|
+
usageSources.push(event.assistantMessageEvent.partial);
|
|
198
|
+
if (t === "agent_end" && Array.isArray(event.messages)) {
|
|
199
|
+
for (const m of event.messages) {
|
|
200
|
+
if (m?.usage)
|
|
201
|
+
usageSources.push(m);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (const s of usageSources) {
|
|
205
|
+
if (s.usage) {
|
|
206
|
+
accumulateUsage(this.accumulate, s.usage);
|
|
207
|
+
this.sawAnyUsage = true;
|
|
208
|
+
}
|
|
209
|
+
if (s.responseModel)
|
|
210
|
+
this.responseModel = s.responseModel;
|
|
211
|
+
else if (s.model && !this.responseModel)
|
|
212
|
+
this.responseModel = s.model;
|
|
213
|
+
}
|
|
214
|
+
// Text deltas -> forward to the human-readable terminal.
|
|
215
|
+
if (t === "message_update" && event.assistantMessageEvent?.type === "text_delta") {
|
|
216
|
+
const delta = event.assistantMessageEvent.delta;
|
|
217
|
+
if (typeof delta === "string" && delta)
|
|
218
|
+
this.emit.onText(delta);
|
|
219
|
+
}
|
|
220
|
+
// Semantic milestones (B).
|
|
221
|
+
switch (t) {
|
|
222
|
+
case "agent_start":
|
|
223
|
+
this.emit.onMilestone("pi-review: review started\n");
|
|
224
|
+
break;
|
|
225
|
+
case "turn_start":
|
|
226
|
+
this.turn += 1;
|
|
227
|
+
this.inAssistantTurn = false;
|
|
228
|
+
if (this.turn > 1)
|
|
229
|
+
this.emit.onMilestone(`pi-review: turn ${this.turn}\n`);
|
|
230
|
+
break;
|
|
231
|
+
case "message_start":
|
|
232
|
+
if (event.message?.role === "assistant")
|
|
233
|
+
this.inAssistantTurn = true;
|
|
234
|
+
break;
|
|
235
|
+
case "tool_execution_start":
|
|
236
|
+
this.emit.onMilestone(`pi-review: tool ${event.toolName ?? "unknown"} started\n`);
|
|
237
|
+
break;
|
|
238
|
+
case "tool_execution_end":
|
|
239
|
+
this.emit.onMilestone(`pi-review: tool ${event.toolName ?? "unknown"} finished\n`);
|
|
240
|
+
break;
|
|
241
|
+
case "agent_end":
|
|
242
|
+
this.emit.onMilestone("pi-review: review finished\n");
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
62
247
|
//# sourceMappingURL=json-events.js.map
|
package/dist/json-events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-events.js","sourceRoot":"","sources":["../src/json-events.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,mEAAmE;AACnE,4EAA4E;
|
|
1
|
+
{"version":3,"file":"json-events.js","sourceRoot":"","sources":["../src/json-events.ts"],"names":[],"mappings":"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"}
|
package/dist/json-events.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { test } from "node:test";
|
|
3
|
-
import { extractFinalText } from "./json-events.js";
|
|
3
|
+
import { extractFinalText, extractUsage, JsonEventStream } from "./json-events.js";
|
|
4
4
|
function lines(...events) {
|
|
5
5
|
return events.map((e) => JSON.stringify(e)).join("\n");
|
|
6
6
|
}
|
|
@@ -85,4 +85,67 @@ test("extractFinalText uses the last agent_end when the child retries", () => {
|
|
|
85
85
|
assert.equal(result.text, "final attempt");
|
|
86
86
|
assert.equal(result.fatal, undefined);
|
|
87
87
|
});
|
|
88
|
+
test("extractUsage accumulates tokens from message_end and agent_end", () => {
|
|
89
|
+
const input = lines({ type: "session", id: "s1" }, { type: "message_end", message: { role: "assistant", usage: { input: 44, output: 3, cacheRead: 17984, cacheWrite: 0, reasoning: 0, totalTokens: 18031, cost: { total: 0.025 } }, model: "hf:zai-org/GLM-5.2" } }, { type: "agent_end", messages: [{ role: "assistant", responseModel: "zai-org/GLM-5.2" }] });
|
|
90
|
+
const result = extractUsage(input);
|
|
91
|
+
assert.ok(result.usage);
|
|
92
|
+
assert.equal(result.usage.input, 44);
|
|
93
|
+
assert.equal(result.usage.output, 3);
|
|
94
|
+
assert.equal(result.usage.cacheRead, 17984);
|
|
95
|
+
assert.equal(result.usage.totalTokens, 18031);
|
|
96
|
+
assert.equal(result.usage.costTotal, 0.025);
|
|
97
|
+
assert.equal(result.responseModel, "zai-org/GLM-5.2");
|
|
98
|
+
});
|
|
99
|
+
test("extractUsage returns undefined when no usage events exist", () => {
|
|
100
|
+
const input = lines({ type: "session", id: "s1" }, { type: "agent_end", messages: [{ role: "assistant" }] });
|
|
101
|
+
const result = extractUsage(input);
|
|
102
|
+
assert.equal(result.usage, undefined);
|
|
103
|
+
assert.equal(result.responseModel, undefined);
|
|
104
|
+
});
|
|
105
|
+
test("extractUsage sums output across multiple assistant turns", () => {
|
|
106
|
+
const input = lines({ type: "message_end", message: { role: "assistant", usage: { input: 100, output: 50, totalTokens: 150 } } }, { type: "message_end", message: { role: "assistant", usage: { input: 100, output: 30, totalTokens: 130 } } });
|
|
107
|
+
const result = extractUsage(input);
|
|
108
|
+
assert.equal(result.usage.output, 80);
|
|
109
|
+
assert.equal(result.usage.input, 100);
|
|
110
|
+
});
|
|
111
|
+
test("JsonEventStream forwards text deltas and emits milestones", () => {
|
|
112
|
+
const texts = [];
|
|
113
|
+
const milestones = [];
|
|
114
|
+
const stream = new JsonEventStream({ onText: (c) => texts.push(c), onMilestone: (l) => milestones.push(l) });
|
|
115
|
+
const input = lines({ type: "agent_start" }, { type: "turn_start" }, { type: "message_update", assistantMessageEvent: { type: "text_delta", delta: "Hello ", partial: { role: "assistant" } } }, { type: "message_update", assistantMessageEvent: { type: "text_delta", delta: "world", partial: { role: "assistant" } } }, { type: "agent_end", messages: [{ role: "assistant", content: [{ type: "text", text: "Hello world" }], responseModel: "fake/model" }] });
|
|
116
|
+
stream.feed(input);
|
|
117
|
+
stream.flush();
|
|
118
|
+
assert.equal(texts.join(""), "Hello world");
|
|
119
|
+
assert.ok(milestones.some((m) => /review started/.test(m)));
|
|
120
|
+
assert.ok(milestones.some((m) => /review finished/.test(m)));
|
|
121
|
+
const usage = stream.usage();
|
|
122
|
+
assert.ok(usage.responseModel === "fake/model" || usage.responseModel === undefined);
|
|
123
|
+
});
|
|
124
|
+
test("JsonEventStream accumulates token usage from streamed events", () => {
|
|
125
|
+
const stream = new JsonEventStream({ onText: () => { }, onMilestone: () => { } });
|
|
126
|
+
stream.feed(lines({ type: "message_end", message: { role: "assistant", usage: { input: 200, output: 50, cacheRead: 100, cacheWrite: 0, reasoning: 10, totalTokens: 260 } } }));
|
|
127
|
+
stream.flush();
|
|
128
|
+
const usage = stream.usage().usage;
|
|
129
|
+
assert.ok(usage);
|
|
130
|
+
assert.equal(usage.input, 200);
|
|
131
|
+
assert.equal(usage.output, 50);
|
|
132
|
+
assert.equal(usage.cacheRead, 100);
|
|
133
|
+
assert.equal(usage.reasoning, 10);
|
|
134
|
+
});
|
|
135
|
+
test("JsonEventStream handles partial lines across chunks", () => {
|
|
136
|
+
const texts = [];
|
|
137
|
+
const stream = new JsonEventStream({ onText: (c) => texts.push(c), onMilestone: () => { } });
|
|
138
|
+
// Feed a partial line, then complete it.
|
|
139
|
+
stream.feed('{"type":"message_update","assistantMessageEvent":{"type":"text_delta","delta":"par');
|
|
140
|
+
stream.feed('tial","partial":{"role":"assistant"}}}\n');
|
|
141
|
+
stream.flush();
|
|
142
|
+
assert.equal(texts.join(""), "partial");
|
|
143
|
+
});
|
|
144
|
+
test("JsonEventStream skips unparseable lines without throwing", () => {
|
|
145
|
+
const stream = new JsonEventStream({ onText: () => { }, onMilestone: () => { } });
|
|
146
|
+
stream.feed("not json\n");
|
|
147
|
+
stream.feed('{"type":"message_update","assistantMessageEvent":{"type":"text_delta","delta":"ok","partial":{"role":"assistant"}}}\n');
|
|
148
|
+
stream.flush();
|
|
149
|
+
assert.equal(stream.usage().usage, undefined);
|
|
150
|
+
});
|
|
88
151
|
//# sourceMappingURL=json-events.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-events.test.js","sourceRoot":"","sources":["../src/json-events.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"json-events.test.js","sourceRoot":"","sources":["../src/json-events.test.ts"],"names":[],"mappings":"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"}
|
package/dist/loop.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReviewRunResult, ReviewStatus, Verdict } from "./types.js";
|
|
2
|
+
export type LoopStopReason = "clean" | "budget_exhausted" | "needs_human" | "blocked";
|
|
3
|
+
export interface LoopRoundPanelSummary {
|
|
4
|
+
configuredReviewers: number;
|
|
5
|
+
successfulReviewers: number;
|
|
6
|
+
confirmedCount: number;
|
|
7
|
+
advisoryCount: number;
|
|
8
|
+
consensusPolicy: string;
|
|
9
|
+
consensusThreshold: number;
|
|
10
|
+
panelHealth: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LoopRoundSummary {
|
|
13
|
+
index: number;
|
|
14
|
+
status: ReviewStatus;
|
|
15
|
+
verdict: Verdict;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
findingCount: number;
|
|
18
|
+
actionableCount: number;
|
|
19
|
+
/** Thinking level requested for this round, if any. */
|
|
20
|
+
thinking?: string;
|
|
21
|
+
/** Token usage for this round, when available. */
|
|
22
|
+
usage?: import("./types.js").TokenUsage;
|
|
23
|
+
/** Present when the round evaluated a panel. */
|
|
24
|
+
panel?: LoopRoundPanelSummary;
|
|
25
|
+
}
|
|
26
|
+
export interface LoopReviewResult {
|
|
27
|
+
rounds: LoopRoundSummary[];
|
|
28
|
+
finalStatus: ReviewStatus;
|
|
29
|
+
stopReason: LoopStopReason;
|
|
30
|
+
exitCode: number;
|
|
31
|
+
}
|
|
32
|
+
export type RunOneReview = (roundIndex: number) => Promise<ReviewRunResult>;
|
|
33
|
+
export declare function formatLoopSummary(result: LoopReviewResult): string;
|
|
34
|
+
/** Runs isolated review rounds through an injected single-run adapter. */
|
|
35
|
+
export declare function runReviewLoop(maxRounds: number, runOneReview: RunOneReview): Promise<LoopReviewResult>;
|
|
36
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA+B,eAAe,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEtG,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAAC;AAEtF,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,YAAY,EAAE,UAAU,CAAC;IACxC,gDAAgD;IAChD,KAAK,CAAC,EAAE,qBAAqB,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,WAAW,EAAE,YAAY,CAAC;IAC1B,UAAU,EAAE,cAAc,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAM5E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAmBlE;AAED,0EAA0E;AAC1E,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAgD3B"}
|
package/dist/loop.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { formatDurationMs, formatUsage } from "./meta-footer.js";
|
|
2
|
+
import { reviewExitCode } from "./review-result.js";
|
|
3
|
+
function displayEnum(value) {
|
|
4
|
+
return value.replaceAll("_", " ").toUpperCase();
|
|
5
|
+
}
|
|
6
|
+
export function formatLoopSummary(result) {
|
|
7
|
+
const lines = ["── pi-review loop " + "─".repeat(23)];
|
|
8
|
+
for (const round of result.rounds) {
|
|
9
|
+
const tokenBit = round.usage ? ` | ${formatUsage(round.usage)}` : "";
|
|
10
|
+
const thinkBit = round.thinking ? ` | think:${round.thinking}` : "";
|
|
11
|
+
if (round.panel) {
|
|
12
|
+
lines.push(` Round ${round.index} ${displayEnum(round.status)} | panel ${round.panel.successfulReviewers}/${round.panel.configuredReviewers} | ${round.panel.confirmedCount} confirmed / ${round.panel.advisoryCount} advisory | ${round.panel.consensusPolicy}≥${round.panel.consensusThreshold} | ${displayEnum(round.panel.panelHealth)}${thinkBit}${tokenBit} | ${formatDurationMs(round.durationMs)}`);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
lines.push(` Round ${round.index} ${displayEnum(round.status)} | ${displayEnum(round.verdict)} | ${round.actionableCount} actionable / ${round.findingCount} total${thinkBit}${tokenBit} | ${formatDurationMs(round.durationMs)}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
lines.push(` Stop ${result.stopReason}`);
|
|
19
|
+
lines.push(` Exit ${result.exitCode}`);
|
|
20
|
+
lines.push("─".repeat(42));
|
|
21
|
+
return lines.join("\n");
|
|
22
|
+
}
|
|
23
|
+
/** Runs isolated review rounds through an injected single-run adapter. */
|
|
24
|
+
export async function runReviewLoop(maxRounds, runOneReview) {
|
|
25
|
+
if (!Number.isSafeInteger(maxRounds) || maxRounds < 1) {
|
|
26
|
+
throw new RangeError("maxRounds must be a positive integer");
|
|
27
|
+
}
|
|
28
|
+
const rounds = [];
|
|
29
|
+
for (let index = 1; index <= maxRounds; index += 1) {
|
|
30
|
+
const run = await runOneReview(index);
|
|
31
|
+
const { meta } = run;
|
|
32
|
+
const panel = isPanelMeta(meta)
|
|
33
|
+
? {
|
|
34
|
+
configuredReviewers: meta.configuredReviewers,
|
|
35
|
+
successfulReviewers: meta.successfulReviewers,
|
|
36
|
+
confirmedCount: meta.confirmedClusters.length,
|
|
37
|
+
advisoryCount: meta.advisories.length,
|
|
38
|
+
consensusPolicy: meta.consensusPolicy,
|
|
39
|
+
consensusThreshold: meta.consensusThreshold,
|
|
40
|
+
panelHealth: meta.panelHealth,
|
|
41
|
+
}
|
|
42
|
+
: undefined;
|
|
43
|
+
rounds.push({
|
|
44
|
+
index,
|
|
45
|
+
status: meta.status,
|
|
46
|
+
verdict: meta.verdict,
|
|
47
|
+
durationMs: meta.durationMs,
|
|
48
|
+
findingCount: meta.findings.length,
|
|
49
|
+
actionableCount: meta.actionableCount,
|
|
50
|
+
...(meta.thinking ? { thinking: meta.thinking } : {}),
|
|
51
|
+
...(meta.usage ? { usage: meta.usage } : {}),
|
|
52
|
+
...(panel ? { panel } : {}),
|
|
53
|
+
});
|
|
54
|
+
if (meta.status === "clean" || meta.status === "needs_human" || meta.status === "blocked") {
|
|
55
|
+
return {
|
|
56
|
+
rounds,
|
|
57
|
+
finalStatus: meta.status,
|
|
58
|
+
stopReason: meta.status,
|
|
59
|
+
exitCode: reviewExitCode(meta.status),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
rounds,
|
|
65
|
+
finalStatus: "has_findings",
|
|
66
|
+
stopReason: "budget_exhausted",
|
|
67
|
+
exitCode: reviewExitCode("has_findings"),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function isPanelMeta(meta) {
|
|
71
|
+
return meta.strategy === "panel";
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=loop.js.map
|
package/dist/loop.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.test.d.ts","sourceRoot":"","sources":["../src/loop.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { formatLoopSummary, runReviewLoop } from "./loop.js";
|
|
4
|
+
function meta(status, verdict, durationMs = 100) {
|
|
5
|
+
return {
|
|
6
|
+
reviewMode: "code",
|
|
7
|
+
verdict,
|
|
8
|
+
verdictSource: "parsed",
|
|
9
|
+
status,
|
|
10
|
+
findings: status === "has_findings"
|
|
11
|
+
? [{ id: "F1", summary: "Fix the gate", actionable: true }]
|
|
12
|
+
: [],
|
|
13
|
+
actionableCount: status === "has_findings" ? 1 : 0,
|
|
14
|
+
durationMs,
|
|
15
|
+
model: "provider/model",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
test("loop stops after a clean first round", async () => {
|
|
19
|
+
let calls = 0;
|
|
20
|
+
const result = await runReviewLoop(3, async () => {
|
|
21
|
+
calls += 1;
|
|
22
|
+
return { meta: meta("clean", "approve"), exitCode: 0 };
|
|
23
|
+
});
|
|
24
|
+
assert.equal(calls, 1);
|
|
25
|
+
assert.equal(result.stopReason, "clean");
|
|
26
|
+
assert.equal(result.exitCode, 0);
|
|
27
|
+
assert.deepEqual(result.rounds.map((round) => round.index), [1]);
|
|
28
|
+
});
|
|
29
|
+
test("loop stops when a later round becomes clean", async () => {
|
|
30
|
+
const sequence = [
|
|
31
|
+
{ meta: meta("has_findings", "request_changes", 120), exitCode: 1 },
|
|
32
|
+
{ meta: meta("clean", "approve", 80), exitCode: 0 },
|
|
33
|
+
];
|
|
34
|
+
const result = await runReviewLoop(3, async (roundIndex) => sequence[roundIndex - 1]);
|
|
35
|
+
assert.equal(result.stopReason, "clean");
|
|
36
|
+
assert.equal(result.exitCode, 0);
|
|
37
|
+
assert.deepEqual(result.rounds.map((round) => round.status), ["has_findings", "clean"]);
|
|
38
|
+
assert.deepEqual(result.rounds.map((round) => round.durationMs), [120, 80]);
|
|
39
|
+
});
|
|
40
|
+
test("loop exhausts the budget while actionable findings remain", async () => {
|
|
41
|
+
let calls = 0;
|
|
42
|
+
const result = await runReviewLoop(2, async () => {
|
|
43
|
+
calls += 1;
|
|
44
|
+
return { meta: meta("has_findings", "request_changes"), exitCode: 1 };
|
|
45
|
+
});
|
|
46
|
+
assert.equal(calls, 2);
|
|
47
|
+
assert.equal(result.stopReason, "budget_exhausted");
|
|
48
|
+
assert.equal(result.finalStatus, "has_findings");
|
|
49
|
+
assert.equal(result.exitCode, 1);
|
|
50
|
+
assert.equal(result.rounds.length, 2);
|
|
51
|
+
});
|
|
52
|
+
test("loop escalates blocked and needs-human outcomes immediately", async () => {
|
|
53
|
+
const scenarios = [
|
|
54
|
+
{ status: "blocked", verdict: "blocked", exitCode: 4 },
|
|
55
|
+
{ status: "needs_human", verdict: "needs_clarification", exitCode: 3 },
|
|
56
|
+
];
|
|
57
|
+
for (const scenario of scenarios) {
|
|
58
|
+
let calls = 0;
|
|
59
|
+
const result = await runReviewLoop(3, async () => {
|
|
60
|
+
calls += 1;
|
|
61
|
+
return {
|
|
62
|
+
meta: meta(scenario.status, scenario.verdict),
|
|
63
|
+
exitCode: scenario.exitCode,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
assert.equal(calls, 1);
|
|
67
|
+
assert.equal(result.stopReason, scenario.status);
|
|
68
|
+
assert.equal(result.exitCode, scenario.exitCode);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
test("loop summary reports each round and final outcome", async () => {
|
|
72
|
+
const sequence = [
|
|
73
|
+
{ meta: meta("has_findings", "request_changes", 1_200), exitCode: 1 },
|
|
74
|
+
{ meta: meta("clean", "approve", 800), exitCode: 0 },
|
|
75
|
+
];
|
|
76
|
+
const result = await runReviewLoop(3, async (roundIndex) => sequence[roundIndex - 1]);
|
|
77
|
+
const summary = formatLoopSummary(result);
|
|
78
|
+
assert.match(summary, /pi-review loop/);
|
|
79
|
+
assert.match(summary, /Round 1.*HAS FINDINGS.*REQUEST CHANGES.*1\.2s/);
|
|
80
|
+
assert.match(summary, /Round 2.*CLEAN.*APPROVE.*800ms/);
|
|
81
|
+
assert.match(summary, /Stop.*clean/);
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=loop.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.test.js","sourceRoot":"","sources":["../src/loop.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type SourceFinding } from "./types.js";
|
|
2
|
+
/** Result of matching a set of source findings into clusters. */
|
|
3
|
+
export interface MatchResult {
|
|
4
|
+
/**
|
|
5
|
+
* Each group is a list of source finding IDs that represent the same
|
|
6
|
+
* underlying issue. Every input source ID must appear in exactly one group.
|
|
7
|
+
*/
|
|
8
|
+
groups: string[][];
|
|
9
|
+
/** Matcher-detected problems (invented IDs, missing IDs, malformed output). */
|
|
10
|
+
errors: string[];
|
|
11
|
+
/** True when a semantic adjudicator was actually consulted. */
|
|
12
|
+
adjudicationUsed: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** A finding matcher clusters source findings into groups. */
|
|
15
|
+
export interface FindingMatcher {
|
|
16
|
+
match(findings: SourceFinding[]): MatchResult | Promise<MatchResult>;
|
|
17
|
+
}
|
|
18
|
+
/** Normalize a path anchor so reviewers that phrase paths slightly differently still match. */
|
|
19
|
+
export declare function normalizePath(value: string | undefined): string;
|
|
20
|
+
/** Normalize a finding summary for deterministic comparison. */
|
|
21
|
+
export declare function normalizeSummary(value: string | undefined): string;
|
|
22
|
+
/** Deterministic cluster key: shared path anchor plus normalized summary. */
|
|
23
|
+
export declare function deterministicKey(finding: {
|
|
24
|
+
path?: string;
|
|
25
|
+
summary: string;
|
|
26
|
+
}): string;
|
|
27
|
+
/**
|
|
28
|
+
* Phase-one matcher: clusters findings that share a path anchor AND a
|
|
29
|
+
* normalized summary. Findings with different paths never merge here; findings
|
|
30
|
+
* with the same path but different wording form separate clusters and become
|
|
31
|
+
* candidates for semantic adjudication.
|
|
32
|
+
*/
|
|
33
|
+
export declare class DeterministicMatcher implements FindingMatcher {
|
|
34
|
+
match(findings: SourceFinding[]): MatchResult;
|
|
35
|
+
}
|
|
36
|
+
/** A candidate group sharing a path anchor but differing in wording. */
|
|
37
|
+
export interface AdjudicationCandidate {
|
|
38
|
+
anchorPath: string;
|
|
39
|
+
findings: SourceFinding[];
|
|
40
|
+
}
|
|
41
|
+
/** Request sent to a semantic adjudicator. */
|
|
42
|
+
export interface AdjudicationRequest {
|
|
43
|
+
candidates: AdjudicationCandidate[];
|
|
44
|
+
}
|
|
45
|
+
/** A proposed merge of source finding IDs into one cluster. */
|
|
46
|
+
export interface AdjudicationMerge {
|
|
47
|
+
sourceFindingIds: string[];
|
|
48
|
+
confidence: number;
|
|
49
|
+
}
|
|
50
|
+
/** Response from a semantic adjudicator. */
|
|
51
|
+
export interface AdjudicationResponse {
|
|
52
|
+
merges: AdjudicationMerge[];
|
|
53
|
+
errors?: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A constrained semantic adjudicator. It receives structured findings only and
|
|
57
|
+
* returns proposed merges with confidence. It may not invent source IDs, drop
|
|
58
|
+
* source IDs, claim new evidence, or act as another reviewer.
|
|
59
|
+
*/
|
|
60
|
+
export interface SemanticAdjudicator {
|
|
61
|
+
adjudicate(request: AdjudicationRequest): AdjudicationResponse | Promise<AdjudicationResponse>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Phase-two matcher: deterministic first, then an injected adjudicator may
|
|
65
|
+
* merge ambiguous same-path candidates. Low-confidence matches are not merged.
|
|
66
|
+
* Invented or missing source IDs are reported as errors and never merged.
|
|
67
|
+
*/
|
|
68
|
+
export declare class SemanticMatcher implements FindingMatcher {
|
|
69
|
+
private readonly adjudicator;
|
|
70
|
+
private readonly deterministic;
|
|
71
|
+
constructor(adjudicator: SemanticAdjudicator);
|
|
72
|
+
match(findings: SourceFinding[]): Promise<MatchResult>;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"AAQA,OAAO,EAAuC,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAErF,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;IACnB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+DAA+D;IAC/D,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACtE;AAED,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAO/D;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQlE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEpF;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,KAAK,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,WAAW;CAoB9C;AAED,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACrC;AAED,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,OAAO,EAAE,mBAAmB,GAAG,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAChG;AAED;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,cAAc;IAExC,OAAO,CAAC,QAAQ,CAAC,WAAW;IADxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8B;gBAC/B,WAAW,EAAE,mBAAmB;IAEvD,KAAK,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAgI7D"}
|