@pourkit/cli 0.0.0-next-20260623054630 → 0.0.0-next-20260625065443
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 +994 -399
- package/dist/cli.js.map +1 -1
- package/dist/e2e/run-live-e2e.js +13 -2
- package/dist/e2e/run-live-e2e.js.map +1 -1
- package/dist/managed/skills/grill-with-docs/SKILL.md +34 -1
- package/dist/managed/skills/to-issues/SKILL.md +2 -0
- package/dist/managed/skills/to-oneshot/SKILL.md +5 -5
- package/dist/managed/skills/to-prd/SKILL.md +16 -9
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5082,7 +5082,7 @@ Before handoff, run: pourkit validate-artifact finalizer ${artifactPathInWorktre
|
|
|
5082
5082
|
|
|
5083
5083
|
// issues/issue-final-review.ts
|
|
5084
5084
|
import { existsSync as existsSync11, readFileSync as readFileSync12 } from "fs";
|
|
5085
|
-
import { isAbsolute as isAbsolute3, join as join11 } from "path";
|
|
5085
|
+
import { isAbsolute as isAbsolute3, join as join11, relative as relative2, sep as sep2 } from "path";
|
|
5086
5086
|
init_common();
|
|
5087
5087
|
var ISSUE_FINAL_REVIEW_ARTIFACT_PATH = join11(
|
|
5088
5088
|
".pourkit",
|
|
@@ -5138,6 +5138,7 @@ async function runIssueFinalReview(options) {
|
|
|
5138
5138
|
repoRoot: repoRoot2,
|
|
5139
5139
|
promptTemplate: agent.promptTemplate,
|
|
5140
5140
|
validationCommand: `pourkit validate-artifact issue-final-review ${artifactPathInWorktree} --issue-number ${issue.number} --branch-name ${builderBranch} --base-ref origin/${target.baseBranch}`,
|
|
5141
|
+
worktreePath,
|
|
5141
5142
|
reviewArtifactPath: options.reviewArtifactPath,
|
|
5142
5143
|
reviewVerdict: options.reviewVerdict
|
|
5143
5144
|
});
|
|
@@ -5347,6 +5348,7 @@ function loadIssueFinalReviewPrompt(options) {
|
|
|
5347
5348
|
repoRoot: repoRoot2,
|
|
5348
5349
|
promptTemplate,
|
|
5349
5350
|
validationCommand,
|
|
5351
|
+
worktreePath,
|
|
5350
5352
|
reviewArtifactPath,
|
|
5351
5353
|
reviewVerdict
|
|
5352
5354
|
} = options;
|
|
@@ -5385,11 +5387,12 @@ Read the selected issue requirements, planning context (including plan and PRD c
|
|
|
5385
5387
|
- If validation fails, fix the artifact or safely retouch the worktree as needed, then rerun the same command.
|
|
5386
5388
|
- Do not finish until the validation command passes.`);
|
|
5387
5389
|
if (reviewVerdict) {
|
|
5390
|
+
const reviewArtifactPathForPrompt = reviewArtifactPath ? formatReviewArtifactPathForPrompt(worktreePath, reviewArtifactPath) : reviewArtifactPath;
|
|
5388
5391
|
prompt += `
|
|
5389
5392
|
|
|
5390
5393
|
## Prior Review Context
|
|
5391
5394
|
|
|
5392
|
-
- Reviewer Artifact Path: ${
|
|
5395
|
+
- Reviewer Artifact Path: ${reviewArtifactPathForPrompt}
|
|
5393
5396
|
- Prior Review Verdict: ${reviewVerdict}`;
|
|
5394
5397
|
if (reviewVerdict === "PASS_WITH_NOTES") {
|
|
5395
5398
|
prompt += `
|
|
@@ -5398,6 +5401,14 @@ Read the selected issue requirements, planning context (including plan and PRD c
|
|
|
5398
5401
|
}
|
|
5399
5402
|
return prompt;
|
|
5400
5403
|
}
|
|
5404
|
+
function formatReviewArtifactPathForPrompt(worktreePath, reviewArtifactPath) {
|
|
5405
|
+
if (!isAbsolute3(reviewArtifactPath)) return reviewArtifactPath;
|
|
5406
|
+
const relativePath = relative2(worktreePath, reviewArtifactPath);
|
|
5407
|
+
if (relativePath && relativePath !== ".." && !relativePath.startsWith(`..${sep2}`) && !isAbsolute3(relativePath)) {
|
|
5408
|
+
return relativePath.replace(/\\/g, "/");
|
|
5409
|
+
}
|
|
5410
|
+
return reviewArtifactPath;
|
|
5411
|
+
}
|
|
5401
5412
|
|
|
5402
5413
|
// pr/pr-body.ts
|
|
5403
5414
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -7401,74 +7412,244 @@ import {
|
|
|
7401
7412
|
writeFileSync as writeFileSync4
|
|
7402
7413
|
} from "fs";
|
|
7403
7414
|
import { join as join15 } from "path";
|
|
7415
|
+
import { z as z2 } from "zod";
|
|
7416
|
+
|
|
7417
|
+
// prd-run/repair-guidance.ts
|
|
7404
7418
|
import { z } from "zod";
|
|
7419
|
+
var PrdRunRepairAttemptSchema = z.object({
|
|
7420
|
+
attemptedAt: z.string().min(1),
|
|
7421
|
+
outcome: z.enum(["blocked", "projection-failed", "unsupported-state"]),
|
|
7422
|
+
failureCode: z.string().min(1),
|
|
7423
|
+
summary: z.string().min(1)
|
|
7424
|
+
}).strict();
|
|
7425
|
+
var PrdRunRepairGuidanceSchema = z.object({
|
|
7426
|
+
createdAt: z.string().min(1),
|
|
7427
|
+
updatedAt: z.string().min(1),
|
|
7428
|
+
blockedGate: z.enum([
|
|
7429
|
+
"receipt-check",
|
|
7430
|
+
"branch-state",
|
|
7431
|
+
"git",
|
|
7432
|
+
"queue",
|
|
7433
|
+
"final-review"
|
|
7434
|
+
]),
|
|
7435
|
+
blockedStage: z.string().min(1),
|
|
7436
|
+
failureCode: z.string().regex(
|
|
7437
|
+
/^[a-z][a-z0-9-]*$/,
|
|
7438
|
+
"failureCode must be kebab-case (lowercase letters, digits, hyphens)"
|
|
7439
|
+
),
|
|
7440
|
+
humanReadableReason: z.string().min(1),
|
|
7441
|
+
repairability: z.enum([
|
|
7442
|
+
"automatic-retry-safe",
|
|
7443
|
+
"operator-action",
|
|
7444
|
+
"unsupported-state"
|
|
7445
|
+
]),
|
|
7446
|
+
nextAction: z.string().min(1),
|
|
7447
|
+
nextRecommendedCommand: z.string().min(1),
|
|
7448
|
+
diagnostics: z.array(z.string()).optional(),
|
|
7449
|
+
offendingPaths: z.array(z.string()).optional(),
|
|
7450
|
+
issue: z.object({
|
|
7451
|
+
number: z.number().int().positive(),
|
|
7452
|
+
title: z.string().optional(),
|
|
7453
|
+
branch: z.string().optional(),
|
|
7454
|
+
worktreePath: z.string().optional()
|
|
7455
|
+
}).strict().optional(),
|
|
7456
|
+
pr: z.object({
|
|
7457
|
+
number: z.number().int().positive().optional(),
|
|
7458
|
+
url: z.string().url().optional()
|
|
7459
|
+
}).strict().optional(),
|
|
7460
|
+
attemptHistory: z.array(PrdRunRepairAttemptSchema).optional(),
|
|
7461
|
+
targetName: z.string().min(1).optional(),
|
|
7462
|
+
baseBranch: z.string().min(1).optional()
|
|
7463
|
+
}).strict();
|
|
7464
|
+
function buildPrdRunRepairGuidance(input) {
|
|
7465
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7466
|
+
return PrdRunRepairGuidanceSchema.parse({
|
|
7467
|
+
createdAt: now,
|
|
7468
|
+
updatedAt: now,
|
|
7469
|
+
blockedGate: input.blockedGate,
|
|
7470
|
+
blockedStage: input.blockedStage,
|
|
7471
|
+
failureCode: input.failureCode,
|
|
7472
|
+
humanReadableReason: input.humanReadableReason,
|
|
7473
|
+
repairability: input.repairability,
|
|
7474
|
+
nextAction: input.nextAction,
|
|
7475
|
+
nextRecommendedCommand: input.nextRecommendedCommand,
|
|
7476
|
+
diagnostics: input.diagnostics,
|
|
7477
|
+
offendingPaths: input.offendingPaths,
|
|
7478
|
+
issue: input.issue,
|
|
7479
|
+
pr: input.pr,
|
|
7480
|
+
targetName: input.targetName,
|
|
7481
|
+
baseBranch: input.baseBranch,
|
|
7482
|
+
attemptHistory: void 0
|
|
7483
|
+
});
|
|
7484
|
+
}
|
|
7485
|
+
function appendPrdRunRepairAttempt(guidance, attempt) {
|
|
7486
|
+
const newAttempt = {
|
|
7487
|
+
attemptedAt: attempt.attemptedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
7488
|
+
outcome: attempt.outcome,
|
|
7489
|
+
failureCode: attempt.failureCode,
|
|
7490
|
+
summary: attempt.summary
|
|
7491
|
+
};
|
|
7492
|
+
const history = [...guidance.attemptHistory ?? [], newAttempt].slice(-5);
|
|
7493
|
+
return PrdRunRepairGuidanceSchema.parse({
|
|
7494
|
+
...guidance,
|
|
7495
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7496
|
+
attemptHistory: history
|
|
7497
|
+
});
|
|
7498
|
+
}
|
|
7499
|
+
function validateActivePrdRunRepairGuidance(record) {
|
|
7500
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7501
|
+
if (record.repairGuidance) {
|
|
7502
|
+
const parsed = PrdRunRepairGuidanceSchema.safeParse(record.repairGuidance);
|
|
7503
|
+
if (parsed.success) {
|
|
7504
|
+
return { ok: true, guidance: parsed.data };
|
|
7505
|
+
}
|
|
7506
|
+
return {
|
|
7507
|
+
ok: false,
|
|
7508
|
+
guidance: {
|
|
7509
|
+
createdAt: now,
|
|
7510
|
+
updatedAt: now,
|
|
7511
|
+
blockedGate: record.blockedGate ?? "queue",
|
|
7512
|
+
blockedStage: "unknown",
|
|
7513
|
+
failureCode: "malformed-repair-guidance",
|
|
7514
|
+
humanReadableReason: "Repair guidance state is malformed or invalid. Inspect the PRD Run record.",
|
|
7515
|
+
repairability: "unsupported-state",
|
|
7516
|
+
nextAction: "inspect-prd-run-state",
|
|
7517
|
+
nextRecommendedCommand: `pourkit prd-run status ${record.prdRef}`,
|
|
7518
|
+
diagnostics: [
|
|
7519
|
+
`Validation error: ${parsed.error?.message ?? "Unknown schema error"}`
|
|
7520
|
+
]
|
|
7521
|
+
}
|
|
7522
|
+
};
|
|
7523
|
+
}
|
|
7524
|
+
return {
|
|
7525
|
+
ok: false,
|
|
7526
|
+
guidance: {
|
|
7527
|
+
createdAt: now,
|
|
7528
|
+
updatedAt: now,
|
|
7529
|
+
blockedGate: record.blockedGate ?? "queue",
|
|
7530
|
+
blockedStage: "unknown",
|
|
7531
|
+
failureCode: "missing-repair-guidance",
|
|
7532
|
+
humanReadableReason: "No active repair guidance found for a blocked or unresolved record.",
|
|
7533
|
+
repairability: "unsupported-state",
|
|
7534
|
+
nextAction: "inspect-prd-run-state",
|
|
7535
|
+
nextRecommendedCommand: `pourkit prd-run status ${record.prdRef}`,
|
|
7536
|
+
diagnostics: record.diagnostics ? [...record.diagnostics] : []
|
|
7537
|
+
}
|
|
7538
|
+
};
|
|
7539
|
+
}
|
|
7540
|
+
function renderPrdRunRepairGuidance(guidance) {
|
|
7541
|
+
const lines = [];
|
|
7542
|
+
lines.push(`Blocked Gate: ${guidance.blockedGate}`);
|
|
7543
|
+
lines.push(`Blocked Stage: ${guidance.blockedStage}`);
|
|
7544
|
+
lines.push(`Failure Code: ${guidance.failureCode}`);
|
|
7545
|
+
lines.push(`Reason: ${guidance.humanReadableReason}`);
|
|
7546
|
+
lines.push(`Repairability: ${guidance.repairability}`);
|
|
7547
|
+
lines.push(`Next Action: ${guidance.nextAction}`);
|
|
7548
|
+
lines.push(`Command: ${guidance.nextRecommendedCommand}`);
|
|
7549
|
+
if (guidance.targetName) lines.push(`Target: ${guidance.targetName}`);
|
|
7550
|
+
if (guidance.baseBranch) lines.push(`Base: ${guidance.baseBranch}`);
|
|
7551
|
+
if (guidance.issue) {
|
|
7552
|
+
const issueLine = `Issue: #${guidance.issue.number}${guidance.issue.title ? ` - ${guidance.issue.title}` : ""}`;
|
|
7553
|
+
lines.push(issueLine);
|
|
7554
|
+
if (guidance.issue.branch) lines.push(` Branch: ${guidance.issue.branch}`);
|
|
7555
|
+
if (guidance.issue.worktreePath)
|
|
7556
|
+
lines.push(` Worktree: ${guidance.issue.worktreePath}`);
|
|
7557
|
+
}
|
|
7558
|
+
if (guidance.pr) {
|
|
7559
|
+
if (guidance.pr.url) lines.push(`PR: ${guidance.pr.url}`);
|
|
7560
|
+
else if (guidance.pr.number) lines.push(`PR: #${guidance.pr.number}`);
|
|
7561
|
+
}
|
|
7562
|
+
if (guidance.diagnostics && guidance.diagnostics.length > 0) {
|
|
7563
|
+
lines.push("Diagnostics:");
|
|
7564
|
+
for (const d of guidance.diagnostics) {
|
|
7565
|
+
lines.push(` - ${d}`);
|
|
7566
|
+
}
|
|
7567
|
+
}
|
|
7568
|
+
if (guidance.offendingPaths && guidance.offendingPaths.length > 0) {
|
|
7569
|
+
lines.push("Offending Paths:");
|
|
7570
|
+
for (const p of guidance.offendingPaths) {
|
|
7571
|
+
lines.push(` - ${p}`);
|
|
7572
|
+
}
|
|
7573
|
+
}
|
|
7574
|
+
if (guidance.attemptHistory && guidance.attemptHistory.length > 0) {
|
|
7575
|
+
const latest = guidance.attemptHistory[guidance.attemptHistory.length - 1];
|
|
7576
|
+
lines.push(`Latest Attempt: ${latest.outcome} - ${latest.summary}`);
|
|
7577
|
+
if (guidance.attemptHistory.length > 1) {
|
|
7578
|
+
lines.push(`Total Attempts: ${guidance.attemptHistory.length}`);
|
|
7579
|
+
}
|
|
7580
|
+
}
|
|
7581
|
+
return lines;
|
|
7582
|
+
}
|
|
7583
|
+
|
|
7584
|
+
// prd-run/state.ts
|
|
7405
7585
|
var PRD_RUN_STATE_DIR = ".pourkit/prd-runs";
|
|
7406
|
-
var PrdRunRecordSchema =
|
|
7407
|
-
prdRef:
|
|
7586
|
+
var PrdRunRecordSchema = z2.object({
|
|
7587
|
+
prdRef: z2.string().regex(
|
|
7408
7588
|
/^PRD-\d{4}$/,
|
|
7409
7589
|
"PRD ref must use four-digit format (e.g., PRD-0052)"
|
|
7410
7590
|
),
|
|
7411
|
-
status:
|
|
7591
|
+
status: z2.enum([
|
|
7412
7592
|
"blocked",
|
|
7413
7593
|
"starting",
|
|
7414
7594
|
"running",
|
|
7415
7595
|
"drained",
|
|
7416
7596
|
"completed_prd_branch"
|
|
7417
7597
|
]),
|
|
7418
|
-
updatedAt:
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7598
|
+
updatedAt: z2.string().min(1),
|
|
7599
|
+
repairGuidance: PrdRunRepairGuidanceSchema.optional(),
|
|
7600
|
+
blockedGate: z2.enum(["receipt-check", "branch-state", "git", "queue", "final-review"]).optional(),
|
|
7601
|
+
targetName: z2.string().min(1).optional(),
|
|
7602
|
+
prdBranch: z2.string().min(1).optional(),
|
|
7603
|
+
blockedReason: z2.string().min(1).optional(),
|
|
7604
|
+
diagnostics: z2.array(z2.string()).optional(),
|
|
7605
|
+
offendingPaths: z2.array(z2.string()).optional(),
|
|
7606
|
+
start: z2.object({
|
|
7607
|
+
status: z2.enum(["started", "succeeded", "adopted", "reused"]),
|
|
7608
|
+
targetName: z2.string().min(1),
|
|
7609
|
+
prdBranch: z2.string().min(1),
|
|
7610
|
+
startBaseBranch: z2.string().min(1),
|
|
7611
|
+
startBaseCommit: z2.string().min(1).optional(),
|
|
7612
|
+
branchAction: z2.enum(["created", "reused", "adopted"]).optional(),
|
|
7613
|
+
startedAt: z2.string().min(1).optional(),
|
|
7614
|
+
queueStartedAt: z2.string().min(1).optional(),
|
|
7615
|
+
queueDrainedAt: z2.string().min(1).optional(),
|
|
7616
|
+
queueProcessedCount: z2.number().int().nonnegative().optional(),
|
|
7617
|
+
queueCommand: z2.literal("queue-run").optional(),
|
|
7618
|
+
refreshReceipts: z2.tuple([]).optional()
|
|
7438
7619
|
}).strict().optional(),
|
|
7439
|
-
finalReview:
|
|
7440
|
-
status:
|
|
7620
|
+
finalReview: z2.object({
|
|
7621
|
+
status: z2.enum([
|
|
7441
7622
|
"started",
|
|
7442
7623
|
"succeeded",
|
|
7443
7624
|
"blocked",
|
|
7444
7625
|
"needs_human_review",
|
|
7445
7626
|
"final_reviewed"
|
|
7446
7627
|
]),
|
|
7447
|
-
targetName:
|
|
7448
|
-
prdBranch:
|
|
7449
|
-
mergeBase:
|
|
7450
|
-
verdict:
|
|
7628
|
+
targetName: z2.string().min(1),
|
|
7629
|
+
prdBranch: z2.string().min(1),
|
|
7630
|
+
mergeBase: z2.string().min(1).optional(),
|
|
7631
|
+
verdict: z2.enum([
|
|
7451
7632
|
"pass_no_changes",
|
|
7452
7633
|
"pass_with_retouch",
|
|
7453
7634
|
"needs_human_review",
|
|
7454
7635
|
"blocked"
|
|
7455
7636
|
]).optional(),
|
|
7456
|
-
artifactPath:
|
|
7457
|
-
diagnostics:
|
|
7458
|
-
reviewedAt:
|
|
7459
|
-
retouchPrNumber:
|
|
7460
|
-
retouchPrUrl:
|
|
7461
|
-
retouchMergeCommit:
|
|
7462
|
-
autoMerge:
|
|
7463
|
-
changedPaths:
|
|
7637
|
+
artifactPath: z2.string().min(1).optional(),
|
|
7638
|
+
diagnostics: z2.array(z2.string()).optional(),
|
|
7639
|
+
reviewedAt: z2.string().min(1).optional(),
|
|
7640
|
+
retouchPrNumber: z2.number().int().positive().optional(),
|
|
7641
|
+
retouchPrUrl: z2.string().url().optional(),
|
|
7642
|
+
retouchMergeCommit: z2.string().min(1).optional(),
|
|
7643
|
+
autoMerge: z2.boolean().optional(),
|
|
7644
|
+
changedPaths: z2.array(z2.string()).optional()
|
|
7464
7645
|
}).strict().optional(),
|
|
7465
|
-
scopeChanges:
|
|
7466
|
-
|
|
7467
|
-
issueNumber:
|
|
7468
|
-
decision:
|
|
7469
|
-
reason:
|
|
7470
|
-
acceptedBy:
|
|
7471
|
-
acceptedAt:
|
|
7646
|
+
scopeChanges: z2.array(
|
|
7647
|
+
z2.object({
|
|
7648
|
+
issueNumber: z2.number().int().positive(),
|
|
7649
|
+
decision: z2.literal("accepted_scope_change"),
|
|
7650
|
+
reason: z2.string().min(1),
|
|
7651
|
+
acceptedBy: z2.string().min(1),
|
|
7652
|
+
acceptedAt: z2.string().min(1)
|
|
7472
7653
|
}).strict()
|
|
7473
7654
|
).optional()
|
|
7474
7655
|
}).strict();
|
|
@@ -7505,6 +7686,26 @@ function readPrdRun(repoRoot2, prdRef) {
|
|
|
7505
7686
|
}
|
|
7506
7687
|
} catch {
|
|
7507
7688
|
}
|
|
7689
|
+
try {
|
|
7690
|
+
const raw = JSON.parse(readFileSync15(recordPath, "utf-8"));
|
|
7691
|
+
if (raw && typeof raw === "object" && raw.status === "blocked" && raw.repairGuidance !== void 0) {
|
|
7692
|
+
const { repairGuidance: _unused, ...rawWithoutGuidance } = raw;
|
|
7693
|
+
const baseRecord = PrdRunRecordSchema.omit({
|
|
7694
|
+
repairGuidance: true
|
|
7695
|
+
}).parse(rawWithoutGuidance);
|
|
7696
|
+
return {
|
|
7697
|
+
record: {
|
|
7698
|
+
...baseRecord,
|
|
7699
|
+
repairGuidance: raw.repairGuidance
|
|
7700
|
+
},
|
|
7701
|
+
diagnostics: [
|
|
7702
|
+
`Repair guidance validation failed at ${recordPath}`,
|
|
7703
|
+
error instanceof Error ? error.message : String(error)
|
|
7704
|
+
]
|
|
7705
|
+
};
|
|
7706
|
+
}
|
|
7707
|
+
} catch {
|
|
7708
|
+
}
|
|
7508
7709
|
return {
|
|
7509
7710
|
record: null,
|
|
7510
7711
|
diagnostics: [
|
|
@@ -7541,14 +7742,11 @@ function listPrdRuns(repoRoot2) {
|
|
|
7541
7742
|
}
|
|
7542
7743
|
function writePrdRunRecord(repoRoot2, record) {
|
|
7543
7744
|
const normalized = normalizePrdRunRef(record.prdRef);
|
|
7745
|
+
const parsed = PrdRunRecordSchema.parse({ ...record, prdRef: normalized });
|
|
7544
7746
|
const stateDir = join15(repoRoot2, PRD_RUN_STATE_DIR);
|
|
7545
7747
|
const recordPath = getRecordPath(repoRoot2, normalized);
|
|
7546
7748
|
mkdirSync7(stateDir, { recursive: true });
|
|
7547
|
-
writeFileSync4(
|
|
7548
|
-
recordPath,
|
|
7549
|
-
JSON.stringify({ ...record, prdRef: normalized }, null, 2),
|
|
7550
|
-
"utf-8"
|
|
7551
|
-
);
|
|
7749
|
+
writeFileSync4(recordPath, JSON.stringify(parsed, null, 2), "utf-8");
|
|
7552
7750
|
}
|
|
7553
7751
|
function getRecordPath(repoRoot2, prdRef) {
|
|
7554
7752
|
return join15(
|
|
@@ -7904,24 +8102,45 @@ function runOneQueueIssueEffect(options) {
|
|
|
7904
8102
|
prdRef
|
|
7905
8103
|
} = options;
|
|
7906
8104
|
return Effect9.gen(function* () {
|
|
7907
|
-
const
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
8105
|
+
const resumeIssueNumber = options.queueRunContext?.resumeIssueNumber;
|
|
8106
|
+
let selectedIssue;
|
|
8107
|
+
if (resumeIssueNumber) {
|
|
8108
|
+
const fetched = yield* Effect9.tryPromise({
|
|
8109
|
+
try: () => issueProvider.fetchIssue(resumeIssueNumber),
|
|
8110
|
+
catch: (e) => {
|
|
8111
|
+
if (e instanceof Error) {
|
|
8112
|
+
return new QueueProviderError(
|
|
8113
|
+
`Failed to fetch resume issue #${resumeIssueNumber}: ${e.message}`
|
|
8114
|
+
);
|
|
8115
|
+
}
|
|
8116
|
+
throw e;
|
|
8117
|
+
}
|
|
8118
|
+
});
|
|
8119
|
+
selectedIssue = fetched;
|
|
8120
|
+
logger.step(
|
|
8121
|
+
"info",
|
|
8122
|
+
`Resuming issue #${selectedIssue.number}: ${selectedIssue.title}`
|
|
8123
|
+
);
|
|
8124
|
+
} else {
|
|
8125
|
+
const outcome = yield* selectNextQueueIssue({
|
|
8126
|
+
config,
|
|
8127
|
+
issueProvider,
|
|
8128
|
+
logger,
|
|
8129
|
+
prdRef
|
|
8130
|
+
});
|
|
8131
|
+
if (!outcome.ok) {
|
|
8132
|
+
return {
|
|
8133
|
+
selected: null,
|
|
8134
|
+
reason: outcome.reason,
|
|
8135
|
+
code: outcome.code
|
|
8136
|
+
};
|
|
8137
|
+
}
|
|
8138
|
+
selectedIssue = outcome.issue;
|
|
7919
8139
|
}
|
|
7920
|
-
const { issue: selected } = outcome;
|
|
7921
8140
|
const baseBranchOverride = options.queueRunContext?.prdBranch;
|
|
7922
8141
|
const runResult = yield* Effect9.tryPromise({
|
|
7923
8142
|
try: () => runIssueCommand({
|
|
7924
|
-
issueNumber:
|
|
8143
|
+
issueNumber: selectedIssue.number,
|
|
7925
8144
|
targetName,
|
|
7926
8145
|
config,
|
|
7927
8146
|
issueProvider,
|
|
@@ -7952,7 +8171,7 @@ function runOneQueueIssueEffect(options) {
|
|
|
7952
8171
|
logger.raw(` PR URL: ${runResult.prUrl}`);
|
|
7953
8172
|
}
|
|
7954
8173
|
logger.raw(` Target: ${runResult.target.name}`);
|
|
7955
|
-
return { selected, runResult };
|
|
8174
|
+
return { selected: selectedIssue, runResult };
|
|
7956
8175
|
});
|
|
7957
8176
|
}
|
|
7958
8177
|
function runQueue(options) {
|
|
@@ -7976,6 +8195,19 @@ function runQueueLoopEffect(options, results) {
|
|
|
7976
8195
|
};
|
|
7977
8196
|
}
|
|
7978
8197
|
const newResults = [...results, outcome];
|
|
8198
|
+
if (options.queueRunContext?.resumeIssueNumber !== void 0) {
|
|
8199
|
+
return {
|
|
8200
|
+
drained: true,
|
|
8201
|
+
processedCount: newResults.length,
|
|
8202
|
+
results: newResults,
|
|
8203
|
+
selected: null,
|
|
8204
|
+
reason: "Resumed issue processed.",
|
|
8205
|
+
code: "drained",
|
|
8206
|
+
allProcessedIssuesFinalizedIntoPrdBranch: Boolean(options.queueRunContext?.prdBranch) && newResults.length > 0 && newResults.every(
|
|
8207
|
+
(result) => result.runResult.publicationStatus === "merged"
|
|
8208
|
+
)
|
|
8209
|
+
};
|
|
8210
|
+
}
|
|
7979
8211
|
const processedIssue = yield* Effect9.tryPromise({
|
|
7980
8212
|
try: () => options.issueProvider.fetchIssue(outcome.selected.number),
|
|
7981
8213
|
catch: (e) => {
|
|
@@ -8021,72 +8253,79 @@ function validatePrdRunStartEvidence(record, context) {
|
|
|
8021
8253
|
if (!record.start) {
|
|
8022
8254
|
return {
|
|
8023
8255
|
ok: false,
|
|
8024
|
-
guidance: {
|
|
8256
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8025
8257
|
blockedGate: "branch-state",
|
|
8026
|
-
|
|
8027
|
-
|
|
8258
|
+
blockedStage: "branch-materialization",
|
|
8259
|
+
failureCode: "missing-start-evidence",
|
|
8260
|
+
humanReadableReason: `PRD Run ${context.prdRef} has no start receipt.`,
|
|
8028
8261
|
repairability: "automatic-retry-safe",
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
}
|
|
8262
|
+
nextAction: "rerun-prd-run-launch",
|
|
8263
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8264
|
+
})
|
|
8032
8265
|
};
|
|
8033
8266
|
}
|
|
8034
8267
|
if (!record.start.startBaseBranch) {
|
|
8035
8268
|
return {
|
|
8036
8269
|
ok: false,
|
|
8037
|
-
guidance: {
|
|
8270
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8038
8271
|
blockedGate: "branch-state",
|
|
8039
|
-
|
|
8040
|
-
|
|
8272
|
+
blockedStage: "branch-materialization",
|
|
8273
|
+
failureCode: "missing-start-base-branch",
|
|
8274
|
+
humanReadableReason: `PRD Run ${context.prdRef} start receipt missing startBaseBranch.`,
|
|
8041
8275
|
repairability: "operator-action",
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
}
|
|
8276
|
+
nextAction: "inspect-and-retry",
|
|
8277
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8278
|
+
})
|
|
8045
8279
|
};
|
|
8046
8280
|
}
|
|
8047
8281
|
if (record.start.startBaseBranch !== context.baseBranch) {
|
|
8048
8282
|
return {
|
|
8049
8283
|
ok: false,
|
|
8050
|
-
guidance: {
|
|
8284
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8051
8285
|
blockedGate: "branch-state",
|
|
8052
|
-
|
|
8053
|
-
|
|
8286
|
+
blockedStage: "branch-materialization",
|
|
8287
|
+
failureCode: "base-mismatch",
|
|
8288
|
+
humanReadableReason: `PRD Run ${context.prdRef} startBaseBranch "${record.start.startBaseBranch}" does not match expected "${context.baseBranch}".`,
|
|
8054
8289
|
repairability: "operator-action",
|
|
8290
|
+
nextAction: "inspect-and-retry",
|
|
8291
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
8055
8292
|
diagnostics: [
|
|
8056
8293
|
`Recorded startBaseBranch: ${record.start.startBaseBranch}`,
|
|
8057
8294
|
`Expected baseBranch: ${context.baseBranch}`
|
|
8058
|
-
]
|
|
8059
|
-
|
|
8060
|
-
}
|
|
8295
|
+
]
|
|
8296
|
+
})
|
|
8061
8297
|
};
|
|
8062
8298
|
}
|
|
8063
8299
|
if (!record.start.prdBranch) {
|
|
8064
8300
|
return {
|
|
8065
8301
|
ok: false,
|
|
8066
|
-
guidance: {
|
|
8302
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8067
8303
|
blockedGate: "branch-state",
|
|
8068
|
-
|
|
8069
|
-
|
|
8304
|
+
blockedStage: "branch-materialization",
|
|
8305
|
+
failureCode: "missing-prd-branch",
|
|
8306
|
+
humanReadableReason: `PRD Run ${context.prdRef} start receipt missing prdBranch.`,
|
|
8070
8307
|
repairability: "operator-action",
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
}
|
|
8308
|
+
nextAction: "inspect-and-retry",
|
|
8309
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8310
|
+
})
|
|
8074
8311
|
};
|
|
8075
8312
|
}
|
|
8076
8313
|
if (record.prdRef !== context.prdRef) {
|
|
8077
8314
|
return {
|
|
8078
8315
|
ok: false,
|
|
8079
|
-
guidance: {
|
|
8316
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8080
8317
|
blockedGate: "branch-state",
|
|
8081
|
-
|
|
8082
|
-
|
|
8318
|
+
blockedStage: "branch-materialization",
|
|
8319
|
+
failureCode: "prd-ref-mismatch",
|
|
8320
|
+
humanReadableReason: `PRD Run prdRef mismatch: "${record.prdRef}" does not match expected "${context.prdRef}".`,
|
|
8083
8321
|
repairability: "operator-action",
|
|
8322
|
+
nextAction: "inspect-and-retry",
|
|
8323
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
8084
8324
|
diagnostics: [
|
|
8085
8325
|
`Recorded prdRef: ${record.prdRef}`,
|
|
8086
8326
|
`Expected prdRef: ${context.prdRef}`
|
|
8087
|
-
]
|
|
8088
|
-
|
|
8089
|
-
}
|
|
8327
|
+
]
|
|
8328
|
+
})
|
|
8090
8329
|
};
|
|
8091
8330
|
}
|
|
8092
8331
|
return { ok: true };
|
|
@@ -8096,95 +8335,104 @@ function validatePrdRunDrainEvidence(record, context) {
|
|
|
8096
8335
|
if (!start) {
|
|
8097
8336
|
return {
|
|
8098
8337
|
ok: false,
|
|
8099
|
-
guidance: {
|
|
8338
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8100
8339
|
blockedGate: "queue",
|
|
8101
|
-
|
|
8102
|
-
|
|
8340
|
+
blockedStage: "queue-drain",
|
|
8341
|
+
failureCode: "missing-drain-evidence",
|
|
8342
|
+
humanReadableReason: `PRD Run ${context.prdRef} has no start receipt for drain validation.`,
|
|
8103
8343
|
repairability: "automatic-retry-safe",
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
}
|
|
8344
|
+
nextAction: "rerun-prd-run-launch",
|
|
8345
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8346
|
+
})
|
|
8107
8347
|
};
|
|
8108
8348
|
}
|
|
8109
8349
|
if (!start.queueStartedAt) {
|
|
8110
8350
|
return {
|
|
8111
8351
|
ok: false,
|
|
8112
|
-
guidance: {
|
|
8352
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8113
8353
|
blockedGate: "queue",
|
|
8114
|
-
|
|
8115
|
-
|
|
8354
|
+
blockedStage: "queue-drain",
|
|
8355
|
+
failureCode: "missing-queue-started-at",
|
|
8356
|
+
humanReadableReason: `PRD Run ${context.prdRef} drain evidence missing queueStartedAt.`,
|
|
8116
8357
|
repairability: "automatic-retry-safe",
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
}
|
|
8358
|
+
nextAction: "rerun-prd-run-launch",
|
|
8359
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8360
|
+
})
|
|
8120
8361
|
};
|
|
8121
8362
|
}
|
|
8122
8363
|
if (start.queueCommand !== "queue-run") {
|
|
8123
8364
|
return {
|
|
8124
8365
|
ok: false,
|
|
8125
|
-
guidance: {
|
|
8366
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8126
8367
|
blockedGate: "queue",
|
|
8127
|
-
|
|
8128
|
-
|
|
8368
|
+
blockedStage: "queue-drain",
|
|
8369
|
+
failureCode: "missing-queue-command",
|
|
8370
|
+
humanReadableReason: `PRD Run ${context.prdRef} drain evidence missing queue-run command.`,
|
|
8129
8371
|
repairability: "automatic-retry-safe",
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
}
|
|
8372
|
+
nextAction: "rerun-prd-run-launch",
|
|
8373
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8374
|
+
})
|
|
8133
8375
|
};
|
|
8134
8376
|
}
|
|
8135
8377
|
if (!start.queueDrainedAt) {
|
|
8136
8378
|
return {
|
|
8137
8379
|
ok: false,
|
|
8138
|
-
guidance: {
|
|
8380
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8139
8381
|
blockedGate: "queue",
|
|
8140
|
-
|
|
8141
|
-
|
|
8382
|
+
blockedStage: "queue-drain",
|
|
8383
|
+
failureCode: "missing-queue-drained-at",
|
|
8384
|
+
humanReadableReason: `PRD Run ${context.prdRef} drain evidence missing queueDrainedAt.`,
|
|
8142
8385
|
repairability: "automatic-retry-safe",
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
}
|
|
8386
|
+
nextAction: "rerun-prd-run-launch",
|
|
8387
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8388
|
+
})
|
|
8146
8389
|
};
|
|
8147
8390
|
}
|
|
8148
8391
|
if (typeof start.queueProcessedCount !== "number") {
|
|
8149
8392
|
return {
|
|
8150
8393
|
ok: false,
|
|
8151
|
-
guidance: {
|
|
8394
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8152
8395
|
blockedGate: "queue",
|
|
8153
|
-
|
|
8154
|
-
|
|
8396
|
+
blockedStage: "queue-drain",
|
|
8397
|
+
failureCode: "missing-queue-processed-count",
|
|
8398
|
+
humanReadableReason: `PRD Run ${context.prdRef} drain evidence missing queueProcessedCount.`,
|
|
8155
8399
|
repairability: "automatic-retry-safe",
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
}
|
|
8400
|
+
nextAction: "rerun-prd-run-launch",
|
|
8401
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8402
|
+
})
|
|
8159
8403
|
};
|
|
8160
8404
|
}
|
|
8161
8405
|
if (start.queueProcessedCount <= 0) {
|
|
8162
8406
|
return {
|
|
8163
8407
|
ok: false,
|
|
8164
|
-
guidance: {
|
|
8408
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8165
8409
|
blockedGate: "queue",
|
|
8166
|
-
|
|
8167
|
-
|
|
8410
|
+
blockedStage: "queue-drain",
|
|
8411
|
+
failureCode: "zero-processed",
|
|
8412
|
+
humanReadableReason: `PRD Run ${context.prdRef} queue drain processed zero issues.`,
|
|
8168
8413
|
repairability: "automatic-retry-safe",
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8414
|
+
nextAction: "rerun-prd-run-launch",
|
|
8415
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
8416
|
+
diagnostics: [`queueProcessedCount: ${start.queueProcessedCount}`]
|
|
8417
|
+
})
|
|
8172
8418
|
};
|
|
8173
8419
|
}
|
|
8174
8420
|
if (start.prdBranch !== context.prdBranch) {
|
|
8175
8421
|
return {
|
|
8176
8422
|
ok: false,
|
|
8177
|
-
guidance: {
|
|
8423
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8178
8424
|
blockedGate: "queue",
|
|
8179
|
-
|
|
8180
|
-
|
|
8425
|
+
blockedStage: "queue-drain",
|
|
8426
|
+
failureCode: "prd-branch-mismatch",
|
|
8427
|
+
humanReadableReason: `PRD Run ${context.prdRef} prdBranch "${start.prdBranch}" does not match expected "${context.prdBranch}".`,
|
|
8181
8428
|
repairability: "operator-action",
|
|
8429
|
+
nextAction: "inspect-and-retry",
|
|
8430
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
8182
8431
|
diagnostics: [
|
|
8183
8432
|
`Recorded prdBranch: ${start.prdBranch}`,
|
|
8184
8433
|
`Expected prdBranch: ${context.prdBranch}`
|
|
8185
|
-
]
|
|
8186
|
-
|
|
8187
|
-
}
|
|
8434
|
+
]
|
|
8435
|
+
})
|
|
8188
8436
|
};
|
|
8189
8437
|
}
|
|
8190
8438
|
return { ok: true };
|
|
@@ -8197,14 +8445,15 @@ function validatePrdRunTerminalEvidence(record, context) {
|
|
|
8197
8445
|
if (context.allChildIssuesFinalizedIntoPrdBranch !== true) {
|
|
8198
8446
|
return {
|
|
8199
8447
|
ok: false,
|
|
8200
|
-
guidance: {
|
|
8448
|
+
guidance: buildPrdRunRepairGuidance({
|
|
8201
8449
|
blockedGate: "queue",
|
|
8202
|
-
|
|
8203
|
-
|
|
8450
|
+
blockedStage: "queue-drain",
|
|
8451
|
+
failureCode: "missing-child-finalization-evidence",
|
|
8452
|
+
humanReadableReason: `PRD Run ${context.prdRef} is missing proof that all child Issues finalized into ${context.prdBranch}.`,
|
|
8204
8453
|
repairability: "operator-action",
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
}
|
|
8454
|
+
nextAction: "inspect-and-retry",
|
|
8455
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
8456
|
+
})
|
|
8208
8457
|
};
|
|
8209
8458
|
}
|
|
8210
8459
|
return { ok: true };
|
|
@@ -8498,10 +8747,11 @@ function buildBlockedOutcome(repoRoot2, prdRef, guidance, targetName) {
|
|
|
8498
8747
|
status: "blocked",
|
|
8499
8748
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8500
8749
|
blockedGate: guidance.blockedGate,
|
|
8501
|
-
blockedReason: guidance.
|
|
8502
|
-
diagnostics: [...guidance.diagnostics
|
|
8503
|
-
offendingPaths: [...guidance.offendingPaths
|
|
8504
|
-
targetName
|
|
8750
|
+
blockedReason: guidance.humanReadableReason,
|
|
8751
|
+
...guidance.diagnostics?.length ? { diagnostics: [...guidance.diagnostics] } : {},
|
|
8752
|
+
...guidance.offendingPaths?.length ? { offendingPaths: [...guidance.offendingPaths] } : {},
|
|
8753
|
+
targetName,
|
|
8754
|
+
repairGuidance: guidance
|
|
8505
8755
|
});
|
|
8506
8756
|
return { kind: "blocked", prdRef, guidance };
|
|
8507
8757
|
}
|
|
@@ -8524,17 +8774,21 @@ function persistStartingPrdRunRecord(repoRoot2, prdRef, existingRecord, start, c
|
|
|
8524
8774
|
start
|
|
8525
8775
|
});
|
|
8526
8776
|
}
|
|
8527
|
-
function blocked(repoRoot2, prdRef, gate, failureCode, reason, diagnostics, targetName) {
|
|
8777
|
+
function blocked(repoRoot2, prdRef, gate, failureCode, reason, diagnostics, targetName, stage, repairability = "operator-action") {
|
|
8528
8778
|
return buildBlockedOutcome(
|
|
8529
8779
|
repoRoot2,
|
|
8530
8780
|
prdRef,
|
|
8531
|
-
{
|
|
8781
|
+
buildPrdRunRepairGuidance({
|
|
8532
8782
|
blockedGate: gate,
|
|
8783
|
+
blockedStage: stage ?? gate,
|
|
8533
8784
|
failureCode,
|
|
8534
|
-
reason,
|
|
8535
|
-
|
|
8536
|
-
repairability: "
|
|
8537
|
-
|
|
8785
|
+
humanReadableReason: reason,
|
|
8786
|
+
repairability,
|
|
8787
|
+
nextAction: repairability === "automatic-retry-safe" ? "rerun-prd-run-launch" : "inspect-and-retry",
|
|
8788
|
+
nextRecommendedCommand: `pourkit prd-run launch ${prdRef}`,
|
|
8789
|
+
...diagnostics?.length ? { diagnostics: [...diagnostics] } : {},
|
|
8790
|
+
...targetName ? { targetName } : {}
|
|
8791
|
+
}),
|
|
8538
8792
|
targetName
|
|
8539
8793
|
);
|
|
8540
8794
|
}
|
|
@@ -8546,8 +8800,11 @@ async function startPrdRun(options) {
|
|
|
8546
8800
|
options.repoRoot,
|
|
8547
8801
|
prdRef,
|
|
8548
8802
|
"branch-state",
|
|
8549
|
-
"
|
|
8550
|
-
`Invalid target name "${options.targetName}". Expected a non-empty target name
|
|
8803
|
+
"invalid-target-name",
|
|
8804
|
+
`Invalid target name "${options.targetName}". Expected a non-empty target name.`,
|
|
8805
|
+
void 0,
|
|
8806
|
+
void 0,
|
|
8807
|
+
"start-validation"
|
|
8551
8808
|
);
|
|
8552
8809
|
}
|
|
8553
8810
|
const existingRecord = readPrdRun(options.repoRoot, prdRef);
|
|
@@ -8562,10 +8819,11 @@ async function startPrdRun(options) {
|
|
|
8562
8819
|
options.repoRoot,
|
|
8563
8820
|
prdRef,
|
|
8564
8821
|
baseResolution.gate,
|
|
8565
|
-
"
|
|
8822
|
+
"base-resolution-failed",
|
|
8566
8823
|
baseResolution.reason,
|
|
8567
8824
|
baseResolution.diagnostics,
|
|
8568
|
-
targetName
|
|
8825
|
+
targetName,
|
|
8826
|
+
"start-validation"
|
|
8569
8827
|
);
|
|
8570
8828
|
}
|
|
8571
8829
|
if (existingRecord.record?.start) {
|
|
@@ -8575,10 +8833,12 @@ async function startPrdRun(options) {
|
|
|
8575
8833
|
options.repoRoot,
|
|
8576
8834
|
prdRef,
|
|
8577
8835
|
"branch-state",
|
|
8578
|
-
"
|
|
8836
|
+
"missing-start-base-branch",
|
|
8579
8837
|
`PRD Run ${prdRef} has a start receipt without startBaseBranch. Run prd-run start to create a fresh start receipt.`,
|
|
8580
8838
|
[`Recorded start: ${JSON.stringify(existingRecord.record.start)}`],
|
|
8581
|
-
targetName
|
|
8839
|
+
targetName,
|
|
8840
|
+
"start-validation",
|
|
8841
|
+
"unsupported-state"
|
|
8582
8842
|
);
|
|
8583
8843
|
}
|
|
8584
8844
|
if (recordedBaseBranch !== baseResolution.baseBranch) {
|
|
@@ -8586,13 +8846,14 @@ async function startPrdRun(options) {
|
|
|
8586
8846
|
options.repoRoot,
|
|
8587
8847
|
prdRef,
|
|
8588
8848
|
"branch-state",
|
|
8589
|
-
"
|
|
8849
|
+
"base-mismatch",
|
|
8590
8850
|
`PRD Run ${prdRef} start receipt records startBaseBranch "${recordedBaseBranch}" but current base resolution resolves to "${baseResolution.baseBranch}". Use --base with the matching value or create a fresh start receipt.`,
|
|
8591
8851
|
[
|
|
8592
8852
|
`Recorded startBaseBranch: ${recordedBaseBranch}`,
|
|
8593
8853
|
`Current base resolution: ${baseResolution.baseBranch} (source: ${baseResolution.source})`
|
|
8594
8854
|
],
|
|
8595
|
-
targetName
|
|
8855
|
+
targetName,
|
|
8856
|
+
"start-validation"
|
|
8596
8857
|
);
|
|
8597
8858
|
}
|
|
8598
8859
|
const currentStatus = existingRecord.record.status;
|
|
@@ -8611,9 +8872,12 @@ async function startPrdRun(options) {
|
|
|
8611
8872
|
options.repoRoot,
|
|
8612
8873
|
prdRef,
|
|
8613
8874
|
fetchResult2.gate,
|
|
8614
|
-
"
|
|
8875
|
+
"fetch-failed",
|
|
8615
8876
|
fetchResult2.reason,
|
|
8616
|
-
fetchResult2.diagnostics
|
|
8877
|
+
fetchResult2.diagnostics,
|
|
8878
|
+
targetName,
|
|
8879
|
+
"branch-materialization",
|
|
8880
|
+
"automatic-retry-safe"
|
|
8617
8881
|
);
|
|
8618
8882
|
}
|
|
8619
8883
|
const branchResult2 = inspectRemotePrdBranch(options.repoRoot, prdRef);
|
|
@@ -8622,9 +8886,12 @@ async function startPrdRun(options) {
|
|
|
8622
8886
|
options.repoRoot,
|
|
8623
8887
|
prdRef,
|
|
8624
8888
|
branchResult2.gate,
|
|
8625
|
-
"
|
|
8889
|
+
"branch-inspection-failed",
|
|
8626
8890
|
branchResult2.reason,
|
|
8627
|
-
branchResult2.diagnostics
|
|
8891
|
+
branchResult2.diagnostics,
|
|
8892
|
+
targetName,
|
|
8893
|
+
"branch-materialization",
|
|
8894
|
+
"automatic-retry-safe"
|
|
8628
8895
|
);
|
|
8629
8896
|
}
|
|
8630
8897
|
if (branchResult2.exists) {
|
|
@@ -8654,14 +8921,16 @@ async function startPrdRun(options) {
|
|
|
8654
8921
|
options.repoRoot,
|
|
8655
8922
|
prdRef,
|
|
8656
8923
|
"branch-state",
|
|
8657
|
-
"
|
|
8924
|
+
"unrecorded-branch-exists",
|
|
8658
8925
|
`PRD Branch ${prdRef} already exists remotely but PRD Run state does not record the same branch and start base commit. Use --adopt-existing-branch to adopt it.`,
|
|
8659
8926
|
[
|
|
8660
8927
|
`Existing remote branch: ${prdRef}`,
|
|
8661
8928
|
`Recorded start branch: ${matchingStart.prdBranch}`,
|
|
8662
8929
|
`Recorded start base commit: ${matchingStart.startBaseCommit}`,
|
|
8663
8930
|
`Current origin/${recordedBaseBranch} head: ${fetchResult2.startBaseCommit}`
|
|
8664
|
-
]
|
|
8931
|
+
],
|
|
8932
|
+
targetName,
|
|
8933
|
+
"branch-materialization"
|
|
8665
8934
|
);
|
|
8666
8935
|
}
|
|
8667
8936
|
const fetchPrdResult = fetchPrdBranch(options.repoRoot, prdRef);
|
|
@@ -8670,9 +8939,12 @@ async function startPrdRun(options) {
|
|
|
8670
8939
|
options.repoRoot,
|
|
8671
8940
|
prdRef,
|
|
8672
8941
|
fetchPrdResult.gate,
|
|
8673
|
-
"
|
|
8942
|
+
"fetch-prd-branch-failed",
|
|
8674
8943
|
fetchPrdResult.reason,
|
|
8675
|
-
fetchPrdResult.diagnostics
|
|
8944
|
+
fetchPrdResult.diagnostics,
|
|
8945
|
+
targetName,
|
|
8946
|
+
"branch-materialization",
|
|
8947
|
+
"automatic-retry-safe"
|
|
8676
8948
|
);
|
|
8677
8949
|
}
|
|
8678
8950
|
const ancestryResult = spawnSync2(
|
|
@@ -8690,12 +8962,14 @@ async function startPrdRun(options) {
|
|
|
8690
8962
|
options.repoRoot,
|
|
8691
8963
|
prdRef,
|
|
8692
8964
|
"branch-state",
|
|
8693
|
-
"
|
|
8965
|
+
"ancestry-check-failed",
|
|
8694
8966
|
`PRD Branch ${prdRef} base ancestry check failed: origin/${recordedBaseBranch} is not an ancestor of origin/${prdRef}. Cannot adopt.`,
|
|
8695
8967
|
[
|
|
8696
8968
|
`Base branch: origin/${recordedBaseBranch}`,
|
|
8697
8969
|
`PRD branch: origin/${prdRef}`
|
|
8698
|
-
]
|
|
8970
|
+
],
|
|
8971
|
+
targetName,
|
|
8972
|
+
"branch-materialization"
|
|
8699
8973
|
);
|
|
8700
8974
|
}
|
|
8701
8975
|
const adoptedStart = buildStartReceipt({
|
|
@@ -8731,9 +9005,12 @@ async function startPrdRun(options) {
|
|
|
8731
9005
|
options.repoRoot,
|
|
8732
9006
|
prdRef,
|
|
8733
9007
|
fetchResult.gate,
|
|
8734
|
-
"
|
|
9008
|
+
"fetch-failed",
|
|
8735
9009
|
fetchResult.reason,
|
|
8736
|
-
fetchResult.diagnostics
|
|
9010
|
+
fetchResult.diagnostics,
|
|
9011
|
+
targetName,
|
|
9012
|
+
"branch-materialization",
|
|
9013
|
+
"automatic-retry-safe"
|
|
8737
9014
|
);
|
|
8738
9015
|
}
|
|
8739
9016
|
const branchResult = inspectRemotePrdBranch(options.repoRoot, prdRef);
|
|
@@ -8742,9 +9019,12 @@ async function startPrdRun(options) {
|
|
|
8742
9019
|
options.repoRoot,
|
|
8743
9020
|
prdRef,
|
|
8744
9021
|
branchResult.gate,
|
|
8745
|
-
"
|
|
9022
|
+
"branch-inspection-failed",
|
|
8746
9023
|
branchResult.reason,
|
|
8747
|
-
branchResult.diagnostics
|
|
9024
|
+
branchResult.diagnostics,
|
|
9025
|
+
targetName,
|
|
9026
|
+
"branch-materialization",
|
|
9027
|
+
"automatic-retry-safe"
|
|
8748
9028
|
);
|
|
8749
9029
|
}
|
|
8750
9030
|
if (branchResult.exists) {
|
|
@@ -8753,14 +9033,16 @@ async function startPrdRun(options) {
|
|
|
8753
9033
|
options.repoRoot,
|
|
8754
9034
|
prdRef,
|
|
8755
9035
|
"branch-state",
|
|
8756
|
-
"
|
|
9036
|
+
"unrecorded-branch-exists",
|
|
8757
9037
|
`PRD Branch ${prdRef} already exists remotely but PRD Run state does not record the same branch and start base commit. Use --adopt-existing-branch to adopt it.`,
|
|
8758
9038
|
[
|
|
8759
9039
|
`Existing remote branch: ${prdRef}`,
|
|
8760
9040
|
`Recorded start branch: ${existingRecord.record?.start?.prdBranch ?? "(missing)"}`,
|
|
8761
9041
|
`Recorded start base commit: ${existingRecord.record?.start?.startBaseCommit ?? "(missing)"}`,
|
|
8762
9042
|
`Current origin/${baseResolution.baseBranch} head: ${fetchResult.startBaseCommit}`
|
|
8763
|
-
]
|
|
9043
|
+
],
|
|
9044
|
+
targetName,
|
|
9045
|
+
"branch-materialization"
|
|
8764
9046
|
);
|
|
8765
9047
|
}
|
|
8766
9048
|
const fetchPrdResult = fetchPrdBranch(options.repoRoot, prdRef);
|
|
@@ -8769,9 +9051,12 @@ async function startPrdRun(options) {
|
|
|
8769
9051
|
options.repoRoot,
|
|
8770
9052
|
prdRef,
|
|
8771
9053
|
fetchPrdResult.gate,
|
|
8772
|
-
"
|
|
9054
|
+
"fetch-prd-branch-failed",
|
|
8773
9055
|
fetchPrdResult.reason,
|
|
8774
|
-
fetchPrdResult.diagnostics
|
|
9056
|
+
fetchPrdResult.diagnostics,
|
|
9057
|
+
targetName,
|
|
9058
|
+
"branch-materialization",
|
|
9059
|
+
"automatic-retry-safe"
|
|
8775
9060
|
);
|
|
8776
9061
|
}
|
|
8777
9062
|
const ancestryResult = spawnSync2(
|
|
@@ -8789,12 +9074,14 @@ async function startPrdRun(options) {
|
|
|
8789
9074
|
options.repoRoot,
|
|
8790
9075
|
prdRef,
|
|
8791
9076
|
"branch-state",
|
|
8792
|
-
"
|
|
9077
|
+
"ancestry-check-failed",
|
|
8793
9078
|
`PRD Branch ${prdRef} base ancestry check failed: origin/${baseResolution.baseBranch} is not an ancestor of origin/${prdRef}. Cannot adopt.`,
|
|
8794
9079
|
[
|
|
8795
9080
|
`Base branch: origin/${baseResolution.baseBranch}`,
|
|
8796
9081
|
`PRD branch: origin/${prdRef}`
|
|
8797
|
-
]
|
|
9082
|
+
],
|
|
9083
|
+
targetName,
|
|
9084
|
+
"branch-materialization"
|
|
8798
9085
|
);
|
|
8799
9086
|
}
|
|
8800
9087
|
const adoptedStart = buildStartReceipt({
|
|
@@ -8831,11 +9118,14 @@ async function startPrdRun(options) {
|
|
|
8831
9118
|
options.repoRoot,
|
|
8832
9119
|
prdRef,
|
|
8833
9120
|
"git",
|
|
8834
|
-
"
|
|
9121
|
+
"branch-creation-failed",
|
|
8835
9122
|
`Failed to create PRD Branch ${prdRef} from ${fetchResult.startBaseCommit}.`,
|
|
8836
9123
|
[error instanceof Error ? error.message : String(error)].filter(
|
|
8837
9124
|
(v) => Boolean(v && v.trim())
|
|
8838
|
-
)
|
|
9125
|
+
),
|
|
9126
|
+
targetName,
|
|
9127
|
+
"branch-materialization",
|
|
9128
|
+
"automatic-retry-safe"
|
|
8839
9129
|
);
|
|
8840
9130
|
}
|
|
8841
9131
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -8858,11 +9148,28 @@ async function startPrdRun(options) {
|
|
|
8858
9148
|
diagnostics: []
|
|
8859
9149
|
};
|
|
8860
9150
|
}
|
|
8861
|
-
function buildLaunchBlockedOutcome(prdRef, guidance, resume, start) {
|
|
9151
|
+
function buildLaunchBlockedOutcome(repoRoot2, prdRef, guidance, resume, start, targetName, startReceipt) {
|
|
9152
|
+
const enrichedGuidance = {
|
|
9153
|
+
...guidance,
|
|
9154
|
+
targetName: guidance.targetName ?? targetName,
|
|
9155
|
+
baseBranch: guidance.baseBranch ?? startReceipt?.startBaseBranch
|
|
9156
|
+
};
|
|
9157
|
+
writePrdRunRecord(repoRoot2, {
|
|
9158
|
+
prdRef,
|
|
9159
|
+
status: "blocked",
|
|
9160
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9161
|
+
blockedGate: enrichedGuidance.blockedGate,
|
|
9162
|
+
blockedReason: enrichedGuidance.humanReadableReason,
|
|
9163
|
+
...enrichedGuidance.diagnostics?.length ? { diagnostics: [...enrichedGuidance.diagnostics] } : {},
|
|
9164
|
+
...enrichedGuidance.offendingPaths?.length ? { offendingPaths: [...enrichedGuidance.offendingPaths] } : {},
|
|
9165
|
+
...targetName ? { targetName } : {},
|
|
9166
|
+
...startReceipt ? { start: startReceipt } : {},
|
|
9167
|
+
repairGuidance: enrichedGuidance
|
|
9168
|
+
});
|
|
8862
9169
|
return {
|
|
8863
9170
|
kind: "blocked",
|
|
8864
9171
|
prdRef,
|
|
8865
|
-
guidance,
|
|
9172
|
+
guidance: enrichedGuidance,
|
|
8866
9173
|
start,
|
|
8867
9174
|
resume
|
|
8868
9175
|
};
|
|
@@ -8886,22 +9193,136 @@ function writeTerminalRecord(repoRoot2, prdRef, status, targetName, startReceipt
|
|
|
8886
9193
|
start: startReceipt
|
|
8887
9194
|
});
|
|
8888
9195
|
}
|
|
9196
|
+
function validateRecordedIssueResumeEvidence(options) {
|
|
9197
|
+
const { prdRef, guidance, startReceipt, targetName } = options;
|
|
9198
|
+
const diagnostics = [];
|
|
9199
|
+
if (guidance.targetName && guidance.targetName !== targetName) {
|
|
9200
|
+
diagnostics.push(
|
|
9201
|
+
`Recorded targetName: ${guidance.targetName}; current targetName: ${targetName}`
|
|
9202
|
+
);
|
|
9203
|
+
}
|
|
9204
|
+
if (guidance.baseBranch && startReceipt?.startBaseBranch && guidance.baseBranch !== startReceipt.startBaseBranch) {
|
|
9205
|
+
diagnostics.push(
|
|
9206
|
+
`Recorded baseBranch: ${guidance.baseBranch}; current startBaseBranch: ${startReceipt.startBaseBranch}`
|
|
9207
|
+
);
|
|
9208
|
+
}
|
|
9209
|
+
const worktreePath = guidance.issue?.worktreePath;
|
|
9210
|
+
if (worktreePath) {
|
|
9211
|
+
const worktreeState = readWorktreeRunState(worktreePath);
|
|
9212
|
+
if (!worktreeState) {
|
|
9213
|
+
diagnostics.push(
|
|
9214
|
+
`Worktree Run State missing or malformed at ${worktreePath}`
|
|
9215
|
+
);
|
|
9216
|
+
} else {
|
|
9217
|
+
if (guidance.issue?.number !== worktreeState.issueNumber) {
|
|
9218
|
+
diagnostics.push(
|
|
9219
|
+
`Recorded issue #${guidance.issue?.number}; Worktree Run State issue #${worktreeState.issueNumber}`
|
|
9220
|
+
);
|
|
9221
|
+
}
|
|
9222
|
+
if (guidance.issue?.branch && guidance.issue.branch !== worktreeState.branchName) {
|
|
9223
|
+
diagnostics.push(
|
|
9224
|
+
`Recorded issue branch: ${guidance.issue.branch}; Worktree Run State branch: ${worktreeState.branchName}`
|
|
9225
|
+
);
|
|
9226
|
+
}
|
|
9227
|
+
if (worktreeState.targetName !== targetName) {
|
|
9228
|
+
diagnostics.push(
|
|
9229
|
+
`Worktree Run State targetName: ${worktreeState.targetName}; current targetName: ${targetName}`
|
|
9230
|
+
);
|
|
9231
|
+
}
|
|
9232
|
+
if (startReceipt?.prdBranch && worktreeState.baseBranch !== startReceipt.prdBranch) {
|
|
9233
|
+
diagnostics.push(
|
|
9234
|
+
`Worktree Run State baseBranch: ${worktreeState.baseBranch}; expected PRD Branch: ${startReceipt.prdBranch}`
|
|
9235
|
+
);
|
|
9236
|
+
}
|
|
9237
|
+
}
|
|
9238
|
+
}
|
|
9239
|
+
if (diagnostics.length === 0) return null;
|
|
9240
|
+
return buildPrdRunRepairGuidance({
|
|
9241
|
+
blockedGate: "queue",
|
|
9242
|
+
blockedStage: guidance.blockedStage || "queue-drain",
|
|
9243
|
+
failureCode: worktreePath ? "worktree-evidence-mismatch" : "branch-evidence-mismatch",
|
|
9244
|
+
humanReadableReason: `PRD Run ${prdRef} recorded repair guidance does not match current resume evidence.`,
|
|
9245
|
+
repairability: "unsupported-state",
|
|
9246
|
+
nextAction: "inspect-prd-run-state",
|
|
9247
|
+
nextRecommendedCommand: `pourkit prd-run status ${prdRef}`,
|
|
9248
|
+
diagnostics,
|
|
9249
|
+
issue: guidance.issue,
|
|
9250
|
+
pr: guidance.pr,
|
|
9251
|
+
targetName: guidance.targetName,
|
|
9252
|
+
baseBranch: guidance.baseBranch
|
|
9253
|
+
});
|
|
9254
|
+
}
|
|
9255
|
+
async function attemptRecordedIssueLabelProjection(options, prdRef, resumeIssueNumber, originalGuidance) {
|
|
9256
|
+
if (resumeIssueNumber === void 0) return true;
|
|
9257
|
+
try {
|
|
9258
|
+
await options.issueProvider.removeLabel(
|
|
9259
|
+
resumeIssueNumber,
|
|
9260
|
+
options.config.labels.agentInProgress
|
|
9261
|
+
);
|
|
9262
|
+
return true;
|
|
9263
|
+
} catch {
|
|
9264
|
+
const state = readPrdRun(options.repoRoot, prdRef).record;
|
|
9265
|
+
const guidance = originalGuidance ?? state?.repairGuidance;
|
|
9266
|
+
if (guidance) {
|
|
9267
|
+
const updated = appendPrdRunRepairAttempt(guidance, {
|
|
9268
|
+
outcome: "projection-failed",
|
|
9269
|
+
failureCode: "label-projection-failed",
|
|
9270
|
+
summary: `Failed to remove "${options.config.labels.agentInProgress}" label from issue #${resumeIssueNumber}`
|
|
9271
|
+
});
|
|
9272
|
+
if (state) {
|
|
9273
|
+
writePrdRunRecord(options.repoRoot, {
|
|
9274
|
+
...state,
|
|
9275
|
+
repairGuidance: updated,
|
|
9276
|
+
updatedAt: updated.updatedAt
|
|
9277
|
+
});
|
|
9278
|
+
}
|
|
9279
|
+
}
|
|
9280
|
+
return false;
|
|
9281
|
+
}
|
|
9282
|
+
}
|
|
8889
9283
|
async function launchPrdRun(options) {
|
|
8890
9284
|
const prdRef = normalizePrdRunRef(options.prdRef);
|
|
8891
9285
|
const existingRecord = readPrdRun(options.repoRoot, prdRef);
|
|
8892
9286
|
const plan = planPrdRunLaunchResume(existingRecord.record);
|
|
9287
|
+
const rec = existingRecord.record;
|
|
9288
|
+
if (rec && (rec.status === "starting" || rec.status === "running") && !rec.repairGuidance) {
|
|
9289
|
+
return buildLaunchBlockedOutcome(
|
|
9290
|
+
options.repoRoot,
|
|
9291
|
+
prdRef,
|
|
9292
|
+
buildPrdRunRepairGuidance({
|
|
9293
|
+
blockedGate: "branch-state",
|
|
9294
|
+
blockedStage: "start-validation",
|
|
9295
|
+
failureCode: "prd-run-in-progress",
|
|
9296
|
+
humanReadableReason: `PRD Run ${prdRef} is already ${rec.status}. A second launch cannot start another Queue drain while the run is in progress.`,
|
|
9297
|
+
repairability: "automatic-retry-safe",
|
|
9298
|
+
nextAction: "wait-or-inspect-active-run",
|
|
9299
|
+
nextRecommendedCommand: "pourkit prd-run status",
|
|
9300
|
+
diagnostics: [
|
|
9301
|
+
`PRD Run ${prdRef} is in status "${rec.status}" without active repair guidance.`
|
|
9302
|
+
]
|
|
9303
|
+
}),
|
|
9304
|
+
plan,
|
|
9305
|
+
void 0,
|
|
9306
|
+
options.targetName
|
|
9307
|
+
);
|
|
9308
|
+
}
|
|
8893
9309
|
if (existingRecord.record === null && existingRecord.diagnostics.length > 0) {
|
|
8894
9310
|
return buildLaunchBlockedOutcome(
|
|
9311
|
+
options.repoRoot,
|
|
8895
9312
|
prdRef,
|
|
8896
|
-
{
|
|
9313
|
+
buildPrdRunRepairGuidance({
|
|
8897
9314
|
blockedGate: "receipt-check",
|
|
8898
|
-
|
|
8899
|
-
|
|
9315
|
+
blockedStage: "start-validation",
|
|
9316
|
+
failureCode: "unsupported-legacy-state",
|
|
9317
|
+
humanReadableReason: `PRD Run ${prdRef} has a malformed or unsupported record. The stored status is no longer a valid launch state.`,
|
|
8900
9318
|
repairability: "unsupported-state",
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
|
|
9319
|
+
nextAction: "inspect-prd-run-state",
|
|
9320
|
+
nextRecommendedCommand: "pourkit prd-run status",
|
|
9321
|
+
diagnostics: [...existingRecord.diagnostics]
|
|
9322
|
+
}),
|
|
9323
|
+
plan,
|
|
9324
|
+
void 0,
|
|
9325
|
+
options.targetName
|
|
8905
9326
|
);
|
|
8906
9327
|
}
|
|
8907
9328
|
if (existingRecord.record?.status === "completed_prd_branch") {
|
|
@@ -8920,16 +9341,20 @@ async function launchPrdRun(options) {
|
|
|
8920
9341
|
const record = existingRecord.record;
|
|
8921
9342
|
if (!record.start) {
|
|
8922
9343
|
return buildLaunchBlockedOutcome(
|
|
9344
|
+
options.repoRoot,
|
|
8923
9345
|
prdRef,
|
|
8924
|
-
{
|
|
9346
|
+
buildPrdRunRepairGuidance({
|
|
8925
9347
|
blockedGate: "queue",
|
|
8926
|
-
|
|
8927
|
-
|
|
9348
|
+
blockedStage: "queue-drain",
|
|
9349
|
+
failureCode: "missing-drain-evidence",
|
|
9350
|
+
humanReadableReason: `PRD Run ${prdRef} is drained but missing start receipt.`,
|
|
8928
9351
|
repairability: "automatic-retry-safe",
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
},
|
|
8932
|
-
plan
|
|
9352
|
+
nextAction: "rerun-prd-run-launch",
|
|
9353
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
9354
|
+
}),
|
|
9355
|
+
plan,
|
|
9356
|
+
void 0,
|
|
9357
|
+
options.targetName
|
|
8933
9358
|
);
|
|
8934
9359
|
}
|
|
8935
9360
|
const resolvedTarget = options.config ? resolveTarget(options.config, options.targetName) : null;
|
|
@@ -8940,16 +9365,22 @@ async function launchPrdRun(options) {
|
|
|
8940
9365
|
});
|
|
8941
9366
|
if (!baseResolution.ok) {
|
|
8942
9367
|
return buildLaunchBlockedOutcome(
|
|
9368
|
+
options.repoRoot,
|
|
8943
9369
|
prdRef,
|
|
8944
|
-
{
|
|
9370
|
+
buildPrdRunRepairGuidance({
|
|
8945
9371
|
blockedGate: baseResolution.gate,
|
|
8946
|
-
|
|
8947
|
-
|
|
9372
|
+
blockedStage: "start-validation",
|
|
9373
|
+
failureCode: "base-resolution-failed",
|
|
9374
|
+
humanReadableReason: baseResolution.reason,
|
|
8948
9375
|
repairability: "operator-action",
|
|
9376
|
+
nextAction: "inspect-and-retry",
|
|
9377
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
8949
9378
|
diagnostics: [...baseResolution.diagnostics],
|
|
8950
9379
|
offendingPaths: [...baseResolution.offendingPaths]
|
|
8951
|
-
},
|
|
8952
|
-
plan
|
|
9380
|
+
}),
|
|
9381
|
+
plan,
|
|
9382
|
+
void 0,
|
|
9383
|
+
options.targetName
|
|
8953
9384
|
);
|
|
8954
9385
|
}
|
|
8955
9386
|
const drainContext = {
|
|
@@ -8962,7 +9393,14 @@ async function launchPrdRun(options) {
|
|
|
8962
9393
|
drainContext
|
|
8963
9394
|
);
|
|
8964
9395
|
if (!terminalEvidence.ok) {
|
|
8965
|
-
return buildLaunchBlockedOutcome(
|
|
9396
|
+
return buildLaunchBlockedOutcome(
|
|
9397
|
+
options.repoRoot,
|
|
9398
|
+
prdRef,
|
|
9399
|
+
terminalEvidence.guidance,
|
|
9400
|
+
plan,
|
|
9401
|
+
void 0,
|
|
9402
|
+
options.targetName
|
|
9403
|
+
);
|
|
8966
9404
|
}
|
|
8967
9405
|
writeTerminalRecord(
|
|
8968
9406
|
options.repoRoot,
|
|
@@ -8985,18 +9423,23 @@ async function launchPrdRun(options) {
|
|
|
8985
9423
|
}
|
|
8986
9424
|
if (plan.blocked === "missing-start-receipt") {
|
|
8987
9425
|
return buildLaunchBlockedOutcome(
|
|
9426
|
+
options.repoRoot,
|
|
8988
9427
|
prdRef,
|
|
8989
|
-
{
|
|
9428
|
+
buildPrdRunRepairGuidance({
|
|
8990
9429
|
blockedGate: "branch-state",
|
|
8991
|
-
|
|
8992
|
-
|
|
9430
|
+
blockedStage: "start-validation",
|
|
9431
|
+
failureCode: "missing-start-receipt",
|
|
9432
|
+
humanReadableReason: `PRD Run ${prdRef} is missing branch/start state. Run prd-run start or rerun prd-run launch.`,
|
|
8993
9433
|
repairability: "automatic-retry-safe",
|
|
9434
|
+
nextAction: "rerun-prd-run-launch",
|
|
9435
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
8994
9436
|
diagnostics: [
|
|
8995
9437
|
`PRD Run ${prdRef} is in status "${existingRecord.record?.status}" but has no start receipt.`
|
|
8996
|
-
]
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9438
|
+
]
|
|
9439
|
+
}),
|
|
9440
|
+
plan,
|
|
9441
|
+
void 0,
|
|
9442
|
+
options.targetName
|
|
9000
9443
|
);
|
|
9001
9444
|
}
|
|
9002
9445
|
let startOutcome;
|
|
@@ -9026,6 +9469,62 @@ async function launchPrdRun(options) {
|
|
|
9026
9469
|
const currentRecord = readPrdRun(options.repoRoot, prdRef).record;
|
|
9027
9470
|
const startReceipt = currentRecord?.start;
|
|
9028
9471
|
const targetName = currentRecord?.targetName ?? options.targetName;
|
|
9472
|
+
let resumeIssueNumber;
|
|
9473
|
+
if (currentRecord?.repairGuidance) {
|
|
9474
|
+
const validation = validateActivePrdRunRepairGuidance(currentRecord);
|
|
9475
|
+
if (!validation.ok) {
|
|
9476
|
+
return buildLaunchBlockedOutcome(
|
|
9477
|
+
options.repoRoot,
|
|
9478
|
+
prdRef,
|
|
9479
|
+
validation.guidance,
|
|
9480
|
+
plan,
|
|
9481
|
+
startOutcome,
|
|
9482
|
+
targetName,
|
|
9483
|
+
startReceipt
|
|
9484
|
+
);
|
|
9485
|
+
}
|
|
9486
|
+
const resumeEvidenceFailure = validateRecordedIssueResumeEvidence({
|
|
9487
|
+
prdRef,
|
|
9488
|
+
guidance: validation.guidance,
|
|
9489
|
+
startReceipt,
|
|
9490
|
+
targetName
|
|
9491
|
+
});
|
|
9492
|
+
if (resumeEvidenceFailure) {
|
|
9493
|
+
return buildLaunchBlockedOutcome(
|
|
9494
|
+
options.repoRoot,
|
|
9495
|
+
prdRef,
|
|
9496
|
+
resumeEvidenceFailure,
|
|
9497
|
+
plan,
|
|
9498
|
+
startOutcome,
|
|
9499
|
+
targetName,
|
|
9500
|
+
startReceipt
|
|
9501
|
+
);
|
|
9502
|
+
}
|
|
9503
|
+
if (validation.guidance.issue?.number) {
|
|
9504
|
+
resumeIssueNumber = validation.guidance.issue.number;
|
|
9505
|
+
} else {
|
|
9506
|
+
return buildLaunchBlockedOutcome(
|
|
9507
|
+
options.repoRoot,
|
|
9508
|
+
prdRef,
|
|
9509
|
+
buildPrdRunRepairGuidance({
|
|
9510
|
+
blockedGate: "queue",
|
|
9511
|
+
blockedStage: "queue-drain",
|
|
9512
|
+
failureCode: "missing-issue-identity",
|
|
9513
|
+
humanReadableReason: `PRD Run ${prdRef} has repair guidance without a recorded Issue identity. Resume is not possible.`,
|
|
9514
|
+
repairability: "unsupported-state",
|
|
9515
|
+
nextAction: "inspect-prd-run-state",
|
|
9516
|
+
nextRecommendedCommand: `pourkit prd-run status ${prdRef}`,
|
|
9517
|
+
diagnostics: [
|
|
9518
|
+
"Repair guidance exists but is missing issue.number field."
|
|
9519
|
+
]
|
|
9520
|
+
}),
|
|
9521
|
+
plan,
|
|
9522
|
+
startOutcome,
|
|
9523
|
+
targetName,
|
|
9524
|
+
startReceipt
|
|
9525
|
+
);
|
|
9526
|
+
}
|
|
9527
|
+
}
|
|
9029
9528
|
if (startReceipt) {
|
|
9030
9529
|
startReceipt.queueStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9031
9530
|
startReceipt.queueCommand = "queue-run";
|
|
@@ -9035,7 +9534,8 @@ async function launchPrdRun(options) {
|
|
|
9035
9534
|
status: "running",
|
|
9036
9535
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9037
9536
|
targetName,
|
|
9038
|
-
start: startReceipt
|
|
9537
|
+
start: startReceipt,
|
|
9538
|
+
repairGuidance: currentRecord?.repairGuidance
|
|
9039
9539
|
});
|
|
9040
9540
|
return await launchGithubQueueDrain(
|
|
9041
9541
|
options,
|
|
@@ -9043,98 +9543,78 @@ async function launchPrdRun(options) {
|
|
|
9043
9543
|
startReceipt,
|
|
9044
9544
|
targetName,
|
|
9045
9545
|
plan,
|
|
9046
|
-
startOutcome
|
|
9546
|
+
startOutcome,
|
|
9547
|
+
resumeIssueNumber
|
|
9047
9548
|
);
|
|
9048
9549
|
}
|
|
9049
|
-
async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName, plan, startOutcome) {
|
|
9550
|
+
async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName, plan, startOutcome, resumeIssueNumber) {
|
|
9050
9551
|
if (!options.issueProvider || !options.prProvider || !options.executionProvider || !options.logger) {
|
|
9051
9552
|
const reason = `PRD Run ${prdRef} requires issueProvider, prProvider, executionProvider, and logger for GitHub-backed queue drain.`;
|
|
9052
|
-
writePrdRunRecord(options.repoRoot, {
|
|
9053
|
-
prdRef,
|
|
9054
|
-
status: "blocked",
|
|
9055
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9056
|
-
targetName,
|
|
9057
|
-
start: startReceipt,
|
|
9058
|
-
blockedGate: "queue",
|
|
9059
|
-
blockedReason: reason,
|
|
9060
|
-
diagnostics: [
|
|
9061
|
-
"Missing one or more required providers for GitHub-backed mode.",
|
|
9062
|
-
"Provide --issue-provider, --pr-provider, --execution-provider, and --logger options."
|
|
9063
|
-
],
|
|
9064
|
-
offendingPaths: []
|
|
9065
|
-
});
|
|
9066
9553
|
return buildLaunchBlockedOutcome(
|
|
9554
|
+
options.repoRoot,
|
|
9067
9555
|
prdRef,
|
|
9068
|
-
{
|
|
9556
|
+
buildPrdRunRepairGuidance({
|
|
9069
9557
|
blockedGate: "queue",
|
|
9070
|
-
|
|
9071
|
-
|
|
9558
|
+
blockedStage: "queue-drain",
|
|
9559
|
+
failureCode: "missing-github-providers",
|
|
9560
|
+
humanReadableReason: reason,
|
|
9072
9561
|
repairability: "operator-action",
|
|
9562
|
+
nextAction: "inspect-and-retry",
|
|
9563
|
+
nextRecommendedCommand: "pourkit prd-run launch --with-providers",
|
|
9073
9564
|
diagnostics: [
|
|
9074
9565
|
"Missing one or more required providers for GitHub-backed mode."
|
|
9075
|
-
]
|
|
9076
|
-
|
|
9077
|
-
},
|
|
9566
|
+
]
|
|
9567
|
+
}),
|
|
9078
9568
|
plan,
|
|
9079
|
-
startOutcome
|
|
9569
|
+
startOutcome,
|
|
9570
|
+
targetName,
|
|
9571
|
+
startReceipt
|
|
9080
9572
|
);
|
|
9081
9573
|
}
|
|
9082
9574
|
if (!startReceipt) {
|
|
9083
|
-
writePrdRunRecord(options.repoRoot, {
|
|
9084
|
-
prdRef,
|
|
9085
|
-
status: "blocked",
|
|
9086
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9087
|
-
targetName,
|
|
9088
|
-
blockedGate: "branch-state",
|
|
9089
|
-
blockedReason: `PRD Run ${prdRef} is missing start receipt before GitHub queue drain.`,
|
|
9090
|
-
diagnostics: [],
|
|
9091
|
-
offendingPaths: []
|
|
9092
|
-
});
|
|
9093
9575
|
return buildLaunchBlockedOutcome(
|
|
9576
|
+
options.repoRoot,
|
|
9094
9577
|
prdRef,
|
|
9095
|
-
{
|
|
9578
|
+
buildPrdRunRepairGuidance({
|
|
9096
9579
|
blockedGate: "branch-state",
|
|
9097
|
-
|
|
9098
|
-
|
|
9580
|
+
blockedStage: "start-validation",
|
|
9581
|
+
failureCode: "missing-start-receipt",
|
|
9582
|
+
humanReadableReason: `PRD Run ${prdRef} is missing start receipt before GitHub queue drain.`,
|
|
9099
9583
|
repairability: "automatic-retry-safe",
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
},
|
|
9584
|
+
nextAction: "rerun-prd-run-launch",
|
|
9585
|
+
nextRecommendedCommand: "pourkit prd-run launch"
|
|
9586
|
+
}),
|
|
9103
9587
|
plan,
|
|
9104
|
-
startOutcome
|
|
9588
|
+
startOutcome,
|
|
9589
|
+
targetName
|
|
9105
9590
|
);
|
|
9106
9591
|
}
|
|
9107
9592
|
if (!options.config) {
|
|
9108
9593
|
const reason = `PRD Run ${prdRef} requires config for GitHub-backed queue drain.`;
|
|
9109
|
-
writePrdRunRecord(options.repoRoot, {
|
|
9110
|
-
prdRef,
|
|
9111
|
-
status: "blocked",
|
|
9112
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9113
|
-
targetName,
|
|
9114
|
-
start: startReceipt,
|
|
9115
|
-
blockedGate: "queue",
|
|
9116
|
-
blockedReason: reason,
|
|
9117
|
-
diagnostics: ["Missing config for GitHub-backed mode."],
|
|
9118
|
-
offendingPaths: []
|
|
9119
|
-
});
|
|
9120
9594
|
return buildLaunchBlockedOutcome(
|
|
9595
|
+
options.repoRoot,
|
|
9121
9596
|
prdRef,
|
|
9122
|
-
{
|
|
9597
|
+
buildPrdRunRepairGuidance({
|
|
9123
9598
|
blockedGate: "queue",
|
|
9124
|
-
|
|
9125
|
-
|
|
9599
|
+
blockedStage: "queue-drain",
|
|
9600
|
+
failureCode: "missing-config",
|
|
9601
|
+
humanReadableReason: reason,
|
|
9126
9602
|
repairability: "operator-action",
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9603
|
+
nextAction: "inspect-and-retry",
|
|
9604
|
+
nextRecommendedCommand: "pourkit prd-run launch --with-config",
|
|
9605
|
+
diagnostics: ["Missing config for GitHub-backed mode."]
|
|
9606
|
+
}),
|
|
9130
9607
|
plan,
|
|
9131
|
-
startOutcome
|
|
9608
|
+
startOutcome,
|
|
9609
|
+
targetName,
|
|
9610
|
+
startReceipt
|
|
9132
9611
|
);
|
|
9133
9612
|
}
|
|
9134
9613
|
const issueProvider = options.issueProvider;
|
|
9135
9614
|
const prProvider = options.prProvider;
|
|
9136
9615
|
const executionProvider = options.executionProvider;
|
|
9137
9616
|
const logger = options.logger;
|
|
9617
|
+
const originalGuidance = readPrdRun(options.repoRoot, prdRef).record?.repairGuidance;
|
|
9138
9618
|
try {
|
|
9139
9619
|
const outcome = await runQueueCommand({
|
|
9140
9620
|
targetName,
|
|
@@ -9149,7 +9629,8 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
|
|
|
9149
9629
|
prdRef,
|
|
9150
9630
|
queueRunContext: {
|
|
9151
9631
|
prdRef,
|
|
9152
|
-
prdBranch: startReceipt.prdBranch
|
|
9632
|
+
prdBranch: startReceipt.prdBranch,
|
|
9633
|
+
...resumeIssueNumber !== void 0 ? { resumeIssueNumber } : {}
|
|
9153
9634
|
}
|
|
9154
9635
|
});
|
|
9155
9636
|
if (outcome.selected === null && outcome.code === "drained") {
|
|
@@ -9157,30 +9638,41 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
|
|
|
9157
9638
|
const diagnostics = [
|
|
9158
9639
|
"Queue drained without processing issues. No PRD-scoped candidates or runnable Issues."
|
|
9159
9640
|
];
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
status: "blocked",
|
|
9163
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9164
|
-
targetName,
|
|
9165
|
-
start: startReceipt,
|
|
9166
|
-
blockedGate: "queue",
|
|
9167
|
-
blockedReason: diagnostics[0],
|
|
9168
|
-
diagnostics,
|
|
9169
|
-
offendingPaths: []
|
|
9170
|
-
});
|
|
9171
|
-
return buildLaunchBlockedOutcome(
|
|
9641
|
+
const result2 = buildLaunchBlockedOutcome(
|
|
9642
|
+
options.repoRoot,
|
|
9172
9643
|
prdRef,
|
|
9173
|
-
{
|
|
9644
|
+
buildPrdRunRepairGuidance({
|
|
9174
9645
|
blockedGate: "queue",
|
|
9175
|
-
|
|
9176
|
-
|
|
9646
|
+
blockedStage: "queue-drain",
|
|
9647
|
+
failureCode: "zero-processed",
|
|
9648
|
+
humanReadableReason: diagnostics[0],
|
|
9177
9649
|
repairability: "automatic-retry-safe",
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9650
|
+
nextAction: "rerun-prd-run-launch",
|
|
9651
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
9652
|
+
diagnostics
|
|
9653
|
+
}),
|
|
9181
9654
|
plan,
|
|
9182
|
-
startOutcome
|
|
9655
|
+
startOutcome,
|
|
9656
|
+
targetName,
|
|
9657
|
+
startReceipt
|
|
9183
9658
|
);
|
|
9659
|
+
const projectionOk2 = await attemptRecordedIssueLabelProjection(
|
|
9660
|
+
options,
|
|
9661
|
+
prdRef,
|
|
9662
|
+
resumeIssueNumber,
|
|
9663
|
+
originalGuidance
|
|
9664
|
+
);
|
|
9665
|
+
if (!projectionOk2 && originalGuidance) {
|
|
9666
|
+
const updatedRecord = readPrdRun(options.repoRoot, prdRef).record;
|
|
9667
|
+
return {
|
|
9668
|
+
kind: "blocked",
|
|
9669
|
+
prdRef,
|
|
9670
|
+
guidance: updatedRecord.repairGuidance,
|
|
9671
|
+
start: startOutcome,
|
|
9672
|
+
resume: plan
|
|
9673
|
+
};
|
|
9674
|
+
}
|
|
9675
|
+
return result2;
|
|
9184
9676
|
}
|
|
9185
9677
|
startReceipt.queueDrainedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9186
9678
|
startReceipt.queueProcessedCount = outcome.processedCount;
|
|
@@ -9200,10 +9692,13 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
|
|
|
9200
9692
|
);
|
|
9201
9693
|
if (!terminalEvidence.ok) {
|
|
9202
9694
|
return buildLaunchBlockedOutcome(
|
|
9695
|
+
options.repoRoot,
|
|
9203
9696
|
prdRef,
|
|
9204
9697
|
terminalEvidence.guidance,
|
|
9205
9698
|
plan,
|
|
9206
|
-
startOutcome
|
|
9699
|
+
startOutcome,
|
|
9700
|
+
targetName,
|
|
9701
|
+
startReceipt
|
|
9207
9702
|
);
|
|
9208
9703
|
}
|
|
9209
9704
|
}
|
|
@@ -9229,84 +9724,117 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
|
|
|
9229
9724
|
}
|
|
9230
9725
|
if (outcome.selected === null) {
|
|
9231
9726
|
const diagnostics = [outcome.reason];
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
status: "blocked",
|
|
9235
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9236
|
-
targetName,
|
|
9237
|
-
start: startReceipt,
|
|
9238
|
-
blockedGate: "queue",
|
|
9239
|
-
blockedReason: outcome.reason,
|
|
9240
|
-
diagnostics,
|
|
9241
|
-
offendingPaths: []
|
|
9242
|
-
});
|
|
9243
|
-
return buildLaunchBlockedOutcome(
|
|
9727
|
+
const result2 = buildLaunchBlockedOutcome(
|
|
9728
|
+
options.repoRoot,
|
|
9244
9729
|
prdRef,
|
|
9245
|
-
{
|
|
9730
|
+
buildPrdRunRepairGuidance({
|
|
9246
9731
|
blockedGate: "queue",
|
|
9247
|
-
|
|
9248
|
-
|
|
9732
|
+
blockedStage: "queue-drain",
|
|
9733
|
+
failureCode: "queue-blocked",
|
|
9734
|
+
humanReadableReason: outcome.reason,
|
|
9249
9735
|
repairability: "automatic-retry-safe",
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9736
|
+
nextAction: "rerun-prd-run-launch",
|
|
9737
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
9738
|
+
diagnostics
|
|
9739
|
+
}),
|
|
9253
9740
|
plan,
|
|
9254
|
-
startOutcome
|
|
9741
|
+
startOutcome,
|
|
9742
|
+
targetName,
|
|
9743
|
+
startReceipt
|
|
9744
|
+
);
|
|
9745
|
+
const projectionOk2 = await attemptRecordedIssueLabelProjection(
|
|
9746
|
+
options,
|
|
9747
|
+
prdRef,
|
|
9748
|
+
resumeIssueNumber,
|
|
9749
|
+
originalGuidance
|
|
9255
9750
|
);
|
|
9751
|
+
if (!projectionOk2 && originalGuidance) {
|
|
9752
|
+
const updatedRecord = readPrdRun(options.repoRoot, prdRef).record;
|
|
9753
|
+
return {
|
|
9754
|
+
kind: "blocked",
|
|
9755
|
+
prdRef,
|
|
9756
|
+
guidance: updatedRecord.repairGuidance,
|
|
9757
|
+
start: startOutcome,
|
|
9758
|
+
resume: plan
|
|
9759
|
+
};
|
|
9760
|
+
}
|
|
9761
|
+
return result2;
|
|
9256
9762
|
}
|
|
9257
9763
|
const outcomeReason = `Unexpected queue outcome: selected issue ${outcome.selected.number}`;
|
|
9258
9764
|
const outcomeDiagnostics = [outcomeReason];
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
status: "blocked",
|
|
9262
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9263
|
-
targetName,
|
|
9264
|
-
start: startReceipt,
|
|
9265
|
-
blockedGate: "queue",
|
|
9266
|
-
blockedReason: outcomeReason,
|
|
9267
|
-
diagnostics: outcomeDiagnostics,
|
|
9268
|
-
offendingPaths: []
|
|
9269
|
-
});
|
|
9270
|
-
return buildLaunchBlockedOutcome(
|
|
9765
|
+
const result = buildLaunchBlockedOutcome(
|
|
9766
|
+
options.repoRoot,
|
|
9271
9767
|
prdRef,
|
|
9272
|
-
{
|
|
9768
|
+
buildPrdRunRepairGuidance({
|
|
9273
9769
|
blockedGate: "queue",
|
|
9274
|
-
|
|
9275
|
-
|
|
9770
|
+
blockedStage: "queue-drain",
|
|
9771
|
+
failureCode: "unexpected-queue-outcome",
|
|
9772
|
+
humanReadableReason: outcomeReason,
|
|
9276
9773
|
repairability: "operator-action",
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9774
|
+
nextAction: "inspect-and-retry",
|
|
9775
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
9776
|
+
diagnostics: outcomeDiagnostics
|
|
9777
|
+
}),
|
|
9280
9778
|
plan,
|
|
9281
|
-
startOutcome
|
|
9779
|
+
startOutcome,
|
|
9780
|
+
targetName,
|
|
9781
|
+
startReceipt
|
|
9782
|
+
);
|
|
9783
|
+
const projectionOk = await attemptRecordedIssueLabelProjection(
|
|
9784
|
+
options,
|
|
9785
|
+
prdRef,
|
|
9786
|
+
resumeIssueNumber,
|
|
9787
|
+
originalGuidance
|
|
9282
9788
|
);
|
|
9789
|
+
if (!projectionOk && originalGuidance) {
|
|
9790
|
+
const updatedRecord = readPrdRun(options.repoRoot, prdRef).record;
|
|
9791
|
+
return {
|
|
9792
|
+
kind: "blocked",
|
|
9793
|
+
prdRef,
|
|
9794
|
+
guidance: updatedRecord.repairGuidance,
|
|
9795
|
+
start: startOutcome,
|
|
9796
|
+
resume: plan
|
|
9797
|
+
};
|
|
9798
|
+
}
|
|
9799
|
+
return result;
|
|
9283
9800
|
} catch (error) {
|
|
9284
9801
|
const msg = error instanceof Error ? error.message : String(error);
|
|
9285
9802
|
const diagnostics = [msg];
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
status: "blocked",
|
|
9289
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9290
|
-
targetName,
|
|
9291
|
-
start: startReceipt,
|
|
9292
|
-
blockedGate: "queue",
|
|
9293
|
-
blockedReason: msg,
|
|
9294
|
-
diagnostics,
|
|
9295
|
-
offendingPaths: []
|
|
9296
|
-
});
|
|
9297
|
-
return buildLaunchBlockedOutcome(
|
|
9803
|
+
const result = buildLaunchBlockedOutcome(
|
|
9804
|
+
options.repoRoot,
|
|
9298
9805
|
prdRef,
|
|
9299
|
-
{
|
|
9806
|
+
buildPrdRunRepairGuidance({
|
|
9300
9807
|
blockedGate: "queue",
|
|
9301
|
-
|
|
9302
|
-
|
|
9808
|
+
blockedStage: "queue-drain",
|
|
9809
|
+
failureCode: "queue-exception",
|
|
9810
|
+
humanReadableReason: msg,
|
|
9303
9811
|
repairability: "automatic-retry-safe",
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9812
|
+
nextAction: "rerun-prd-run-launch",
|
|
9813
|
+
nextRecommendedCommand: "pourkit prd-run launch",
|
|
9814
|
+
diagnostics
|
|
9815
|
+
}),
|
|
9307
9816
|
plan,
|
|
9308
|
-
startOutcome
|
|
9817
|
+
startOutcome,
|
|
9818
|
+
targetName,
|
|
9819
|
+
startReceipt
|
|
9309
9820
|
);
|
|
9821
|
+
const projectionOk = await attemptRecordedIssueLabelProjection(
|
|
9822
|
+
options,
|
|
9823
|
+
prdRef,
|
|
9824
|
+
resumeIssueNumber,
|
|
9825
|
+
originalGuidance
|
|
9826
|
+
);
|
|
9827
|
+
if (!projectionOk && originalGuidance) {
|
|
9828
|
+
const updatedRecord = readPrdRun(options.repoRoot, prdRef).record;
|
|
9829
|
+
return {
|
|
9830
|
+
kind: "blocked",
|
|
9831
|
+
prdRef,
|
|
9832
|
+
guidance: updatedRecord.repairGuidance,
|
|
9833
|
+
start: startOutcome,
|
|
9834
|
+
resume: plan
|
|
9835
|
+
};
|
|
9836
|
+
}
|
|
9837
|
+
return result;
|
|
9310
9838
|
}
|
|
9311
9839
|
}
|
|
9312
9840
|
|
|
@@ -9357,7 +9885,7 @@ function mapLaunchPrdRunOutcomeToCommandResult(outcome, options) {
|
|
|
9357
9885
|
};
|
|
9358
9886
|
}
|
|
9359
9887
|
if (outcome.kind === "blocked") {
|
|
9360
|
-
const diagnostics = outcome.guidance
|
|
9888
|
+
const diagnostics = renderPrdRunRepairGuidance(outcome.guidance);
|
|
9361
9889
|
return {
|
|
9362
9890
|
prdRef,
|
|
9363
9891
|
status: "blocked",
|
|
@@ -9366,7 +9894,7 @@ function mapLaunchPrdRunOutcomeToCommandResult(outcome, options) {
|
|
|
9366
9894
|
resumed: [...outcome.resume.resumed],
|
|
9367
9895
|
diagnostics,
|
|
9368
9896
|
blockedGate: outcome.guidance.blockedGate,
|
|
9369
|
-
blockedReason: outcome.guidance.
|
|
9897
|
+
blockedReason: outcome.guidance.humanReadableReason,
|
|
9370
9898
|
offendingPaths: outcome.guidance.offendingPaths ? [...outcome.guidance.offendingPaths] : [],
|
|
9371
9899
|
start: outcome.start ? mapStartPrdRunOutcomeToCommandResult(outcome.start) : void 0
|
|
9372
9900
|
};
|
|
@@ -9391,27 +9919,40 @@ function mapStartPrdRunOutcomeToCommandResult(outcome) {
|
|
|
9391
9919
|
diagnostics: [...outcome.diagnostics]
|
|
9392
9920
|
};
|
|
9393
9921
|
}
|
|
9394
|
-
const diagnostics = outcome.guidance.diagnostics ? [...outcome.guidance.diagnostics] : [outcome.guidance.reason];
|
|
9395
9922
|
return {
|
|
9396
9923
|
prdRef: outcome.prdRef,
|
|
9397
9924
|
status: "blocked",
|
|
9398
9925
|
blockedGate: outcome.guidance.blockedGate,
|
|
9399
|
-
blockedReason: outcome.guidance.
|
|
9400
|
-
diagnostics,
|
|
9926
|
+
blockedReason: outcome.guidance.humanReadableReason,
|
|
9927
|
+
diagnostics: renderPrdRunRepairGuidance(outcome.guidance),
|
|
9401
9928
|
offendingPaths: outcome.guidance.offendingPaths ? [...outcome.guidance.offendingPaths] : []
|
|
9402
9929
|
};
|
|
9403
9930
|
}
|
|
9404
9931
|
function runPrdRunStatusCommand(options) {
|
|
9405
9932
|
const prdRef = normalizePrdRunRef(options.prdRef);
|
|
9406
9933
|
const { record, diagnostics } = readPrdRun(options.repoRoot, prdRef);
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9934
|
+
if (record?.status === "completed_prd_branch") {
|
|
9935
|
+
return {
|
|
9936
|
+
prdRef,
|
|
9937
|
+
record,
|
|
9938
|
+
diagnostics: [
|
|
9939
|
+
...diagnostics,
|
|
9940
|
+
buildCompletedPrdBranchHint(record.prdBranch ?? prdRef)
|
|
9941
|
+
]
|
|
9942
|
+
};
|
|
9943
|
+
}
|
|
9944
|
+
if (record?.status === "blocked") {
|
|
9945
|
+
const validated = validateActivePrdRunRepairGuidance(record);
|
|
9946
|
+
return {
|
|
9947
|
+
prdRef,
|
|
9948
|
+
record,
|
|
9949
|
+
diagnostics: [
|
|
9950
|
+
...diagnostics,
|
|
9951
|
+
...renderPrdRunRepairGuidance(validated.guidance)
|
|
9952
|
+
]
|
|
9953
|
+
};
|
|
9954
|
+
}
|
|
9955
|
+
return { prdRef, record, diagnostics };
|
|
9415
9956
|
}
|
|
9416
9957
|
function runPrdRunListCommand(options) {
|
|
9417
9958
|
return listPrdRuns(options.repoRoot);
|
|
@@ -10093,9 +10634,9 @@ Recall before substantial work: before starting non-trivial planning or implemen
|
|
|
10093
10634
|
|
|
10094
10635
|
Capture durable knowledge: store concise reusable observations when a durable resolved error, design decision, user preference, significant outcome, or long-session progress summary is discovered. Do not store trivial details, raw logs, transcripts, tool output, git status, prompt dumps, secrets, or ephemeral state.
|
|
10095
10636
|
|
|
10096
|
-
Database path:
|
|
10637
|
+
Database path: host CLI commands must pass \`--db .pourkit/icm/memories.db\` from the repository root. Pourkit-launched Docker runs set \`$POURKIT_ICM_DB\` to the mounted container DB path for runtime plumbing. The Pourkit Memory Store is repo-scoped; do not use a global ICM database or topic naming as the isolation boundary.
|
|
10097
10638
|
|
|
10098
|
-
CLI fallback: when MCP memory tools are unavailable, recall with \`icm --db
|
|
10639
|
+
CLI fallback: when MCP memory tools are unavailable, recall with \`icm --db .pourkit/icm/memories.db recall "<query>"\`, and store durable observations with \`icm --db .pourkit/icm/memories.db store -c "<concise reusable observation>"\`.
|
|
10099
10640
|
|
|
10100
10641
|
Memory is advisory only. Never treat memory as a replacement for reading current repository files, Run Context, artifacts, or verification output. When memory conflicts with current source or canonical state, current source and canonical state win.
|
|
10101
10642
|
|
|
@@ -10107,17 +10648,17 @@ You MUST use it actively. Not optional.
|
|
|
10107
10648
|
|
|
10108
10649
|
### Recall (before starting work)
|
|
10109
10650
|
\`\`\`bash
|
|
10110
|
-
icm recall "query" # search memories
|
|
10111
|
-
icm recall "query" -t "topic-name" # filter by topic
|
|
10112
|
-
icm recall-context "query" --limit 5 # formatted for prompt injection
|
|
10651
|
+
icm --db .pourkit/icm/memories.db recall "query" # search memories
|
|
10652
|
+
icm --db .pourkit/icm/memories.db recall "query" -t "topic-name" # filter by topic
|
|
10653
|
+
icm --db .pourkit/icm/memories.db recall-context "query" --limit 5 # formatted for prompt injection
|
|
10113
10654
|
\`\`\`
|
|
10114
10655
|
|
|
10115
10656
|
### Store \u2014 MANDATORY triggers
|
|
10116
|
-
You MUST call \`icm store\` when ANY of the following happens:
|
|
10117
|
-
1. **Error resolved** \u2192 \`icm store -t errors-resolved -c "description" -i high -k "keyword1,keyword2"\`
|
|
10118
|
-
2. **Architecture/design decision** \u2192 \`icm store -t decisions-{project} -c "description" -i high\`
|
|
10119
|
-
3. **User preference discovered** \u2192 \`icm store -t preferences -c "description" -i critical\`
|
|
10120
|
-
4. **Significant task completed** \u2192 \`icm store -t context-{project} -c "summary of work done" -i high\`
|
|
10657
|
+
You MUST call \`icm --db .pourkit/icm/memories.db store\` when ANY of the following happens:
|
|
10658
|
+
1. **Error resolved** \u2192 \`icm --db .pourkit/icm/memories.db store -t errors-resolved -c "description" -i high -k "keyword1,keyword2"\`
|
|
10659
|
+
2. **Architecture/design decision** \u2192 \`icm --db .pourkit/icm/memories.db store -t decisions-{project} -c "description" -i high\`
|
|
10660
|
+
3. **User preference discovered** \u2192 \`icm --db .pourkit/icm/memories.db store -t preferences -c "description" -i critical\`
|
|
10661
|
+
4. **Significant task completed** \u2192 \`icm --db .pourkit/icm/memories.db store -t context-{project} -c "summary of work done" -i high\`
|
|
10121
10662
|
5. **Conversation exceeds ~20 tool calls without a store** \u2192 store a progress summary
|
|
10122
10663
|
|
|
10123
10664
|
Do this BEFORE responding to the user. Not after. Not later. Immediately.
|
|
@@ -10126,9 +10667,9 @@ Do NOT store: trivial details, info already in CLAUDE.md, ephemeral state (build
|
|
|
10126
10667
|
|
|
10127
10668
|
### Other commands
|
|
10128
10669
|
\`\`\`bash
|
|
10129
|
-
icm update <id> -c "updated content" # edit memory in-place
|
|
10130
|
-
icm health # topic hygiene audit
|
|
10131
|
-
icm topics # list all topics
|
|
10670
|
+
icm --db .pourkit/icm/memories.db update <id> -c "updated content" # edit memory in-place
|
|
10671
|
+
icm --db .pourkit/icm/memories.db health # topic hygiene audit
|
|
10672
|
+
icm --db .pourkit/icm/memories.db topics # list all topics
|
|
10132
10673
|
\`\`\`
|
|
10133
10674
|
<!-- icm:end -->`;
|
|
10134
10675
|
}
|
|
@@ -12296,9 +12837,13 @@ Init applied: ${result.applied} operations applied, ${result.skipped} skipped.`
|
|
|
12296
12837
|
|
|
12297
12838
|
// commands/memory-init.ts
|
|
12298
12839
|
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync5 } from "fs";
|
|
12840
|
+
import { execFile as execFile3 } from "child_process";
|
|
12299
12841
|
import { join as join17 } from "path";
|
|
12842
|
+
import { promisify as promisify3 } from "util";
|
|
12843
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
12300
12844
|
async function runMemoryInitCommand(options) {
|
|
12301
12845
|
const cwd = options.cwd ?? process.cwd();
|
|
12846
|
+
const execCommand = options.execCommand ?? execFileAsync3;
|
|
12302
12847
|
const configPath = join17(cwd, ".pourkit", "config.json");
|
|
12303
12848
|
if (!existsSync17(configPath)) {
|
|
12304
12849
|
return {
|
|
@@ -12331,7 +12876,21 @@ async function runMemoryInitCommand(options) {
|
|
|
12331
12876
|
const next = { ...raw, memory };
|
|
12332
12877
|
writeFileSync5(configPath, JSON.stringify(next, null, 2) + "\n");
|
|
12333
12878
|
}
|
|
12334
|
-
|
|
12879
|
+
const memoryDir = join17(cwd, ".pourkit", "icm");
|
|
12880
|
+
const memoryDbPath = join17(memoryDir, "memories.db");
|
|
12881
|
+
mkdirSync8(memoryDir, { recursive: true });
|
|
12882
|
+
let dbInitialized = false;
|
|
12883
|
+
let warning;
|
|
12884
|
+
try {
|
|
12885
|
+
await execCommand(
|
|
12886
|
+
"icm",
|
|
12887
|
+
["--db", memoryDbPath, "recall", "pourkit memory init smoke"],
|
|
12888
|
+
{ cwd }
|
|
12889
|
+
);
|
|
12890
|
+
dbInitialized = true;
|
|
12891
|
+
} catch {
|
|
12892
|
+
warning = "ICM is not available or could not initialize .pourkit/icm/memories.db. Install ICM and run `pourkit doctor` to verify repo-scoped memory setup.";
|
|
12893
|
+
}
|
|
12335
12894
|
const gitignorePath = join17(cwd, ".gitignore");
|
|
12336
12895
|
updateManagedBlockSync(gitignorePath, generateGitignoreBlock());
|
|
12337
12896
|
const managed = await generateManagedAgentInstructions({
|
|
@@ -12352,7 +12911,9 @@ async function runMemoryInitCommand(options) {
|
|
|
12352
12911
|
return {
|
|
12353
12912
|
ok: true,
|
|
12354
12913
|
alreadyEnabled,
|
|
12355
|
-
|
|
12914
|
+
dbInitialized,
|
|
12915
|
+
warning,
|
|
12916
|
+
message: `${alreadyEnabled ? "Memory is already enabled. Refreshed repo-scoped memory setup." : "Memory enabled. Run `pourkit doctor` to verify setup."}${warning ? ` ${warning}` : ""}`
|
|
12356
12917
|
};
|
|
12357
12918
|
}
|
|
12358
12919
|
function updateManagedBlockSync(filePath, content) {
|
|
@@ -12494,7 +13055,7 @@ async function runSerenaStatusCommand(options) {
|
|
|
12494
13055
|
// commands/config-schema.ts
|
|
12495
13056
|
import { readFileSync as readFileSync18, existsSync as existsSync18 } from "fs";
|
|
12496
13057
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile2, readdir as readdir2 } from "fs/promises";
|
|
12497
|
-
import { resolve as resolve3, dirname as dirname5, relative as
|
|
13058
|
+
import { resolve as resolve3, dirname as dirname5, relative as relative3 } from "path";
|
|
12498
13059
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
12499
13060
|
import Ajv2 from "ajv";
|
|
12500
13061
|
init_common();
|
|
@@ -12533,6 +13094,8 @@ function localSchemaDir(repoRoot2) {
|
|
|
12533
13094
|
return resolve3(repoRoot2, ".pourkit/schema");
|
|
12534
13095
|
}
|
|
12535
13096
|
var MANAGED_BLOCK_BEGIN2 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
|
|
13097
|
+
var MANAGED_BLOCK_BEGIN_MARKER = MANAGED_BLOCK_BEGIN2.trim();
|
|
13098
|
+
var MANAGED_BLOCK_END_MARKER = "<!-- END POURKIT MANAGED BLOCK -->";
|
|
12536
13099
|
var OLD_DOCS_PATH_PATTERN = ".pourkit/docs/agents/";
|
|
12537
13100
|
function resolvePackagedManagedPath(...segments) {
|
|
12538
13101
|
return resolve3(__dirname3, "..", "managed", ...segments);
|
|
@@ -12557,7 +13120,7 @@ async function readPackagedTextFile(filePath) {
|
|
|
12557
13120
|
}
|
|
12558
13121
|
}
|
|
12559
13122
|
function isPathContained(parent, child) {
|
|
12560
|
-
const relativePath =
|
|
13123
|
+
const relativePath = relative3(parent, child);
|
|
12561
13124
|
return !relativePath.startsWith("..") && !relativePath.startsWith("../");
|
|
12562
13125
|
}
|
|
12563
13126
|
async function walkDir2(dir) {
|
|
@@ -12812,7 +13375,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12812
13375
|
if (existsSync18(overridesDir)) {
|
|
12813
13376
|
const overrideFiles = await walkDir2(overridesDir);
|
|
12814
13377
|
for (const file of overrideFiles) {
|
|
12815
|
-
const relPath =
|
|
13378
|
+
const relPath = relative3(cwd, file);
|
|
12816
13379
|
if (!warnings.some((w) => w.kind === "overridden" && w.path === relPath)) {
|
|
12817
13380
|
warnings.push({
|
|
12818
13381
|
severity: "warning",
|
|
@@ -12952,8 +13515,8 @@ async function validateWorkflowPack(cwd) {
|
|
|
12952
13515
|
failures.push({
|
|
12953
13516
|
severity: "failure",
|
|
12954
13517
|
kind: "path_escape",
|
|
12955
|
-
path:
|
|
12956
|
-
message: `Override file path escapes repository: ${
|
|
13518
|
+
path: relative3(cwd, file),
|
|
13519
|
+
message: `Override file path escapes repository: ${relative3(cwd, file)}`
|
|
12957
13520
|
});
|
|
12958
13521
|
}
|
|
12959
13522
|
}
|
|
@@ -12965,7 +13528,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12965
13528
|
if (!file.endsWith(".md")) continue;
|
|
12966
13529
|
try {
|
|
12967
13530
|
const content = await readFile5(file, "utf-8");
|
|
12968
|
-
const relPath =
|
|
13531
|
+
const relPath = relative3(cwd, file);
|
|
12969
13532
|
const violations = scanManagedPolicyText(content, relPath);
|
|
12970
13533
|
for (const v of violations) {
|
|
12971
13534
|
failures.push({
|
|
@@ -12988,7 +13551,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12988
13551
|
if (!existsSync18(skillFile)) continue;
|
|
12989
13552
|
try {
|
|
12990
13553
|
const content = await readFile5(skillFile, "utf-8");
|
|
12991
|
-
const relPath =
|
|
13554
|
+
const relPath = relative3(cwd, skillFile);
|
|
12992
13555
|
const violations = scanManagedPolicyText(content, relPath);
|
|
12993
13556
|
for (const v of violations) {
|
|
12994
13557
|
failures.push({
|
|
@@ -13009,7 +13572,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
13009
13572
|
if (!existsSync18(promptFile)) continue;
|
|
13010
13573
|
try {
|
|
13011
13574
|
const content = await readFile5(promptFile, "utf-8");
|
|
13012
|
-
const relPath =
|
|
13575
|
+
const relPath = relative3(cwd, promptFile);
|
|
13013
13576
|
const violations = scanManagedPolicyText(content, relPath);
|
|
13014
13577
|
for (const v of violations) {
|
|
13015
13578
|
failures.push({
|
|
@@ -13031,7 +13594,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
13031
13594
|
if (!existsSync18(addonSkillFile)) continue;
|
|
13032
13595
|
try {
|
|
13033
13596
|
const content = await readFile5(addonSkillFile, "utf-8");
|
|
13034
|
-
const relPath =
|
|
13597
|
+
const relPath = relative3(cwd, addonSkillFile);
|
|
13035
13598
|
const violations = scanManagedPolicyText(content, relPath);
|
|
13036
13599
|
for (const v of violations) {
|
|
13037
13600
|
failures.push({
|
|
@@ -13052,7 +13615,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
13052
13615
|
if (!existsSync18(addonDocFile)) continue;
|
|
13053
13616
|
try {
|
|
13054
13617
|
const content = await readFile5(addonDocFile, "utf-8");
|
|
13055
|
-
const relPath =
|
|
13618
|
+
const relPath = relative3(cwd, addonDocFile);
|
|
13056
13619
|
const violations = scanManagedPolicyText(content, relPath);
|
|
13057
13620
|
for (const v of violations) {
|
|
13058
13621
|
failures.push({
|
|
@@ -13090,21 +13653,53 @@ async function validateMemoryHealth(cwd, memoryConfig) {
|
|
|
13090
13653
|
ok: hasGitignoreEntry,
|
|
13091
13654
|
detail: hasGitignoreEntry ? ".gitignore covers .pourkit/icm/" : ".gitignore does not cover .pourkit/icm/"
|
|
13092
13655
|
});
|
|
13656
|
+
const memoryDbPath = resolve3(cwd, ".pourkit", "icm", "memories.db");
|
|
13657
|
+
const hasMemoryDb = existsSync18(memoryDbPath);
|
|
13658
|
+
checks.push({
|
|
13659
|
+
name: "icm-db-exists",
|
|
13660
|
+
ok: hasMemoryDb,
|
|
13661
|
+
detail: hasMemoryDb ? ".pourkit/icm/memories.db exists" : ".pourkit/icm/memories.db is missing"
|
|
13662
|
+
});
|
|
13093
13663
|
const shapeValid = memoryConfig.enabled === true && memoryConfig.provider === "icm";
|
|
13094
13664
|
checks.push({
|
|
13095
13665
|
name: "config-memory-shape",
|
|
13096
13666
|
ok: shapeValid,
|
|
13097
13667
|
detail: shapeValid ? "memory: { enabled: true, provider: icm }" : `invalid memory config: enabled=${memoryConfig.enabled}, provider=${memoryConfig.provider}`
|
|
13098
13668
|
});
|
|
13669
|
+
const staleAgentFiles = ["AGENTS.md", "CLAUDE.md"].filter((fileName) => {
|
|
13670
|
+
const filePath = resolve3(cwd, fileName);
|
|
13671
|
+
if (!existsSync18(filePath)) return false;
|
|
13672
|
+
const content = readFileSync18(filePath, "utf-8");
|
|
13673
|
+
const managedBlock = extractManagedBlockContent(content);
|
|
13674
|
+
return managedBlock !== null && hasBareIcmMemoryCommand(managedBlock);
|
|
13675
|
+
});
|
|
13676
|
+
checks.push({
|
|
13677
|
+
name: "agent-memory-instructions",
|
|
13678
|
+
ok: staleAgentFiles.length === 0,
|
|
13679
|
+
detail: staleAgentFiles.length === 0 ? "managed agent memory instructions avoid bare ICM commands" : `stale bare ICM commands found in ${staleAgentFiles.join(", ")}`
|
|
13680
|
+
});
|
|
13099
13681
|
checks.push({
|
|
13100
13682
|
name: "docker-image-advisory",
|
|
13101
13683
|
ok: true,
|
|
13102
13684
|
detail: "advisory only"
|
|
13103
13685
|
});
|
|
13104
13686
|
const ok = checks.filter((c) => c.name !== "docker-image-advisory").every((c) => c.ok);
|
|
13105
|
-
const recommendation = ok ? null : "Run `pourkit memory init` to repair ICM memory setup, install ICM on PATH for host planning, or rebuild the sandbox image for Docker runs.";
|
|
13687
|
+
const recommendation = ok ? null : "Run `pourkit memory init` or `pourkit sync workflow-pack` to repair ICM memory setup, install ICM on PATH for host planning, or rebuild the sandbox image for Docker runs.";
|
|
13106
13688
|
return { ok, enabled: true, checks, recommendation };
|
|
13107
13689
|
}
|
|
13690
|
+
function hasBareIcmMemoryCommand(content) {
|
|
13691
|
+
return /(^|\n)\s*icm\s+(recall|recall-context|store|update|health|topics)\b/.test(
|
|
13692
|
+
content
|
|
13693
|
+
) || /`icm\s+(recall|recall-context|store|update|health|topics)\b/.test(content);
|
|
13694
|
+
}
|
|
13695
|
+
function extractManagedBlockContent(content) {
|
|
13696
|
+
const beginIdx = content.indexOf(MANAGED_BLOCK_BEGIN_MARKER);
|
|
13697
|
+
if (beginIdx === -1) return null;
|
|
13698
|
+
const contentStart = beginIdx + MANAGED_BLOCK_BEGIN_MARKER.length;
|
|
13699
|
+
const endIdx = content.indexOf(MANAGED_BLOCK_END_MARKER, contentStart);
|
|
13700
|
+
if (endIdx === -1) return null;
|
|
13701
|
+
return content.slice(contentStart, endIdx);
|
|
13702
|
+
}
|
|
13108
13703
|
async function runDoctorCommand(options) {
|
|
13109
13704
|
const repoRootPath = options.cwd ?? process.cwd();
|
|
13110
13705
|
const schemaDir = localSchemaDir(repoRootPath);
|
|
@@ -13245,7 +13840,7 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
13245
13840
|
// commands/workflow-pack-sync.ts
|
|
13246
13841
|
import { existsSync as existsSync19, readdirSync as readdirSync4 } from "fs";
|
|
13247
13842
|
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir3 } from "fs/promises";
|
|
13248
|
-
import { resolve as resolve4, dirname as dirname6, relative as
|
|
13843
|
+
import { resolve as resolve4, dirname as dirname6, relative as relative4, normalize as normalize2 } from "path";
|
|
13249
13844
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13250
13845
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
13251
13846
|
var __dirname4 = dirname6(__filename4);
|
|
@@ -13288,7 +13883,7 @@ async function readPackagedTextFile2(filePath) {
|
|
|
13288
13883
|
}
|
|
13289
13884
|
}
|
|
13290
13885
|
function isPathContained2(parent, child) {
|
|
13291
|
-
const relativePath =
|
|
13886
|
+
const relativePath = relative4(parent, child);
|
|
13292
13887
|
return !relativePath.startsWith("..") && !relativePath.startsWith("../");
|
|
13293
13888
|
}
|
|
13294
13889
|
function isProjectOwnedPath(relativePath) {
|
|
@@ -13397,7 +13992,7 @@ async function detectOverrides(cwd) {
|
|
|
13397
13992
|
return [];
|
|
13398
13993
|
}
|
|
13399
13994
|
const files = await walkDir3(overridesDir);
|
|
13400
|
-
return files.map((f) =>
|
|
13995
|
+
return files.map((f) => relative4(cwd, f));
|
|
13401
13996
|
}
|
|
13402
13997
|
async function detectProjectOwnedFiles(cwd) {
|
|
13403
13998
|
const found = [];
|
|
@@ -13412,7 +14007,7 @@ async function detectProjectOwnedFiles(cwd) {
|
|
|
13412
14007
|
if (existsSync19(fullDir)) {
|
|
13413
14008
|
const files = await walkDir3(fullDir);
|
|
13414
14009
|
for (const file of files) {
|
|
13415
|
-
found.push(
|
|
14010
|
+
found.push(relative4(cwd, file));
|
|
13416
14011
|
}
|
|
13417
14012
|
}
|
|
13418
14013
|
}
|
|
@@ -13665,7 +14260,7 @@ async function syncSkill(skillName, catalog, acc, ctx) {
|
|
|
13665
14260
|
return;
|
|
13666
14261
|
}
|
|
13667
14262
|
for (const sourceFile of skillFiles) {
|
|
13668
|
-
const relPath =
|
|
14263
|
+
const relPath = relative4(skillDir, sourceFile);
|
|
13669
14264
|
const targetRelativePath = `.pourkit/managed/skills/${skillName}/${relPath}`;
|
|
13670
14265
|
if (isProjectOwnedPath(targetRelativePath)) {
|
|
13671
14266
|
skippedProjectOwned.push(targetRelativePath);
|
|
@@ -13741,7 +14336,7 @@ async function syncAddonSkill(skillName, acc, ctx) {
|
|
|
13741
14336
|
return;
|
|
13742
14337
|
}
|
|
13743
14338
|
for (const sourceFile of skillFiles) {
|
|
13744
|
-
const relPath =
|
|
14339
|
+
const relPath = relative4(addonSkillDir, sourceFile);
|
|
13745
14340
|
const targetRelativePath = `.pourkit/managed/addons/release/skills/${skillName}/${relPath}`;
|
|
13746
14341
|
if (isProjectOwnedPath(targetRelativePath)) {
|
|
13747
14342
|
skippedProjectOwned.push(targetRelativePath);
|
|
@@ -15533,11 +16128,11 @@ function createCliProgram(version) {
|
|
|
15533
16128
|
return program;
|
|
15534
16129
|
}
|
|
15535
16130
|
async function resolveCliVersion() {
|
|
15536
|
-
if (isPackageVersion("0.0.0-next-
|
|
15537
|
-
return "0.0.0-next-
|
|
16131
|
+
if (isPackageVersion("0.0.0-next-20260625065443")) {
|
|
16132
|
+
return "0.0.0-next-20260625065443";
|
|
15538
16133
|
}
|
|
15539
|
-
if (isReleaseVersion("0.0.0-next-
|
|
15540
|
-
return "0.0.0-next-
|
|
16134
|
+
if (isReleaseVersion("0.0.0-next-20260625065443")) {
|
|
16135
|
+
return "0.0.0-next-20260625065443";
|
|
15541
16136
|
}
|
|
15542
16137
|
try {
|
|
15543
16138
|
const root = repoRoot();
|