@unifan/pi-review-zh 1.0.10 → 1.0.11

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.
@@ -9,10 +9,10 @@ inheritSkills: false
9
9
  ---
10
10
  你是**极速单兵审查官(Lite Reviewer)**。你的任务是对本次改动做一次快速、全面、高精准度的体检(涵盖逻辑 Bug、安全隐患与规范一致性)。追求快而准。
11
11
 
12
- ## 执行计划(严格保持极简)
13
- 1. 读取任务中的 diff 文件。纯文档变更直接报告 `SKIPPED: docs-only`。
14
- 2. 重点直接分析 diff 本身,必要时最多读取 1~2 个上下文文件。
15
- 3. 输出 Markdown 报告并在末尾附带机器读取的 JSON 块。尽量在 3~5 轮内完成。
12
+ ## 执行计划(严格极简,2~3轮内强制完成)
13
+ 1. 读取任务中的 diff 文件与清单文件。纯文档变更直接报告 `SKIPPED: docs-only`。
14
+ 2. 重点聚焦 diff 本身代码逻辑。若上下文足够直接撰写报告;若确需核验,最多仅读 1 个相关文件或单次 grep。
15
+ 3. **必须在第 2~3 轮内输出最终 Markdown 报告与 JSON 块并立即停止**!严禁进行超过 3 轮的漫游探索!
16
16
 
17
17
  ## 重点关注
18
18
  逻辑致命缺陷与安全隐患第一,明确的规范冲突第二。不提废话风格建议。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unifan/pi-review-zh",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Pi AI 并发代码审查扩展(多专家子代理并发 + 门禁裁判系统,中文增强版)",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/directive.ts CHANGED
