@pourkit/cli 0.0.0-next-20260621094003 → 0.0.0-next-20260621233457

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/dist/cli.js CHANGED
@@ -442,6 +442,25 @@ function checkRemovedFields(raw) {
442
442
  );
443
443
  }
444
444
  }
445
+ const strategy = target.strategy;
446
+ if (strategy && typeof strategy === "object") {
447
+ const review = strategy.review;
448
+ if (review && typeof review === "object") {
449
+ if ("passWithNotesRefactorAttempts" in review) {
450
+ throw new Error(
451
+ `targets[${i}].strategy.review.passWithNotesRefactorAttempts has been removed; PASS_WITH_NOTES no longer triggers Refactor.`
452
+ );
453
+ }
454
+ const reviewer = review.reviewer;
455
+ if (reviewer && typeof reviewer === "object") {
456
+ if ("passWithNotesRefactorAttempts" in reviewer) {
457
+ throw new Error(
458
+ `targets[${i}].strategy.review.reviewer.passWithNotesRefactorAttempts has been removed; PASS_WITH_NOTES no longer triggers Refactor.`
459
+ );
460
+ }
461
+ }
462
+ }
463
+ }
445
464
  }
446
465
  }
447
466
  }
@@ -773,14 +792,12 @@ function parseConfig(raw) {
773
792
  reviewReviewer.outputRetries
774
793
  ),
775
794
  criteria: reviewReviewer.criteria,
776
- includeReviewHistory: reviewReviewer.includeReviewHistory,
777
- passWithNotesRefactorAttempts: reviewReviewer.passWithNotesRefactorAttempts
795
+ includeReviewHistory: reviewReviewer.includeReviewHistory
778
796
  },
779
797
  refactor: applyStageAgentDefaults(
780
798
  reviewRefactor
781
799
  ),
782
- maxIterations: review.maxIterations,
783
- passWithNotesRefactorAttempts: review.passWithNotesRefactorAttempts ?? 2
800
+ maxIterations: review.maxIterations
784
801
  },
785
802
  ...verifyLabeled ? { verify: { commands: verifyLabeled } } : {},
