@zephyrdeng/pi-review 0.18.3 → 0.20.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.
Files changed (71) hide show
  1. package/README.md +7 -0
  2. package/README.zh-CN.md +7 -0
  3. package/dist/args.d.ts.map +1 -1
  4. package/dist/args.js +20 -2
  5. package/dist/args.js.map +1 -1
  6. package/dist/claude-plugin-sync.test.d.ts +2 -0
  7. package/dist/claude-plugin-sync.test.d.ts.map +1 -0
  8. package/dist/claude-plugin-sync.test.js +33 -0
  9. package/dist/claude-plugin-sync.test.js.map +1 -0
  10. package/dist/claude-plugin.d.ts +16 -0
  11. package/dist/claude-plugin.d.ts.map +1 -0
  12. package/dist/claude-plugin.js +58 -0
  13. package/dist/claude-plugin.js.map +1 -0
  14. package/dist/claude-plugin.test.d.ts +2 -0
  15. package/dist/claude-plugin.test.d.ts.map +1 -0
  16. package/dist/claude-plugin.test.js +21 -0
  17. package/dist/claude-plugin.test.js.map +1 -0
  18. package/dist/cli.js +12 -3
  19. package/dist/cli.js.map +1 -1
  20. package/dist/install.d.ts.map +1 -1
  21. package/dist/install.js +13 -4
  22. package/dist/install.js.map +1 -1
  23. package/dist/meta-footer.d.ts +3 -1
  24. package/dist/meta-footer.d.ts.map +1 -1
  25. package/dist/meta-footer.js +10 -0
  26. package/dist/meta-footer.js.map +1 -1
  27. package/dist/panel-ui.d.ts +8 -0
  28. package/dist/panel-ui.d.ts.map +1 -1
  29. package/dist/panel-ui.js +23 -0
  30. package/dist/panel-ui.js.map +1 -1
  31. package/dist/panel-ui.test.js +23 -1
  32. package/dist/panel-ui.test.js.map +1 -1
  33. package/dist/panel.d.ts +6 -0
  34. package/dist/panel.d.ts.map +1 -1
  35. package/dist/panel.js +17 -2
  36. package/dist/panel.js.map +1 -1
  37. package/dist/review.d.ts.map +1 -1
  38. package/dist/review.js +5 -1
  39. package/dist/review.js.map +1 -1
  40. package/dist/skill-update.test.js +2 -2
  41. package/dist/skill-update.test.js.map +1 -1
  42. package/dist/types.d.ts +60 -1
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js.map +1 -1
  45. package/dist/update.d.ts.map +1 -1
  46. package/dist/update.js +9 -3
  47. package/dist/update.js.map +1 -1
  48. package/dist/verify-cli.d.ts +14 -0
  49. package/dist/verify-cli.d.ts.map +1 -0
  50. package/dist/verify-cli.js +223 -0
  51. package/dist/verify-cli.js.map +1 -0
  52. package/dist/verify-cli.test.d.ts +2 -0
  53. package/dist/verify-cli.test.d.ts.map +1 -0
  54. package/dist/verify-cli.test.js +208 -0
  55. package/dist/verify-cli.test.js.map +1 -0
  56. package/dist/verify-regression.test.d.ts +2 -0
  57. package/dist/verify-regression.test.d.ts.map +1 -0
  58. package/dist/verify-regression.test.js +307 -0
  59. package/dist/verify-regression.test.js.map +1 -0
  60. package/dist/verify.d.ts +151 -0
  61. package/dist/verify.d.ts.map +1 -0
  62. package/dist/verify.js +737 -0
  63. package/dist/verify.js.map +1 -0
  64. package/dist/verify.test.d.ts +2 -0
  65. package/dist/verify.test.d.ts.map +1 -0
  66. package/dist/verify.test.js +442 -0
  67. package/dist/verify.test.js.map +1 -0
  68. package/package.json +3 -2
  69. package/resources/review-presets.json +3 -3
  70. package/skills/pi-review/SKILL.md +26 -0
  71. package/skills/pi-review/references/codex-tools.md +1 -1