@@ -243,8 +243,8 @@ export function buildWorkflowScript(input: {
243
243
  lines.push("try {");
244
244
  lines.push(" reviewers = await runs.all([");
245
245
  for (const r of reviewers) {
246
- const tb = LEAN_BUDGETS.defaultToolBudget;
247
- const tbForId = r.id === "history-context" ? LEAN_BUDGETS.historyToolBudget : tb;
246
+ const tbForId = toolBudgetForReviewer(r.id);
247
+ const turnsForId = r.id === "lite-review" ? { maxTurns: 4, graceTurns: 1 } : budgets.turnBudget;
248
248
  const taskParts = [
249
249
  READ_ONLY_PREFIX,
250
250
  `读取 ${JSON.stringify(diffPath)} 作为改动内容——diff 是权威的修改记录,工作区文件仅作上下文参考。若工作区文件与 diff 存在差异,以 diff 为准并在 coverage.limitations 中说明。所有问题描述必须使用中文。`,
@@ -254,6 +254,11 @@ export function buildWorkflowScript(input: {
254
254
  "严禁读取 plan.md, progress.md, 以及 .pi-subagents/ 目录下的任何文件或 node_modules。",
255
255
  "优先使用 Read/Grep。若使用 bash,仅限简单的单条命令(禁止 &&/||/; 等复合命令)。",
256
256
  ];
257
+ if (r.id === "lite-review") {
258
+ taskParts.push(
259
+ "极速模式要求:严格在 2~3 轮内完成!读取 diff 后若无需核验直接出报告;若需核验最多只读 1 个文件或单次 grep,下一轮立即输出最终报告并停止!",
260
+ );
261
+ }
257
262
  if (r.id === "claude-md-compliance") {
258
263
  taskParts.push(
259
264
  "若 change-profile.rulePaths 为空,返回跳过状态:SKIPPED: no-rules,不提出虚构的违规。",
@@ -301,7 +306,7 @@ export function buildWorkflowScript(input: {
301
306
  }
302
307
  lines.push(` toolBudget: { soft: ${tbForId.soft}, hard: ${tbForId.hard} },`);
303
308
  lines.push(
304
- ` turnBudget: { maxTurns: ${budgets.turnBudget.maxTurns}, graceTurns: ${budgets.turnBudget.graceTurns} },${modelClause}`,
309
+ ` turnBudget: { maxTurns: ${turnsForId.maxTurns}, graceTurns: ${turnsForId.graceTurns} },${modelClause}`,
305
310
  );
306
311
  lines.push(" },");
307
312
  }
@@ -311,14 +316,19 @@ export function buildWorkflowScript(input: {
311
316
  lines.push(" await new Promise((resolve) => setTimeout(resolve, 800));");
312
317
  lines.push(" reviewers = await runs.all([");
313
318
  for (const r of reviewers) {
314
- const tb = LEAN_BUDGETS.defaultToolBudget;
315
- const tbForId = r.id === "history-context" ? LEAN_BUDGETS.historyToolBudget : tb;
319
+ const tbForId = toolBudgetForReviewer(r.id);
320
+ const turnsForId = r.id === "lite-review" ? { maxTurns: 4, graceTurns: 1 } : budgets.turnBudget;
316
321
  const taskParts = [
317
322
  READ_ONLY_PREFIX,
318
323
  `读取 ${JSON.stringify(diffPath)} 作为改动内容——diff 是权威的修改记录,工作区文件仅作上下文参考。所有问题描述必须使用中文。`,
319
324
  `你的当前工作区为目标工作区 (${JSON.stringify(workspacePath)})。在此目录下执行必要的 read/grep。`,
320
325
  "在额度内完成分析;最终回复必须输出格式规范的 Markdown 审查报告(包含中文 Summary / Findings / Coverage 章节)并停止。所有问题描述、证据引用和总结必须使用纯正中文。",
321
326
  ];
327
+ if (r.id === "lite-review") {
328
+ taskParts.push(
329
+ "极速模式要求:严格在 2~3 轮内完成!读取 diff 后若无需核验直接出报告;若需核验最多只读 1 个文件或单次 grep,下一轮立即输出最终报告并停止!",
330
+ );
331
+ }
322
332
  const modelClause =
323
333
  r.model && r.model !== "inherit"
324
334
  ? `\n model: ${JSON.stringify(r.model)},`
@@ -337,7 +347,7 @@ export function buildWorkflowScript(input: {
337
347
  }
338
348
  lines.push(` toolBudget: { soft: ${tbForId.soft}, hard: ${tbForId.hard} },`);
339
349
  lines.push(
340
- ` turnBudget: { maxTurns: ${budgets.turnBudget.maxTurns}, graceTurns: ${budgets.turnBudget.graceTurns} },${modelClause}`,
350
+ ` turnBudget: { maxTurns: ${turnsForId.maxTurns}, graceTurns: ${turnsForId.graceTurns} },${modelClause}`,
341
351
  );
342
352
  lines.push(" },");
343
353
  }
@@ -25,6 +25,8 @@ export interface LeanBudgetSpec {
25
25
  defaultToolBudget: ToolBudgetSpec;
26
26
  /** Stricter per-child tool budget for history-context (injected per runs.all item). */
27
27
  historyToolBudget: ToolBudgetSpec;
28
+ /** Ultra-lean tool budget for lite-review. */
29
+ liteToolBudget: ToolBudgetSpec;
28
30
  /** Gate child budgets (injected onto the runs.run("gate", ...) item). */
29
31
  gateTurnBudget: { maxTurns: number; graceTurns: number };
30
32
  gateToolBudget: ToolBudgetSpec;
@@ -33,15 +35,17 @@ export interface LeanBudgetSpec {
33
35
  }
34
36
 
35
37
  export const LEAN_BUDGETS: LeanBudgetSpec = {
36
- turnBudget: { maxTurns: 26, graceTurns: 2 },
37
- defaultToolBudget: { soft: 20, hard: 32 },
38
- historyToolBudget: { soft: 14, hard: 24 },
39
- gateTurnBudget: { maxTurns: 16, graceTurns: 2 },
40
- gateToolBudget: { soft: 14, hard: 20 },
41
- timeoutMs: 1_000_000,
38
+ turnBudget: { maxTurns: 8, graceTurns: 1 },
39
+ defaultToolBudget: { soft: 6, hard: 10 },
40
+ historyToolBudget: { soft: 4, hard: 6 },
41
+ liteToolBudget: { soft: 3, hard: 5 },
42
+ gateTurnBudget: { maxTurns: 6, graceTurns: 1 },
43
+ gateToolBudget: { soft: 6, hard: 10 },
44
+ timeoutMs: 600_000,
42
45
  };
43
46
 
44
47
  export function toolBudgetForReviewer(id: string): ToolBudgetSpec {
48
+ if (id === "lite-review") return LEAN_BUDGETS.liteToolBudget;
45
49
  if (id === "history-context") return LEAN_BUDGETS.historyToolBudget;
46
50
  return LEAN_BUDGETS.defaultToolBudget;
47
51
  }
@@ -107,15 +107,32 @@ function emptyCoverage(): ReviewerOutput["coverage"] {
107
107
 
108
108
  /** Build a deterministic verdict + report from a workflow return value. */
109
109
  export function runReportTool(input: ReportToolInput): ReportToolResult {
110
- if (!input.workflowReturn || typeof input.workflowReturn !== "object") {
110
+ let rawWorkflowReturn = input.workflowReturn;
111
+ if (typeof rawWorkflowReturn === "string") {
112
+ try {
113
+ rawWorkflowReturn = JSON.parse(rawWorkflowReturn);
114
+ } catch {
115
+ return { ok: false, error: "workflowReturn must be an object or valid JSON string" };
116
+ }
117
+ }
118
+ if (!rawWorkflowReturn || typeof rawWorkflowReturn !== "object") {
111
119
  return { ok: false, error: "workflowReturn must be an object" };
112
120
  }
113
- const ret = input.workflowReturn as {
121
+ const ret = rawWorkflowReturn as {
114
122
  reviewers?: unknown;
115
123
  gate?: unknown;
116
124
  reviewersShaped?: unknown;
125
+ error?: unknown;
117
126
  };
118
- if (!Array.isArray(ret.reviewers)) {
127
+ let reviewersList = Array.isArray(ret.reviewers) ? (ret.reviewers as unknown[]) : [];
128
+ if (reviewersList.length === 0 && ret.error) {
129
+ reviewersList = [{
130
+ key: "execution-error",
131
+ ok: false,
132
+ error: String(ret.error),
133
+ output: undefined,
134
+ }];
135
+ } else if (!Array.isArray(ret.reviewers)) {
119
136
  return { ok: false, error: "workflowReturn.reviewers must be an array" };
120
137
  }
121
138
 
@@ -124,7 +141,7 @@ export function runReportTool(input: ReportToolInput): ReportToolResult {
124
141
  const threshold = input.threshold ?? 8;
125
142
  const policy = input.verdictPolicy ?? "strict";
126
143
 
127
- const reviewersRaw = ret.reviewers as Array<{
144
+ const reviewersRaw = reviewersList as Array<{
128
145
  key: string;
129
146
  ok: boolean;
130
147
  error?: string;