taskplane 0.22.6 → 0.22.7

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.
@@ -2148,6 +2148,9 @@ export default function (pi: ExtensionAPI) {
2148
2148
 
2149
2149
  // ── review_step Tool (orchestrated mode only) ───────────────────
2150
2150
 
2151
+ /** Per-step code review cycle counter. Reset when reviewer is killed after APPROVE. */
2152
+ const stepCodeReviewCounts = new Map<number, number>();
2153
+
2151
2154
  /**
2152
2155
  * Reset reviewer telemetry fields on state to idle/zero.
2153
2156
  * Called after a review completes to clear dashboard metrics.
@@ -2291,6 +2294,30 @@ export default function (pi: ExtensionAPI) {
2291
2294
  const reviewsDir = join(task.taskFolder, ".reviews");
2292
2295
  if (!existsSync(reviewsDir)) mkdirSync(reviewsDir, { recursive: true });
2293
2296
 
2297
+ // Per-step code review cycle limit
2298
+ if (reviewType === "code") {
2299
+ const codeCount = (stepCodeReviewCounts.get(stepNum) || 0) + 1;
2300
+ stepCodeReviewCounts.set(stepNum, codeCount);
2301
+ const maxCycles = config.context.max_review_cycles || 2;
2302
+ if (codeCount > maxCycles) {
2303
+ logExecution(statusPath, `Skip code review`,
2304
+ `Step ${stepNum} code review cycle limit reached (${codeCount}/${maxCycles}) — auto-approving`);
2305
+ // Kill reviewer to free context for next step
2306
+ if (state.persistentReviewerKill) {
2307
+ try { state.persistentReviewerKill(); } catch {}
2308
+ }
2309
+ state.persistentReviewerSession = null;
2310
+ state.persistentReviewerKill = null;
2311
+ state.persistentReviewerSignalNum = 0;
2312
+ state.reviewerRespawnCount = 0;
2313
+ stepCodeReviewCounts.delete(stepNum);
2314
+ return {
2315
+ content: [{ type: "text" as const, text: `APPROVE — Code review cycle limit reached (${maxCycles}). Auto-approved to prevent context exhaustion.` }],
2316
+ details: undefined,
2317
+ };
2318
+ }
2319
+ }
2320
+
2294
2321
  // Low-risk step check (safety net — worker template also skips)
2295
2322
  if (isLowRiskStep(stepNum, task.steps.length)) {
2296
2323
  const label = stepNum === 0 ? "Preflight" : "final step";
@@ -2551,17 +2578,19 @@ export default function (pi: ExtensionAPI) {
2551
2578
  updateWidgets();
2552
2579
 
2553
2580
  // Extract verdict and build result
2554
- const { resultText } = processReviewVerdict(
2581
+ const { resultText, verdict } = processReviewVerdict(
2555
2582
  reviewContent, statusPath, num, reviewType, stepNum, state.reviewCounter,
2556
2583
  );
2557
2584
 
2558
- // After code review: kill the persistent reviewer to free context.
2559
- // The reviewer persists through a plan+code pair for one step,
2560
- // then gets a fresh session for the next step.
2561
- if (reviewType === "code") {
2562
- console.error(`[task-runner] code review complete for step ${stepNum} — killing reviewer for fresh context on next step`);
2585
+ // After code review APPROVE: kill the persistent reviewer to free context.
2586
+ // The reviewer persists through plan+code for one step, and through
2587
+ // REVISE→fix→re-review cycles (it knows what it asked to be fixed).
2588
+ // Only kill on APPROVE — a REVISE means the worker needs to fix and
2589
+ // re-submit, and the same reviewer should evaluate the follow-up.
2590
+ if (reviewType === "code" && (verdict === "APPROVE" || verdict === "UNAVAILABLE")) {
2591
+ console.error(`[task-runner] code review ${verdict} for step ${stepNum} — killing reviewer for fresh context on next step`);
2563
2592
  logExecution(statusPath, `Reviewer R${num}`,
2564
- `code review complete — killing persistent reviewer (step ${stepNum} cycle done)`);
2593
+ `code review ${verdict} — killing persistent reviewer (step ${stepNum} cycle done)`);
2565
2594
  if (state.persistentReviewerKill) {
2566
2595
  try { state.persistentReviewerKill(); } catch {}
2567
2596
  }
@@ -2569,6 +2598,7 @@ export default function (pi: ExtensionAPI) {
2569
2598
  state.persistentReviewerKill = null;
2570
2599
  state.persistentReviewerSignalNum = 0;
2571
2600
  state.reviewerRespawnCount = 0;
2601
+ stepCodeReviewCounts.delete(stepNum);
2572
2602
  }
2573
2603
 
2574
2604
  state.reviewerStatus = "idle";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.22.6",
3
+ "version": "0.22.7",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",