pi-review-loop 0.2.1 → 0.3.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 (3) hide show
  1. package/README.md +9 -11
  2. package/index.ts +76 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -44,18 +44,8 @@ The pattern is the same: keep reviewing until there's genuinely nothing left to
44
44
 
45
45
  ## Install
46
46
 
47
- **npm** (recommended):
48
-
49
47
  ```bash
50
- npm install -g pi-review-loop
51
- ```
52
-
53
- The extension is automatically copied to `~/.pi/agent/extensions/pi-review-loop/`.
54
-
55
- **Or clone directly:**
56
-
57
- ```bash
58
- git clone https://github.com/nicobailon/pi-review-loop ~/.pi/agent/extensions/pi-review-loop
48
+ pi install npm:pi-review-loop
59
49
  ```
60
50
 
61
51
  Restart pi to load the extension. On activation, you'll see status in the footer:
@@ -253,9 +243,13 @@ The loop exits when:
253
243
  | Command | Description |
254
244
  |---------|-------------|
255
245
  | `/review-start` | Activate and send review prompt immediately |
246
+ | `/review-start "focus on X"` | Start review with custom focus appended to prompt |
247
+ | `/review-plan` | Activate and review plans/specs/PRDs (uses `double-check-plan` template) |
248
+ | `/review-plan "focus on X"` | Review plan with custom focus appended to prompt |
256
249
  | `/review-exit` | Exit review mode |
257
250
  | `/review-max <n>` | Set max iterations (session only) |
258
251
  | `/review-auto [on\|off]` | Toggle auto-trigger from keywords (session only) |
252
+ | `/review-auto "focus on X"` | Enable auto-trigger AND start review with custom focus |
259
253
  | `/review-status` | Show current state |
260
254
 
261
255
  ## Tool API
@@ -272,6 +266,9 @@ review_loop({ start: true })
272
266
  // Start with custom max iterations
273
267
  review_loop({ start: true, maxIterations: 5 })
274
268
 
269
+ // Start with custom focus
270
+ review_loop({ start: true, focus: "focus on error handling and edge cases" })
271
+
275
272
  // Stop review mode
276
273
  review_loop({ stop: true })
277
274
 
@@ -290,6 +287,7 @@ review_loop({ autoTrigger: false })
290
287
  "currentIteration": 2,
291
288
  "maxIterations": 7,
292
289
  "autoTrigger": false,
290
+ "focus": "focus on error handling",
293
291
  "message": "Review mode active: iteration 2/7"
294
292
  }