786
803
  issueFinalReview: {
@@ -1168,9 +1185,11 @@ function parseReviewVerdict(output) {
1168
1185
  }
1169
1186
 
1170
1187
  // commands/review.ts
1188
+ import { Effect as Effect3 } from "effect";
1189
+
1190
+ // issues/issue-review-loop.ts
1171
1191
  import {
1172
1192
  existsSync as existsSync6,
1173
- mkdirSync as mkdirSync5,
1174
1193
  readFileSync as readFileSync6,
1175
1194
  readdirSync as readdirSync2,
1176
1195
  writeFileSync as writeFileSync3
@@ -1465,7 +1484,7 @@ function buildRunContextMarkdown(options) {
1465
1484
  );
1466
1485
  }
1467
1486
  if (sections.includes("verification-commands")) {
1468
- parts.push(...renderCommandList(target, "Verification Commands"));
1487
+ parts.push(...renderCommandList(target, "Verification Commands", repoRoot2));
1469
1488
  }
1470
1489
  if (sections.includes("review-criteria")) {
1471
1490
  parts.push(...renderCriteria(reviewerCriteria));
@@ -1483,14 +1502,27 @@ function buildRunContextMarkdown(options) {
1483
1502
  }
1484
1503
  return parts.join("\n");
1485
1504
  }
1486
- function renderCommandList(target, heading) {
1505
+ function renderCommandList(target, heading, repoRoot2) {
1487
1506
  const commands = getVerificationCommands(target);
1507
+ const wrapperCommand = buildRunVerificationCommand(target);
1488
1508
  const parts = [
1489
1509
  `## ${heading}`,
1490
1510
  "",
1491
- `Run this command from the repository root: \`${buildRunVerificationCommand(target)}\``,
1511
+ `Run this command from the repository root: \`${wrapperCommand}\``,
1512
+ "",
1513
+ "Use the wrapper as the configured verification method for Builder, Reviewer, Refactor, and Issue Final Review handoffs. Run the underlying commands directly only when no wrapper path can run, and record that degraded path in the role's artifact or handoff notes.",
1492
1514
  ""
1493
1515
  ];
1516
+ if (isPourkitSourceRepo(repoRoot2)) {
1517
+ parts.push(
1518
+ "Pourkit self-development fallback:",
1519
+ "",
1520
+ `- If \`${wrapperCommand}\` fails before running configured commands because the installed CLI rejects this worktree's config schemaVersion, build and rerun the same target with the worktree-local CLI: \`npm run build --workspace pourkit\`, then \`node pourkit/dist/cli.js run-verification --target ${target.name}\`.`,
1521
+ '- Treat local CLI wrapper success as valid configured verification and record it as `verification.method: "local-wrapper"` in Issue Final Review artifacts, or as local-wrapper verification in Builder/Reviewer/Refactor handoff notes.',
1522
+ '- Fall back to the underlying configured commands only if the worktree-local CLI cannot be built or invoked; record that degraded path as `verification.method: "commands"` in Issue Final Review artifacts, or as direct-command verification in Builder/Reviewer/Refactor handoff notes, and explain why the wrapper path could not run.',
1523
+ ""
1524
+ );
1525
+ }
1494
1526
  if (commands.length > 0) {
1495
1527
  parts.push(
1496
1528
  "Configured commands executed by the wrapper:",
@@ -1503,6 +1535,17 @@ function renderCommandList(target, heading) {
1503
1535
  }
1504
1536
  return parts;
1505
1537
  }
1538
+ function isPourkitSourceRepo(repoRoot2) {
1539
+ if (!repoRoot2) return false;
1540
+ const packagePath = join5(repoRoot2, "pourkit", "package.json");
1541
+ if (!existsSync4(packagePath)) return false;
1542
+ try {
1543
+ const parsed = JSON.parse(readFileSync4(packagePath, "utf-8"));
1544
+ return parsed.name === "@pourkit/cli";
1545
+ } catch {
1546
+ return false;
1547
+ }
1548
+ }
1506
1549
  function renderParentPrdContext(issue, parentPrdIssue, repoRoot2) {
1507
1550
  const parent = extractIssueSection(issue.body, "Parent");
1508
1551
  const parentRef = parent?.match(/\bPRD-\d+\b/i)?.[0]?.toUpperCase() ?? issue.title.match(/^\s*(PRD-\d+)\s*\/\s*I-\d+\b/i)?.[1]?.toUpperCase();
@@ -1971,7 +2014,7 @@ function validateRecoveryDecision(artifact, allowedDecisions) {
1971
2014
  return { valid: true, decision };
1972
2015
  }
1973
2016
 
1974
- // commands/review.ts
2017
+ // issues/issue-review-loop.ts
1975
2018
  import { Effect as Effect2, Layer as Layer2 } from "effect";
1976
2019
  var ReviewArtifactValidationError = class extends Error {
1977
2020
  constructor(message) {
@@ -2162,6 +2205,172 @@ function validateReviewArtifact(output, verdict, iteration, priorRefactorArtifac
2162
2205
  }
2163
2206
  }
2164
2207
  }
2208
+ function renderReviewHistory(reviewHistory) {
2209
+ if (reviewHistory.length === 0) {
2210
+ return "";
2211
+ }
2212
+ return `## Review History
2213
+
2214
+ ${reviewHistory.map((entry, index) => `### Iteration ${index + 1}
2215
+
2216
+ ${entry.trimEnd()}`).join("\n\n")}
2217
+
2218
+ `;
2219
+ }
2220
+ function renderReviewCriteriaEffect(repoRoot2, criteria, fs) {
2221
+ return Effect2.gen(function* () {
2222
+ const parts = [];
2223
+ for (const criterion of criteria) {
2224
+ const snippetPath = join6(
2225
+ repoRoot2,
2226
+ ".pourkit",
2227
+ "managed",
2228
+ "prompts",
2229
+ `reviewer-${criterion}.snippet.md`
2230
+ );
2231
+ const exists = yield* fs.exists(snippetPath).pipe(Effect2.orDie);
2232
+ if (exists) {
2233
+ const content = yield* fs.readFile(snippetPath).pipe(Effect2.orDie);
2234
+ parts.push(content.trimEnd());
2235
+ } else {
2236
+ parts.push(`- ${criterion}`);
2237
+ }
2238
+ }
2239
+ return parts.join("\n\n");
2240
+ });
2241
+ }
2242
+ function loadReviewerPromptTemplateEffect(repoRoot2, promptTemplate, criteriaBlock, fs) {
2243
+ return Effect2.gen(function* () {
2244
+ const promptTemplatePath = resolvePromptTemplatePath(
2245
+ repoRoot2,
2246
+ promptTemplate
2247
+ );
2248
+ const exists = yield* fs.exists(promptTemplatePath).pipe(Effect2.orDie);
2249
+ const promptBody = exists ? yield* fs.readFile(promptTemplatePath).pipe(Effect2.orDie) : promptTemplate;
2250
+ const hasCriteriaPlaceholder = promptBody.includes("{{REVIEW_CRITERIA}}");
2251
+ return {
2252
+ content: promptBody.replace(/\{\{REVIEW_CRITERIA\}\}/g, criteriaBlock),
2253
+ hasCriteriaPlaceholder
2254
+ };
2255
+ });
2256
+ }
2257
+ function buildReviewerPromptEffect(repoRoot2, promptTemplate, criteria, artifactPathInWorktree, iteration, fs, reviewHistory = [], priorRefactorArtifacts, humanHandoffResolved, priorReviewerArtifacts) {
2258
+ return Effect2.gen(function* () {
2259
+ const criteriaBlock = yield* renderReviewCriteriaEffect(
2260
+ repoRoot2,
2261
+ criteria,
2262
+ fs
2263
+ );
2264
+ const { content: renderedTemplate, hasCriteriaPlaceholder } = yield* loadReviewerPromptTemplateEffect(
2265
+ repoRoot2,
2266
+ promptTemplate,
2267
+ criteriaBlock,
2268
+ fs
2269
+ );
2270
+ const priorRefactorBlock = priorRefactorArtifacts ? `${priorRefactorArtifacts}` : "";
2271
+ const priorRefactorProtocolReminder = priorRefactorArtifacts ? `## Prior Refactor Protocol Reminder
2272
+
2273
+ MANDATORY: because this prompt contains ## Prior Refactor Artifacts, your artifact must contain ## Prior Refactor Response Assessment exactly, before verdict. Section headings must match the names defined in this protocol exactly.
2274
+
2275
+ ` : "";
2276
+ const priorReviewerBlock = priorReviewerArtifacts ? `${priorReviewerArtifacts}` : "";
2277
+ const humanHandoffBoundary = humanHandoffResolved ? `## Human-Resolved Handoff Boundary
2278
+
2279
+ A prior review emitted \`NEEDS_HUMAN\` and stopped the agent loop. The issue has since been moved back to \`ready-for-agent\`.
2280
+
2281
+ Before carrying forward old blockers, inspect newer issue comments and the current worktree. Treat prior Reviewer and Refactor Artifacts as historical context, not active findings unless they still apply.
2282
+
2283
+ ` : "";
2284
+ return appendProtectedWorkGuidance(`${renderedTemplate}
2285
+
2286
+ ## Shared Run Context
2287
+
2288
+ Read the selected issue requirements, planning context (including plan and PRD content when present), branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}
2289
+
2290
+ ## Initial Verification Pass
2291
+
2292
+ - First read ${RUN_CONTEXT_PATH_IN_WORKTREE} only far enough to identify the configured verification commands.
2293
+ - Before reviewing code, diffs, artifacts, or prior findings, run the configured verification wrapper yourself from the Worktree.
2294
+ - If ${RUN_CONTEXT_PATH_IN_WORKTREE} provides a worktree-local CLI fallback, use that fallback before considering direct command execution.
2295
+ - Run underlying verification commands directly only when no wrapper path can run, and record why verification used direct commands.
2296
+ - If a configured command fails, keep reviewing after recording the failure details; use the failure output as review evidence.
2297
+ - If a command cannot run because the environment is missing required setup, dependencies, or scripts outside agent control, treat it as a human handoff blocker.
2298
+ - If no verification commands are configured, note that and proceed with normal review.
2299
+
2300
+ ## Scope Evidence Rules
2301
+
2302
+ - Use the Run Context's canonical base ref, for example \`origin/<base>\`, for scope diffs and commit ranges.
2303
+ - Do not use bare PRD/base branch names such as \`PRD-0063\`, \`main\`, or \`dev\` for scope decisions; local branches with those names may be stale.
2304
+ - Only call a file or commit out of scope when it is part of the working branch's delta from the canonical base ref.
2305
+ - Do not recommend reverting accepted sibling/base work. If a file is present or changed on the canonical base ref, it is not this Issue's scope overreach.
2306
+ - If scope evidence is ambiguous, use \`NEEDS_HUMAN\` or ask for a runner/base mismatch decision instead of telling Refactor to revert files.
2307
+
2308
+ ${hasCriteriaPlaceholder ? "" : `## Review Criteria
2309
+
2310
+ ${criteriaBlock}
2311
+
2312
+ `}${humanHandoffBoundary}${priorReviewerBlock}${renderReviewHistory(reviewHistory)}${priorRefactorBlock}${priorRefactorProtocolReminder}## Output
2313
+
2314
+ Write your review to: ${artifactPathInWorktree}
2315
+
2316
+ Before handoff, run: pourkit validate-artifact reviewer ${artifactPathInWorktree} --iteration ${iteration}${priorRefactorArtifacts ? " --prior-refactor-artifacts" : ""}
2317
+
2318
+ Do not provide a separate chat response. The runner only reads the file above.
2319
+
2320
+ End the file with exactly one wrapped verdict token: <verdict>PASS</verdict>, <verdict>PASS_WITH_NOTES</verdict>, <verdict>NEEDS_REFACTOR</verdict>, <verdict>FAIL</verdict>, or <verdict>NEEDS_HUMAN</verdict>. The verdict token must appear exactly once in the output.
2321
+
2322
+ Findings must include an ID column with values in the format R${iteration}.F{findingNumber} (e.g., R${iteration}.F1, R${iteration}.F2) and a Supersedes column referencing the finding ID being superseded (or a hyphen for new findings).
2323
+
2324
+ When verdict is NEEDS_HUMAN, include Human Handoff Summary and Human Handoff Reason sections before the final verdict token.`);
2325
+ });
2326
+ }
2327
+ function recoverReviewOutputFromString(logContent) {
2328
+ const startIndex = logContent.indexOf("## Findings");
2329
+ if (startIndex === -1) return null;
2330
+ const verdictMatch = logContent.slice(startIndex).match(
2331
+ /<verdict>(PASS|PASS_WITH_NOTES|NEEDS_REFACTOR|FAIL|NEEDS_HUMAN)<\/verdict>/
2332
+ );
2333
+ if (!verdictMatch || verdictMatch.index === void 0) return null;
2334
+ const recoveredOutput = logContent.slice(startIndex, startIndex + verdictMatch.index + verdictMatch[0].length).trim();
2335
+ return recoveredOutput.length > 0 ? recoveredOutput : null;
2336
+ }
2337
+ function recoverReviewOutputFromLog(logPath) {
2338
+ if (!existsSync6(logPath)) {
2339
+ return null;
2340
+ }
2341
+ const logContent = readFileSync6(logPath, "utf-8");
2342
+ return recoverReviewOutputFromString(logContent);
2343
+ }
2344
+ function readReviewArtifact(artifactPath, logPath) {
2345
+ if (existsSync6(artifactPath)) {
2346
+ const output = readFileSync6(artifactPath, "utf-8");
2347
+ if (output.trim()) {
2348
+ return output;
2349
+ }
2350
+ }
2351
+ const recoveredOutput = logPath ? recoverReviewOutputFromLog(logPath) : null;
2352
+ if (recoveredOutput) {
2353
+ writeFileSync3(artifactPath, recoveredOutput, "utf-8");
2354
+ return recoveredOutput;
2355
+ }
2356
+ if (!existsSync6(artifactPath)) {
2357
+ throw new Error(`Reviewer did not produce output at ${artifactPath}`);
2358
+ }
2359
+ throw new Error(`Reviewer produced empty output at ${artifactPath}`);
2360
+ }
2361
+ function bridgeExecutionProvider(ep) {
2362
+ return Layer2.succeed(
2363
+ ExecutionProvider,
2364
+ ExecutionProvider.of({
2365
+ execute: (opts) => Effect2.tryPromise({
2366
+ try: () => ep.execute(opts),
2367
+ catch: (e) => new Error(
2368
+ e instanceof Error ? e.message : `Execution failed: ${String(e)}`
2369
+ )
2370
+ })
2371
+ })
2372
+ );
2373
+ }
2165
2374
  function runReviewCommandEffect(options) {
2166
2375
  const {
2167
2376
  executionProvider,
@@ -2314,100 +2523,43 @@ function runReviewCommandEffect(options) {
2314
2523
  return { verdict: parsedVerdict, output, artifactPath };
2315
2524
  });
2316
2525
  }
2317
- function bridgeExecutionProvider(ep) {
2318
- return Layer2.succeed(
2319
- ExecutionProvider,
2320
- ExecutionProvider.of({
2321
- execute: (opts) => Effect2.tryPromise({
2322
- try: () => ep.execute(opts),
2323
- catch: (e) => new Error(
2324
- e instanceof Error ? e.message : `Execution failed: ${String(e)}`
2325
- )
2326
- })
2327
- })
2328
- );
2329
- }
2330
- function buildReviewerPromptEffect(repoRoot2, promptTemplate, criteria, artifactPathInWorktree, iteration, fs, reviewHistory = [], priorRefactorArtifacts, humanHandoffResolved, priorReviewerArtifacts) {
2526
+ function buildRefactorPromptEffect(repoRoot2, promptTemplate, latestReview, artifactPathInWorktree, iteration, fs) {
2331
2527
  return Effect2.gen(function* () {
2332
- const criteriaBlock = yield* renderReviewCriteriaEffect(
2333
- repoRoot2,
2334
- criteria,
2335
- fs
2336
- );
2337
- const { content: renderedTemplate, hasCriteriaPlaceholder } = yield* loadReviewerPromptTemplateEffect(
2528
+ const promptTemplatePath = resolvePromptTemplatePath(
2338
2529
  repoRoot2,
2339
- promptTemplate,
2340
- criteriaBlock,
2341
- fs
2530
+ promptTemplate
2342
2531
  );
2343
- const priorRefactorBlock = priorRefactorArtifacts ? `${priorRefactorArtifacts}` : "";
2344
- const priorRefactorProtocolReminder = priorRefactorArtifacts ? `## Prior Refactor Protocol Reminder
2345
-
2346
- MANDATORY: because this prompt contains ## Prior Refactor Artifacts, your artifact must contain ## Prior Refactor Response Assessment exactly, before verdict. Section headings must match the names defined in this protocol exactly.
2347
-
2348
- ` : "";
2349
- const priorReviewerBlock = priorReviewerArtifacts ? `${priorReviewerArtifacts}` : "";
2350
- const humanHandoffBoundary = humanHandoffResolved ? `## Human-Resolved Handoff Boundary
2351
-
2352
- A prior review emitted \`NEEDS_HUMAN\` and stopped the agent loop. The issue has since been moved back to \`ready-for-agent\`.
2353
-
2354
- Before carrying forward old blockers, inspect newer issue comments and the current worktree. Treat prior Reviewer and Refactor Artifacts as historical context, not active findings unless they still apply.
2355
-
2356
- ` : "";
2357
- return appendProtectedWorkGuidance(`${renderedTemplate}
2532
+ const exists = yield* fs.exists(promptTemplatePath).pipe(Effect2.orDie);
2533
+ const promptBody = exists ? yield* fs.readFile(promptTemplatePath).pipe(Effect2.orDie) : promptTemplate;
2534
+ const findingIds = extractLatestFindingIds(latestReview, iteration);
2535
+ const findingArgs = findingIds.map((id) => ` --finding-id ${id}`).join("");
2536
+ return appendProtectedWorkGuidance(`${promptBody}
2358
2537
 
2359
2538
  ## Shared Run Context
2360
2539
 
2361
2540
  Read the selected issue requirements, planning context (including plan and PRD content when present), branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}
2362
2541
 
2363
- ## Initial Verification Pass
2364
-
2365
- - First read ${RUN_CONTEXT_PATH_IN_WORKTREE} only far enough to identify the configured verification commands.
2366
- - Before reviewing code, diffs, artifacts, or prior findings, run each configured verification command yourself from the Worktree.
2367
- - Run the commands exactly as configured. Do not substitute narrower commands unless the configured command cannot run.
2368
- - If a configured command fails, keep reviewing after recording the failure details; use the failure output as review evidence.
2369
- - If a command cannot run because the environment is missing required setup, dependencies, or scripts outside agent control, treat it as a human handoff blocker.
2370
- - If no verification commands are configured, note that and proceed with normal review.
2542
+ ## Verification Handoff
2371
2543
 
2372
- ## Scope Evidence Rules
2544
+ - Run the verification wrapper listed in ${RUN_CONTEXT_PATH_IN_WORKTREE} after making changes.
2545
+ - If ${RUN_CONTEXT_PATH_IN_WORKTREE} provides a worktree-local CLI fallback, use that fallback before considering direct command execution.
2546
+ - Run underlying verification commands directly only when no wrapper path can run, and record why verification used direct commands in the Refactor Artifact.
2547
+ - If configured verification fails because of fixable Issue work, fix the work and rerun verification before handoff.
2548
+ - Failed or blocked verification prohibits <promise>COMPLETE</promise>.
2373
2549
 
2374
- - Use the Run Context's canonical base ref, for example \`origin/<base>\`, for scope diffs and commit ranges.
2375
- - Do not use bare PRD/base branch names such as \`PRD-0063\`, \`main\`, or \`dev\` for scope decisions; local branches with those names may be stale.
2376
- - Only call a file or commit out of scope when it is part of the working branch's delta from the canonical base ref.
2377
- - Do not recommend reverting accepted sibling/base work. If a file is present or changed on the canonical base ref, it is not this Issue's scope overreach.
2378
- - If scope evidence is ambiguous, use \`NEEDS_HUMAN\` or ask for a runner/base mismatch decision instead of telling Refactor to revert files.
2379
-
2380
- ${hasCriteriaPlaceholder ? "" : `## Review Criteria
2381
-
2382
- ${criteriaBlock}
2383
-
2384
- `}${humanHandoffBoundary}${priorReviewerBlock}${renderReviewHistory(reviewHistory)}${priorRefactorBlock}${priorRefactorProtocolReminder}## Output
2385
-
2386
- Write your review to: ${artifactPathInWorktree}
2550
+ ## Latest Review
2387
2551
 
2388
- Before handoff, run: pourkit validate-artifact reviewer ${artifactPathInWorktree} --iteration ${iteration}${priorRefactorArtifacts ? " --prior-refactor-artifacts" : ""}
2552
+ ${latestReview.trimEnd()}
2389
2553
 
2390
- Do not provide a separate chat response. The runner only reads the file above.
2554
+ ## Output
2391
2555
 
2392
- End the file with exactly one wrapped verdict token: <verdict>PASS</verdict>, <verdict>PASS_WITH_NOTES</verdict>, <verdict>NEEDS_REFACTOR</verdict>, <verdict>FAIL</verdict>, or <verdict>NEEDS_HUMAN</verdict>. The verdict token must appear exactly once in the output.
2556
+ Write your refactor artifact to: ${artifactPathInWorktree}
2393
2557
 
2394
- Findings must include an ID column with values in the format R${iteration}.F{findingNumber} (e.g., R${iteration}.F1, R${iteration}.F2) and a Supersedes column referencing the finding ID being superseded (or a hyphen for new findings).
2558
+ Before handoff, run: pourkit validate-artifact refactor ${artifactPathInWorktree} --iteration ${iteration}${findingArgs}
2395
2559
 
2396
- When verdict is NEEDS_HUMAN, include Human Handoff Summary and Human Handoff Reason sections before the final verdict token.`);
2560
+ When you are done, finish with <promise>COMPLETE</promise>.`);
2397
2561
  });
2398
2562
  }
2399
- function renderReviewHistory(reviewHistory) {
2400
- if (reviewHistory.length === 0) {
2401
- return "";
2402
- }
2403
- return `## Review History
2404
-
2405
- ${reviewHistory.map((entry, index) => `### Iteration ${index + 1}
2406
-
2407
- ${entry.trimEnd()}`).join("\n\n")}
2408
-
2409
- `;
2410
- }
2411
2563
  function renderPriorRefactorArtifactsEffect(worktreePath, currentIteration) {
2412
2564
  return Effect2.gen(function* () {
2413
2565
  const fb = yield* FileSystem;
@@ -2468,78 +2620,54 @@ ${iterationsBlocks}
2468
2620
  `;
2469
2621
  });
2470
2622
  }
2471
- function loadReviewerPromptTemplateEffect(repoRoot2, promptTemplate, criteriaBlock, fs) {
2472
- return Effect2.gen(function* () {
2473
- const promptTemplatePath = resolvePromptTemplatePath(
2474
- repoRoot2,
2475
- promptTemplate
2476
- );
2477
- const exists = yield* fs.exists(promptTemplatePath).pipe(Effect2.orDie);
2478
- const promptBody = exists ? yield* fs.readFile(promptTemplatePath).pipe(Effect2.orDie) : promptTemplate;
2479
- const hasCriteriaPlaceholder = promptBody.includes("{{REVIEW_CRITERIA}}");
2480
- return {
2481
- content: promptBody.replace(/\{\{REVIEW_CRITERIA\}\}/g, criteriaBlock),
2482
- hasCriteriaPlaceholder
2483
- };
2484
- });
2485
- }
2486
- function renderReviewCriteriaEffect(repoRoot2, criteria, fs) {
2623
+ function persistIterationArtifactEffect(worktreePath, output, iteration, fs) {
2487
2624
  return Effect2.gen(function* () {
2488
- const parts = [];
2489
- for (const criterion of criteria) {
2490
- const snippetPath = join6(
2491
- repoRoot2,
2492
- ".pourkit",
2493
- "managed",
2494
- "prompts",
2495
- `reviewer-${criterion}.snippet.md`
2496
- );
2497
- const exists = yield* fs.exists(snippetPath).pipe(Effect2.orDie);
2498
- if (exists) {
2499
- const content = yield* fs.readFile(snippetPath).pipe(Effect2.orDie);
2500
- parts.push(content.trimEnd());
2501
- } else {
2502
- parts.push(`- ${criterion}`);
2503
- }
2504
- }
2505
- return parts.join("\n\n");
2625
+ const dir = join6(worktreePath, ".pourkit", ".tmp", "reviewers");
2626
+ yield* fs.mkdir(dir).pipe(Effect2.catchAll(() => Effect2.void));
2627
+ yield* fs.writeFile(join6(dir, `iteration-${iteration}.md`), output).pipe(Effect2.catchAll(() => Effect2.void));
2506
2628
  });
2507
2629
  }
2508
- function recoverReviewOutputFromString(logContent) {
2509
- const startIndex = logContent.indexOf("## Findings");
2510
- if (startIndex === -1) return null;
2511
- const verdictMatch = logContent.slice(startIndex).match(
2512
- /<verdict>(PASS|PASS_WITH_NOTES|NEEDS_REFACTOR|FAIL|NEEDS_HUMAN)<\/verdict>/
2513
- );
2514
- if (!verdictMatch || verdictMatch.index === void 0) return null;
2515
- const recoveredOutput = logContent.slice(startIndex, startIndex + verdictMatch.index + verdictMatch[0].length).trim();
2516
- return recoveredOutput.length > 0 ? recoveredOutput : null;
2517
- }
2518
- function recoverReviewOutputFromLog(logPath) {
2519
- if (!existsSync6(logPath)) {
2520
- return null;
2521
- }
2522
- const logContent = readFileSync6(logPath, "utf-8");
2523
- return recoverReviewOutputFromString(logContent);
2524
- }
2525
- function readReviewArtifact(artifactPath, logPath) {
2526
- if (existsSync6(artifactPath)) {
2527
- const output = readFileSync6(artifactPath, "utf-8");
2528
- if (output.trim()) {
2529
- return output;
2530
- }
2630
+ function mapResult(result) {
2631
+ const base = {
2632
+ output: result.output,
2633
+ iterations: result.iterations,
2634
+ lifetimeIterations: result.lifetimeIterations,
2635
+ refactorCompletedForLastReview: result.refactorCompletedForLastReview,
2636
+ refactorArtifactPaths: result.refactorArtifactPaths
2637
+ };
2638
+ if (result.exhaustedMaxIterations) {
2639
+ return {
2640
+ status: "exhausted_max_iterations",
2641
+ reviewVerdict: result.verdict === "FAIL" ? "FAIL" : "NEEDS_REFACTOR",
2642
+ reviewArtifactPath: result.artifactPath,
2643
+ ...base,
2644
+ reason: "max_iterations"
2645
+ };
2531
2646
  }
2532
- const recoveredOutput = logPath ? recoverReviewOutputFromLog(logPath) : null;
2533
- if (recoveredOutput) {
2534
- writeFileSync3(artifactPath, recoveredOutput, "utf-8");
2535
- return recoveredOutput;
2647
+ if (result.verdict === "NEEDS_HUMAN") {
2648
+ return {
2649
+ status: "needs_human",
2650
+ reviewVerdict: "NEEDS_HUMAN",
2651
+ reviewArtifactPath: result.artifactPath,
2652
+ ...base
2653
+ };
2536
2654
  }
2537
- if (!existsSync6(artifactPath)) {
2538
- throw new Error(`Reviewer did not produce output at ${artifactPath}`);
2655
+ if (result.verdict === "FAIL") {
2656
+ return {
2657
+ status: "needs_human",
2658
+ reviewVerdict: "NEEDS_HUMAN",
2659
+ reviewArtifactPath: result.artifactPath,
2660
+ ...base
2661
+ };
2539
2662
  }
2540
- throw new Error(`Reviewer produced empty output at ${artifactPath}`);
2663
+ return {
2664
+ status: "passed",
2665
+ reviewVerdict: result.verdict,
2666
+ reviewArtifactPath: result.artifactPath,
2667
+ ...base
2668
+ };
2541
2669
  }
2542
- function runReviewWithRefactorLoop(options) {
2670
+ function runIssueReviewLoop(options) {
2543
2671
  const {
2544
2672
  executionProvider,
2545
2673
  config,
@@ -2565,7 +2693,6 @@ function runReviewWithRefactorLoop(options) {
2565
2693
  return Effect2.die(new Error("No refactorer config found"));
2566
2694
  }
2567
2695
  const maxIterations = strategy.review.maxIterations;
2568
- const passWithNotesRefactorAttempts = strategy.review.passWithNotesRefactorAttempts;
2569
2696
  let resolvedStartingIteration = startingLifetimeIteration;
2570
2697
  {
2571
2698
  const reviewersDir = join6(worktreePath, ".pourkit", ".tmp", "reviewers");
@@ -2598,7 +2725,6 @@ function runReviewWithRefactorLoop(options) {
2598
2725
  iteration: 0,
2599
2726
  lastResult: null,
2600
2727
  reviewHistory: [],
2601
- passWithNotesRefactorAttemptsRemaining: passWithNotesRefactorAttempts,
2602
2728
  accumulatedRefactorPaths: [],
2603
2729
  doneResult: null
2604
2730
  };
@@ -2654,11 +2780,7 @@ function runReviewWithRefactorLoop(options) {
2654
2780
  }
2655
2781
  };
2656
2782
  }
2657
- if (reviewResult.verdict === "PASS_WITH_NOTES" && s.passWithNotesRefactorAttemptsRemaining === 0) {
2658
- logger.step(
2659
- "info",
2660
- "PASS_WITH_NOTES refactor attempts exhausted, treating as PASS"
2661
- );
2783
+ if (reviewResult.verdict === "PASS_WITH_NOTES") {
2662
2784
  return {
2663
2785
  ...s,
2664
2786
  done: true,
@@ -2666,7 +2788,7 @@ function runReviewWithRefactorLoop(options) {
2666
2788
  lastResult: reviewResult,
2667
2789
  reviewHistory: updatedHistory,
2668
2790
  doneResult: {
2669
- verdict: "PASS",
2791
+ verdict: reviewResult.verdict,
2670
2792
  output: reviewResult.output,
2671
2793
  artifactPath: reviewResult.artifactPath,
2672
2794
  iterations: iteration,
@@ -2677,14 +2799,6 @@ function runReviewWithRefactorLoop(options) {
2677
2799
  }
2678
2800
  };
2679
2801
  }
2680
- let updatedPassWithNotesRefactorAttemptsRemaining = s.passWithNotesRefactorAttemptsRemaining;
2681
- if (reviewResult.verdict === "PASS_WITH_NOTES") {
2682
- updatedPassWithNotesRefactorAttemptsRemaining--;
2683
- logger.step(
2684
- "info",
2685
- `PASS_WITH_NOTES refactor attempts remaining: ${updatedPassWithNotesRefactorAttemptsRemaining}`
2686
- );
2687
- }
2688
2802
  if (reviewResult.verdict === "NEEDS_HUMAN") {
2689
2803
  logger.step("info", "NEEDS_HUMAN verdict, stopping review loop");
2690
2804
  return {
@@ -2705,7 +2819,7 @@ function runReviewWithRefactorLoop(options) {
2705
2819
  }
2706
2820
  };
2707
2821
  }
2708
- if (reviewResult.verdict === "NEEDS_REFACTOR" || reviewResult.verdict === "PASS_WITH_NOTES" || reviewResult.verdict === "FAIL") {
2822
+ if (reviewResult.verdict === "NEEDS_REFACTOR" || reviewResult.verdict === "FAIL") {
2709
2823
  logger.step("info", "Running refactor agent");
2710
2824
  const refactorArtifactPathInWorktree = join6(
2711
2825
  ".pourkit",
@@ -2861,7 +2975,6 @@ function runReviewWithRefactorLoop(options) {
2861
2975
  iteration,
2862
2976
  lastResult: reviewResult,
2863
2977
  reviewHistory: updatedHistory,
2864
- passWithNotesRefactorAttemptsRemaining: updatedPassWithNotesRefactorAttemptsRemaining,
2865
2978
  accumulatedRefactorPaths: updatedAccumulated,
2866
2979
  doneResult: null
2867
2980
  };
@@ -2871,7 +2984,6 @@ function runReviewWithRefactorLoop(options) {
2871
2984
  iteration,
2872
2985
  lastResult: reviewResult,
2873
2986
  reviewHistory: updatedHistory,
2874
- passWithNotesRefactorAttemptsRemaining: updatedPassWithNotesRefactorAttemptsRemaining,
2875
2987
  accumulatedRefactorPaths: s.accumulatedRefactorPaths,
2876
2988
  doneResult: null
2877
2989
  };
@@ -2882,7 +2994,7 @@ function runReviewWithRefactorLoop(options) {
2882
2994
  }
2883
2995
  logger.step("warn", `Max review iterations (${maxIterations}) exhausted`);
2884
2996
  return {
2885
- verdict: "FAIL",
2997
+ verdict: finalState.lastResult?.verdict ?? "FAIL",
2886
2998
  output: finalState.lastResult?.output ?? "",
2887
2999
  artifactPath: finalState.lastResult?.artifactPath ?? "",
2888
3000
  iterations: finalState.iteration,
@@ -2894,45 +3006,10 @@ function runReviewWithRefactorLoop(options) {
2894
3006
  });
2895
3007
  const executionLayer = bridgeExecutionProvider(executionProvider);
2896
3008
  return program.pipe(
2897
- Effect2.provide(Layer2.merge(executionLayer, FileSystemDefault))
3009
+ Effect2.provide(Layer2.merge(executionLayer, FileSystemDefault)),
3010
+ Effect2.map(mapResult)
2898
3011
  );
2899
3012
  }
2900
- function persistIterationArtifactEffect(worktreePath, output, iteration, fs) {
2901
- return Effect2.gen(function* () {
2902
- const dir = join6(worktreePath, ".pourkit", ".tmp", "reviewers");
2903
- yield* fs.mkdir(dir).pipe(Effect2.catchAll(() => Effect2.void));
2904
- yield* fs.writeFile(join6(dir, `iteration-${iteration}.md`), output).pipe(Effect2.catchAll(() => Effect2.void));
2905
- });
2906
- }
2907
- function buildRefactorPromptEffect(repoRoot2, promptTemplate, latestReview, artifactPathInWorktree, iteration, fs) {
2908
- return Effect2.gen(function* () {
2909
- const promptTemplatePath = resolvePromptTemplatePath(
2910
- repoRoot2,
2911
- promptTemplate
2912
- );
2913
- const exists = yield* fs.exists(promptTemplatePath).pipe(Effect2.orDie);
2914
- const promptBody = exists ? yield* fs.readFile(promptTemplatePath).pipe(Effect2.orDie) : promptTemplate;
2915
- const findingIds = extractLatestFindingIds(latestReview, iteration);
2916
- const findingArgs = findingIds.map((id) => ` --finding-id ${id}`).join("");
2917
- return appendProtectedWorkGuidance(`${promptBody}
2918
-
2919
- ## Shared Run Context
2920
-
2921
- Read the selected issue requirements, planning context (including plan and PRD content when present), branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}
2922
-
2923
- ## Latest Review
2924
-
2925
- ${latestReview.trimEnd()}
2926
-
2927
- ## Output
2928
-
2929
- Write your refactor artifact to: ${artifactPathInWorktree}
2930
-
2931
- Before handoff, run: pourkit validate-artifact refactor ${artifactPathInWorktree} --iteration ${iteration}${findingArgs}
2932
-
2933
- When you are done, finish with <promise>COMPLETE</promise>.`);
2934
- });
2935
- }
2936
3013
 
2937
3014
  // pr/pr-description.ts
2938
3015
  var CONVENTIONAL_TITLE_PATTERN = /^(feat|fix|perf|refactor|docs|test|chore|ci|build)(\([^)]+\))?!?:\s+\S/;
@@ -3183,6 +3260,12 @@ var ISSUE_FINAL_REVIEW_SCOPE_VERDICTS = [
3183
3260
  "incidental",
3184
3261
  "out-of-scope"
3185
3262
  ];
3263
+ var ISSUE_FINAL_REVIEW_VERIFICATION_METHODS = [
3264
+ "wrapper",
3265
+ "local-wrapper",
3266
+ "commands",
3267
+ "none"
3268
+ ];
3186
3269
  function invalid(options, reason, diagnostics = []) {
3187
3270
  return {
3188
3271
  ok: false,
@@ -3490,6 +3573,15 @@ function validateIssueFinalReviewArtifact(parsed, options) {
3490
3573
  diagnostics
3491
3574
  };
3492
3575
  }
3576
+ if ("method" in verification && !ISSUE_FINAL_REVIEW_VERIFICATION_METHODS.includes(
3577
+ verification.method
3578
+ )) {
3579
+ return {
3580
+ ok: false,
3581
+ reason: 'verification.method must be "wrapper", "local-wrapper", "commands", or "none"',
3582
+ diagnostics
3583
+ };
3584
+ }
3493
3585
  diagnostics.push("verification: present");
3494
3586
  const verificationWasRecorded = verification.required === true || Array.isArray(verification.commands) && verification.commands.length > 0;
3495
3587
  if (parsed.verdict === "pass" && verificationWasRecorded) {
@@ -3504,6 +3596,20 @@ function validateIssueFinalReviewArtifact(parsed, options) {
3504
3596
  ]
3505
3597
  };
3506
3598
  }
3599
+ if (typeof verification.method !== "string") {
3600
+ return {
3601
+ ok: false,
3602
+ reason: "Issue Final Review pass with verification evidence requires verification.method",
3603
+ diagnostics
3604
+ };
3605
+ }
3606
+ if (verification.method === "none") {
3607
+ return {
3608
+ ok: false,
3609
+ reason: 'Issue Final Review pass with verification evidence requires verification.method other than "none"',
3610
+ diagnostics
3611
+ };
3612
+ }
3507
3613
  diagnostics.push("pass verification: valid");
3508
3614
  }
3509
3615
  if (parsed.selfRetouched === true && parsed.verdict === "pass") {
@@ -3708,10 +3814,10 @@ init_common();
3708
3814
  import { Exit as Exit3 } from "effect";
3709
3815
 
3710
3816
  // failure-resolution/effect-runtime.ts
3711
- import { Effect as Effect4 } from "effect";
3817
+ import { Effect as Effect5 } from "effect";
3712
3818
 
3713
3819
  // shared/effect-runtime.ts
3714
- import { Effect as Effect3, Exit } from "effect";
3820
+ import { Effect as Effect4, Exit } from "effect";
3715
3821
  import { UnknownException } from "effect/Cause";
3716
3822
  var initialized = false;
3717
3823
  function initializeEffectRuntime() {
@@ -3720,7 +3826,7 @@ function initializeEffectRuntime() {
3720
3826
  }
3721
3827
  function runEffect(program) {
3722
3828
  ensureEffectRuntime();
3723
- return Effect3.runPromiseExit(program);
3829
+ return Effect4.runPromiseExit(program);
3724
3830
  }
3725
3831
  function ensureEffectRuntime() {
3726
3832
  if (!initialized) {
@@ -3898,23 +4004,23 @@ function recordStageAttempt(worktreePath, record) {
3898
4004
 
3899
4005
  // failure-resolution/effect-runtime.ts
3900
4006
  function baseRefreshEffect(options) {
3901
- return Effect4.promise(() => refreshStaleIssueBranch(options)).pipe(
3902
- Effect4.flatMap(
4007
+ return Effect5.promise(() => refreshStaleIssueBranch(options)).pipe(
4008
+ Effect5.flatMap(
3903
4009
  (result) => {
3904
4010
  switch (result.status) {
3905
4011
  case "refreshed":
3906
- return Effect4.succeed({ status: "refreshed" });
4012
+ return Effect5.succeed({ status: "refreshed" });
3907
4013
  case "skipped-current":
3908
- return Effect4.succeed({ status: "skipped-current" });
4014
+ return Effect5.succeed({ status: "skipped-current" });
3909
4015
  case "conflicted":
3910
- return Effect4.fail(
4016
+ return Effect5.fail(
3911
4017
  new RebaseConflict({
3912
4018
  conflictedPaths: result.conflictedPaths,
3913
4019
  message: result.message
3914
4020
  })
3915
4021
  );
3916
4022
  case "refused-published-history":
3917
- return Effect4.fail(
4023
+ return Effect5.fail(
3918
4024
  new PublishedHistoryRisk({
3919
4025
  prNumber: result.prNumber,
3920
4026
  prState: result.prState
@@ -3929,8 +4035,8 @@ async function runBaseRefreshAttempt(options) {
3929
4035
  const attemptId = createStageAttemptId();
3930
4036
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3931
4037
  const program = baseRefreshEffect(options).pipe(
3932
- Effect4.tapBoth({
3933
- onSuccess: (success) => Effect4.sync(() => {
4038
+ Effect5.tapBoth({
4039
+ onSuccess: (success) => Effect5.sync(() => {
3934
4040
  recordStageAttempt(options.worktreePath, {
3935
4041
  id: attemptId,
3936
4042
  stage: "baseRefresh",
@@ -3939,7 +4045,7 @@ async function runBaseRefreshAttempt(options) {
3939
4045
  outcome: "success"
3940
4046
  });
3941
4047
  }),
3942
- onFailure: (failure) => Effect4.sync(() => {
4048
+ onFailure: (failure) => Effect5.sync(() => {
3943
4049
  recordStageAttempt(options.worktreePath, {
3944
4050
  id: attemptId,
3945
4051
  stage: "baseRefresh",
@@ -4862,7 +4968,15 @@ function loadBuilderPrompt(repoRoot2, promptTemplate) {
4862
4968
 
4863
4969
  ## Shared Run Context
4864
4970
 
4865
- Read the selected issue requirements, planning context (including plan and PRD content when present), comments, branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}`);
4971
+ Read the selected issue requirements, planning context (including plan and PRD content when present), comments, branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}
4972
+
4973
+ ## Verification Handoff
4974
+
4975
+ - Run the verification wrapper listed in ${RUN_CONTEXT_PATH_IN_WORKTREE}.
4976
+ - If ${RUN_CONTEXT_PATH_IN_WORKTREE} provides a worktree-local CLI fallback, use that fallback before considering direct command execution.
4977
+ - Run underlying verification commands directly only when no wrapper path can run, and report why verification used direct commands.
4978
+ - If configured verification fails because of fixable Issue work, fix the work and rerun verification before handoff.
4979
+ - Failed or blocked verification prohibits <promise>COMPLETE</promise>.`);
4866
4980
  }
4867
4981
  async function syncRemoteBaseRef(worktreePath, baseRef, logger) {
4868
4982
  const remoteBase = parseRemoteBaseRef(baseRef);
@@ -4907,9 +5021,9 @@ import { readFileSync as readFileSync12 } from "fs";
4907
5021
  init_common();
4908
5022
  import { join as join10 } from "path";
4909
5023
  import { readFile } from "fs/promises";
4910
- import { Effect as Effect5 } from "effect";
5024
+ import { Effect as Effect6 } from "effect";
4911
5025
  function collectFinalizerContextEffect(options) {
4912
- return Effect5.gen(function* () {
5026
+ return Effect6.gen(function* () {
4913
5027
  const git = yield* GitOperations;
4914
5028
  const fs = yield* FileSystem;
4915
5029
  const remoteBase = remoteTargetBase(options.targetBase);
@@ -4922,8 +5036,8 @@ function collectFinalizerContextEffect(options) {
4922
5036
  ],
4923
5037
  { cwd: options.worktreePath }
4924
5038
  ).pipe(
4925
- Effect5.catchAll(
4926
- (error) => Effect5.fail(
5039
+ Effect6.catchAll(
5040
+ (error) => Effect6.fail(
4927
5041
  new Error(`Failed to collect commit range: ${error.message}`)
4928
5042
  )
4929
5043
  )
@@ -4938,9 +5052,9 @@ function collectFinalizerContextEffect(options) {
4938
5052
  let reviewArtifact;
4939
5053
  if (options.reviewArtifactPath) {
4940
5054
  const content = yield* fs.readFile(options.reviewArtifactPath).pipe(
4941
- Effect5.catchIf(
5055
+ Effect6.catchIf(
4942
5056
  (error) => error.message.includes("ENOENT") || error.message.includes("no such file"),
4943
- () => Effect5.fail(
5057
+ () => Effect6.fail(
4944
5058
  new Error(
4945
5059
  `Review artifact not found at ${options.reviewArtifactPath}. Ensure the review stage completed before running finalizer generation.`
4946
5060
  )
@@ -4948,7 +5062,7 @@ function collectFinalizerContextEffect(options) {
4948
5062
  )
4949
5063
  );
4950
5064
  if (!content.trim()) {
4951
- return yield* Effect5.fail(
5065
+ return yield* Effect6.fail(
4952
5066
  new Error(
4953
5067
  `Review artifact at ${options.reviewArtifactPath} is empty. Ensure the review stage produced output before running finalizer generation.`
4954
5068
  )
@@ -5024,12 +5138,12 @@ Before handoff, run: pourkit validate-artifact finalizer ${artifactPathInWorktre
5024
5138
  }
5025
5139
 
5026
5140
  // commands/pr-description-agent.ts
5027
- import { Effect as Effect6, Layer as Layer3 } from "effect";
5141
+ import { Effect as Effect7, Layer as Layer3 } from "effect";
5028
5142
  function bridgeExecutionProvider2(ep) {
5029
5143
  return Layer3.succeed(
5030
5144
  ExecutionProvider,
5031
5145
  ExecutionProvider.of({
5032
- execute: (opts) => Effect6.tryPromise({
5146
+ execute: (opts) => Effect7.tryPromise({
5033
5147
  try: () => ep.execute(opts),
5034
5148
  catch: (e) => new Error(
5035
5149
  e instanceof Error ? e.message : `Execution failed: ${String(e)}`
@@ -5047,7 +5161,7 @@ function runFinalizerAgent(options) {
5047
5161
  "agent-output.md"
5048
5162
  );
5049
5163
  const artifactPath = join11(options.worktreePath, artifactPathInWorktree);
5050
- const program = Effect6.gen(function* () {
5164
+ const program = Effect7.gen(function* () {
5051
5165
  const fs = yield* FileSystem;
5052
5166
  const context = yield* collectFinalizerContextEffect({
5053
5167
  targetBase: options.targetBaseBranch,
@@ -5056,8 +5170,8 @@ function runFinalizerAgent(options) {
5056
5170
  reviewArtifactPath: options.reviewArtifactPath,
5057
5171
  logger: options.logger
5058
5172
  }).pipe(
5059
- Effect6.catchAll(
5060
- (error) => Effect6.fail(
5173
+ Effect7.catchAll(
5174
+ (error) => Effect7.fail(
5061
5175
  new FinalizerFailure({
5062
5176
  message: `Failed to collect finalizer context: ${error.message}`
5063
5177
  })
@@ -5102,7 +5216,7 @@ function runFinalizerAgent(options) {
5102
5216
  });
5103
5217
  const executionLayer = bridgeExecutionProvider2(executionProvider);
5104
5218
  return program.pipe(
5105
- Effect6.provide(
5219
+ Effect7.provide(
5106
5220
  Layer3.mergeAll(executionLayer, FileSystemDefault, GitOperationsDefault)
5107
5221
  )
5108
5222
  );
@@ -5112,11 +5226,11 @@ function runPrDescriptionFinalizerCore(options) {
5112
5226
  options.worktreePath,
5113
5227
  options.artifactPathInWorktree
5114
5228
  );
5115
- return Effect6.gen(function* () {
5229
+ return Effect7.gen(function* () {
5116
5230
  let parsed;
5117
5231
  let lastValidationError;
5118
5232
  for (let protocolAttempt = 1; protocolAttempt <= options.maxAttempts; protocolAttempt++) {
5119
- const retryResult = yield* Effect6.tryPromise({
5233
+ const retryResult = yield* Effect7.tryPromise({
5120
5234
  try: () => executeWithMissingOrEmptyArtifactRetry({
5121
5235
  executionProvider: options.executionProvider,
5122
5236
  missingOrEmptyRetries: resolveMissingOrEmptyOutputRetries(
@@ -5153,7 +5267,7 @@ function runPrDescriptionFinalizerCore(options) {
5153
5267
  });
5154
5268
  const executionResult = retryResult.executionResult;
5155
5269
  if (!executionResult.success) {
5156
- return yield* Effect6.fail(
5270
+ return yield* Effect7.fail(
5157
5271
  new FinalizerFailure({
5158
5272
  message: `Finalizer agent execution failed: ${executionResult.error}`
5159
5273
  })
@@ -5191,7 +5305,7 @@ function runPrDescriptionFinalizerCore(options) {
5191
5305
  }
5192
5306
  }
5193
5307
  if (!parsed) {
5194
- return yield* Effect6.fail(
5308
+ return yield* Effect7.fail(
5195
5309
  new FinalizerFailure({
5196
5310
  message: lastValidationError?.message ?? "Finalizer validation failed"
5197
5311
  })
@@ -5206,20 +5320,20 @@ function runPrDescriptionFinalizerCore(options) {
5206
5320
  });
5207
5321
  }
5208
5322
  function loadFinalizerPromptEffect(repoRoot2, promptTemplate, fs) {
5209
- return Effect6.gen(function* () {
5323
+ return Effect7.gen(function* () {
5210
5324
  const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
5211
- const exists = yield* fs.exists(promptPath).pipe(Effect6.orDie);
5325
+ const exists = yield* fs.exists(promptPath).pipe(Effect7.orDie);
5212
5326
  if (exists) {
5213
- return yield* fs.readFile(promptPath).pipe(Effect6.orDie);
5327
+ return yield* fs.readFile(promptPath).pipe(Effect7.orDie);
5214
5328
  }
5215
5329
  return promptTemplate;
5216
5330
  });
5217
5331
  }
5218
5332
  function persistGeneratedArtifactEffect(worktreePath, output, fs) {
5219
- return Effect6.gen(function* () {
5333
+ return Effect7.gen(function* () {
5220
5334
  const dir = join11(worktreePath, ".pourkit", ".tmp", "finalizer");
5221
- yield* fs.mkdir(dir).pipe(Effect6.catchAll(() => Effect6.void));
5222
- yield* fs.writeFile(join11(dir, "generated.md"), output).pipe(Effect6.catchAll(() => Effect6.void));
5335
+ yield* fs.mkdir(dir).pipe(Effect7.catchAll(() => Effect7.void));
5336
+ yield* fs.writeFile(join11(dir, "generated.md"), output).pipe(Effect7.catchAll(() => Effect7.void));
5223
5337
  });
5224
5338
  }
5225
5339
 
@@ -5559,7 +5673,7 @@ function secondsRemaining(deadline, observedAt) {
5559
5673
  }
5560
5674
 
5561
5675
  // issues/merge-coordinator.ts
5562
- import { Effect as Effect7, Either } from "effect";
5676
+ import { Effect as Effect8, Either } from "effect";
5563
5677
  import { UnknownException as UnknownException2 } from "effect/Cause";
5564
5678
  function unwrapError2(error) {
5565
5679
  if (error instanceof UnknownException2 && error.error !== void 0) {
@@ -5578,9 +5692,9 @@ function runMergeCoordinator(options) {
5578
5692
  } = options;
5579
5693
  const method = options.method ?? "squash";
5580
5694
  const waitForTargetGreen = options.waitForTargetGreen ?? true;
5581
- return Effect7.gen(function* () {
5582
- const checksEither = yield* Effect7.either(
5583
- Effect7.tryPromise(
5695
+ return Effect8.gen(function* () {
5696
+ const checksEither = yield* Effect8.either(
5697
+ Effect8.tryPromise(
5584
5698
  () => prProvider.waitForPrChecks(prNumber, checkWaitOptions)
5585
5699
  )
5586
5700
  );
@@ -5593,8 +5707,8 @@ function runMergeCoordinator(options) {
5593
5707
  error: error instanceof Error ? error : new Error(String(error))
5594
5708
  };
5595
5709
  }
5596
- const mergeEither = yield* Effect7.either(
5597
- Effect7.tryPromise(
5710
+ const mergeEither = yield* Effect8.either(
5711
+ Effect8.tryPromise(
5598
5712
  () => prProvider.mergePr(prNumber, { method, matchHeadCommit })
5599
5713
  )
5600
5714
  );
@@ -5608,8 +5722,8 @@ function runMergeCoordinator(options) {
5608
5722
  };
5609
5723
  }
5610
5724
  if (waitForTargetGreen) {
5611
- const targetEither = yield* Effect7.either(
5612
- Effect7.tryPromise(
5725
+ const targetEither = yield* Effect8.either(
5726
+ Effect8.tryPromise(
5613
5727
  () => waitForBranchChecks(prProvider, logger, {
5614
5728
  branchName: targetBranch,
5615
5729
  checksFoundTimeoutMs: checkWaitOptions.checksFoundTimeoutMs,
@@ -5808,6 +5922,9 @@ function buildIssueFinalReviewPrComment(artifact) {
5808
5922
  `- **Required:** ${formatBoolean(artifact.verification.required)}`,
5809
5923
  `- **Passed:** ${formatBoolean(artifact.verification.passed)}`
5810
5924
  );
5925
+ if (typeof artifact.verification.method === "string") {
5926
+ lines.push(`- **Method:** ${formatLabel(artifact.verification.method)}`);
5927
+ }
5811
5928
  const commands = Array.isArray(artifact.verification.commands) ? artifact.verification.commands.filter(
5812
5929
  (command) => typeof command === "string"
5813
5930
  ) : [];
@@ -6005,7 +6122,7 @@ function findSecretLikeContent(source, content) {
6005
6122
  ];
6006
6123
  for (const { kind, regex } of patterns) {
6007
6124
  for (const match of content.matchAll(regex)) {
6008
- if (isAllowedSecretPlaceholder(match[0])) {
6125
+ if (isAllowedSecretPlaceholder(match[0]) || isAllowedDocumentationTokenReference(match[0])) {
6009
6126
  continue;
6010
6127
  }
6011
6128
  findings.push({ source, kind });
@@ -6026,6 +6143,9 @@ function isAllowedSecretPlaceholder(value) {
6026
6143
  "xxxxx"
6027
6144
  ].some((allowed) => normalized.includes(allowed));
6028
6145
  }
6146
+ function isAllowedDocumentationTokenReference(value) {
6147
+ return /^token\s*:\s*["']?<verdict>/i.test(value);
6148
+ }
6029
6149
 
6030
6150
  // commands/issue-final-review-agent.ts
6031
6151
  import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
@@ -6055,7 +6175,9 @@ async function runIssueFinalReviewAgent(options) {
6055
6175
  const prompt = loadIssueFinalReviewPrompt({
6056
6176
  repoRoot: repoRoot2,
6057
6177
  promptTemplate: agent.promptTemplate,
6058
- validationCommand: `pourkit validate-artifact issue-final-review ${artifactPathInWorktree} --issue-number ${issue.number} --branch-name ${builderBranch} --base-ref origin/${target.baseBranch}`
6178
+ validationCommand: `pourkit validate-artifact issue-final-review ${artifactPathInWorktree} --issue-number ${issue.number} --branch-name ${builderBranch} --base-ref origin/${target.baseBranch}`,
6179
+ reviewArtifactPath: options.reviewArtifactPath,
6180
+ reviewVerdict: options.reviewVerdict
6059
6181
  });
6060
6182
  const entry = await executeWithMissingOrEmptyArtifactRetry({
6061
6183
  executionProvider,
@@ -6151,10 +6273,16 @@ function extractChangedPaths(parsed) {
6151
6273
  ).filter((path9) => typeof path9 === "string") : [];
6152
6274
  }
6153
6275
  function loadIssueFinalReviewPrompt(options) {
6154
- const { repoRoot: repoRoot2, promptTemplate, validationCommand } = options;
6276
+ const {
6277
+ repoRoot: repoRoot2,
6278
+ promptTemplate,
6279
+ validationCommand,
6280
+ reviewArtifactPath,
6281
+ reviewVerdict
6282
+ } = options;
6155
6283
  const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
6156
6284
  const promptBody = existsSync12(promptPath) ? readFileSync14(promptPath, "utf-8") : promptTemplate;
6157
- return appendProtectedWorkGuidance(`${promptBody}
6285
+ let prompt = appendProtectedWorkGuidance(`${promptBody}
6158
6286
 
6159
6287
  ## Shared Run Context
6160
6288
 
@@ -6163,8 +6291,10 @@ Read the selected issue requirements, planning context (including plan and PRD c
6163
6291
  ## Initial Verification Pass
6164
6292
 
6165
6293
  - First read ${RUN_CONTEXT_PATH_IN_WORKTREE} only far enough to identify the configured verification commands.
6166
- - Before reviewing code, diffs, artifacts, or prior findings, run each configured verification command yourself from the Worktree.
6167
- - Run the commands exactly as configured. Do not substitute narrower commands unless the configured command cannot run.
6294
+ - Before reviewing code, diffs, artifacts, or prior findings, run the verification wrapper from the Worktree.
6295
+ - If the installed Pourkit CLI rejects the worktree config schemaVersion and the Run Context provides a Pourkit self-development fallback, build and run the worktree-local CLI wrapper exactly as instructed.
6296
+ - Do not substitute direct underlying commands unless neither wrapper path can run; if you must use direct commands, record degraded verification with \`verification.method: "commands"\` and explain why in \`verification.summary\`.
6297
+ - Record successful wrapper verification with \`verification.method: "wrapper"\`, or worktree-local CLI wrapper verification with \`verification.method: "local-wrapper"\`.
6168
6298
  - If a configured verification command fails because of fixable Issue work, self-retouch the Worktree, then rerun all configured verification commands.
6169
6299
  - Do not return \`pass\` while any configured verification command is failing.
6170
6300
  - If a command cannot run because the environment is missing required setup, dependencies, or scripts outside agent control, treat it as a human handoff blocker.
@@ -6186,6 +6316,19 @@ Read the selected issue requirements, planning context (including plan and PRD c
6186
6316
  - This validation checks both the artifact shape and \`changedFiles\` coverage against the canonical Git diff.
6187
6317
  - If validation fails, fix the artifact or safely retouch the worktree as needed, then rerun the same command.
6188
6318
  - Do not finish until the validation command passes.`);
6319
+ if (reviewVerdict) {
6320
+ prompt += `
6321
+
6322
+ ## Prior Review Context
6323
+
6324
+ - Reviewer Artifact Path: ${reviewArtifactPath}
6325
+ - Prior Review Verdict: ${reviewVerdict}`;
6326
+ if (reviewVerdict === "PASS_WITH_NOTES") {
6327
+ prompt += `
6328
+ - This Issue passed the prior Reviewer with notes. Read the Reviewer Artifact and inspect its notes before making your final pass decision.`;
6329
+ }
6330
+ }
6331
+ return prompt;
6189
6332
  }
6190
6333
 
6191
6334
  // issues/issue-worktree-resolution.ts
@@ -6375,6 +6518,7 @@ async function advanceIssueFinalReview(options) {
6375
6518
  repoRoot: repoRoot2,
6376
6519
  logger,
6377
6520
  reviewArtifactPath,
6521
+ reviewVerdict,
6378
6522
  worktreeState
6379
6523
  } = options;
6380
6524
  const ifrFromState = worktreeState?.issueFinalReview;
@@ -6415,6 +6559,7 @@ async function advanceIssueFinalReview(options) {
6415
6559
  repoRoot: repoRoot2,
6416
6560
  logger,
6417
6561
  reviewArtifactPath,
6562
+ reviewVerdict,
6418
6563
  ...options.memory ? { memory: options.memory } : {}
6419
6564
  });
6420
6565
  await assertCanonicalBaseAncestor2({
@@ -6580,7 +6725,7 @@ async function fetchParentPrdIssue(issue, issueProvider) {
6580
6725
  async function advanceIssueRunReview(options) {
6581
6726
  const accumulatedRefactorPaths = [];
6582
6727
  const reviewResult = await runEffectAndMapExit(
6583
- runReviewWithRefactorLoop({
6728
+ runIssueReviewLoop({
6584
6729
  ...options,
6585
6730
  onRefactorProgress: (progress) => {
6586
6731
  if (progress.refactorArtifactPath) {
@@ -6603,16 +6748,29 @@ async function advanceIssueRunReview(options) {
6603
6748
  stageName: "Review/Refactor",
6604
6749
  logger: options.logger
6605
6750
  });
6606
- updateWorktreeRunState(options.worktreePath, {
6607
- review: {
6608
- lifetimeIterations: reviewResult.lifetimeIterations,
6609
- lastVerdict: reviewResult.verdict,
6610
- lastArtifactPath: reviewResult.artifactPath,
6611
- refactorCompletedForLastReview: reviewResult.refactorCompletedForLastReview,
6612
- exhaustedPreviousRun: reviewResult.exhaustedMaxIterations || reviewResult.verdict === "FAIL" || void 0,
6613
- refactorArtifactPaths: accumulatedRefactorPaths.length > 0 ? accumulatedRefactorPaths : void 0
6614
- }
6615
- });
6751
+ const commonFields = {
6752
+ lifetimeIterations: reviewResult.lifetimeIterations,
6753
+ lastArtifactPath: reviewResult.reviewArtifactPath,
6754
+ refactorCompletedForLastReview: reviewResult.refactorCompletedForLastReview,
6755
+ refactorArtifactPaths: accumulatedRefactorPaths.length > 0 ? accumulatedRefactorPaths : void 0
6756
+ };
6757
+ if (reviewResult.status === "passed" || reviewResult.status === "needs_human") {
6758
+ updateWorktreeRunState(options.worktreePath, {
6759
+ review: {
6760
+ ...commonFields,
6761
+ lastVerdict: reviewResult.reviewVerdict,
6762
+ exhaustedPreviousRun: void 0
6763
+ }
6764
+ });
6765
+ } else {
6766
+ updateWorktreeRunState(options.worktreePath, {
6767
+ review: {
6768
+ ...commonFields,
6769
+ lastVerdict: reviewResult.reviewVerdict,
6770
+ exhaustedPreviousRun: true
6771
+ }
6772
+ });
6773
+ }
6616
6774
  return reviewResult;
6617
6775
  }
6618
6776
  async function completeIssueRun(options) {
@@ -6810,14 +6968,14 @@ async function transitionIssueToHumanHandoff(options) {
6810
6968
  const transitions = makeIssueTransitions2(issueProvider, config);
6811
6969
  await transitions.moveToReadyForHuman(issueNumber);
6812
6970
  const summary = extractHumanHandoffSummary(reviewResult.output);
6813
- const refactorDir = getRefactorArtifactDir(reviewResult.artifactPath);
6971
+ const refactorDir = getRefactorArtifactDir(reviewResult.reviewArtifactPath);
6814
6972
  const comment = [
6815
6973
  "Pourkit stopped the review/refactor loop because human input is needed.",
6816
6974
  "",
6817
6975
  summary,
6818
6976
  "",
6819
6977
  "Artifacts:",
6820
- `- Review: ${reviewResult.artifactPath}`,
6978
+ `- Review: ${reviewResult.reviewArtifactPath}`,
6821
6979
  `- Refactors: ${refactorDir}`
6822
6980
  ].join("\n");
6823
6981
  await issueProvider.commentIssue(issueNumber, comment);
@@ -7035,8 +7193,10 @@ async function runIssueLifecycle(options) {
7035
7193
  const startResult = await options.deps.startIssueRun(options.runOptions);
7036
7194
  const reviewAlreadyPassed = startResult.worktreeState?.review.lastVerdict && !startResult.worktreeState.review.exhaustedPreviousRun && (startResult.worktreeState.review.lastVerdict === "PASS" || startResult.worktreeState.review.lastVerdict === "PASS_WITH_NOTES");
7037
7195
  let reviewArtifactPath;
7196
+ let reviewVerdict = void 0;
7038
7197
  if (reviewAlreadyPassed) {
7039
7198
  reviewArtifactPath = startResult.worktreeState.review.lastArtifactPath;
7199
+ reviewVerdict = startResult.worktreeState.review.lastVerdict;
7040
7200
  } else {
7041
7201
  const reviewResult = await options.deps.advanceIssueRunReview({
7042
7202
  executionProvider: options.runOptions.executionProvider,
@@ -7053,28 +7213,34 @@ async function runIssueLifecycle(options) {
7053
7213
  serena: startResult.serena,
7054
7214
  memory: startResult.memory
7055
7215
  });
7056
- if (reviewResult.exhaustedMaxIterations) {
7057
- throw new Error(
7058
- "Review loop exhausted maximum iterations without passing"
7059
- );
7060
- }
7061
- if (reviewResult.verdict === "FAIL") {
7062
- const summary = reviewResult.output?.trim() || "no summary provided";
7063
- throw new Error(`Review loop failed: ${summary}`);
7064
- }
7065
- if (reviewResult.verdict === "NEEDS_HUMAN") {
7066
- await options.deps.transitionReviewNeedsHumanToHandoff({
7067
- issueProvider: options.issueProvider,
7068
- issueNumber: options.issueNumber,
7069
- config: options.config,
7070
- logger: options.logger,
7071
- reviewResult
7072
- });
7073
- throw new IssueRunHumanHandoffStop(
7074
- "Review requires human handoff: NEEDS_HUMAN verdict"
7075
- );
7216
+ switch (reviewResult.status) {
7217
+ case "passed":
7218
+ reviewArtifactPath = reviewResult.reviewArtifactPath;
7219
+ reviewVerdict = reviewResult.reviewVerdict;
7220
+ break;
7221
+ case "needs_human":
7222
+ await options.deps.transitionReviewNeedsHumanToHandoff({
7223
+ issueProvider: options.issueProvider,
7224
+ issueNumber: options.issueNumber,
7225
+ config: options.config,
7226
+ logger: options.logger,
7227
+ reviewResult
7228
+ });
7229
+ throw new IssueRunHumanHandoffStop(
7230
+ "Review requires human handoff: NEEDS_HUMAN verdict"
7231
+ );
7232
+ case "exhausted_max_iterations":
7233
+ await options.deps.transitionReviewNeedsHumanToHandoff({
7234
+ issueProvider: options.issueProvider,
7235
+ issueNumber: options.issueNumber,
7236
+ config: options.config,
7237
+ logger: options.logger,
7238
+ reviewResult
7239
+ });
7240
+ throw new IssueRunHumanHandoffStop(
7241
+ "Review exhausted maximum iterations - requires human handoff"
7242
+ );
7076
7243
  }
7077
- reviewArtifactPath = reviewResult.artifactPath;
7078
7244
  }
7079
7245
  const finalReviewResult = await options.deps.advanceIssueFinalReview({
7080
7246
  executionProvider: options.runOptions.executionProvider,
@@ -7087,6 +7253,7 @@ async function runIssueLifecycle(options) {
7087
7253
  repoRoot: options.repoRoot,
7088
7254
  logger: options.logger,
7089
7255
  reviewArtifactPath,
7256
+ reviewVerdict,
7090
7257
  worktreeState: startResult.worktreeState,
7091
7258
  memory: startResult.memory
7092
7259
  });
@@ -7458,7 +7625,7 @@ import { Match, pipe } from "effect";
7458
7625
 
7459
7626
  // commands/queue.ts
7460
7627
  init_common();
7461
- import { Effect as Effect8 } from "effect";
7628
+ import { Effect as Effect9 } from "effect";
7462
7629
 
7463
7630
  // issues/select-issue.ts
7464
7631
  init_common();
@@ -7631,8 +7798,8 @@ function issueDataToCandidate(issue) {
7631
7798
  function selectNextQueueIssue(options) {
7632
7799
  const { config, issueProvider, logger, prdRef } = options;
7633
7800
  logger.step("info", "Loading candidate issues from provider");
7634
- return Effect8.gen(function* () {
7635
- const candidates = yield* Effect8.tryPromise({
7801
+ return Effect9.gen(function* () {
7802
+ const candidates = yield* Effect9.tryPromise({
7636
7803
  try: () => issueProvider.listCandidates(),
7637
7804
  catch: (e) => {
7638
7805
  if (e instanceof Error) {
@@ -7703,7 +7870,7 @@ function selectNextQueueIssue(options) {
7703
7870
  (c) => c.number === selection.issue.number
7704
7871
  );
7705
7872
  if (!selected) {
7706
- return yield* Effect8.die(
7873
+ return yield* Effect9.die(
7707
7874
  new Error(
7708
7875
  `Selected issue #${selection.issue.number} not found in candidate list`
7709
7876
  )
@@ -7758,8 +7925,8 @@ function makeReconcileDeps(options) {
7758
7925
  };
7759
7926
  }
7760
7927
  function reconcileBlockedEffect(options) {
7761
- return Effect8.gen(function* () {
7762
- const blocked2 = yield* Effect8.tryPromise({
7928
+ return Effect9.gen(function* () {
7929
+ const blocked2 = yield* Effect9.tryPromise({
7763
7930
  try: () => options.issueProvider.listBlockedIssues(),
7764
7931
  catch: (e) => {
7765
7932
  if (e instanceof Error) {
@@ -7773,7 +7940,7 @@ function reconcileBlockedEffect(options) {
7773
7940
  "info",
7774
7941
  `Reconciling ${blocked2.length} blocked issue(s)`
7775
7942
  );
7776
- yield* Effect8.tryPromise({
7943
+ yield* Effect9.tryPromise({
7777
7944
  try: () => reconcileBlockedIssues(blocked2, makeReconcileDeps(options)),
7778
7945
  catch: (e) => {
7779
7946
  if (e instanceof Error) {
@@ -7797,7 +7964,7 @@ function runOneQueueIssueEffect(options) {
7797
7964
  repoRoot: repoRoot2,
7798
7965
  prdRef
7799
7966
  } = options;
7800
- return Effect8.gen(function* () {
7967
+ return Effect9.gen(function* () {
7801
7968
  const outcome = yield* selectNextQueueIssue({
7802
7969
  config,
7803
7970
  issueProvider,
@@ -7813,7 +7980,7 @@ function runOneQueueIssueEffect(options) {
7813
7980
  }
7814
7981
  const { issue: selected } = outcome;
7815
7982
  const baseBranchOverride = options.queueRunContext?.prdBranch;
7816
- const runResult = yield* Effect8.tryPromise({
7983
+ const runResult = yield* Effect9.tryPromise({
7817
7984
  try: () => runIssueCommand({
7818
7985
  issueNumber: selected.number,
7819
7986
  targetName,
@@ -7853,7 +8020,7 @@ function runQueue(options) {
7853
8020
  return runOneQueueIssueEffect(options);
7854
8021
  }
7855
8022
  function runQueueLoopEffect(options, results) {
7856
- return Effect8.gen(function* () {
8023
+ return Effect9.gen(function* () {
7857
8024
  yield* reconcileBlockedEffect(options);
7858
8025
  const outcome = yield* runOneQueueIssueEffect(options);
7859
8026
  if (outcome.selected === null) {
@@ -7870,7 +8037,7 @@ function runQueueLoopEffect(options, results) {
7870
8037
  };
7871
8038
  }
7872
8039
  const newResults = [...results, outcome];
7873
- const processedIssue = yield* Effect8.tryPromise({
8040
+ const processedIssue = yield* Effect9.tryPromise({
7874
8041
  try: () => options.issueProvider.fetchIssue(outcome.selected.number),
7875
8042
  catch: (e) => {
7876
8043
  if (e instanceof Error) {
@@ -10225,8 +10392,7 @@ function generateConfigTemplate(options) {
10225
10392
  model: "opencode-go/qwen3.6-plus",
10226
10393
  promptTemplate: ".pourkit/managed/prompts/refactor.prompt.md"
10227
10394
  },
10228
- maxIterations: 3,
10229
- passWithNotesRefactorAttempts: 2
10395
+ maxIterations: 3
10230
10396
  },
10231
10397
  issueFinalReview: {
10232
10398
  agent: "pourkit-reviewer",
@@ -10256,7 +10422,7 @@ function generateConfigTemplate(options) {
10256
10422
  }
10257
10423
  const config = {
10258
10424
  $schema: "./schema/pourkit.schema.json",
10259
- schemaVersion: 2,
10425
+ schemaVersion: 3,
10260
10426
  targets: [target],
10261
10427
  workflowPack: {
10262
10428
  version: "1.0.0",
@@ -15454,11 +15620,11 @@ function createCliProgram(version) {
15454
15620
  return program;
15455
15621
  }
15456
15622
  async function resolveCliVersion() {
15457
- if (isPackageVersion("0.0.0-next-20260621094003")) {
15458
- return "0.0.0-next-20260621094003";
15623
+ if (isPackageVersion("0.0.0-next-20260621233457")) {
15624
+ return "0.0.0-next-20260621233457";
15459
15625
  }
15460
- if (isReleaseVersion("0.0.0-next-20260621094003")) {
15461
- return "0.0.0-next-20260621094003";
15626
+ if (isReleaseVersion("0.0.0-next-20260621233457")) {
15627
+ return "0.0.0-next-20260621233457";
15462
15628
  }
15463
15629
  try {
15464
15630
  const root = repoRoot();