@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 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: ${reviewArtifactPath}
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 = z.object({
7407
- prdRef: z.string().regex(
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: z.enum([
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: z.string().min(1),
7419
- blockedGate: z.enum(["receipt-check", "branch-state", "git", "queue", "final-review"]).optional(),
7420
- targetName: z.string().min(1).optional(),
7421
- prdBranch: z.string().min(1).optional(),
7422
- blockedReason: z.string().min(1).optional(),
7423
- diagnostics: z.array(z.string()).optional(),
7424
- offendingPaths: z.array(z.string()).optional(),
7425
- start: z.object({
7426
- status: z.enum(["started", "succeeded", "adopted", "reused"]),
7427
- targetName: z.string().min(1),
7428
- prdBranch: z.string().min(1),
7429
- startBaseBranch: z.string().min(1),
7430
- startBaseCommit: z.string().min(1).optional(),
7431
- branchAction: z.enum(["created", "reused", "adopted"]).optional(),
7432
- startedAt: z.string().min(1).optional(),
7433
- queueStartedAt: z.string().min(1).optional(),
7434
- queueDrainedAt: z.string().min(1).optional(),
7435
- queueProcessedCount: z.number().int().nonnegative().optional(),
7436
- queueCommand: z.literal("queue-run").optional(),
7437
- refreshReceipts: z.tuple([]).optional()
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: z.object({
7440
- status: z.enum([
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: z.string().min(1),
7448
- prdBranch: z.string().min(1),
7449
- mergeBase: z.string().min(1).optional(),
7450
- verdict: z.enum([
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: z.string().min(1).optional(),
7457
- diagnostics: z.array(z.string()).optional(),
7458
- reviewedAt: z.string().min(1).optional(),
7459
- retouchPrNumber: z.number().int().positive().optional(),
7460
- retouchPrUrl: z.string().url().optional(),
7461
- retouchMergeCommit: z.string().min(1).optional(),
7462
- autoMerge: z.boolean().optional(),
7463
- changedPaths: z.array(z.string()).optional()
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: z.array(
7466
- z.object({
7467
- issueNumber: z.number().int().positive(),
7468
- decision: z.literal("accepted_scope_change"),
7469
- reason: z.string().min(1),
7470
- acceptedBy: z.string().min(1),
7471
- acceptedAt: z.string().min(1)
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 outcome = yield* selectNextQueueIssue({
7908
- config,
7909
- issueProvider,
7910
- logger,
7911
- prdRef
7912
- });
7913
- if (!outcome.ok) {
7914
- return {
7915
- selected: null,
7916
- reason: outcome.reason,
7917
- code: outcome.code
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: selected.number,
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
- failureCode: "missing_start_evidence",
8027
- reason: `PRD Run ${context.prdRef} has no start receipt.`,
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
- diagnostics: [],
8030
- offendingPaths: []
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
- failureCode: "missing_start_base_branch",
8040
- reason: `PRD Run ${context.prdRef} start receipt missing startBaseBranch.`,
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
- diagnostics: [],
8043
- offendingPaths: []
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
- failureCode: "base_mismatch",
8053
- reason: `PRD Run ${context.prdRef} startBaseBranch "${record.start.startBaseBranch}" does not match expected "${context.baseBranch}".`,
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
- offendingPaths: []
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
- failureCode: "missing_prd_branch",
8069
- reason: `PRD Run ${context.prdRef} start receipt missing prdBranch.`,
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
- diagnostics: [],
8072
- offendingPaths: []
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
- failureCode: "prd_ref_mismatch",
8082
- reason: `PRD Run prdRef mismatch: "${record.prdRef}" does not match expected "${context.prdRef}".`,
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
- offendingPaths: []
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
- failureCode: "missing_drain_evidence",
8102
- reason: `PRD Run ${context.prdRef} has no start receipt for drain validation.`,
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
- diagnostics: [],
8105
- offendingPaths: []
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
- failureCode: "missing_queue_started_at",
8115
- reason: `PRD Run ${context.prdRef} drain evidence missing queueStartedAt.`,
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
- diagnostics: [],
8118
- offendingPaths: []
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
- failureCode: "missing_queue_command",
8128
- reason: `PRD Run ${context.prdRef} drain evidence missing queue-run command.`,
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
- diagnostics: [],
8131
- offendingPaths: []
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
- failureCode: "missing_queue_drained_at",
8141
- reason: `PRD Run ${context.prdRef} drain evidence missing queueDrainedAt.`,
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
- diagnostics: [],
8144
- offendingPaths: []
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
- failureCode: "missing_queue_processed_count",
8154
- reason: `PRD Run ${context.prdRef} drain evidence missing queueProcessedCount.`,
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
- diagnostics: [],
8157
- offendingPaths: []
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
- failureCode: "zero_processed",
8167
- reason: `PRD Run ${context.prdRef} queue drain processed zero issues.`,
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
- diagnostics: [`queueProcessedCount: ${start.queueProcessedCount}`],
8170
- offendingPaths: []
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
- failureCode: "prd_branch_mismatch",
8180
- reason: `PRD Run ${context.prdRef} prdBranch "${start.prdBranch}" does not match expected "${context.prdBranch}".`,
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
- offendingPaths: []
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
- failureCode: "missing_child_finalization_evidence",
8203
- reason: `PRD Run ${context.prdRef} is missing proof that all child Issues finalized into ${context.prdBranch}.`,
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
- diagnostics: [],
8206
- offendingPaths: []
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.reason,
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
- diagnostics: diagnostics ? [...diagnostics] : [],
8536
- repairability: "operator-action"
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
- "invalid_target_name",
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
- "base_resolution_failed",
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
- "missing_start_base_branch",
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
- "base_mismatch",
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
- "fetch_failed",
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
- "branch_inspection_failed",
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
- "unrecorded_branch_exists",
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
- "fetch_prd_branch_failed",
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
- "ancestry_check_failed",
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
- "fetch_failed",
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
- "branch_inspection_failed",
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
- "unrecorded_branch_exists",
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
- "fetch_prd_branch_failed",
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
- "ancestry_check_failed",
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
- "branch_creation_failed",
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
- failureCode: "unsupported_legacy_state",
8899
- reason: `PRD Run ${prdRef} has a malformed or unsupported record. The stored status is no longer a valid launch state.`,
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
- diagnostics: [...existingRecord.diagnostics],
8902
- offendingPaths: []
8903
- },
8904
- plan
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
- failureCode: "missing_drain_evidence",
8927
- reason: `PRD Run ${prdRef} is drained but missing start receipt.`,
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
- diagnostics: [],
8930
- offendingPaths: []
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
- failureCode: "base_resolution_failed",
8947
- reason: baseResolution.reason,
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(prdRef, terminalEvidence.guidance, plan);
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
- failureCode: "missing_start_receipt",
8992
- reason: `PRD Run ${prdRef} is missing branch/start state. Run prd-run start or rerun prd-run launch.`,
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
- offendingPaths: []
8998
- },
8999
- plan
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
- failureCode: "missing_github_providers",
9071
- reason,
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
- offendingPaths: []
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
- failureCode: "missing_start_receipt",
9098
- reason: `PRD Run ${prdRef} is missing start receipt before GitHub queue drain.`,
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
- diagnostics: [],
9101
- offendingPaths: []
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
- failureCode: "missing_config",
9125
- reason,
9599
+ blockedStage: "queue-drain",
9600
+ failureCode: "missing-config",
9601
+ humanReadableReason: reason,
9126
9602
  repairability: "operator-action",
9127
- diagnostics: ["Missing config for GitHub-backed mode."],
9128
- offendingPaths: []
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
- writePrdRunRecord(options.repoRoot, {
9161
- prdRef,
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
- failureCode: "zero_processed",
9176
- reason: diagnostics[0],
9646
+ blockedStage: "queue-drain",
9647
+ failureCode: "zero-processed",
9648
+ humanReadableReason: diagnostics[0],
9177
9649
  repairability: "automatic-retry-safe",
9178
- diagnostics,
9179
- offendingPaths: []
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
- writePrdRunRecord(options.repoRoot, {
9233
- prdRef,
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
- failureCode: "queue_blocked",
9248
- reason: outcome.reason,
9732
+ blockedStage: "queue-drain",
9733
+ failureCode: "queue-blocked",
9734
+ humanReadableReason: outcome.reason,
9249
9735
  repairability: "automatic-retry-safe",
9250
- diagnostics,
9251
- offendingPaths: []
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
- writePrdRunRecord(options.repoRoot, {
9260
- prdRef,
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
- failureCode: "unexpected_queue_outcome",
9275
- reason: outcomeReason,
9770
+ blockedStage: "queue-drain",
9771
+ failureCode: "unexpected-queue-outcome",
9772
+ humanReadableReason: outcomeReason,
9276
9773
  repairability: "operator-action",
9277
- diagnostics: outcomeDiagnostics,
9278
- offendingPaths: []
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
- writePrdRunRecord(options.repoRoot, {
9287
- prdRef,
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
- failureCode: "queue_exception",
9302
- reason: msg,
9808
+ blockedStage: "queue-drain",
9809
+ failureCode: "queue-exception",
9810
+ humanReadableReason: msg,
9303
9811
  repairability: "automatic-retry-safe",
9304
- diagnostics,
9305
- offendingPaths: []
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.diagnostics ? [...outcome.guidance.diagnostics] : [outcome.guidance.reason];
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.reason,
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.reason,
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
- return {
9408
- prdRef,
9409
- record,
9410
- diagnostics: record?.status === "completed_prd_branch" ? [
9411
- ...diagnostics,
9412
- buildCompletedPrdBranchHint(record.prdBranch ?? prdRef)
9413
- ] : diagnostics
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: use \`$POURKIT_ICM_DB\` when set, otherwise use \`.pourkit/icm/memories.db\`. The Pourkit Memory Store is repo-scoped; do not use a global ICM database or topic naming as the isolation boundary.
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 "$POURKIT_ICM_DB" recall "<query>"\` or \`icm --db .pourkit/icm/memories.db recall "<query>"\`, and store durable observations with \`icm --db "$POURKIT_ICM_DB" store -c "<concise reusable observation>"\` or \`icm --db .pourkit/icm/memories.db store -c "<concise reusable observation>"\`.
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
- mkdirSync8(join17(cwd, ".pourkit", "icm"), { recursive: true });
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
- message: alreadyEnabled ? "Memory is already enabled. Refreshed repo-scoped memory setup." : "Memory enabled. Run `pourkit doctor` to verify setup."
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 relative2 } from "path";
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 = relative2(parent, child);
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 = relative2(cwd, file);
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: relative2(cwd, file),
12956
- message: `Override file path escapes repository: ${relative2(cwd, file)}`
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 = relative2(cwd, file);
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 = relative2(cwd, skillFile);
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 = relative2(cwd, promptFile);
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 = relative2(cwd, addonSkillFile);
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 = relative2(cwd, addonDocFile);
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 relative3, normalize as normalize2 } from "path";
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 = relative3(parent, child);
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) => relative3(cwd, 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(relative3(cwd, file));
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 = relative3(skillDir, sourceFile);
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 = relative3(addonSkillDir, sourceFile);
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-20260623054630")) {
15537
- return "0.0.0-next-20260623054630";
16131
+ if (isPackageVersion("0.0.0-next-20260625065443")) {
16132
+ return "0.0.0-next-20260625065443";
15538
16133
  }
15539
- if (isReleaseVersion("0.0.0-next-20260623054630")) {
15540
- return "0.0.0-next-20260623054630";
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();