@pourkit/cli 0.0.0-next-20260608221925 → 0.0.0-next-20260609130908
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 +471 -253
- package/dist/cli.js.map +1 -1
- package/dist/e2e/run-live-e2e.js +2 -26
- package/dist/e2e/run-live-e2e.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1354,13 +1354,7 @@ function buildRunContextMarkdown(options) {
|
|
|
1354
1354
|
);
|
|
1355
1355
|
}
|
|
1356
1356
|
if (sections.includes("verification-commands")) {
|
|
1357
|
-
parts.push(
|
|
1358
|
-
...renderCommandList(
|
|
1359
|
-
target,
|
|
1360
|
-
getVerificationCommands(target),
|
|
1361
|
-
"Verification Commands"
|
|
1362
|
-
)
|
|
1363
|
-
);
|
|
1357
|
+
parts.push(...renderCommandList(target, "Verification Commands"));
|
|
1364
1358
|
}
|
|
1365
1359
|
if (sections.includes("review-criteria")) {
|
|
1366
1360
|
parts.push(...renderCriteria(reviewerCriteria));
|
|
@@ -1378,29 +1372,11 @@ function buildRunContextMarkdown(options) {
|
|
|
1378
1372
|
}
|
|
1379
1373
|
return parts.join("\n");
|
|
1380
1374
|
}
|
|
1381
|
-
function renderCommandList(target,
|
|
1382
|
-
if (commands.length === 0) {
|
|
1383
|
-
return [
|
|
1384
|
-
`## ${heading}`,
|
|
1385
|
-
"",
|
|
1386
|
-
`Run this command from the repository root: \`${buildRunVerificationCommand(target)}\``,
|
|
1387
|
-
"",
|
|
1388
|
-
"Underlying project commands:",
|
|
1389
|
-
"",
|
|
1390
|
-
"(none configured)",
|
|
1391
|
-
""
|
|
1392
|
-
];
|
|
1393
|
-
}
|
|
1375
|
+
function renderCommandList(target, heading) {
|
|
1394
1376
|
return [
|
|
1395
1377
|
`## ${heading}`,
|
|
1396
1378
|
"",
|
|
1397
1379
|
`Run this command from the repository root: \`${buildRunVerificationCommand(target)}\``,
|
|
1398
|
-
"",
|
|
1399
|
-
"Underlying project commands:",
|
|
1400
|
-
"",
|
|
1401
|
-
"Run these commands from the repository root exactly as written. Do not substitute equivalent scripts from nested package.json files.",
|
|
1402
|
-
"",
|
|
1403
|
-
...commands.map((command) => `- ${command.label}: \`${command.command}\``),
|
|
1404
1380
|
""
|
|
1405
1381
|
];
|
|
1406
1382
|
}
|
|
@@ -8597,7 +8573,20 @@ var LocalPrdRunRecordSchema = z3.object({
|
|
|
8597
8573
|
baseCommit: z3.string().min(1)
|
|
8598
8574
|
}).optional(),
|
|
8599
8575
|
queue: z3.object({ completedAt: z3.string().min(1) }).optional(),
|
|
8600
|
-
finalReview: z3.object({
|
|
8576
|
+
finalReview: z3.object({
|
|
8577
|
+
completedAt: z3.string().min(1),
|
|
8578
|
+
targetName: z3.string().optional(),
|
|
8579
|
+
prdBranch: z3.string().optional(),
|
|
8580
|
+
mergeBase: z3.string().optional(),
|
|
8581
|
+
verdict: z3.enum([
|
|
8582
|
+
"pass_no_changes",
|
|
8583
|
+
"pass_with_retouch",
|
|
8584
|
+
"needs_human_review",
|
|
8585
|
+
"blocked"
|
|
8586
|
+
]).optional(),
|
|
8587
|
+
diagnostics: z3.array(z3.string()).optional(),
|
|
8588
|
+
artifactPath: z3.string().optional()
|
|
8589
|
+
}).optional(),
|
|
8601
8590
|
reconciliation: z3.object({ completedAt: z3.string().min(1) }).optional(),
|
|
8602
8591
|
complete: z3.object({
|
|
8603
8592
|
completedAt: z3.string().min(1),
|
|
@@ -9278,7 +9267,7 @@ async function runLocalFinalReview(prdId, options) {
|
|
|
9278
9267
|
}
|
|
9279
9268
|
let verdict;
|
|
9280
9269
|
if (commands.length === 0 || failures.length === 0) {
|
|
9281
|
-
const retouchBranch = `local
|
|
9270
|
+
const retouchBranch = `local-${prdId}-final-review-retouch`;
|
|
9282
9271
|
try {
|
|
9283
9272
|
execSync2(`git show-ref --verify --quiet refs/heads/${retouchBranch}`, {
|
|
9284
9273
|
cwd: root,
|
|
@@ -9292,7 +9281,7 @@ async function runLocalFinalReview(prdId, options) {
|
|
|
9292
9281
|
} else if (failures.length === commands.length) {
|
|
9293
9282
|
verdict = "blocked";
|
|
9294
9283
|
} else {
|
|
9295
|
-
const retouchBranch = `local
|
|
9284
|
+
const retouchBranch = `local-${prdId}-final-review-retouch`;
|
|
9296
9285
|
try {
|
|
9297
9286
|
execSync2(`git show-ref --verify --quiet refs/heads/${retouchBranch}`, {
|
|
9298
9287
|
cwd: root,
|
|
@@ -9321,10 +9310,10 @@ async function runLocalFinalReview(prdId, options) {
|
|
|
9321
9310
|
}
|
|
9322
9311
|
return result;
|
|
9323
9312
|
}
|
|
9324
|
-
async function squashFinalReviewRetouch(prdId, repoRoot2) {
|
|
9313
|
+
async function squashFinalReviewRetouch(prdId, repoRoot2, title, body) {
|
|
9325
9314
|
const root = repoRoot2 ?? process.cwd();
|
|
9326
9315
|
const targetBranch = `local/${prdId}`;
|
|
9327
|
-
const retouchBranch = `local
|
|
9316
|
+
const retouchBranch = `local-${prdId}-final-review-retouch`;
|
|
9328
9317
|
try {
|
|
9329
9318
|
execFileSync3(
|
|
9330
9319
|
"git",
|
|
@@ -9371,15 +9360,26 @@ async function squashFinalReviewRetouch(prdId, repoRoot2) {
|
|
|
9371
9360
|
return;
|
|
9372
9361
|
} catch {
|
|
9373
9362
|
}
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9363
|
+
if (title) {
|
|
9364
|
+
const commitBody = body ? `${title}
|
|
9365
|
+
|
|
9366
|
+
${body}` : title;
|
|
9367
|
+
execFileSync3("git", ["commit", "-m", commitBody], {
|
|
9378
9368
|
cwd: root,
|
|
9379
9369
|
encoding: "utf8",
|
|
9380
9370
|
stdio: "pipe"
|
|
9381
|
-
}
|
|
9382
|
-
|
|
9371
|
+
});
|
|
9372
|
+
} else {
|
|
9373
|
+
execFileSync3(
|
|
9374
|
+
"git",
|
|
9375
|
+
["commit", "-m", `Squash merge ${retouchBranch} into ${targetBranch}`],
|
|
9376
|
+
{
|
|
9377
|
+
cwd: root,
|
|
9378
|
+
encoding: "utf8",
|
|
9379
|
+
stdio: "pipe"
|
|
9380
|
+
}
|
|
9381
|
+
);
|
|
9382
|
+
}
|
|
9383
9383
|
const mergeCommit = execFileSync3("git", ["rev-parse", "HEAD"], {
|
|
9384
9384
|
cwd: root,
|
|
9385
9385
|
encoding: "utf8",
|
|
@@ -10722,10 +10722,6 @@ function loadFinalReviewPrompt(repoRoot2, promptTemplate) {
|
|
|
10722
10722
|
const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
|
|
10723
10723
|
return existsSync17(promptPath) ? readFileSync17(promptPath, "utf-8") : promptTemplate;
|
|
10724
10724
|
}
|
|
10725
|
-
function formatVerificationCommands(commands) {
|
|
10726
|
-
if (commands.length === 0) return "No verification commands configured.";
|
|
10727
|
-
return commands.map((cmd) => `- ${cmd.label}: ${cmd.command}`).join("\n");
|
|
10728
|
-
}
|
|
10729
10725
|
function buildFinalReviewPrompt(options) {
|
|
10730
10726
|
return [
|
|
10731
10727
|
"# Active PRD Final Review Context",
|
|
@@ -10740,9 +10736,6 @@ function buildFinalReviewPrompt(options) {
|
|
|
10740
10736
|
"",
|
|
10741
10737
|
`Run this command before handoff when retouch changes are made: pourkit run-verification --target ${options.targetName}`,
|
|
10742
10738
|
"",
|
|
10743
|
-
"Underlying project commands:",
|
|
10744
|
-
formatVerificationCommands(options.verificationCommands),
|
|
10745
|
-
"",
|
|
10746
10739
|
"Evidence Packet (do not infer PRD context from local state files):",
|
|
10747
10740
|
JSON.stringify(options.evidencePacket, null, 2),
|
|
10748
10741
|
"",
|
|
@@ -10867,9 +10860,6 @@ function buildFinalReviewFinalizerPrompt(options) {
|
|
|
10867
10860
|
"Changed paths:",
|
|
10868
10861
|
...options.changedPaths.map((p) => `- ${p}`),
|
|
10869
10862
|
"",
|
|
10870
|
-
"Verification commands given to Final Review:",
|
|
10871
|
-
formatVerificationCommands(options.verificationCommands),
|
|
10872
|
-
"",
|
|
10873
10863
|
promptBody
|
|
10874
10864
|
].join("\n");
|
|
10875
10865
|
}
|
|
@@ -10896,8 +10886,7 @@ async function runFinalReviewPrFinalizer(options) {
|
|
|
10896
10886
|
prdBranch: options.prdBranch,
|
|
10897
10887
|
mergeBase: options.mergeBase,
|
|
10898
10888
|
summary: options.summary,
|
|
10899
|
-
changedPaths: options.changedPaths
|
|
10900
|
-
verificationCommands: options.verificationCommands
|
|
10889
|
+
changedPaths: options.changedPaths
|
|
10901
10890
|
}),
|
|
10902
10891
|
branchName: options.branchName,
|
|
10903
10892
|
repoRoot: options.repoRoot,
|
|
@@ -10957,17 +10946,32 @@ function ensureFinalReviewWorktree(options) {
|
|
|
10957
10946
|
};
|
|
10958
10947
|
}
|
|
10959
10948
|
mkdirSync11(dirname5(worktreePath), { recursive: true });
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10949
|
+
if (options.isLocal) {
|
|
10950
|
+
const branchResult = spawnSync3(
|
|
10951
|
+
"git",
|
|
10952
|
+
["branch", "-f", options.branchName, options.checkoutBase],
|
|
10953
|
+
{ cwd: options.repoRoot, encoding: "utf8" }
|
|
10954
|
+
);
|
|
10955
|
+
if (branchResult.status !== 0) {
|
|
10956
|
+
return {
|
|
10957
|
+
ok: false,
|
|
10958
|
+
reason: `Final Review failed to prepare branch ${options.branchName}.`,
|
|
10959
|
+
diagnostics: collectSpawnDiagnostics(branchResult, "git branch failed")
|
|
10960
|
+
};
|
|
10961
|
+
}
|
|
10962
|
+
} else {
|
|
10963
|
+
const branchResult = spawnSync3(
|
|
10964
|
+
"git",
|
|
10965
|
+
["branch", "-f", options.branchName, `origin/${options.checkoutBase}`],
|
|
10966
|
+
{ cwd: options.repoRoot, encoding: "utf8" }
|
|
10967
|
+
);
|
|
10968
|
+
if (branchResult.status !== 0) {
|
|
10969
|
+
return {
|
|
10970
|
+
ok: false,
|
|
10971
|
+
reason: `Final Review failed to prepare branch ${options.branchName}.`,
|
|
10972
|
+
diagnostics: collectSpawnDiagnostics(branchResult, "git branch failed")
|
|
10973
|
+
};
|
|
10974
|
+
}
|
|
10971
10975
|
}
|
|
10972
10976
|
const addResult = spawnSync3(
|
|
10973
10977
|
"git",
|
|
@@ -11079,6 +11083,156 @@ async function createOrReuseFinalReviewRetouchPr(options) {
|
|
|
11079
11083
|
})
|
|
11080
11084
|
});
|
|
11081
11085
|
}
|
|
11086
|
+
async function writeAndVerifyLocalDualReceipt(repoRoot2, prdRef, record, targetName, prdBranch, mergeBase, verdict, reviewedAt, isLocalMode) {
|
|
11087
|
+
if (!isLocalMode) return null;
|
|
11088
|
+
let currentRecord = await readLocalPrdRun(repoRoot2, prdRef);
|
|
11089
|
+
if (!currentRecord) {
|
|
11090
|
+
currentRecord = {
|
|
11091
|
+
prdId: normalizePrdRunRef2(prdRef),
|
|
11092
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11093
|
+
receipts: {},
|
|
11094
|
+
metadata: {}
|
|
11095
|
+
};
|
|
11096
|
+
}
|
|
11097
|
+
const localStoreReceipt = {
|
|
11098
|
+
completedAt: reviewedAt,
|
|
11099
|
+
targetName,
|
|
11100
|
+
prdBranch,
|
|
11101
|
+
mergeBase,
|
|
11102
|
+
verdict,
|
|
11103
|
+
diagnostics: [],
|
|
11104
|
+
artifactPath: ".pourkit/final-review-artifact.json"
|
|
11105
|
+
};
|
|
11106
|
+
await writeLocalPrdRunRecord(repoRoot2, prdRef, {
|
|
11107
|
+
...currentRecord,
|
|
11108
|
+
receipts: {
|
|
11109
|
+
...currentRecord.receipts,
|
|
11110
|
+
finalReview: localStoreReceipt
|
|
11111
|
+
}
|
|
11112
|
+
});
|
|
11113
|
+
const prdRunStateResult = readPrdRun(repoRoot2, prdRef);
|
|
11114
|
+
const localStoreResult = await readLocalPrdRun(repoRoot2, prdRef);
|
|
11115
|
+
if (!prdRunStateResult.record?.finalReview) {
|
|
11116
|
+
const reason = `PRD Run State missing finalReview receipt after write for ${prdRef}.`;
|
|
11117
|
+
writePrdRunRecord(repoRoot2, {
|
|
11118
|
+
...record,
|
|
11119
|
+
prdRef,
|
|
11120
|
+
status: "blocked",
|
|
11121
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11122
|
+
blockedGate: "final-review",
|
|
11123
|
+
blockedReason: reason,
|
|
11124
|
+
diagnostics: [reason],
|
|
11125
|
+
targetName,
|
|
11126
|
+
offendingPaths: []
|
|
11127
|
+
});
|
|
11128
|
+
return {
|
|
11129
|
+
prdRef,
|
|
11130
|
+
status: "blocked",
|
|
11131
|
+
blockedGate: "final-review",
|
|
11132
|
+
blockedReason: reason,
|
|
11133
|
+
diagnostics: [reason],
|
|
11134
|
+
offendingPaths: []
|
|
11135
|
+
};
|
|
11136
|
+
}
|
|
11137
|
+
if (!localStoreResult?.receipts.finalReview) {
|
|
11138
|
+
const reason = `Local PRD Run store missing finalReview receipt after write for ${prdRef}.`;
|
|
11139
|
+
writePrdRunRecord(repoRoot2, {
|
|
11140
|
+
...record,
|
|
11141
|
+
prdRef,
|
|
11142
|
+
status: "blocked",
|
|
11143
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11144
|
+
blockedGate: "final-review",
|
|
11145
|
+
blockedReason: reason,
|
|
11146
|
+
diagnostics: [reason],
|
|
11147
|
+
targetName,
|
|
11148
|
+
offendingPaths: []
|
|
11149
|
+
});
|
|
11150
|
+
return {
|
|
11151
|
+
prdRef,
|
|
11152
|
+
status: "blocked",
|
|
11153
|
+
blockedGate: "final-review",
|
|
11154
|
+
blockedReason: reason,
|
|
11155
|
+
diagnostics: [reason],
|
|
11156
|
+
offendingPaths: []
|
|
11157
|
+
};
|
|
11158
|
+
}
|
|
11159
|
+
const stateFr = prdRunStateResult.record.finalReview;
|
|
11160
|
+
const localFr = localStoreResult.receipts.finalReview;
|
|
11161
|
+
const mismatchFields = [];
|
|
11162
|
+
if (stateFr.targetName !== localFr.targetName)
|
|
11163
|
+
mismatchFields.push("targetName");
|
|
11164
|
+
if (stateFr.prdBranch !== localFr.prdBranch) mismatchFields.push("prdBranch");
|
|
11165
|
+
if (stateFr.mergeBase !== localFr.mergeBase) mismatchFields.push("mergeBase");
|
|
11166
|
+
if (stateFr.verdict !== localFr.verdict) mismatchFields.push("verdict");
|
|
11167
|
+
if (!stateFr.artifactPath !== !localFr.artifactPath)
|
|
11168
|
+
mismatchFields.push("artifactPath");
|
|
11169
|
+
if (!stateFr.diagnostics !== !localFr.diagnostics)
|
|
11170
|
+
mismatchFields.push("diagnostics");
|
|
11171
|
+
if (!stateFr.reviewedAt !== !localFr.completedAt)
|
|
11172
|
+
mismatchFields.push("reviewedTimestamp");
|
|
11173
|
+
if (mismatchFields.length > 0) {
|
|
11174
|
+
const reason = `Dual receipt mismatch on fields: ${mismatchFields.join(", ")}`;
|
|
11175
|
+
writePrdRunRecord(repoRoot2, {
|
|
11176
|
+
...record,
|
|
11177
|
+
prdRef,
|
|
11178
|
+
status: "blocked",
|
|
11179
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11180
|
+
blockedGate: "final-review",
|
|
11181
|
+
blockedReason: reason,
|
|
11182
|
+
diagnostics: [reason],
|
|
11183
|
+
targetName,
|
|
11184
|
+
finalReview: stateFr,
|
|
11185
|
+
offendingPaths: []
|
|
11186
|
+
});
|
|
11187
|
+
return {
|
|
11188
|
+
prdRef,
|
|
11189
|
+
status: "blocked",
|
|
11190
|
+
blockedGate: "final-review",
|
|
11191
|
+
blockedReason: reason,
|
|
11192
|
+
diagnostics: [reason],
|
|
11193
|
+
offendingPaths: []
|
|
11194
|
+
};
|
|
11195
|
+
}
|
|
11196
|
+
return null;
|
|
11197
|
+
}
|
|
11198
|
+
async function verifyLocalDualFinalReviewReceipts(repoRoot2, prdRef) {
|
|
11199
|
+
const prdRunStateResult = readPrdRun(repoRoot2, prdRef);
|
|
11200
|
+
const stateFr = prdRunStateResult.record?.finalReview;
|
|
11201
|
+
const localStoreResult = await readLocalPrdRun(repoRoot2, prdRef);
|
|
11202
|
+
const localFr = localStoreResult?.receipts.finalReview;
|
|
11203
|
+
const diagnostics = [];
|
|
11204
|
+
const validFinalReviewStatuses = /* @__PURE__ */ new Set(["final_reviewed", "succeeded"]);
|
|
11205
|
+
if (!stateFr || !validFinalReviewStatuses.has(stateFr.status)) {
|
|
11206
|
+
diagnostics.push(
|
|
11207
|
+
stateFr ? `PRD Run State finalReview status is "${stateFr.status}". Expected "final_reviewed" or "succeeded".` : "PRD Run State has no finalReview receipt."
|
|
11208
|
+
);
|
|
11209
|
+
return {
|
|
11210
|
+
ok: false,
|
|
11211
|
+
reason: diagnostics[0],
|
|
11212
|
+
diagnostics
|
|
11213
|
+
};
|
|
11214
|
+
}
|
|
11215
|
+
if (!localFr) {
|
|
11216
|
+
diagnostics.push("Local PRD Run Store has no finalReview receipt.");
|
|
11217
|
+
return {
|
|
11218
|
+
ok: false,
|
|
11219
|
+
reason: diagnostics[0],
|
|
11220
|
+
diagnostics
|
|
11221
|
+
};
|
|
11222
|
+
}
|
|
11223
|
+
const mismatchFields = [];
|
|
11224
|
+
if (stateFr.targetName !== localFr.targetName)
|
|
11225
|
+
mismatchFields.push("targetName");
|
|
11226
|
+
if (stateFr.prdBranch !== localFr.prdBranch) mismatchFields.push("prdBranch");
|
|
11227
|
+
if (stateFr.mergeBase !== localFr.mergeBase) mismatchFields.push("mergeBase");
|
|
11228
|
+
if (stateFr.verdict !== localFr.verdict) mismatchFields.push("verdict");
|
|
11229
|
+
if (mismatchFields.length > 0) {
|
|
11230
|
+
const reason = `Dual receipt mismatch on fields: ${mismatchFields.join(", ")}`;
|
|
11231
|
+
diagnostics.push(reason);
|
|
11232
|
+
return { ok: false, reason, diagnostics };
|
|
11233
|
+
}
|
|
11234
|
+
return { ok: true };
|
|
11235
|
+
}
|
|
11082
11236
|
async function runPrdRunFinalReviewCommand(options) {
|
|
11083
11237
|
const prdRef = normalizePrdRunRef2(options.prdRef);
|
|
11084
11238
|
const targetName = options.targetName.trim();
|
|
@@ -11143,6 +11297,39 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11143
11297
|
offendingPaths: []
|
|
11144
11298
|
};
|
|
11145
11299
|
}
|
|
11300
|
+
if (record.mode === "local") {
|
|
11301
|
+
const runnableIssues = await getRunnableLocalIssues(
|
|
11302
|
+
prdRef,
|
|
11303
|
+
options.repoRoot
|
|
11304
|
+
);
|
|
11305
|
+
if (runnableIssues.length > 0) {
|
|
11306
|
+
const reason = `PRD Run ${prdRef} is marked "drained" but ${runnableIssues.length} runnable local Issues remain. Queue drain receipt may be premature.`;
|
|
11307
|
+
writePrdRunRecord(options.repoRoot, {
|
|
11308
|
+
...record,
|
|
11309
|
+
status: "blocked",
|
|
11310
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11311
|
+
blockedGate: "final-review",
|
|
11312
|
+
blockedReason: reason,
|
|
11313
|
+
diagnostics: [
|
|
11314
|
+
`Current status: ${record.status}`,
|
|
11315
|
+
`Runnable issues remaining: ${runnableIssues.length}`
|
|
11316
|
+
],
|
|
11317
|
+
targetName,
|
|
11318
|
+
offendingPaths: []
|
|
11319
|
+
});
|
|
11320
|
+
return {
|
|
11321
|
+
prdRef,
|
|
11322
|
+
status: "blocked",
|
|
11323
|
+
blockedGate: "final-review",
|
|
11324
|
+
blockedReason: reason,
|
|
11325
|
+
diagnostics: [
|
|
11326
|
+
`Current status: ${record.status}`,
|
|
11327
|
+
`Runnable issues remaining: ${runnableIssues.length}`
|
|
11328
|
+
],
|
|
11329
|
+
offendingPaths: []
|
|
11330
|
+
};
|
|
11331
|
+
}
|
|
11332
|
+
}
|
|
11146
11333
|
if (!options.issueProvider) {
|
|
11147
11334
|
const reason = "Missing IssueProvider. Cannot validate child completeness.";
|
|
11148
11335
|
writePrdRunRecord(options.repoRoot, {
|
|
@@ -11251,8 +11438,19 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11251
11438
|
offendingPaths: []
|
|
11252
11439
|
};
|
|
11253
11440
|
}
|
|
11254
|
-
const
|
|
11255
|
-
|
|
11441
|
+
const isLocalMode = record.mode === "local";
|
|
11442
|
+
let mergeBaseResult;
|
|
11443
|
+
let prdBranch;
|
|
11444
|
+
if (isLocalMode) {
|
|
11445
|
+
prdBranch = getLocalPrdBranchName(prdRef);
|
|
11446
|
+
mergeBaseResult = computeLocalFinalReviewMergeBase(
|
|
11447
|
+
options.repoRoot,
|
|
11448
|
+
prdBranch
|
|
11449
|
+
);
|
|
11450
|
+
} else {
|
|
11451
|
+
prdBranch = record.prdBranch ?? prdRef;
|
|
11452
|
+
mergeBaseResult = computeFinalReviewMergeBase(options.repoRoot, prdRef);
|
|
11453
|
+
}
|
|
11256
11454
|
if (!mergeBaseResult.ok) {
|
|
11257
11455
|
writePrdRunRecord(options.repoRoot, {
|
|
11258
11456
|
...record,
|
|
@@ -11265,7 +11463,7 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11265
11463
|
finalReview: {
|
|
11266
11464
|
status: "blocked",
|
|
11267
11465
|
targetName,
|
|
11268
|
-
prdBranch
|
|
11466
|
+
prdBranch,
|
|
11269
11467
|
mergeBase: mergeBaseResult.mergeBase,
|
|
11270
11468
|
diagnostics: mergeBaseResult.diagnostics,
|
|
11271
11469
|
reviewedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -11281,7 +11479,6 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11281
11479
|
offendingPaths: []
|
|
11282
11480
|
};
|
|
11283
11481
|
}
|
|
11284
|
-
const prdBranch = record.prdBranch ?? prdRef;
|
|
11285
11482
|
const manifestResult = readPlanningArtifactManifest(options.repoRoot, prdRef);
|
|
11286
11483
|
if (!manifestResult.ok) {
|
|
11287
11484
|
const reason = `Evidence Packet construction failed: ${manifestResult.reason}`;
|
|
@@ -11341,11 +11538,12 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11341
11538
|
planning: record.planning,
|
|
11342
11539
|
finalReview: startReceipt
|
|
11343
11540
|
});
|
|
11344
|
-
const finalReviewBranchName = buildFinalReviewBranchName(prdBranch);
|
|
11541
|
+
const finalReviewBranchName = isLocalMode ? `${prdBranch.replace(/\//g, "-")}-final-review-retouch` : buildFinalReviewBranchName(prdBranch);
|
|
11345
11542
|
const worktreeResult = ensureFinalReviewWorktree({
|
|
11346
11543
|
repoRoot: options.repoRoot,
|
|
11347
11544
|
branchName: finalReviewBranchName,
|
|
11348
|
-
checkoutBase: prdBranch
|
|
11545
|
+
checkoutBase: prdBranch,
|
|
11546
|
+
isLocal: isLocalMode
|
|
11349
11547
|
});
|
|
11350
11548
|
if (!worktreeResult.ok) {
|
|
11351
11549
|
writePrdRunRecord(options.repoRoot, {
|
|
@@ -11386,8 +11584,7 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11386
11584
|
repoRoot: options.repoRoot,
|
|
11387
11585
|
promptTemplate: finalReviewConfig.promptTemplate,
|
|
11388
11586
|
targetName,
|
|
11389
|
-
evidencePacket
|
|
11390
|
-
verificationCommands
|
|
11587
|
+
evidencePacket
|
|
11391
11588
|
}),
|
|
11392
11589
|
target: targetConfig,
|
|
11393
11590
|
repoRoot: options.repoRoot,
|
|
@@ -11530,6 +11727,7 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11530
11727
|
}
|
|
11531
11728
|
const { verdict, summary, diagnostics: artifactDiagnostics } = artifactResult;
|
|
11532
11729
|
if (verdict === "pass_no_changes") {
|
|
11730
|
+
const reviewedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11533
11731
|
const receipt = {
|
|
11534
11732
|
status: "succeeded",
|
|
11535
11733
|
targetName,
|
|
@@ -11538,17 +11736,29 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11538
11736
|
verdict: "pass_no_changes",
|
|
11539
11737
|
artifactPath: ".pourkit/final-review-artifact.json",
|
|
11540
11738
|
diagnostics: [],
|
|
11541
|
-
reviewedAt
|
|
11739
|
+
reviewedAt
|
|
11542
11740
|
};
|
|
11543
11741
|
writePrdRunRecord(options.repoRoot, {
|
|
11544
11742
|
...record,
|
|
11545
11743
|
status: "final_reviewed",
|
|
11546
|
-
updatedAt:
|
|
11744
|
+
updatedAt: reviewedAt,
|
|
11547
11745
|
targetName,
|
|
11548
11746
|
start: record.start,
|
|
11549
11747
|
planning: record.planning,
|
|
11550
11748
|
finalReview: receipt
|
|
11551
11749
|
});
|
|
11750
|
+
const blocked = await writeAndVerifyLocalDualReceipt(
|
|
11751
|
+
options.repoRoot,
|
|
11752
|
+
prdRef,
|
|
11753
|
+
record,
|
|
11754
|
+
targetName,
|
|
11755
|
+
prdBranch,
|
|
11756
|
+
mergeBaseResult.mergeBase,
|
|
11757
|
+
"pass_no_changes",
|
|
11758
|
+
reviewedAt,
|
|
11759
|
+
isLocalMode
|
|
11760
|
+
);
|
|
11761
|
+
if (blocked) return blocked;
|
|
11552
11762
|
return {
|
|
11553
11763
|
prdRef,
|
|
11554
11764
|
status: "final_reviewed",
|
|
@@ -11557,7 +11767,7 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11557
11767
|
};
|
|
11558
11768
|
}
|
|
11559
11769
|
if (verdict === "pass_with_retouch") {
|
|
11560
|
-
if (!options.prProvider) {
|
|
11770
|
+
if (!options.prProvider && !isLocalMode) {
|
|
11561
11771
|
const reason = "Missing PRProvider. Cannot create retouch PR without a PR provider.";
|
|
11562
11772
|
writePrdRunRecord(options.repoRoot, {
|
|
11563
11773
|
...record,
|
|
@@ -11588,7 +11798,7 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11588
11798
|
};
|
|
11589
11799
|
}
|
|
11590
11800
|
const autoMerge = options.autoMerge ?? true;
|
|
11591
|
-
const existingRetouchPrNumber = record.finalReview?.retouchPrNumber;
|
|
11801
|
+
const existingRetouchPrNumber = !isLocalMode ? record.finalReview?.retouchPrNumber : void 0;
|
|
11592
11802
|
if (existingRetouchPrNumber && autoMerge) {
|
|
11593
11803
|
const existingPr = await getPrByNumberIfAvailable(
|
|
11594
11804
|
options.prProvider,
|
|
@@ -11674,7 +11884,6 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11674
11884
|
mergeBase: mergeBaseResult.mergeBase,
|
|
11675
11885
|
summary,
|
|
11676
11886
|
changedPaths: scopeResult.changedPaths,
|
|
11677
|
-
verificationCommands,
|
|
11678
11887
|
logger: options.logger
|
|
11679
11888
|
});
|
|
11680
11889
|
if (!finalizerResult.ok) {
|
|
@@ -11706,6 +11915,116 @@ async function runPrdRunFinalReviewCommand(options) {
|
|
|
11706
11915
|
offendingPaths: []
|
|
11707
11916
|
};
|
|
11708
11917
|
}
|
|
11918
|
+
if (isLocalMode) {
|
|
11919
|
+
let localResult;
|
|
11920
|
+
try {
|
|
11921
|
+
const result = await squashFinalReviewRetouch(
|
|
11922
|
+
prdRef,
|
|
11923
|
+
options.repoRoot,
|
|
11924
|
+
finalizerResult.title,
|
|
11925
|
+
finalizerResult.body
|
|
11926
|
+
);
|
|
11927
|
+
if (!result) {
|
|
11928
|
+
const reason = "Retouch branch missing or empty. Cannot squash-merge.";
|
|
11929
|
+
writePrdRunRecord(options.repoRoot, {
|
|
11930
|
+
...record,
|
|
11931
|
+
status: "blocked",
|
|
11932
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11933
|
+
blockedGate: "final-review",
|
|
11934
|
+
blockedReason: reason,
|
|
11935
|
+
diagnostics: [reason],
|
|
11936
|
+
targetName,
|
|
11937
|
+
finalReview: {
|
|
11938
|
+
status: "blocked",
|
|
11939
|
+
targetName,
|
|
11940
|
+
prdBranch,
|
|
11941
|
+
mergeBase: mergeBaseResult.mergeBase,
|
|
11942
|
+
verdict: "pass_with_retouch",
|
|
11943
|
+
diagnostics: [reason],
|
|
11944
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11945
|
+
},
|
|
11946
|
+
offendingPaths: []
|
|
11947
|
+
});
|
|
11948
|
+
return {
|
|
11949
|
+
prdRef,
|
|
11950
|
+
status: "blocked",
|
|
11951
|
+
blockedGate: "final-review",
|
|
11952
|
+
blockedReason: reason,
|
|
11953
|
+
diagnostics: [reason],
|
|
11954
|
+
offendingPaths: []
|
|
11955
|
+
};
|
|
11956
|
+
}
|
|
11957
|
+
localResult = result;
|
|
11958
|
+
} catch (error) {
|
|
11959
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
11960
|
+
writePrdRunRecord(options.repoRoot, {
|
|
11961
|
+
...record,
|
|
11962
|
+
status: "blocked",
|
|
11963
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11964
|
+
blockedGate: "final-review",
|
|
11965
|
+
blockedReason: `Local retouch squash-merge failed: ${msg}`,
|
|
11966
|
+
diagnostics: [msg],
|
|
11967
|
+
targetName,
|
|
11968
|
+
finalReview: {
|
|
11969
|
+
status: "blocked",
|
|
11970
|
+
targetName,
|
|
11971
|
+
prdBranch,
|
|
11972
|
+
mergeBase: mergeBaseResult.mergeBase,
|
|
11973
|
+
verdict: "pass_with_retouch",
|
|
11974
|
+
diagnostics: [msg],
|
|
11975
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11976
|
+
},
|
|
11977
|
+
offendingPaths: []
|
|
11978
|
+
});
|
|
11979
|
+
return {
|
|
11980
|
+
prdRef,
|
|
11981
|
+
status: "blocked",
|
|
11982
|
+
blockedGate: "final-review",
|
|
11983
|
+
blockedReason: `Local retouch squash-merge failed: ${msg}`,
|
|
11984
|
+
diagnostics: [msg],
|
|
11985
|
+
offendingPaths: []
|
|
11986
|
+
};
|
|
11987
|
+
}
|
|
11988
|
+
const receipt2 = {
|
|
11989
|
+
status: "final_reviewed",
|
|
11990
|
+
targetName,
|
|
11991
|
+
prdBranch,
|
|
11992
|
+
mergeBase: mergeBaseResult.mergeBase,
|
|
11993
|
+
verdict: "pass_with_retouch",
|
|
11994
|
+
artifactPath: ".pourkit/final-review-artifact.json",
|
|
11995
|
+
diagnostics: [],
|
|
11996
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11997
|
+
retouchMergeCommit: localResult.mergeCommit,
|
|
11998
|
+
changedPaths: localResult.changedPaths
|
|
11999
|
+
};
|
|
12000
|
+
writePrdRunRecord(options.repoRoot, {
|
|
12001
|
+
...record,
|
|
12002
|
+
status: "final_reviewed",
|
|
12003
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12004
|
+
targetName,
|
|
12005
|
+
start: record.start,
|
|
12006
|
+
planning: record.planning,
|
|
12007
|
+
finalReview: receipt2
|
|
12008
|
+
});
|
|
12009
|
+
const blocked = await writeAndVerifyLocalDualReceipt(
|
|
12010
|
+
options.repoRoot,
|
|
12011
|
+
prdRef,
|
|
12012
|
+
record,
|
|
12013
|
+
targetName,
|
|
12014
|
+
prdBranch,
|
|
12015
|
+
mergeBaseResult.mergeBase,
|
|
12016
|
+
"pass_with_retouch",
|
|
12017
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
12018
|
+
isLocalMode
|
|
12019
|
+
);
|
|
12020
|
+
if (blocked) return blocked;
|
|
12021
|
+
return {
|
|
12022
|
+
prdRef,
|
|
12023
|
+
status: "final_reviewed",
|
|
12024
|
+
finalReview: receipt2,
|
|
12025
|
+
diagnostics: []
|
|
12026
|
+
};
|
|
12027
|
+
}
|
|
11709
12028
|
let retouchPr;
|
|
11710
12029
|
try {
|
|
11711
12030
|
retouchPr = await createOrReuseFinalReviewRetouchPr({
|
|
@@ -13895,6 +14214,37 @@ function computeFinalReviewMergeBase(repoRoot2, prdRef) {
|
|
|
13895
14214
|
}
|
|
13896
14215
|
return { ok: true, mergeBase, diagnostics: fetchDiagnostics };
|
|
13897
14216
|
}
|
|
14217
|
+
function computeLocalFinalReviewMergeBase(repoRoot2, prdBranch) {
|
|
14218
|
+
const mergeBaseResult = spawnSync3("git", ["merge-base", "dev", prdBranch], {
|
|
14219
|
+
cwd: repoRoot2,
|
|
14220
|
+
encoding: "utf8"
|
|
14221
|
+
});
|
|
14222
|
+
if (mergeBaseResult.status !== 0) {
|
|
14223
|
+
const diagnostics = [];
|
|
14224
|
+
if (mergeBaseResult.stderr?.toString?.()?.trim()) {
|
|
14225
|
+
diagnostics.push(mergeBaseResult.stderr.toString().trim());
|
|
14226
|
+
}
|
|
14227
|
+
if (mergeBaseResult.stdout?.toString?.()?.trim()) {
|
|
14228
|
+
diagnostics.push(mergeBaseResult.stdout.toString().trim());
|
|
14229
|
+
}
|
|
14230
|
+
return {
|
|
14231
|
+
ok: false,
|
|
14232
|
+
gate: "final-review",
|
|
14233
|
+
reason: `Final Review merge-base computation failed for dev and ${prdBranch}.`,
|
|
14234
|
+
diagnostics: diagnostics.length > 0 ? diagnostics : ["git merge-base returned non-zero exit status"]
|
|
14235
|
+
};
|
|
14236
|
+
}
|
|
14237
|
+
const mergeBase = mergeBaseResult.stdout?.toString?.()?.trim();
|
|
14238
|
+
if (!mergeBase) {
|
|
14239
|
+
return {
|
|
14240
|
+
ok: false,
|
|
14241
|
+
gate: "final-review",
|
|
14242
|
+
reason: `Final Review merge-base returned empty result for dev and ${prdBranch}.`,
|
|
14243
|
+
diagnostics: [`merge-base stdout was empty for dev..${prdBranch}`]
|
|
14244
|
+
};
|
|
14245
|
+
}
|
|
14246
|
+
return { ok: true, mergeBase, diagnostics: [] };
|
|
14247
|
+
}
|
|
13898
14248
|
function validateReconciliationArtifact2(artifact, context) {
|
|
13899
14249
|
const errors = [];
|
|
13900
14250
|
if (!artifact.prdRef) {
|
|
@@ -14339,201 +14689,47 @@ async function runPrdRunLaunchCommand(options) {
|
|
|
14339
14689
|
let finalReviewResult;
|
|
14340
14690
|
if (!skipped.includes("final-review")) {
|
|
14341
14691
|
attempted.push("final-review");
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14345
|
-
|
|
14346
|
-
prdRef
|
|
14347
|
-
);
|
|
14348
|
-
if (existsSync17(localStorePath2)) {
|
|
14349
|
-
const prdRecord = readPrdRun(options.repoRoot, prdRef);
|
|
14350
|
-
if (prdRecord.record && prdRecord.record.status !== "drained" && !canRetryFinalReviewBlock(prdRecord.record)) {
|
|
14351
|
-
const reason = `Final Review blocked: Queue drain not completed. Status is "${prdRecord.record.status}". Finish all child Issues before Final Review.`;
|
|
14352
|
-
writePrdRunRecord(options.repoRoot, {
|
|
14353
|
-
prdRef,
|
|
14354
|
-
status: "blocked",
|
|
14355
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14356
|
-
blockedGate: "final-review",
|
|
14357
|
-
blockedReason: reason,
|
|
14358
|
-
diagnostics: [
|
|
14359
|
-
`Current status: ${prdRecord.record.status}. Queue drain receipt is missing. Run child Issues through queue-run before Final Review.`
|
|
14360
|
-
],
|
|
14361
|
-
targetName: options.targetName,
|
|
14362
|
-
offendingPaths: []
|
|
14363
|
-
});
|
|
14364
|
-
return {
|
|
14365
|
-
prdRef,
|
|
14366
|
-
status: "blocked",
|
|
14367
|
-
attempted,
|
|
14368
|
-
skipped: [
|
|
14369
|
-
...skipped.includes("prepare") ? ["prepare"] : [],
|
|
14370
|
-
...skipped.includes("start") ? ["queue"] : [],
|
|
14371
|
-
"reconcile"
|
|
14372
|
-
],
|
|
14373
|
-
resumed,
|
|
14374
|
-
diagnostics: [
|
|
14375
|
-
`Current status: ${prdRecord.record.status}. Queue drain receipt is missing. Run child Issues through queue-run before Final Review.`
|
|
14376
|
-
],
|
|
14377
|
-
blockedGate: "final-review",
|
|
14378
|
-
blockedReason: reason,
|
|
14379
|
-
offendingPaths: [],
|
|
14380
|
-
prepare: prepareResult,
|
|
14381
|
-
start: startResult
|
|
14382
|
-
};
|
|
14383
|
-
}
|
|
14384
|
-
const targetConfig = options.config?.targets?.find(
|
|
14385
|
-
(t) => t.name === options.targetName
|
|
14692
|
+
if (existingRecord.record?.mode === "local") {
|
|
14693
|
+
const runnableIssues = await getRunnableLocalIssues(
|
|
14694
|
+
prdRef,
|
|
14695
|
+
options.repoRoot
|
|
14386
14696
|
);
|
|
14387
|
-
|
|
14388
|
-
|
|
14389
|
-
repoRoot: options.repoRoot,
|
|
14390
|
-
verificationCommands
|
|
14391
|
-
});
|
|
14392
|
-
if (!localResult.ok) {
|
|
14393
|
-
const reason = localResult.message ?? "Local Final Review blocked.";
|
|
14394
|
-
writePrdRunRecord(options.repoRoot, {
|
|
14395
|
-
prdRef,
|
|
14396
|
-
status: "blocked",
|
|
14397
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14398
|
-
blockedGate: "final-review",
|
|
14399
|
-
blockedReason: reason,
|
|
14400
|
-
diagnostics: [reason],
|
|
14401
|
-
targetName: options.targetName,
|
|
14402
|
-
offendingPaths: []
|
|
14403
|
-
});
|
|
14404
|
-
return {
|
|
14405
|
-
prdRef,
|
|
14406
|
-
status: "blocked",
|
|
14407
|
-
attempted,
|
|
14408
|
-
skipped: [
|
|
14409
|
-
...skipped.includes("prepare") ? ["prepare"] : [],
|
|
14410
|
-
...skipped.includes("start") ? ["queue"] : [],
|
|
14411
|
-
"reconcile"
|
|
14412
|
-
],
|
|
14413
|
-
resumed,
|
|
14414
|
-
diagnostics: [reason],
|
|
14415
|
-
blockedGate: "final-review",
|
|
14416
|
-
blockedReason: reason,
|
|
14417
|
-
offendingPaths: [],
|
|
14418
|
-
prepare: prepareResult,
|
|
14419
|
-
start: startResult
|
|
14420
|
-
};
|
|
14421
|
-
}
|
|
14422
|
-
if (localResult.verdict === "blocked" || localResult.verdict === "needs_human_review") {
|
|
14423
|
-
const reason = localResult.message ?? `Local Final Review verdict: ${localResult.verdict}`;
|
|
14424
|
-
writePrdRunRecord(options.repoRoot, {
|
|
14425
|
-
prdRef,
|
|
14426
|
-
status: "blocked",
|
|
14427
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14428
|
-
blockedGate: "final-review",
|
|
14429
|
-
blockedReason: reason,
|
|
14430
|
-
diagnostics: [reason],
|
|
14431
|
-
targetName: options.targetName,
|
|
14432
|
-
offendingPaths: []
|
|
14433
|
-
});
|
|
14697
|
+
if (runnableIssues.length > 0) {
|
|
14698
|
+
const reason = `Config-local Final Review blocked: Queue not drained (${runnableIssues.length} runnable Issues remain).`;
|
|
14434
14699
|
return {
|
|
14435
14700
|
prdRef,
|
|
14436
14701
|
status: "blocked",
|
|
14437
14702
|
attempted,
|
|
14438
|
-
skipped: [
|
|
14439
|
-
...skipped.includes("prepare") ? ["prepare"] : [],
|
|
14440
|
-
...skipped.includes("start") ? ["queue"] : [],
|
|
14441
|
-
"reconcile"
|
|
14442
|
-
],
|
|
14703
|
+
skipped: ["start", "queue", "reconcile"],
|
|
14443
14704
|
resumed,
|
|
14444
14705
|
diagnostics: [reason],
|
|
14445
14706
|
blockedGate: "final-review",
|
|
14446
14707
|
blockedReason: reason,
|
|
14447
14708
|
offendingPaths: [],
|
|
14448
14709
|
prepare: prepareResult,
|
|
14449
|
-
start: startResult
|
|
14450
|
-
|
|
14451
|
-
}
|
|
14452
|
-
let retouchMergeCommit;
|
|
14453
|
-
let changedPaths;
|
|
14454
|
-
if (localResult.verdict === "pass_with_retouch") {
|
|
14455
|
-
try {
|
|
14456
|
-
const evidence = await squashFinalReviewRetouch(
|
|
14457
|
-
prdRef,
|
|
14458
|
-
options.repoRoot
|
|
14459
|
-
);
|
|
14460
|
-
if (evidence) {
|
|
14461
|
-
retouchMergeCommit = evidence.mergeCommit;
|
|
14462
|
-
changedPaths = evidence.changedPaths;
|
|
14463
|
-
}
|
|
14464
|
-
} catch (error) {
|
|
14465
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
14466
|
-
writePrdRunRecord(options.repoRoot, {
|
|
14710
|
+
start: startResult,
|
|
14711
|
+
finalReview: {
|
|
14467
14712
|
prdRef,
|
|
14468
14713
|
status: "blocked",
|
|
14469
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14470
14714
|
blockedGate: "final-review",
|
|
14471
14715
|
blockedReason: reason,
|
|
14472
14716
|
diagnostics: [reason],
|
|
14473
|
-
targetName: options.targetName,
|
|
14474
14717
|
offendingPaths: []
|
|
14475
|
-
}
|
|
14476
|
-
|
|
14477
|
-
prdRef,
|
|
14478
|
-
status: "blocked",
|
|
14479
|
-
attempted,
|
|
14480
|
-
skipped: [
|
|
14481
|
-
...skipped.includes("prepare") ? ["prepare"] : [],
|
|
14482
|
-
...skipped.includes("start") ? ["queue"] : [],
|
|
14483
|
-
"reconcile"
|
|
14484
|
-
],
|
|
14485
|
-
resumed,
|
|
14486
|
-
diagnostics: [reason],
|
|
14487
|
-
blockedGate: "final-review",
|
|
14488
|
-
blockedReason: reason,
|
|
14489
|
-
offendingPaths: [],
|
|
14490
|
-
prepare: prepareResult,
|
|
14491
|
-
start: startResult
|
|
14492
|
-
};
|
|
14493
|
-
}
|
|
14718
|
+
}
|
|
14719
|
+
};
|
|
14494
14720
|
}
|
|
14495
|
-
const receipt = {
|
|
14496
|
-
status: "final_reviewed",
|
|
14497
|
-
targetName: options.targetName,
|
|
14498
|
-
prdBranch: `local/${prdRef}`,
|
|
14499
|
-
mergeBase: localResult.receipt?.mergeBase,
|
|
14500
|
-
diagnostics: [],
|
|
14501
|
-
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14502
|
-
verdict: localResult.verdict ?? "pass_no_changes",
|
|
14503
|
-
retouchMergeCommit,
|
|
14504
|
-
changedPaths
|
|
14505
|
-
};
|
|
14506
|
-
const existingRecord2 = readPrdRun(options.repoRoot, prdRef);
|
|
14507
|
-
writePrdRunRecord(options.repoRoot, {
|
|
14508
|
-
prdRef,
|
|
14509
|
-
status: "final_reviewed",
|
|
14510
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14511
|
-
targetName: options.targetName,
|
|
14512
|
-
manifestPath: existingRecord2.record?.manifestPath,
|
|
14513
|
-
planning: existingRecord2.record?.planning,
|
|
14514
|
-
start: existingRecord2.record?.start,
|
|
14515
|
-
finalReview: receipt
|
|
14516
|
-
});
|
|
14517
|
-
finalReviewResult = {
|
|
14518
|
-
prdRef,
|
|
14519
|
-
status: "final_reviewed",
|
|
14520
|
-
finalReview: receipt,
|
|
14521
|
-
diagnostics: localResult.message ? [localResult.message] : []
|
|
14522
|
-
};
|
|
14523
|
-
diagnostics.push(...localResult.message ? [localResult.message] : []);
|
|
14524
|
-
} else {
|
|
14525
|
-
finalReviewResult = await runPrdRunFinalReviewCommand({
|
|
14526
|
-
repoRoot: options.repoRoot,
|
|
14527
|
-
prdRef,
|
|
14528
|
-
targetName: options.targetName,
|
|
14529
|
-
autoMerge: options.autoMerge,
|
|
14530
|
-
issueProvider: options.issueProvider,
|
|
14531
|
-
prProvider: options.prProvider,
|
|
14532
|
-
executionProvider: options.executionProvider,
|
|
14533
|
-
config: options.config,
|
|
14534
|
-
logger: options.logger
|
|
14535
|
-
});
|
|
14536
14721
|
}
|
|
14722
|
+
finalReviewResult = await runPrdRunFinalReviewCommand({
|
|
14723
|
+
repoRoot: options.repoRoot,
|
|
14724
|
+
prdRef,
|
|
14725
|
+
targetName: options.targetName,
|
|
14726
|
+
autoMerge: options.autoMerge,
|
|
14727
|
+
issueProvider: options.issueProvider,
|
|
14728
|
+
prProvider: options.prProvider,
|
|
14729
|
+
executionProvider: options.executionProvider,
|
|
14730
|
+
config: options.config,
|
|
14731
|
+
logger: options.logger
|
|
14732
|
+
});
|
|
14537
14733
|
const skippedAfterFr = [
|
|
14538
14734
|
...skipped.includes("prepare") ? ["prepare"] : [],
|
|
14539
14735
|
...skipped.includes("start") ? ["queue"] : [],
|
|
@@ -14603,6 +14799,28 @@ async function runPrdRunLaunchCommand(options) {
|
|
|
14603
14799
|
finalReview: finalReviewResult
|
|
14604
14800
|
};
|
|
14605
14801
|
}
|
|
14802
|
+
if (prdRecord.record?.mode === "local") {
|
|
14803
|
+
const dualCheck = await verifyLocalDualFinalReviewReceipts(
|
|
14804
|
+
options.repoRoot,
|
|
14805
|
+
prdRef
|
|
14806
|
+
);
|
|
14807
|
+
if (!dualCheck.ok) {
|
|
14808
|
+
return {
|
|
14809
|
+
prdRef,
|
|
14810
|
+
status: "blocked",
|
|
14811
|
+
attempted,
|
|
14812
|
+
skipped: [...skipped],
|
|
14813
|
+
resumed,
|
|
14814
|
+
diagnostics: dualCheck.diagnostics,
|
|
14815
|
+
blockedGate: "reconciliation",
|
|
14816
|
+
blockedReason: dualCheck.reason,
|
|
14817
|
+
offendingPaths: [],
|
|
14818
|
+
prepare: prepareResult,
|
|
14819
|
+
start: startResult,
|
|
14820
|
+
finalReview: finalReviewResult
|
|
14821
|
+
};
|
|
14822
|
+
}
|
|
14823
|
+
}
|
|
14606
14824
|
const localResult = await runLocalReconciliation(prdRef, {
|
|
14607
14825
|
repoRoot: options.repoRoot
|
|
14608
14826
|
});
|
|
@@ -21169,11 +21387,11 @@ function createCliProgram(version) {
|
|
|
21169
21387
|
return program;
|
|
21170
21388
|
}
|
|
21171
21389
|
async function resolveCliVersion() {
|
|
21172
|
-
if (isPackageVersion("0.0.0-next-
|
|
21173
|
-
return "0.0.0-next-
|
|
21390
|
+
if (isPackageVersion("0.0.0-next-20260609130908")) {
|
|
21391
|
+
return "0.0.0-next-20260609130908";
|
|
21174
21392
|
}
|
|
21175
|
-
if (isReleaseVersion("0.0.0-next-
|
|
21176
|
-
return "0.0.0-next-
|
|
21393
|
+
if (isReleaseVersion("0.0.0-next-20260609130908")) {
|
|
21394
|
+
return "0.0.0-next-20260609130908";
|
|
21177
21395
|
}
|
|
21178
21396
|
try {
|
|
21179
21397
|
const root = repoRoot();
|