@zephyrdeng/pi-review 0.6.2 → 0.7.1

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.
Files changed (163) hide show
  1. package/README.md +126 -14
  2. package/README.zh-CN.md +79 -4
  3. package/dist/args.d.ts +8 -0
  4. package/dist/args.d.ts.map +1 -1
  5. package/dist/args.js +167 -28
  6. package/dist/args.js.map +1 -1
  7. package/dist/args.test.d.ts +2 -0
  8. package/dist/args.test.d.ts.map +1 -0
  9. package/dist/args.test.js +125 -0
  10. package/dist/args.test.js.map +1 -0
  11. package/dist/child-process.d.ts +3 -0
  12. package/dist/child-process.d.ts.map +1 -1
  13. package/dist/child-process.js +26 -0
  14. package/dist/child-process.js.map +1 -1
  15. package/dist/child-process.test.js +13 -0
  16. package/dist/child-process.test.js.map +1 -1
  17. package/dist/cli-exit.test.d.ts +2 -0
  18. package/dist/cli-exit.test.d.ts.map +1 -0
  19. package/dist/cli-exit.test.js +84 -0
  20. package/dist/cli-exit.test.js.map +1 -0
  21. package/dist/cli.js +16 -2
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config.d.ts +1 -0
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +1 -0
  26. package/dist/config.js.map +1 -1
  27. package/dist/extensions/review.d.ts +2 -0
  28. package/dist/extensions/review.js +22 -0
  29. package/dist/extensions/rv-prompts.d.ts +19 -0
  30. package/dist/extensions/rv-prompts.js +132 -0
  31. package/dist/index.d.ts +22 -7
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +15 -6
  34. package/dist/index.js.map +1 -1
  35. package/dist/json-events.d.ts +71 -0
  36. package/dist/json-events.d.ts.map +1 -1
  37. package/dist/json-events.js +250 -0
  38. package/dist/json-events.js.map +1 -1
  39. package/dist/json-events.test.js +217 -1
  40. package/dist/json-events.test.js.map +1 -1
  41. package/dist/loop.d.ts +36 -0
  42. package/dist/loop.d.ts.map +1 -0
  43. package/dist/loop.js +73 -0
  44. package/dist/loop.js.map +1 -0
  45. package/dist/loop.test.d.ts +2 -0
  46. package/dist/loop.test.d.ts.map +1 -0
  47. package/dist/loop.test.js +83 -0
  48. package/dist/loop.test.js.map +1 -0
  49. package/dist/matcher.d.ts +74 -0
  50. package/dist/matcher.d.ts.map +1 -0
  51. package/dist/matcher.js +202 -0
  52. package/dist/matcher.js.map +1 -0
  53. package/dist/matcher.test.d.ts +2 -0
  54. package/dist/matcher.test.d.ts.map +1 -0
  55. package/dist/matcher.test.js +161 -0
  56. package/dist/matcher.test.js.map +1 -0
  57. package/dist/meta-footer.d.ts +15 -1
  58. package/dist/meta-footer.d.ts.map +1 -1
  59. package/dist/meta-footer.js +108 -0
  60. package/dist/meta-footer.js.map +1 -1
  61. package/dist/meta-footer.test.js +43 -1
  62. package/dist/meta-footer.test.js.map +1 -1
  63. package/dist/panel-aggregate.d.ts +18 -0
  64. package/dist/panel-aggregate.d.ts.map +1 -0
  65. package/dist/panel-aggregate.js +247 -0
  66. package/dist/panel-aggregate.js.map +1 -0
  67. package/dist/panel-aggregate.test.d.ts +2 -0
  68. package/dist/panel-aggregate.test.d.ts.map +1 -0
  69. package/dist/panel-aggregate.test.js +461 -0
  70. package/dist/panel-aggregate.test.js.map +1 -0
  71. package/dist/panel-cancellation.test.d.ts +2 -0
  72. package/dist/panel-cancellation.test.d.ts.map +1 -0
  73. package/dist/panel-cancellation.test.js +24 -0
  74. package/dist/panel-cancellation.test.js.map +1 -0
  75. package/dist/panel-cli.test.d.ts +2 -0
  76. package/dist/panel-cli.test.d.ts.map +1 -0
  77. package/dist/panel-cli.test.js +239 -0
  78. package/dist/panel-cli.test.js.map +1 -0
  79. package/dist/panel-config.d.ts +19 -0
  80. package/dist/panel-config.d.ts.map +1 -0
  81. package/dist/panel-config.js +115 -0
  82. package/dist/panel-config.js.map +1 -0
  83. package/dist/panel-config.test.d.ts +2 -0
  84. package/dist/panel-config.test.d.ts.map +1 -0
  85. package/dist/panel-config.test.js +94 -0
  86. package/dist/panel-config.test.js.map +1 -0
  87. package/dist/panel-loop.test.d.ts +2 -0
  88. package/dist/panel-loop.test.d.ts.map +1 -0
  89. package/dist/panel-loop.test.js +118 -0
  90. package/dist/panel-loop.test.js.map +1 -0
  91. package/dist/panel-tools.test.d.ts +2 -0
  92. package/dist/panel-tools.test.d.ts.map +1 -0
  93. package/dist/panel-tools.test.js +12 -0
  94. package/dist/panel-tools.test.js.map +1 -0
  95. package/dist/panel-usage.d.ts +6 -0
  96. package/dist/panel-usage.d.ts.map +1 -0
  97. package/dist/panel-usage.js +21 -0
  98. package/dist/panel-usage.js.map +1 -0
  99. package/dist/panel-view.d.ts +41 -0
  100. package/dist/panel-view.d.ts.map +1 -0
  101. package/dist/panel-view.js +90 -0
  102. package/dist/panel-view.js.map +1 -0
  103. package/dist/panel-view.test.d.ts +2 -0
  104. package/dist/panel-view.test.d.ts.map +1 -0
  105. package/dist/panel-view.test.js +45 -0
  106. package/dist/panel-view.test.js.map +1 -0
  107. package/dist/panel.d.ts +20 -0
  108. package/dist/panel.d.ts.map +1 -0
  109. package/dist/panel.js +393 -0
  110. package/dist/panel.js.map +1 -0
  111. package/dist/presets.d.ts +2 -1
  112. package/dist/presets.d.ts.map +1 -1
  113. package/dist/presets.js +10 -0
  114. package/dist/presets.js.map +1 -1
  115. package/dist/prompt.d.ts +14 -1
  116. package/dist/prompt.d.ts.map +1 -1
  117. package/dist/prompt.js +61 -15
  118. package/dist/prompt.js.map +1 -1
  119. package/dist/prompt.test.d.ts +2 -0
  120. package/dist/prompt.test.d.ts.map +1 -0
  121. package/dist/prompt.test.js +37 -0
  122. package/dist/prompt.test.js.map +1 -0
  123. package/dist/review-events.d.ts +70 -0
  124. package/dist/review-events.d.ts.map +1 -0
  125. package/dist/review-events.js +52 -0
  126. package/dist/review-events.js.map +1 -0
  127. package/dist/review-events.test.d.ts +2 -0
  128. package/dist/review-events.test.d.ts.map +1 -0
  129. package/dist/review-events.test.js +47 -0
  130. package/dist/review-events.test.js.map +1 -0
  131. package/dist/review-result.d.ts +5 -0
  132. package/dist/review-result.d.ts.map +1 -0
  133. package/dist/review-result.js +98 -0
  134. package/dist/review-result.js.map +1 -0
  135. package/dist/review-result.test.d.ts +2 -0
  136. package/dist/review-result.test.d.ts.map +1 -0
  137. package/dist/review-result.test.js +196 -0
  138. package/dist/review-result.test.js.map +1 -0
  139. package/dist/review.d.ts +10 -4
  140. package/dist/review.d.ts.map +1 -1
  141. package/dist/review.js +82 -20
  142. package/dist/review.js.map +1 -1
  143. package/dist/review.meta.test.js +2 -2
  144. package/dist/review.meta.test.js.map +1 -1
  145. package/dist/skill-protocol.test.d.ts +2 -0
  146. package/dist/skill-protocol.test.d.ts.map +1 -0
  147. package/dist/skill-protocol.test.js +35 -0
  148. package/dist/skill-protocol.test.js.map +1 -0
  149. package/dist/types.d.ts +151 -5
  150. package/dist/types.d.ts.map +1 -1
  151. package/dist/types.js +13 -0
  152. package/dist/types.js.map +1 -1
  153. package/extensions/panel-tool.test.ts +30 -0
  154. package/extensions/panel-tool.ts +169 -0
  155. package/extensions/review.ts +3 -1
  156. package/extensions/rv-prompts.test.ts +8 -1
  157. package/extensions/rv-prompts.ts +6 -4
  158. package/package.json +14 -5
  159. package/resources/panel-presets.json +21 -0
  160. package/resources/review-presets.json +2 -2
  161. package/resources/system-prompt.md +11 -1
  162. package/skills/pi-review/SKILL.md +93 -15
  163. package/skills/pi-review/references/codex-tools.md +19 -6