295
293
  ```
package/index.ts CHANGED
@@ -6,6 +6,7 @@ export default function (pi: ExtensionAPI) {
6
6
  let settings: ReviewerLoopSettings = loadSettings();
7
7
  let reviewModeActive = false;
8
8
  let currentIteration = 0;
9
+ let customPromptSuffix = "";
9
10
 
10
11
  function updateStatus(ctx: ExtensionContext) {
11
12
  if (reviewModeActive) {
@@ -18,9 +19,25 @@ export default function (pi: ExtensionAPI) {
18
19
  }
19
20
  }
20
21
 
22
+ function buildReviewPrompt(promptConfig: { type: "inline" | "file" | "template"; value: string }): string {
23
+ const basePrompt = getReviewPrompt(promptConfig);
24
+ if (customPromptSuffix) {
25
+ return `${basePrompt}\n\n**Additional focus:** ${customPromptSuffix}`;
26
+ }
27
+ return basePrompt;
28
+ }
29
+
30
+ function parseCustomText(args: string): string {
31
+ // Match quoted strings: "text" or 'text' (must use matching quotes)
32
+ const match = args.match(/^"(.+)"$/s) || args.match(/^'(.+)'$/s) ||
33
+ args.match(/"(.+?)"/s) || args.match(/'(.+?)'/s);
34
+ return match ? match[1].trim() : "";
35
+ }
36
+
21
37
  function exitReviewMode(ctx: ExtensionContext, reason: string) {
22
38
  reviewModeActive = false;
23
39
  currentIteration = 0;
40
+ customPromptSuffix = "";
24
41
  updateStatus(ctx);
25
42
  ctx.ui.notify(`Review mode ended: ${reason}`, "info");
26
43
  }
@@ -103,19 +120,33 @@ export default function (pi: ExtensionAPI) {
103
120
  }
104
121
 
105
122
  updateStatus(ctx);
106
- pi.sendUserMessage(getReviewPrompt(settings.reviewPromptConfig), {
123
+ pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig), {
107
124
  deliverAs: "followUp",
108
125
  });
109
126
  });
110
127
 
111
128
  pi.registerCommand("review-start", {
112
- description: "Activate review loop and send review prompt immediately",
113
- handler: async (_args, ctx) => {
129
+ description: "Activate review loop and send review prompt immediately. Optional: add custom focus with quotes.",
130
+ handler: async (args, ctx) => {
114
131
  if (reviewModeActive) {
115
132
  ctx.ui.notify("Review mode is already active", "info");
116
133
  } else {
134
+ customPromptSuffix = parseCustomText(args);
117
135
  enterReviewMode(ctx);
118
- pi.sendUserMessage(getReviewPrompt(settings.reviewPromptConfig));
136
+ pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig));
137
+ }
138
+ },
139
+ });
140
+
141
+ pi.registerCommand("review-plan", {
142
+ description: "Activate review loop for plans/specs/PRDs. Optional: add custom focus with quotes.",
143
+ handler: async (args, ctx) => {
144
+ if (reviewModeActive) {
145
+ ctx.ui.notify("Review mode is already active", "info");
146
+ } else {
147
+ customPromptSuffix = parseCustomText(args);
148
+ enterReviewMode(ctx);
149
+ pi.sendUserMessage(buildReviewPrompt({ type: "template", value: "double-check-plan" }));
119
150
  }
120
151
  },
121
152
  });
@@ -162,17 +193,36 @@ export default function (pi: ExtensionAPI) {
162
193
  });
163
194
 
164
195
  pi.registerCommand("review-auto", {
165
- description: "Toggle auto-trigger from keywords (off by default)",
196
+ description: "Toggle auto-trigger, or start review with custom focus: /review-auto \"focus on X\"",
166
197
  handler: async (args, ctx) => {
167
- const arg = args.trim().toLowerCase();
168
- if (arg === "on" || arg === "true" || arg === "1") {
198
+ const arg = args.trim();
199
+ const argLower = arg.toLowerCase();
200
+
201
+ // Check for quoted custom text first
202
+ const customText = parseCustomText(arg);
203
+ if (customText) {
204
+ // Custom text provided: enable auto-trigger and start review with custom focus
205
+ settings.autoTrigger = true;
206
+ customPromptSuffix = customText;
207
+ if (reviewModeActive) {
208
+ ctx.ui.notify(`Auto-trigger enabled, focus updated for next iteration`, "info");
209
+ } else {
210
+ enterReviewMode(ctx);
211
+ pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig));
212
+ ctx.ui.notify(`Auto-trigger enabled, review started with custom focus`, "info");
213
+ }
214
+ return;
215
+ }
216
+
217
+ // Standard on/off/toggle behavior
218
+ if (argLower === "on" || argLower === "true" || argLower === "1") {
169
219
  settings.autoTrigger = true;
170
- } else if (arg === "off" || arg === "false" || arg === "0") {
220
+ } else if (argLower === "off" || argLower === "false" || argLower === "0") {
171
221
  settings.autoTrigger = false;
172
222
  } else if (arg === "") {
173
223
  settings.autoTrigger = !settings.autoTrigger;
174
224
  } else {
175
- ctx.ui.notify("Usage: /review-auto [on|off]", "error");
225
+ ctx.ui.notify("Usage: /review-auto [on|off] or /review-auto \"custom focus\"", "error");
176
226
  return;
177
227
  }
178
228
  ctx.ui.notify(
@@ -208,6 +258,11 @@ export default function (pi: ExtensionAPI) {
208
258
  minimum: 1,
209
259
  })
210
260
  ),
261
+ focus: Type.Optional(
262
+ Type.String({
263
+ description: "Custom focus/instructions to append to the review prompt (e.g., \"focus on error handling\")",
264
+ })
265
+ ),
211
266
  }),
212
267
 
213
268
  async execute(_toolCallId, params, _onUpdate, ctx) {
@@ -225,6 +280,11 @@ export default function (pi: ExtensionAPI) {
225
280
  );
226
281
  }
227
282
 
283
+ // Update custom focus if provided
284
+ if (typeof params.focus === "string") {
285
+ customPromptSuffix = params.focus.trim();
286
+ }
287
+
228
288
  // Mode: start > stop > status
229
289
  if (params.start) {
230
290
  if (reviewModeActive) {
@@ -237,6 +297,7 @@ export default function (pi: ExtensionAPI) {
237
297
  currentIteration,
238
298
  maxIterations: settings.maxIterations,
239
299
  autoTrigger: settings.autoTrigger,
300
+ focus: customPromptSuffix || undefined,
240
301
  message: "Review mode is already active",
241
302
  }),
242
303
  },
@@ -245,7 +306,7 @@ export default function (pi: ExtensionAPI) {
245
306
  }
246
307
 
247
308
  enterReviewMode(ctx);
248
- pi.sendUserMessage(getReviewPrompt(settings.reviewPromptConfig));
309
+ pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig));
249
310
 
250
311
  return {
251
312
  content: [
@@ -256,7 +317,10 @@ export default function (pi: ExtensionAPI) {
256
317
  currentIteration,
257
318
  maxIterations: settings.maxIterations,
258
319
  autoTrigger: settings.autoTrigger,
259
- message: "Review mode started. Review prompt sent.",
320
+ focus: customPromptSuffix || undefined,
321
+ message: customPromptSuffix
322
+ ? `Review mode started with custom focus. Review prompt sent.`
323
+ : "Review mode started. Review prompt sent.",
260
324
  }),
261
325
  },
262
326
  ],
@@ -309,6 +373,7 @@ export default function (pi: ExtensionAPI) {
309
373
  currentIteration,
310
374
  maxIterations: settings.maxIterations,
311
375
  autoTrigger: settings.autoTrigger,
376
+ focus: customPromptSuffix || undefined,
312
377
  message: reviewModeActive
313
378
  ? `Review mode active: iteration ${currentIteration}/${settings.maxIterations}`
314
379
  : "Review mode inactive",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-review-loop",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Automated code review loop extension for pi coding agent",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/install.js",