@pourkit/cli 0.0.0-next-20260715085442 → 0.0.0-next-20260724200221

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
@@ -58,20 +58,20 @@ function createLogger(name, filePath) {
58
58
  );
59
59
  },
60
60
  async close() {
61
- await new Promise((resolve7) => {
61
+ await new Promise((resolve8) => {
62
62
  if (!fileStream) {
63
- resolve7();
63
+ resolve8();
64
64
  return;
65
65
  }
66
66
  const timer = setTimeout(() => {
67
67
  if (!fileStream.destroyed) {
68
68
  fileStream.destroy();
69
69
  }
70
- resolve7();
70
+ resolve8();
71
71
  }, 2e3);
72
72
  fileStream.end(() => {
73
73
  clearTimeout(timer);
74
- resolve7();
74
+ resolve8();
75
75
  });
76
76
  });
77
77
  }
@@ -266,7 +266,7 @@ async function execJson(command, args, options = {}) {
266
266
  return JSON.parse(result.stdout);
267
267
  }
268
268
  function sleep(ms) {
269
- return new Promise((resolve7) => setTimeout(resolve7, ms));
269
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
270
270
  }
271
271
  async function execCaptureWithRetry(command, args, options = {}) {
272
272
  const retries = options.retries ?? 3;
@@ -378,18 +378,6 @@ function applyStageAgentDefaults(agent) {
378
378
  outputRetries: applyOutputRetriesDefaults(agent.outputRetries)
379
379
  };
380
380
  }
381
- var DEFAULT_POST_COMPLETION_FINAL_REVIEW_PROMPT = "post-completion-final-review.prompt.md";
382
- function applyPostCompletionFinalReviewDefaults(agent, issueFinalReview) {
383
- if (agent) return applyStageAgentDefaults(agent);
384
- return applyStageAgentDefaults({
385
- agent: issueFinalReview.agent,
386
- model: issueFinalReview.model,
387
- variant: issueFinalReview.variant,
388
- env: issueFinalReview.env,
389
- promptTemplate: DEFAULT_POST_COMPLETION_FINAL_REVIEW_PROMPT,
390
- outputRetries: issueFinalReview.outputRetries
391
- });
392
- }
393
381
  function assertRepoRelativePath(value, location) {
394
382
  const normalized = normalize(value);
395
383
  if (isAbsolute(value) || isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${sep}`)) {
@@ -526,9 +514,8 @@ function normalizePourkitConfig(input) {
526
514
  ),
527
515
  maxAttempts: t.strategy.issueFinalReview.maxAttempts
528
516
  },
529
- postCompletionFinalReview: applyPostCompletionFinalReviewDefaults(
530
- t.strategy.postCompletionFinalReview,
531
- t.strategy.issueFinalReview
517
+ postCompletionFinalReview: applyStageAgentDefaults(
518
+ t.strategy.postCompletionFinalReview
532
519
  ),
533
520
  finalize: {
534
521
  prDescriptionAgent: applyStageAgentDefaults(
@@ -636,6 +623,16 @@ function getValidator() {
636
623
  }
637
624
  return _validate;
638
625
  }
626
+ function getPackagedConfigSchemaVersion() {
627
+ const schema = _schema ?? JSON.parse(readFileSync(SCHEMA_PATH, "utf-8"));
628
+ _schema = schema;
629
+ const props = schema.properties;
630
+ const schemaVersion = props?.schemaVersion?.const;
631
+ if (typeof schemaVersion !== "number" || !Number.isInteger(schemaVersion)) {
632
+ throw new Error("Packaged Pourkit config schema is missing schemaVersion");
633
+ }
634
+ return schemaVersion;
635
+ }
639
636
  function resolveMissingOrEmptyOutputRetries(config) {
640
637
  return config?.outputRetries?.missingOrEmpty ?? DEFAULT_MISSING_OR_EMPTY_OUTPUT_RETRIES;
641
638
  }
@@ -905,11 +902,11 @@ var OBSOLETE_CONFIG_PATHS = [
905
902
  ];
906
903
  var CANONICAL_CONFIG_PATH = ".pourkit/config.json";
907
904
  async function loadRepoConfig(repoRoot2, _configFileName) {
908
- const { existsSync: existsSync25 } = await import("fs");
905
+ const { existsSync: existsSync26 } = await import("fs");
909
906
  const { join: pjoin } = await import("path");
910
907
  for (const obPath of OBSOLETE_CONFIG_PATHS) {
911
908
  const fullPath = pjoin(repoRoot2, obPath);
912
- if (existsSync25(fullPath)) {
909
+ if (existsSync26(fullPath)) {
913
910
  const isRootJson = obPath === "pourkit.json";
914
911
  throw new Error(
915
912
  isRootJson ? `Found root ${obPath}, but Pourkit config now lives at ${CANONICAL_CONFIG_PATH}. Move the file and update "$schema" to "./schema/pourkit.schema.json".` : `Found ${obPath}, but executable config is no longer supported. Move configuration to ${CANONICAL_CONFIG_PATH} with "$schema": "./schema/pourkit.schema.json".`
@@ -917,13 +914,13 @@ async function loadRepoConfig(repoRoot2, _configFileName) {
917
914
  }
918
915
  }
919
916
  const configPath = pjoin(repoRoot2, CANONICAL_CONFIG_PATH);
920
- if (!existsSync25(configPath)) {
917
+ if (!existsSync26(configPath)) {
921
918
  throw new Error(
922
919
  `No Pourkit config found at ${CANONICAL_CONFIG_PATH}. Run pourkit init or create ${CANONICAL_CONFIG_PATH} with "$schema": "./schema/pourkit.schema.json".`
923
920
  );
924
921
  }
925
- const { readFile: readFile9 } = await import("fs/promises");
926
- const raw = await readFile9(configPath, "utf-8");
922
+ const { readFile: readFile10 } = await import("fs/promises");
923
+ const raw = await readFile10(configPath, "utf-8");
927
924
  let parsed;
928
925
  try {
929
926
  parsed = JSON.parse(raw);
@@ -934,10 +931,10 @@ async function loadRepoConfig(repoRoot2, _configFileName) {
934
931
  return parseConfig(parsed);
935
932
  }
936
933
  async function loadConfig(configPath) {
937
- const { readFile: readFile9 } = await import("fs/promises");
934
+ const { readFile: readFile10 } = await import("fs/promises");
938
935
  const ext = configPath.split(".").pop()?.toLowerCase();
939
936
  if (ext === "json") {
940
- const raw = await readFile9(configPath, "utf-8");
937
+ const raw = await readFile10(configPath, "utf-8");
941
938
  return parseConfig(JSON.parse(raw));
942
939
  }
943
940
  if (ext === "mjs" || ext === "js" || ext === "ts") {
@@ -4281,19 +4278,12 @@ var POST_COMPLETION_FINAL_REVIEW_ARTIFACT_PATH = join9(
4281
4278
  "post-completion-final-review",
4282
4279
  "agent-output.json"
4283
4280
  );
4284
- var DEFAULT_POST_COMPLETION_FINAL_REVIEW_PROMPT2 = "post-completion-final-review.prompt.md";
4285
4281
  function resolvePostCompletionFinalReviewAgent(target) {
4286
4282
  const configured = target.strategy.postCompletionFinalReview;
4287
4283
  if (configured) return configured;
4288
- const fallback = target.strategy.issueFinalReview;
4289
- return {
4290
- agent: fallback.agent,
4291
- model: fallback.model,
4292
- variant: fallback.variant,
4293
- env: fallback.env,
4294
- outputRetries: fallback.outputRetries,
4295
- promptTemplate: DEFAULT_POST_COMPLETION_FINAL_REVIEW_PROMPT2
4296
- };
4284
+ throw new Error(
4285
+ "Post-Completion Final Review requires targets[].strategy.postCompletionFinalReview config."
4286
+ );
4297
4287
  }
4298
4288
  async function runPostCompletionFinalReview(options) {
4299
4289
  const {
@@ -6618,7 +6608,7 @@ async function canReachMcp(url) {
6618
6608
  return true;
6619
6609
  } catch {
6620
6610
  if (attempt < 9) {
6621
- await new Promise((resolve7) => setTimeout(resolve7, 100));
6611
+ await new Promise((resolve8) => setTimeout(resolve8, 100));
6622
6612
  }
6623
6613
  }
6624
6614
  }
@@ -8659,7 +8649,10 @@ async function runIssueLifecycle(options) {
8659
8649
  startResult,
8660
8650
  reviewArtifactPath
8661
8651
  });
8662
- if (result.publicationStatus === "merged" && !startResult.parentPrdIssue) {
8652
+ const isPrdChildIssue = Boolean(
8653
+ startResult.parentPrdIssue || options.runOptions.beadsIssueRunContext
8654
+ );
8655
+ if (result.publicationStatus === "merged" && !isPrdChildIssue) {
8663
8656
  await options.deps.runOneshotPostCompletionFinalReview({
8664
8657
  issueNumber: options.issueNumber,
8665
8658
  repoRoot: options.repoRoot,
@@ -10598,7 +10591,7 @@ async function resolveGithubProjectionState(options) {
10598
10591
  expectedKind: "parent",
10599
10592
  prdRef: options.workspace.prdRef,
10600
10593
  githubIssueNumber: parentGithubIssueNumber,
10601
- allowMissingCanonicalMatch: parentGithubIssueNumber === void 0 && options.currentState.parent === null,
10594
+ allowMissingCanonicalMatch: parentGithubIssueNumber === void 0,
10602
10595
  affected: [
10603
10596
  {
10604
10597
  kind: "prd",
@@ -10620,7 +10613,7 @@ async function resolveGithubProjectionState(options) {
10620
10613
  expectedKind: "child",
10621
10614
  prdRef: options.workspace.prdRef,
10622
10615
  githubIssueNumber,
10623
- allowMissingCanonicalMatch: action?.type === "create_child" && githubIssueNumber === void 0,
10616
+ allowMissingCanonicalMatch: (action?.type === "create_child" || action?.type === "update_child") && githubIssueNumber === void 0,
10624
10617
  affected: [
10625
10618
  {
10626
10619
  kind: "child",
@@ -10845,7 +10838,7 @@ async function executeGithubProjectionActions(options) {
10845
10838
  child.childRef
10846
10839
  ),
10847
10840
  githubIssueNumber: action?.type === "update_child" ? action.githubIssueNumber : void 0,
10848
- allowMissingCanonicalMatch: action?.type !== "update_child"
10841
+ allowMissingCanonicalMatch: action?.type !== "update_child" || action.githubIssueNumber === void 0
10849
10842
  });
10850
10843
  children.push({ childRef: child.childRef, githubIssue });
10851
10844
  }
@@ -12396,15 +12389,19 @@ function inspectRemotePrdBranch(repoRoot2, prdRef) {
12396
12389
  return { ok: true, exists: true, headSha };
12397
12390
  }
12398
12391
  function fetchPrdBranch(repoRoot2, prdRef) {
12399
- const result = spawnSync2("git", ["fetch", "origin", prdRef], {
12400
- cwd: repoRoot2,
12401
- encoding: "utf8"
12402
- });
12392
+ const result = spawnSync2(
12393
+ "git",
12394
+ ["fetch", "origin", `${prdRef}:refs/remotes/origin/${prdRef}`],
12395
+ {
12396
+ cwd: repoRoot2,
12397
+ encoding: "utf8"
12398
+ }
12399
+ );
12403
12400
  if (result.status !== 0) {
12404
12401
  return {
12405
12402
  ok: false,
12406
12403
  gate: "git",
12407
- reason: `PRD Run start failed while fetching origin/${prdRef}.`,
12404
+ reason: `PRD Run failed while fetching origin/${prdRef}.`,
12408
12405
  diagnostics: [
12409
12406
  result.error instanceof Error ? result.error.message : void 0,
12410
12407
  result.stderr?.toString?.() ?? String(result.stderr ?? ""),
@@ -12415,6 +12412,65 @@ function fetchPrdBranch(repoRoot2, prdRef) {
12415
12412
  }
12416
12413
  return { ok: true };
12417
12414
  }
12415
+ function postCompletionRetouchBranch(prdRef) {
12416
+ return `pourkit/post-completion/${prdRef}`;
12417
+ }
12418
+ function postCompletionRetouchWorktreePath(repoRoot2, retouchBranch) {
12419
+ return join23(
12420
+ repoRoot2,
12421
+ ".sandcastle",
12422
+ "worktrees",
12423
+ retouchBranch.replace(/\//g, "-")
12424
+ );
12425
+ }
12426
+ async function ensurePostCompletionRetouchWorktree(options) {
12427
+ const { repoRoot: repoRoot2, retouchBranch, baseRef, logger } = options;
12428
+ const gitLogger = typeof logger.step === "function" ? logger : void 0;
12429
+ const worktreeList = await execCapture(
12430
+ "git",
12431
+ ["worktree", "list", "--porcelain"],
12432
+ {
12433
+ cwd: repoRoot2,
12434
+ logger: gitLogger,
12435
+ label: "git worktree list"
12436
+ }
12437
+ );
12438
+ const registeredWorktreePath = parseWorktreeListPorcelain(
12439
+ worktreeList.stdout,
12440
+ retouchBranch
12441
+ );
12442
+ if (registeredWorktreePath) {
12443
+ return { worktreePath: registeredWorktreePath };
12444
+ }
12445
+ const worktreePath = postCompletionRetouchWorktreePath(
12446
+ repoRoot2,
12447
+ retouchBranch
12448
+ );
12449
+ let branchExists = false;
12450
+ try {
12451
+ await execCapture(
12452
+ "git",
12453
+ ["show-ref", "--verify", "--quiet", `refs/heads/${retouchBranch}`],
12454
+ {
12455
+ cwd: repoRoot2,
12456
+ logger: gitLogger,
12457
+ label: "git branch exists"
12458
+ }
12459
+ );
12460
+ branchExists = true;
12461
+ } catch {
12462
+ }
12463
+ await execCapture(
12464
+ "git",
12465
+ branchExists ? ["worktree", "add", worktreePath, retouchBranch] : ["worktree", "add", "-b", retouchBranch, worktreePath, baseRef],
12466
+ {
12467
+ cwd: repoRoot2,
12468
+ logger: gitLogger,
12469
+ label: "git worktree add post-completion retouch"
12470
+ }
12471
+ );
12472
+ return { worktreePath };
12473
+ }
12418
12474
  async function ensurePrdBranchPublished(repoRoot2, prdRef, startBaseCommit) {
12419
12475
  const pushResult = spawnSync2(
12420
12476
  "git",
@@ -13049,7 +13105,27 @@ async function prdParentIssueIsClosed(options) {
13049
13105
  }
13050
13106
  }
13051
13107
  async function reconcileBlockedBeadsIssueProjection(options) {
13052
- const { issue, issueProvider, config, prdRef, logger } = options;
13108
+ const { issue, issueProvider, config, prdRef, logger, retryRepair } = options;
13109
+ if (shouldRestoreRetryableBeadsProjection({ issue, config, retryRepair })) {
13110
+ logCoordinatorStep(
13111
+ logger,
13112
+ "info",
13113
+ `Restoring retryable GitHub projection for Beads Issue #${issue.number}.`
13114
+ );
13115
+ for (const label of [
13116
+ config.labels.blocked,
13117
+ config.labels.agentInProgress,
13118
+ config.labels.readyForHuman
13119
+ ]) {
13120
+ if (!issue.labels.includes(label)) continue;
13121
+ try {
13122
+ await issueProvider.removeLabel(issue.number, label);
13123
+ } catch {
13124
+ }
13125
+ }
13126
+ await issueProvider.addLabels(issue.number, [config.labels.readyForAgent]);
13127
+ return await issueProvider.fetchIssue(issue.number);
13128
+ }
13053
13129
  if (!issue.labels.includes(config.labels.blocked)) {
13054
13130
  return issue;
13055
13131
  }
@@ -13109,6 +13185,16 @@ async function reconcileBlockedBeadsIssueProjection(options) {
13109
13185
  }
13110
13186
  return refreshed;
13111
13187
  }
13188
+ function shouldRestoreRetryableBeadsProjection(options) {
13189
+ const { issue, config, retryRepair } = options;
13190
+ if (!retryRepair) return false;
13191
+ if (issue.state !== "open") return false;
13192
+ const guidance = retryRepair.guidance;
13193
+ if (guidance.repairability !== "automatic-retry-safe") return false;
13194
+ if (guidance.blockedGate !== "queue") return false;
13195
+ if (issue.labels.includes(config.labels.blocked)) return false;
13196
+ return !issue.labels.includes(config.labels.readyForAgent) || issue.labels.includes(config.labels.agentInProgress) || issue.labels.includes(config.labels.readyForHuman);
13197
+ }
13112
13198
  async function releaseSkippedBlockedBeadsChildren(options) {
13113
13199
  for (const child of options.children) {
13114
13200
  let result;
@@ -13135,6 +13221,19 @@ async function releaseSkippedBlockedBeadsChildren(options) {
13135
13221
  }
13136
13222
  }
13137
13223
  }
13224
+ async function closeBeadsChildForClosedIssueProjection(options) {
13225
+ logCoordinatorStep(
13226
+ options.logger,
13227
+ "info",
13228
+ `Closing Beads child ${options.beadsChildId} because GitHub Issue #${options.issue.number} is already closed.`
13229
+ );
13230
+ await closeBeadsPrdChild({
13231
+ repoRoot: options.repoRoot,
13232
+ childId: options.beadsChildId,
13233
+ reason: `Issue #${options.issue.number} already closed`,
13234
+ logger: options.logger
13235
+ });
13236
+ }
13138
13237
  function extractIssueFromQueueError(error) {
13139
13238
  if (!error || typeof error !== "object" || !("issue" in error)) {
13140
13239
  return void 0;
@@ -13452,6 +13551,70 @@ async function runPostCompletionAfterTerminal(options, prdRef, record, resumeFac
13452
13551
  options.config,
13453
13552
  record.targetName ?? options.targetName
13454
13553
  );
13554
+ const remotePrdBranch = inspectRemotePrdBranch(options.repoRoot, prdBranch);
13555
+ if (!remotePrdBranch.ok) {
13556
+ return buildLaunchBlockedOutcome(
13557
+ options.repoRoot,
13558
+ prdRef,
13559
+ buildPrdRunRepairGuidance({
13560
+ blockedGate: remotePrdBranch.gate,
13561
+ blockedStage: "post-completion-final-review",
13562
+ failureCode: "post-completion-branch-fetch-failed",
13563
+ humanReadableReason: remotePrdBranch.reason,
13564
+ repairability: "operator-action",
13565
+ nextAction: "inspect-and-retry",
13566
+ nextRecommendedCommand: `pourkit prd-run status ${prdRef}`,
13567
+ diagnostics: [...remotePrdBranch.diagnostics],
13568
+ offendingPaths: [...remotePrdBranch.offendingPaths]
13569
+ }),
13570
+ resumeFacts,
13571
+ startOutcome,
13572
+ record.targetName,
13573
+ record.start
13574
+ );
13575
+ }
13576
+ if (!remotePrdBranch.exists) {
13577
+ return buildLaunchBlockedOutcome(
13578
+ options.repoRoot,
13579
+ prdRef,
13580
+ buildPrdRunRepairGuidance({
13581
+ blockedGate: "git",
13582
+ blockedStage: "post-completion-final-review",
13583
+ failureCode: "post-completion-branch-missing",
13584
+ humanReadableReason: `Post-Completion Final Review for ${prdRef} requires origin/${prdBranch}, but the remote PRD branch does not exist.`,
13585
+ repairability: "operator-action",
13586
+ nextAction: "inspect-and-retry",
13587
+ nextRecommendedCommand: `pourkit prd-run status ${prdRef}`,
13588
+ diagnostics: [`Missing remote PRD branch: origin/${prdBranch}`]
13589
+ }),
13590
+ resumeFacts,
13591
+ startOutcome,
13592
+ record.targetName,
13593
+ record.start
13594
+ );
13595
+ }
13596
+ const fetchPrdResult = fetchPrdBranch(options.repoRoot, prdBranch);
13597
+ if (!fetchPrdResult.ok) {
13598
+ return buildLaunchBlockedOutcome(
13599
+ options.repoRoot,
13600
+ prdRef,
13601
+ buildPrdRunRepairGuidance({
13602
+ blockedGate: fetchPrdResult.gate,
13603
+ blockedStage: "post-completion-final-review",
13604
+ failureCode: "post-completion-branch-fetch-failed",
13605
+ humanReadableReason: fetchPrdResult.reason,
13606
+ repairability: "operator-action",
13607
+ nextAction: "inspect-and-retry",
13608
+ nextRecommendedCommand: `pourkit prd-run status ${prdRef}`,
13609
+ diagnostics: [...fetchPrdResult.diagnostics],
13610
+ offendingPaths: [...fetchPrdResult.offendingPaths]
13611
+ }),
13612
+ resumeFacts,
13613
+ startOutcome,
13614
+ record.targetName,
13615
+ record.start
13616
+ );
13617
+ }
13455
13618
  const sourceDocResult = await resolvePrdPostCompletionSourceDocument({
13456
13619
  repoRoot: options.repoRoot,
13457
13620
  prdRef
@@ -13499,7 +13662,36 @@ async function runPostCompletionAfterTerminal(options, prdRef, record, resumeFac
13499
13662
  record.start
13500
13663
  );
13501
13664
  }
13502
- const worktreePath = options.repoRoot;
13665
+ const retouchBranch = postCompletionRetouchBranch(prdRef);
13666
+ let worktreePath;
13667
+ try {
13668
+ worktreePath = (await ensurePostCompletionRetouchWorktree({
13669
+ repoRoot: options.repoRoot,
13670
+ retouchBranch,
13671
+ baseRef: `origin/${prdBranch}`,
13672
+ logger: options.logger
13673
+ })).worktreePath;
13674
+ } catch (error) {
13675
+ const msg = error instanceof Error ? error.message : String(error);
13676
+ return buildLaunchBlockedOutcome(
13677
+ options.repoRoot,
13678
+ prdRef,
13679
+ buildPrdRunRepairGuidance({
13680
+ blockedGate: "git",
13681
+ blockedStage: "post-completion-final-review",
13682
+ failureCode: "post-completion-worktree-failed",
13683
+ humanReadableReason: `Post-Completion Final Review for ${prdRef} could not prepare a retouch worktree: ${msg}`,
13684
+ repairability: "operator-action",
13685
+ nextAction: "inspect-and-retry",
13686
+ nextRecommendedCommand: `pourkit prd-run status ${prdRef}`,
13687
+ diagnostics: [msg]
13688
+ }),
13689
+ resumeFacts,
13690
+ startOutcome,
13691
+ record.targetName,
13692
+ record.start
13693
+ );
13694
+ }
13503
13695
  const sourceDocumentPath = sourceDocResult.relativePath;
13504
13696
  stateAdapter.write({
13505
13697
  status: "in_progress",
@@ -13595,7 +13787,6 @@ async function runPostCompletionAfterTerminal(options, prdRef, record, resumeFac
13595
13787
  resume: resumeFacts
13596
13788
  };
13597
13789
  }
13598
- const retouchBranch = `pourkit/post-completion/${prdRef}`;
13599
13790
  stateAdapter.write({ retouchBranch });
13600
13791
  const prDescriptionResult = await runEffectAndMapExit(
13601
13792
  runPostCompletionPrDescriptionAgent({
@@ -13682,6 +13873,7 @@ async function launchPrdRun(options) {
13682
13873
  const plan = planPrdRunLaunchResume(existingRecord.record);
13683
13874
  const rec = existingRecord.record;
13684
13875
  if (rec && (rec.status === "starting" || rec.status === "running") && !rec.repairGuidance) {
13876
+ const nextRecommendedCommand = `pourkit prd-run launch ${prdRef}${rec.targetName ? ` --target ${rec.targetName}` : ""}${rec.start?.startBaseBranch ? ` --base ${rec.start.startBaseBranch}` : ""}`;
13685
13877
  return buildLaunchBlockedOutcome(
13686
13878
  options.repoRoot,
13687
13879
  prdRef,
@@ -13691,15 +13883,17 @@ async function launchPrdRun(options) {
13691
13883
  failureCode: "prd-run-in-progress",
13692
13884
  humanReadableReason: `PRD Run ${prdRef} is already ${rec.status}. A second launch cannot start another Queue drain while the run is in progress.`,
13693
13885
  repairability: "automatic-retry-safe",
13694
- nextAction: "wait-or-inspect-active-run",
13695
- nextRecommendedCommand: "pourkit prd-run status",
13886
+ nextAction: "confirm-no-active-run-then-rerun-prd-run-launch",
13887
+ nextRecommendedCommand,
13696
13888
  diagnostics: [
13697
- `PRD Run ${prdRef} is in status "${rec.status}" without active repair guidance.`
13889
+ `PRD Run ${prdRef} is in status "${rec.status}" without active repair guidance.`,
13890
+ "If no pourkit/sandcastle agent process is still active for this PRD, rerun the launch command to resume from the preserved start receipt."
13698
13891
  ]
13699
13892
  }),
13700
13893
  plan,
13701
13894
  void 0,
13702
- options.targetName
13895
+ rec.targetName ?? options.targetName,
13896
+ rec.start
13703
13897
  );
13704
13898
  }
13705
13899
  if (existingRecord.record === null && existingRecord.diagnostics.length > 0) {
@@ -14679,7 +14873,13 @@ async function launchBeadsQueueDrain(options, prdRef, startReceipt, targetName,
14679
14873
  issueProvider,
14680
14874
  config: options.config,
14681
14875
  prdRef,
14682
- logger
14876
+ logger,
14877
+ ...resumeBeadsContext ? {
14878
+ retryRepair: {
14879
+ guidance: originalGuidance,
14880
+ beadsChildId: resumeBeadsContext.childId
14881
+ }
14882
+ } : {}
14683
14883
  });
14684
14884
  if (fetchedIssue.labels.includes(options.config.labels.blocked)) {
14685
14885
  logCoordinatorStep(
@@ -14829,8 +15029,24 @@ async function launchBeadsQueueDrain(options, prdRef, startReceipt, targetName,
14829
15029
  );
14830
15030
  }
14831
15031
  try {
14832
- const issue = await reconcileBlockedBeadsIssueProjection({
14833
- issue: contextResult.issue,
15032
+ let issue = contextResult.issue;
15033
+ if (issue.state === "closed") {
15034
+ beadsClaimAttempted = true;
15035
+ await closeBeadsChildForClosedIssueProjection({
15036
+ repoRoot: options.repoRoot,
15037
+ issue,
15038
+ beadsChildId: contextResult.beads.childId,
15039
+ logger
15040
+ });
15041
+ processedResults.push({
15042
+ beadsChildId: contextResult.beads.childId,
15043
+ issueNumber: issue.number,
15044
+ publicationStatus: "merged"
15045
+ });
15046
+ continue;
15047
+ }
15048
+ issue = await reconcileBlockedBeadsIssueProjection({
15049
+ issue,
14834
15050
  issueProvider,
14835
15051
  config: options.config,
14836
15052
  prdRef,
@@ -16177,7 +16393,7 @@ function generateConfigTemplate(options) {
16177
16393
  };
16178
16394
  const config = {
16179
16395
  $schema: "./schema/pourkit.schema.json",
16180
- schemaVersion: 4,
16396
+ schemaVersion: getPackagedConfigSchemaVersion(),
16181
16397
  targets: [target],
16182
16398
  workflowPack: {
16183
16399
  version: "1.0.0",
@@ -18323,12 +18539,20 @@ async function runSerenaStatusCommand(options) {
18323
18539
  }
18324
18540
 
18325
18541
  // commands/config-schema.ts
18326
- import { readFileSync as readFileSync20, existsSync as existsSync21, readdirSync as readdirSync5 } from "fs";
18327
- import { mkdir as mkdir6, readFile as readFile7, writeFile as writeFile3, readdir as readdir4 } from "fs/promises";
18328
- import { resolve as resolve5, dirname as dirname6, relative as relative4, basename } from "path";
18542
+ import { readFileSync as readFileSync21, existsSync as existsSync22, readdirSync as readdirSync5 } from "fs";
18543
+ import { mkdir as mkdir6, readFile as readFile8, writeFile as writeFile4, readdir as readdir4 } from "fs/promises";
18544
+ import { resolve as resolve6, dirname as dirname7, relative as relative4, basename } from "path";
18545
+ import { fileURLToPath as fileURLToPath4 } from "url";
18546
+ import Ajv3 from "ajv";
18547
+ init_common();
18548
+
18549
+ // commands/config-migration.ts
18550
+ import { existsSync as existsSync21, readFileSync as readFileSync20 } from "fs";
18551
+ import { writeFile as writeFile3, rename as rename2 } from "fs/promises";
18552
+ import { resolve as resolve5, dirname as dirname6 } from "path";
18329
18553
  import { fileURLToPath as fileURLToPath3 } from "url";
18554
+ import { randomUUID as randomUUID2 } from "crypto";
18330
18555
  import Ajv2 from "ajv";
18331
- init_common();
18332
18556
  var __filename3 = fileURLToPath3(import.meta.url);
18333
18557
  var __dirname3 = dirname6(__filename3);
18334
18558
  function resolvePackagedAssetPath2(fileName) {
@@ -18336,16 +18560,454 @@ function resolvePackagedAssetPath2(fileName) {
18336
18560
  resolve5(__dirname3, "schema", fileName),
18337
18561
  resolve5(__dirname3, "../schema", fileName)
18338
18562
  ];
18339
- return candidates.find((candidate) => existsSync21(candidate)) ?? candidates[0];
18563
+ return candidates.find((c) => existsSync21(c)) ?? candidates[0];
18340
18564
  }
18341
18565
  var PACKAGED_SCHEMA_PATH = resolvePackagedAssetPath2("pourkit.schema.json");
18342
- var PACKAGED_HASH_PATH = resolvePackagedAssetPath2("pourkit.schema.hash");
18566
+ var SAFE_DEFAULTS = {
18567
+ "#$schema": "./schema/pourkit.schema.json",
18568
+ "/targets/*/strategy#postCompletionFinalReview": {
18569
+ agent: "pourkit-reviewer",
18570
+ model: "openai/gpt-5.5",
18571
+ variant: "max",
18572
+ promptTemplate: ".pourkit/managed/prompts/post-completion-final-review.prompt.md"
18573
+ }
18574
+ };
18575
+ function normalizePathForLookup(instancePath) {
18576
+ return instancePath.replace(/\/\d+/g, "/*");
18577
+ }
18578
+ function getCurrentSchemaVersion(schema) {
18579
+ const props = schema.properties;
18580
+ const svProp = props?.schemaVersion;
18581
+ return svProp?.const ?? 0;
18582
+ }
18583
+ function getSchema() {
18584
+ return JSON.parse(readFileSync20(PACKAGED_SCHEMA_PATH, "utf-8"));
18585
+ }
18586
+ function setNestedValue(obj, instancePath, property, value) {
18587
+ let target = obj;
18588
+ if (instancePath) {
18589
+ const segments = instancePath.split("/").filter(Boolean);
18590
+ for (const seg of segments) {
18591
+ if (!target || typeof target !== "object") return;
18592
+ if (Array.isArray(target)) {
18593
+ const idx = Number(seg);
18594
+ if (isNaN(idx) || idx < 0) return;
18595
+ target = target[idx];
18596
+ } else {
18597
+ const t2 = target;
18598
+ const next = t2[seg];
18599
+ if (next !== void 0 && typeof next === "object") {
18600
+ target = next;
18601
+ } else {
18602
+ return;
18603
+ }
18604
+ }
18605
+ }
18606
+ }
18607
+ if (!target || typeof target !== "object") return;
18608
+ const t = target;
18609
+ if (!(property in t)) {
18610
+ t[property] = structuredClone(value);
18611
+ }
18612
+ }
18613
+ function planConfigMigration(rawConfig, options = {}) {
18614
+ const schema = options.schema ?? getSchema();
18615
+ const currentSchemaVersion = getCurrentSchemaVersion(schema);
18616
+ let existingSchemaVersion;
18617
+ if (rawConfig && typeof rawConfig === "object") {
18618
+ const sv = rawConfig.schemaVersion;
18619
+ if (typeof sv === "number") {
18620
+ existingSchemaVersion = sv;
18621
+ }
18622
+ }
18623
+ const ajv = new Ajv2({ strict: true, allErrors: true });
18624
+ ajv.addKeyword("x-pourkit-schema-version");
18625
+ const validate = ajv.compile(schema);
18626
+ let workingConfig = structuredClone(rawConfig);
18627
+ const plannedChanges = [];
18628
+ const blockers = [];
18629
+ let schemaVersionPlanned = false;
18630
+ for (let iteration = 0; iteration < 100; iteration++) {
18631
+ const valid2 = validate(workingConfig);
18632
+ if (valid2) {
18633
+ if (plannedChanges.length === 0 && !schemaVersionPlanned) {
18634
+ return {
18635
+ status: "current",
18636
+ safe: true,
18637
+ available: false,
18638
+ command: null,
18639
+ plannedChanges: [],
18640
+ blockers: [],
18641
+ existingSchemaVersion,
18642
+ currentSchemaVersion,
18643
+ schemaSyncPlanned: false
18644
+ };
18645
+ }
18646
+ const migrated = structuredClone(workingConfig);
18647
+ if (existingSchemaVersion !== void 0 && existingSchemaVersion !== currentSchemaVersion) {
18648
+ migrated.schemaVersion = currentSchemaVersion;
18649
+ }
18650
+ return {
18651
+ status: "migratable",
18652
+ safe: true,
18653
+ available: true,
18654
+ command: "pourkit config migrate",
18655
+ plannedChanges,
18656
+ blockers: [],
18657
+ existingSchemaVersion,
18658
+ currentSchemaVersion,
18659
+ migratedConfig: migrated,
18660
+ schemaSyncPlanned: true
18661
+ };
18662
+ }
18663
+ const errors = validate.errors ?? [];
18664
+ const appliedSafeDefaults = applySafeDefaults(
18665
+ errors,
18666
+ workingConfig,
18667
+ plannedChanges
18668
+ );
18669
+ if (appliedSafeDefaults) {
18670
+ continue;
18671
+ }
18672
+ if (!schemaVersionPlanned) {
18673
+ for (const err of errors) {
18674
+ if (err.keyword === "const" && err.instancePath === "/schemaVersion") {
18675
+ if (existingSchemaVersion === void 0 || !Number.isInteger(existingSchemaVersion)) {
18676
+ blockers.push(
18677
+ `/schemaVersion: invalid value; migration only updates older integer schema versions to supported schema version ${currentSchemaVersion}`
18678
+ );
18679
+ continue;
18680
+ }
18681
+ if (existingSchemaVersion > currentSchemaVersion) {
18682
+ blockers.push(
18683
+ `/schemaVersion: ${existingSchemaVersion} is newer than supported schema version ${currentSchemaVersion}`
18684
+ );
18685
+ continue;
18686
+ }
18687
+ schemaVersionPlanned = true;
18688
+ plannedChanges.push(
18689
+ `Update schemaVersion from ${existingSchemaVersion ?? "?"} to ${currentSchemaVersion}`
18690
+ );
18691
+ workingConfig.schemaVersion = currentSchemaVersion;
18692
+ }
18693
+ }
18694
+ if (schemaVersionPlanned) {
18695
+ continue;
18696
+ }
18697
+ if (blockers.length > 0) {
18698
+ return {
18699
+ status: "blocked",
18700
+ safe: false,
18701
+ available: false,
18702
+ command: null,
18703
+ plannedChanges,
18704
+ blockers,
18705
+ existingSchemaVersion,
18706
+ currentSchemaVersion,
18707
+ schemaSyncPlanned: false
18708
+ };
18709
+ }
18710
+ }
18711
+ for (const err of errors) {
18712
+ if (err.keyword === "required") {
18713
+ const missingProperty = err.params.missingProperty;
18714
+ const concretePath = err.instancePath ? `${err.instancePath}/${missingProperty}` : missingProperty;
18715
+ const lookupKey = `${normalizePathForLookup(err.instancePath)}#${missingProperty}`;
18716
+ if (!(lookupKey in SAFE_DEFAULTS)) {
18717
+ blockers.push(
18718
+ `${concretePath}: required property missing, no registered safe default`
18719
+ );
18720
+ }
18721
+ } else if (err.keyword === "additionalProperties") {
18722
+ const additionalProp = err.params.additionalProperty;
18723
+ const path9 = err.instancePath || "";
18724
+ blockers.push(
18725
+ `${path9 ? `${path9}.${additionalProp}` : additionalProp}: unknown property, removal not supported`
18726
+ );
18727
+ } else if (err.keyword === "const" && err.instancePath === "/schemaVersion") {
18728
+ continue;
18729
+ } else if (err.keyword === "type") {
18730
+ const expected = err.params.type;
18731
+ const path9 = err.instancePath || "";
18732
+ blockers.push(
18733
+ `${path9 || "Config"} must be ${expected === "integer" ? "an integer" : `a ${expected}`}`
18734
+ );
18735
+ } else {
18736
+ const path9 = err.instancePath || "";
18737
+ blockers.push(`${path9 || "Config"} ${err.message || "is invalid"}`);
18738
+ }
18739
+ }
18740
+ if (blockers.length > 0) {
18741
+ return {
18742
+ status: "blocked",
18743
+ safe: false,
18744
+ available: false,
18745
+ command: null,
18746
+ plannedChanges,
18747
+ blockers,
18748
+ existingSchemaVersion,
18749
+ currentSchemaVersion,
18750
+ schemaSyncPlanned: false
18751
+ };
18752
+ }
18753
+ return {
18754
+ status: "blocked",
18755
+ safe: false,
18756
+ available: false,
18757
+ command: null,
18758
+ plannedChanges,
18759
+ blockers: ["Unexpected validation state"],
18760
+ existingSchemaVersion,
18761
+ currentSchemaVersion,
18762
+ schemaSyncPlanned: false
18763
+ };
18764
+ }
18765
+ return {
18766
+ status: "blocked",
18767
+ safe: false,
18768
+ available: false,
18769
+ command: null,
18770
+ plannedChanges,
18771
+ blockers: ["Too many validation iterations"],
18772
+ existingSchemaVersion,
18773
+ currentSchemaVersion,
18774
+ schemaSyncPlanned: false
18775
+ };
18776
+ }
18777
+ function applySafeDefaults(errors, workingConfig, plannedChanges) {
18778
+ let applied = false;
18779
+ for (const err of errors) {
18780
+ if (err.keyword !== "required") continue;
18781
+ const instancePath = err.instancePath;
18782
+ const missingProperty = err.params.missingProperty;
18783
+ const lookupKey = `${normalizePathForLookup(instancePath)}#${missingProperty}`;
18784
+ const concretePath = instancePath ? `${instancePath}/${missingProperty}` : missingProperty;
18785
+ if (lookupKey in SAFE_DEFAULTS) {
18786
+ const defaultValue = SAFE_DEFAULTS[lookupKey];
18787
+ const targetExists = checkPropertyExists(
18788
+ workingConfig,
18789
+ instancePath,
18790
+ missingProperty
18791
+ );
18792
+ if (!targetExists) {
18793
+ setNestedValue(
18794
+ workingConfig,
18795
+ instancePath,
18796
+ missingProperty,
18797
+ defaultValue
18798
+ );
18799
+ plannedChanges.push(`Add ${concretePath}`);
18800
+ applied = true;
18801
+ }
18802
+ }
18803
+ }
18804
+ return applied;
18805
+ }
18806
+ function checkPropertyExists(obj, instancePath, property) {
18807
+ let target = obj;
18808
+ if (instancePath) {
18809
+ const segments = instancePath.split("/").filter(Boolean);
18810
+ for (const seg of segments) {
18811
+ if (!target || typeof target !== "object") return true;
18812
+ if (Array.isArray(target)) {
18813
+ const idx = Number(seg);
18814
+ if (isNaN(idx) || idx < 0) return true;
18815
+ target = target[idx];
18816
+ } else {
18817
+ const t = target;
18818
+ const next = t[seg];
18819
+ if (next !== void 0 && typeof next === "object") {
18820
+ target = next;
18821
+ } else {
18822
+ return true;
18823
+ }
18824
+ }
18825
+ }
18826
+ }
18827
+ if (!target || typeof target !== "object") return true;
18828
+ return property in target;
18829
+ }
18830
+ async function writeFileAtomic2(filePath, content) {
18831
+ const tmpPath = `${filePath}.tmp.${randomUUID2()}`;
18832
+ await writeFile3(tmpPath, content, "utf-8");
18833
+ await rename2(tmpPath, filePath);
18834
+ }
18835
+ async function runConfigMigrateCommand(options) {
18836
+ const repoRootPath = options.cwd ?? process.cwd();
18837
+ const configPath = resolve5(repoRootPath, ".pourkit/config.json");
18838
+ if (!existsSync21(configPath)) {
18839
+ return {
18840
+ status: "blocked",
18841
+ safe: false,
18842
+ plannedChanges: [],
18843
+ blockers: [".pourkit/config.json not found"],
18844
+ configPath,
18845
+ schemaSync: null,
18846
+ currentSchemaVersion: getCurrentSchemaVersion(getSchema())
18847
+ };
18848
+ }
18849
+ let rawConfig;
18850
+ try {
18851
+ const content = readFileSync20(configPath, "utf-8");
18852
+ rawConfig = JSON.parse(content);
18853
+ } catch (err) {
18854
+ const msg = err instanceof SyntaxError ? err.message : String(err);
18855
+ return {
18856
+ status: "blocked",
18857
+ safe: false,
18858
+ plannedChanges: [],
18859
+ blockers: [`.pourkit/config.json: ${msg}`],
18860
+ configPath,
18861
+ schemaSync: null,
18862
+ currentSchemaVersion: getCurrentSchemaVersion(getSchema())
18863
+ };
18864
+ }
18865
+ const plan = planConfigMigration(rawConfig);
18866
+ if (plan.status === "current") {
18867
+ return {
18868
+ status: "current",
18869
+ safe: true,
18870
+ plannedChanges: [],
18871
+ blockers: [],
18872
+ configPath,
18873
+ schemaSync: null,
18874
+ existingSchemaVersion: plan.existingSchemaVersion,
18875
+ currentSchemaVersion: plan.currentSchemaVersion
18876
+ };
18877
+ }
18878
+ if (plan.status === "blocked") {
18879
+ return {
18880
+ status: "blocked",
18881
+ safe: false,
18882
+ plannedChanges: plan.plannedChanges,
18883
+ blockers: plan.blockers,
18884
+ configPath,
18885
+ schemaSync: null,
18886
+ existingSchemaVersion: plan.existingSchemaVersion,
18887
+ currentSchemaVersion: plan.currentSchemaVersion
18888
+ };
18889
+ }
18890
+ if (options.dryRun) {
18891
+ return {
18892
+ status: "dry-run",
18893
+ safe: plan.safe,
18894
+ plannedChanges: plan.plannedChanges,
18895
+ blockers: plan.blockers,
18896
+ configPath,
18897
+ schemaSync: null,
18898
+ existingSchemaVersion: plan.existingSchemaVersion,
18899
+ currentSchemaVersion: plan.currentSchemaVersion
18900
+ };
18901
+ }
18902
+ const migratedConfig = plan.migratedConfig;
18903
+ if (!migratedConfig) {
18904
+ return {
18905
+ status: "blocked",
18906
+ safe: false,
18907
+ plannedChanges: plan.plannedChanges,
18908
+ blockers: ["Migration plan did not produce migrated config"],
18909
+ configPath,
18910
+ schemaSync: null,
18911
+ existingSchemaVersion: plan.existingSchemaVersion,
18912
+ currentSchemaVersion: plan.currentSchemaVersion
18913
+ };
18914
+ }
18915
+ const configContent = JSON.stringify(migratedConfig, null, 2) + "\n";
18916
+ await writeFileAtomic2(configPath, configContent);
18917
+ const schemaSync = await runConfigSyncSchemaCommand({ cwd: repoRootPath });
18918
+ return {
18919
+ status: "migrated",
18920
+ safe: true,
18921
+ plannedChanges: plan.plannedChanges,
18922
+ blockers: [],
18923
+ configPath,
18924
+ schemaSync,
18925
+ existingSchemaVersion: plan.existingSchemaVersion,
18926
+ currentSchemaVersion: plan.currentSchemaVersion
18927
+ };
18928
+ }
18929
+ function renderConfigMigrateResult(result) {
18930
+ const lines = [];
18931
+ switch (result.status) {
18932
+ case "current":
18933
+ lines.push(
18934
+ `Config is already current for schema version ${result.currentSchemaVersion}.`
18935
+ );
18936
+ lines.push("No changes needed.");
18937
+ break;
18938
+ case "dry-run":
18939
+ lines.push(
18940
+ "Dry-run: config migration would apply the following changes:"
18941
+ );
18942
+ if (result.plannedChanges.length > 0) {
18943
+ lines.push("");
18944
+ for (const change of result.plannedChanges) {
18945
+ lines.push(` ${change}`);
18946
+ }
18947
+ }
18948
+ if (result.blockers.length > 0) {
18949
+ lines.push("");
18950
+ lines.push("Blockers:");
18951
+ for (const blocker of result.blockers) {
18952
+ lines.push(` ${blocker}`);
18953
+ }
18954
+ }
18955
+ lines.push("");
18956
+ lines.push("No files were written.");
18957
+ break;
18958
+ case "migrated":
18959
+ lines.push("Config migration completed successfully.");
18960
+ if (result.plannedChanges.length > 0) {
18961
+ lines.push("");
18962
+ for (const change of result.plannedChanges) {
18963
+ lines.push(` ${change}`);
18964
+ }
18965
+ }
18966
+ if (result.schemaSync) {
18967
+ if (result.schemaSync.schemaWritten) {
18968
+ lines.push("Schema file updated.");
18969
+ }
18970
+ if (result.schemaSync.hashWritten) {
18971
+ lines.push("Schema hash updated.");
18972
+ }
18973
+ }
18974
+ break;
18975
+ case "blocked":
18976
+ lines.push("Config migration is blocked.");
18977
+ if (result.blockers.length > 0) {
18978
+ lines.push("");
18979
+ for (const blocker of result.blockers) {
18980
+ lines.push(` ${blocker}`);
18981
+ }
18982
+ }
18983
+ lines.push("");
18984
+ lines.push("No files were written.");
18985
+ break;
18986
+ }
18987
+ return lines.join("\n") + "\n";
18988
+ }
18989
+ function renderConfigMigrateResultJson(result) {
18990
+ return JSON.stringify(result, null, 2);
18991
+ }
18992
+
18993
+ // commands/config-schema.ts
18994
+ var __filename4 = fileURLToPath4(import.meta.url);
18995
+ var __dirname4 = dirname7(__filename4);
18996
+ function resolvePackagedAssetPath3(fileName) {
18997
+ const candidates = [
18998
+ resolve6(__dirname4, "schema", fileName),
18999
+ resolve6(__dirname4, "../schema", fileName)
19000
+ ];
19001
+ return candidates.find((candidate) => existsSync22(candidate)) ?? candidates[0];
19002
+ }
19003
+ var PACKAGED_SCHEMA_PATH2 = resolvePackagedAssetPath3("pourkit.schema.json");
19004
+ var PACKAGED_HASH_PATH = resolvePackagedAssetPath3("pourkit.schema.hash");
18343
19005
  var _schemaValidator = null;
18344
19006
  var _schemaErrors = null;
18345
19007
  function getSchemaValidator() {
18346
19008
  if (!_schemaValidator) {
18347
- const schema = JSON.parse(readFileSync20(PACKAGED_SCHEMA_PATH, "utf-8"));
18348
- const ajv = new Ajv2({ strict: true });
19009
+ const schema = JSON.parse(readFileSync21(PACKAGED_SCHEMA_PATH2, "utf-8"));
19010
+ const ajv = new Ajv3({ strict: true });
18349
19011
  ajv.addKeyword("x-pourkit-schema-version");
18350
19012
  const validate = ajv.compile(schema);
18351
19013
  _schemaValidator = (data) => {
@@ -18358,41 +19020,41 @@ function getSchemaValidator() {
18358
19020
  return _schemaValidator;
18359
19021
  }
18360
19022
  function readPackagedHash() {
18361
- return readFileSync20(PACKAGED_HASH_PATH, "utf-8");
19023
+ return readFileSync21(PACKAGED_HASH_PATH, "utf-8");
18362
19024
  }
18363
19025
  function localSchemaDir(repoRoot2) {
18364
- return resolve5(repoRoot2, ".pourkit/schema");
19026
+ return resolve6(repoRoot2, ".pourkit/schema");
18365
19027
  }
18366
19028
  var MANAGED_BLOCK_BEGIN2 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
18367
19029
  var MANAGED_BLOCK_BEGIN_MARKER = MANAGED_BLOCK_BEGIN2.trim();
18368
19030
  var MANAGED_BLOCK_END_MARKER = "<!-- END POURKIT MANAGED BLOCK -->";
18369
19031
  var OLD_DOCS_PATH_PATTERN = ".pourkit/docs/agents/";
18370
19032
  function resolvePackagedManagedPath(...segments) {
18371
- const bundledPath = resolve5(__dirname3, "managed", ...segments);
18372
- const sourcePath = resolve5(__dirname3, "..", "managed", ...segments);
19033
+ const bundledPath = resolve6(__dirname4, "managed", ...segments);
19034
+ const sourcePath = resolve6(__dirname4, "..", "managed", ...segments);
18373
19035
  const candidates = [bundledPath, sourcePath];
18374
- return candidates.find((candidate) => existsSync21(candidate)) ?? bundledPath;
19036
+ return candidates.find((candidate) => existsSync22(candidate)) ?? bundledPath;
18375
19037
  }
18376
19038
  function resolvePackagedOpenCodeAgentsDir() {
18377
19039
  const candidates = [
18378
- resolve5(__dirname3, ".opencode", "agents"),
18379
- resolve5(__dirname3, "..", ".opencode", "agents"),
18380
- resolve5(__dirname3, "..", "..", ".opencode", "agents")
19040
+ resolve6(__dirname4, ".opencode", "agents"),
19041
+ resolve6(__dirname4, "..", ".opencode", "agents"),
19042
+ resolve6(__dirname4, "..", "..", ".opencode", "agents")
18381
19043
  ];
18382
- return candidates.find((candidate) => existsSync21(candidate)) ?? candidates[0];
19044
+ return candidates.find((candidate) => existsSync22(candidate)) ?? candidates[0];
18383
19045
  }
18384
19046
  function listPackagedOpenCodeAgentFiles() {
18385
19047
  const agentsDir = resolvePackagedOpenCodeAgentsDir();
18386
19048
  try {
18387
- return readdirSync5(agentsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => resolve5(agentsDir, entry.name));
19049
+ return readdirSync5(agentsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => resolve6(agentsDir, entry.name));
18388
19050
  } catch {
18389
19051
  return [];
18390
19052
  }
18391
19053
  }
18392
19054
  async function readManifestAssets(cwd) {
18393
- const manifestPath = resolve5(cwd, ".pourkit/manifest.json");
19055
+ const manifestPath = resolve6(cwd, ".pourkit/manifest.json");
18394
19056
  try {
18395
- const content = await readFile7(manifestPath, "utf-8");
19057
+ const content = await readFile8(manifestPath, "utf-8");
18396
19058
  const manifest = JSON.parse(content);
18397
19059
  if (typeof manifest.assets !== "object" || manifest.assets === null || Array.isArray(manifest.assets)) {
18398
19060
  return {};
@@ -18416,7 +19078,7 @@ function resolvePackagedReleaseAddonDocPath(docName) {
18416
19078
  }
18417
19079
  async function readPackagedTextFile(filePath) {
18418
19080
  try {
18419
- return await readFile7(filePath, "utf-8");
19081
+ return await readFile8(filePath, "utf-8");
18420
19082
  } catch {
18421
19083
  return null;
18422
19084
  }
@@ -18430,7 +19092,7 @@ async function walkDir2(dir) {
18430
19092
  try {
18431
19093
  const entries = await readdir4(dir, { withFileTypes: true });
18432
19094
  for (const entry of entries) {
18433
- const full = resolve5(dir, entry.name);
19095
+ const full = resolve6(dir, entry.name);
18434
19096
  if (entry.isDirectory()) {
18435
19097
  files.push(...await walkDir2(full));
18436
19098
  } else {
@@ -18513,8 +19175,8 @@ async function validateWorkflowPack(cwd) {
18513
19175
  const baselineSkills = getBaselineManagedSkillNames();
18514
19176
  const manifestAssets = await readManifestAssets(cwd);
18515
19177
  for (const docName of catalog.docs) {
18516
- const localPath = resolve5(cwd, `.pourkit/managed/docs/agents/${docName}`);
18517
- if (!existsSync21(localPath)) {
19178
+ const localPath = resolve6(cwd, `.pourkit/managed/docs/agents/${docName}`);
19179
+ if (!existsSync22(localPath)) {
18518
19180
  failures.push({
18519
19181
  severity: "failure",
18520
19182
  kind: "missing_managed_asset",
@@ -18526,13 +19188,13 @@ async function validateWorkflowPack(cwd) {
18526
19188
  const packagedContent = await readPackagedTextFile(packagedPath);
18527
19189
  if (packagedContent !== null) {
18528
19190
  try {
18529
- const localContent = await readFile7(localPath, "utf-8");
19191
+ const localContent = await readFile8(localPath, "utf-8");
18530
19192
  if (localContent !== packagedContent) {
18531
- const overridePath = resolve5(
19193
+ const overridePath = resolve6(
18532
19194
  cwd,
18533
19195
  `.pourkit/overrides/docs/agents/${docName}`
18534
19196
  );
18535
- if (existsSync21(overridePath)) {
19197
+ if (existsSync22(overridePath)) {
18536
19198
  warnings.push({
18537
19199
  severity: "warning",
18538
19200
  kind: "overridden",
@@ -18554,16 +19216,16 @@ async function validateWorkflowPack(cwd) {
18554
19216
  }
18555
19217
  }
18556
19218
  for (const skillName of baselineSkills) {
18557
- const skillDir = resolve5(cwd, `.pourkit/managed/skills/${skillName}`);
18558
- const skillSourcePath = resolve5(skillDir, "SKILL.md");
18559
- if (!existsSync21(skillDir)) {
19219
+ const skillDir = resolve6(cwd, `.pourkit/managed/skills/${skillName}`);
19220
+ const skillSourcePath = resolve6(skillDir, "SKILL.md");
19221
+ if (!existsSync22(skillDir)) {
18560
19222
  failures.push({
18561
19223
  severity: "failure",
18562
19224
  kind: "missing_managed_asset",
18563
19225
  path: `.pourkit/managed/skills/${skillName}/SKILL.md`,
18564
19226
  message: `Missing managed skill: ${skillName}`
18565
19227
  });
18566
- } else if (!existsSync21(skillSourcePath)) {
19228
+ } else if (!existsSync22(skillSourcePath)) {
18567
19229
  failures.push({
18568
19230
  severity: "failure",
18569
19231
  kind: "missing_managed_asset",
@@ -18579,13 +19241,13 @@ async function validateWorkflowPack(cwd) {
18579
19241
  const packagedContent = await readPackagedTextFile(packagedSkillPath);
18580
19242
  if (packagedContent !== null) {
18581
19243
  try {
18582
- const localContent = await readFile7(skillSourcePath, "utf-8");
19244
+ const localContent = await readFile8(skillSourcePath, "utf-8");
18583
19245
  if (localContent !== packagedContent) {
18584
- const overridePath = resolve5(
19246
+ const overridePath = resolve6(
18585
19247
  cwd,
18586
19248
  `.pourkit/overrides/skills/${skillName}/SKILL.md`
18587
19249
  );
18588
- if (existsSync21(overridePath)) {
19250
+ if (existsSync22(overridePath)) {
18589
19251
  warnings.push({
18590
19252
  severity: "warning",
18591
19253
  kind: "overridden",
@@ -18607,8 +19269,8 @@ async function validateWorkflowPack(cwd) {
18607
19269
  }
18608
19270
  }
18609
19271
  for (const promptName of catalog.prompts) {
18610
- const promptPath = resolve5(cwd, `.pourkit/managed/prompts/${promptName}`);
18611
- if (!existsSync21(promptPath)) {
19272
+ const promptPath = resolve6(cwd, `.pourkit/managed/prompts/${promptName}`);
19273
+ if (!existsSync22(promptPath)) {
18612
19274
  failures.push({
18613
19275
  severity: "failure",
18614
19276
  kind: "missing_managed_asset",
@@ -18618,16 +19280,16 @@ async function validateWorkflowPack(cwd) {
18618
19280
  }
18619
19281
  }
18620
19282
  for (const skillName of baselineSkills) {
18621
- const projectionDir = resolve5(cwd, `.agents/skills/${skillName}`);
18622
- const projectionPath = resolve5(projectionDir, "SKILL.md");
18623
- if (!existsSync21(projectionDir)) {
19283
+ const projectionDir = resolve6(cwd, `.agents/skills/${skillName}`);
19284
+ const projectionPath = resolve6(projectionDir, "SKILL.md");
19285
+ if (!existsSync22(projectionDir)) {
18624
19286
  warnings.push({
18625
19287
  severity: "warning",
18626
19288
  kind: "projection_stale",
18627
19289
  path: `.agents/skills/${skillName}/SKILL.md`,
18628
19290
  message: `Missing skill projection for ${skillName}. Run 'pourkit sync workflow-pack' to regenerate.`
18629
19291
  });
18630
- } else if (!existsSync21(projectionPath)) {
19292
+ } else if (!existsSync22(projectionPath)) {
18631
19293
  warnings.push({
18632
19294
  severity: "warning",
18633
19295
  kind: "projection_stale",
@@ -18643,7 +19305,7 @@ async function validateWorkflowPack(cwd) {
18643
19305
  const packagedContent = await readPackagedTextFile(managedSourcePath);
18644
19306
  if (packagedContent !== null) {
18645
19307
  try {
18646
- const projectionContent = await readFile7(projectionPath, "utf-8");
19308
+ const projectionContent = await readFile8(projectionPath, "utf-8");
18647
19309
  const managedSourceRelativePath = `.pourkit/managed/skills/${skillName}/SKILL.md`;
18648
19310
  if (projectionContent !== buildOpenCodeSkillProjectionContent(
18649
19311
  managedSourceRelativePath,
@@ -18664,8 +19326,8 @@ async function validateWorkflowPack(cwd) {
18664
19326
  for (const agentFile of listPackagedOpenCodeAgentFiles()) {
18665
19327
  const fileName = basename(agentFile);
18666
19328
  const relativePath = `.opencode/agents/${fileName}`;
18667
- const localPath = resolve5(cwd, relativePath);
18668
- if (!existsSync21(localPath)) {
19329
+ const localPath = resolve6(cwd, relativePath);
19330
+ if (!existsSync22(localPath)) {
18669
19331
  failures.push({
18670
19332
  severity: "failure",
18671
19333
  kind: "missing_managed_asset",
@@ -18680,7 +19342,7 @@ async function validateWorkflowPack(cwd) {
18680
19342
  const packagedContent = await readPackagedTextFile(agentFile);
18681
19343
  if (packagedContent === null) continue;
18682
19344
  try {
18683
- const localContent = await readFile7(localPath, "utf-8");
19345
+ const localContent = await readFile8(localPath, "utf-8");
18684
19346
  if (localContent !== packagedContent) {
18685
19347
  failures.push({
18686
19348
  severity: "failure",
@@ -18692,10 +19354,10 @@ async function validateWorkflowPack(cwd) {
18692
19354
  } catch {
18693
19355
  }
18694
19356
  }
18695
- const agentsPath = resolve5(cwd, "AGENTS.md");
18696
- if (existsSync21(agentsPath)) {
19357
+ const agentsPath = resolve6(cwd, "AGENTS.md");
19358
+ if (existsSync22(agentsPath)) {
18697
19359
  try {
18698
- const agentsContent = await readFile7(agentsPath, "utf-8");
19360
+ const agentsContent = await readFile8(agentsPath, "utf-8");
18699
19361
  if (agentsContent.includes(OLD_DOCS_PATH_PATTERN)) {
18700
19362
  failures.push({
18701
19363
  severity: "failure",
@@ -18715,8 +19377,8 @@ async function validateWorkflowPack(cwd) {
18715
19377
  } catch {
18716
19378
  }
18717
19379
  }
18718
- const overridesDir = resolve5(cwd, ".pourkit/overrides");
18719
- if (existsSync21(overridesDir)) {
19380
+ const overridesDir = resolve6(cwd, ".pourkit/overrides");
19381
+ if (existsSync22(overridesDir)) {
18720
19382
  const overrideFiles = await walkDir2(overridesDir);
18721
19383
  for (const file of overrideFiles) {
18722
19384
  const relPath = relative4(cwd, file);
@@ -18730,19 +19392,19 @@ async function validateWorkflowPack(cwd) {
18730
19392
  }
18731
19393
  }
18732
19394
  }
18733
- const configPath = resolve5(cwd, ".pourkit/config.json");
18734
- if (existsSync21(configPath)) {
19395
+ const configPath = resolve6(cwd, ".pourkit/config.json");
19396
+ if (existsSync22(configPath)) {
18735
19397
  try {
18736
- const configContent = await readFile7(configPath, "utf-8");
19398
+ const configContent = await readFile8(configPath, "utf-8");
18737
19399
  const parsed = JSON.parse(configContent);
18738
19400
  const releaseEnabled = parsed.releaseWorkflow?.enabled === true;
18739
19401
  if (releaseEnabled) {
18740
19402
  for (const skillName of catalog.releaseAddonSkills) {
18741
- const addonDir = resolve5(
19403
+ const addonDir = resolve6(
18742
19404
  cwd,
18743
19405
  `.pourkit/managed/addons/release/skills/${skillName}`
18744
19406
  );
18745
- if (!existsSync21(addonDir)) {
19407
+ if (!existsSync22(addonDir)) {
18746
19408
  failures.push({
18747
19409
  severity: "failure",
18748
19410
  kind: "release_config_conflict",
@@ -18752,11 +19414,11 @@ async function validateWorkflowPack(cwd) {
18752
19414
  }
18753
19415
  }
18754
19416
  for (const docName of catalog.releaseAddonDocs) {
18755
- const addonDocPath = resolve5(
19417
+ const addonDocPath = resolve6(
18756
19418
  cwd,
18757
19419
  `.pourkit/managed/addons/release/docs/agents/${docName}`
18758
19420
  );
18759
- if (!existsSync21(addonDocPath)) {
19421
+ if (!existsSync22(addonDocPath)) {
18760
19422
  failures.push({
18761
19423
  severity: "failure",
18762
19424
  kind: "release_config_conflict",
@@ -18768,7 +19430,7 @@ async function validateWorkflowPack(cwd) {
18768
19430
  resolvePackagedReleaseAddonDocPath(docName)
18769
19431
  );
18770
19432
  if (packagedContent !== null) {
18771
- const localContent = await readFile7(addonDocPath, "utf-8");
19433
+ const localContent = await readFile8(addonDocPath, "utf-8");
18772
19434
  if (localContent !== packagedContent) {
18773
19435
  failures.push({
18774
19436
  severity: "failure",
@@ -18797,11 +19459,11 @@ async function validateWorkflowPack(cwd) {
18797
19459
  }
18798
19460
  } else {
18799
19461
  for (const skillName of catalog.releaseAddonSkills) {
18800
- const addonDir = resolve5(
19462
+ const addonDir = resolve6(
18801
19463
  cwd,
18802
19464
  `.pourkit/managed/addons/release/skills/${skillName}`
18803
19465
  );
18804
- if (existsSync21(addonDir)) {
19466
+ if (existsSync22(addonDir)) {
18805
19467
  failures.push({
18806
19468
  severity: "failure",
18807
19469
  kind: "release_config_conflict",
@@ -18811,11 +19473,11 @@ async function validateWorkflowPack(cwd) {
18811
19473
  }
18812
19474
  }
18813
19475
  for (const docName of catalog.releaseAddonDocs) {
18814
- const addonDocPath = resolve5(
19476
+ const addonDocPath = resolve6(
18815
19477
  cwd,
18816
19478
  `.pourkit/managed/addons/release/docs/agents/${docName}`
18817
19479
  );
18818
- if (existsSync21(addonDocPath)) {
19480
+ if (existsSync22(addonDocPath)) {
18819
19481
  failures.push({
18820
19482
  severity: "failure",
18821
19483
  kind: "release_config_conflict",
@@ -18828,16 +19490,16 @@ async function validateWorkflowPack(cwd) {
18828
19490
  } catch {
18829
19491
  }
18830
19492
  }
18831
- const manifestPath = resolve5(cwd, ".pourkit/manifest.json");
18832
- if (existsSync21(manifestPath)) {
19493
+ const manifestPath = resolve6(cwd, ".pourkit/manifest.json");
19494
+ if (existsSync22(manifestPath)) {
18833
19495
  try {
18834
- const manifestContent = await readFile7(manifestPath, "utf-8");
19496
+ const manifestContent = await readFile8(manifestPath, "utf-8");
18835
19497
  const manifest = JSON.parse(manifestContent);
18836
19498
  const wp = manifest.workflowPack;
18837
19499
  if (wp?.projections) {
18838
19500
  for (const proj of wp.projections) {
18839
19501
  if (proj.path) {
18840
- const resolved = resolve5(cwd, proj.path);
19502
+ const resolved = resolve6(cwd, proj.path);
18841
19503
  if (!isPathContained(cwd, resolved)) {
18842
19504
  failures.push({
18843
19505
  severity: "failure",
@@ -18851,8 +19513,8 @@ async function validateWorkflowPack(cwd) {
18851
19513
  } catch {
18852
19514
  }
18853
19515
  }
18854
- const pathEscapeOverrideDir = resolve5(cwd, ".pourkit/overrides");
18855
- if (existsSync21(pathEscapeOverrideDir)) {
19516
+ const pathEscapeOverrideDir = resolve6(cwd, ".pourkit/overrides");
19517
+ if (existsSync22(pathEscapeOverrideDir)) {
18856
19518
  const overrideFiles = await walkDir2(pathEscapeOverrideDir);
18857
19519
  for (const file of overrideFiles) {
18858
19520
  if (!isPathContained(cwd, file)) {
@@ -18865,13 +19527,13 @@ async function validateWorkflowPack(cwd) {
18865
19527
  }
18866
19528
  }
18867
19529
  }
18868
- const managedDocsDir = resolve5(cwd, ".pourkit/managed/docs/agents");
18869
- if (existsSync21(managedDocsDir)) {
19530
+ const managedDocsDir = resolve6(cwd, ".pourkit/managed/docs/agents");
19531
+ if (existsSync22(managedDocsDir)) {
18870
19532
  const docFiles = await walkDir2(managedDocsDir);
18871
19533
  for (const file of docFiles) {
18872
19534
  if (!file.endsWith(".md")) continue;
18873
19535
  try {
18874
- const content = await readFile7(file, "utf-8");
19536
+ const content = await readFile8(file, "utf-8");
18875
19537
  const relPath = relative4(cwd, file);
18876
19538
  const violations = scanManagedPolicyText(content, relPath);
18877
19539
  for (const v of violations) {
@@ -18886,15 +19548,15 @@ async function validateWorkflowPack(cwd) {
18886
19548
  }
18887
19549
  }
18888
19550
  }
18889
- const managedSkillsDir = resolve5(cwd, ".pourkit/managed/skills");
18890
- if (existsSync21(managedSkillsDir)) {
19551
+ const managedSkillsDir = resolve6(cwd, ".pourkit/managed/skills");
19552
+ if (existsSync22(managedSkillsDir)) {
18891
19553
  const skillDirs = await readdir4(managedSkillsDir, { withFileTypes: true });
18892
19554
  for (const entry of skillDirs) {
18893
19555
  if (!entry.isDirectory()) continue;
18894
- const skillFile = resolve5(managedSkillsDir, entry.name, "SKILL.md");
18895
- if (!existsSync21(skillFile)) continue;
19556
+ const skillFile = resolve6(managedSkillsDir, entry.name, "SKILL.md");
19557
+ if (!existsSync22(skillFile)) continue;
18896
19558
  try {
18897
- const content = await readFile7(skillFile, "utf-8");
19559
+ const content = await readFile8(skillFile, "utf-8");
18898
19560
  const relPath = relative4(cwd, skillFile);
18899
19561
  const violations = scanManagedPolicyText(content, relPath);
18900
19562
  for (const v of violations) {
@@ -18909,13 +19571,13 @@ async function validateWorkflowPack(cwd) {
18909
19571
  }
18910
19572
  }
18911
19573
  }
18912
- const managedPromptsDir = resolve5(cwd, ".pourkit/managed/prompts");
18913
- if (existsSync21(managedPromptsDir)) {
19574
+ const managedPromptsDir = resolve6(cwd, ".pourkit/managed/prompts");
19575
+ if (existsSync22(managedPromptsDir)) {
18914
19576
  for (const promptName of catalog.prompts) {
18915
- const promptFile = resolve5(managedPromptsDir, promptName);
18916
- if (!existsSync21(promptFile)) continue;
19577
+ const promptFile = resolve6(managedPromptsDir, promptName);
19578
+ if (!existsSync22(promptFile)) continue;
18917
19579
  try {
18918
- const content = await readFile7(promptFile, "utf-8");
19580
+ const content = await readFile8(promptFile, "utf-8");
18919
19581
  const relPath = relative4(cwd, promptFile);
18920
19582
  const violations = scanManagedPolicyText(content, relPath);
18921
19583
  for (const v of violations) {
@@ -18931,13 +19593,13 @@ async function validateWorkflowPack(cwd) {
18931
19593
  }
18932
19594
  }
18933
19595
  for (const skillName of catalog.releaseAddonSkills) {
18934
- const addonSkillFile = resolve5(
19596
+ const addonSkillFile = resolve6(
18935
19597
  cwd,
18936
19598
  `.pourkit/managed/addons/release/skills/${skillName}/SKILL.md`
18937
19599
  );
18938
- if (!existsSync21(addonSkillFile)) continue;
19600
+ if (!existsSync22(addonSkillFile)) continue;
18939
19601
  try {
18940
- const content = await readFile7(addonSkillFile, "utf-8");
19602
+ const content = await readFile8(addonSkillFile, "utf-8");
18941
19603
  const relPath = relative4(cwd, addonSkillFile);
18942
19604
  const violations = scanManagedPolicyText(content, relPath);
18943
19605
  for (const v of violations) {
@@ -18952,13 +19614,13 @@ async function validateWorkflowPack(cwd) {
18952
19614
  }
18953
19615
  }
18954
19616
  for (const docName of catalog.releaseAddonDocs) {
18955
- const addonDocFile = resolve5(
19617
+ const addonDocFile = resolve6(
18956
19618
  cwd,
18957
19619
  `.pourkit/managed/addons/release/docs/agents/${docName}`
18958
19620
  );
18959
- if (!existsSync21(addonDocFile)) continue;
19621
+ if (!existsSync22(addonDocFile)) continue;
18960
19622
  try {
18961
- const content = await readFile7(addonDocFile, "utf-8");
19623
+ const content = await readFile8(addonDocFile, "utf-8");
18962
19624
  const relPath = relative4(cwd, addonDocFile);
18963
19625
  const violations = scanManagedPolicyText(content, relPath);
18964
19626
  for (const v of violations) {
@@ -18989,16 +19651,16 @@ async function validateMemoryHealth(cwd, memoryConfig) {
18989
19651
  ok: icmPath !== null,
18990
19652
  detail: icmPath !== null ? icmPath : "icm not found on PATH"
18991
19653
  });
18992
- const gitignorePath = resolve5(cwd, ".gitignore");
18993
- const gitignoreContent = existsSync21(gitignorePath) ? readFileSync20(gitignorePath, "utf-8") : "";
19654
+ const gitignorePath = resolve6(cwd, ".gitignore");
19655
+ const gitignoreContent = existsSync22(gitignorePath) ? readFileSync21(gitignorePath, "utf-8") : "";
18994
19656
  const hasGitignoreEntry = gitignoreContent.includes(".pourkit/icm/");
18995
19657
  checks.push({
18996
19658
  name: "icm-gitignore",
18997
19659
  ok: hasGitignoreEntry,
18998
19660
  detail: hasGitignoreEntry ? ".gitignore covers .pourkit/icm/" : ".gitignore does not cover .pourkit/icm/"
18999
19661
  });
19000
- const memoryDbPath = resolve5(cwd, ".pourkit", "icm", "memories.db");
19001
- const hasMemoryDb = existsSync21(memoryDbPath);
19662
+ const memoryDbPath = resolve6(cwd, ".pourkit", "icm", "memories.db");
19663
+ const hasMemoryDb = existsSync22(memoryDbPath);
19002
19664
  checks.push({
19003
19665
  name: "icm-db-exists",
19004
19666
  ok: hasMemoryDb,
@@ -19011,9 +19673,9 @@ async function validateMemoryHealth(cwd, memoryConfig) {
19011
19673
  detail: shapeValid ? "memory: { enabled: true, provider: icm }" : `invalid memory config: enabled=${memoryConfig.enabled}, provider=${memoryConfig.provider}`
19012
19674
  });
19013
19675
  const staleAgentFiles = ["AGENTS.md", "CLAUDE.md"].filter((fileName) => {
19014
- const filePath = resolve5(cwd, fileName);
19015
- if (!existsSync21(filePath)) return false;
19016
- const content = readFileSync20(filePath, "utf-8");
19676
+ const filePath = resolve6(cwd, fileName);
19677
+ if (!existsSync22(filePath)) return false;
19678
+ const content = readFileSync21(filePath, "utf-8");
19017
19679
  const managedBlock = extractManagedBlockContent(content);
19018
19680
  return managedBlock !== null && hasBareIcmMemoryCommand(managedBlock);
19019
19681
  });
@@ -19047,10 +19709,10 @@ function extractManagedBlockContent(content) {
19047
19709
  async function runDoctorCommand(options) {
19048
19710
  const repoRootPath = options.cwd ?? process.cwd();
19049
19711
  const schemaDir = localSchemaDir(repoRootPath);
19050
- const localSchemaPath = resolve5(schemaDir, "pourkit.schema.json");
19051
- const localHashPath = resolve5(schemaDir, "pourkit.schema.hash");
19052
- const localSchemaExists = existsSync21(localSchemaPath);
19053
- const localHashExists = existsSync21(localHashPath);
19712
+ const localSchemaPath = resolve6(schemaDir, "pourkit.schema.json");
19713
+ const localHashPath = resolve6(schemaDir, "pourkit.schema.hash");
19714
+ const localSchemaExists = existsSync22(localSchemaPath);
19715
+ const localHashExists = existsSync22(localHashPath);
19054
19716
  let packagedHash = null;
19055
19717
  try {
19056
19718
  packagedHash = readPackagedHash();
@@ -19059,19 +19721,20 @@ async function runDoctorCommand(options) {
19059
19721
  let localHashContent = null;
19060
19722
  if (localHashExists) {
19061
19723
  try {
19062
- localHashContent = await readFile7(localHashPath, "utf-8");
19724
+ localHashContent = await readFile8(localHashPath, "utf-8");
19063
19725
  } catch {
19064
19726
  }
19065
19727
  }
19066
19728
  const schema = !localSchemaExists ? "missing" : !packagedHash || !localHashContent ? "missing" : localHashContent.trim() === packagedHash.trim() ? "fresh" : "stale";
19067
19729
  const hash = !localHashExists ? "missing" : !packagedHash ? "missing" : localHashContent && localHashContent.trim() === packagedHash.trim() ? "fresh" : "stale";
19068
19730
  const overall = schema === "fresh" && hash === "fresh" ? "fresh" : schema === "missing" || hash === "missing" ? "missing" : "stale";
19069
- const configPath = resolve5(repoRootPath, ".pourkit/config.json");
19731
+ const configPath = resolve6(repoRootPath, ".pourkit/config.json");
19070
19732
  let configValidation;
19071
19733
  let rawMemoryConfig;
19072
- if (existsSync21(configPath)) {
19734
+ let configMigration;
19735
+ if (existsSync22(configPath)) {
19073
19736
  try {
19074
- const raw = JSON.parse(readFileSync20(configPath, "utf-8"));
19737
+ const raw = JSON.parse(readFileSync21(configPath, "utf-8"));
19075
19738
  rawMemoryConfig = raw.memory;
19076
19739
  const validate = getSchemaValidator();
19077
19740
  const valid2 = validate(raw);
@@ -19086,25 +19749,47 @@ async function runDoctorCommand(options) {
19086
19749
  )
19087
19750
  };
19088
19751
  }
19752
+ const plan = planConfigMigration(raw);
19753
+ configMigration = {
19754
+ available: plan.available,
19755
+ safe: plan.safe,
19756
+ command: plan.command,
19757
+ plannedChanges: plan.plannedChanges,
19758
+ blockers: plan.blockers
19759
+ };
19089
19760
  } catch (err) {
19090
19761
  const msg = err instanceof SyntaxError ? err.message : String(err);
19091
19762
  configValidation = {
19092
19763
  ok: false,
19093
19764
  errors: [`.pourkit/config.json: ${msg}`]
19094
19765
  };
19766
+ configMigration = {
19767
+ available: false,
19768
+ safe: false,
19769
+ command: null,
19770
+ plannedChanges: [],
19771
+ blockers: [`.pourkit/config.json: ${msg}`]
19772
+ };
19095
19773
  }
19096
19774
  } else {
19097
19775
  configValidation = {
19098
19776
  ok: false,
19099
19777
  errors: [".pourkit/config.json not found"]
19100
19778
  };
19779
+ configMigration = {
19780
+ available: false,
19781
+ safe: false,
19782
+ command: null,
19783
+ plannedChanges: [],
19784
+ blockers: [".pourkit/config.json not found"]
19785
+ };
19101
19786
  }
19102
19787
  const obsoleteConfigs = [
19103
19788
  "pourkit.config.ts",
19104
19789
  "pourkit.config.mjs",
19105
19790
  "pourkit.config.js",
19106
19791
  "pourkit.json"
19107
- ].filter((p) => existsSync21(resolve5(repoRootPath, p)));
19792
+ ].filter((p) => existsSync22(resolve6(repoRootPath, p)));
19108
19793
  const workflowPack = await validateWorkflowPack(repoRootPath);
19109
19794
  const memory = await validateMemoryHealth(repoRootPath, rawMemoryConfig);
19110
19795
  let recommendation = null;
@@ -19114,7 +19799,15 @@ async function runDoctorCommand(options) {
19114
19799
  `Found obsolete config files: ${obsoleteConfigs.join(", ")}. Move configuration to .pourkit/config.json with "$schema": "./schema/pourkit.schema.json".`
19115
19800
  );
19116
19801
  }
19117
- if (!configValidation.ok) {
19802
+ if (configMigration.available && configMigration.safe) {
19803
+ recParts.push(
19804
+ 'A safe config migration is available. Run "pourkit config migrate" to apply it.'
19805
+ );
19806
+ } else if (!configMigration.available && configMigration.blockers.length > 0) {
19807
+ recParts.push(
19808
+ "Config migration is blocked; fix errors in .pourkit/config.json."
19809
+ );
19810
+ } else if (!configValidation.ok) {
19118
19811
  recParts.push(
19119
19812
  "Config validation failed; fix errors in .pourkit/config.json."
19120
19813
  );
@@ -19139,6 +19832,7 @@ async function runDoctorCommand(options) {
19139
19832
  configValidation,
19140
19833
  obsoleteConfigs,
19141
19834
  schemaAssets: { schema, hash, overall },
19835
+ configMigration,
19142
19836
  workflowPack,
19143
19837
  memory,
19144
19838
  recommendation
@@ -19148,30 +19842,30 @@ async function runConfigSyncSchemaCommand(options) {
19148
19842
  const repoRootPath = options.cwd ?? process.cwd();
19149
19843
  const schemaDir = localSchemaDir(repoRootPath);
19150
19844
  await mkdir6(schemaDir, { recursive: true });
19151
- const packagedSchema = await readFile7(PACKAGED_SCHEMA_PATH, "utf-8");
19152
- const packagedHash = await readFile7(PACKAGED_HASH_PATH, "utf-8");
19153
- const localSchemaPath = resolve5(schemaDir, "pourkit.schema.json");
19154
- const localHashPath = resolve5(schemaDir, "pourkit.schema.hash");
19845
+ const packagedSchema = await readFile8(PACKAGED_SCHEMA_PATH2, "utf-8");
19846
+ const packagedHash = await readFile8(PACKAGED_HASH_PATH, "utf-8");
19847
+ const localSchemaPath = resolve6(schemaDir, "pourkit.schema.json");
19848
+ const localHashPath = resolve6(schemaDir, "pourkit.schema.hash");
19155
19849
  let schemaWritten = false;
19156
19850
  let hashWritten = false;
19157
- if (existsSync21(localSchemaPath)) {
19158
- const existing = await readFile7(localSchemaPath, "utf-8");
19851
+ if (existsSync22(localSchemaPath)) {
19852
+ const existing = await readFile8(localSchemaPath, "utf-8");
19159
19853
  if (existing !== packagedSchema) {
19160
- await writeFile3(localSchemaPath, packagedSchema, "utf-8");
19854
+ await writeFile4(localSchemaPath, packagedSchema, "utf-8");
19161
19855
  schemaWritten = true;
19162
19856
  }
19163
19857
  } else {
19164
- await writeFile3(localSchemaPath, packagedSchema, "utf-8");
19858
+ await writeFile4(localSchemaPath, packagedSchema, "utf-8");
19165
19859
  schemaWritten = true;
19166
19860
  }
19167
- if (existsSync21(localHashPath)) {
19168
- const existing = await readFile7(localHashPath, "utf-8");
19861
+ if (existsSync22(localHashPath)) {
19862
+ const existing = await readFile8(localHashPath, "utf-8");
19169
19863
  if (existing !== packagedHash) {
19170
- await writeFile3(localHashPath, packagedHash, "utf-8");
19864
+ await writeFile4(localHashPath, packagedHash, "utf-8");
19171
19865
  hashWritten = true;
19172
19866
  }
19173
19867
  } else {
19174
- await writeFile3(localHashPath, packagedHash, "utf-8");
19868
+ await writeFile4(localHashPath, packagedHash, "utf-8");
19175
19869
  hashWritten = true;
19176
19870
  }
19177
19871
  return {
@@ -19182,13 +19876,13 @@ async function runConfigSyncSchemaCommand(options) {
19182
19876
  }
19183
19877
 
19184
19878
  // commands/workflow-pack-sync.ts
19185
- import { existsSync as existsSync22, readdirSync as readdirSync6 } from "fs";
19186
- import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile4, readdir as readdir5 } from "fs/promises";
19879
+ import { existsSync as existsSync23, readdirSync as readdirSync6 } from "fs";
19880
+ import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile5, readdir as readdir5 } from "fs/promises";
19187
19881
  import { createHash as createHash2 } from "crypto";
19188
- import { resolve as resolve6, dirname as dirname7, relative as relative5, normalize as normalize2, basename as basename2 } from "path";
19189
- import { fileURLToPath as fileURLToPath4 } from "url";
19190
- var __filename4 = fileURLToPath4(import.meta.url);
19191
- var __dirname4 = dirname7(__filename4);
19882
+ import { resolve as resolve7, dirname as dirname8, relative as relative5, normalize as normalize2, basename as basename2 } from "path";
19883
+ import { fileURLToPath as fileURLToPath5 } from "url";
19884
+ var __filename5 = fileURLToPath5(import.meta.url);
19885
+ var __dirname5 = dirname8(__filename5);
19192
19886
  var PROJECT_OWNED_PATHS = [".pourkit/CONTEXT.md", ".pourkit/CONTEXT-MAP.md"];
19193
19887
  var PROJECT_OWNED_DIRECTORIES = [
19194
19888
  ".pourkit/docs/adr",
@@ -19197,23 +19891,23 @@ var PROJECT_OWNED_DIRECTORIES = [
19197
19891
  ];
19198
19892
  var OVERRIDES_DIR = ".pourkit/overrides";
19199
19893
  function resolvePackagedManagedPath2(...segments) {
19200
- const bundledPath = resolve6(__dirname4, "managed", ...segments);
19201
- const sourcePath = resolve6(__dirname4, "..", "managed", ...segments);
19894
+ const bundledPath = resolve7(__dirname5, "managed", ...segments);
19895
+ const sourcePath = resolve7(__dirname5, "..", "managed", ...segments);
19202
19896
  const candidates = [bundledPath, sourcePath];
19203
- return candidates.find((candidate) => existsSync22(candidate)) ?? bundledPath;
19897
+ return candidates.find((candidate) => existsSync23(candidate)) ?? bundledPath;
19204
19898
  }
19205
19899
  function resolvePackagedOpenCodeAgentsDir2() {
19206
19900
  const candidates = [
19207
- resolve6(__dirname4, ".opencode", "agents"),
19208
- resolve6(__dirname4, "..", ".opencode", "agents"),
19209
- resolve6(__dirname4, "..", "..", ".opencode", "agents")
19901
+ resolve7(__dirname5, ".opencode", "agents"),
19902
+ resolve7(__dirname5, "..", ".opencode", "agents"),
19903
+ resolve7(__dirname5, "..", "..", ".opencode", "agents")
19210
19904
  ];
19211
- return candidates.find((candidate) => existsSync22(candidate)) ?? candidates[0];
19905
+ return candidates.find((candidate) => existsSync23(candidate)) ?? candidates[0];
19212
19906
  }
19213
19907
  function listPackagedOpenCodeAgentFiles2() {
19214
19908
  const agentsDir = resolvePackagedOpenCodeAgentsDir2();
19215
19909
  try {
19216
- return readdirSync6(agentsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => resolve6(agentsDir, entry.name));
19910
+ return readdirSync6(agentsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => resolve7(agentsDir, entry.name));
19217
19911
  } catch {
19218
19912
  return [];
19219
19913
  }
@@ -19247,7 +19941,7 @@ function resolvePackagedManagedPromptPath(promptName) {
19247
19941
  }
19248
19942
  async function readPackagedTextFile2(filePath) {
19249
19943
  try {
19250
- return await readFile8(filePath, "utf-8");
19944
+ return await readFile9(filePath, "utf-8");
19251
19945
  } catch {
19252
19946
  return null;
19253
19947
  }
@@ -19306,7 +20000,7 @@ async function walkDir3(dir) {
19306
20000
  try {
19307
20001
  const entries = await readdir5(dir, { withFileTypes: true });
19308
20002
  for (const entry of entries) {
19309
- const full = resolve6(dir, entry.name);
20003
+ const full = resolve7(dir, entry.name);
19310
20004
  if (entry.isDirectory()) {
19311
20005
  files.push(...await walkDir3(full));
19312
20006
  } else {
@@ -19324,20 +20018,20 @@ async function syncFile(cwd, targetRelativePath, sourceContent, errors) {
19324
20018
  if (sourceContent === null) {
19325
20019
  return false;
19326
20020
  }
19327
- const targetPath = resolve6(cwd, targetRelativePath);
20021
+ const targetPath = resolve7(cwd, targetRelativePath);
19328
20022
  const escapeError = checkForPathEscape(cwd, targetPath);
19329
20023
  if (escapeError) {
19330
20024
  errors.push(escapeError);
19331
20025
  return false;
19332
20026
  }
19333
- await mkdir7(resolve6(targetPath, ".."), { recursive: true });
19334
- if (existsSync22(targetPath)) {
19335
- const existing = await readFile8(targetPath, "utf-8");
20027
+ await mkdir7(resolve7(targetPath, ".."), { recursive: true });
20028
+ if (existsSync23(targetPath)) {
20029
+ const existing = await readFile9(targetPath, "utf-8");
19336
20030
  if (existing === sourceContent) {
19337
20031
  return false;
19338
20032
  }
19339
20033
  }
19340
- await writeFile4(targetPath, sourceContent, "utf-8");
20034
+ await writeFile5(targetPath, sourceContent, "utf-8");
19341
20035
  return true;
19342
20036
  }
19343
20037
  function walkDirSync(dir) {
@@ -19345,7 +20039,7 @@ function walkDirSync(dir) {
19345
20039
  try {
19346
20040
  const entries = readdirSync6(dir, { withFileTypes: true });
19347
20041
  for (const entry of entries) {
19348
- const full = resolve6(dir, entry.name);
20042
+ const full = resolve7(dir, entry.name);
19349
20043
  if (entry.isDirectory()) {
19350
20044
  result.push(...walkDirSync(full));
19351
20045
  } else {
@@ -19357,8 +20051,8 @@ function walkDirSync(dir) {
19357
20051
  return result;
19358
20052
  }
19359
20053
  async function detectOverrides(cwd) {
19360
- const overridesDir = resolve6(cwd, OVERRIDES_DIR);
19361
- if (!existsSync22(overridesDir)) {
20054
+ const overridesDir = resolve7(cwd, OVERRIDES_DIR);
20055
+ if (!existsSync23(overridesDir)) {
19362
20056
  return [];
19363
20057
  }
19364
20058
  const files = await walkDir3(overridesDir);
@@ -19367,14 +20061,14 @@ async function detectOverrides(cwd) {
19367
20061
  async function detectProjectOwnedFiles(cwd) {
19368
20062
  const found = [];
19369
20063
  for (const ownedPath of PROJECT_OWNED_PATHS) {
19370
- const fullPath = resolve6(cwd, ownedPath);
19371
- if (existsSync22(fullPath)) {
20064
+ const fullPath = resolve7(cwd, ownedPath);
20065
+ if (existsSync23(fullPath)) {
19372
20066
  found.push(ownedPath);
19373
20067
  }
19374
20068
  }
19375
20069
  for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
19376
- const fullDir = resolve6(cwd, ownedDir);
19377
- if (existsSync22(fullDir)) {
20070
+ const fullDir = resolve7(cwd, ownedDir);
20071
+ if (existsSync23(fullDir)) {
19378
20072
  const files = await walkDir3(fullDir);
19379
20073
  for (const file of files) {
19380
20074
  found.push(relative5(cwd, file));
@@ -19385,14 +20079,35 @@ async function detectProjectOwnedFiles(cwd) {
19385
20079
  }
19386
20080
  async function isReleaseWorkflowEnabled(cwd) {
19387
20081
  try {
19388
- const configPath = resolve6(cwd, ".pourkit", "config.json");
19389
- const content = await readFile8(configPath, "utf-8");
20082
+ const configPath = resolve7(cwd, ".pourkit", "config.json");
20083
+ const content = await readFile9(configPath, "utf-8");
19390
20084
  const parsed = JSON.parse(content);
19391
20085
  return parsed.releaseWorkflow?.enabled === true;
19392
20086
  } catch {
19393
20087
  return false;
19394
20088
  }
19395
20089
  }
20090
+ async function readConfiguredMemory(cwd) {
20091
+ const configPath = resolve7(cwd, ".pourkit", "config.json");
20092
+ try {
20093
+ const config = await loadConfig(configPath);
20094
+ if (config.memory?.enabled === true && config.memory?.provider === "icm") {
20095
+ return config.memory;
20096
+ }
20097
+ } catch {
20098
+ }
20099
+ try {
20100
+ const content = await readFile9(configPath, "utf-8");
20101
+ const parsed = JSON.parse(content);
20102
+ const memory = parsed.memory;
20103
+ if (typeof memory === "object" && memory !== null && !Array.isArray(memory) && memory.enabled === true && memory.provider === "icm") {
20104
+ return { enabled: true, provider: "icm" };
20105
+ }
20106
+ } catch {
20107
+ return void 0;
20108
+ }
20109
+ return void 0;
20110
+ }
19396
20111
  async function runWorkflowPackSyncCommand(options) {
19397
20112
  const cwd = options.cwd ?? process.cwd();
19398
20113
  const catalog = getWorkflowPackCatalog();
@@ -19401,10 +20116,10 @@ async function runWorkflowPackSyncCommand(options) {
19401
20116
  const skippedProjectOwned = [];
19402
20117
  const overrides = [];
19403
20118
  const errors = [];
19404
- const manifestPath = resolve6(cwd, ".pourkit", "manifest.json");
20119
+ const manifestPath = resolve7(cwd, ".pourkit", "manifest.json");
19405
20120
  let manifestReadFailed = false;
19406
20121
  let manifest = {};
19407
- const existingRawManifest = await readFile8(manifestPath, "utf-8").catch(
20122
+ const existingRawManifest = await readFile9(manifestPath, "utf-8").catch(
19408
20123
  () => null
19409
20124
  );
19410
20125
  if (existingRawManifest) {
@@ -19534,28 +20249,20 @@ async function runWorkflowPackSyncCommand(options) {
19534
20249
  });
19535
20250
  }
19536
20251
  const schemaResult = await runConfigSyncSchemaCommand({ cwd });
19537
- let configMemory;
19538
- try {
19539
- const configPath = resolve6(cwd, ".pourkit", "config.json");
19540
- const config = await loadConfig(configPath);
19541
- if (config.memory?.enabled === true && config.memory?.provider === "icm") {
19542
- configMemory = config.memory;
19543
- }
19544
- } catch {
19545
- }
20252
+ const configMemory = await readConfiguredMemory(cwd);
19546
20253
  const managedBlockContent = generateManagedBlockContent(configMemory);
19547
20254
  const fullManagedBlock = buildManagedBlock(managedBlockContent);
19548
20255
  async function syncManagedAgentFile(fileName, options2) {
19549
- const filePath = resolve6(cwd, fileName);
19550
- if (!existsSync22(filePath)) {
20256
+ const filePath = resolve7(cwd, fileName);
20257
+ if (!existsSync23(filePath)) {
19551
20258
  if (!options2.createIfMissing) return false;
19552
- await writeFile4(filePath, fullManagedBlock, "utf-8");
20259
+ await writeFile5(filePath, fullManagedBlock, "utf-8");
19553
20260
  return true;
19554
20261
  }
19555
- const existing = await readFile8(filePath, "utf-8");
20262
+ const existing = await readFile9(filePath, "utf-8");
19556
20263
  const newContent = upsertManagedBlock(existing, managedBlockContent);
19557
20264
  if (newContent !== existing) {
19558
- await writeFile4(filePath, newContent, "utf-8");
20265
+ await writeFile5(filePath, newContent, "utf-8");
19559
20266
  return true;
19560
20267
  }
19561
20268
  return false;
@@ -19590,8 +20297,8 @@ async function runWorkflowPackSyncCommand(options) {
19590
20297
  errors.push("Failed to write manifest metadata");
19591
20298
  } else {
19592
20299
  try {
19593
- await mkdir7(resolve6(manifestPath, ".."), { recursive: true });
19594
- await writeFile4(
20300
+ await mkdir7(resolve7(manifestPath, ".."), { recursive: true });
20301
+ await writeFile5(
19595
20302
  manifestPath,
19596
20303
  JSON.stringify(manifest, null, 2) + "\n",
19597
20304
  "utf-8"
@@ -19631,7 +20338,7 @@ async function syncOpenCodeAgentFile(sourceFile, acc, ctx, manifestState) {
19631
20338
  const sourceContent = await readPackagedTextFile2(sourceFile);
19632
20339
  const fileName = basename2(sourceFile);
19633
20340
  const targetRelativePath = `.opencode/agents/${fileName}`;
19634
- const targetPath = resolve6(cwd, targetRelativePath);
20341
+ const targetPath = resolve7(cwd, targetRelativePath);
19635
20342
  const escapeError = checkForPathEscape(cwd, targetPath);
19636
20343
  if (escapeError) {
19637
20344
  errors.push(escapeError);
@@ -19645,14 +20352,14 @@ async function syncOpenCodeAgentFile(sourceFile, acc, ctx, manifestState) {
19645
20352
  ownership: "managed",
19646
20353
  sha256: sha256Text(sourceContent)
19647
20354
  };
19648
- if (!existsSync22(targetPath)) {
19649
- await mkdir7(resolve6(targetPath, ".."), { recursive: true });
19650
- await writeFile4(targetPath, sourceContent, "utf-8");
20355
+ if (!existsSync23(targetPath)) {
20356
+ await mkdir7(resolve7(targetPath, ".."), { recursive: true });
20357
+ await writeFile5(targetPath, sourceContent, "utf-8");
19651
20358
  updated.push(targetRelativePath);
19652
20359
  manifestState.manifestAssetUpdates[targetRelativePath] = nextAsset;
19653
20360
  return;
19654
20361
  }
19655
- const existingContent = await readFile8(targetPath, "utf-8");
20362
+ const existingContent = await readFile9(targetPath, "utf-8");
19656
20363
  const existingAsset = manifestState.existingManifestAssets[targetRelativePath];
19657
20364
  const isManifestManaged = existingAsset?.ownership === "managed";
19658
20365
  if (existingContent === sourceContent) {
@@ -19665,7 +20372,7 @@ async function syncOpenCodeAgentFile(sourceFile, acc, ctx, manifestState) {
19665
20372
  }
19666
20373
  return;
19667
20374
  }
19668
- await writeFile4(targetPath, sourceContent, "utf-8");
20375
+ await writeFile5(targetPath, sourceContent, "utf-8");
19669
20376
  updated.push(targetRelativePath);
19670
20377
  manifestState.manifestAssetUpdates[targetRelativePath] = nextAsset;
19671
20378
  }
@@ -20459,7 +21166,7 @@ function formatChecks2(checks) {
20459
21166
  init_common();
20460
21167
 
20461
21168
  // execution/sandcastle-execution.ts
20462
- import { existsSync as existsSync24, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
21169
+ import { existsSync as existsSync25, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
20463
21170
  import { join as join28 } from "path";
20464
21171
  import { createWorktree, opencode } from "@ai-hero/sandcastle";
20465
21172
  import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
@@ -20467,14 +21174,14 @@ import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
20467
21174
  // execution/execution-provider.ts
20468
21175
  init_common();
20469
21176
  import { mkdtempSync } from "fs";
20470
- import { writeFile as writeFile5 } from "fs/promises";
21177
+ import { writeFile as writeFile6 } from "fs/promises";
20471
21178
  import { tmpdir } from "os";
20472
- import { dirname as dirname8, join as join26 } from "path";
21179
+ import { dirname as dirname9, join as join26 } from "path";
20473
21180
  async function writeExecutionArtifacts(worktreePath, artifacts) {
20474
21181
  for (const artifact of artifacts) {
20475
21182
  const filePath = join26(worktreePath, artifact.path);
20476
- await ensureDir(dirname8(filePath));
20477
- await writeFile5(filePath, artifact.content, "utf-8");
21183
+ await ensureDir(dirname9(filePath));
21184
+ await writeFile6(filePath, artifact.content, "utf-8");
20478
21185
  }
20479
21186
  }
20480
21187
 
@@ -20487,18 +21194,18 @@ import path7 from "path";
20487
21194
 
20488
21195
  // execution/sandbox-image.ts
20489
21196
  import { createHash as createHash3 } from "crypto";
20490
- import { existsSync as existsSync23, readFileSync as readFileSync21 } from "fs";
21197
+ import { existsSync as existsSync24, readFileSync as readFileSync22 } from "fs";
20491
21198
  import path6 from "path";
20492
21199
  function sandboxImageName(repoRoot2, installIcm) {
20493
21200
  const dirName = path6.basename(repoRoot2.replace(/[\\/]+$/, "")) || "local";
20494
21201
  const sanitized = dirName.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
20495
21202
  const baseName = sanitized || "local";
20496
21203
  const dockerfilePath = path6.join(repoRoot2, ".sandcastle", "Dockerfile");
20497
- if (!existsSync23(dockerfilePath)) {
21204
+ if (!existsSync24(dockerfilePath)) {
20498
21205
  const base2 = `sandcastle:${baseName}`;
20499
21206
  return installIcm ? `${base2}-icm` : base2;
20500
21207
  }
20501
- const fingerprint = createHash3("sha256").update(readFileSync21(dockerfilePath)).digest("hex").slice(0, 8);
21208
+ const fingerprint = createHash3("sha256").update(readFileSync22(dockerfilePath)).digest("hex").slice(0, 8);
20502
21209
  const base = `sandcastle:${baseName}-${fingerprint}`;
20503
21210
  return installIcm ? `${base}-icm` : base;
20504
21211
  }
@@ -20683,7 +21390,7 @@ var SandcastleExecutionSession = class {
20683
21390
  );
20684
21391
  }
20685
21392
  const hostMemoryDir = join28(repoRoot2, ".pourkit", "icm");
20686
- if (!existsSync24(hostMemoryDir) || !statSync2(hostMemoryDir).isDirectory()) {
21393
+ if (!existsSync25(hostMemoryDir) || !statSync2(hostMemoryDir).isDirectory()) {
20687
21394
  throw new MissingHostMemoryDirError(
20688
21395
  "Memory enabled but host .pourkit/icm/ directory is missing. Run `pourkit memory init` to create the repo-scoped memory store."
20689
21396
  );
@@ -20848,7 +21555,7 @@ function sanitizeBranch(branchName) {
20848
21555
  function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
20849
21556
  return paths.filter((relativePath) => {
20850
21557
  const source = join28(repoRoot2, relativePath);
20851
- if (!existsSync24(source)) {
21558
+ if (!existsSync25(source)) {
20852
21559
  return true;
20853
21560
  }
20854
21561
  try {
@@ -20859,7 +21566,7 @@ function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
20859
21566
  return true;
20860
21567
  }
20861
21568
  const destination = join28(worktreePath, relativePath);
20862
- return !existsSync24(destination);
21569
+ return !existsSync25(destination);
20863
21570
  });
20864
21571
  }
20865
21572
  function formatAgentStreamEvent(event) {
@@ -21555,6 +22262,24 @@ function createCliProgram(version) {
21555
22262
  console.log("Schema assets are up to date.");
21556
22263
  }
21557
22264
  });
22265
+ configCommand.command("migrate").description("Migrate config to the current schema version").option("--cwd <path>", "target repository directory").option("--dry-run", "show planned changes without writing").option("--json", "output machine-readable JSON").action(
22266
+ async (options) => {
22267
+ const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
22268
+ const result = await runConfigMigrateCommand({
22269
+ cwd: targetRepoRoot,
22270
+ dryRun: options.dryRun ?? false,
22271
+ json: options.json ?? false
22272
+ });
22273
+ if (options.json) {
22274
+ console.log(renderConfigMigrateResultJson(result));
22275
+ } else {
22276
+ console.log(renderConfigMigrateResult(result));
22277
+ }
22278
+ if (result.status === "blocked") {
22279
+ process.exitCode = 1;
22280
+ }
22281
+ }
22282
+ );
21558
22283
  const syncCommand = program.command("sync").description("Sync commands for refreshing managed assets");
21559
22284
  syncCommand.command("workflow-pack").description("Refresh managed workflow pack assets from packaged sources").option("--cwd <path>", "target repository directory").action(async (options) => {
21560
22285
  const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
@@ -21712,11 +22437,11 @@ function createCliProgram(version) {
21712
22437
  return program;
21713
22438
  }
21714
22439
  async function resolveCliVersion() {
21715
- if (isPackageVersion("0.0.0-next-20260715085442")) {
21716
- return "0.0.0-next-20260715085442";
22440
+ if (isPackageVersion("0.0.0-next-20260724200221")) {
22441
+ return "0.0.0-next-20260724200221";
21717
22442
  }
21718
- if (isReleaseVersion("0.0.0-next-20260715085442")) {
21719
- return "0.0.0-next-20260715085442";
22443
+ if (isReleaseVersion("0.0.0-next-20260724200221")) {
22444
+ return "0.0.0-next-20260724200221";
21720
22445
  }
21721
22446
  try {
21722
22447
  const root = repoRoot();