@zephyrdeng/pi-review 0.4.7 → 0.4.8
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 +20 -0
- package/README.zh-CN.md +1 -1
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +8 -0
- package/dist/args.js.map +1 -1
- package/dist/json-events.d.ts +7 -0
- package/dist/json-events.d.ts.map +1 -0
- package/dist/json-events.js +62 -0
- package/dist/json-events.js.map +1 -0
- package/dist/json-events.test.d.ts +2 -0
- package/dist/json-events.test.d.ts.map +1 -0
- package/dist/json-events.test.js +88 -0
- package/dist/json-events.test.js.map +1 -0
- package/dist/review.d.ts +2 -0
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +62 -9
- package/dist/review.js.map +1 -1
- package/dist/review.meta.test.js +7 -1
- package/dist/review.meta.test.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/skills/pi-review/SKILL.md +7 -6
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ Works as a standalone CLI, a Pi package (extension + skill), or integrated into
|
|
|
21
21
|
- **Structured output** — machine-readable `PI_REVIEW_META` JSON footer for automation
|
|
22
22
|
- **Model-agnostic** — use any model available in your Pi installation
|
|
23
23
|
- **Live streaming** — child review output is forwarded as it arrives (use `--no-stream` to buffer)
|
|
24
|
+
- **Progress logging for AI hosts** — `--progress-log <path>` writes a live JSON event log so agent hosts that buffer tool stdout (Claude Code, Codex, ...) can still show real-time progress
|
|
24
25
|
- **Session continuity** — keep sessions alive for follow-up questions with `--keep-session`
|
|
25
26
|
- **Customizable presets** — extend or override review modes via JSON configuration
|
|
26
27
|
- **Pi package integration** — `/rv` slash command and agent skill included
|
|
@@ -135,6 +136,24 @@ pi-review --mode challenge --keep-session -- @docs/design.md
|
|
|
135
136
|
pi-review --continue <sessionHandle> --mode challenge --model provider/model -- "expand finding 2"
|
|
136
137
|
```
|
|
137
138
|
|
|
139
|
+
## Live Progress in AI Hosts
|
|
140
|
+
|
|
141
|
+
Agent hosts like Claude Code, Cursor, and Codex typically buffer a Bash tool's stdout until the command exits, so a multi-minute review can look like a silent wait followed by one large dump — even though `pi-review` streams by default. `--progress-log <path>` sidesteps this: it runs the child in `--mode json` and writes its event log to a file in real time, independent of what the calling tool does with stdout.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Start the review in the background, writing structured progress events to a file
|
|
145
|
+
pi-review --progress-log /tmp/pi-review.jsonl -- @src/foo.ts &
|
|
146
|
+
|
|
147
|
+
# Tail it from another process/tool (e.g. Claude Code's Monitor tool) for live updates.
|
|
148
|
+
# `message_update` and `tool_execution_update` carry high-frequency token-level deltas —
|
|
149
|
+
# excluding them keeps the feed to milestone events (tool start/end, turn end, agent end).
|
|
150
|
+
tail -f -n +1 /tmp/pi-review.jsonl | jq -c --unbuffered '
|
|
151
|
+
select(.type != "message_update" and .type != "tool_execution_update")
|
|
152
|
+
'
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The JSON event schema is pi CLI's own internal format, not a contract `pi-review` guarantees — it may change between pi versions. `pi-review` parses it defensively (unparseable lines are skipped, missing events degrade to a diagnostic `parseError`) and still prints the same clean Markdown + `PI_REVIEW_META` footer to stdout once the child exits.
|
|
156
|
+
|
|
138
157
|
## CLI Reference
|
|
139
158
|
|
|
140
159
|
```
|
|
@@ -154,6 +173,7 @@ pi-review models [search]
|
|
|
154
173
|
| `--continue <handle>` | Continue an existing session |
|
|
155
174
|
| `--name <name>` | Session name (with `--keep-session`) |
|
|
156
175
|
| `--no-stream` | Buffer child output until exit (default: stream live) |
|
|
176
|
+
| `--progress-log <path>` | Stream child `--mode json` events to this file (cannot combine with `--no-stream`) |
|
|
157
177
|
|
|
158
178
|
## Configuration
|
|
159
179
|
|
package/README.zh-CN.md
CHANGED
|
@@ -62,7 +62,7 @@ pi-review models
|
|
|
62
62
|
|
|
63
63
|
跟进审查时,`--continue` 与首次 `/rv` 一样可**选填** `--mode`、`--model`(以及后续 CLI 支持的其它选项由 skill 直接调用 CLI 时传入)。
|
|
64
64
|
|
|
65
|
-
`/rv` 会向主会话注入**英文任务说明**(按 `--mode` 等参数区分),由主 Agent 按 **pi-review** skill 调用 `pi-review` CLI 跑子会话。`pi-review` **默认流式转发**子进程输出,终端可实时看到审查进度;需要整段缓冲时加 `--no-stream
|
|
65
|
+
`/rv` 会向主会话注入**英文任务说明**(按 `--mode` 等参数区分),由主 Agent 按 **pi-review** skill 调用 `pi-review` CLI 跑子会话。`pi-review` **默认流式转发**子进程输出,终端可实时看到审查进度;需要整段缓冲时加 `--no-stream`。若在 Claude Code / Codex 这类会缓冲 Bash 工具 stdout 的 AI host 里使用,可加 `--progress-log <path>` 把结构化进度事件实时写入文件,配合 `tail -f` 之类的工具在宿主里也能看到实时进度(见英文 README 的 “Live Progress in AI Hosts”)。Tab 补全是固定选项提示,不是另一套实现。
|
|
66
66
|
|
|
67
67
|
## 输出格式
|
|
68
68
|
|
package/dist/args.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA+C7C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA+FpD"}
|
package/dist/args.js
CHANGED
|
@@ -16,6 +16,7 @@ Options:
|
|
|
16
16
|
--skill <path> Load an extra pi skill (repeatable)
|
|
17
17
|
--tools <csv> Override allowed tools
|
|
18
18
|
--no-stream Buffer child output until exit (default: stream live)
|
|
19
|
+
--progress-log <path> Stream child --mode json events to this file (cannot combine with --no-stream)
|
|
19
20
|
-h, --help Show help
|
|
20
21
|
|
|
21
22
|
Session (requires Pi session support):
|
|
@@ -108,6 +109,9 @@ export function parseArgs(argv) {
|
|
|
108
109
|
case "--no-stream":
|
|
109
110
|
options.stream = false;
|
|
110
111
|
break;
|
|
112
|
+
case "--progress-log":
|
|
113
|
+
options.progressLog = requireValue(arg, argv);
|
|
114
|
+
break;
|
|
111
115
|
default:
|
|
112
116
|
if (arg.startsWith("--")) {
|
|
113
117
|
process.stderr.write(`pi-review: unknown option: ${arg}\n`);
|
|
@@ -122,6 +126,10 @@ export function parseArgs(argv) {
|
|
|
122
126
|
process.stderr.write("pi-review: --keep-session and --continue cannot be used together\n");
|
|
123
127
|
process.exit(2);
|
|
124
128
|
}
|
|
129
|
+
if (options.progressLog && !options.stream) {
|
|
130
|
+
process.stderr.write("pi-review: --progress-log cannot be used with --no-stream\n");
|
|
131
|
+
process.exit(2);
|
|
132
|
+
}
|
|
125
133
|
return options;
|
|
126
134
|
}
|
|
127
135
|
//# sourceMappingURL=args.js.map
|
package/dist/args.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAEA,SAAS,KAAK,CAAC,QAAQ,GAAG,CAAC;IACzB,MAAM,GAAG,GAAG
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAEA,SAAS,KAAK,CAAC,QAAQ,GAAG,CAAC;IACzB,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Bb,CAAC;IACA,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9D,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,IAAc;IAChD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,IAAI,qBAAqB,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,EAAG,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ;QAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5E,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC/H,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,eAAe,EAAE,CAAC;QAChC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACzI,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,iBAAiB,EAAE,CAAC;QAClC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3I,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACxG,CAAC;IAED,IAAI,IAAI,GAAG,MAAM,CAAC;IAClB,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,IAAI,GAAG,IAAI,CAAC,KAAK,EAAG,CAAC;IACvB,CAAC;IAED,MAAM,OAAO,GAAe;QAC1B,OAAO,EAAE,QAAQ;QACjB,IAAI;QACJ,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,KAAK;QAClB,MAAM,EAAE,IAAI;KACb,CAAC;IAEF,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAG,CAAC;QAC1B,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM;QACR,CAAC;QACD,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACX,KAAK,CAAC,CAAC,CAAC,CAAC;gBACT,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACvC,MAAM;YACR,KAAK,gBAAgB;gBACnB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;gBAC3B,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,CAAC,cAAc,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACjD,MAAM;YACR,KAAK,SAAS;gBACZ,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACxC,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC3C,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC3C,MAAM;YACR,KAAK,SAAS;gBACZ,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC7C,MAAM;YACR,KAAK,SAAS;gBACZ,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACxC,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACvC,MAAM;YACR,KAAK,aAAa;gBAChB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;gBACvB,MAAM;YACR,KAAK,gBAAgB;gBACnB,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC9C,MAAM;YACR;gBACE,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,GAAG,IAAI,CAAC,CAAC;oBAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBACD,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;gBACnC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;gBAChB,MAAM;QACV,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oEAAoE,CAAC,CAAC;QAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-events.d.ts","sourceRoot":"","sources":["../src/json-events.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAcD,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,kBAAkB,CAsD1E"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Parses pi's `--mode json` event stream. That format is owned by the pi
|
|
2
|
+
// binary, not a contract pi-review guarantees, so parsing degrades
|
|
3
|
+
// gracefully (never throws) when lines are malformed or events are missing.
|
|
4
|
+
function textFromMessage(message) {
|
|
5
|
+
if (!message || !Array.isArray(message.content))
|
|
6
|
+
return "";
|
|
7
|
+
return message.content
|
|
8
|
+
.filter((block) => block?.type === "text" && typeof block.text === "string")
|
|
9
|
+
.map((block) => block.text)
|
|
10
|
+
.join("");
|
|
11
|
+
}
|
|
12
|
+
function isFatalStop(message) {
|
|
13
|
+
return message.stopReason === "error" || message.stopReason === "aborted";
|
|
14
|
+
}
|
|
15
|
+
export function extractFinalText(jsonLinesText) {
|
|
16
|
+
let lastAssistantMessage;
|
|
17
|
+
let sawAgentEnd = false;
|
|
18
|
+
for (const line of jsonLinesText.split("\n")) {
|
|
19
|
+
if (!line.trim())
|
|
20
|
+
continue;
|
|
21
|
+
let event;
|
|
22
|
+
try {
|
|
23
|
+
event = JSON.parse(line);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (event?.message?.role === "assistant") {
|
|
29
|
+
lastAssistantMessage = event.message;
|
|
30
|
+
}
|
|
31
|
+
if (event?.type === "agent_end" && Array.isArray(event.messages)) {
|
|
32
|
+
sawAgentEnd = true;
|
|
33
|
+
for (let i = event.messages.length - 1; i >= 0; i--) {
|
|
34
|
+
const message = event.messages[i];
|
|
35
|
+
if (message?.role === "assistant") {
|
|
36
|
+
lastAssistantMessage = message;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!lastAssistantMessage) {
|
|
43
|
+
return { text: "", error: "no assistant message found in --mode json output" };
|
|
44
|
+
}
|
|
45
|
+
if (isFatalStop(lastAssistantMessage)) {
|
|
46
|
+
return {
|
|
47
|
+
text: textFromMessage(lastAssistantMessage),
|
|
48
|
+
error: lastAssistantMessage.errorMessage ||
|
|
49
|
+
`assistant turn ended with stopReason=${lastAssistantMessage.stopReason}`,
|
|
50
|
+
fatal: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const text = textFromMessage(lastAssistantMessage);
|
|
54
|
+
if (!text) {
|
|
55
|
+
return { text: "", error: "final assistant message had no text content" };
|
|
56
|
+
}
|
|
57
|
+
if (!sawAgentEnd) {
|
|
58
|
+
return { text, error: "no agent_end event found; used last streamed assistant message as a fallback" };
|
|
59
|
+
}
|
|
60
|
+
return { text };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=json-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-events.js","sourceRoot":"","sources":["../src/json-events.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,mEAAmE;AACnE,4EAA4E;AAe5E,SAAS,eAAe,CAAC,OAAyC;IAChE,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3D,OAAO,OAAO,CAAC,OAAO;SACnB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;SAC3E,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,OAA6B;IAChD,OAAO,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,aAAqB;IACpD,IAAI,oBAAsD,CAAC;IAC3D,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAE3B,IAAI,KAA2F,CAAC;QAChG,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,KAAK,EAAE,OAAO,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;YACzC,oBAAoB,GAAG,KAAK,CAAC,OAAO,CAAC;QACvC,CAAC;QAED,IAAI,KAAK,EAAE,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjE,WAAW,GAAG,IAAI,CAAC;YACnB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpD,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAClC,IAAI,OAAO,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;oBAClC,oBAAoB,GAAG,OAAO,CAAC;oBAC/B,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,kDAAkD,EAAE,CAAC;IACjF,CAAC;IAED,IAAI,WAAW,CAAC,oBAAoB,CAAC,EAAE,CAAC;QACtC,OAAO;YACL,IAAI,EAAE,eAAe,CAAC,oBAAoB,CAAC;YAC3C,KAAK,EACH,oBAAoB,CAAC,YAAY;gBACjC,wCAAwC,oBAAoB,CAAC,UAAU,EAAE;YAC3E,KAAK,EAAE,IAAI;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,eAAe,CAAC,oBAAoB,CAAC,CAAC;IACnD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,6CAA6C,EAAE,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,8EAA8E,EAAE,CAAC;IACzG,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-events.test.d.ts","sourceRoot":"","sources":["../src/json-events.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { extractFinalText } from "./json-events.js";
|
|
4
|
+
function lines(...events) {
|
|
5
|
+
return events.map((e) => JSON.stringify(e)).join("\n");
|
|
6
|
+
}
|
|
7
|
+
test("extractFinalText reads the final assistant text from agent_end", () => {
|
|
8
|
+
const input = lines({ type: "session", id: "s1" }, { type: "agent_start" }, { type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "partial" }] } }, {
|
|
9
|
+
type: "agent_end",
|
|
10
|
+
messages: [
|
|
11
|
+
{ role: "user", content: [{ type: "text", text: "review this" }] },
|
|
12
|
+
{
|
|
13
|
+
role: "assistant",
|
|
14
|
+
content: [
|
|
15
|
+
{ type: "text", text: "## Verdict\napprove\n\n" },
|
|
16
|
+
{ type: "text", text: "## Summary\nlooks good" },
|
|
17
|
+
],
|
|
18
|
+
stopReason: "stop",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
const result = extractFinalText(input);
|
|
23
|
+
assert.equal(result.text, "## Verdict\napprove\n\n## Summary\nlooks good");
|
|
24
|
+
assert.equal(result.error, undefined);
|
|
25
|
+
assert.equal(result.fatal, undefined);
|
|
26
|
+
});
|
|
27
|
+
test("extractFinalText skips unparseable and empty lines", () => {
|
|
28
|
+
const good = lines({
|
|
29
|
+
type: "agent_end",
|
|
30
|
+
messages: [{ role: "assistant", content: [{ type: "text", text: "ok" }], stopReason: "stop" }],
|
|
31
|
+
});
|
|
32
|
+
const input = ["", "not json {{{", good, "", "}} also not json"].join("\n");
|
|
33
|
+
const result = extractFinalText(input);
|
|
34
|
+
assert.equal(result.text, "ok");
|
|
35
|
+
assert.equal(result.error, undefined);
|
|
36
|
+
});
|
|
37
|
+
test("extractFinalText falls back to the last streamed assistant message when agent_end is missing", () => {
|
|
38
|
+
const input = lines({ type: "message_update", message: { role: "assistant", content: [{ type: "text", text: "first" }] } }, { type: "message_update", message: { role: "assistant", content: [{ type: "text", text: "first final" }] } });
|
|
39
|
+
const result = extractFinalText(input);
|
|
40
|
+
assert.equal(result.text, "first final");
|
|
41
|
+
assert.match(result.error ?? "", /agent_end/);
|
|
42
|
+
assert.equal(result.fatal, undefined);
|
|
43
|
+
});
|
|
44
|
+
test("extractFinalText reports an error when no assistant content exists at all", () => {
|
|
45
|
+
const input = lines({
|
|
46
|
+
type: "agent_end",
|
|
47
|
+
messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
|
|
48
|
+
});
|
|
49
|
+
const result = extractFinalText(input);
|
|
50
|
+
assert.equal(result.text, "");
|
|
51
|
+
assert.ok(result.error);
|
|
52
|
+
});
|
|
53
|
+
test("extractFinalText marks a fatal stop reason", () => {
|
|
54
|
+
const input = lines({
|
|
55
|
+
type: "agent_end",
|
|
56
|
+
messages: [
|
|
57
|
+
{
|
|
58
|
+
role: "assistant",
|
|
59
|
+
content: [{ type: "text", text: "" }],
|
|
60
|
+
stopReason: "error",
|
|
61
|
+
errorMessage: "provider rate limited",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
const result = extractFinalText(input);
|
|
66
|
+
assert.equal(result.fatal, true);
|
|
67
|
+
assert.equal(result.error, "provider rate limited");
|
|
68
|
+
});
|
|
69
|
+
test("extractFinalText handles empty input without throwing", () => {
|
|
70
|
+
const result = extractFinalText("");
|
|
71
|
+
assert.equal(result.text, "");
|
|
72
|
+
assert.ok(result.error);
|
|
73
|
+
});
|
|
74
|
+
test("extractFinalText uses the last agent_end when the child retries", () => {
|
|
75
|
+
const input = lines({
|
|
76
|
+
type: "agent_end",
|
|
77
|
+
willRetry: true,
|
|
78
|
+
messages: [{ role: "assistant", content: [{ type: "text", text: "first attempt" }], stopReason: "error" }],
|
|
79
|
+
}, {
|
|
80
|
+
type: "agent_end",
|
|
81
|
+
willRetry: false,
|
|
82
|
+
messages: [{ role: "assistant", content: [{ type: "text", text: "final attempt" }], stopReason: "stop" }],
|
|
83
|
+
});
|
|
84
|
+
const result = extractFinalText(input);
|
|
85
|
+
assert.equal(result.text, "final attempt");
|
|
86
|
+
assert.equal(result.fatal, undefined);
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=json-events.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-events.test.js","sourceRoot":"","sources":["../src/json-events.test.ts"],"names":[],"mappings":"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"}
|
package/dist/review.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { ParsedArgs } from "./types.js";
|
|
|
2
2
|
import { type ChildRunResult } from "./child-process.js";
|
|
3
3
|
/** Ensures PI_REVIEW_META is on its own line after streamed child stdout. */
|
|
4
4
|
export declare function metaLinePrefix(childStdout: string, streamMode: boolean): string;
|
|
5
|
+
/** True when the final text must be printed after exit instead of having streamed live. */
|
|
6
|
+
export declare function progressLogBuffersOutput(streamMode: boolean, hasProgressLog: boolean): boolean;
|
|
5
7
|
export declare function childRuntimeError(child: Pick<ChildRunResult, "status" | "signal" | "error">): string | undefined;
|
|
6
8
|
export declare function runModels(piBin: string, args: string[]): never;
|
|
7
9
|
export declare function runReview(parsed: ParsedArgs): Promise<void>;
|
package/dist/review.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AACzD,OAAO,EAA2C,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAkClG,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,CAG/E;AAED,2FAA2F;AAC3F,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CAE9F;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAKhH;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAM9D;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsIjE"}
|
package/dist/review.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { spawnSync } from "node:child_process";
|
|
@@ -5,6 +6,7 @@ import { spawnBufferedChild, spawnStreamingChild } from "./child-process.js";
|
|
|
5
6
|
import { loadPresets, loadSystemPrompt } from "./presets.js";
|
|
6
7
|
import { splitPayload, buildPrompt } from "./prompt.js";
|
|
7
8
|
import { parseVerdict } from "./verdict.js";
|
|
9
|
+
import { extractFinalText } from "./json-events.js";
|
|
8
10
|
import { makeRunSessionDir, newestJsonl } from "./session.js";
|
|
9
11
|
import { fail, hasPathSeparator, expandMaybeHome, normalizeTools } from "./utils.js";
|
|
10
12
|
import { resolveConfig } from "./config.js";
|
|
@@ -12,7 +14,6 @@ function readStdin() {
|
|
|
12
14
|
if (process.stdin.isTTY)
|
|
13
15
|
return "";
|
|
14
16
|
try {
|
|
15
|
-
const fs = require("node:fs");
|
|
16
17
|
return fs.readFileSync(0, "utf8").trim();
|
|
17
18
|
}
|
|
18
19
|
catch {
|
|
@@ -39,6 +40,10 @@ export function metaLinePrefix(childStdout, streamMode) {
|
|
|
39
40
|
return "";
|
|
40
41
|
return childStdout.endsWith("\n") ? "" : "\n";
|
|
41
42
|
}
|
|
43
|
+
/** True when the final text must be printed after exit instead of having streamed live. */
|
|
44
|
+
export function progressLogBuffersOutput(streamMode, hasProgressLog) {
|
|
45
|
+
return !streamMode || hasProgressLog;
|
|
46
|
+
}
|
|
42
47
|
export function childRuntimeError(child) {
|
|
43
48
|
if (child.error)
|
|
44
49
|
return child.error.message;
|
|
@@ -66,6 +71,8 @@ export async function runReview(parsed) {
|
|
|
66
71
|
const payload = splitPayload(parsed.payload);
|
|
67
72
|
const prompt = buildPrompt(parsed.mode, preset, payload, stdinText);
|
|
68
73
|
const args = ["-p"];
|
|
74
|
+
if (parsed.progressLog)
|
|
75
|
+
args.push("--mode", "json");
|
|
69
76
|
const systemPrompt = loadSystemPrompt(config.systemPromptFile);
|
|
70
77
|
if (systemPrompt)
|
|
71
78
|
args.push("--append-system-prompt", systemPrompt);
|
|
@@ -97,19 +104,52 @@ export async function runReview(parsed) {
|
|
|
97
104
|
args.push("--no-session");
|
|
98
105
|
}
|
|
99
106
|
args.push(...payload.fileRefs, prompt);
|
|
107
|
+
let progressStream;
|
|
108
|
+
let progressStreamError;
|
|
109
|
+
if (parsed.progressLog) {
|
|
110
|
+
try {
|
|
111
|
+
fs.mkdirSync(path.dirname(parsed.progressLog), { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
fail(`failed to prepare --progress-log directory: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
progressStream = fs.createWriteStream(parsed.progressLog, { flags: "a" });
|
|
117
|
+
progressStream.on("error", (error) => {
|
|
118
|
+
progressStreamError = error;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
100
121
|
const startedAt = Date.now();
|
|
101
|
-
const spawnOpts = {
|
|
122
|
+
const spawnOpts = {
|
|
123
|
+
cwd: process.cwd(),
|
|
124
|
+
env: childEnv(config.piBin),
|
|
125
|
+
...(progressStream ? { stdoutSink: progressStream } : {}),
|
|
126
|
+
};
|
|
102
127
|
const child = parsed.stream
|
|
103
128
|
? await spawnStreamingChild(config.piBin, args, spawnOpts)
|
|
104
129
|
: spawnBufferedChild(config.piBin, args, spawnOpts);
|
|
105
130
|
const durationMs = Date.now() - startedAt;
|
|
106
|
-
|
|
131
|
+
if (progressStream) {
|
|
132
|
+
await new Promise((resolve) => progressStream.end(() => resolve()));
|
|
133
|
+
if (progressStreamError) {
|
|
134
|
+
process.stderr.write(`pi-review: warning: --progress-log write failed: ${progressStreamError.message}\n`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let stdout = child.stdout || "";
|
|
107
138
|
const stderr = child.stderr || "";
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
139
|
+
let extractedError;
|
|
140
|
+
let extractedFatal = false;
|
|
141
|
+
if (parsed.progressLog) {
|
|
142
|
+
const extracted = extractFinalText(stdout);
|
|
143
|
+
stdout = extracted.text;
|
|
144
|
+
extractedError = extracted.error;
|
|
145
|
+
extractedFatal = Boolean(extracted.fatal);
|
|
146
|
+
}
|
|
147
|
+
const bufferedPrint = progressLogBuffersOutput(parsed.stream, Boolean(parsed.progressLog));
|
|
148
|
+
if (bufferedPrint && stdout) {
|
|
149
|
+
process.stdout.write(stdout.endsWith("\n") ? stdout : `${stdout}\n`);
|
|
150
|
+
}
|
|
151
|
+
if (!parsed.stream && stderr) {
|
|
152
|
+
process.stderr.write(stderr.endsWith("\n") ? stderr : `${stderr}\n`);
|
|
113
153
|
}
|
|
114
154
|
if (parsed.keepSession) {
|
|
115
155
|
sessionHandle = newestJsonl(runSessionDir);
|
|
@@ -123,6 +163,19 @@ export async function runReview(parsed) {
|
|
|
123
163
|
parseError: runtimeError,
|
|
124
164
|
};
|
|
125
165
|
}
|
|
166
|
+
else if (extractedFatal) {
|
|
167
|
+
verdictInfo = {
|
|
168
|
+
verdict: "blocked",
|
|
169
|
+
verdictSource: "runtime_error",
|
|
170
|
+
parseError: extractedError,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
else if (extractedError) {
|
|
174
|
+
verdictInfo = {
|
|
175
|
+
...verdictInfo,
|
|
176
|
+
parseError: [verdictInfo.parseError, extractedError].filter(Boolean).join("; "),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
126
179
|
const meta = {
|
|
127
180
|
reviewMode: parsed.mode,
|
|
128
181
|
verdict: verdictInfo.verdict,
|
|
@@ -132,7 +185,7 @@ export async function runReview(parsed) {
|
|
|
132
185
|
sessionHandle: sessionHandle || undefined,
|
|
133
186
|
parseError: verdictInfo.parseError || undefined,
|
|
134
187
|
};
|
|
135
|
-
const metaPrefix = metaLinePrefix(stdout,
|
|
188
|
+
const metaPrefix = metaLinePrefix(stdout, !bufferedPrint);
|
|
136
189
|
if (metaPrefix)
|
|
137
190
|
process.stdout.write(metaPrefix);
|
|
138
191
|
process.stdout.write(`PI_REVIEW_META: ${JSON.stringify(meta)}\n`);
|
package/dist/review.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.js","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAuB,MAAM,oBAAoB,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,SAAS,SAAS;IAChB,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"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"}
|
package/dist/review.meta.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { test } from "node:test";
|
|
3
|
-
import { childRuntimeError, metaLinePrefix } from "./review.js";
|
|
3
|
+
import { childRuntimeError, metaLinePrefix, progressLogBuffersOutput } from "./review.js";
|
|
4
4
|
test("metaLinePrefix adds newline when streamed stdout lacks trailing newline", () => {
|
|
5
5
|
assert.equal(metaLinePrefix("hello", true), "\n");
|
|
6
6
|
assert.equal(metaLinePrefix("hello\n", true), "");
|
|
@@ -12,4 +12,10 @@ test("metaLinePrefix is empty in buffered mode", () => {
|
|
|
12
12
|
test("childRuntimeError treats spawn errors as runtime errors", () => {
|
|
13
13
|
assert.equal(childRuntimeError({ status: null, signal: null, error: new Error("spawn ENOENT") }), "spawn ENOENT");
|
|
14
14
|
});
|
|
15
|
+
test("progressLogBuffersOutput buffers whenever streaming is off or a progress log is set", () => {
|
|
16
|
+
assert.equal(progressLogBuffersOutput(true, true), true);
|
|
17
|
+
assert.equal(progressLogBuffersOutput(true, false), false);
|
|
18
|
+
assert.equal(progressLogBuffersOutput(false, false), true);
|
|
19
|
+
assert.equal(progressLogBuffersOutput(false, true), true);
|
|
20
|
+
});
|
|
15
21
|
//# sourceMappingURL=review.meta.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.meta.test.js","sourceRoot":"","sources":["../src/review.meta.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"review.meta.test.js","sourceRoot":"","sources":["../src/review.meta.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE1F,IAAI,CAAC,yEAAyE,EAAE,GAAG,EAAE;IACnF,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACpD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,CAAC,KAAK,CACV,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,EACnF,cAAc,CACf,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qFAAqF,EAAE,GAAG,EAAE;IAC/F,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;AAC5D,CAAC,CAAC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface ParsedArgs {
|
|
|
9
9
|
keepSession: boolean;
|
|
10
10
|
/** When false, buffer child output and print after exit (legacy / scripting). Default: stream. */
|
|
11
11
|
stream: boolean;
|
|
12
|
+
/** When set, run the child in --mode json and stream its event log to this file path. */
|
|
13
|
+
progressLog?: string;
|
|
12
14
|
continueHandle?: string;
|
|
13
15
|
model?: string;
|
|
14
16
|
provider?: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,2EAA4E,CAAC;AAClG,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,QAAQ,GAAG,QAAQ,GAAG,eAAe,GAAG,iBAAiB,GAAG,QAAQ,CAAC;IAC9E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,kGAAkG;IAClG,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,QAAQ,GAAG,UAAU,GAAG,eAAe,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,2EAA4E,CAAC;AAClG,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,QAAQ,GAAG,QAAQ,GAAG,eAAe,GAAG,iBAAiB,GAAG,QAAQ,CAAC;IAC9E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,kGAAkG;IAClG,MAAM,EAAE,OAAO,CAAC;IAChB,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,QAAQ,GAAG,UAAU,GAAG,eAAe,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zephyrdeng/pi-review",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Isolated AI-powered code and plan reviews from the command line",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "ZephyrDeng <zephyrTang@aliyun.com>",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"build": "tsc",
|
|
68
68
|
"check": "tsc --noEmit",
|
|
69
69
|
"smoke": "node dist/cli.js --help >/dev/null",
|
|
70
|
-
"test": "npx --yes tsx --test src/child-process.test.ts src/review.meta.test.ts extensions/rv-prompts.test.ts",
|
|
70
|
+
"test": "npx --yes tsx --test src/child-process.test.ts src/review.meta.test.ts src/json-events.test.ts extensions/rv-prompts.test.ts",
|
|
71
71
|
"test:rv": "npx --yes tsx --test extensions/rv-prompts.test.ts",
|
|
72
72
|
"prepublishOnly": "npm run build",
|
|
73
73
|
"pack:dry": "npm pack --dry-run"
|
|
@@ -27,8 +27,8 @@ When resolving this fallback, use the actual directory that contains this `SKILL
|
|
|
27
27
|
|
|
28
28
|
- `pi-review` **streams** child `pi` stdout/stderr to the process terminal by default (`--no-stream` buffers until exit).
|
|
29
29
|
- **Pi** with `/rv` or a foreground bash that inherits stdio: users often see output arrive live.
|
|
30
|
-
- **Claude Code, Cursor, Codex**, and similar hosts usually **buffer tool stdout** until the bash command exits, so the chat may show the review **all at once** even though the CLI is streaming. That is expected—not a misconfiguration.
|
|
31
|
-
- For **live** progress in those hosts
|
|
30
|
+
- **Claude Code, Cursor, Codex**, and similar hosts usually **buffer tool stdout** until the bash command exits, so the chat may show the review **all at once** even though the CLI is streaming. That is expected—not a misconfiguration. Also note: pi-review's default `text` mode produces **no output at all** during the tool-use/thinking phase (only the final answer), so even a local terminal looks silent for most of a multi-minute review.
|
|
31
|
+
- For **live** progress in those hosts, prefer `--progress-log <path>`: it runs the child in `--mode json` and writes a structured, incremental event log to that file, independent of host stdout buffering. Run `pi-review --progress-log <path> ...` with a background/async tool call, then tail the file (e.g. with a Monitor-style tool) filtering out `message_update`/`tool_execution_update` (high-frequency token deltas) to surface milestone events. Fall back to a **local terminal** running the same command only if the host has no way to run a background command or tail a file.
|
|
32
32
|
|
|
33
33
|
## Review status (no slash command)
|
|
34
34
|
|
|
@@ -49,7 +49,7 @@ There is **no** `/status` slash in this skill. When the user asks for **review s
|
|
|
49
49
|
|
|
50
50
|
3. **Last conclusion** — if this conversation already has a `PI_REVIEW_META` line, quote `verdict`, `durationMs`, and `sessionHandle` instead of re-running review.
|
|
51
51
|
|
|
52
|
-
4. **Live output** — remind that chat tools may not stream; for live
|
|
52
|
+
4. **Live output** — remind that chat tools may not stream; prefer re-running with `--progress-log <path>` + a background/tail workflow for live progress, or use a **terminal** running `pi-review` (default streaming) as a fallback.
|
|
53
53
|
|
|
54
54
|
Do not implement findings from a status check; status is informational only.
|
|
55
55
|
|
|
@@ -73,7 +73,7 @@ Do not implement findings from a status check; status is informational only.
|
|
|
73
73
|
|
|
74
74
|
3. Run an isolated review:
|
|
75
75
|
```bash
|
|
76
|
-
pi-review [--mode <name>] [--model <provider/model[:thinking]>] [--keep-session|--continue <handle>] -- <@files|text...>
|
|
76
|
+
pi-review [--mode <name>] [--model <provider/model[:thinking]>] [--keep-session|--continue <handle>] [--progress-log <path>] -- <@files|text...>
|
|
77
77
|
```
|
|
78
78
|
Rules:
|
|
79
79
|
- Use the model decision from step 1; do not invent model IDs.
|
|
@@ -82,7 +82,8 @@ Do not implement findings from a status check; status is informational only.
|
|
|
82
82
|
- Use `--continue <handle>` only with a previous `PI_REVIEW_META.sessionHandle`.
|
|
83
83
|
- Put file references as `@path` after `--`.
|
|
84
84
|
- Do not ask `pi-review` to edit, patch, commit, or implement.
|
|
85
|
-
- Default streams child output live; add `--no-stream` only when the caller must buffer until exit.
|
|
85
|
+
- Default streams child output live; add `--no-stream` only when the caller must buffer until exit (cannot combine with `--progress-log`).
|
|
86
|
+
- In a host that buffers tool stdout (Claude Code, Codex, ...), prefer running with `--progress-log <path>` in the background and tailing the file for live progress instead of waiting on the blocking call.
|
|
86
87
|
Completion criterion: the command includes the resolved model/default choice and a concrete review target.
|
|
87
88
|
|
|
88
89
|
4. Return the result:
|
|
@@ -102,4 +103,4 @@ pi-review --mode challenge --continue <sessionHandle> -- "expand finding 2"
|
|
|
102
103
|
## Status examples (user phrasing)
|
|
103
104
|
|
|
104
105
|
- "review status" / "is the review still running?" → run **Review status** checks above.
|
|
105
|
-
- "show streaming in Claude Code" → explain tool buffering;
|
|
106
|
+
- "show streaming in Claude Code" / "the wait is bad, is there a better way" → explain tool buffering; re-run with `--progress-log <path>` + a background/tail workflow (or Pi `/rv`) for live progress, offering a local terminal only as a fallback.
|