@@ -0,0 +1,307 @@
1
+ // Regression guard for --verify being strictly opt-in: with the flag absent,
2
+ // the reviewer argv (which carries the full prompt) and PI_REVIEW_META_JSON
3
+ // must stay byte-identical to the pre-verify base (16855bc). The inline
4
+ // snapshots below were recorded on that base before any verify code existed.
5
+ import fs from "node:fs";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { spawnSync } from "node:child_process";
9
+ import { fileURLToPath } from "node:url";
10
+ import { afterEach, expect, test } from "vitest";
11
+ const repoRoot = path.dirname(fileURLToPath(new URL("../package.json", import.meta.url)));
12
+ let tempDir = "";
13
+ afterEach(() => {
14
+ if (tempDir)
15
+ fs.rmSync(tempDir, { recursive: true, force: true });
16
+ tempDir = "";
17
+ });
18
+ function writeFixtures(dir) {
19
+ const presets = path.join(dir, "presets.json");
20
+ fs.writeFileSync(presets, JSON.stringify({ code: { description: "fixture", tools: "read,grep,find,ls", instructions: "Fixture instructions." } }));
21
+ const systemPrompt = path.join(dir, "system.md");
22
+ fs.writeFileSync(systemPrompt, "Fixture system prompt.");
23
+ const argvDir = path.join(dir, "argv");
24
+ fs.mkdirSync(argvDir);
25
+ const fakePi = path.join(dir, "fake-pi");
26
+ fs.writeFileSync(fakePi, `#!/usr/bin/env node
27
+ const fs = require("node:fs");
28
+ const path = require("node:path");
29
+ fs.writeFileSync(path.join(process.env.FAKE_PI_ARGV_DIR, process.pid + ".json"), JSON.stringify(process.argv.slice(2)));
30
+ const text = "## Verdict\\napprove\\n\\n## Summary\\n- Fixture.\\n\\n## Findings\\nNo material findings.\\n";
31
+ const line = (o) => process.stdout.write(JSON.stringify(o) + "\\n");
32
+ line({ type: "message_end", message: { role: "assistant", content: [{ type: "text", text }], model: "fake/model", stopReason: "stop" } });
33
+ line({ type: "agent_end", messages: [{ role: "assistant", content: [{ type: "text", text }] }] });
34
+ `);
35
+ fs.chmodSync(fakePi, 0o755);
36
+ return { presets, systemPrompt, argvDir, fakePi };
37
+ }
38
+ function runCli(args) {
39
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-review-verify-regression-"));
40
+ const fx = writeFixtures(tempDir);
41
+ const env = {
42
+ ...process.env,
43
+ PI_BIN: fx.fakePi,
44
+ PI_REVIEW_PRESETS: fx.presets,
45
+ PI_REVIEW_SYSTEM_PROMPT: fx.systemPrompt,
46
+ FAKE_PI_ARGV_DIR: fx.argvDir,
47
+ };
48
+ delete env.TYPESAFE_API_KEY;
49
+ delete env.PI_REVIEW_META_STDOUT;
50
+ const result = spawnSync(process.execPath, ["--import", "tsx", path.join(repoRoot, "src/cli.ts"), ...args, "--", "@src/types.ts", "check the gate"], { cwd: repoRoot, env, encoding: "utf8", timeout: 60_000, input: "" });
51
+ // Generic panel roles are shuffled per run; pin them so the snapshot is stable.
52
+ const normalize = (value) => value.split(repoRoot).join("<ROOT>").split(tempDir).join("<TMP>").replace(/- Role: [^\\\n]+/g, "- Role: <ROLE>");
53
+ const argvs = fs.readdirSync(fx.argvDir).map((name) => normalize(fs.readFileSync(path.join(fx.argvDir, name), "utf8"))).sort();
54
+ const metaLine = result.stderr.split("\n").find((line) => line.startsWith("PI_REVIEW_META_JSON: "));
55
+ const meta = JSON.parse(metaLine.slice("PI_REVIEW_META_JSON: ".length));
56
+ meta.durationMs = 0;
57
+ for (const reviewer of meta.reviewers ?? [])
58
+ Object.assign(reviewer, { durationMs: 0, role: "<ROLE>" });
59
+ return { status: result.status, argvs: argvs.map((a) => JSON.parse(a)), meta };
60
+ }
61
+ test("single review without --verify: argv, prompt, and meta match the base", () => {
62
+ const run = runCli(["--no-stream"]);
63
+ expect(run.status).toBe(0);
64
+ expect(run.argvs).toMatchInlineSnapshot(`
65
+ [
66
+ [
67
+ "-p",
68
+ "--mode",
69
+ "json",
70
+ "--append-system-prompt",
71
+ "Fixture system prompt.",
72
+ "--tools",
73
+ "read,grep,find,ls",
74
+ "--no-session",
75
+ "--no-extensions",
76
+ "--extension",
77
+ "<ROOT>/src/rules-extension.ts",
78
+ "@src/types.ts",
79
+ "You are running pi-review mode \`code\`.
80
+
81
+ Your job is to produce a review conclusion only. Do not edit files, do not write files, do not produce patches, and do not claim implementation work was done.
82
+
83
+ Fixture instructions.
84
+
85
+ Output Markdown with exactly these top-level sections:
86
+
87
+ ## Verdict
88
+ One of: approve | request_changes | needs_clarification | blocked
89
+
90
+ ## Summary
91
+ Short conclusion in 2-5 bullets.
92
+
93
+ ## Findings
94
+ Prioritized findings. For every material finding, use this exact shape (increment IDs as F1, F2, ...):
95
+
96
+ ### F1: <summary>
97
+ - Severity: critical | high | medium | low
98
+ - Path: <path or none>
99
+ - Lines: <line or line-range in Path, or none>
100
+ - Side: base | working (optional; defaults to working)
101
+ - Actionable: yes | no
102
+ - Evidence: <concrete evidence>
103
+ - Impact: <why it matters>
104
+ - Recommendation: <specific next step>
105
+
106
+ Set Actionable to yes when the host must fix or consciously reject the finding before clean closeout. Use no for informational or explicitly out-of-scope follow-up findings. Include Lines only when you have reliable line numbers for Path: a single line (\`42\`) or an inclusive range (\`42-58\`). Omit Lines or write "none" for file-level or non-line-specific findings — never guess a line number. Side marks which half of a diff Lines refers to (\`base\` = before the change, \`working\` = after); omit it to default to \`working\`. If there are no material findings, write "No material findings."
107
+
108
+ ## Risks and Blind Spots
109
+ What could still be wrong, missing, or unverified.
110
+
111
+ ## Open Questions
112
+ Questions the parent agent or user should answer before acting. If none, write "None."
113
+
114
+ <user-request>
115
+ check the gate
116
+ </user-request>
117
+
118
+ Review the attached file reference(s): @src/types.ts",
119
+ ],
120
+ ]
121
+ `);
122
+ expect(run.meta).toMatchInlineSnapshot(`
123
+ {
124
+ "actionableCount": 0,
125
+ "durationMs": 0,
126
+ "findings": [],
127
+ "metaVersion": 1,
128
+ "model": null,
129
+ "reviewMode": "code",
130
+ "status": "clean",
131
+ "verdict": "approve",
132
+ "verdictSource": "parsed",
133
+ }
134
+ `);
135
+ });
136
+ test("panel review without --verify: reviewer argv, prompts, and meta match the base", () => {
137
+ const run = runCli(["--reviewers", "2"]);
138
+ expect(run.status).toBe(0);
139
+ expect(run.argvs).toMatchInlineSnapshot(`
140
+ [
141
+ [
142
+ "-p",
143
+ "--mode",
144
+ "json",
145
+ "--append-system-prompt",
146
+ "Fixture system prompt.",
147
+ "--tools",
148
+ "read,grep,find,ls",
149
+ "--no-extensions",
150
+ "--extension",
151
+ "<ROOT>/src/rules-extension.ts",
152
+ "--no-session",
153
+ "@src/types.ts",
154
+ "You are an independent panel reviewer.
155
+ - Reviewer ID: r1
156
+ - Role: <ROLE>
157
+ You cannot see other reviewers' findings. Submit your own independent conclusion only.
158
+
159
+ You are running pi-review mode \`code\`.
160
+
161
+ Your job is to produce a review conclusion only. Do not edit files, do not write files, do not produce patches, and do not claim implementation work was done.
162
+
163
+ Fixture instructions.
164
+
165
+ Output Markdown with exactly these top-level sections:
166
+
167
+ ## Verdict
168
+ One of: approve | request_changes | needs_clarification | blocked
169
+
170
+ ## Summary
171
+ Short conclusion in 2-5 bullets.
172
+
173
+ ## Findings
174
+ Prioritized findings. For every material finding, use this exact shape (increment IDs as F1, F2, ...):
175
+
176
+ ### F1: <summary>
177
+ - Severity: critical | high | medium | low
178
+ - Path: <path or none>
179
+ - Lines: <line or line-range in Path, or none>
180
+ - Side: base | working (optional; defaults to working)
181
+ - Actionable: yes | no
182
+ - Evidence: <concrete evidence>
183
+ - Impact: <why it matters>
184
+ - Recommendation: <specific next step>
185
+
186
+ Set Actionable to yes when the host must fix or consciously reject the finding before clean closeout. Use no for informational or explicitly out-of-scope follow-up findings. Include Lines only when you have reliable line numbers for Path: a single line (\`42\`) or an inclusive range (\`42-58\`). Omit Lines or write "none" for file-level or non-line-specific findings — never guess a line number. Side marks which half of a diff Lines refers to (\`base\` = before the change, \`working\` = after); omit it to default to \`working\`. If there are no material findings, write "No material findings."
187
+
188
+ ## Risks and Blind Spots
189
+ What could still be wrong, missing, or unverified.
190
+
191
+ ## Open Questions
192
+ Questions the parent agent or user should answer before acting. If none, write "None."
193
+
194
+ <user-request>
195
+ check the gate
196
+ </user-request>
197
+
198
+ Review the attached file reference(s): @src/types.ts",
199
+ ],
200
+ [
201
+ "-p",
202
+ "--mode",
203
+ "json",
204
+ "--append-system-prompt",
205
+ "Fixture system prompt.",
206
+ "--tools",
207
+ "read,grep,find,ls",
208
+ "--no-extensions",
209
+ "--extension",
210
+ "<ROOT>/src/rules-extension.ts",
211
+ "--no-session",
212
+ "@src/types.ts",
213
+ "You are an independent panel reviewer.
214
+ - Reviewer ID: r2
215
+ - Role: <ROLE>
216
+ You cannot see other reviewers' findings. Submit your own independent conclusion only.
217
+
218
+ You are running pi-review mode \`code\`.
219
+
220
+ Your job is to produce a review conclusion only. Do not edit files, do not write files, do not produce patches, and do not claim implementation work was done.
221
+
222
+ Fixture instructions.
223
+
224
+ Output Markdown with exactly these top-level sections:
225
+
226
+ ## Verdict
227
+ One of: approve | request_changes | needs_clarification | blocked
228
+
229
+ ## Summary
230
+ Short conclusion in 2-5 bullets.
231
+
232
+ ## Findings
233
+ Prioritized findings. For every material finding, use this exact shape (increment IDs as F1, F2, ...):
234
+
235
+ ### F1: <summary>
236
+ - Severity: critical | high | medium | low
237
+ - Path: <path or none>
238
+ - Lines: <line or line-range in Path, or none>
239
+ - Side: base | working (optional; defaults to working)
240
+ - Actionable: yes | no
241
+ - Evidence: <concrete evidence>
242
+ - Impact: <why it matters>
243
+ - Recommendation: <specific next step>
244
+
245
+ Set Actionable to yes when the host must fix or consciously reject the finding before clean closeout. Use no for informational or explicitly out-of-scope follow-up findings. Include Lines only when you have reliable line numbers for Path: a single line (\`42\`) or an inclusive range (\`42-58\`). Omit Lines or write "none" for file-level or non-line-specific findings — never guess a line number. Side marks which half of a diff Lines refers to (\`base\` = before the change, \`working\` = after); omit it to default to \`working\`. If there are no material findings, write "No material findings."
246
+
247
+ ## Risks and Blind Spots
248
+ What could still be wrong, missing, or unverified.
249
+
250
+ ## Open Questions
251
+ Questions the parent agent or user should answer before acting. If none, write "None."
252
+
253
+ <user-request>
254
+ check the gate
255
+ </user-request>
256
+
257
+ Review the attached file reference(s): @src/types.ts",
258
+ ],
259
+ ]
260
+ `);
261
+ expect(run.meta).toMatchInlineSnapshot(`
262
+ {
263
+ "actionableCount": 0,
264
+ "adjudicationUsed": false,
265
+ "advisories": [],
266
+ "configuredReviewers": 2,
267
+ "confirmedClusters": [],
268
+ "consensusPolicy": "quorum",
269
+ "consensusThreshold": 2,
270
+ "durationMs": 0,
271
+ "findings": [],
272
+ "metaVersion": 1,
273
+ "model": null,
274
+ "panelHealth": "healthy",
275
+ "reviewMode": "code",
276
+ "reviewers": [
277
+ {
278
+ "contributed": true,
279
+ "durationMs": 0,
280
+ "model": null,
281
+ "reviewerId": "r1",
282
+ "role": "<ROLE>",
283
+ "status": "clean",
284
+ "verdict": "approve",
285
+ "verdictSource": "parsed",
286
+ },
287
+ {
288
+ "contributed": true,
289
+ "durationMs": 0,
290
+ "model": null,
291
+ "reviewerId": "r2",
292
+ "role": "<ROLE>",
293
+ "status": "clean",
294
+ "verdict": "approve",
295
+ "verdictSource": "parsed",
296
+ },
297
+ ],
298
+ "sourceFindings": [],
299
+ "status": "clean",
300
+ "strategy": "panel",
301
+ "successfulReviewers": 2,
302
+ "verdict": "approve",
303
+ "verdictSource": "parsed",
304
+ }
305
+ `);
306
+ });
307
+ //# sourceMappingURL=verify-regression.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-regression.test.js","sourceRoot":"","sources":["../src/verify-regression.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ import type { ParsedArgs, VerificationApproval, VerificationStepResult, VerificationSummary } from "./types.js";
2
+ export declare const VERIFY_CONFIG_FILE = ".pi-review.json";
3
+ export declare const DEFAULT_STEP_TIMEOUT_SEC = 300;
4
+ export declare const MAX_STEP_TIMEOUT_SEC = 1800;
5
+ export declare const OUTPUT_TAIL_LIMIT = 4000;
6
+ export declare const DEFAULT_MAX_FOLLOW_UP_ROUNDS = 1;
7
+ export interface PlanFile {
8
+ path: string;
9
+ content: string;
10
+ }
11
+ export interface PlanStep {
12
+ id: string;
13
+ argv: string[];
14
+ purpose: string;
15
+ cwd?: string;
16
+ expectedDurationSec?: number;
17
+ sideEffects?: string;
18
+ idempotent?: boolean;
19
+ isolated?: boolean;
20
+ timeoutSec?: number;
21
+ round?: number;
22
+ files?: PlanFile[];
23
+ }
24
+ export interface VerificationPlan {
25
+ version: 1;
26
+ proposer?: "host" | "pi";
27
+ summary?: string;
28
+ steps: PlanStep[];
29
+ }
30
+ export interface WhitelistCommand {
31
+ id: string;
32
+ argv: string[];
33
+ timeoutSec?: number;
34
+ }
35
+ export interface VerifyRepoConfig {
36
+ commands: WhitelistCommand[];
37
+ link: string[];
38
+ maxFollowUpRounds: number;
39
+ }
40
+ export interface ApprovalDecision {
41
+ id: string;
42
+ stepSha256: string;
43
+ decision: "approved" | "rejected";
44
+ }
45
+ export interface ApprovalRecord {
46
+ version: 1;
47
+ planSha256: string;
48
+ approvedBy?: string;
49
+ approvedAt?: string;
50
+ decisions: ApprovalDecision[];
51
+ }
52
+ /** Invalid plan / approval / config input (a usage problem, not a run failure). */
53
+ export declare class VerifyInputError extends Error {
54
+ constructor(message: string);
55
+ }
56
+ export declare function sha256(text: string): string;
57
+ /** Content hash an approval binds to; any edit to the step changes it. */
58
+ export declare function stepSha256(step: PlanStep): string;
59
+ export declare function planSha256(plan: VerificationPlan): string;
60
+ /** A relative path that stays inside its root (no absolute paths, no `..`). */
61
+ export declare function isSafeRelativePath(value: unknown): value is string;
62
+ /** Validate a plan object. Throws VerifyInputError with the first problem found. */
63
+ export declare function parsePlan(raw: unknown, maxFollowUpRounds?: number): VerificationPlan;
64
+ /** Parse `.pi-review.json` text. Only the `verify` key is read. */
65
+ export declare function parseRepoConfig(text: string): VerifyRepoConfig;
66
+ export declare function parseApproval(raw: unknown): ApprovalRecord;
67
+ /** Build an approval record for the plan's current content. */
68
+ export declare function createApproval(plan: VerificationPlan, options: {
69
+ all?: boolean;
70
+ approve?: string[];
71
+ reject?: string[];
72
+ by?: string;
73
+ now?: Date;
74
+ }): ApprovalRecord;
75
+ export interface ResolvedStep {
76
+ step: PlanStep;
77
+ origin: "whitelist" | "plan";
78
+ approval: VerificationApproval;
79
+ sha: string;
80
+ /** Effective timeout: the step's own, else the matching whitelist entry's. */
81
+ timeoutSec?: number;
82
+ }
83
+ /**
84
+ * Decide which steps may run. Without a plan, every whitelist command runs.
85
+ * With a plan: an explicit matching rejection wins; a rejection recorded for a
86
+ * different version of the step makes it `stale` (never whitelist pre-approved);
87
+ * then exact-argv whitelist matches (no files, no cwd) are pre-approved; then a
88
+ * matching approval; any other decision for the same id is `stale`.
89
+ */
90
+ export declare function resolveSteps(plan: VerificationPlan | undefined, config: VerifyRepoConfig, approvals: ApprovalRecord[]): ResolvedStep[];
91
+ export declare function isRunnable(approval: VerificationApproval): boolean;
92
+ /** Overall status from step outcomes (tree guard and setup errors are applied by the caller). */
93
+ /** True only for steps whose command was actually spawned (setup errors and skips have no duration). */
94
+ export declare function stepExecuted(step: VerificationStepResult): boolean;
95
+ export declare function overallStatus(steps: VerificationStepResult[]): VerificationSummary["status"];
96
+ /** Minimal environment for verification commands: allowlist minus anything secret-shaped. */
97
+ export declare function verificationEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
98
+ export interface CommandResult {
99
+ exitCode: number | null;
100
+ signal?: string;
101
+ timedOut: boolean;
102
+ durationMs: number;
103
+ outputTail: string;
104
+ truncated: boolean;
105
+ error?: string;
106
+ /** Informational; never changes the step status (e.g. output may be incomplete). */
107
+ note?: string;
108
+ }
109
+ /** Run argv without a shell in its own process group, with a timeout and a bounded output tail. */
110
+ export declare function runCommand(argv: string[], options: {
111
+ cwd: string;
112
+ env: NodeJS.ProcessEnv;
113
+ timeoutMs: number;
114
+ outputLimit?: number;
115
+ }): Promise<CommandResult>;
116
+ /** Porcelain status of the original tree, compared before/after verification. */
117
+ export declare function gitStatusSnapshot(repoRoot: string): string;
118
+ /** Read the standing whitelist from HEAD; uncommitted edits never grant pre-approval. */
119
+ export declare function loadRepoConfig(repoRoot: string): VerifyRepoConfig;
120
+ /** Resolve `rel` inside `root`, refusing paths that escape it (including through symlinks). */
121
+ export declare function resolveInside(root: string, rel: string): string;
122
+ export interface IsolatedCopy {
123
+ dir: string;
124
+ cleanup: () => void;
125
+ }
126
+ /**
127
+ * Snapshot HEAD + tracked changes + untracked non-ignored files through a
128
+ * throwaway index (the real index, tree, and stash stay untouched), then
129
+ * check it out as a detached worktree with hooks disabled.
130
+ */
131
+ export declare function createIsolatedCopy(repoRoot: string, link?: string[]): IsolatedCopy;
132
+ export interface RunVerificationOptions {
133
+ cwd: string;
134
+ planFile?: string;
135
+ approvalFiles?: string[];
136
+ env?: NodeJS.ProcessEnv;
137
+ onLog?: (line: string) => void;
138
+ /** Test seam: override the per-step output tail size. */
139
+ outputLimit?: number;
140
+ }
141
+ /**
142
+ * Run verification once. Never throws: every setup problem degrades to
143
+ * `status: "unverified"` with a reason so the review still runs and says so.
144
+ */
145
+ export declare function runVerification(options: RunVerificationOptions): Promise<VerificationSummary>;
146
+ export declare function formatVerificationSection(summary: VerificationSummary): string;
147
+ /** Run verification for a review/loop round when it was requested; undefined otherwise. */
148
+ export declare function verificationForReview(parsed: Pick<ParsedArgs, "verify" | "verifyPlan" | "verifyApprovals">, quiet?: boolean): Promise<VerificationSummary | undefined>;
149
+ /** Append the shared verification section to a reviewer prompt (identity when verification is off). */
150
+ export declare function withVerificationSection(prompt: string, summary: VerificationSummary | undefined): string;
151
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}