@fyeeme/pi-review 2.0.1 → 2.1.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.
- package/README.md +14 -13
- package/index.ts +2 -2
- package/package.json +58 -57
- package/prompts/{review.md → review.parallel.md} +4 -4
- package/prompts/review.single.md +16 -0
- package/prompts/simplify.parallel.md +1 -1
- package/prompts/simplify.single.md +1 -1
- package/skills/{review → code-review}/SKILL.md +164 -70
- package/skills/{simplify → code-simplify}/SKILL.md +15 -15
- package/src/config.ts +16 -10
- package/src/diff.ts +2 -2
- package/src/dispatch.ts +94 -31
- package/src/loop.ts +266 -0
- package/src/tools/review_report.ts +81 -33
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: simplify
|
|
3
|
-
description: "Review the changed code for reuse, simplification, efficiency, and altitude cleanups, then apply the fixes. Quality only — it does not hunt for bugs; use /review for that. v3 (from Claude Code CLI v2.1.227, symbol-level verified; re-verified against v2.1.261 on 2026-09-05 — bodies unchanged except Altitude) — 4 cleanup agents fan out in parallel when context allows, else a single-pass inline cleanup; either way the fixes are applied, verified against the project's check command, and auto-reverted on failure, then reported as structured outcomes via review_report."
|
|
2
|
+
name: code-simplify
|
|
3
|
+
description: "Review the changed code for reuse, simplification, efficiency, and altitude cleanups, then apply the fixes. Quality only — it does not hunt for bugs; use /code-review for that. v3 (from Claude Code CLI v2.1.227, symbol-level verified; re-verified against v2.1.261 on 2026-09-05 — bodies unchanged except Altitude) — 4 cleanup agents fan out in parallel when context allows, else a single-pass inline cleanup; either way the fixes are applied, verified against the project's check command, and auto-reverted on failure, then reported as structured outcomes via review_report."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<!--
|
|
7
7
|
Origin: Claude Code built-in skill `/simplify` (CLI v2.1.227), reverse-
|
|
8
|
-
engineered from bin/claude.exe raw bytes. Pi registers it as /simplify.
|
|
8
|
+
engineered from bin/claude.exe raw bytes. Pi registers it as /code-simplify.
|
|
9
9
|
|
|
10
10
|
Lineage:
|
|
11
11
|
v2.1.220 → the first reconstruction (v1)
|
|
@@ -26,7 +26,7 @@ description: "Review the changed code for reuse, simplification, efficiency, and
|
|
|
26
26
|
behavior"; "Quality only — it does not hunt for bugs; use
|
|
27
27
|
/code-review for that") and the Agent-tool fan-out ("all in a
|
|
28
28
|
single message so they run concurrently") are unchanged.
|
|
29
|
-
The /code-review↔/simplify division of labor is now stated
|
|
29
|
+
The /code-review↔/code-simplify division of labor is now stated
|
|
30
30
|
explicitly in both skills upstream — same as here.
|
|
31
31
|
|
|
32
32
|
CC 2.1.227 empirical evidence (symbol-level, extracted from bin/claude.exe):
|
|
@@ -46,9 +46,9 @@ description: "Review the changed code for reuse, simplification, efficiency, and
|
|
|
46
46
|
FORKED_AGENT_DEFAULT_MAX_TURNS = 50 — mirrored as the subagent tool's
|
|
47
47
|
defaults (PI_MAX_CONCURRENT_SUBAGENTS env still overrides the ceiling).
|
|
48
48
|
|
|
49
|
-
Bundled: ships inside the pi-review extension (skills/simplify/SKILL.md).
|
|
49
|
+
Bundled: ships inside the pi-review extension (skills/code-simplify/SKILL.md).
|
|
50
50
|
|
|
51
|
-
Invocation: /simplify [<target>]
|
|
51
|
+
Invocation: /code-simplify [<target>]
|
|
52
52
|
target = file path | PR number | branch name
|
|
53
53
|
|
|
54
54
|
════════════════════════════════════════════════════════════════════════
|
|
@@ -69,10 +69,10 @@ description: "Review the changed code for reuse, simplification, efficiency, and
|
|
|
69
69
|
Dii. The cleanup agents' tool whitelist (read/grep/find/ls/bash) never
|
|
70
70
|
includes a fan-out tool, so recursion stays physically bounded
|
|
71
71
|
regardless of tool registration. The decision is made
|
|
72
|
-
DETERMINISTICALLY by the /simplify handler — it can
|
|
72
|
+
DETERMINISTICALLY by the /code-simplify handler — it can
|
|
73
73
|
read ctx.getContextUsage(), which a pure-prompt skill cannot — and announced
|
|
74
74
|
in the trigger message; this skill just provides the two mode bodies.
|
|
75
|
-
3. Command — CC: /simplify; Pi: /simplify.
|
|
75
|
+
3. Command — CC: /simplify; Pi: /code-simplify.
|
|
76
76
|
4. Dispatch — CC's lead model writes the 4 Agent prompts itself after its
|
|
77
77
|
visible Phase 0. Pi keeps the same TIMELINE but moves the packaging into
|
|
78
78
|
code: the trigger message carries the handler-resolved scope, the
|
|
@@ -94,9 +94,9 @@ description: "Review the changed code for reuse, simplification, efficiency, and
|
|
|
94
94
|
|
|
95
95
|
You are improving the quality of the changed code, not hunting for bugs. Review
|
|
96
96
|
it for reuse, simplification, efficiency, and altitude issues, then fix what you
|
|
97
|
-
find. Do not look for correctness bugs — that is what `/review` is for.
|
|
97
|
+
find. Do not look for correctness bugs — that is what `/code-review` is for.
|
|
98
98
|
|
|
99
|
-
The `/simplify` handler has already chosen the mode (PARALLEL or
|
|
99
|
+
The `/code-simplify` handler has already chosen the mode (PARALLEL or
|
|
100
100
|
SINGLE-PASS) from real context usage and announced it in the trigger message.
|
|
101
101
|
Follow the body that matches; do not fake the mode you weren't asked to run.
|
|
102
102
|
Both modes open the same way: the trigger message carries the handler-resolved
|
|
@@ -106,7 +106,7 @@ VISIBLE, model-run step before anything launches.
|
|
|
106
106
|
## Phase 0 — Gather the diff
|
|
107
107
|
|
|
108
108
|
When the trigger message carries a handler-resolved scope (it always does for
|
|
109
|
-
/simplify), use THAT: run the exact `git -C … diff …` command the trigger
|
|
109
|
+
/code-simplify), use THAT: run the exact `git -C … diff …` command the trigger
|
|
110
110
|
provides — the handler already ran the cascade (merge-base → HEAD → staged →
|
|
111
111
|
unstaged) to pick it — read the full diff, and write a 2–4 line change-intent
|
|
112
112
|
summary before anything else. Do not re-derive a different range. That summary
|
|
@@ -125,7 +125,7 @@ review that target instead. Treat this diff as the review scope.)
|
|
|
125
125
|
|
|
126
126
|
# PARALLEL MODE (context not near-full AND diff under the fan-out threshold AND fan-out available)
|
|
127
127
|
|
|
128
|
-
`/simplify → visible Phase 0 (read the diff, summarize) → subagent tool (parallel, 4 cleaner agents) → apply the fixes`
|
|
128
|
+
`/code-simplify → visible Phase 0 (read the diff, summarize) → subagent tool (parallel, 4 cleaner agents) → apply the fixes`
|
|
129
129
|
|
|
130
130
|
## Phase 1 — Review (4 cleanup agents in parallel)
|
|
131
131
|
|
|
@@ -184,7 +184,7 @@ Follow the shared **Phase 2** procedure at the end of this skill (snapshot → a
|
|
|
184
184
|
|
|
185
185
|
# SINGLE-PASS MODE (context near-full OR diff too large OR fan-out unavailable)
|
|
186
186
|
|
|
187
|
-
`/simplify → handler decided single-pass (reasons in the trigger message) → inline cleanup → apply the fixes`
|
|
187
|
+
`/code-simplify → handler decided single-pass (reasons in the trigger message) → inline cleanup → apply the fixes`
|
|
188
188
|
|
|
189
189
|
The handler decided against the 4-agent fan-out (context near-full, diff too
|
|
190
190
|
large, fan-out unavailable, or usage unmeasurable — the exact reasons are in
|
|
@@ -237,7 +237,7 @@ Follow the shared **Phase 2** procedure at the end of this skill (snapshot → a
|
|
|
237
237
|
# Phase 2 — Apply, verify, and report (shared by both modes)
|
|
238
238
|
|
|
239
239
|
Dedup findings that point at the same line or mechanism first. Then apply,
|
|
240
|
-
verify, and report. This safety net is what distinguishes `/simplify` from
|
|
240
|
+
verify, and report. This safety net is what distinguishes `/code-simplify` from
|
|
241
241
|
a blind cleanup: a finding is only "done" once it is applied AND the project
|
|
242
242
|
still verifies — otherwise it is reverted.
|
|
243
243
|
|
|
@@ -258,7 +258,7 @@ for any file in a subdirectory. If a fix CREATES a new file, record its path so
|
|
|
258
258
|
Step 3a can remove it on rollback (it has no baseline entry).
|
|
259
259
|
|
|
260
260
|
This baseline captures the working-tree state **including** the user's
|
|
261
|
-
uncommitted changes — reverting to it undoes only `/simplify`'s fixes,
|
|
261
|
+
uncommitted changes — reverting to it undoes only `/code-simplify`'s fixes,
|
|
262
262
|
never the user's diff. Do **not** use `git checkout` / `git restore` to revert:
|
|
263
263
|
that would discard the user's intended changes too.
|
|
264
264
|
|
package/src/config.ts
CHANGED
|
@@ -10,19 +10,20 @@
|
|
|
10
10
|
*
|
|
11
11
|
* {
|
|
12
12
|
* "maxTurns": {
|
|
13
|
-
* "subagent": 20, // per-call budget for each /review finder batch
|
|
14
|
-
* "gapHunt": 15, // budget for the /review Phase 3 gap-hunter
|
|
15
|
-
* "simplify": 15
|
|
13
|
+
* "subagent": 20, // per-call budget for each /code-review finder batch (xhigh/max)
|
|
14
|
+
* "gapHunt": 15, // budget for the /code-review Phase 3 gap-hunter (xhigh/max)
|
|
15
|
+
* "simplify": 15, // budget for each /code-simplify PARALLEL cleaner agent
|
|
16
|
+
* "loop": 3 // --loop fix→re-review round cap (single-pass levels)
|
|
16
17
|
* }
|
|
17
18
|
* }
|
|
18
19
|
*
|
|
19
20
|
* The defaults here are the numbers the bundled prompts and skills were
|
|
20
|
-
* written with (finder 20 / gap-hunt 15 / simplify 15). With no config file
|
|
21
|
+
* written with (finder 20 / gap-hunt 15 / simplify 15 / loop 3). With no config file
|
|
21
22
|
* — or with any key absent or invalid — the rendered instructions carry
|
|
22
23
|
* exactly those numbers, so absence of configuration changes nothing.
|
|
23
24
|
*
|
|
24
25
|
* Read at command time (like pi-subagents' maxConcurrency): an edited file
|
|
25
|
-
* takes effect on the next /review or /simplify without a restart. Malformed
|
|
26
|
+
* takes effect on the next /code-review or /code-simplify without a restart. Malformed
|
|
26
27
|
* files are ignored with a stderr warning (never fatal); unknown/garbage
|
|
27
28
|
* fields are dropped on read.
|
|
28
29
|
*/
|
|
@@ -33,16 +34,18 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
33
34
|
/** Settings file name (both layers). */
|
|
34
35
|
const CONFIG_FILE = "pi-review.json";
|
|
35
36
|
|
|
36
|
-
/** The
|
|
37
|
+
/** The dispatchable turn budgets, keyed by what they throttle. */
|
|
37
38
|
export interface TurnBudgets {
|
|
38
|
-
/** `maxTurns` set on each /review finder-batch `subagent` call. */
|
|
39
|
+
/** `maxTurns` set on each /code-review finder-batch `subagent` call. */
|
|
39
40
|
subagent: number;
|
|
40
|
-
/** `maxTurns` set on each /review Phase 2 verifier `subagent` call. */
|
|
41
|
+
/** `maxTurns` set on each /code-review Phase 2 verifier `subagent` call. */
|
|
41
42
|
verifier: number;
|
|
42
|
-
/** `maxTurns` set on the /review Phase 3 gap-hunt `subagent` call. */
|
|
43
|
+
/** `maxTurns` set on the /code-review Phase 3 gap-hunt `subagent` call. */
|
|
43
44
|
gapHunt: number;
|
|
44
|
-
/** `maxTurns` set on each /simplify PARALLEL cleaner `subagent` call. */
|
|
45
|
+
/** `maxTurns` set on each /code-simplify PARALLEL cleaner `subagent` call. */
|
|
45
46
|
simplify: number;
|
|
47
|
+
/** Max fix→re-review rounds when /code-review runs with --loop. */
|
|
48
|
+
loop: number;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
/** Built-in budgets — identical to the literals in prompts/ and skills/. */
|
|
@@ -51,6 +54,7 @@ export const DEFAULT_TURN_BUDGETS: TurnBudgets = {
|
|
|
51
54
|
verifier: 15,
|
|
52
55
|
gapHunt: 15,
|
|
53
56
|
simplify: 15,
|
|
57
|
+
loop: 3,
|
|
54
58
|
};
|
|
55
59
|
|
|
56
60
|
function globalPath(): string {
|
|
@@ -85,6 +89,8 @@ function readBudgetsFile(path: string): Partial<TurnBudgets> {
|
|
|
85
89
|
if (gapHunt !== undefined) out.gapHunt = gapHunt;
|
|
86
90
|
const simplify = sanitizeBudget(mt.simplify);
|
|
87
91
|
if (simplify !== undefined) out.simplify = simplify;
|
|
92
|
+
const loop = sanitizeBudget(mt.loop);
|
|
93
|
+
if (loop !== undefined) out.loop = loop;
|
|
88
94
|
return out;
|
|
89
95
|
} catch (err) {
|
|
90
96
|
const reason = err instanceof Error ? err.message : String(err);
|
package/src/diff.ts
CHANGED
|
@@ -30,7 +30,7 @@ export function findGitRoot(from: string): string | null {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/** Normalize a /simplify target argument: trimmed, with an optional
|
|
33
|
+
/** Normalize a /code-simplify target argument: trimmed, with an optional
|
|
34
34
|
* path-prefix `@` PRESERVED — a real directory may itself start with `@`
|
|
35
35
|
* (e.g. node_modules/@scope/pkg), so the resolver tries the literal path
|
|
36
36
|
* first and only falls back to the @-stripped form when it does not exist. */
|
|
@@ -38,7 +38,7 @@ function normalizeTarget(target: string | undefined): string {
|
|
|
38
38
|
return (target ?? "").trim();
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/** Resolve the diff scope for a review/simplify target. Pure — unit-testable.
|
|
41
|
+
/** Resolve the diff scope for a code-review/code-simplify target. Pure — unit-testable.
|
|
42
42
|
*
|
|
43
43
|
* - target absent/unresolvable → the nearest git root of `cwd`, full diff.
|
|
44
44
|
* - target is a path → its nearest git root; the relative path inside that
|
package/src/dispatch.ts
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
* change here — the templates and skills are the registration surface.
|
|
14
14
|
*/
|
|
15
15
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
16
|
-
import { parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
import { CONFIG_DIR_NAME, getAgentDir, parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
17
17
|
import { isFanoutToolAllowed } from "@fyeeme/pi-subagents";
|
|
18
18
|
import * as fs from "node:fs";
|
|
19
|
-
import * as os from "node:os";
|
|
20
19
|
import * as path from "node:path";
|
|
21
20
|
import { fileURLToPath } from "node:url";
|
|
22
21
|
import { loadTurnBudgets } from "./config.ts";
|
|
23
22
|
import { DIFF_SCOPES, buildContextPackage, getRepoDiff, verifyLine } from "./diff.ts";
|
|
23
|
+
import { extractLoopFlag, runLoopFixing } from "./loop.ts";
|
|
24
24
|
import { bundledSkillPath } from "./skills.ts";
|
|
25
25
|
import { parseGuards, selectVariant } from "./strategy.ts";
|
|
26
26
|
|
|
@@ -51,17 +51,19 @@ export function render(body: string, vars: Record<string, string>): string {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// ---------------------------------------------------------------------------
|
|
54
|
-
// /review — effort-level code review (v1 command semantics, relocated)
|
|
54
|
+
// /code-review — effort-level code review (v1 command semantics, relocated)
|
|
55
55
|
// ---------------------------------------------------------------------------
|
|
56
56
|
|
|
57
|
-
/** Effort levels the /review command accepts (mirrors CC's effort enum). */
|
|
57
|
+
/** Effort levels the /code-review command accepts (mirrors CC's effort enum). */
|
|
58
58
|
export const REVIEW_LEVELS = ["low", "medium", "high", "xhigh", "max"] as const;
|
|
59
59
|
export type ReviewLevel = (typeof REVIEW_LEVELS)[number];
|
|
60
60
|
|
|
61
61
|
const DEFAULT_LEVEL: ReviewLevel = "low";
|
|
62
62
|
|
|
63
|
-
/** Where the last explicitly-typed effort is persisted (CC 2.1.223
|
|
64
|
-
|
|
63
|
+
/** Where the last explicitly-typed effort is persisted (CC 2.1.223
|
|
64
|
+
* codeReviewLastEffort). Shares the config file so users have a single
|
|
65
|
+
* pi-review.json; the field is written alongside `maxTurns`, never over it. */
|
|
66
|
+
const STATE_FILE = path.join(getAgentDir(), "pi-review.json");
|
|
65
67
|
|
|
66
68
|
export type EffortSource = "explicit" | "last-used" | "default";
|
|
67
69
|
|
|
@@ -69,6 +71,12 @@ export type EffortSource = "explicit" | "last-used" | "default";
|
|
|
69
71
|
* Parse a leading effort level out of raw args; the remainder (flags + target)
|
|
70
72
|
* is returned verbatim. Pure — unit-testable.
|
|
71
73
|
*/
|
|
74
|
+
/** True when the effort level uses the xhigh/max finder/verifier fan-out;
|
|
75
|
+
* false for the single-pass levels (low/medium/high). Pure — unit-testable. */
|
|
76
|
+
export function usesFanout(level: ReviewLevel): boolean {
|
|
77
|
+
return level === "xhigh" || level === "max";
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
export function parseReviewArgs(args: string): { level: ReviewLevel | undefined; rest: string } {
|
|
73
81
|
const tokens = (args ?? "").trim().split(/\s+/).filter(Boolean);
|
|
74
82
|
if (tokens.length === 0) return { level: undefined, rest: "" };
|
|
@@ -108,15 +116,30 @@ function readLastEffort(): ReviewLevel | undefined {
|
|
|
108
116
|
}
|
|
109
117
|
function writeLastEffort(level: ReviewLevel): void {
|
|
110
118
|
try {
|
|
119
|
+
// The state field shares a file with user-authored config (maxTurns), so
|
|
120
|
+
// read-modify-write instead of overwriting, and never clobber a
|
|
121
|
+
// hand-edited file we cannot parse.
|
|
122
|
+
let existing: Record<string, unknown> = {};
|
|
123
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
124
|
+
let raw: unknown;
|
|
125
|
+
try {
|
|
126
|
+
raw = JSON.parse(fs.readFileSync(STATE_FILE, "utf8"));
|
|
127
|
+
} catch {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
131
|
+
existing = raw as Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
existing.codeReviewLastEffort = level;
|
|
111
134
|
fs.mkdirSync(path.dirname(STATE_FILE), { recursive: true });
|
|
112
|
-
fs.writeFileSync(STATE_FILE, JSON.stringify(
|
|
135
|
+
fs.writeFileSync(STATE_FILE, `${JSON.stringify(existing, null, 2)}\n`);
|
|
113
136
|
} catch {
|
|
114
137
|
/* ignore — non-critical */
|
|
115
138
|
}
|
|
116
139
|
}
|
|
117
140
|
|
|
118
141
|
// ---------------------------------------------------------------------------
|
|
119
|
-
// /simplify — cleanup fan-out with the declared parallel strategy
|
|
142
|
+
// /code-simplify — cleanup fan-out with the declared parallel strategy
|
|
120
143
|
// ---------------------------------------------------------------------------
|
|
121
144
|
|
|
122
145
|
/** v1 DIFF_TOO_LARGE_CHARS — kept for the single-pass "too large to read at
|
|
@@ -128,11 +151,11 @@ const DIFF_TOO_LARGE_CHARS = 400_000;
|
|
|
128
151
|
// ---------------------------------------------------------------------------
|
|
129
152
|
|
|
130
153
|
export function registerDispatcher(pi: ExtensionAPI): void {
|
|
131
|
-
pi.registerCommand("review", {
|
|
154
|
+
pi.registerCommand("code-review", {
|
|
132
155
|
description:
|
|
133
|
-
"Review the current diff using the review skill. Usage: /review [low|medium|high|xhigh|max] [--fix] [--comment] [--share] [<pr#>|<branch>|<path>]",
|
|
156
|
+
"Review the current diff using the code-review skill. low/medium/high review in a single pass in this session; xhigh/max fan out finder/verifier agents. Usage: /code-review [low|medium|high|xhigh|max] [--fix] [--loop] [--comment] [--share] [<pr#>|<branch>|<path>]",
|
|
134
157
|
getArgumentCompletions(prefix) {
|
|
135
|
-
const tokens = ["low", "medium", "high", "xhigh", "max", "--fix", "--comment", "--share"];
|
|
158
|
+
const tokens = ["low", "medium", "high", "xhigh", "max", "--fix", "--loop", "--comment", "--share"];
|
|
136
159
|
return tokens.filter((t) => t.startsWith(prefix)).map((t) => ({ label: t, value: t }));
|
|
137
160
|
},
|
|
138
161
|
async handler(args, ctx) {
|
|
@@ -141,42 +164,82 @@ export function registerDispatcher(pi: ExtensionAPI): void {
|
|
|
141
164
|
const lastUsed = explicit ? undefined : readLastEffort();
|
|
142
165
|
if (explicit) writeLastEffort(explicit); // remember the explicit level
|
|
143
166
|
const { level, source } = resolveEffort(explicit, lastUsed);
|
|
144
|
-
const { body } = loadTemplate("review.md");
|
|
145
167
|
const budgets = loadTurnBudgets();
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
|
|
169
|
+
// Effort split: low/medium/high review in ONE pass in the main session
|
|
170
|
+
// (no subprocess fan-out); xhigh/max keep the finder/verifier pipeline.
|
|
171
|
+
const fanout = usesFanout(level);
|
|
172
|
+
|
|
173
|
+
// --loop is extension-level (drives fix→re-review rounds against the
|
|
174
|
+
// structured report), so it never reaches the skill text. It needs a
|
|
175
|
+
// single report turn to loop on — fan-out levels have no such turn.
|
|
176
|
+
const { wantLoop, rest: flagsRest } = extractLoopFlag(rest);
|
|
177
|
+
const loopArmed = wantLoop && !fanout;
|
|
178
|
+
if (wantLoop && fanout) {
|
|
179
|
+
ctx.ui.notify(
|
|
180
|
+
`/code-review: --loop applies to single-pass levels (low/medium/high) — ignored for ${level}.`,
|
|
181
|
+
"warning",
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const { body } = loadTemplate(fanout ? "review.parallel.md" : "review.single.md");
|
|
186
|
+
const shared = {
|
|
187
|
+
effort: level,
|
|
188
|
+
"effort-source": source,
|
|
189
|
+
"extra-args": flagsRest ? `; extra args: ${flagsRest}` : "",
|
|
190
|
+
skill: bundledSkillPath("code-review/SKILL.md"),
|
|
191
|
+
// Consumed by the skill's --fix flow (apply → verify → re-report).
|
|
192
|
+
verify: verifyLine(ctx.cwd),
|
|
193
|
+
};
|
|
194
|
+
void pi.sendUserMessage(
|
|
195
|
+
render(
|
|
196
|
+
body,
|
|
197
|
+
fanout
|
|
198
|
+
? {
|
|
199
|
+
...shared,
|
|
200
|
+
"finder-max-turns": String(budgets.subagent),
|
|
201
|
+
"verifier-max-turns": String(budgets.verifier),
|
|
202
|
+
"gap-hunt-max-turns": String(budgets.gapHunt),
|
|
203
|
+
}
|
|
204
|
+
: {
|
|
205
|
+
...shared,
|
|
206
|
+
// Told to the session so every finding carries a P0–P3 priority.
|
|
207
|
+
"loop-note": loopArmed
|
|
208
|
+
? `\nLoop fixing is armed: after your report, the extension drives up to ${budgets.loop} fix→re-review rounds until no P0/P1 findings remain — so tag every finding with a priority (P0–P3).\n`
|
|
209
|
+
: "",
|
|
210
|
+
},
|
|
211
|
+
),
|
|
158
212
|
);
|
|
213
|
+
if (loopArmed) {
|
|
214
|
+
await runLoopFixing(pi, ctx, {
|
|
215
|
+
level,
|
|
216
|
+
passes: budgets.loop,
|
|
217
|
+
// Must match where review_report writes (CONFIG_DIR_NAME,
|
|
218
|
+
// not necessarily ".pi") or the loop never finds a report.
|
|
219
|
+
reviewDir: path.join(ctx.cwd, CONFIG_DIR_NAME, "review"),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
159
222
|
},
|
|
160
223
|
});
|
|
161
224
|
|
|
162
|
-
pi.registerCommand("simplify", {
|
|
225
|
+
pi.registerCommand("code-simplify", {
|
|
163
226
|
description:
|
|
164
|
-
"Clean up the changed code (reuse/simplification/efficiency/altitude) using the simplify skill. Mode (parallel 4-agent vs single-pass) is decided from the strategy declared in prompts/simplify.*.md (context usage, diff size, fan-out availability); PARALLEL opens with a visible Phase 0 before the subagent tool launches the agents. Usage: /simplify [<target>]",
|
|
227
|
+
"Clean up the changed code (reuse/simplification/efficiency/altitude) using the code-simplify skill. Mode (parallel 4-agent vs single-pass) is decided from the strategy declared in prompts/simplify.*.md (context usage, diff size, fan-out availability); PARALLEL opens with a visible Phase 0 before the subagent tool launches the agents. Usage: /code-simplify [<target>]",
|
|
165
228
|
async handler(args, ctx) {
|
|
166
229
|
try {
|
|
167
230
|
// ctx.signal (undefined while idle) lets Esc abort an in-flight diff.
|
|
168
231
|
const outcome = await getRepoDiff(ctx.cwd, args?.trim() || undefined, undefined, ctx.signal);
|
|
169
232
|
if (outcome.kind === "no-repo") {
|
|
170
|
-
ctx.ui.notify(`/simplify: ${ctx.cwd} is not inside a git repo — nothing to clean up.`, "warning");
|
|
233
|
+
ctx.ui.notify(`/code-simplify: ${ctx.cwd} is not inside a git repo — nothing to clean up.`, "warning");
|
|
171
234
|
return;
|
|
172
235
|
}
|
|
173
236
|
if (outcome.kind === "git-error") {
|
|
174
|
-
ctx.ui.notify(`/simplify: git failed — ${outcome.message}`, "error");
|
|
237
|
+
ctx.ui.notify(`/code-simplify: git failed — ${outcome.message}`, "error");
|
|
175
238
|
return;
|
|
176
239
|
}
|
|
177
240
|
if (outcome.kind === "empty") {
|
|
178
241
|
ctx.ui.notify(
|
|
179
|
-
`/simplify: no changes found (checked unpushed+uncommitted vs @{upstream}, uncommitted vs HEAD, staged, unstaged) — nothing to clean up.`,
|
|
242
|
+
`/code-simplify: no changes found (checked unpushed+uncommitted vs @{upstream}, uncommitted vs HEAD, staged, unstaged) — nothing to clean up.`,
|
|
180
243
|
"warning",
|
|
181
244
|
);
|
|
182
245
|
return;
|
|
@@ -193,7 +256,7 @@ export function registerDispatcher(pi: ExtensionAPI): void {
|
|
|
193
256
|
});
|
|
194
257
|
const pct = usage && usage.percent != null ? `${Math.round(usage.percent)}%` : "?";
|
|
195
258
|
const target = args || "(whole diff)";
|
|
196
|
-
const skill = bundledSkillPath("simplify/SKILL.md");
|
|
259
|
+
const skill = bundledSkillPath("code-simplify/SKILL.md");
|
|
197
260
|
const scopeLabel = DIFF_SCOPES[outcome.scopeKind];
|
|
198
261
|
const contextPackage = buildContextPackage(outcome.diff, outcome.gitRoot, scopeLabel);
|
|
199
262
|
const verify = verifyLine(outcome.gitRoot);
|
|
@@ -231,7 +294,7 @@ export function registerDispatcher(pi: ExtensionAPI): void {
|
|
|
231
294
|
}),
|
|
232
295
|
);
|
|
233
296
|
} catch (err) {
|
|
234
|
-
ctx.ui.notify(`/simplify failed: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
297
|
+
ctx.ui.notify(`/code-simplify failed: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
235
298
|
}
|
|
236
299
|
},
|
|
237
300
|
});
|