@@ -0,0 +1,37 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { buildPrompt, buildReviewerPrompt, buildAdjudicatorPrompt } from "./prompt.js";
4
+ test("review prompt requests the parseable finding contract", () => {
5
+ const prompt = buildPrompt("code", { description: "code", instructions: "Review the code." }, { fileRefs: ["@src/cli.ts"], userText: "" }, "");
6
+ assert.match(prompt, /### F1: <summary>/);
7
+ assert.match(prompt, /Severity: critical \| high \| medium \| low/);
8
+ assert.match(prompt, /Path: <path or none>/);
9
+ assert.match(prompt, /Actionable: yes \| no/);
10
+ assert.match(prompt, /No material findings\./);
11
+ });
12
+ test("reviewer prompt injects stable reviewer identity and the shared contract", () => {
13
+ const reviewer = { id: "security", role: "Security reviewer" };
14
+ const prompt = buildReviewerPrompt("code", { description: "code", instructions: "Review the code." }, { fileRefs: ["@src/cli.ts"], userText: "" }, "", reviewer);
15
+ assert.match(prompt, /Reviewer ID: security/);
16
+ assert.match(prompt, /Role: Security reviewer/);
17
+ assert.match(prompt, /cannot see other reviewers' findings/);
18
+ assert.match(prompt, /### F1: <summary>/);
19
+ assert.match(prompt, /## Verdict/);
20
+ });
21
+ test("adjudicator prompt enforces aggregation-only constraints and the strict clustering contract", () => {
22
+ const findings = [
23
+ { id: "r1#F1", reviewerId: "r1", finding: { summary: "loop bound is wrong", actionable: true, path: "src/cli.ts" } },
24
+ { id: "r2#F1", reviewerId: "r2", finding: { summary: "off-by-one iteration", actionable: true, path: "src/cli.ts" } },
25
+ ];
26
+ const prompt = buildAdjudicatorPrompt([{ anchorPath: "src/cli.ts", findings }]);
27
+ assert.match(prompt, /consensus adjudicator/i);
28
+ assert.match(prompt, /aggregation-only/);
29
+ assert.match(prompt, /may not invent new findings/);
30
+ assert.match(prompt, /no write tools/);
31
+ assert.match(prompt, /"sourceFindingIds":\["r1#F1","r2#F1"\],"confidence"/);
32
+ assert.match(prompt, /must come from the candidates below/);
33
+ // Adjudicator receives structured findings, not free repo access.
34
+ assert.match(prompt, /r1#F1/);
35
+ assert.match(prompt, /loop bound is wrong/);
36
+ });
37
+ //# sourceMappingURL=prompt.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.test.js","sourceRoot":"","sources":["../src/prompt.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { PanelReviewMeta, ReviewerSubmission, TokenUsage } from "./types.js";
2
+ export declare const REVIEW_EVENT_VERSION: 1;
3
+ export declare const REVIEW_EVENT_TEXT_LIMIT = 512;
4
+ export interface ReviewerIdentity {
5
+ reviewerId: string;
6
+ role: string;
7
+ model: string | null;
8
+ thinking?: string;
9
+ }
10
+ type ReviewEventBase<T extends string> = {
11
+ v: typeof REVIEW_EVENT_VERSION;
12
+ runId: string;
13
+ seq: number;
14
+ at: number;
15
+ type: T;
16
+ };
17
+ export type ReviewEvent = (ReviewEventBase<"panel.started"> & {
18
+ target: string;
19
+ mode: string;
20
+ panelPreset?: string;
21
+ reviewers: ReviewerIdentity[];
22
+ }) | (ReviewEventBase<"reviewer.queued"> & {
23
+ reviewerId: string;
24
+ }) | (ReviewEventBase<"reviewer.started"> & {
25
+ reviewerId: string;
26
+ }) | (ReviewEventBase<"reviewer.turn.started"> & {
27
+ reviewerId: string;
28
+ turn: number;
29
+ }) | (ReviewEventBase<"reviewer.tool.started"> & {
30
+ reviewerId: string;
31
+ tool: string;
32
+ summary?: string;
33
+ }) | (ReviewEventBase<"reviewer.tool.finished"> & {
34
+ reviewerId: string;
35
+ tool: string;
36
+ summary?: string;
37
+ }) | (ReviewEventBase<"reviewer.text.delta"> & {
38
+ reviewerId: string;
39
+ text: string;
40
+ }) | (ReviewEventBase<"reviewer.usage"> & {
41
+ reviewerId: string;
42
+ usage: TokenUsage;
43
+ }) | (ReviewEventBase<"reviewer.completed"> & {
44
+ reviewerId: string;
45
+ submission: ReviewerSubmission;
46
+ }) | (ReviewEventBase<"reviewer.failed"> & {
47
+ reviewerId: string;
48
+ message: string;
49
+ }) | (ReviewEventBase<"reviewer.cancelled"> & {
50
+ reviewerId: string;
51
+ message?: string;
52
+ }) | ReviewEventBase<"aggregation.started"> | (ReviewEventBase<"panel.completed"> & {
53
+ meta: PanelReviewMeta;
54
+ });
55
+ type ReviewEventPayload<T extends ReviewEvent["type"]> = Omit<Extract<ReviewEvent, {
56
+ type: T;
57
+ }>, "v" | "runId" | "seq" | "at" | "type">;
58
+ export type ReviewEventListener = (event: ReviewEvent) => void;
59
+ /** Replace common secret-shaped values and optionally cap renderer-visible free text. */
60
+ export declare function redactReviewEventText(value: string, limit?: number): string;
61
+ /** Redact and bound arbitrary renderer-visible data while preserving its shape. */
62
+ export declare function redactReviewEventPayload<T>(value: T): T;
63
+ /** Redact machine-readable review metadata without truncating its findings. */
64
+ export declare function redactReviewMetaPayload<T>(value: T): T;
65
+ /** Build one ordered event stream for exactly one panel run. */
66
+ export declare function createReviewEventEmitter(runId: string, listener?: ReviewEventListener, now?: () => number): <T extends ReviewEvent["type"]>(type: T, payload: ReviewEventPayload<T>) => Extract<ReviewEvent, {
67
+ type: T;
68
+ }>;
69
+ export {};
70
+ //# sourceMappingURL=review-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-events.d.ts","sourceRoot":"","sources":["../src/review-events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ // Stable, pi-review-owned event contract for live renderers and replay.
2
+ // Raw Pi JSONL remains an implementation detail of the child process.
3
+ export const REVIEW_EVENT_VERSION = 1;
4
+ export const REVIEW_EVENT_TEXT_LIMIT = 512;
5
+ /** Replace common secret-shaped values and optionally cap renderer-visible free text. */
6
+ export function redactReviewEventText(value, limit) {
7
+ const redacted = value
8
+ .replace(/\b(?:sk|rk|pk)[_-][A-Za-z0-9_-]{8,}\b|\b(?:ghp|github_pat)_[A-Za-z0-9_-]{8,}\b/gi, "[REDACTED]")
9
+ .replace(/\b(api[_-]?key|token|password|secret)\s*[=:]\s*[^\s,;]+/gi, "$1=[REDACTED]");
10
+ if (limit === undefined || redacted.length <= limit)
11
+ return redacted;
12
+ return `${redacted.slice(0, Math.max(0, limit - 1))}…`;
13
+ }
14
+ function redactValue(value, limit) {
15
+ if (typeof value === "string")
16
+ return redactReviewEventText(value, limit);
17
+ if (Array.isArray(value))
18
+ return value.map((item) => redactValue(item, limit));
19
+ if (value && typeof value === "object") {
20
+ return Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, redactValue(nested, limit)]));
21
+ }
22
+ return value;
23
+ }
24
+ /** Redact and bound arbitrary renderer-visible data while preserving its shape. */
25
+ export function redactReviewEventPayload(value) {
26
+ return redactValue(value, REVIEW_EVENT_TEXT_LIMIT);
27
+ }
28
+ /** Redact machine-readable review metadata without truncating its findings. */
29
+ export function redactReviewMetaPayload(value) {
30
+ return redactValue(value);
31
+ }
32
+ function redactEvent(event) {
33
+ const { v, runId, seq, at, type, ...payload } = event;
34
+ return { v, runId, seq, at, type, ...redactReviewEventPayload(payload) };
35
+ }
36
+ /** Build one ordered event stream for exactly one panel run. */
37
+ export function createReviewEventEmitter(runId, listener, now = Date.now) {
38
+ let seq = 0;
39
+ return (type, payload) => {
40
+ const event = redactEvent({
41
+ v: REVIEW_EVENT_VERSION,
42
+ runId,
43
+ seq: ++seq,
44
+ at: now(),
45
+ type,
46
+ ...payload,
47
+ });
48
+ listener?.(event);
49
+ return event;
50
+ };
51
+ }
52
+ //# sourceMappingURL=review-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-events.js","sourceRoot":"","sources":["../src/review-events.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,sEAAsE;AAItE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAU,CAAC;AAC/C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAuC3C,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CAAC,KAAa,EAAE,KAAc;IACjE,MAAM,QAAQ,GAAG,KAAK;SACnB,OAAO,CAAC,kFAAkF,EAAE,YAAY,CAAC;SACzG,OAAO,CAAC,2DAA2D,EAAE,eAAe,CAAC,CAAC;IACzF,IAAI,KAAK,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,IAAI,KAAK;QAAE,OAAO,QAAQ,CAAC;IACrE,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACzD,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC1E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7G,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,wBAAwB,CAAI,KAAQ;IAClD,OAAO,WAAW,CAAC,KAAK,EAAE,uBAAuB,CAAM,CAAC;AAC1D,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,uBAAuB,CAAI,KAAQ;IACjD,OAAO,WAAW,CAAC,KAAK,CAAM,CAAC;AACjC,CAAC;AAED,SAAS,WAAW,CAAwB,KAAQ;IAClD,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC;IACtD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,GAAI,wBAAwB,CAAC,OAAO,CAAY,EAAO,CAAC;AAC5F,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,wBAAwB,CAAC,KAAa,EAAE,QAA8B,EAAE,MAAoB,IAAI,CAAC,GAAG;IAClH,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,OAAO,CAAgC,IAAO,EAAE,OAA8B,EAAqC,EAAE;QACnH,MAAM,KAAK,GAAG,WAAW,CAAC;YACxB,CAAC,EAAE,oBAAoB;YACvB,KAAK;YACL,GAAG,EAAE,EAAE,GAAG;YACV,EAAE,EAAE,GAAG,EAAE;YACT,IAAI;YACJ,GAAG,OAAO;SAC0B,CAAC,CAAC;QACxC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=review-events.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-events.test.d.ts","sourceRoot":"","sources":["../src/review-events.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { createReviewEventEmitter, redactReviewEventPayload, redactReviewEventText } from "./review-events.js";
4
+ test("ReviewEvent v1 emits a monotonic, replayable panel lifecycle", () => {
5
+ const events = [];
6
+ const emit = createReviewEventEmitter("run-1", (event) => events.push(event));
7
+ emit("panel.started", { target: "@src", mode: "code", reviewers: [] });
8
+ emit("aggregation.started", {});
9
+ assert.deepEqual(events.map((event) => event.type), ["panel.started", "aggregation.started"]);
10
+ assert.deepEqual(events.map((event) => event.seq), [1, 2]);
11
+ assert.deepEqual([...new Set(events.map((event) => event.runId))], ["run-1"]);
12
+ });
13
+ test("ReviewEvent v1 redacts obvious secrets and bounds renderer text", () => {
14
+ const text = redactReviewEventText(`token=sk-secret-value ${"x".repeat(900)}`, 512);
15
+ assert.doesNotMatch(text, /sk-secret-value/);
16
+ assert.match(text, /^token=\[REDACTED\]/);
17
+ assert.doesNotMatch(text, /\$1=/);
18
+ assert.ok(text.length <= 512);
19
+ });
20
+ test("ReviewEvent v1 recognizes dashed API key prefixes", () => {
21
+ assert.equal(redactReviewEventText("credential sk-live-secret-value"), "credential [REDACTED]");
22
+ });
23
+ test("ReviewEvent v1 redacts bounded final reviewer findings before renderers receive them", () => {
24
+ const events = [];
25
+ const emit = createReviewEventEmitter("run-1", (event) => {
26
+ if (event.type === "reviewer.completed")
27
+ events.push(event);
28
+ });
29
+ emit("reviewer.completed", {
30
+ reviewerId: "security",
31
+ submission: {
32
+ reviewerId: "security",
33
+ durationMs: 1,
34
+ result: { status: "has_findings", verdict: "request_changes", verdictSource: "parsed", actionableCount: 1, findings: [{ summary: `token=sk-final-secret ${"x".repeat(900)}`, actionable: true }] },
35
+ },
36
+ });
37
+ const summary = events[0].submission.result.findings[0].summary;
38
+ assert.doesNotMatch(summary, /sk-final-secret/);
39
+ assert.ok(summary.length <= 512);
40
+ });
41
+ test("redacted panel metadata keeps its renderer-safe shape", () => {
42
+ const meta = redactReviewEventPayload({ model: "token=sk-model-secret", confirmedClusters: [{ summary: "x".repeat(900) }] });
43
+ assert.equal(meta.confirmedClusters.length, 1);
44
+ assert.doesNotMatch(meta.model, /sk-model-secret/);
45
+ assert.ok(meta.confirmedClusters[0].summary.length <= 512);
46
+ });
47
+ //# sourceMappingURL=review-events.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-events.test.js","sourceRoot":"","sources":["../src/review-events.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ReviewStatus, StructuredReviewResult, VerdictInfo } from "./types.js";
2
+ export declare function reviewExitCode(status: ReviewStatus): number;
3
+ /** Derives the machine review contract from the human-readable conclusion. */
4
+ export declare function parseReviewResult(markdown: string, verdictInfo?: VerdictInfo): StructuredReviewResult;
5
+ //# sourceMappingURL=review-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-result.d.ts","sourceRoot":"","sources":["../src/review-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,YAAY,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAoFnG,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE3D;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,WAAoC,GAChD,sBAAsB,CA4BxB"}
@@ -0,0 +1,98 @@
1
+ import { parseVerdict } from "./verdict.js";
2
+ function escapeRegExp(value) {
3
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4
+ }
5
+ function markdownSection(markdown, heading) {
6
+ const escaped = escapeRegExp(heading);
7
+ return markdown.match(new RegExp(`(?:^|\\n)##\\s*${escaped}\\s*\\n+([\\s\\S]*?)(?=\\n##\\s+|$)`, "i"))?.[1]?.trim() ?? "";
8
+ }
9
+ function field(block, name) {
10
+ const escaped = escapeRegExp(name);
11
+ return block.match(new RegExp(`^\\s*[-*]\\s*(?:\\*\\*)?${escaped}(?:\\*\\*)?\\s*:\\s*(.+?)\\s*$`, "im"))?.[1]?.trim();
12
+ }
13
+ const SEVERITY_PREFIX = /^(critical|high|medium|low|info|warning)\s*[:—-]\s*/i;
14
+ function findingBlocks(section) {
15
+ const headings = [...section.matchAll(/^###\s+(.+?)\s*$/gm)].map((match) => ({
16
+ header: match[1],
17
+ index: match.index ?? 0,
18
+ length: match[0].length,
19
+ }));
20
+ if (headings.length > 0)
21
+ return headings;
22
+ return [...section.matchAll(/^(?:[-*]|(\d+)[.)])\s+(.+?)\s*$/gm)].map((match) => ({
23
+ header: match[2],
24
+ index: match.index ?? 0,
25
+ length: match[0].length,
26
+ ...(match[1] ? { listId: match[1] } : {}),
27
+ }));
28
+ }
29
+ function parseStructuredFindings(markdown, verdictInfo) {
30
+ const section = markdownSection(markdown, "Findings");
31
+ const blocks = findingBlocks(section);
32
+ return blocks.map((entry, index) => {
33
+ const plainHeader = entry.header.replace(/[*_]/g, "").trim();
34
+ const idParts = plainHeader.match(/^([A-Za-z]+\d+|\d+)[.):\s-]+(.+)$/);
35
+ let summary = (idParts?.[2] ?? plainHeader).trim();
36
+ const severityFromHeader = summary.match(SEVERITY_PREFIX)?.[1]?.toLowerCase();
37
+ summary = summary.replace(SEVERITY_PREFIX, "");
38
+ const pathFromHeader = summary.match(/`([^`]+)`/)?.[1];
39
+ if (pathFromHeader)
40
+ summary = summary.replace(/`[^`]+`\s*[:—-]?\s*/, "");
41
+ const blockStart = entry.index + entry.length;
42
+ const blockEnd = blocks[index + 1]?.index ?? section.length;
43
+ const block = section.slice(blockStart, blockEnd);
44
+ const severity = field(block, "Severity")?.toLowerCase() ?? severityFromHeader;
45
+ const rawPath = field(block, "Path")?.replace(/^`|`$/g, "") ?? pathFromHeader;
46
+ const findingPath = rawPath && !/^(?:none|n\/a|-)$/i.test(rawPath) ? rawPath : undefined;
47
+ const actionableField = field(block, "Actionable");
48
+ const actionable = actionableField === undefined
49
+ ? verdictInfo.verdict === "request_changes"
50
+ : /^(?:yes|true)$/i.test(actionableField);
51
+ const id = entry.listId ?? idParts?.[1];
52
+ return {
53
+ ...(id ? { id } : {}),
54
+ ...(severity ? { severity } : {}),
55
+ ...(findingPath ? { path: findingPath } : {}),
56
+ summary: summary.replace(/[`*_]/g, "").trim(),
57
+ actionable,
58
+ };
59
+ });
60
+ }
61
+ const REVIEW_EXIT_CODE = {
62
+ clean: 0,
63
+ has_findings: 1,
64
+ needs_human: 3,
65
+ blocked: 4,
66
+ };
67
+ export function reviewExitCode(status) {
68
+ return REVIEW_EXIT_CODE[status];
69
+ }
70
+ /** Derives the machine review contract from the human-readable conclusion. */
71
+ export function parseReviewResult(markdown, verdictInfo = parseVerdict(markdown)) {
72
+ const findings = parseStructuredFindings(markdown, verdictInfo);
73
+ const actionableCount = findings.filter((finding) => finding.actionable).length;
74
+ let status;
75
+ switch (verdictInfo.verdict) {
76
+ case "approve":
77
+ status = "clean";
78
+ break;
79
+ case "request_changes":
80
+ status = "has_findings";
81
+ break;
82
+ case "needs_clarification":
83
+ status = "needs_human";
84
+ break;
85
+ case "blocked":
86
+ status = "blocked";
87
+ break;
88
+ }
89
+ if (verdictInfo.verdict === "approve" && actionableCount > 0)
90
+ status = "has_findings";
91
+ return {
92
+ ...verdictInfo,
93
+ status,
94
+ findings,
95
+ actionableCount,
96
+ };
97
+ }
98
+ //# sourceMappingURL=review-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-result.js","sourceRoot":"","sources":["../src/review-result.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=review-result.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-result.test.d.ts","sourceRoot":"","sources":["../src/review-result.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,196 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+ import { parseReviewResult, reviewExitCode } from "./review-result.js";
4
+ test("approve with no material findings is clean", () => {
5
+ const result = parseReviewResult(`
6
+ ## Verdict
7
+ approve
8
+
9
+ ## Summary
10
+ - Ready to ship.
11
+
12
+ ## Findings
13
+ No material findings.
14
+
15
+ ## Risks and Blind Spots
16
+ None.
17
+
18
+ ## Open Questions
19
+ None.
20
+ `);
21
+ assert.equal(result.verdict, "approve");
22
+ assert.equal(result.status, "clean");
23
+ assert.deepEqual(result.findings, []);
24
+ assert.equal(result.actionableCount, 0);
25
+ });
26
+ test("request_changes exposes structured actionable findings", () => {
27
+ const result = parseReviewResult(`
28
+ ## Verdict
29
+ request_changes
30
+
31
+ ## Summary
32
+ - The loop accepts an invalid budget.
33
+
34
+ ## Findings
35
+ ### F1: Validate the round budget
36
+ - Severity: high
37
+ - Path: src/args.ts
38
+ - Actionable: yes
39
+ - Evidence: Zero rounds bypasses the review gate.
40
+ - Impact: CI can report success without a review.
41
+ - Recommendation: Reject values below one.
42
+
43
+ ## Risks and Blind Spots
44
+ None.
45
+
46
+ ## Open Questions
47
+ None.
48
+ `);
49
+ assert.equal(result.status, "has_findings");
50
+ assert.deepEqual(result.findings, [
51
+ {
52
+ id: "F1",
53
+ severity: "high",
54
+ path: "src/args.ts",
55
+ summary: "Validate the round budget",
56
+ actionable: true,
57
+ },
58
+ ]);
59
+ assert.equal(result.actionableCount, 1);
60
+ });
61
+ test("partial Markdown findings use verdict-aware actionable defaults", () => {
62
+ const result = parseReviewResult(`
63
+ ## Verdict
64
+ request_changes
65
+
66
+ ## Summary
67
+ - The round budget is unsafe.
68
+
69
+ ## Findings
70
+ ### High: \`src/args.ts\` accepts zero rounds
71
+ - Evidence: --max-rounds 0 reaches the runner.
72
+ - Impact: The gate can skip all reviews.
73
+ - Recommendation: Require a positive integer.
74
+
75
+ ## Risks and Blind Spots
76
+ None.
77
+
78
+ ## Open Questions
79
+ None.
80
+ `);
81
+ assert.deepEqual(result.findings, [
82
+ {
83
+ severity: "high",
84
+ path: "src/args.ts",
85
+ summary: "accepts zero rounds",
86
+ actionable: true,
87
+ },
88
+ ]);
89
+ assert.equal(result.actionableCount, 1);
90
+ assert.equal(result.status, "has_findings");
91
+ });
92
+ test("legacy top-level finding lists remain machine-readable", () => {
93
+ const result = parseReviewResult(`
94
+ ## Verdict
95
+ request_changes
96
+
97
+ ## Summary
98
+ - CI does not fail closed.
99
+
100
+ ## Findings
101
+ 1. **High** — \`src/cli.ts\`: Dirty reviews still exit zero
102
+ - Evidence: runReview forwards the child exit code.
103
+ - Impact: A review gate passes with actionable findings.
104
+ - Recommendation: Map structured status to a stable exit code.
105
+
106
+ ## Risks and Blind Spots
107
+ None.
108
+
109
+ ## Open Questions
110
+ None.
111
+ `);
112
+ assert.deepEqual(result.findings, [
113
+ {
114
+ id: "1",
115
+ severity: "high",
116
+ path: "src/cli.ts",
117
+ summary: "Dirty reviews still exit zero",
118
+ actionable: true,
119
+ },
120
+ ]);
121
+ });
122
+ test("an actionable finding overrides an approve verdict", () => {
123
+ const result = parseReviewResult(`
124
+ ## Verdict
125
+ approve
126
+
127
+ ## Findings
128
+ ### F1: Fix before closeout
129
+ - Severity: medium
130
+ - Actionable: true
131
+
132
+ ## Risks and Blind Spots
133
+ None.
134
+
135
+ ## Open Questions
136
+ None.
137
+ `);
138
+ assert.equal(result.status, "has_findings");
139
+ assert.equal(result.actionableCount, 1);
140
+ });
141
+ test("non-actionable findings without a path keep approve clean", () => {
142
+ const result = parseReviewResult(`
143
+ ## Verdict
144
+ approve
145
+
146
+ ## Findings
147
+ ### F1: Track a future improvement
148
+ - Severity: low
149
+ - Path: none
150
+ - Actionable: no
151
+ `);
152
+ assert.equal(result.status, "clean");
153
+ assert.deepEqual(result.findings, [
154
+ {
155
+ id: "F1",
156
+ severity: "low",
157
+ summary: "Track a future improvement",
158
+ actionable: false,
159
+ },
160
+ ]);
161
+ });
162
+ test("clarification, parse fallback, and runtime failures escalate", () => {
163
+ const clarification = parseReviewResult(`
164
+ ## Verdict
165
+ needs_clarification
166
+
167
+ ## Findings
168
+ ### F1: Confirm the intended contract
169
+ - Severity: high
170
+ - Actionable: yes
171
+ `);
172
+ assert.equal(clarification.status, "needs_human");
173
+ const fallback = parseReviewResult("## Findings\nNo material findings.");
174
+ assert.equal(fallback.status, "needs_human");
175
+ assert.equal(fallback.verdictSource, "fallback");
176
+ assert.match(fallback.parseError ?? "", /Could not parse/);
177
+ const runtime = parseReviewResult(`
178
+ ## Findings
179
+ ### F1: Retry the child
180
+ - Severity: high
181
+ - Actionable: yes
182
+ `, {
183
+ verdict: "blocked",
184
+ verdictSource: "runtime_error",
185
+ parseError: "child pi exited with status 1",
186
+ });
187
+ assert.equal(runtime.status, "blocked");
188
+ assert.equal(runtime.verdictSource, "runtime_error");
189
+ });
190
+ test("review statuses map to stable gate exit codes", () => {
191
+ assert.equal(reviewExitCode("clean"), 0);
192
+ assert.equal(reviewExitCode("has_findings"), 1);
193
+ assert.equal(reviewExitCode("needs_human"), 3);
194
+ assert.equal(reviewExitCode("blocked"), 4);
195
+ });
196
+ //# sourceMappingURL=review-result.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-result.test.js","sourceRoot":"","sources":["../src/review-result.test.ts"],"names":[],"mappings":"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"}
package/dist/review.d.ts CHANGED
@@ -1,10 +1,16 @@
1
- import type { ParsedArgs } from "./types.js";
1
+ import type { ParsedArgs, ReviewRunResult } from "./types.js";
2
2
  import { type ChildRunResult } from "./child-process.js";
3
+ export declare function readReviewStdin(): string;
4
+ export declare function childEnv(piBin: string): NodeJS.ProcessEnv;
3
5
  /** Ensures the ASCII meta footer starts on its own line after streamed child stdout. */
4
6
  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;
7
+ /** True when the final text must be printed after exit instead of having streamed live.
8
+ * With --mode json streaming, text deltas are forwarded live in streaming mode;
9
+ * --progress-log no longer forces buffering (it only tees the raw event stream). */
10
+ export declare function progressLogBuffersOutput(streamMode: boolean, _hasProgressLog: boolean): boolean;
7
11
  export declare function childRuntimeError(child: Pick<ChildRunResult, "status" | "signal" | "error">): string | undefined;
8
12
  export declare function runModels(piBin: string, args: string[]): never;
9
- export declare function runReview(parsed: ParsedArgs): Promise<void>;
13
+ export declare function runReviewOnce(parsed: ParsedArgs, stdinText?: string): Promise<ReviewRunResult>;
14
+ /** CLI-compatible single review entrypoint. */
15
+ export declare function runReview(parsed: ParsedArgs): Promise<never>;
10
16
  //# sourceMappingURL=review.d.ts.map
@@ -1 +1 @@
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;AAmClG,wFAAwF;AACxF,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,CA6IjE"}
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../src/review.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAc,eAAe,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EAA2C,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAYlG,wBAAgB,eAAe,IAAI,MAAM,CAOxC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAczD;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,CAG/E;AAED;;oFAEoF;AACpF,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,OAAO,CAE/F;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,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,SAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAkM/G;AAED,+CAA+C;AAC/C,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAGlE"}