@pourkit/cli 0.0.0-next-20260619074943 → 0.0.0-next-20260619094345

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
@@ -869,20 +869,6 @@ function parseConfig(raw) {
869
869
  function getVerificationCommands(target) {
870
870
  return target.strategy.verify?.commands ?? [];
871
871
  }
872
- function resolvePrdRunMode(target, opts) {
873
- if (opts?.localOverride === true) {
874
- return { mode: "local", source: "cli-override", targetName: target.name };
875
- }
876
- const configMode = target.prdRun?.mode;
877
- if (configMode) {
878
- return {
879
- mode: configMode,
880
- source: "target-config",
881
- targetName: target.name
882
- };
883
- }
884
- return { mode: "github", source: "default", targetName: target.name };
885
- }
886
872
  function shouldCleanupRepositoryAfterPrdDrain(target) {
887
873
  return target.prdRun?.cleanupRepository ?? true;
888
874
  }
@@ -894,11 +880,11 @@ var OBSOLETE_CONFIG_PATHS = [
894
880
  ];
895
881
  var CANONICAL_CONFIG_PATH = ".pourkit/config.json";
896
882
  async function loadRepoConfig(repoRoot2, _configFileName) {
897
- const { existsSync: existsSync24 } = await import("fs");
883
+ const { existsSync: existsSync21 } = await import("fs");
898
884
  const { join: pjoin } = await import("path");
899
885
  for (const obPath of OBSOLETE_CONFIG_PATHS) {
900
886
  const fullPath = pjoin(repoRoot2, obPath);
901
- if (existsSync24(fullPath)) {
887
+ if (existsSync21(fullPath)) {
902
888
  const isRootJson = obPath === "pourkit.json";
903
889
  throw new Error(
904
890
  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".`
@@ -906,13 +892,13 @@ async function loadRepoConfig(repoRoot2, _configFileName) {
906
892
  }
907
893
  }
908
894
  const configPath = pjoin(repoRoot2, CANONICAL_CONFIG_PATH);
909
- if (!existsSync24(configPath)) {
895
+ if (!existsSync21(configPath)) {
910
896
  throw new Error(
911
897
  `No Pourkit config found at ${CANONICAL_CONFIG_PATH}. Run pourkit init or create ${CANONICAL_CONFIG_PATH} with "$schema": "./schema/pourkit.schema.json".`
912
898
  );
913
899
  }
914
- const { readFile: readFile8 } = await import("fs/promises");
915
- const raw = await readFile8(configPath, "utf-8");
900
+ const { readFile: readFile7 } = await import("fs/promises");
901
+ const raw = await readFile7(configPath, "utf-8");
916
902
  let parsed;
917
903
  try {
918
904
  parsed = JSON.parse(raw);
@@ -923,10 +909,10 @@ async function loadRepoConfig(repoRoot2, _configFileName) {
923
909
  return parseConfig(parsed);
924
910
  }
925
911
  async function loadConfig(configPath) {
926
- const { readFile: readFile8 } = await import("fs/promises");
912
+ const { readFile: readFile7 } = await import("fs/promises");
927
913
  const ext = configPath.split(".").pop()?.toLowerCase();
928
914
  if (ext === "json") {
929
- const raw = await readFile8(configPath, "utf-8");
915
+ const raw = await readFile7(configPath, "utf-8");
930
916
  return parseConfig(JSON.parse(raw));
931
917
  }
932
918
  if (ext === "mjs" || ext === "js" || ext === "ts") {
@@ -1148,10 +1134,9 @@ async function cleanupRepository(options) {
1148
1134
  }
1149
1135
 
1150
1136
  // commands/artifact-validation.ts
1151
- import { createHash } from "crypto";
1152
1137
  import { execSync } from "child_process";
1153
- import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync7 } from "fs";
1154
- import { isAbsolute as isAbsolute3, join as join7, resolve as resolve3 } from "path";
1138
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
1139
+ import { isAbsolute as isAbsolute3, resolve as resolve3 } from "path";
1155
1140
 
1156
1141
  // pr/review-verdict.ts
1157
1142
  var ReviewVerdictProtocolError = class extends Error {
@@ -3670,18 +3655,6 @@ function validateAgentArtifact(options) {
3670
3655
  }
3671
3656
  return valid(options, [`decision: ${parsed.json.recoveryDecision}`]);
3672
3657
  }
3673
- case "local-prd":
3674
- case "local-issue":
3675
- case "local-triage":
3676
- return invalid(
3677
- options,
3678
- `Local artifact kind must be validated through runLocalValidateArtifactCommand`
3679
- );
3680
- case "local-prepare":
3681
- return invalid(
3682
- options,
3683
- `Artifact kind "${options.kind}" has been removed from PRD Run validation`
3684
- );
3685
3658
  }
3686
3659
  } catch (error) {
3687
3660
  if (error instanceof ReviewArtifactValidationError || error instanceof ReviewVerdictProtocolError || error instanceof PrDescriptionProtocolError || error instanceof ConflictResolutionArtifactProtocolError || error instanceof RecoveryArtifactInvalid || error instanceof Error) {
@@ -3735,874 +3708,127 @@ function isIssueFinalReviewAuditedPath(path9) {
3735
3708
  function shellQuote(value) {
3736
3709
  return `'${value.replace(/'/g, `'"'"'`)}'`;
3737
3710
  }
3738
- function runLocalValidateArtifactCommand(options) {
3739
- const resolvedPath = resolve3(options.repoRoot, options.artifactPath);
3740
- const resolvedExtra = (options.extraArgs ?? []).map(
3741
- (p) => isAbsolute3(p) ? p : resolve3(options.repoRoot, p)
3742
- );
3743
- let localResult;
3744
- switch (options.kind) {
3745
- case "local-prd":
3746
- localResult = validateLocalPrd(resolvedPath);
3747
- break;
3748
- case "local-issue":
3749
- localResult = validateLocalIssue(resolvedPath);
3750
- break;
3751
- case "local-triage":
3752
- localResult = validateLocalTriage(resolvedPath, resolvedExtra);
3753
- break;
3754
- default:
3755
- return {
3756
- ok: false,
3757
- kind: options.kind,
3758
- artifactPath: resolvedPath,
3759
- reason: `Unsupported local artifact kind "${options.kind}"`,
3760
- diagnostics: []
3761
- };
3762
- }
3763
- if (localResult.ok) {
3764
- return {
3765
- ok: true,
3766
- kind: options.kind,
3767
- artifactPath: resolvedPath,
3768
- diagnostics: []
3769
- };
3770
- }
3771
- const diagnostics = [];
3772
- if (localResult.gate) diagnostics.push(`gate: ${localResult.gate}`);
3773
- if (localResult.failureCode)
3774
- diagnostics.push(`failureCode: ${localResult.failureCode}`);
3775
- if (localResult.offendingPath)
3776
- diagnostics.push(`offendingPath: ${localResult.offendingPath}`);
3777
- if (localResult.message) diagnostics.push(localResult.message);
3778
- return {
3779
- ok: false,
3780
- kind: options.kind,
3781
- artifactPath: resolvedPath,
3782
- reason: localResult.message ?? "Validation failed",
3783
- diagnostics
3784
- };
3711
+
3712
+ // commands/issue-run.ts
3713
+ import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
3714
+ import { isAbsolute as isAbsolute5, join as join14 } from "path";
3715
+
3716
+ // pr/templates.ts
3717
+ init_common();
3718
+ function renderBranchName(template, issue) {
3719
+ return renderTemplate(template, issue);
3785
3720
  }
3786
- function readLocalArtifact(path9, failureCode) {
3787
- try {
3788
- const raw = readFileSync7(path9, "utf-8");
3789
- const parsed = JSON.parse(raw);
3790
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
3791
- return {
3792
- ok: false,
3793
- failureCode: failureCode ?? "invalid_prd_artifact",
3794
- offendingPath: path9,
3795
- message: `Expected a JSON object, got ${Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed}`
3796
- };
3797
- }
3798
- return { ok: true, data: parsed };
3799
- } catch (e) {
3800
- return {
3801
- ok: false,
3802
- failureCode: failureCode ?? "invalid_prd_artifact",
3803
- offendingPath: path9,
3804
- message: `Failed to read or parse: ${e}`
3805
- };
3806
- }
3721
+ function renderTemplate(template, issue) {
3722
+ const issueSlug = slugify(issue.title);
3723
+ return template.replace(/\{\{issue\.number\}\}/g, String(issue.number)).replace(/\{\{issue\.title\}\}/g, issue.title).replace(/\{\{issue\.body\}\}/g, issue.body).replace(/\{\{issue\.slug\}\}/g, issueSlug).replace(/\{\{issue\.state\}\}/g, issue.state);
3807
3724
  }
3808
- var VALID_LOCAL_PRD_STATUSES = [
3809
- "draft",
3810
- "ready",
3811
- "prepared",
3812
- "running",
3813
- "final-review",
3814
- "reconciliation",
3815
- "complete",
3816
- "blocked"
3817
- ];
3818
- var TO_PRD_REQUIRED_HEADINGS = [
3819
- "Problem Statement",
3820
- "Solution",
3821
- "Plan Documents",
3822
- "User Stories",
3823
- "Implementation Decisions",
3824
- "Testing Decisions",
3825
- "Out of Scope",
3826
- "Further Notes"
3827
- ];
3828
- var TO_ISSUES_REQUIRED_HEADINGS = [
3829
- "Parent",
3830
- "Plan Documents",
3831
- "Source of truth for behavior",
3832
- "What to build",
3833
- "High-level explanation",
3834
- "Affected code paths",
3835
- "Exploration evidence",
3836
- "Contract decisions",
3837
- "Execution path matrix",
3838
- "Regression contract (CRITICAL)",
3839
- "Step-by-step implementation",
3840
- "Contracts / interfaces",
3841
- "Edge cases",
3842
- "Validation",
3843
- "Out of scope",
3844
- "Priority",
3845
- "Acceptance criteria",
3846
- "Blocked by"
3847
- ];
3848
- var VALID_LOCAL_ISSUE_STATUSES = [
3849
- "needs-triage",
3850
- "ready-for-agent",
3851
- "blocked",
3852
- "ready-for-human",
3853
- "wontfix",
3854
- "running",
3855
- "complete"
3856
- ];
3857
- var VALID_ISSUE_TRIAGE_LABELS = [
3858
- "needs-triage",
3859
- "ready-for-agent",
3860
- "blocked",
3861
- "ready-for-human",
3862
- "wontfix",
3863
- "running",
3864
- "complete"
3865
- ];
3866
- var VALID_ISSUE_CATEGORY_LABELS = ["bug", "enhancement"];
3867
- var VALID_ISSUE_TYPE_LABELS = [
3868
- "type:bugfix",
3869
- "type:infra",
3870
- "type:feature",
3871
- "type:polish",
3872
- "type:refactor"
3873
- ];
3874
- var ISSUE_RECEIPT_FIELDS = [
3875
- "createdAt",
3876
- "updatedAt",
3877
- "preparedAt",
3878
- "startedAt",
3879
- "completedAt",
3880
- "reviewedAt",
3881
- "mergedAt"
3882
- ];
3883
- var ISSUE_PROJECTION_FIELDS = [
3884
- "issueNumber",
3885
- "issueUrl",
3886
- "publishedAt",
3887
- "syncedAt"
3888
- ];
3889
- function getMarkdownHeadings(markdown) {
3890
- const headingRegex = /^## (.+)$/gm;
3891
- const headings = [];
3892
- let match;
3893
- while ((match = headingRegex.exec(markdown)) !== null) {
3894
- headings.push(match[1].trim());
3725
+
3726
+ // commands/issue-run.ts
3727
+ init_common();
3728
+
3729
+ // commands/base-refresh.ts
3730
+ init_common();
3731
+ async function isIssueBranchStale(worktreePath, baseBranch, logger) {
3732
+ try {
3733
+ await execCapture(
3734
+ "git",
3735
+ ["merge-base", "--is-ancestor", baseBranch, "HEAD"],
3736
+ {
3737
+ cwd: worktreePath,
3738
+ logger,
3739
+ label: "git merge-base --is-ancestor"
3740
+ }
3741
+ );
3742
+ return false;
3743
+ } catch {
3744
+ return true;
3895
3745
  }
3896
- return headings;
3897
3746
  }
3898
- function validateLocalPrd(path9) {
3899
- const parsed = readLocalArtifact(path9);
3900
- if (!parsed.ok) return parsed;
3901
- const data = parsed.data;
3902
- if (data.schemaVersion !== 1) {
3903
- return {
3904
- ok: false,
3905
- failureCode: "invalid_prd_artifact",
3906
- offendingPath: path9,
3907
- message: "schemaVersion must be 1"
3908
- };
3909
- }
3910
- if (data.kind !== "prd") {
3911
- return {
3912
- ok: false,
3913
- failureCode: "invalid_prd_artifact",
3914
- offendingPath: path9,
3915
- message: "kind must be prd"
3916
- };
3917
- }
3918
- if (typeof data.id !== "string" || data.id.trim() === "") {
3919
- return {
3920
- ok: false,
3921
- failureCode: "invalid_prd_artifact",
3922
- offendingPath: path9,
3923
- message: "id must be a non-empty string"
3924
- };
3925
- }
3926
- if (typeof data.title !== "string" || data.title.trim() === "") {
3927
- return {
3928
- ok: false,
3929
- failureCode: "invalid_prd_artifact",
3930
- offendingPath: path9,
3931
- message: "title must be a non-empty string"
3932
- };
3933
- }
3934
- if (typeof data.status !== "string" || !VALID_LOCAL_PRD_STATUSES.includes(data.status)) {
3935
- return {
3936
- ok: false,
3937
- failureCode: "invalid_prd_artifact",
3938
- offendingPath: path9,
3939
- message: `status must be one of: ${VALID_LOCAL_PRD_STATUSES.join(", ")}`
3940
- };
3941
- }
3942
- if (!Array.isArray(data.childIssueIds)) {
3943
- return {
3944
- ok: false,
3945
- failureCode: "invalid_prd_artifact",
3946
- offendingPath: path9,
3947
- message: "childIssueIds must be an array"
3948
- };
3949
- }
3950
- if (!Array.isArray(data.linkedDecisionIds)) {
3951
- return {
3952
- ok: false,
3953
- failureCode: "invalid_prd_artifact",
3954
- offendingPath: path9,
3955
- message: "linkedDecisionIds must be an array"
3956
- };
3957
- }
3958
- if (!data.reconciliationTarget || typeof data.reconciliationTarget !== "object") {
3959
- return {
3960
- ok: false,
3961
- failureCode: "invalid_prd_artifact",
3962
- offendingPath: path9,
3963
- message: "reconciliationTarget must be an object"
3964
- };
3965
- }
3966
- const reconciliationTarget = data.reconciliationTarget;
3967
- if (typeof reconciliationTarget.localPrdBranch !== "string" || reconciliationTarget.localPrdBranch.trim() === "") {
3968
- return {
3969
- ok: false,
3970
- failureCode: "invalid_prd_artifact",
3971
- offendingPath: path9,
3972
- message: "reconciliationTarget.localPrdBranch must be a non-empty string"
3973
- };
3974
- }
3975
- if (typeof reconciliationTarget.integrationBranch !== "string" || reconciliationTarget.integrationBranch.trim() === "") {
3976
- return {
3977
- ok: false,
3978
- failureCode: "invalid_prd_artifact",
3979
- offendingPath: path9,
3980
- message: "reconciliationTarget.integrationBranch must be a non-empty string"
3981
- };
3982
- }
3983
- if (typeof data.bodyMarkdown !== "string" || data.bodyMarkdown.trim() === "") {
3984
- return {
3985
- ok: false,
3986
- failureCode: "invalid_prd_artifact",
3987
- offendingPath: path9,
3988
- message: "bodyMarkdown must be a non-empty string"
3989
- };
3990
- }
3991
- if (!data.bodyContract || typeof data.bodyContract !== "object") {
3992
- return {
3993
- ok: false,
3994
- failureCode: "invalid_prd_artifact",
3995
- offendingPath: path9,
3996
- message: "bodyContract must be an object"
3997
- };
3998
- }
3999
- const bodyContract = data.bodyContract;
4000
- if (bodyContract.contract !== "to-prd") {
4001
- return {
4002
- ok: false,
4003
- failureCode: "invalid_prd_artifact",
4004
- offendingPath: path9,
4005
- message: 'bodyContract.contract must be "to-prd"'
4006
- };
4007
- }
4008
- if (!Array.isArray(bodyContract.requiredHeadings)) {
4009
- return {
4010
- ok: false,
4011
- failureCode: "invalid_prd_artifact",
4012
- offendingPath: path9,
4013
- message: "bodyContract.requiredHeadings must be an array"
4014
- };
4015
- }
4016
- const requiredHeadings = bodyContract.requiredHeadings;
4017
- const missingHeadings = TO_PRD_REQUIRED_HEADINGS.filter(
4018
- (h) => !requiredHeadings.includes(h)
4019
- );
4020
- if (missingHeadings.length > 0) {
4021
- return {
4022
- ok: false,
4023
- failureCode: "invalid_prd_artifact",
4024
- offendingPath: path9,
4025
- message: `bodyContract.requiredHeadings missing: ${missingHeadings.join(", ")}`
4026
- };
4027
- }
4028
- const markdownHeadings = getMarkdownHeadings(data.bodyMarkdown);
4029
- const missingInMarkdown = TO_PRD_REQUIRED_HEADINGS.filter(
4030
- (h) => !markdownHeadings.includes(h)
4031
- );
4032
- if (missingInMarkdown.length > 0) {
4033
- return {
4034
- ok: false,
4035
- failureCode: "invalid_prd_artifact",
4036
- offendingPath: path9,
4037
- message: `bodyMarkdown missing headings: ${missingInMarkdown.join(", ")}`
4038
- };
3747
+ async function refreshStaleIssueBranch(options) {
3748
+ const {
3749
+ worktreePath,
3750
+ baseBranch,
3751
+ localGitBaseRef,
3752
+ logger,
3753
+ prNumber,
3754
+ prState
3755
+ } = options;
3756
+ const stale = await isIssueBranchStale(worktreePath, localGitBaseRef, logger);
3757
+ if (!stale) {
3758
+ return { status: "skipped-current" };
4039
3759
  }
4040
- if (!data.receipts || typeof data.receipts !== "object") {
3760
+ if (prNumber !== void 0 && prState !== void 0) {
4041
3761
  return {
4042
- ok: false,
4043
- failureCode: "invalid_prd_artifact",
4044
- offendingPath: path9,
4045
- message: "receipts must be an object"
3762
+ status: "refused-published-history",
3763
+ prNumber,
3764
+ prState
4046
3765
  };
4047
3766
  }
4048
- const receipts = data.receipts;
4049
- const expectedReceiptFields = [
4050
- "createdAt",
4051
- "updatedAt",
4052
- "preparedAt",
4053
- "startedAt",
4054
- "finalReviewedAt",
4055
- "reconciledAt",
4056
- "completedAt"
4057
- ];
4058
- for (const field of expectedReceiptFields) {
4059
- if (!(field in receipts)) {
4060
- return {
4061
- ok: false,
4062
- failureCode: "invalid_prd_artifact",
4063
- offendingPath: path9,
4064
- message: `receipts.${field} is missing`
4065
- };
3767
+ try {
3768
+ await execCapture("git", ["rebase", "--autostash", localGitBaseRef], {
3769
+ cwd: worktreePath,
3770
+ logger,
3771
+ label: "git rebase --autostash"
3772
+ });
3773
+ return { status: "refreshed" };
3774
+ } catch (error) {
3775
+ let conflictedPaths = [];
3776
+ try {
3777
+ const statusResult = await execCapture("git", ["status", "--porcelain"], {
3778
+ cwd: worktreePath,
3779
+ logger,
3780
+ label: "git status"
3781
+ });
3782
+ conflictedPaths = statusResult.stdout.split("\n").filter((line) => /^(AA|DD|UU|AU|UA|DU|UD)\s/.test(line)).map((line) => line.slice(3).trim()).filter(Boolean);
3783
+ } catch {
4066
3784
  }
4067
- }
4068
- if (!data.githubProjection || typeof data.githubProjection !== "object") {
4069
3785
  return {
4070
- ok: false,
4071
- failureCode: "invalid_prd_artifact",
4072
- offendingPath: path9,
4073
- message: "githubProjection must be an object"
3786
+ status: "conflicted",
3787
+ message: error instanceof Error ? error.message : String(error),
3788
+ conflictedPaths
4074
3789
  };
4075
3790
  }
4076
- const githubProjection = data.githubProjection;
4077
- const expectedProjectionFields = [
4078
- "issueNumber",
4079
- "issueUrl",
4080
- "publishedAt",
4081
- "syncedAt"
4082
- ];
4083
- for (const field of expectedProjectionFields) {
4084
- if (!(field in githubProjection)) {
4085
- return {
4086
- ok: false,
4087
- failureCode: "invalid_prd_artifact",
4088
- offendingPath: path9,
4089
- message: `githubProjection.${field} is missing`
4090
- };
3791
+ }
3792
+ function invalidateAfterBaseRefresh(state) {
3793
+ return {
3794
+ issueNumber: state.issueNumber,
3795
+ targetName: state.targetName,
3796
+ branchName: state.branchName,
3797
+ baseBranch: state.baseBranch,
3798
+ createdAt: state.createdAt,
3799
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3800
+ completedStages: {
3801
+ builder: state.completedStages.builder
3802
+ },
3803
+ review: {
3804
+ lifetimeIterations: 0
4091
3805
  }
4092
- }
4093
- return { ok: true };
3806
+ };
4094
3807
  }
4095
- function validateLocalIssue(path9) {
4096
- const parsed = readLocalArtifact(path9);
4097
- if (!parsed.ok) {
4098
- return {
4099
- ok: false,
4100
- failureCode: "invalid_issue_artifact",
4101
- offendingPath: path9,
4102
- message: parsed.message
4103
- };
4104
- }
4105
- const data = parsed.data;
4106
- if (data.schemaVersion !== 1) {
4107
- return {
4108
- ok: false,
4109
- failureCode: "invalid_issue_artifact",
4110
- offendingPath: path9,
4111
- message: "schemaVersion must be 1"
4112
- };
4113
- }
4114
- if (data.kind !== "issue") {
4115
- return {
4116
- ok: false,
4117
- failureCode: "invalid_issue_artifact",
4118
- offendingPath: path9,
4119
- message: 'kind must be "issue"'
4120
- };
4121
- }
4122
- if (typeof data.id !== "string" || data.id.trim() === "") {
4123
- return {
4124
- ok: false,
4125
- failureCode: "invalid_issue_artifact",
4126
- offendingPath: path9,
4127
- message: "id must be a non-empty string"
4128
- };
4129
- }
4130
- if (typeof data.parentPrdId !== "string" || !/^PRD-\d{4}$/.test(data.parentPrdId.trim())) {
4131
- return {
4132
- ok: false,
4133
- failureCode: "invalid_issue_artifact",
4134
- offendingPath: path9,
4135
- message: "parentPrdId must match PRD-0000N format"
4136
- };
3808
+
3809
+ // failure-resolution/effect-runtime.ts
3810
+ import { Effect as Effect4 } from "effect";
3811
+
3812
+ // shared/effect-runtime.ts
3813
+ import { Effect as Effect3, Exit } from "effect";
3814
+ import { UnknownException } from "effect/Cause";
3815
+ var initialized = false;
3816
+ function initializeEffectRuntime() {
3817
+ if (initialized) return;
3818
+ initialized = true;
3819
+ }
3820
+ function runEffect(program) {
3821
+ ensureEffectRuntime();
3822
+ return Effect3.runPromiseExit(program);
3823
+ }
3824
+ function ensureEffectRuntime() {
3825
+ if (!initialized) {
3826
+ initializeEffectRuntime();
4137
3827
  }
4138
- if (typeof data.title !== "string" || data.title.trim() === "") {
4139
- return {
4140
- ok: false,
4141
- failureCode: "invalid_issue_artifact",
4142
- offendingPath: path9,
4143
- message: "title must be a non-empty string"
4144
- };
4145
- }
4146
- if (typeof data.status !== "string" || !VALID_LOCAL_ISSUE_STATUSES.includes(data.status)) {
4147
- return {
4148
- ok: false,
4149
- failureCode: "invalid_issue_artifact",
4150
- offendingPath: path9,
4151
- message: `status must be one of: ${VALID_LOCAL_ISSUE_STATUSES.join(", ")}`
4152
- };
4153
- }
4154
- if (!Array.isArray(data.labels)) {
4155
- return {
4156
- ok: false,
4157
- failureCode: "invalid_issue_artifact",
4158
- offendingPath: path9,
4159
- message: "labels must be an array"
4160
- };
4161
- }
4162
- const labels = data.labels;
4163
- const triageLabel = labels.find((l) => VALID_ISSUE_TRIAGE_LABELS.includes(l));
4164
- const categoryLabel = labels.find(
4165
- (l) => VALID_ISSUE_CATEGORY_LABELS.includes(l)
4166
- );
4167
- const typeLabel = labels.find((l) => VALID_ISSUE_TYPE_LABELS.includes(l));
4168
- const unknownLabels = labels.filter(
4169
- (l) => !VALID_ISSUE_TRIAGE_LABELS.includes(l) && !VALID_ISSUE_CATEGORY_LABELS.includes(l) && !VALID_ISSUE_TYPE_LABELS.includes(l)
4170
- );
4171
- if (!triageLabel) {
4172
- return {
4173
- ok: false,
4174
- failureCode: "invalid_issue_artifact",
4175
- offendingPath: path9,
4176
- message: `labels must include one triage-state label from: ${VALID_ISSUE_TRIAGE_LABELS.join(", ")}`
4177
- };
4178
- }
4179
- if (!categoryLabel) {
4180
- return {
4181
- ok: false,
4182
- failureCode: "invalid_issue_artifact",
4183
- offendingPath: path9,
4184
- message: `labels must include one category label from: ${VALID_ISSUE_CATEGORY_LABELS.join(", ")}`
4185
- };
4186
- }
4187
- if (!typeLabel) {
4188
- return {
4189
- ok: false,
4190
- failureCode: "invalid_issue_artifact",
4191
- offendingPath: path9,
4192
- message: `labels must include one type label from: ${VALID_ISSUE_TYPE_LABELS.join(", ")}`
4193
- };
4194
- }
4195
- if (data.status !== "running" && data.status !== "complete" && triageLabel !== data.status) {
4196
- return {
4197
- ok: false,
4198
- failureCode: "invalid_issue_artifact",
4199
- offendingPath: path9,
4200
- message: `triage-state label must match status: expected "${data.status}", got "${triageLabel}"`
4201
- };
4202
- }
4203
- const typeLabels = labels.filter((l) => l.startsWith("type:"));
4204
- if (typeLabels.length > 1) {
4205
- return {
4206
- ok: false,
4207
- failureCode: "invalid_issue_artifact",
4208
- offendingPath: path9,
4209
- message: "more than one type:* label found"
4210
- };
4211
- }
4212
- if (labels.length !== 3 || unknownLabels.length > 0) {
4213
- return {
4214
- ok: false,
4215
- failureCode: "invalid_issue_artifact",
4216
- offendingPath: path9,
4217
- message: "labels must contain exactly 3 entries: one triage-state, one category, one type:*"
4218
- };
4219
- }
4220
- if (!Array.isArray(data.dependencyIssueIds)) {
4221
- return {
4222
- ok: false,
4223
- failureCode: "invalid_issue_artifact",
4224
- offendingPath: path9,
4225
- message: "dependencyIssueIds must be an array"
4226
- };
4227
- }
4228
- if (typeof data.branchName !== "string" || !/^local\/PRD-\d{4}\/I-\d{2}-[a-z0-9-]+$/.test(data.branchName)) {
4229
- return {
4230
- ok: false,
4231
- failureCode: "invalid_issue_artifact",
4232
- offendingPath: path9,
4233
- message: "branchName must match local/PRD-0000N/I-0N-slug pattern"
4234
- };
4235
- }
4236
- if (!(data.blockedReason === null || typeof data.blockedReason === "string")) {
4237
- return {
4238
- ok: false,
4239
- failureCode: "invalid_issue_artifact",
4240
- offendingPath: path9,
4241
- message: "blockedReason must be a string or null"
4242
- };
4243
- }
4244
- if (!(data.readyForHumanReason === null || typeof data.readyForHumanReason === "string")) {
4245
- return {
4246
- ok: false,
4247
- failureCode: "invalid_issue_artifact",
4248
- offendingPath: path9,
4249
- message: "readyForHumanReason must be a string or null"
4250
- };
4251
- }
4252
- if (typeof data.bodyMarkdown !== "string" || data.bodyMarkdown.trim() === "") {
4253
- return {
4254
- ok: false,
4255
- failureCode: "invalid_issue_artifact",
4256
- offendingPath: path9,
4257
- message: "bodyMarkdown must be a non-empty string"
4258
- };
4259
- }
4260
- if (!data.bodyContract || typeof data.bodyContract !== "object") {
4261
- return {
4262
- ok: false,
4263
- failureCode: "invalid_issue_artifact",
4264
- offendingPath: path9,
4265
- message: "bodyContract must be an object"
4266
- };
4267
- }
4268
- const bodyContract = data.bodyContract;
4269
- if (bodyContract.contract !== "to-issues") {
4270
- return {
4271
- ok: false,
4272
- failureCode: "invalid_issue_artifact",
4273
- offendingPath: path9,
4274
- message: 'bodyContract.contract must be "to-issues"'
4275
- };
4276
- }
4277
- if (!Array.isArray(bodyContract.requiredHeadings)) {
4278
- return {
4279
- ok: false,
4280
- failureCode: "invalid_issue_artifact",
4281
- offendingPath: path9,
4282
- message: "bodyContract.requiredHeadings must be an array"
4283
- };
4284
- }
4285
- const requiredHeadings = bodyContract.requiredHeadings;
4286
- const missingHeadings = TO_ISSUES_REQUIRED_HEADINGS.filter(
4287
- (h) => !requiredHeadings.includes(h)
4288
- );
4289
- if (missingHeadings.length > 0) {
4290
- return {
4291
- ok: false,
4292
- failureCode: "invalid_issue_artifact",
4293
- offendingPath: path9,
4294
- message: `bodyContract.requiredHeadings missing: ${missingHeadings.join(", ")}`
4295
- };
4296
- }
4297
- const markdownHeadings = getMarkdownHeadings(data.bodyMarkdown);
4298
- const missingInMarkdown = TO_ISSUES_REQUIRED_HEADINGS.filter(
4299
- (h) => !markdownHeadings.includes(h)
4300
- );
4301
- if (missingInMarkdown.length > 0) {
4302
- return {
4303
- ok: false,
4304
- failureCode: "invalid_issue_artifact",
4305
- offendingPath: path9,
4306
- message: `bodyMarkdown missing headings: ${missingInMarkdown.join(", ")}`
4307
- };
4308
- }
4309
- if (!data.receipts || typeof data.receipts !== "object") {
4310
- return {
4311
- ok: false,
4312
- failureCode: "invalid_issue_artifact",
4313
- offendingPath: path9,
4314
- message: "receipts must be an object"
4315
- };
4316
- }
4317
- const receipts = data.receipts;
4318
- for (const field of ISSUE_RECEIPT_FIELDS) {
4319
- if (!(field in receipts)) {
4320
- return {
4321
- ok: false,
4322
- failureCode: "invalid_issue_artifact",
4323
- offendingPath: path9,
4324
- message: `receipts.${field} is missing`
4325
- };
4326
- }
4327
- }
4328
- if (!data.githubProjection || typeof data.githubProjection !== "object") {
4329
- return {
4330
- ok: false,
4331
- failureCode: "invalid_issue_artifact",
4332
- offendingPath: path9,
4333
- message: "githubProjection must be an object"
4334
- };
4335
- }
4336
- const githubProjection = data.githubProjection;
4337
- for (const field of ISSUE_PROJECTION_FIELDS) {
4338
- if (!(field in githubProjection)) {
4339
- return {
4340
- ok: false,
4341
- failureCode: "invalid_issue_artifact",
4342
- offendingPath: path9,
4343
- message: `githubProjection.${field} is missing`
4344
- };
4345
- }
4346
- }
4347
- return { ok: true };
4348
- }
4349
- function validateLocalTriage(prdPath, issuePaths) {
4350
- const prd = readLocalArtifact(
4351
- prdPath,
4352
- "triage_inconsistent"
4353
- );
4354
- if (!prd.ok || !prd.data) {
4355
- return {
4356
- ok: false,
4357
- failureCode: "triage_inconsistent",
4358
- offendingPath: prdPath,
4359
- message: prd.message ?? "Invalid PRD artifact"
4360
- };
4361
- }
4362
- if (issuePaths.length === 0) {
4363
- return { ok: true };
4364
- }
4365
- const issues = [];
4366
- for (const issuePath of issuePaths) {
4367
- const issue = readLocalArtifact(
4368
- issuePath,
4369
- "triage_inconsistent"
4370
- );
4371
- if (!issue.ok || !issue.data) {
4372
- return {
4373
- ok: false,
4374
- failureCode: "triage_inconsistent",
4375
- offendingPath: issuePath,
4376
- message: issue.message ?? "Invalid Issue artifact"
4377
- };
4378
- }
4379
- issues.push({ path: issuePath, data: issue.data });
4380
- }
4381
- const issuesById = new Map(issues.map((i) => [i.data.id, i]));
4382
- const needsTriage = issues.filter((i) => i.data.status === "needs-triage");
4383
- if (needsTriage.length > 0) {
4384
- return {
4385
- ok: false,
4386
- failureCode: "triage_inconsistent",
4387
- message: `Parent PRD cannot prepare: child Issue(s) still in needs-triage: ${needsTriage.map((i) => i.data.id).join(", ")}`
4388
- };
4389
- }
4390
- for (const issue of issues.filter((i) => i.data.status === "blocked")) {
4391
- const deps = issue.data.dependencyIssueIds ?? [];
4392
- const blockedReason = issue.data.blockedReason;
4393
- const readyForHumanReason = issue.data.readyForHumanReason;
4394
- if (deps.length === 0 && blockedReason == null && readyForHumanReason == null) {
4395
- return {
4396
- ok: false,
4397
- failureCode: "triage_inconsistent",
4398
- offendingPath: issue.path,
4399
- message: `Blocked Issue ${issue.data.id} requires at least one blocker source: dependencyIssueIds, blockedReason, or readyForHumanReason`
4400
- };
4401
- }
4402
- }
4403
- for (const issue of issues.filter(
4404
- (i) => i.data.status === "ready-for-human"
4405
- )) {
4406
- if (issue.data.readyForHumanReason == null) {
4407
- return {
4408
- ok: false,
4409
- failureCode: "triage_inconsistent",
4410
- offendingPath: issue.path,
4411
- message: `ready-for-human Issue ${issue.data.id} must have a readyForHumanReason`
4412
- };
4413
- }
4414
- }
4415
- for (const issue of issues.filter((i) => i.data.status === "wontfix")) {
4416
- if (issue.data.blockedReason == null) {
4417
- return {
4418
- ok: false,
4419
- failureCode: "triage_inconsistent",
4420
- offendingPath: issue.path,
4421
- message: `wontfix Issue ${issue.data.id} must have a blockedReason`
4422
- };
4423
- }
4424
- }
4425
- const blockedCount = issues.filter((i) => i.data.status === "blocked").length;
4426
- if (blockedCount > 0) {
4427
- const readyForAgentCount = issues.filter(
4428
- (i) => i.data.status === "ready-for-agent"
4429
- ).length;
4430
- if (readyForAgentCount === 0) {
4431
- return {
4432
- ok: false,
4433
- failureCode: "triage_inconsistent",
4434
- message: "At least one child Issue must be ready-for-agent when blocked children exist"
4435
- };
4436
- }
4437
- }
4438
- for (const issue of issues) {
4439
- const labels = issue.data.labels ?? [];
4440
- const status = issue.data.status;
4441
- const triageLabel = labels.find(
4442
- (l) => VALID_ISSUE_TRIAGE_LABELS.includes(l)
4443
- );
4444
- if (triageLabel && status !== "running" && status !== "complete" && triageLabel !== status) {
4445
- return {
4446
- ok: false,
4447
- failureCode: "triage_inconsistent",
4448
- offendingPath: issue.path,
4449
- message: `Issue ${issue.data.id} has status "${status}" but triage-state label "${triageLabel}"`
4450
- };
4451
- }
4452
- }
4453
- for (const issue of issues) {
4454
- const labels = issue.data.labels ?? [];
4455
- const triageLabels = labels.filter(
4456
- (l) => VALID_ISSUE_TRIAGE_LABELS.includes(l)
4457
- );
4458
- if (triageLabels.length !== 1) {
4459
- return {
4460
- ok: false,
4461
- failureCode: "triage_inconsistent",
4462
- offendingPath: issue.path,
4463
- message: `Issue ${issue.data.id} must have exactly one triage-state label, got ${triageLabels.length}`
4464
- };
4465
- }
4466
- }
4467
- for (const issue of issues.filter(
4468
- (i) => i.data.status === "ready-for-agent"
4469
- )) {
4470
- const deps = issue.data.dependencyIssueIds ?? [];
4471
- for (const depId of deps) {
4472
- const dep = issuesById.get(depId);
4473
- if (dep && dep.data.status !== "complete") {
4474
- return {
4475
- ok: false,
4476
- failureCode: "triage_inconsistent",
4477
- offendingPath: issue.path,
4478
- message: `ready-for-agent Issue ${issue.data.id} has unresolved dependency ${depId} (status: ${dep.data.status})`
4479
- };
4480
- }
4481
- }
4482
- }
4483
- return { ok: true };
4484
- }
4485
-
4486
- // commands/issue-run.ts
4487
- import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
4488
- import { isAbsolute as isAbsolute5, join as join16 } from "path";
4489
-
4490
- // pr/templates.ts
4491
- init_common();
4492
- function renderBranchName(template, issue) {
4493
- return renderTemplate(template, issue);
4494
- }
4495
- function renderTemplate(template, issue) {
4496
- const issueSlug = slugify(issue.title);
4497
- return template.replace(/\{\{issue\.number\}\}/g, String(issue.number)).replace(/\{\{issue\.title\}\}/g, issue.title).replace(/\{\{issue\.body\}\}/g, issue.body).replace(/\{\{issue\.slug\}\}/g, issueSlug).replace(/\{\{issue\.state\}\}/g, issue.state);
4498
- }
4499
-
4500
- // commands/issue-run.ts
4501
- init_common();
4502
-
4503
- // commands/base-refresh.ts
4504
- init_common();
4505
- async function isIssueBranchStale(worktreePath, baseBranch, logger) {
4506
- try {
4507
- await execCapture(
4508
- "git",
4509
- ["merge-base", "--is-ancestor", baseBranch, "HEAD"],
4510
- {
4511
- cwd: worktreePath,
4512
- logger,
4513
- label: "git merge-base --is-ancestor"
4514
- }
4515
- );
4516
- return false;
4517
- } catch {
4518
- return true;
4519
- }
4520
- }
4521
- async function refreshStaleIssueBranch(options) {
4522
- const {
4523
- worktreePath,
4524
- baseBranch,
4525
- localGitBaseRef,
4526
- logger,
4527
- prNumber,
4528
- prState
4529
- } = options;
4530
- const stale = await isIssueBranchStale(worktreePath, localGitBaseRef, logger);
4531
- if (!stale) {
4532
- return { status: "skipped-current" };
4533
- }
4534
- if (prNumber !== void 0 && prState !== void 0) {
4535
- return {
4536
- status: "refused-published-history",
4537
- prNumber,
4538
- prState
4539
- };
4540
- }
4541
- try {
4542
- await execCapture("git", ["rebase", "--autostash", localGitBaseRef], {
4543
- cwd: worktreePath,
4544
- logger,
4545
- label: "git rebase --autostash"
4546
- });
4547
- return { status: "refreshed" };
4548
- } catch (error) {
4549
- let conflictedPaths = [];
4550
- try {
4551
- const statusResult = await execCapture("git", ["status", "--porcelain"], {
4552
- cwd: worktreePath,
4553
- logger,
4554
- label: "git status"
4555
- });
4556
- conflictedPaths = statusResult.stdout.split("\n").filter((line) => /^(AA|DD|UU|AU|UA|DU|UD)\s/.test(line)).map((line) => line.slice(3).trim()).filter(Boolean);
4557
- } catch {
4558
- }
4559
- return {
4560
- status: "conflicted",
4561
- message: error instanceof Error ? error.message : String(error),
4562
- conflictedPaths
4563
- };
4564
- }
4565
- }
4566
- function invalidateAfterBaseRefresh(state) {
4567
- return {
4568
- issueNumber: state.issueNumber,
4569
- targetName: state.targetName,
4570
- branchName: state.branchName,
4571
- baseBranch: state.baseBranch,
4572
- createdAt: state.createdAt,
4573
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4574
- completedStages: {
4575
- builder: state.completedStages.builder
4576
- },
4577
- review: {
4578
- lifetimeIterations: 0
4579
- }
4580
- };
4581
- }
4582
-
4583
- // failure-resolution/effect-runtime.ts
4584
- import { Effect as Effect4 } from "effect";
4585
-
4586
- // shared/effect-runtime.ts
4587
- import { Effect as Effect3, Exit } from "effect";
4588
- import { UnknownException } from "effect/Cause";
4589
- var initialized = false;
4590
- function initializeEffectRuntime() {
4591
- if (initialized) return;
4592
- initialized = true;
4593
- }
4594
- function runEffect(program) {
4595
- ensureEffectRuntime();
4596
- return Effect3.runPromiseExit(program);
4597
- }
4598
- function ensureEffectRuntime() {
4599
- if (!initialized) {
4600
- initializeEffectRuntime();
4601
- }
4602
- }
4603
- function unwrapError(error) {
4604
- if (error instanceof UnknownException && error.error !== void 0) {
4605
- return error.error;
3828
+ }
3829
+ function unwrapError(error) {
3830
+ if (error instanceof UnknownException && error.error !== void 0) {
3831
+ return error.error;
4606
3832
  }
4607
3833
  return error;
4608
3834
  }
@@ -4621,15 +3847,15 @@ function runEffectAndMapExit(program) {
4621
3847
 
4622
3848
  // shared/attempt-log.ts
4623
3849
  import { appendFileSync, existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "fs";
4624
- import { dirname as dirname4, join as join8 } from "path";
3850
+ import { dirname as dirname4, join as join7 } from "path";
4625
3851
  var ATTEMPT_LOG_PATH = ".pourkit/attempt-log.jsonl";
4626
3852
  function writeAttemptLog(worktreePath, entry) {
4627
- const logPath = join8(worktreePath, ATTEMPT_LOG_PATH);
3853
+ const logPath = join7(worktreePath, ATTEMPT_LOG_PATH);
4628
3854
  mkdirSync6(dirname4(logPath), { recursive: true });
4629
3855
  appendFileSync(logPath, JSON.stringify(entry) + "\n", "utf-8");
4630
3856
  }
4631
3857
  function readAttemptLog(worktreePath) {
4632
- const logPath = join8(worktreePath, ATTEMPT_LOG_PATH);
3858
+ const logPath = join7(worktreePath, ATTEMPT_LOG_PATH);
4633
3859
  if (!existsSync8(logPath)) {
4634
3860
  return [];
4635
3861
  }
@@ -4753,12 +3979,12 @@ async function runBaseRefreshAttempt(options) {
4753
3979
 
4754
3980
  // commands/conflict-resolution.ts
4755
3981
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
4756
- import { join as join9 } from "path";
3982
+ import { join as join8 } from "path";
4757
3983
  init_common();
4758
3984
  var CONFLICT_MARKER_PATTERN2 = /<<<<<<<|=======|>>>>>>>/m;
4759
3985
  async function hasUnresolvedConflictMarkers(worktreePath, files) {
4760
3986
  for (const file of files) {
4761
- const filePath = join9(worktreePath, file);
3987
+ const filePath = join8(worktreePath, file);
4762
3988
  try {
4763
3989
  const content = readFileSync9(filePath, "utf-8");
4764
3990
  if (CONFLICT_MARKER_PATTERN2.test(content)) {
@@ -5092,7 +4318,7 @@ async function prepareSerenaForTarget(options) {
5092
4318
 
5093
4319
  // failure-resolution/failure-resolution-agent.ts
5094
4320
  import { readFileSync as readFileSync10 } from "fs";
5095
- import { join as join10 } from "path";
4321
+ import { join as join9 } from "path";
5096
4322
 
5097
4323
  // failure-resolution/recovery-policy.ts
5098
4324
  function isSecuritySensitiveFailure(failure) {
@@ -5168,7 +4394,7 @@ async function runFailureResolutionAgent(options) {
5168
4394
  } = options;
5169
4395
  const frConfig = target.strategy.failureResolution;
5170
4396
  const artifactPath = packet.artifactTarget;
5171
- const fullArtifactPath = join10(worktreePath, artifactPath);
4397
+ const fullArtifactPath = join9(worktreePath, artifactPath);
5172
4398
  const fingerprint = computeFailureFingerprint(packet.stageName, failure._tag);
5173
4399
  const prompt = [
5174
4400
  `# Failure Resolution: ${packet.failureType}`,
@@ -5339,12 +4565,12 @@ async function writeRecoveryAttempt(worktreePath, outcome, fingerprint, summary,
5339
4565
  }
5340
4566
 
5341
4567
  // commands/pr-description-agent.ts
5342
- import { join as join12 } from "path";
4568
+ import { join as join11 } from "path";
5343
4569
  import { readFileSync as readFileSync11 } from "fs";
5344
4570
 
5345
4571
  // pr/pr-description-context.ts
5346
4572
  init_common();
5347
- import { join as join11 } from "path";
4573
+ import { join as join10 } from "path";
5348
4574
  import { readFile } from "fs/promises";
5349
4575
  import { Effect as Effect5 } from "effect";
5350
4576
  function collectFinalizerContextEffect(options) {
@@ -5409,7 +4635,7 @@ function remoteTargetBase(targetBase) {
5409
4635
  return targetBase.includes("/") ? targetBase : `origin/${targetBase}`;
5410
4636
  }
5411
4637
  function buildFinalizerPrompt(context, promptTemplate) {
5412
- const artifactPathInWorktree = join11(
4638
+ const artifactPathInWorktree = join10(
5413
4639
  ".pourkit",
5414
4640
  ".tmp",
5415
4641
  "finalizer",
@@ -5479,13 +4705,13 @@ function bridgeExecutionProvider2(ep) {
5479
4705
  }
5480
4706
  function runFinalizerAgent(options) {
5481
4707
  const { executionProvider } = options;
5482
- const artifactPathInWorktree = join12(
4708
+ const artifactPathInWorktree = join11(
5483
4709
  ".pourkit",
5484
4710
  ".tmp",
5485
4711
  "finalizer",
5486
4712
  "agent-output.md"
5487
4713
  );
5488
- const artifactPath = join12(options.worktreePath, artifactPathInWorktree);
4714
+ const artifactPath = join11(options.worktreePath, artifactPathInWorktree);
5489
4715
  const program = Effect6.gen(function* () {
5490
4716
  const fs = yield* FileSystem;
5491
4717
  const context = yield* collectFinalizerContextEffect({
@@ -5547,7 +4773,7 @@ function runFinalizerAgent(options) {
5547
4773
  );
5548
4774
  }
5549
4775
  function runPrDescriptionFinalizerCore(options) {
5550
- const artifactPath = join12(
4776
+ const artifactPath = join11(
5551
4777
  options.worktreePath,
5552
4778
  options.artifactPathInWorktree
5553
4779
  );
@@ -5656,300 +4882,12 @@ function loadFinalizerPromptEffect(repoRoot2, promptTemplate, fs) {
5656
4882
  }
5657
4883
  function persistGeneratedArtifactEffect(worktreePath, output, fs) {
5658
4884
  return Effect6.gen(function* () {
5659
- const dir = join12(worktreePath, ".pourkit", ".tmp", "finalizer");
4885
+ const dir = join11(worktreePath, ".pourkit", ".tmp", "finalizer");
5660
4886
  yield* fs.mkdir(dir).pipe(Effect6.catchAll(() => Effect6.void));
5661
- yield* fs.writeFile(join12(dir, "generated.md"), output).pipe(Effect6.catchAll(() => Effect6.void));
4887
+ yield* fs.writeFile(join11(dir, "generated.md"), output).pipe(Effect6.catchAll(() => Effect6.void));
5662
4888
  });
5663
4889
  }
5664
4890
 
5665
- // prd-run/local-merge-coordinator.ts
5666
- import { execFileSync as execFileSync2 } from "child_process";
5667
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "fs";
5668
- import { join as join13 } from "path";
5669
-
5670
- // prd-run/local-branches.ts
5671
- import { execFileSync, spawnSync as spawnSync2 } from "child_process";
5672
- function getLocalPrdBranchName(prdId) {
5673
- return `local/${prdId}`;
5674
- }
5675
- function materializeLocalPrdBranch(prdId, startBaseCommit, repoRoot2) {
5676
- const branch = getLocalPrdBranchName(prdId);
5677
- const root = repoRoot2 ?? process.cwd();
5678
- const branchExists = (() => {
5679
- try {
5680
- return spawnSync2("git", ["rev-parse", "--verify", "--quiet", branch], {
5681
- cwd: root,
5682
- encoding: "utf8",
5683
- stdio: "pipe"
5684
- }).status === 0;
5685
- } catch {
5686
- return false;
5687
- }
5688
- })();
5689
- if (branchExists) {
5690
- const currentCommit = spawnSync2("git", ["rev-parse", branch], {
5691
- cwd: root,
5692
- encoding: "utf8",
5693
- stdio: "pipe"
5694
- }).stdout?.toString?.().trim() ?? "";
5695
- if (currentCommit !== startBaseCommit) {
5696
- return {
5697
- ok: false,
5698
- failureCode: "branch_commit_mismatch",
5699
- message: `Local PRD branch ${branch} exists at commit ${currentCommit} but expected commit ${startBaseCommit}. The branch has diverged from the start base. To resolve, delete the local branch and rerun start, or manually reset it to the expected commit.`
5700
- };
5701
- }
5702
- return {
5703
- ok: true,
5704
- created: false
5705
- };
5706
- }
5707
- const branchResult = spawnSync2("git", ["branch", branch, startBaseCommit], {
5708
- cwd: root,
5709
- encoding: "utf8",
5710
- stdio: "pipe"
5711
- });
5712
- if (branchResult.status !== 0) {
5713
- const stderr = branchResult.stderr?.toString?.() ?? "unknown error";
5714
- return {
5715
- ok: false,
5716
- failureCode: "branch_creation_failed",
5717
- message: `Failed to create local PRD branch ${branch} at ${startBaseCommit}: ${stderr}`
5718
- };
5719
- }
5720
- return { ok: true, created: true };
5721
- }
5722
- var PROTECTED_BRANCHES = /* @__PURE__ */ new Set(["dev", "next", "main"]);
5723
- var LOCAL_BRANCH_PATTERN = /^local\/PRD-\d{4}(\/(I-\d{2}(-[a-z0-9-]+)?)?)?$/;
5724
- function validateLocalBranchName(name) {
5725
- if (!name || name.length === 0) {
5726
- return {
5727
- ok: false,
5728
- failureCode: "invalid_format",
5729
- message: "Branch name is empty."
5730
- };
5731
- }
5732
- if (isProtectedBranch(name)) {
5733
- return {
5734
- ok: false,
5735
- failureCode: "protected_branch",
5736
- message: `Branch "${name}" is protected.`
5737
- };
5738
- }
5739
- if (!LOCAL_BRANCH_PATTERN.test(name)) {
5740
- return {
5741
- ok: false,
5742
- failureCode: "invalid_format",
5743
- message: `Branch "${name}" does not match the local branch pattern.`
5744
- };
5745
- }
5746
- return { ok: true };
5747
- }
5748
- function isProtectedBranch(name) {
5749
- return PROTECTED_BRANCHES.has(name);
5750
- }
5751
-
5752
- // prd-run/local-merge-coordinator.ts
5753
- function getLocalStorePath(repoRoot2, prdId) {
5754
- return join13(repoRoot2, ".pourkit", "local-prd-runs", prdId);
5755
- }
5756
- function getMergeReceiptPath(repoRoot2, prdId, issueId) {
5757
- return join13(
5758
- getLocalStorePath(repoRoot2, prdId),
5759
- "merge-receipts",
5760
- `${issueId}.json`
5761
- );
5762
- }
5763
- function getIssueArtifactPath(repoRoot2, prdId, issueId) {
5764
- return join13(getLocalStorePath(repoRoot2, prdId), "issues", `${issueId}.json`);
5765
- }
5766
- function readIssueBranchName(repoRoot2, prdId, issueId) {
5767
- const issuePath = getIssueArtifactPath(repoRoot2, prdId, issueId);
5768
- if (!existsSync10(issuePath)) return null;
5769
- try {
5770
- const content = readFileSync12(issuePath, "utf-8");
5771
- const parsed = JSON.parse(content);
5772
- return typeof parsed.branchName === "string" && parsed.branchName ? parsed.branchName : null;
5773
- } catch {
5774
- return null;
5775
- }
5776
- }
5777
- async function hasLocalIssueMergeReceipt(prdId, issueId, repoRoot2) {
5778
- const root = repoRoot2 ?? process.cwd();
5779
- const receiptPath = getMergeReceiptPath(root, prdId, issueId);
5780
- if (!existsSync10(receiptPath)) return null;
5781
- try {
5782
- const content = readFileSync12(receiptPath, "utf-8");
5783
- const parsed = JSON.parse(content);
5784
- if (typeof parsed.prdId === "string" && typeof parsed.issueId === "string" && typeof parsed.stage === "string" && typeof parsed.sourceBranch === "string" && typeof parsed.localPrdBranch === "string" && typeof parsed.mergeCommit === "string" && typeof parsed.completedAt === "string") {
5785
- return parsed;
5786
- }
5787
- return null;
5788
- } catch {
5789
- return null;
5790
- }
5791
- }
5792
- async function squashMergeLocalIssue(prdId, issueId, input, repoRoot2) {
5793
- const root = repoRoot2 ?? process.cwd();
5794
- const receiptPath = getMergeReceiptPath(root, prdId, issueId);
5795
- if (existsSync10(receiptPath)) {
5796
- try {
5797
- const existing = JSON.parse(
5798
- readFileSync12(receiptPath, "utf-8")
5799
- );
5800
- if (existing.prdId === prdId && existing.issueId === issueId && existing.mergeCommit) {
5801
- return {
5802
- ok: false,
5803
- failureCode: "already_merged",
5804
- repairGuidance: `Issue ${issueId} was already merged into ${existing.localPrdBranch}. Merge commit: ${existing.mergeCommit}`
5805
- };
5806
- }
5807
- return {
5808
- ok: false,
5809
- failureCode: "invalid_receipt",
5810
- repairGuidance: `Merge receipt for ${issueId} belongs to different prd/issue. Remove it manually: ${receiptPath}`
5811
- };
5812
- } catch {
5813
- return {
5814
- ok: false,
5815
- failureCode: "invalid_receipt",
5816
- repairGuidance: `Merge receipt for ${issueId} is corrupted. Remove it manually: ${receiptPath}`
5817
- };
5818
- }
5819
- }
5820
- const sourceBranch = input?.sourceBranch ?? readIssueBranchName(root, prdId, issueId);
5821
- if (!sourceBranch) {
5822
- return {
5823
- ok: false,
5824
- failureCode: "not_found",
5825
- repairGuidance: `No source branch found for issue ${issueId} under PRD ${prdId}. Ensure the issue artifact exists with a valid branchName field.`
5826
- };
5827
- }
5828
- try {
5829
- execFileSync2(
5830
- "git",
5831
- ["show-ref", "--verify", "--quiet", `refs/heads/${sourceBranch}`],
5832
- { cwd: root, encoding: "utf8", stdio: "pipe" }
5833
- );
5834
- } catch {
5835
- return {
5836
- ok: false,
5837
- failureCode: "not_found",
5838
- repairGuidance: `Source branch "${sourceBranch}" does not exist locally. Check that the branch was created and not deleted.`
5839
- };
5840
- }
5841
- const targetBranch = getLocalPrdBranchName(prdId);
5842
- try {
5843
- execFileSync2(
5844
- "git",
5845
- ["show-ref", "--verify", "--quiet", `refs/heads/${targetBranch}`],
5846
- { cwd: root, encoding: "utf8", stdio: "pipe" }
5847
- );
5848
- } catch {
5849
- return {
5850
- ok: false,
5851
- failureCode: "not_found",
5852
- repairGuidance: `Local PRD branch "${targetBranch}" does not exist. Run \`prd-run start\` first to create it.`
5853
- };
5854
- }
5855
- try {
5856
- execFileSync2("git", ["checkout", targetBranch], {
5857
- cwd: root,
5858
- encoding: "utf8",
5859
- stdio: "pipe"
5860
- });
5861
- let preMergeHead;
5862
- try {
5863
- preMergeHead = execFileSync2("git", ["rev-parse", "HEAD"], {
5864
- cwd: root,
5865
- encoding: "utf8",
5866
- stdio: "pipe"
5867
- }).trim();
5868
- } catch {
5869
- return {
5870
- ok: false,
5871
- failureCode: "merge_error",
5872
- repairGuidance: "Failed to read current HEAD before merge."
5873
- };
5874
- }
5875
- execFileSync2("git", ["merge", "--squash", sourceBranch], {
5876
- cwd: root,
5877
- encoding: "utf8",
5878
- stdio: "pipe"
5879
- });
5880
- if (input) {
5881
- execFileSync2(
5882
- "git",
5883
- ["commit", "-m", input.finalizerTitle, "-m", input.finalizerBody],
5884
- { cwd: root, encoding: "utf8", stdio: "pipe" }
5885
- );
5886
- } else {
5887
- execFileSync2(
5888
- "git",
5889
- ["commit", "-m", `Squash merge ${sourceBranch} into ${targetBranch}`],
5890
- { cwd: root, encoding: "utf8", stdio: "pipe" }
5891
- );
5892
- }
5893
- const revParseResult = execFileSync2("git", ["rev-parse", "HEAD"], {
5894
- cwd: root,
5895
- encoding: "utf8",
5896
- stdio: "pipe"
5897
- });
5898
- const mergeCommit = revParseResult.trim();
5899
- const receipt = {
5900
- prdId,
5901
- issueId,
5902
- stage: "child-issue",
5903
- sourceBranch,
5904
- localPrdBranch: targetBranch,
5905
- mergeCommit,
5906
- finalizerArtifactPath: input?.finalizerArtifactPath ?? "",
5907
- completedAt: (/* @__PURE__ */ new Date()).toISOString()
5908
- };
5909
- try {
5910
- const receiptsDir = join13(
5911
- root,
5912
- ".pourkit",
5913
- "local-prd-runs",
5914
- prdId,
5915
- "merge-receipts"
5916
- );
5917
- mkdirSync7(receiptsDir, { recursive: true });
5918
- writeFileSync4(receiptPath, JSON.stringify(receipt, null, 2), "utf-8");
5919
- } catch {
5920
- try {
5921
- execFileSync2("git", ["reset", "--hard", preMergeHead], {
5922
- cwd: root,
5923
- encoding: "utf8",
5924
- stdio: "pipe"
5925
- });
5926
- } catch {
5927
- }
5928
- return {
5929
- ok: false,
5930
- failureCode: "receipt_error",
5931
- repairGuidance: "Failed to write merge receipt. Check disk space and permissions on .pourkit/local-prd-runs/. The merge commit has been rolled back."
5932
- };
5933
- }
5934
- return { ok: true, receipt };
5935
- } catch (error) {
5936
- const message = error instanceof Error ? error.message : String(error);
5937
- if (message.toLowerCase().includes("conflict")) {
5938
- return {
5939
- ok: false,
5940
- failureCode: "conflict",
5941
- repairGuidance: "Merge conflict during squash. Resolve conflicts in the working tree, then retry."
5942
- };
5943
- }
5944
- const stderr = error instanceof Error && "stderr" in error ? error.stderr : void 0;
5945
- return {
5946
- ok: false,
5947
- failureCode: "merge_error",
5948
- repairGuidance: stderr ? `Merge failed: ${stderr}` : `Merge failed: ${message}`
5949
- };
5950
- }
5951
- }
5952
-
5953
4891
  // pr/pr-body.ts
5954
4892
  import { readFile as readFile2 } from "fs/promises";
5955
4893
  var DEFAULT_MANUAL_PR_BODY = `## Summary
@@ -6020,8 +4958,8 @@ function extractClosingRefs(body) {
6020
4958
 
6021
4959
  // issues/github-issue-publication.ts
6022
4960
  init_common();
6023
- import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
6024
- import { isAbsolute as isAbsolute4, join as join14 } from "path";
4961
+ import { existsSync as existsSync10, readFileSync as readFileSync12 } from "fs";
4962
+ import { isAbsolute as isAbsolute4, join as join12 } from "path";
6025
4963
 
6026
4964
  // issues/issue-transitions.ts
6027
4965
  function createIssueTransitions(deps, labels) {
@@ -6496,11 +5434,11 @@ function readIssueFinalReviewArtifact(worktreeState, worktreePath) {
6496
5434
  if (!configuredPath) {
6497
5435
  return null;
6498
5436
  }
6499
- const artifactPath = isAbsolute4(configuredPath) ? configuredPath : join14(worktreePath, configuredPath);
6500
- if (!existsSync11(artifactPath)) return null;
5437
+ const artifactPath = isAbsolute4(configuredPath) ? configuredPath : join12(worktreePath, configuredPath);
5438
+ if (!existsSync10(artifactPath)) return null;
6501
5439
  let parsed;
6502
5440
  try {
6503
- parsed = JSON.parse(readFileSync13(artifactPath, "utf-8"));
5441
+ parsed = JSON.parse(readFileSync12(artifactPath, "utf-8"));
6504
5442
  } catch {
6505
5443
  return null;
6506
5444
  }
@@ -6755,9 +5693,9 @@ function isAllowedSecretPlaceholder(value) {
6755
5693
  }
6756
5694
 
6757
5695
  // commands/issue-final-review-agent.ts
6758
- import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
6759
- import { join as join15 } from "path";
6760
- var ISSUE_FINAL_REVIEW_ARTIFACT_PATH = join15(
5696
+ import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
5697
+ import { join as join13 } from "path";
5698
+ var ISSUE_FINAL_REVIEW_ARTIFACT_PATH = join13(
6761
5699
  ".pourkit",
6762
5700
  ".tmp",
6763
5701
  "issue-final-review",
@@ -6775,7 +5713,7 @@ async function runIssueFinalReviewAgent(options) {
6775
5713
  logger
6776
5714
  } = options;
6777
5715
  const artifactPathInWorktree = ISSUE_FINAL_REVIEW_ARTIFACT_PATH;
6778
- const artifactPath = join15(worktreePath, artifactPathInWorktree);
5716
+ const artifactPath = join13(worktreePath, artifactPathInWorktree);
6779
5717
  const strategy = target.strategy;
6780
5718
  const issueFinalReview = strategy.issueFinalReview;
6781
5719
  const agent = issueFinalReview;
@@ -6880,7 +5818,7 @@ function extractChangedPaths(parsed) {
6880
5818
  function loadIssueFinalReviewPrompt(options) {
6881
5819
  const { repoRoot: repoRoot2, promptTemplate, validationCommand } = options;
6882
5820
  const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
6883
- const promptBody = existsSync12(promptPath) ? readFileSync14(promptPath, "utf-8") : promptTemplate;
5821
+ const promptBody = existsSync11(promptPath) ? readFileSync13(promptPath, "utf-8") : promptTemplate;
6884
5822
  return appendProtectedWorkGuidance(`${promptBody}
6885
5823
 
6886
5824
  ## Shared Run Context
@@ -6991,7 +5929,7 @@ async function advanceIssueFinalReview(options) {
6991
5929
  "Issue Final Review state is incomplete: missing artifactPath"
6992
5930
  );
6993
5931
  }
6994
- const artifactPath = isAbsolute5(ifrFromState.artifactPath) ? ifrFromState.artifactPath : join16(worktreePath, ifrFromState.artifactPath);
5932
+ const artifactPath = isAbsolute5(ifrFromState.artifactPath) ? ifrFromState.artifactPath : join14(worktreePath, ifrFromState.artifactPath);
6995
5933
  const validation = validateAgentArtifact({
6996
5934
  kind: "issue-final-review",
6997
5935
  artifactPath,
@@ -7396,7 +6334,6 @@ async function completeIssueRun(options) {
7396
6334
  let prTitle = issue.title;
7397
6335
  let prBody;
7398
6336
  let finalizerResult;
7399
- const isLocalModeForFinalizer = options.prdRunMode?.mode === "local";
7400
6337
  const finalizerFromState = worktreeState?.finalizer?.completed ? worktreeState.finalizer : null;
7401
6338
  if (finalizerFromState) {
7402
6339
  try {
@@ -7404,12 +6341,12 @@ async function completeIssueRun(options) {
7404
6341
  prTitle = finalizerFromState.title;
7405
6342
  prBody = finalizerFromState.body;
7406
6343
  } else if (finalizerFromState.artifactPath) {
7407
- if (!existsSync13(finalizerFromState.artifactPath)) {
6344
+ if (!existsSync12(finalizerFromState.artifactPath)) {
7408
6345
  throw new FinalizerFailure({
7409
6346
  message: `Finalizer artifact missing at ${finalizerFromState.artifactPath}`
7410
6347
  });
7411
6348
  }
7412
- const artifactContent = readFileSync15(
6349
+ const artifactContent = readFileSync14(
7413
6350
  finalizerFromState.artifactPath,
7414
6351
  "utf-8"
7415
6352
  );
@@ -7422,17 +6359,6 @@ async function completeIssueRun(options) {
7422
6359
  });
7423
6360
  }
7424
6361
  } catch (error) {
7425
- if (isLocalModeForFinalizer) {
7426
- return {
7427
- branchName,
7428
- target,
7429
- issue,
7430
- noOp: false,
7431
- mode: "local",
7432
- failureCode: "finalizer_failed",
7433
- repairGuidance: error instanceof Error ? error.message : "Finalizer state is invalid"
7434
- };
7435
- }
7436
6362
  throw error;
7437
6363
  }
7438
6364
  } else {
@@ -7453,17 +6379,6 @@ async function completeIssueRun(options) {
7453
6379
  })
7454
6380
  );
7455
6381
  } catch (error) {
7456
- if (isLocalModeForFinalizer) {
7457
- return {
7458
- branchName,
7459
- target,
7460
- issue,
7461
- noOp: false,
7462
- mode: "local",
7463
- failureCode: "finalizer_failed",
7464
- repairGuidance: error instanceof Error ? error.message : "Finalizer execution failed"
7465
- };
7466
- }
7467
6382
  throw error;
7468
6383
  }
7469
6384
  prTitle = finalizerResult.title;
@@ -7498,150 +6413,25 @@ async function completeIssueRun(options) {
7498
6413
  const finalCommitFromState = worktreeState?.finalCommit?.completed;
7499
6414
  if (!finalCommitFromState) {
7500
6415
  await finalizeWorktreeCommit({
7501
- worktreePath: executionResult.worktreePath,
7502
- baseRef: `origin/${effectiveBaseBranch}`,
7503
- title: prTitle,
7504
- body: finalBody,
7505
- logger
7506
- });
7507
- if (executionResult.worktreePath) {
7508
- const revParse = await execCapture("git", ["rev-parse", "HEAD"], {
7509
- cwd: executionResult.worktreePath,
7510
- logger,
7511
- label: "git rev-parse HEAD"
7512
- });
7513
- updateWorktreeRunState(executionResult.worktreePath, {
7514
- finalCommit: {
7515
- completed: true,
7516
- sha: revParse.stdout.trim()
7517
- }
7518
- });
7519
- }
7520
- }
7521
- const isLocalMode = options.prdRunMode?.mode === "local";
7522
- if (isLocalMode) {
7523
- const parsed = parseStackedIssue(issue.title, issue.body);
7524
- const prdId = parsed.parentRef;
7525
- if (!prdId) {
7526
- return {
7527
- branchName,
7528
- target,
7529
- issue,
7530
- noOp: false,
7531
- mode: "local",
7532
- failureCode: "finalizer_failed",
7533
- repairGuidance: "Local mode requires a PRD reference (## Parent) in the issue body or title. Add the parent PRD reference and retry."
7534
- };
7535
- }
7536
- const finalizerFromWorktreeState = worktreeState?.finalizer;
7537
- if (finalizerFromWorktreeState && !finalizerFromWorktreeState.completed) {
7538
- return {
7539
- branchName,
7540
- target,
7541
- issue,
7542
- noOp: false,
7543
- mode: "local",
7544
- failureCode: "finalizer_failed",
7545
- repairGuidance: "Finalizer did not complete on previous run. Re-run the issue finalizer and try again."
7546
- };
7547
- }
7548
- if (!prTitle || !finalBody) {
7549
- return {
7550
- branchName,
7551
- target,
7552
- issue,
7553
- noOp: false,
7554
- mode: "local",
7555
- failureCode: "finalizer_failed",
7556
- repairGuidance: "Finalizer produced empty title or body. Re-run the issue finalizer and try again."
7557
- };
7558
- }
7559
- const existingReceipt = await hasLocalIssueMergeReceipt(
7560
- prdId,
7561
- `issue-${issueNumber}`,
7562
- ROOT
7563
- );
7564
- if (existingReceipt) {
7565
- return {
7566
- branchName,
7567
- target,
7568
- issue,
7569
- noOp: false,
7570
- mode: "local",
7571
- failureCode: "already_merged",
7572
- localPrdBranch: existingReceipt.localPrdBranch,
7573
- mergeCommit: existingReceipt.mergeCommit,
7574
- receiptPath: join16(
7575
- ROOT,
7576
- ".pourkit",
7577
- "local-prd-runs",
7578
- prdId,
7579
- "merge-receipts",
7580
- `issue-${issueNumber}.json`
7581
- )
7582
- };
7583
- }
7584
- const mergeResult = await squashMergeLocalIssue(
7585
- prdId,
7586
- `issue-${issueNumber}`,
7587
- {
7588
- finalizerTitle: prTitle,
7589
- finalizerBody: finalBody,
7590
- finalizerArtifactPath: worktreeState?.finalizer?.artifactPath ?? "",
7591
- sourceBranch: branchName
7592
- },
7593
- ROOT
7594
- );
7595
- if (!mergeResult.ok) {
7596
- return {
7597
- branchName,
7598
- target,
7599
- issue,
7600
- noOp: false,
7601
- mode: "local",
7602
- failureCode: mergeResult.failureCode,
7603
- repairGuidance: mergeResult.repairGuidance ?? `Local squash-merge failed: ${mergeResult.failureCode}`
7604
- };
7605
- }
7606
- await issueProvider.removeLabel(issueNumber, config.labels.agentInProgress);
7607
- await issueProvider.removeLabel(
7608
- issueNumber,
7609
- config.labels.prOpenAwaitingMerge
7610
- );
7611
- let childCloseSucceeded = false;
7612
- try {
7613
- await issueProvider.closeIssue(issueNumber);
7614
- childCloseSucceeded = true;
7615
- } catch (error) {
7616
- logger.step(
7617
- "warn",
7618
- `Issue #${issueNumber} could not be closed: ${error instanceof Error ? error.message : String(error)}`
7619
- );
7620
- }
7621
- if (childCloseSucceeded) {
7622
- await maybeCloseParentAfterChildCompletion(
7623
- issueProvider,
7624
- issueNumber,
7625
- logger
7626
- );
6416
+ worktreePath: executionResult.worktreePath,
6417
+ baseRef: `origin/${effectiveBaseBranch}`,
6418
+ title: prTitle,
6419
+ body: finalBody,
6420
+ logger
6421
+ });
6422
+ if (executionResult.worktreePath) {
6423
+ const revParse = await execCapture("git", ["rev-parse", "HEAD"], {
6424
+ cwd: executionResult.worktreePath,
6425
+ logger,
6426
+ label: "git rev-parse HEAD"
6427
+ });
6428
+ updateWorktreeRunState(executionResult.worktreePath, {
6429
+ finalCommit: {
6430
+ completed: true,
6431
+ sha: revParse.stdout.trim()
6432
+ }
6433
+ });
7627
6434
  }
7628
- return {
7629
- branchName,
7630
- target,
7631
- issue,
7632
- noOp: false,
7633
- mode: "local",
7634
- localPrdBranch: getLocalPrdBranchName(prdId),
7635
- mergeCommit: mergeResult.receipt.mergeCommit,
7636
- receiptPath: join16(
7637
- ROOT,
7638
- ".pourkit",
7639
- "local-prd-runs",
7640
- prdId,
7641
- "merge-receipts",
7642
- `issue-${issueNumber}.json`
7643
- )
7644
- };
7645
6435
  }
7646
6436
  if (!executionResult.worktreePath) {
7647
6437
  throw new Error(
@@ -8008,7 +6798,7 @@ async function resolveIssueWorktree(root, branchName, baseBranch, logger) {
8008
6798
  return { mode: "new", branchName, baseRef };
8009
6799
  }
8010
6800
  function issueWorktreePath(root, branchName) {
8011
- return join16(root, ".sandcastle", "worktrees", branchName.replace(/\//g, "-"));
6801
+ return join14(root, ".sandcastle", "worktrees", branchName.replace(/\//g, "-"));
8012
6802
  }
8013
6803
  function resolveRegisteredIssueWorktreePath(worktreeListPorcelain, root, branchName) {
8014
6804
  const branchWorktreePath = parseWorktreeListPorcelain(
@@ -8036,7 +6826,7 @@ async function syncTargetBranch(root, baseBranch, logger) {
8036
6826
  }
8037
6827
  function loadBuilderPrompt(repoRoot2, promptTemplate) {
8038
6828
  const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
8039
- const promptBody = existsSync13(promptPath) ? readFileSync15(promptPath, "utf-8") : promptTemplate;
6829
+ const promptBody = existsSync12(promptPath) ? readFileSync14(promptPath, "utf-8") : promptTemplate;
8040
6830
  return appendProtectedWorkGuidance(`${promptBody}
8041
6831
 
8042
6832
  ## Shared Run Context
@@ -8531,18 +7321,17 @@ async function runIssueCreateCommand(args, issueProvider, logger) {
8531
7321
 
8532
7322
  // commands/prd-run.ts
8533
7323
  import { lstatSync, realpathSync } from "fs";
8534
- import { join as join21 } from "path";
7324
+ import { join as join16 } from "path";
8535
7325
 
8536
7326
  // prd-run/state.ts
8537
7327
  import {
8538
- existsSync as existsSync14,
8539
- mkdirSync as mkdirSync8,
8540
- readFileSync as readFileSync16,
8541
- readdirSync as readdirSync4,
8542
- writeFileSync as writeFileSync5
7328
+ existsSync as existsSync13,
7329
+ mkdirSync as mkdirSync7,
7330
+ readFileSync as readFileSync15,
7331
+ readdirSync as readdirSync3,
7332
+ writeFileSync as writeFileSync4
8543
7333
  } from "fs";
8544
- import { mkdir as mkdir4, readFile as readFile4, writeFile } from "fs/promises";
8545
- import { join as join17 } from "path";
7334
+ import { join as join15 } from "path";
8546
7335
  import { z } from "zod";
8547
7336
  var PRD_RUN_STATE_DIR = ".pourkit/prd-runs";
8548
7337
  var PrdRunRecordSchema = z.object({
@@ -8559,11 +7348,9 @@ var PrdRunRecordSchema = z.object({
8559
7348
  "waiting_for_integration",
8560
7349
  "finalizing",
8561
7350
  "final_reviewed",
8562
- "complete",
8563
- "completed_local_branch"
7351
+ "complete"
8564
7352
  ]),
8565
7353
  updatedAt: z.string().min(1),
8566
- mode: z.enum(["github", "local"]).optional(),
8567
7354
  blockedGate: z.enum(["receipt-check", "branch-state", "git", "queue", "final-review"]).optional(),
8568
7355
  targetName: z.string().min(1).optional(),
8569
7356
  prdBranch: z.string().min(1).optional(),
@@ -8633,16 +7420,16 @@ function normalizePrdRunRef(ref) {
8633
7420
  function readPrdRun(repoRoot2, prdRef) {
8634
7421
  const normalized = normalizePrdRunRef(prdRef);
8635
7422
  const recordPath = getRecordPath(repoRoot2, normalized);
8636
- if (!existsSync14(recordPath)) {
7423
+ if (!existsSync13(recordPath)) {
8637
7424
  return { record: null, diagnostics: [] };
8638
7425
  }
8639
7426
  try {
8640
- const raw = JSON.parse(readFileSync16(recordPath, "utf-8"));
7427
+ const raw = JSON.parse(readFileSync15(recordPath, "utf-8"));
8641
7428
  const parsed = normalizeLegacyPrdRunRecord(PrdRunRecordSchema.parse(raw));
8642
7429
  return { record: parsed, diagnostics: [] };
8643
7430
  } catch (error) {
8644
7431
  try {
8645
- const raw = JSON.parse(readFileSync16(recordPath, "utf-8"));
7432
+ const raw = JSON.parse(readFileSync15(recordPath, "utf-8"));
8646
7433
  if (raw && typeof raw === "object" && raw.start && typeof raw.start === "object" && raw.start.startBaseBranch === void 0) {
8647
7434
  return {
8648
7435
  record: raw,
@@ -8663,20 +7450,20 @@ function readPrdRun(repoRoot2, prdRef) {
8663
7450
  }
8664
7451
  }
8665
7452
  function listPrdRuns(repoRoot2) {
8666
- const stateDir = join17(repoRoot2, PRD_RUN_STATE_DIR);
8667
- if (!existsSync14(stateDir)) {
7453
+ const stateDir = join15(repoRoot2, PRD_RUN_STATE_DIR);
7454
+ if (!existsSync13(stateDir)) {
8668
7455
  return { records: [], diagnostics: [] };
8669
7456
  }
8670
7457
  const records = [];
8671
7458
  const diagnostics = [];
8672
- for (const entry of readdirSync4(stateDir, { withFileTypes: true }).sort(
7459
+ for (const entry of readdirSync3(stateDir, { withFileTypes: true }).sort(
8673
7460
  (left, right) => left.name.localeCompare(right.name)
8674
7461
  )) {
8675
7462
  if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
8676
- const recordPath = join17(stateDir, entry.name);
7463
+ const recordPath = join15(stateDir, entry.name);
8677
7464
  try {
8678
7465
  const record = normalizeLegacyPrdRunRecord(
8679
- PrdRunRecordSchema.parse(JSON.parse(readFileSync16(recordPath, "utf-8")))
7466
+ PrdRunRecordSchema.parse(JSON.parse(readFileSync15(recordPath, "utf-8")))
8680
7467
  );
8681
7468
  records.push(record);
8682
7469
  } catch (error) {
@@ -8689,10 +7476,10 @@ function listPrdRuns(repoRoot2) {
8689
7476
  }
8690
7477
  function writePrdRunRecord(repoRoot2, record) {
8691
7478
  const normalized = normalizePrdRunRef(record.prdRef);
8692
- const stateDir = join17(repoRoot2, PRD_RUN_STATE_DIR);
7479
+ const stateDir = join15(repoRoot2, PRD_RUN_STATE_DIR);
8693
7480
  const recordPath = getRecordPath(repoRoot2, normalized);
8694
- mkdirSync8(stateDir, { recursive: true });
8695
- writeFileSync5(
7481
+ mkdirSync7(stateDir, { recursive: true });
7482
+ writeFileSync4(
8696
7483
  recordPath,
8697
7484
  JSON.stringify({ ...record, prdRef: normalized }, null, 2),
8698
7485
  "utf-8"
@@ -8708,43 +7495,8 @@ function normalizeLegacyPrdRunRecord(record) {
8708
7495
  offendingPaths: void 0
8709
7496
  };
8710
7497
  }
8711
- var LocalPrdRunRecordSchema = z.object({
8712
- prdId: z.string().regex(
8713
- /^PRD-\d{4}$/,
8714
- "PRD id must use four-digit format (e.g., PRD-0052)"
8715
- ),
8716
- createdAt: z.string().min(1),
8717
- receipts: z.object({
8718
- start: z.object({
8719
- startedAt: z.string().min(1),
8720
- branch: z.string().min(1),
8721
- baseCommit: z.string().min(1)
8722
- }).strict().optional(),
8723
- queue: z.object({ completedAt: z.string().min(1) }).strict().optional(),
8724
- finalReview: z.object({
8725
- completedAt: z.string().min(1),
8726
- targetName: z.string().optional(),
8727
- prdBranch: z.string().optional(),
8728
- mergeBase: z.string().optional(),
8729
- verdict: z.enum([
8730
- "pass_no_changes",
8731
- "pass_with_retouch",
8732
- "needs_human_review",
8733
- "blocked"
8734
- ]).optional(),
8735
- diagnostics: z.array(z.string()).optional(),
8736
- artifactPath: z.string().optional()
8737
- }).strict().optional(),
8738
- complete: z.object({
8739
- completedAt: z.string().min(1),
8740
- branch: z.string().min(1),
8741
- stages: z.array(z.string())
8742
- }).strict().optional()
8743
- }).strict(),
8744
- metadata: z.record(z.unknown())
8745
- }).strict();
8746
7498
  function getRecordPath(repoRoot2, prdRef) {
8747
- return join17(
7499
+ return join15(
8748
7500
  repoRoot2,
8749
7501
  PRD_RUN_STATE_DIR,
8750
7502
  `${normalizePrdRunRef(prdRef)}.json`
@@ -8752,567 +7504,9 @@ function getRecordPath(repoRoot2, prdRef) {
8752
7504
  }
8753
7505
 
8754
7506
  // prd-run/coordinator.ts
8755
- import { spawnSync as spawnSync3 } from "child_process";
8756
- import { existsSync as existsSync16, readFileSync as readFileSync18 } from "fs";
8757
- import { join as join20 } from "path";
7507
+ import { spawnSync as spawnSync2 } from "child_process";
8758
7508
  import { Match, pipe } from "effect";
8759
7509
 
8760
- // prd-run/local-queue-loop.ts
8761
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "fs";
8762
- import { join as join19 } from "path";
8763
-
8764
- // prd-run/local-artifacts.ts
8765
- import { existsSync as existsSync15 } from "fs";
8766
- import { join as join18 } from "path";
8767
- var REQUIRED_PRD_FIELDS = [
8768
- "schemaVersion",
8769
- "kind",
8770
- "id",
8771
- "title",
8772
- "status",
8773
- "childIssueIds",
8774
- "linkedDecisionIds",
8775
- "reconciliationTarget",
8776
- "bodyMarkdown",
8777
- "bodyContract",
8778
- "receipts",
8779
- "githubProjection"
8780
- ];
8781
- var REQUIRED_ISSUE_FIELDS = [
8782
- "schemaVersion",
8783
- "kind",
8784
- "id",
8785
- "parentPrdId",
8786
- "title",
8787
- "status",
8788
- "labels",
8789
- "dependencyIssueIds",
8790
- "branchName",
8791
- "blockedReason",
8792
- "readyForHumanReason",
8793
- "bodyMarkdown",
8794
- "bodyContract",
8795
- "receipts",
8796
- "githubProjection"
8797
- ];
8798
- function prdStorePath(repoRoot2, prdId) {
8799
- return join18(repoRoot2, ".pourkit", "local-prd-runs", prdId);
8800
- }
8801
- function prdArtifactPath(repoRoot2, prdId) {
8802
- return join18(prdStorePath(repoRoot2, prdId), "prd.json");
8803
- }
8804
- function issueArtifactPath(repoRoot2, prdId, issueId) {
8805
- return join18(prdStorePath(repoRoot2, prdId), "issues", `${issueId}.json`);
8806
- }
8807
- function hasRequiredFields(data, requiredFields) {
8808
- for (const field of requiredFields) {
8809
- if (!(field in data)) {
8810
- return String(field);
8811
- }
8812
- }
8813
- return null;
8814
- }
8815
- async function resolveLocalPrdArtifact(prdId, repoRoot2) {
8816
- const root = repoRoot2 ?? process.cwd();
8817
- const prdPath = prdArtifactPath(root, prdId);
8818
- if (!existsSync15(prdPath)) {
8819
- return {
8820
- ok: false,
8821
- failureCode: "missing_prd_artifact",
8822
- message: `Local PRD artifact not found at ${prdPath}. Create the PRD artifact at .pourkit/local-prd-runs/${prdId}/prd.json using to-prd-local.`
8823
- };
8824
- }
8825
- const result = readLocalArtifact(prdPath);
8826
- if (!result.ok || !result.data) {
8827
- return {
8828
- ok: false,
8829
- failureCode: "invalid_artifact",
8830
- message: `Failed to read or parse PRD artifact at ${prdPath}: ${result.message}`
8831
- };
8832
- }
8833
- const missing = hasRequiredFields(
8834
- result.data,
8835
- REQUIRED_PRD_FIELDS
8836
- );
8837
- if (missing) {
8838
- return {
8839
- ok: false,
8840
- failureCode: "invalid_artifact",
8841
- message: `PRD artifact at ${prdPath} is missing required field: ${missing}`
8842
- };
8843
- }
8844
- if (result.data.kind !== "prd") {
8845
- return {
8846
- ok: false,
8847
- failureCode: "invalid_artifact",
8848
- message: `PRD artifact at ${prdPath} has kind "${result.data.kind}", expected "prd"`
8849
- };
8850
- }
8851
- return { ok: true, data: result.data };
8852
- }
8853
- async function resolveLocalIssueArtifacts(prdId, repoRoot2) {
8854
- const root = repoRoot2 ?? process.cwd();
8855
- const prdResult = await resolveLocalPrdArtifact(prdId, root);
8856
- if (!prdResult.ok) {
8857
- return prdResult;
8858
- }
8859
- const childIssueIds = prdResult.data.childIssueIds;
8860
- const issues = [];
8861
- for (const childId of childIssueIds) {
8862
- const issuePath = issueArtifactPath(root, prdId, childId);
8863
- if (!existsSync15(issuePath)) {
8864
- return {
8865
- ok: false,
8866
- failureCode: "missing_child_issue",
8867
- missingId: childId,
8868
- message: `Child Issue artifact "${childId}" not found at ${issuePath}. Ensure all child issues listed in childIssueIds have corresponding JSON artifacts under .pourkit/local-prd-runs/${prdId}/issues/.`
8869
- };
8870
- }
8871
- const result = readLocalArtifact(issuePath);
8872
- if (!result.ok || !result.data) {
8873
- return {
8874
- ok: false,
8875
- failureCode: "invalid_artifact",
8876
- missingId: childId,
8877
- message: `Failed to read or parse Issue artifact at ${issuePath}: ${result.message}`
8878
- };
8879
- }
8880
- const missing = hasRequiredFields(
8881
- result.data,
8882
- REQUIRED_ISSUE_FIELDS
8883
- );
8884
- if (missing) {
8885
- return {
8886
- ok: false,
8887
- failureCode: "invalid_artifact",
8888
- missingId: childId,
8889
- message: `Issue artifact at ${issuePath} is missing required field: ${missing}`
8890
- };
8891
- }
8892
- if (result.data.kind !== "issue") {
8893
- return {
8894
- ok: false,
8895
- failureCode: "invalid_artifact",
8896
- missingId: childId,
8897
- message: `Issue artifact at ${issuePath} has kind "${result.data.kind}", expected "issue"`
8898
- };
8899
- }
8900
- issues.push(result.data);
8901
- }
8902
- return { ok: true, data: issues };
8903
- }
8904
-
8905
- // prd-run/local-issue-run.ts
8906
- import { execFileSync as execFileSync3 } from "child_process";
8907
- init_common();
8908
- async function createLocalIssueBranch(prdId, issueId, repoRoot2) {
8909
- const root = repoRoot2 ?? process.cwd();
8910
- const issuesResult = await resolveLocalIssueArtifacts(prdId, root);
8911
- if (!issuesResult.ok) {
8912
- throw new Error(
8913
- `Cannot create local issue branch: ${issuesResult.message}`
8914
- );
8915
- }
8916
- const issue = issuesResult.data.find((i) => i.id === issueId);
8917
- if (!issue) {
8918
- throw new Error(`Issue "${issueId}" not found under PRD "${prdId}"`);
8919
- }
8920
- const slug = slugify(issue.title);
8921
- const branchName = `local/${prdId}/${issueId}-${slug}`;
8922
- const validation = validateLocalBranchName(branchName);
8923
- if (!validation.ok) {
8924
- throw new Error(
8925
- `Invalid local issue branch name "${branchName}": ${validation.message}`
8926
- );
8927
- }
8928
- const localPrdBranch = `local/${prdId}`;
8929
- try {
8930
- execFileSync3(
8931
- "git",
8932
- ["show-ref", "--verify", "--quiet", `refs/heads/${localPrdBranch}`],
8933
- {
8934
- cwd: root,
8935
- encoding: "utf8",
8936
- stdio: "pipe"
8937
- }
8938
- );
8939
- } catch {
8940
- throw new Error(
8941
- `Local PRD branch "${localPrdBranch}" does not exist. Create it first.`
8942
- );
8943
- }
8944
- let branchExists = false;
8945
- try {
8946
- execFileSync3(
8947
- "git",
8948
- ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`],
8949
- {
8950
- cwd: root,
8951
- encoding: "utf8",
8952
- stdio: "pipe"
8953
- }
8954
- );
8955
- branchExists = true;
8956
- } catch {
8957
- }
8958
- if (!branchExists) {
8959
- execFileSync3("git", ["checkout", "-b", branchName, localPrdBranch], {
8960
- cwd: root,
8961
- encoding: "utf8",
8962
- stdio: "pipe"
8963
- });
8964
- }
8965
- return { branchName, issue };
8966
- }
8967
- async function runLocalIssue(prdId, issueId, builder, repoRoot2, memory) {
8968
- try {
8969
- const root = repoRoot2 ?? process.cwd();
8970
- const { branchName: branch, issue } = await createLocalIssueBranch(
8971
- prdId,
8972
- issueId,
8973
- root
8974
- );
8975
- if (builder) {
8976
- const result = await builder.execute({
8977
- prdId,
8978
- issueId,
8979
- branch,
8980
- bodyMarkdown: issue.bodyMarkdown,
8981
- ...memory ? { memory } : {}
8982
- });
8983
- if (!result.ok) {
8984
- return {
8985
- ok: false,
8986
- issueId,
8987
- branch,
8988
- failureCode: result.error ?? "Builder execution failed"
8989
- };
8990
- }
8991
- if (!result.issueFinalReviewPassedAt || !result.finalizerTitle || !result.finalizerBody) {
8992
- return {
8993
- ok: false,
8994
- issueId,
8995
- branch,
8996
- failureCode: "Local issue run did not produce Issue Final Review and finalizer receipts"
8997
- };
8998
- }
8999
- return {
9000
- ok: true,
9001
- issueId,
9002
- branch,
9003
- issueFinalReviewPassedAt: result.issueFinalReviewPassedAt,
9004
- finalizerTitle: result.finalizerTitle,
9005
- finalizerBody: result.finalizerBody,
9006
- finalizerArtifactPath: result.finalizerArtifactPath
9007
- };
9008
- }
9009
- return {
9010
- ok: false,
9011
- issueId,
9012
- branch,
9013
- failureCode: "Local issue runner requires Issue Final Review and finalizer lifecycle execution before merge"
9014
- };
9015
- } catch (error) {
9016
- return {
9017
- ok: false,
9018
- issueId,
9019
- branch: "",
9020
- failureCode: error instanceof Error ? error.message : String(error)
9021
- };
9022
- }
9023
- }
9024
-
9025
- // prd-run/local-issue-adapter.ts
9026
- var VALID_TRIAGE_LABELS = /* @__PURE__ */ new Set([
9027
- "needs-triage",
9028
- "ready-for-agent",
9029
- "blocked",
9030
- "ready-for-human",
9031
- "wontfix"
9032
- ]);
9033
- function countTypeLabels(labels) {
9034
- return labels.filter((l) => l.startsWith("type:")).length;
9035
- }
9036
- function countTriageLabels(labels) {
9037
- return labels.filter((l) => VALID_TRIAGE_LABELS.has(l)).length;
9038
- }
9039
- function countCategoryLabels(labels) {
9040
- const triageCount = countTriageLabels(labels);
9041
- const typeCount = countTypeLabels(labels);
9042
- return labels.length - triageCount - typeCount;
9043
- }
9044
- function hasValidLabels(labels) {
9045
- if (countTriageLabels(labels) !== 1) return false;
9046
- if (!labels.includes("ready-for-agent")) return false;
9047
- if (countTypeLabels(labels) !== 1) return false;
9048
- if (countCategoryLabels(labels) !== 1) return false;
9049
- return true;
9050
- }
9051
- function isIssueBlockedByDependencies(issue, issues) {
9052
- const blockers = [];
9053
- for (const depId of issue.dependencyIssueIds) {
9054
- const dep = issues.find((i) => i.id === depId);
9055
- if (!dep || dep.receipts.completedAt === null) {
9056
- blockers.push(depId);
9057
- }
9058
- }
9059
- return blockers;
9060
- }
9061
- async function getRunnableLocalIssues(prdId, repoRoot2) {
9062
- const issuesResult = await resolveLocalIssueArtifacts(prdId, repoRoot2);
9063
- if (!issuesResult.ok) return [];
9064
- const issues = issuesResult.data;
9065
- const runnable = [];
9066
- for (const issue of issues) {
9067
- if (!hasValidLabels(issue.labels)) continue;
9068
- if (issue.status !== "ready-for-agent") continue;
9069
- const blockers = isIssueBlockedByDependencies(issue, issues);
9070
- runnable.push({
9071
- id: issue.id,
9072
- title: issue.title,
9073
- labels: issue.labels,
9074
- blockedBy: blockers.length > 0 ? blockers : void 0
9075
- });
9076
- }
9077
- const filtered = runnable.filter(
9078
- (i) => !i.blockedBy || i.blockedBy.length === 0
9079
- );
9080
- return filtered;
9081
- }
9082
-
9083
- // prd-run/local-queue-loop.ts
9084
- var CHILD_CLEANUP_LABELS = ["agent-in-progress", "pr-open-awaiting-merge"];
9085
- var LOCAL_ISSUE_ID_REGEX = /^I-(\d+)$/i;
9086
- function getIssueArtifactPath2(repoRoot2, prdId, issueId) {
9087
- return join19(
9088
- repoRoot2,
9089
- ".pourkit",
9090
- "local-prd-runs",
9091
- prdId,
9092
- "issues",
9093
- `${issueId}.json`
9094
- );
9095
- }
9096
- function readIssueArtifact(repoRoot2, prdId, issueId) {
9097
- try {
9098
- const content = readFileSync17(
9099
- getIssueArtifactPath2(repoRoot2, prdId, issueId),
9100
- "utf-8"
9101
- );
9102
- return JSON.parse(content);
9103
- } catch {
9104
- return null;
9105
- }
9106
- }
9107
- function writeIssueArtifact(repoRoot2, prdId, issue) {
9108
- writeFileSync6(
9109
- getIssueArtifactPath2(repoRoot2, prdId, issue.id),
9110
- JSON.stringify(issue, null, 2),
9111
- "utf-8"
9112
- );
9113
- }
9114
- function compareLocalIssueIds(a, b) {
9115
- const aMatch = a.match(LOCAL_ISSUE_ID_REGEX);
9116
- const bMatch = b.match(LOCAL_ISSUE_ID_REGEX);
9117
- if (aMatch && bMatch) {
9118
- const aNumber = Number.parseInt(aMatch[1], 10);
9119
- const bNumber = Number.parseInt(bMatch[1], 10);
9120
- if (aNumber !== bNumber) return aNumber - bNumber;
9121
- }
9122
- return a.localeCompare(b);
9123
- }
9124
- async function reconcileLocalBlockedIssues(prdId, repoRoot2) {
9125
- const root = repoRoot2 ?? process.cwd();
9126
- const issuesResult = await resolveLocalIssueArtifacts(prdId, root);
9127
- if (!issuesResult.ok) return;
9128
- const issues = issuesResult.data;
9129
- for (const issue of issues) {
9130
- const isBlocked = issue.status === "blocked";
9131
- if (!isBlocked) continue;
9132
- if (issue.dependencyIssueIds.length === 0) continue;
9133
- const depResults = await Promise.all(
9134
- issue.dependencyIssueIds.map(
9135
- (depId) => hasLocalIssueMergeReceipt(prdId, depId, root)
9136
- )
9137
- );
9138
- if (!depResults.every(Boolean)) continue;
9139
- const updated = readIssueArtifact(root, prdId, issue.id);
9140
- if (!updated) continue;
9141
- updated.blockedReason = null;
9142
- updated.labels = updated.labels.filter((l) => l !== "blocked");
9143
- if (!updated.labels.includes("ready-for-agent")) {
9144
- updated.labels.push("ready-for-agent");
9145
- }
9146
- if (hasValidLabels(updated.labels)) {
9147
- updated.status = "ready-for-agent";
9148
- } else {
9149
- updated.status = "needs-triage";
9150
- updated.labels = updated.labels.filter((l) => l !== "ready-for-agent");
9151
- if (!updated.labels.includes("needs-triage")) {
9152
- updated.labels.push("needs-triage");
9153
- }
9154
- }
9155
- updated.receipts.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9156
- writeIssueArtifact(root, prdId, updated);
9157
- }
9158
- }
9159
- async function cleanupChildGitHubIssue(issue, issueProvider) {
9160
- const issueNumber = issue.githubProjection.issueNumber;
9161
- if (!issueNumber) return { ok: true };
9162
- if (!issueProvider) {
9163
- return {
9164
- ok: false,
9165
- failureCode: "missing_issue_provider",
9166
- repairGuidance: "Issue provider is not available. Cannot close child GitHub Issue or remove labels. Configure a GitHub Issue provider to enable cleanup parity."
9167
- };
9168
- }
9169
- for (const label of CHILD_CLEANUP_LABELS) {
9170
- try {
9171
- await issueProvider.removeLabel(issueNumber, label);
9172
- } catch {
9173
- }
9174
- }
9175
- try {
9176
- await issueProvider.closeIssue(issueNumber);
9177
- } catch {
9178
- }
9179
- return { ok: true };
9180
- }
9181
- async function runLocalQueueLoop(prdId, repoRoot2, issueProvider, memory) {
9182
- const root = repoRoot2 ?? process.cwd();
9183
- const completedIssues = [];
9184
- const blockedIssues = [];
9185
- await reconcileLocalBlockedIssues(prdId, root);
9186
- for (; ; ) {
9187
- const runnable = await getRunnableLocalIssues(prdId, root);
9188
- if (runnable.length === 0) {
9189
- const issuesResult = await resolveLocalIssueArtifacts(prdId, root);
9190
- if (issuesResult.ok) {
9191
- for (const issue2 of issuesResult.data) {
9192
- if (issue2.status === "blocked") {
9193
- blockedIssues.push(issue2.id);
9194
- }
9195
- }
9196
- }
9197
- break;
9198
- }
9199
- const issue = [...runnable].sort(
9200
- (a, b) => compareLocalIssueIds(a.id, b.id)
9201
- )[0];
9202
- const runResult = memory ? await runLocalIssue(prdId, issue.id, void 0, root, memory) : await runLocalIssue(prdId, issue.id, void 0, root);
9203
- if (!runResult.ok) {
9204
- return {
9205
- ok: false,
9206
- completedIssues,
9207
- blockedIssues,
9208
- failureCode: runResult.failureCode ?? `Issue ${issue.id} failed`,
9209
- repairGuidance: `Local issue run failed for ${issue.id}. Check the issue artifact and branch state.`,
9210
- blockedGate: "queue"
9211
- };
9212
- }
9213
- if (!runResult.issueFinalReviewPassedAt || !runResult.finalizerTitle || !runResult.finalizerBody) {
9214
- return {
9215
- ok: false,
9216
- completedIssues,
9217
- blockedIssues,
9218
- failureCode: runResult.failureCode ?? "issue_final_review_not_passed",
9219
- repairGuidance: "Local issue run must complete Issue Final Review and finalizer before local squash merge.",
9220
- blockedGate: "queue"
9221
- };
9222
- }
9223
- const runArtifact = readIssueArtifact(root, prdId, issue.id);
9224
- if (!runArtifact) {
9225
- return {
9226
- ok: false,
9227
- completedIssues,
9228
- blockedIssues,
9229
- failureCode: "missing_issue_artifact",
9230
- repairGuidance: `Issue artifact not found for ${issue.id} under PRD ${prdId}. Ensure the issue exists before running the queue loop.`,
9231
- blockedGate: "queue"
9232
- };
9233
- }
9234
- runArtifact.issueFinalReviewPassedAt = runResult.issueFinalReviewPassedAt;
9235
- runArtifact.receipts.reviewedAt = runResult.issueFinalReviewPassedAt;
9236
- runArtifact.receipts.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9237
- writeIssueArtifact(root, prdId, runArtifact);
9238
- const mergeResult = await squashMergeLocalIssue(
9239
- prdId,
9240
- issue.id,
9241
- {
9242
- finalizerTitle: runResult.finalizerTitle,
9243
- finalizerBody: runResult.finalizerBody,
9244
- finalizerArtifactPath: runResult.finalizerArtifactPath ?? "",
9245
- sourceBranch: runResult.branch
9246
- },
9247
- root
9248
- );
9249
- if (!mergeResult.ok) {
9250
- if (mergeResult.failureCode === "already_merged") {
9251
- const alreadyMergedArtifact = readIssueArtifact(root, prdId, issue.id);
9252
- if (alreadyMergedArtifact) {
9253
- alreadyMergedArtifact.status = "complete";
9254
- alreadyMergedArtifact.receipts.completedAt = mergeResult.receipt?.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
9255
- alreadyMergedArtifact.receipts.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9256
- writeIssueArtifact(root, prdId, alreadyMergedArtifact);
9257
- const cleanupResult = await cleanupChildGitHubIssue(
9258
- alreadyMergedArtifact,
9259
- issueProvider
9260
- );
9261
- if (!cleanupResult.ok) {
9262
- return {
9263
- ok: false,
9264
- completedIssues,
9265
- blockedIssues,
9266
- failureCode: cleanupResult.failureCode ?? "child_cleanup_failed",
9267
- repairGuidance: cleanupResult.repairGuidance ?? `Child GitHub Issue cleanup failed for ${issue.id}.`,
9268
- blockedGate: "queue"
9269
- };
9270
- }
9271
- }
9272
- completedIssues.push(issue.id);
9273
- await reconcileLocalBlockedIssues(prdId, root);
9274
- continue;
9275
- }
9276
- return {
9277
- ok: false,
9278
- completedIssues,
9279
- blockedIssues,
9280
- failureCode: mergeResult.failureCode ?? `Merge of ${issue.id} failed`,
9281
- repairGuidance: mergeResult.repairGuidance,
9282
- blockedGate: "queue"
9283
- };
9284
- }
9285
- const completedArtifact = readIssueArtifact(root, prdId, issue.id);
9286
- if (completedArtifact) {
9287
- completedArtifact.status = "complete";
9288
- completedArtifact.receipts.completedAt = mergeResult.receipt?.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
9289
- completedArtifact.receipts.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9290
- writeIssueArtifact(root, prdId, completedArtifact);
9291
- const cleanupResult = await cleanupChildGitHubIssue(
9292
- completedArtifact,
9293
- issueProvider
9294
- );
9295
- if (!cleanupResult.ok) {
9296
- return {
9297
- ok: false,
9298
- completedIssues,
9299
- blockedIssues,
9300
- failureCode: cleanupResult.failureCode ?? "child_cleanup_failed",
9301
- repairGuidance: cleanupResult.repairGuidance ?? `Child GitHub Issue cleanup failed for ${issue.id}.`,
9302
- blockedGate: "queue"
9303
- };
9304
- }
9305
- }
9306
- completedIssues.push(issue.id);
9307
- await reconcileLocalBlockedIssues(prdId, root);
9308
- }
9309
- return {
9310
- ok: true,
9311
- completedIssues,
9312
- blockedIssues
9313
- };
9314
- }
9315
-
9316
7510
  // commands/queue.ts
9317
7511
  init_common();
9318
7512
  import { Effect as Effect8 } from "effect";
@@ -9670,7 +7864,6 @@ function runOneQueueIssueEffect(options) {
9670
7864
  }
9671
7865
  const { issue: selected } = outcome;
9672
7866
  const baseBranchOverride = options.queueRunContext?.prdBranch;
9673
- const prdRunMode = options.prdRunMode ?? options.queueRunContext?.prdRunMode;
9674
7867
  const runResult = yield* Effect8.tryPromise({
9675
7868
  try: () => runIssueCommand({
9676
7869
  issueNumber: selected.number,
@@ -9682,8 +7875,7 @@ function runOneQueueIssueEffect(options) {
9682
7875
  force,
9683
7876
  logger,
9684
7877
  repoRoot: repoRoot2,
9685
- ...baseBranchOverride ? { baseBranchOverride } : {},
9686
- ...prdRunMode ? { prdRunMode } : {}
7878
+ ...baseBranchOverride ? { baseBranchOverride } : {}
9687
7879
  }),
9688
7880
  catch: (e) => {
9689
7881
  if (e instanceof Error && e.name === "HumanHandoffStop") {
@@ -9699,10 +7891,6 @@ function runOneQueueIssueEffect(options) {
9699
7891
  logger.raw(` Branch: ${runResult.branchName}`);
9700
7892
  if (runResult.noOp) {
9701
7893
  logger.raw(" Status: no-op (closed without PR)");
9702
- } else if (runResult.mode === "local") {
9703
- logger.raw(` Local PRD Branch: ${runResult.localPrdBranch}`);
9704
- logger.raw(` Merge Commit: ${runResult.mergeCommit}`);
9705
- logger.raw(` Receipt: ${runResult.receiptPath}`);
9706
7894
  } else {
9707
7895
  logger.raw(` PR Title: ${runResult.prTitle}`);
9708
7896
  logger.raw(` PR Number: ${runResult.prNumber}`);
@@ -9762,8 +7950,7 @@ async function runQueueCommand(options) {
9762
7950
  logger: options.logger,
9763
7951
  repoRoot: options.repoRoot,
9764
7952
  prdRef: options.prdRef,
9765
- queueRunContext: options.queueRunContext,
9766
- prdRunMode: options.queueRunContext?.prdRunMode
7953
+ queueRunContext: options.queueRunContext
9767
7954
  };
9768
7955
  if (!options.loop) {
9769
7956
  return runEffectAndMapExit(runQueue(queueOptions));
@@ -9793,11 +7980,6 @@ function planPrdRunLaunchResume(record) {
9793
7980
  skipped: ["start", "queue"],
9794
7981
  resumed: []
9795
7982
  })),
9796
- Match.when({ status: "completed_local_branch" }, () => ({
9797
- attempted: [],
9798
- skipped: ["start", "queue"],
9799
- resumed: []
9800
- })),
9801
7983
  Match.when({ status: "complete" }, () => ({
9802
7984
  attempted: [],
9803
7985
  skipped: ["start", "queue"],
@@ -9936,51 +8118,25 @@ function resolvePrdRunBaseBranch(options) {
9936
8118
  return {
9937
8119
  ok: false,
9938
8120
  gate: "branch-state",
9939
- reason: `Invalid PRD Run base branch: "${trimmed}" must not end with a trailing slash.`,
9940
- diagnostics: [`Provided branch value: "${trimmed}"`],
9941
- offendingPaths: []
9942
- };
9943
- }
9944
- if (trimmed.endsWith(".lock")) {
9945
- return {
9946
- ok: false,
9947
- gate: "branch-state",
9948
- reason: `Invalid PRD Run base branch: "${trimmed}" must not end with ".lock" suffix.`,
9949
- diagnostics: [`Provided branch value: "${trimmed}"`],
9950
- offendingPaths: []
9951
- };
9952
- }
9953
- const source = options.baseBranchOverride !== void 0 ? "override" : "target";
9954
- return { ok: true, baseBranch: trimmed, source };
9955
- }
9956
- function validateLocalStartStore(repoRoot2, prdRef) {
9957
- const localStoreDir = join20(repoRoot2, ".pourkit", "local-prd-runs", prdRef);
9958
- const localStorePath = join20(localStoreDir, "prd.json");
9959
- let localStoreReady = false;
9960
- if (existsSync16(localStorePath)) {
9961
- try {
9962
- const content = JSON.parse(readFileSync18(localStorePath, "utf8"));
9963
- localStoreReady = content?.id === prdRef && content?.kind === "prd";
9964
- } catch {
9965
- localStoreReady = false;
9966
- }
8121
+ reason: `Invalid PRD Run base branch: "${trimmed}" must not end with a trailing slash.`,
8122
+ diagnostics: [`Provided branch value: "${trimmed}"`],
8123
+ offendingPaths: []
8124
+ };
9967
8125
  }
9968
- if (!localStoreReady) {
8126
+ if (trimmed.endsWith(".lock")) {
9969
8127
  return {
9970
8128
  ok: false,
9971
8129
  gate: "branch-state",
9972
- reason: `Local PRD Run Store not ready for ${prdRef}. Expected valid prd.json at .pourkit/local-prd-runs/${prdRef}/prd.json with matching PRD ID. Ensure Local PRD Run Store is initialized before starting.`,
9973
- diagnostics: [
9974
- `Expected store path: .pourkit/local-prd-runs/${prdRef}/prd.json`,
9975
- `Expected PRD ID: ${prdRef}`
9976
- ],
8130
+ reason: `Invalid PRD Run base branch: "${trimmed}" must not end with ".lock" suffix.`,
8131
+ diagnostics: [`Provided branch value: "${trimmed}"`],
9977
8132
  offendingPaths: []
9978
8133
  };
9979
8134
  }
9980
- return { ok: true };
8135
+ const source = options.baseBranchOverride !== void 0 ? "override" : "target";
8136
+ return { ok: true, baseBranch: trimmed, source };
9981
8137
  }
9982
8138
  function fetchOriginBranch(repoRoot2, baseBranch) {
9983
- const fetchResult = spawnSync3("git", ["fetch", "origin", baseBranch], {
8139
+ const fetchResult = spawnSync2("git", ["fetch", "origin", baseBranch], {
9984
8140
  cwd: repoRoot2,
9985
8141
  encoding: "utf8"
9986
8142
  });
@@ -9997,7 +8153,7 @@ function fetchOriginBranch(repoRoot2, baseBranch) {
9997
8153
  offendingPaths: []
9998
8154
  };
9999
8155
  }
10000
- const revParseResult = spawnSync3(
8156
+ const revParseResult = spawnSync2(
10001
8157
  "git",
10002
8158
  ["rev-parse", `origin/${baseBranch}`],
10003
8159
  {
@@ -10021,7 +8177,7 @@ function fetchOriginBranch(repoRoot2, baseBranch) {
10021
8177
  return { ok: true, startBaseCommit: revParseResult.stdout.trim() };
10022
8178
  }
10023
8179
  function inspectRemotePrdBranch(repoRoot2, prdRef) {
10024
- const result = spawnSync3("git", ["ls-remote", "--heads", "origin", prdRef], {
8180
+ const result = spawnSync2("git", ["ls-remote", "--heads", "origin", prdRef], {
10025
8181
  cwd: repoRoot2,
10026
8182
  encoding: "utf8"
10027
8183
  });
@@ -10045,7 +8201,7 @@ function inspectRemotePrdBranch(repoRoot2, prdRef) {
10045
8201
  return { ok: true, exists: true, headSha };
10046
8202
  }
10047
8203
  function fetchPrdBranch(repoRoot2, prdRef) {
10048
- const result = spawnSync3("git", ["fetch", "origin", prdRef], {
8204
+ const result = spawnSync2("git", ["fetch", "origin", prdRef], {
10049
8205
  cwd: repoRoot2,
10050
8206
  encoding: "utf8"
10051
8207
  });
@@ -10065,7 +8221,7 @@ function fetchPrdBranch(repoRoot2, prdRef) {
10065
8221
  return { ok: true };
10066
8222
  }
10067
8223
  async function ensurePrdBranchPublished(repoRoot2, prdRef, startBaseCommit) {
10068
- const pushResult = spawnSync3(
8224
+ const pushResult = spawnSync2(
10069
8225
  "git",
10070
8226
  ["push", "origin", `${startBaseCommit}:refs/heads/${prdRef}`],
10071
8227
  {
@@ -10124,8 +8280,7 @@ function persistStartingPrdRunRecord(repoRoot2, prdRef, existingRecord, start, c
10124
8280
  status: "starting",
10125
8281
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10126
8282
  targetName: context.targetName,
10127
- start,
10128
- mode: context.mode
8283
+ start
10129
8284
  });
10130
8285
  }
10131
8286
  function blocked(repoRoot2, prdRef, gate, failureCode, reason, diagnostics, targetName) {
@@ -10155,28 +8310,6 @@ async function startPrdRun(options) {
10155
8310
  );
10156
8311
  }
10157
8312
  const existingRecord = readPrdRun(options.repoRoot, prdRef);
10158
- const resolvedMode = options.config ? (() => {
10159
- try {
10160
- const target = resolveTarget(options.config, targetName);
10161
- return resolvePrdRunMode(target).mode;
10162
- } catch {
10163
- return void 0;
10164
- }
10165
- })() : void 0;
10166
- if (resolvedMode && existingRecord.record?.mode && existingRecord.record.mode !== resolvedMode) {
10167
- return blocked(
10168
- options.repoRoot,
10169
- prdRef,
10170
- "branch-state",
10171
- "mode_mismatch",
10172
- `PRD Run ${prdRef} mode mismatch: recorded "${existingRecord.record.mode}" but resolved "${resolvedMode}". Resolve by using the correct target.`,
10173
- [
10174
- `Recorded mode: ${existingRecord.record.mode}`,
10175
- `Resolved mode: ${resolvedMode}`
10176
- ],
10177
- targetName
10178
- );
10179
- }
10180
8313
  const resolvedTarget = options.config ? resolveTarget(options.config, targetName) : null;
10181
8314
  const targetBaseBranch = resolvedTarget?.baseBranch ?? "main";
10182
8315
  const baseResolution = resolvePrdRunBaseBranch({
@@ -10222,11 +8355,10 @@ async function startPrdRun(options) {
10222
8355
  );
10223
8356
  }
10224
8357
  const currentStatus = existingRecord.record.status;
10225
- if (currentStatus === "running" || currentStatus === "drained" || currentStatus === "completed_prd_branch" || currentStatus === "completed_local_branch" || currentStatus === "complete") {
8358
+ if (currentStatus === "running" || currentStatus === "drained" || currentStatus === "completed_prd_branch" || currentStatus === "complete") {
10226
8359
  return {
10227
8360
  kind: "started",
10228
8361
  prdRef,
10229
- mode: resolvedMode,
10230
8362
  start: existingRecord.record.start,
10231
8363
  diagnostics: [],
10232
8364
  preservedStatus: currentStatus
@@ -10267,12 +8399,11 @@ async function startPrdRun(options) {
10267
8399
  prdRef,
10268
8400
  existingRecord,
10269
8401
  reusedStart,
10270
- { targetName, mode: resolvedMode }
8402
+ { targetName }
10271
8403
  );
10272
8404
  return {
10273
8405
  kind: "started",
10274
8406
  prdRef,
10275
- mode: resolvedMode,
10276
8407
  start: reusedStart,
10277
8408
  diagnostics: []
10278
8409
  };
@@ -10303,7 +8434,7 @@ async function startPrdRun(options) {
10303
8434
  fetchPrdResult.diagnostics
10304
8435
  );
10305
8436
  }
10306
- const ancestryResult = spawnSync3(
8437
+ const ancestryResult = spawnSync2(
10307
8438
  "git",
10308
8439
  [
10309
8440
  "merge-base",
@@ -10340,12 +8471,11 @@ async function startPrdRun(options) {
10340
8471
  prdRef,
10341
8472
  existingRecord,
10342
8473
  adoptedStart,
10343
- { targetName, mode: resolvedMode }
8474
+ { targetName }
10344
8475
  );
10345
8476
  return {
10346
8477
  kind: "started",
10347
8478
  prdRef,
10348
- mode: resolvedMode,
10349
8479
  start: adoptedStart,
10350
8480
  diagnostics: []
10351
8481
  };
@@ -10365,59 +8495,6 @@ async function startPrdRun(options) {
10365
8495
  fetchResult.diagnostics
10366
8496
  );
10367
8497
  }
10368
- if (resolvedMode === "local") {
10369
- const localStoreResult = validateLocalStartStore(options.repoRoot, prdRef);
10370
- if (!localStoreResult.ok) {
10371
- return blocked(
10372
- options.repoRoot,
10373
- prdRef,
10374
- localStoreResult.gate,
10375
- "local_store_invalid",
10376
- localStoreResult.reason,
10377
- localStoreResult.diagnostics
10378
- );
10379
- }
10380
- const localBranchName = getLocalPrdBranchName(prdRef);
10381
- const localBranchResult = materializeLocalPrdBranch(
10382
- prdRef,
10383
- fetchResult.startBaseCommit,
10384
- options.repoRoot
10385
- );
10386
- if (!localBranchResult.ok) {
10387
- return blocked(
10388
- options.repoRoot,
10389
- prdRef,
10390
- "branch-state",
10391
- "local_branch_failed",
10392
- localBranchResult.message,
10393
- [localBranchResult.message]
10394
- );
10395
- }
10396
- const updatedAt2 = (/* @__PURE__ */ new Date()).toISOString();
10397
- const start2 = buildStartReceipt({
10398
- status: "started",
10399
- targetName,
10400
- prdBranch: localBranchName,
10401
- startBaseBranch: baseResolution.baseBranch,
10402
- startBaseCommit: fetchResult.startBaseCommit,
10403
- branchAction: localBranchResult.created ? "created" : "reused",
10404
- startedAt: updatedAt2
10405
- });
10406
- persistStartingPrdRunRecord(
10407
- options.repoRoot,
10408
- prdRef,
10409
- existingRecord,
10410
- start2,
10411
- { targetName, mode: resolvedMode }
10412
- );
10413
- return {
10414
- kind: "started",
10415
- prdRef,
10416
- mode: resolvedMode,
10417
- start: start2,
10418
- diagnostics: []
10419
- };
10420
- }
10421
8498
  const branchResult = inspectRemotePrdBranch(options.repoRoot, prdRef);
10422
8499
  if (!branchResult.ok) {
10423
8500
  return blocked(
@@ -10456,7 +8533,7 @@ async function startPrdRun(options) {
10456
8533
  fetchPrdResult.diagnostics
10457
8534
  );
10458
8535
  }
10459
- const ancestryResult = spawnSync3(
8536
+ const ancestryResult = spawnSync2(
10460
8537
  "git",
10461
8538
  [
10462
8539
  "merge-base",
@@ -10493,12 +8570,11 @@ async function startPrdRun(options) {
10493
8570
  prdRef,
10494
8571
  existingRecord,
10495
8572
  adoptedStart,
10496
- { targetName, mode: resolvedMode }
8573
+ { targetName }
10497
8574
  );
10498
8575
  return {
10499
8576
  kind: "started",
10500
8577
  prdRef,
10501
- mode: resolvedMode,
10502
8578
  start: adoptedStart,
10503
8579
  diagnostics: []
10504
8580
  };
@@ -10532,13 +8608,11 @@ async function startPrdRun(options) {
10532
8608
  startedAt: updatedAt
10533
8609
  });
10534
8610
  persistStartingPrdRunRecord(options.repoRoot, prdRef, existingRecord, start, {
10535
- targetName,
10536
- mode: resolvedMode
8611
+ targetName
10537
8612
  });
10538
8613
  return {
10539
8614
  kind: "started",
10540
8615
  prdRef,
10541
- mode: resolvedMode,
10542
8616
  start,
10543
8617
  diagnostics: []
10544
8618
  };
@@ -10552,25 +8626,23 @@ function buildLaunchBlockedOutcome(prdRef, guidance, resume, start) {
10552
8626
  resume
10553
8627
  };
10554
8628
  }
10555
- function writeDrainedRecord(repoRoot2, prdRef, startReceipt, targetName, mode) {
8629
+ function writeDrainedRecord(repoRoot2, prdRef, startReceipt, targetName) {
10556
8630
  writePrdRunRecord(repoRoot2, {
10557
8631
  prdRef,
10558
8632
  status: "drained",
10559
8633
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10560
8634
  targetName,
10561
- start: startReceipt,
10562
- mode
8635
+ start: startReceipt
10563
8636
  });
10564
8637
  }
10565
- function writeTerminalRecord(repoRoot2, prdRef, status, targetName, startReceipt, prdBranch, mode) {
8638
+ function writeTerminalRecord(repoRoot2, prdRef, status, targetName, startReceipt, prdBranch) {
10566
8639
  writePrdRunRecord(repoRoot2, {
10567
8640
  prdRef,
10568
8641
  status,
10569
8642
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10570
8643
  targetName,
10571
8644
  prdBranch,
10572
- start: startReceipt,
10573
- mode
8645
+ start: startReceipt
10574
8646
  });
10575
8647
  }
10576
8648
  function validatePrdRunStartEvidence(record, context) {
@@ -10629,22 +8701,6 @@ function validatePrdRunStartEvidence(record, context) {
10629
8701
  }
10630
8702
  };
10631
8703
  }
10632
- if (record.mode && record.mode !== context.mode) {
10633
- return {
10634
- ok: false,
10635
- guidance: {
10636
- blockedGate: "branch-state",
10637
- failureCode: "mode_mismatch",
10638
- reason: `PRD Run ${context.prdRef} mode mismatch: recorded "${record.mode}" but expected "${context.mode}".`,
10639
- repairability: "operator-action",
10640
- diagnostics: [
10641
- `Recorded mode: ${record.mode}`,
10642
- `Expected mode: ${context.mode}`
10643
- ],
10644
- offendingPaths: []
10645
- }
10646
- };
10647
- }
10648
8704
  if (record.prdRef !== context.prdRef) {
10649
8705
  return {
10650
8706
  ok: false,
@@ -10764,31 +8820,6 @@ function validatePrdRunDrainEvidence(record, context) {
10764
8820
  async function launchPrdRun(options) {
10765
8821
  const prdRef = normalizePrdRunRef(options.prdRef);
10766
8822
  const existingRecord = readPrdRun(options.repoRoot, prdRef);
10767
- const resolvedLaunchMode = options.config ? (() => {
10768
- try {
10769
- const target = resolveTarget(options.config, options.targetName);
10770
- return resolvePrdRunMode(target).mode;
10771
- } catch {
10772
- return void 0;
10773
- }
10774
- })() : void 0;
10775
- if (resolvedLaunchMode && existingRecord.record?.mode && existingRecord.record.mode !== resolvedLaunchMode) {
10776
- return buildLaunchBlockedOutcome(
10777
- prdRef,
10778
- {
10779
- blockedGate: "branch-state",
10780
- failureCode: "mode_mismatch",
10781
- reason: `PRD Run ${prdRef} mode mismatch: recorded "${existingRecord.record.mode}" but resolved "${resolvedLaunchMode}". Resolve by using the correct target.`,
10782
- repairability: "operator-action",
10783
- diagnostics: [
10784
- `Recorded mode: ${existingRecord.record.mode}`,
10785
- `Resolved mode: ${resolvedLaunchMode}`
10786
- ],
10787
- offendingPaths: []
10788
- },
10789
- { attempted: [], skipped: ["start", "queue"], resumed: [] }
10790
- );
10791
- }
10792
8823
  const plan = planPrdRunLaunchResume(existingRecord.record);
10793
8824
  if (plan.blocked === "final_reviewed-incompatible") {
10794
8825
  return buildLaunchBlockedOutcome(
@@ -10806,7 +8837,7 @@ async function launchPrdRun(options) {
10806
8837
  plan
10807
8838
  );
10808
8839
  }
10809
- if (existingRecord.record?.status === "completed_prd_branch" || existingRecord.record?.status === "complete" || existingRecord.record?.status === "completed_local_branch") {
8840
+ if (existingRecord.record?.status === "completed_prd_branch" || existingRecord.record?.status === "complete") {
10810
8841
  return {
10811
8842
  kind: "already-terminal",
10812
8843
  prdRef,
@@ -10834,7 +8865,6 @@ async function launchPrdRun(options) {
10834
8865
  plan
10835
8866
  );
10836
8867
  }
10837
- const drainMode = resolvedLaunchMode ?? record.mode ?? "github";
10838
8868
  const resolvedTarget = options.config ? resolveTarget(options.config, options.targetName) : null;
10839
8869
  const targetBaseBranch = resolvedTarget?.baseBranch ?? "main";
10840
8870
  const baseResolution = resolvePrdRunBaseBranch({
@@ -10857,7 +8887,6 @@ async function launchPrdRun(options) {
10857
8887
  }
10858
8888
  const drainContext = {
10859
8889
  prdRef,
10860
- mode: drainMode,
10861
8890
  baseBranch: baseResolution.baseBranch,
10862
8891
  prdBranch: record.start.prdBranch
10863
8892
  };
@@ -10869,20 +8898,18 @@ async function launchPrdRun(options) {
10869
8898
  if (!drainEvidence.ok) {
10870
8899
  return buildLaunchBlockedOutcome(prdRef, drainEvidence.guidance, plan);
10871
8900
  }
10872
- const terminalStatus = drainMode === "local" ? "completed_local_branch" : "completed_prd_branch";
10873
8901
  writeTerminalRecord(
10874
8902
  options.repoRoot,
10875
8903
  prdRef,
10876
- terminalStatus,
8904
+ "completed_prd_branch",
10877
8905
  record.targetName ?? options.targetName,
10878
8906
  record.start,
10879
- record.start.prdBranch,
10880
- drainMode
8907
+ record.start.prdBranch
10881
8908
  );
10882
8909
  return {
10883
8910
  kind: "completed",
10884
8911
  prdRef,
10885
- status: terminalStatus,
8912
+ status: "completed_prd_branch",
10886
8913
  prdBranch: record.start.prdBranch,
10887
8914
  diagnostics: [
10888
8915
  `PRD Run ${prdRef} completed from drained state. Branch: ${record.start.prdBranch}.`
@@ -10933,7 +8960,6 @@ async function launchPrdRun(options) {
10933
8960
  const currentRecord = readPrdRun(options.repoRoot, prdRef).record;
10934
8961
  const startReceipt = currentRecord?.start;
10935
8962
  const targetName = currentRecord?.targetName ?? options.targetName;
10936
- const explicitMode = resolvedLaunchMode ?? currentRecord?.mode;
10937
8963
  if (startReceipt) {
10938
8964
  startReceipt.queueStartedAt = (/* @__PURE__ */ new Date()).toISOString();
10939
8965
  startReceipt.queueCommand = "queue-run";
@@ -10943,236 +8969,18 @@ async function launchPrdRun(options) {
10943
8969
  status: "running",
10944
8970
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10945
8971
  targetName,
10946
- start: startReceipt,
10947
- mode: explicitMode
8972
+ start: startReceipt
10948
8973
  });
10949
- if (explicitMode === "local") {
10950
- return await launchLocalQueueDrain(
10951
- options,
10952
- prdRef,
10953
- startReceipt,
10954
- targetName,
10955
- explicitMode,
10956
- plan,
10957
- startOutcome
10958
- );
10959
- }
10960
8974
  return await launchGithubQueueDrain(
10961
8975
  options,
10962
8976
  prdRef,
10963
8977
  startReceipt,
10964
8978
  targetName,
10965
- explicitMode,
10966
8979
  plan,
10967
8980
  startOutcome
10968
8981
  );
10969
8982
  }
10970
- async function launchLocalQueueDrain(options, prdRef, startReceipt, targetName, mode, plan, startOutcome) {
10971
- if (!startReceipt) {
10972
- writePrdRunRecord(options.repoRoot, {
10973
- prdRef,
10974
- status: "blocked",
10975
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
10976
- targetName,
10977
- blockedGate: "branch-state",
10978
- blockedReason: `PRD Run ${prdRef} is missing start receipt before local queue drain.`,
10979
- diagnostics: [],
10980
- offendingPaths: []
10981
- });
10982
- return buildLaunchBlockedOutcome(
10983
- prdRef,
10984
- {
10985
- blockedGate: "branch-state",
10986
- failureCode: "missing_start_receipt",
10987
- reason: `PRD Run ${prdRef} is missing start receipt before local queue drain.`,
10988
- repairability: "automatic-retry-safe",
10989
- diagnostics: [],
10990
- offendingPaths: []
10991
- },
10992
- plan,
10993
- startOutcome
10994
- );
10995
- }
10996
- const localStoreDir = join20(
10997
- options.repoRoot,
10998
- ".pourkit",
10999
- "local-prd-runs",
11000
- prdRef
11001
- );
11002
- let localStoreReady = false;
11003
- if (existsSync16(localStoreDir)) {
11004
- const localStorePath = join20(localStoreDir, "prd.json");
11005
- try {
11006
- const content = JSON.parse(readFileSync18(localStorePath, "utf8"));
11007
- localStoreReady = content?.id === prdRef && content?.kind === "prd";
11008
- } catch {
11009
- localStoreReady = false;
11010
- }
11011
- }
11012
- if (!localStoreReady) {
11013
- const reason = `Local PRD Run Store not ready for ${prdRef}. Expected valid prd.json at .pourkit/local-prd-runs/${prdRef}/prd.json with matching PRD ID.`;
11014
- writePrdRunRecord(options.repoRoot, {
11015
- prdRef,
11016
- status: "blocked",
11017
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11018
- targetName,
11019
- start: startReceipt,
11020
- mode,
11021
- blockedGate: "branch-state",
11022
- blockedReason: reason,
11023
- diagnostics: [
11024
- `Expected store path: .pourkit/local-prd-runs/${prdRef}/prd.json`,
11025
- `Expected PRD ID: ${prdRef}`
11026
- ],
11027
- offendingPaths: []
11028
- });
11029
- return buildLaunchBlockedOutcome(
11030
- prdRef,
11031
- {
11032
- blockedGate: "branch-state",
11033
- failureCode: "local_store_invalid",
11034
- reason,
11035
- repairability: "operator-action",
11036
- diagnostics: [
11037
- `Expected store path: .pourkit/local-prd-runs/${prdRef}/prd.json`,
11038
- `Expected PRD ID: ${prdRef}`
11039
- ],
11040
- offendingPaths: []
11041
- },
11042
- plan,
11043
- startOutcome
11044
- );
11045
- }
11046
- const memoryExecutionContext = options.config?.memory?.enabled ? { available: true, sandboxDbPath: "/home/agent/.pourkit/icm/memories.db" } : void 0;
11047
- const queueResult = await runLocalQueueLoop(
11048
- prdRef,
11049
- options.repoRoot,
11050
- options.issueProvider,
11051
- memoryExecutionContext
11052
- );
11053
- if (!queueResult.ok) {
11054
- const failureCode = queueResult.failureCode ?? "queue_error";
11055
- const reason = queueResult.repairGuidance ?? `Local queue loop blocked: ${failureCode}`;
11056
- const diagnostics = [
11057
- `Local queue loop failed with failureCode "${failureCode}".`,
11058
- ...queueResult.repairGuidance ? [`Repair guidance: ${queueResult.repairGuidance}`] : []
11059
- ];
11060
- writePrdRunRecord(options.repoRoot, {
11061
- prdRef,
11062
- status: "blocked",
11063
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11064
- targetName,
11065
- start: startReceipt,
11066
- mode,
11067
- blockedGate: "queue",
11068
- blockedReason: reason,
11069
- diagnostics,
11070
- offendingPaths: []
11071
- });
11072
- return buildLaunchBlockedOutcome(
11073
- prdRef,
11074
- {
11075
- blockedGate: "queue",
11076
- failureCode,
11077
- reason,
11078
- repairability: "automatic-retry-safe",
11079
- diagnostics,
11080
- offendingPaths: []
11081
- },
11082
- plan,
11083
- startOutcome
11084
- );
11085
- }
11086
- if (queueResult.blockedIssues.length > 0) {
11087
- const reason = `Queue processed complete but ${queueResult.blockedIssues.length} blocked child issue(s) remain.`;
11088
- const diagnostics = [
11089
- reason,
11090
- `Blocked issues: ${queueResult.blockedIssues.join(", ")}`,
11091
- "Resolve blocked children before parent close."
11092
- ];
11093
- writePrdRunRecord(options.repoRoot, {
11094
- prdRef,
11095
- status: "blocked",
11096
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11097
- targetName,
11098
- start: startReceipt,
11099
- mode,
11100
- blockedGate: "queue",
11101
- blockedReason: reason,
11102
- diagnostics,
11103
- offendingPaths: []
11104
- });
11105
- return buildLaunchBlockedOutcome(
11106
- prdRef,
11107
- {
11108
- blockedGate: "queue",
11109
- failureCode: "blocked_child_issues",
11110
- reason,
11111
- repairability: "operator-action",
11112
- diagnostics,
11113
- offendingPaths: []
11114
- },
11115
- plan,
11116
- startOutcome
11117
- );
11118
- }
11119
- startReceipt.queueDrainedAt = (/* @__PURE__ */ new Date()).toISOString();
11120
- startReceipt.queueProcessedCount = queueResult.completedIssues.length + queueResult.blockedIssues.length;
11121
- const prdBranch = startReceipt.prdBranch ?? `local/${prdRef}`;
11122
- writeDrainedRecord(options.repoRoot, prdRef, startReceipt, targetName, mode);
11123
- const drainRecord = readPrdRun(options.repoRoot, prdRef).record;
11124
- if (drainRecord) {
11125
- const drainContext = {
11126
- prdRef,
11127
- mode,
11128
- baseBranch: startReceipt.startBaseBranch,
11129
- prdBranch
11130
- };
11131
- const startEvidence = validatePrdRunStartEvidence(
11132
- drainRecord,
11133
- drainContext
11134
- );
11135
- if (!startEvidence.ok) {
11136
- return buildLaunchBlockedOutcome(
11137
- prdRef,
11138
- startEvidence.guidance,
11139
- plan,
11140
- startOutcome
11141
- );
11142
- }
11143
- const drainEvidence = validatePrdRunDrainEvidence(
11144
- drainRecord,
11145
- drainContext
11146
- );
11147
- if (!drainEvidence.ok) {
11148
- return buildLaunchBlockedOutcome(
11149
- prdRef,
11150
- drainEvidence.guidance,
11151
- plan,
11152
- startOutcome
11153
- );
11154
- }
11155
- }
11156
- writeTerminalRecord(
11157
- options.repoRoot,
11158
- prdRef,
11159
- "completed_local_branch",
11160
- targetName,
11161
- startReceipt,
11162
- prdBranch,
11163
- mode
11164
- );
11165
- return {
11166
- kind: "completed",
11167
- prdRef,
11168
- status: "completed_local_branch",
11169
- prdBranch,
11170
- diagnostics: [`Local PRD Run ${prdRef} completed. Branch: ${prdBranch}.`],
11171
- start: startOutcome,
11172
- resume: plan
11173
- };
11174
- }
11175
- async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName, mode, plan, startOutcome) {
8983
+ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName, plan, startOutcome) {
11176
8984
  if (!options.issueProvider || !options.prProvider || !options.executionProvider || !options.logger) {
11177
8985
  const reason = `PRD Run ${prdRef} requires issueProvider, prProvider, executionProvider, and logger for GitHub-backed queue drain.`;
11178
8986
  writePrdRunRecord(options.repoRoot, {
@@ -11181,7 +8989,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11181
8989
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11182
8990
  targetName,
11183
8991
  start: startReceipt,
11184
- mode,
11185
8992
  blockedGate: "queue",
11186
8993
  blockedReason: reason,
11187
8994
  diagnostics: [
@@ -11212,7 +9019,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11212
9019
  status: "blocked",
11213
9020
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11214
9021
  targetName,
11215
- mode,
11216
9022
  blockedGate: "branch-state",
11217
9023
  blockedReason: `PRD Run ${prdRef} is missing start receipt before GitHub queue drain.`,
11218
9024
  diagnostics: [],
@@ -11240,7 +9046,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11240
9046
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11241
9047
  targetName,
11242
9048
  start: startReceipt,
11243
- mode,
11244
9049
  blockedGate: "queue",
11245
9050
  blockedReason: reason,
11246
9051
  diagnostics: ["Missing config for GitHub-backed mode."],
@@ -11264,13 +9069,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11264
9069
  const prProvider = options.prProvider;
11265
9070
  const executionProvider = options.executionProvider;
11266
9071
  const logger = options.logger;
11267
- let resolvedModeForQueue;
11268
- try {
11269
- const target = resolveTarget(options.config, options.targetName);
11270
- resolvedModeForQueue = resolvePrdRunMode(target);
11271
- } catch {
11272
- resolvedModeForQueue = void 0;
11273
- }
11274
9072
  try {
11275
9073
  const outcome = await runQueueCommand({
11276
9074
  targetName,
@@ -11285,8 +9083,7 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11285
9083
  prdRef,
11286
9084
  queueRunContext: {
11287
9085
  prdRef,
11288
- prdBranch: startReceipt.prdBranch,
11289
- prdRunMode: resolvedModeForQueue
9086
+ prdBranch: startReceipt.prdBranch
11290
9087
  }
11291
9088
  });
11292
9089
  if (outcome.selected === null && outcome.code === "drained") {
@@ -11300,7 +9097,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11300
9097
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11301
9098
  targetName,
11302
9099
  start: startReceipt,
11303
- mode,
11304
9100
  blockedGate: "queue",
11305
9101
  blockedReason: diagnostics[0],
11306
9102
  diagnostics,
@@ -11323,19 +9119,11 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11323
9119
  startReceipt.queueDrainedAt = (/* @__PURE__ */ new Date()).toISOString();
11324
9120
  startReceipt.queueProcessedCount = outcome.processedCount;
11325
9121
  const prdBranch = startReceipt.prdBranch ?? prdRef;
11326
- writeDrainedRecord(
11327
- options.repoRoot,
11328
- prdRef,
11329
- startReceipt,
11330
- targetName,
11331
- mode
11332
- );
9122
+ writeDrainedRecord(options.repoRoot, prdRef, startReceipt, targetName);
11333
9123
  const drainRecord = readPrdRun(options.repoRoot, prdRef).record;
11334
9124
  if (drainRecord) {
11335
- const drainMode = mode ?? "github";
11336
9125
  const drainContext = {
11337
9126
  prdRef,
11338
- mode: drainMode,
11339
9127
  baseBranch: startReceipt.startBaseBranch,
11340
9128
  prdBranch
11341
9129
  };
@@ -11370,8 +9158,7 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11370
9158
  "completed_prd_branch",
11371
9159
  targetName,
11372
9160
  startReceipt,
11373
- prdBranch,
11374
- mode
9161
+ prdBranch
11375
9162
  );
11376
9163
  return {
11377
9164
  kind: "completed",
@@ -11393,7 +9180,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11393
9180
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11394
9181
  targetName,
11395
9182
  start: startReceipt,
11396
- mode,
11397
9183
  blockedGate: "queue",
11398
9184
  blockedReason: outcome.reason,
11399
9185
  diagnostics,
@@ -11421,7 +9207,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11421
9207
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11422
9208
  targetName,
11423
9209
  start: startReceipt,
11424
- mode,
11425
9210
  blockedGate: "queue",
11426
9211
  blockedReason: outcomeReason,
11427
9212
  diagnostics: outcomeDiagnostics,
@@ -11449,7 +9234,6 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11449
9234
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
11450
9235
  targetName,
11451
9236
  start: startReceipt,
11452
- mode,
11453
9237
  blockedGate: "queue",
11454
9238
  blockedReason: msg,
11455
9239
  diagnostics,
@@ -11472,13 +9256,13 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
11472
9256
  }
11473
9257
 
11474
9258
  // prd-run/final-review-validation.ts
11475
- import { existsSync as existsSync17, readFileSync as readFileSync19 } from "fs";
9259
+ import { existsSync as existsSync14, readFileSync as readFileSync16 } from "fs";
11476
9260
 
11477
9261
  // commands/prd-run.ts
11478
9262
  async function runPrdRunLaunchCommand(options) {
11479
9263
  const outcome = await launchPrdRun(options);
11480
9264
  const result = mapLaunchPrdRunOutcomeToCommandResult(outcome, options);
11481
- if (options.config && options.logger && (result.status === "completed_prd_branch" || result.status === "completed_local_branch")) {
9265
+ if (options.config && options.logger && result.status === "completed_prd_branch") {
11482
9266
  try {
11483
9267
  const target = resolveTarget(options.config, options.targetName);
11484
9268
  if (shouldCleanupRepositoryAfterPrdDrain(target)) {
@@ -11505,10 +9289,7 @@ function mapLaunchPrdRunOutcomeToCommandResult(outcome, options) {
11505
9289
  if (outcome.kind === "already-terminal") {
11506
9290
  const diagnostics = [
11507
9291
  `PRD Run ${prdRef} is already in status "${outcome.status}".`,
11508
- ...outcome.status === "completed_prd_branch" ? [buildCompletedPrdBranchHint(outcome.prdBranch ?? prdRef)] : [],
11509
- ...outcome.status === "completed_local_branch" ? [
11510
- `Local PRD Run ${prdRef} completed. Branch: ${outcome.prdBranch ?? `local/${prdRef}`}.`
11511
- ] : []
9292
+ ...outcome.status === "completed_prd_branch" ? [buildCompletedPrdBranchHint(outcome.prdBranch ?? prdRef)] : []
11512
9293
  ];
11513
9294
  return {
11514
9295
  prdRef,
@@ -11985,16 +9766,16 @@ async function runPrMergeCommand(args, logger, prProvider, config) {
11985
9766
  }
11986
9767
 
11987
9768
  // commands/init.ts
11988
- import { existsSync as existsSync18, statSync } from "fs";
9769
+ import { existsSync as existsSync15, statSync } from "fs";
11989
9770
  import {
11990
9771
  copyFile,
11991
- mkdir as mkdir5,
11992
- readFile as readFile5,
9772
+ mkdir as mkdir4,
9773
+ readFile as readFile4,
11993
9774
  readdir,
11994
9775
  rename,
11995
- writeFile as writeFile2
9776
+ writeFile
11996
9777
  } from "fs/promises";
11997
- import { createHash as createHash2, randomUUID } from "crypto";
9778
+ import { createHash, randomUUID } from "crypto";
11998
9779
  import path5 from "path";
11999
9780
  import { execFile as execFile2 } from "child_process";
12000
9781
  import { promisify as promisify2 } from "util";
@@ -12301,7 +10082,7 @@ function resolveSourceAssetPath(sourceRoot, ...segments) {
12301
10082
  path5.join(sourceRoot, "dist", ...segments)
12302
10083
  ];
12303
10084
  for (const candidatePath of candidatePaths) {
12304
- if (existsSync18(candidatePath)) return candidatePath;
10085
+ if (existsSync15(candidatePath)) return candidatePath;
12305
10086
  }
12306
10087
  return path5.join(sourceRoot, "pourkit", ...segments);
12307
10088
  }
@@ -12518,7 +10299,7 @@ function generateConfigTemplate(options) {
12518
10299
  }
12519
10300
  const config = {
12520
10301
  $schema: "./schema/pourkit.schema.json",
12521
- schemaVersion: 1,
10302
+ schemaVersion: 2,
12522
10303
  targets: [target],
12523
10304
  workflowPack: {
12524
10305
  version: "1.0.0",
@@ -12707,11 +10488,11 @@ async function walkDir(dir) {
12707
10488
  return files;
12708
10489
  }
12709
10490
  async function computeFileChecksum(filePath) {
12710
- const content = await readFile5(filePath);
12711
- return createHash2("sha256").update(content).digest("hex");
10491
+ const content = await readFile4(filePath);
10492
+ return createHash("sha256").update(content).digest("hex");
12712
10493
  }
12713
10494
  function lockfileExists(root, name) {
12714
- return existsSync18(path5.join(root, name));
10495
+ return existsSync15(path5.join(root, name));
12715
10496
  }
12716
10497
  function detectPackageManager(root) {
12717
10498
  if (lockfileExists(root, "pnpm-lock.yaml")) return "pnpm";
@@ -12755,7 +10536,7 @@ async function discoverLocalSource(sourcePath) {
12755
10536
  async function discoverReadme(root) {
12756
10537
  for (const name of ["README.md", "readme.md"]) {
12757
10538
  const p = path5.join(root, name);
12758
- if (existsSync18(p)) {
10539
+ if (existsSync15(p)) {
12759
10540
  return p;
12760
10541
  }
12761
10542
  }
@@ -12765,7 +10546,7 @@ async function discoverAgentFiles(root) {
12765
10546
  const files = [];
12766
10547
  for (const name of ["AGENTS.md", "CLAUDE.md"]) {
12767
10548
  const p = path5.join(root, name);
12768
- if (existsSync18(p)) {
10549
+ if (existsSync15(p)) {
12769
10550
  files.push(p);
12770
10551
  }
12771
10552
  }
@@ -12773,7 +10554,7 @@ async function discoverAgentFiles(root) {
12773
10554
  }
12774
10555
  async function discoverMerlleState(root) {
12775
10556
  const p = path5.join(root, ".pourkit", "state.json");
12776
- return existsSync18(p) ? p : null;
10557
+ return existsSync15(p) ? p : null;
12777
10558
  }
12778
10559
  async function discoverAgentSkills(root) {
12779
10560
  const dirs = [
@@ -12782,7 +10563,7 @@ async function discoverAgentSkills(root) {
12782
10563
  ];
12783
10564
  const found = [];
12784
10565
  for (const d of dirs) {
12785
- if (existsSync18(d)) {
10566
+ if (existsSync15(d)) {
12786
10567
  found.push(d);
12787
10568
  }
12788
10569
  }
@@ -12792,12 +10573,12 @@ async function discoverRootDomainDocs(root) {
12792
10573
  const docs = [];
12793
10574
  for (const name of ["CONTEXT.md", "CONTEXT-MAP.md"]) {
12794
10575
  const p = path5.join(root, name);
12795
- if (existsSync18(p)) {
10576
+ if (existsSync15(p)) {
12796
10577
  docs.push(p);
12797
10578
  }
12798
10579
  }
12799
10580
  const adrDir = path5.join(root, "docs", "adr");
12800
- if (existsSync18(adrDir)) {
10581
+ if (existsSync15(adrDir)) {
12801
10582
  const entries = await readdir(adrDir, { withFileTypes: true });
12802
10583
  for (const entry of entries) {
12803
10584
  if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -12939,7 +10720,7 @@ async function planInit(options) {
12939
10720
  for (const file of skillFiles) {
12940
10721
  const relPath = path5.relative(s, file);
12941
10722
  const destPath = path5.join(targetRoot, ".agents", "skills", relPath);
12942
- if (!existsSync18(destPath)) {
10723
+ if (!existsSync15(destPath)) {
12943
10724
  operations.push({
12944
10725
  kind: "copy",
12945
10726
  sourcePath: file,
@@ -13002,7 +10783,7 @@ async function planInit(options) {
13002
10783
  });
13003
10784
  }
13004
10785
  if (sourceRoot) {
13005
- if (!existsSync18(sourceRoot) || !statSync(sourceRoot).isDirectory()) {
10786
+ if (!existsSync15(sourceRoot) || !statSync(sourceRoot).isDirectory()) {
13006
10787
  warnings.push(
13007
10788
  `--from-local path does not exist or is not a directory: ${sourceRoot}`
13008
10789
  );
@@ -13067,9 +10848,9 @@ async function planInit(options) {
13067
10848
  "release",
13068
10849
  "skills"
13069
10850
  );
13070
- const srcSkills = existsSync18(packagedManagedSkills) ? [
10851
+ const srcSkills = existsSync15(packagedManagedSkills) ? [
13071
10852
  packagedManagedSkills,
13072
- ...existsSync18(packagedReleaseAddonSkills) ? [packagedReleaseAddonSkills] : []
10853
+ ...existsSync15(packagedReleaseAddonSkills) ? [packagedReleaseAddonSkills] : []
13073
10854
  ] : await discoverAgentSkills(sourceRoot);
13074
10855
  for (const s of srcSkills) {
13075
10856
  const isOpenCode = s.includes(".opencode");
@@ -13092,7 +10873,7 @@ async function planInit(options) {
13092
10873
  "skills",
13093
10874
  relPath
13094
10875
  );
13095
- if (!existsSync18(destPath)) {
10876
+ if (!existsSync15(destPath)) {
13096
10877
  operations.push({
13097
10878
  kind: "copy",
13098
10879
  sourcePath: file,
@@ -13179,7 +10960,7 @@ async function planInit(options) {
13179
10960
  });
13180
10961
  continue;
13181
10962
  }
13182
- const sourceContent = await readFile5(file, "utf-8");
10963
+ const sourceContent = await readFile4(file, "utf-8");
13183
10964
  const managedSourcePath = isReleaseAddon ? `.pourkit/managed/addons/release/skills/${skillName}/${relPath}` : `.pourkit/managed/skills/${skillName}/${relPath}`;
13184
10965
  operations.push({
13185
10966
  kind: "create",
@@ -13224,7 +11005,7 @@ async function planInit(options) {
13224
11005
  requiresConfirmation: false,
13225
11006
  destructive: false
13226
11007
  });
13227
- } else if (existsSync18(destPath)) {
11008
+ } else if (existsSync15(destPath)) {
13228
11009
  operations.push({
13229
11010
  kind: "skip",
13230
11011
  path: destPath,
@@ -13259,7 +11040,7 @@ async function planInit(options) {
13259
11040
  let packageScripts = {};
13260
11041
  let hasPackageJson = true;
13261
11042
  try {
13262
- const pkgContent = await readFile5(
11043
+ const pkgContent = await readFile4(
13263
11044
  path5.join(targetRoot, "package.json"),
13264
11045
  "utf-8"
13265
11046
  );
@@ -13282,7 +11063,7 @@ async function planInit(options) {
13282
11063
  }
13283
11064
  }
13284
11065
  const contextPath = path5.join(targetRoot, ".pourkit", "CONTEXT.md");
13285
- if (!existsSync18(contextPath) && !merleDestPaths.has(contextPath)) {
11066
+ if (!existsSync15(contextPath) && !merleDestPaths.has(contextPath)) {
13286
11067
  operations.push({
13287
11068
  kind: "create",
13288
11069
  path: contextPath,
@@ -13300,7 +11081,7 @@ async function planInit(options) {
13300
11081
  "adr",
13301
11082
  ".gitkeep"
13302
11083
  );
13303
- if (!existsSync18(adrGitkeep)) {
11084
+ if (!existsSync15(adrGitkeep)) {
13304
11085
  operations.push({
13305
11086
  kind: "create",
13306
11087
  path: adrGitkeep,
@@ -13322,7 +11103,7 @@ async function planInit(options) {
13322
11103
  "docs",
13323
11104
  "agents"
13324
11105
  );
13325
- const srcDocAgents = existsSync18(packagedManagedDocAgents) ? packagedManagedDocAgents : legacyDocAgents;
11106
+ const srcDocAgents = existsSync15(packagedManagedDocAgents) ? packagedManagedDocAgents : legacyDocAgents;
13326
11107
  const tgtManagedDocAgents = path5.join(
13327
11108
  targetRoot,
13328
11109
  ".pourkit",
@@ -13336,12 +11117,12 @@ async function planInit(options) {
13336
11117
  "docs",
13337
11118
  "agents"
13338
11119
  );
13339
- if (existsSync18(srcDocAgents)) {
11120
+ if (existsSync15(srcDocAgents)) {
13340
11121
  const docFiles = await walkDir(srcDocAgents);
13341
11122
  for (const file of docFiles) {
13342
11123
  const relPath = path5.relative(srcDocAgents, file);
13343
11124
  const managedDocDest = path5.join(tgtManagedDocAgents, relPath);
13344
- if (!existsSync18(managedDocDest) && relPath === "triage-labels.md") {
11125
+ if (!existsSync15(managedDocDest) && relPath === "triage-labels.md") {
13345
11126
  operations.push({
13346
11127
  kind: "create",
13347
11128
  path: managedDocDest,
@@ -13353,7 +11134,7 @@ async function planInit(options) {
13353
11134
  options.labels ?? DEFAULT_RUNNER_LABELS
13354
11135
  )
13355
11136
  });
13356
- } else if (!existsSync18(managedDocDest)) {
11137
+ } else if (!existsSync15(managedDocDest)) {
13357
11138
  const checksum = await computeFileChecksum(file);
13358
11139
  operations.push({
13359
11140
  kind: "copy",
@@ -13375,7 +11156,7 @@ async function planInit(options) {
13375
11156
  relPath
13376
11157
  );
13377
11158
  const stubDocDest = path5.join(tgtStubDocAgents, relPath);
13378
- if (existsSync18(stubDocDest)) continue;
11159
+ if (existsSync15(stubDocDest)) continue;
13379
11160
  operations.push({
13380
11161
  kind: "create",
13381
11162
  path: stubDocDest,
@@ -13409,7 +11190,7 @@ Do not edit this file.
13409
11190
  "docs",
13410
11191
  "agents"
13411
11192
  );
13412
- if (existsSync18(packagedReleaseAddonDocs)) {
11193
+ if (existsSync15(packagedReleaseAddonDocs)) {
13413
11194
  const docFiles = await walkDir(packagedReleaseAddonDocs);
13414
11195
  for (const file of docFiles) {
13415
11196
  const relPath = path5.relative(packagedReleaseAddonDocs, file);
@@ -13433,19 +11214,19 @@ Do not edit this file.
13433
11214
  "prompts"
13434
11215
  );
13435
11216
  const legacyPrompts = path5.join(sourceRoot, ".pourkit", "prompts");
13436
- const srcPrompts = existsSync18(packagedManagedPrompts) ? packagedManagedPrompts : legacyPrompts;
11217
+ const srcPrompts = existsSync15(packagedManagedPrompts) ? packagedManagedPrompts : legacyPrompts;
13437
11218
  const tgtManagedPrompts = path5.join(
13438
11219
  targetRoot,
13439
11220
  ".pourkit",
13440
11221
  "managed",
13441
11222
  "prompts"
13442
11223
  );
13443
- if (existsSync18(srcPrompts)) {
11224
+ if (existsSync15(srcPrompts)) {
13444
11225
  const promptFiles = await walkDir(srcPrompts);
13445
11226
  for (const file of promptFiles) {
13446
11227
  const relPath = path5.relative(srcPrompts, file);
13447
11228
  const promptDest = path5.join(tgtManagedPrompts, relPath);
13448
- if (existsSync18(promptDest)) continue;
11229
+ if (existsSync15(promptDest)) continue;
13449
11230
  const checksum = await computeFileChecksum(file);
13450
11231
  operations.push({
13451
11232
  kind: "copy",
@@ -13469,7 +11250,7 @@ Do not edit this file.
13469
11250
  ".sandcastle",
13470
11251
  "Dockerfile"
13471
11252
  );
13472
- if (existsSync18(tgtSandboxDockerfile)) {
11253
+ if (existsSync15(tgtSandboxDockerfile)) {
13473
11254
  operations.push({
13474
11255
  kind: "skip",
13475
11256
  path: tgtSandboxDockerfile,
@@ -13478,7 +11259,7 @@ Do not edit this file.
13478
11259
  requiresConfirmation: false,
13479
11260
  destructive: false
13480
11261
  });
13481
- } else if (existsSync18(srcSandboxDockerfile)) {
11262
+ } else if (existsSync15(srcSandboxDockerfile)) {
13482
11263
  const checksum = await computeFileChecksum(srcSandboxDockerfile);
13483
11264
  operations.push({
13484
11265
  kind: "copy",
@@ -13492,7 +11273,7 @@ Do not edit this file.
13492
11273
  });
13493
11274
  }
13494
11275
  const configJsonPath = path5.join(targetRoot, ".pourkit", "config.json");
13495
- if (!existsSync18(configJsonPath)) {
11276
+ if (!existsSync15(configJsonPath)) {
13496
11277
  const verifyCommands = inferVerificationCommands(
13497
11278
  packageScripts,
13498
11279
  pm || "npm"
@@ -13536,9 +11317,9 @@ Do not edit this file.
13536
11317
  "schema",
13537
11318
  "pourkit.schema.json"
13538
11319
  );
13539
- if (existsSync18(srcSchemaJson)) {
11320
+ if (existsSync15(srcSchemaJson)) {
13540
11321
  const checksum = await computeFileChecksum(srcSchemaJson);
13541
- if (!existsSync18(schemaJsonPath)) {
11322
+ if (!existsSync15(schemaJsonPath)) {
13542
11323
  operations.push({
13543
11324
  kind: "copy",
13544
11325
  sourcePath: srcSchemaJson,
@@ -13571,9 +11352,9 @@ Do not edit this file.
13571
11352
  "schema",
13572
11353
  "pourkit.schema.hash"
13573
11354
  );
13574
- if (existsSync18(srcSchemaHash)) {
11355
+ if (existsSync15(srcSchemaHash)) {
13575
11356
  const checksum = await computeFileChecksum(srcSchemaHash);
13576
- if (!existsSync18(schemaHashPath)) {
11357
+ if (!existsSync15(schemaHashPath)) {
13577
11358
  operations.push({
13578
11359
  kind: "copy",
13579
11360
  sourcePath: srcSchemaHash,
@@ -13599,7 +11380,7 @@ Do not edit this file.
13599
11380
  const hasExistingAgents = operations.some(
13600
11381
  (op) => (op.kind === "skip" || op.kind === "update") && op.path?.endsWith("AGENTS.md")
13601
11382
  );
13602
- if ((agentFileMode === "agents" || agentFileMode === "both") && !hasExistingAgents && !existsSync18(path5.join(targetRoot, "AGENTS.md"))) {
11383
+ if ((agentFileMode === "agents" || agentFileMode === "both") && !hasExistingAgents && !existsSync15(path5.join(targetRoot, "AGENTS.md"))) {
13603
11384
  operations.push({
13604
11385
  kind: "create",
13605
11386
  path: path5.join(targetRoot, "AGENTS.md"),
@@ -13615,7 +11396,7 @@ ${managedAgentContent}${MANAGED_BLOCK_END}
13615
11396
  const hasExistingClaude = operations.some(
13616
11397
  (op) => (op.kind === "skip" || op.kind === "update") && op.path?.endsWith("CLAUDE.md")
13617
11398
  );
13618
- if ((agentFileMode === "claude" || agentFileMode === "both") && !hasExistingClaude && !existsSync18(path5.join(targetRoot, "CLAUDE.md"))) {
11399
+ if ((agentFileMode === "claude" || agentFileMode === "both") && !hasExistingClaude && !existsSync15(path5.join(targetRoot, "CLAUDE.md"))) {
13619
11400
  operations.push({
13620
11401
  kind: "create",
13621
11402
  path: path5.join(targetRoot, "CLAUDE.md"),
@@ -13630,7 +11411,7 @@ ${managedAgentContent}${MANAGED_BLOCK_END}
13630
11411
  }
13631
11412
  const gitignoreTarget = path5.join(targetRoot, ".gitignore");
13632
11413
  const gitignoreContent = generateGitignoreBlock();
13633
- if (!existsSync18(gitignoreTarget)) {
11414
+ if (!existsSync15(gitignoreTarget)) {
13634
11415
  operations.push({
13635
11416
  kind: "create",
13636
11417
  path: gitignoreTarget,
@@ -13654,7 +11435,7 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
13654
11435
  });
13655
11436
  }
13656
11437
  const openCodePath = path5.join(targetRoot, "opencode.json");
13657
- if (!existsSync18(openCodePath)) {
11438
+ if (!existsSync15(openCodePath)) {
13658
11439
  operations.push({
13659
11440
  kind: "create",
13660
11441
  path: openCodePath,
@@ -13666,7 +11447,7 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
13666
11447
  });
13667
11448
  } else {
13668
11449
  try {
13669
- const existingContent = await readFile5(openCodePath, "utf-8");
11450
+ const existingContent = await readFile4(openCodePath, "utf-8");
13670
11451
  const existingConfig = JSON.parse(existingContent);
13671
11452
  if (typeof existingConfig !== "object" || existingConfig === null || Array.isArray(existingConfig)) {
13672
11453
  warnings.push(
@@ -13711,7 +11492,7 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
13711
11492
  }
13712
11493
  }
13713
11494
  const manifestPath = path5.join(targetRoot, ".pourkit", "manifest.json");
13714
- if (existsSync18(manifestPath)) {
11495
+ if (existsSync15(manifestPath)) {
13715
11496
  operations.push({
13716
11497
  kind: "skip",
13717
11498
  path: manifestPath,
@@ -14092,7 +11873,7 @@ async function promptForInitChoices(plan, current) {
14092
11873
  }
14093
11874
  async function writeFileAtomic(filePath, content) {
14094
11875
  const tmpPath = `${filePath}.tmp.${randomUUID()}`;
14095
- await writeFile2(tmpPath, content, "utf-8");
11876
+ await writeFile(tmpPath, content, "utf-8");
14096
11877
  await rename(tmpPath, filePath);
14097
11878
  }
14098
11879
  var MANAGED_BLOCK_BEGIN = "<!-- BEGIN POURKIT MANAGED BLOCK -->";
@@ -14101,13 +11882,13 @@ async function updateManagedBlock(filePath, content) {
14101
11882
  const blockContent = `${MANAGED_BLOCK_BEGIN}
14102
11883
  ${content}${MANAGED_BLOCK_END}
14103
11884
  `;
14104
- if (!existsSync18(filePath)) {
11885
+ if (!existsSync15(filePath)) {
14105
11886
  const dir = path5.dirname(filePath);
14106
- await mkdir5(dir, { recursive: true });
11887
+ await mkdir4(dir, { recursive: true });
14107
11888
  await writeFileAtomic(filePath, blockContent);
14108
11889
  return;
14109
11890
  }
14110
- const existing = await readFile5(filePath, "utf-8");
11891
+ const existing = await readFile4(filePath, "utf-8");
14111
11892
  const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN);
14112
11893
  const endIdx = existing.indexOf(MANAGED_BLOCK_END);
14113
11894
  if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
@@ -14130,7 +11911,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
14130
11911
  if (op.requiresConfirmation) continue;
14131
11912
  const relPath = path5.relative(plan.targetRoot, op.path);
14132
11913
  if (relPath === ".pourkit/manifest.json") continue;
14133
- if (existsSync18(op.path)) {
11914
+ if (existsSync15(op.path)) {
14134
11915
  const sha256 = await computeFileChecksum(op.path);
14135
11916
  assets[relPath] = {
14136
11917
  ownership: op.ownership || "managed",
@@ -14139,7 +11920,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
14139
11920
  }
14140
11921
  }
14141
11922
  const manifest = {
14142
- schemaVersion: 1,
11923
+ schemaVersion: 2,
14143
11924
  initializedAt: (/* @__PURE__ */ new Date()).toISOString(),
14144
11925
  pourkit: {
14145
11926
  versionSource: sourceMeta.versionSource,
@@ -14155,7 +11936,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
14155
11936
  workflowPack: buildWorkflowPackMetadata(plan.enabledAddons ?? []),
14156
11937
  assets
14157
11938
  };
14158
- await mkdir5(manifestDir, { recursive: true });
11939
+ await mkdir4(manifestDir, { recursive: true });
14159
11940
  await writeFileAtomic(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
14160
11941
  return manifest;
14161
11942
  }
@@ -14176,12 +11957,12 @@ async function applyInitPlan(plan, options) {
14176
11957
  skipped++;
14177
11958
  continue;
14178
11959
  }
14179
- if (existsSync18(op.path) && !op.destructive) {
11960
+ if (existsSync15(op.path) && !op.destructive) {
14180
11961
  skipped++;
14181
11962
  continue;
14182
11963
  }
14183
11964
  const dir = path5.dirname(op.path);
14184
- await mkdir5(dir, { recursive: true });
11965
+ await mkdir4(dir, { recursive: true });
14185
11966
  await writeFileAtomic(op.path, op.content ?? "");
14186
11967
  applied++;
14187
11968
  break;
@@ -14191,7 +11972,7 @@ async function applyInitPlan(plan, options) {
14191
11972
  skipped++;
14192
11973
  continue;
14193
11974
  }
14194
- if (existsSync18(op.path)) {
11975
+ if (existsSync15(op.path)) {
14195
11976
  skipped++;
14196
11977
  continue;
14197
11978
  }
@@ -14200,7 +11981,7 @@ async function applyInitPlan(plan, options) {
14200
11981
  skipped++;
14201
11982
  } else {
14202
11983
  const dir = path5.dirname(op.path);
14203
- await mkdir5(dir, { recursive: true });
11984
+ await mkdir4(dir, { recursive: true });
14204
11985
  await copyFile(op.sourcePath, op.path);
14205
11986
  applied++;
14206
11987
  }
@@ -14220,12 +12001,12 @@ async function applyInitPlan(plan, options) {
14220
12001
  skipped++;
14221
12002
  continue;
14222
12003
  }
14223
- if (existsSync18(op.path)) {
12004
+ if (existsSync15(op.path)) {
14224
12005
  skipped++;
14225
12006
  continue;
14226
12007
  }
14227
12008
  const dir = path5.dirname(op.path);
14228
- await mkdir5(dir, { recursive: true });
12009
+ await mkdir4(dir, { recursive: true });
14229
12010
  await rename(op.sourcePath, op.path);
14230
12011
  applied++;
14231
12012
  break;
@@ -14364,7 +12145,7 @@ async function applyInitFromSource(options) {
14364
12145
  if (!manifestSkipped) {
14365
12146
  const agentFiles = [];
14366
12147
  for (const name of ["AGENTS.md", "CLAUDE.md"]) {
14367
- if (existsSync18(path5.join(targetRoot, name))) {
12148
+ if (existsSync15(path5.join(targetRoot, name))) {
14368
12149
  agentFiles.push(path5.join(targetRoot, name));
14369
12150
  }
14370
12151
  }
@@ -14540,18 +12321,18 @@ Init applied: ${result.applied} operations applied, ${result.skipped} skipped.`
14540
12321
  }
14541
12322
 
14542
12323
  // commands/memory-init.ts
14543
- import { existsSync as existsSync19, mkdirSync as mkdirSync9, readFileSync as readFileSync20, writeFileSync as writeFileSync7 } from "fs";
14544
- import { join as join22 } from "path";
12324
+ import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync5 } from "fs";
12325
+ import { join as join17 } from "path";
14545
12326
  async function runMemoryInitCommand(options) {
14546
12327
  const cwd = options.cwd ?? process.cwd();
14547
- const configPath = join22(cwd, ".pourkit", "config.json");
14548
- if (!existsSync19(configPath)) {
12328
+ const configPath = join17(cwd, ".pourkit", "config.json");
12329
+ if (!existsSync16(configPath)) {
14549
12330
  return {
14550
12331
  ok: false,
14551
12332
  message: "No .pourkit/config.json found. Run `pourkit init` first to initialize Pourkit, then run `pourkit memory init`."
14552
12333
  };
14553
12334
  }
14554
- const raw = JSON.parse(readFileSync20(configPath, "utf8"));
12335
+ const raw = JSON.parse(readFileSync17(configPath, "utf8"));
14555
12336
  let alreadyEnabled = false;
14556
12337
  if (Object.prototype.hasOwnProperty.call(raw, "memory")) {
14557
12338
  const m = raw.memory;
@@ -14574,10 +12355,10 @@ async function runMemoryInitCommand(options) {
14574
12355
  const memory = { enabled: true, provider: "icm" };
14575
12356
  if (!alreadyEnabled) {
14576
12357
  const next = { ...raw, memory };
14577
- writeFileSync7(configPath, JSON.stringify(next, null, 2) + "\n");
12358
+ writeFileSync5(configPath, JSON.stringify(next, null, 2) + "\n");
14578
12359
  }
14579
- mkdirSync9(join22(cwd, ".pourkit", "icm"), { recursive: true });
14580
- const gitignorePath = join22(cwd, ".gitignore");
12360
+ mkdirSync8(join17(cwd, ".pourkit", "icm"), { recursive: true });
12361
+ const gitignorePath = join17(cwd, ".gitignore");
14581
12362
  updateManagedBlockSync(gitignorePath, generateGitignoreBlock());
14582
12363
  const managed = await generateManagedAgentInstructions({
14583
12364
  sourceRoot: cwd,
@@ -14585,14 +12366,14 @@ async function runMemoryInitCommand(options) {
14585
12366
  });
14586
12367
  let updatedAgentFile = false;
14587
12368
  for (const fileName of ["AGENTS.md", "CLAUDE.md"]) {
14588
- const agentPath = join22(cwd, fileName);
14589
- if (existsSync19(agentPath)) {
12369
+ const agentPath = join17(cwd, fileName);
12370
+ if (existsSync16(agentPath)) {
14590
12371
  updateManagedBlockSync(agentPath, managed);
14591
12372
  updatedAgentFile = true;
14592
12373
  }
14593
12374
  }
14594
12375
  if (!updatedAgentFile) {
14595
- updateManagedBlockSync(join22(cwd, "AGENTS.md"), managed);
12376
+ updateManagedBlockSync(join17(cwd, "AGENTS.md"), managed);
14596
12377
  }
14597
12378
  return {
14598
12379
  ok: true,
@@ -14604,21 +12385,21 @@ function updateManagedBlockSync(filePath, content) {
14604
12385
  const blockContent = `${MANAGED_BLOCK_BEGIN}
14605
12386
  ${content}${MANAGED_BLOCK_END}
14606
12387
  `;
14607
- if (!existsSync19(filePath)) {
14608
- writeFileSync7(filePath, blockContent);
12388
+ if (!existsSync16(filePath)) {
12389
+ writeFileSync5(filePath, blockContent);
14609
12390
  return;
14610
12391
  }
14611
- const existing = readFileSync20(filePath, "utf8");
12392
+ const existing = readFileSync17(filePath, "utf8");
14612
12393
  const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN);
14613
12394
  const endIdx = existing.indexOf(MANAGED_BLOCK_END);
14614
12395
  if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
14615
12396
  const before = existing.slice(0, beginIdx);
14616
12397
  const after = existing.slice(endIdx + MANAGED_BLOCK_END.length);
14617
- writeFileSync7(filePath, before + blockContent + after);
12398
+ writeFileSync5(filePath, before + blockContent + after);
14618
12399
  return;
14619
12400
  }
14620
12401
  const suffix = existing.endsWith("\n") ? "" : "\n";
14621
- writeFileSync7(filePath, `${existing}${suffix}${blockContent}`);
12402
+ writeFileSync5(filePath, `${existing}${suffix}${blockContent}`);
14622
12403
  }
14623
12404
 
14624
12405
  // commands/serena.ts
@@ -14737,8 +12518,8 @@ async function runSerenaStatusCommand(options) {
14737
12518
  }
14738
12519
 
14739
12520
  // commands/config-schema.ts
14740
- import { readFileSync as readFileSync21, existsSync as existsSync20 } from "fs";
14741
- import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
12521
+ import { readFileSync as readFileSync18, existsSync as existsSync17 } from "fs";
12522
+ import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile2, readdir as readdir2 } from "fs/promises";
14742
12523
  import { resolve as resolve4, dirname as dirname5, relative as relative2 } from "path";
14743
12524
  import { fileURLToPath as fileURLToPath3 } from "url";
14744
12525
  import Ajv2 from "ajv";
@@ -14750,7 +12531,7 @@ function resolvePackagedAssetPath2(fileName) {
14750
12531
  resolve4(__dirname3, "schema", fileName),
14751
12532
  resolve4(__dirname3, "../schema", fileName)
14752
12533
  ];
14753
- return candidates.find((candidate) => existsSync20(candidate)) ?? candidates[0];
12534
+ return candidates.find((candidate) => existsSync17(candidate)) ?? candidates[0];
14754
12535
  }
14755
12536
  var PACKAGED_SCHEMA_PATH = resolvePackagedAssetPath2("pourkit.schema.json");
14756
12537
  var PACKAGED_HASH_PATH = resolvePackagedAssetPath2("pourkit.schema.hash");
@@ -14758,7 +12539,7 @@ var _schemaValidator = null;
14758
12539
  var _schemaErrors = null;
14759
12540
  function getSchemaValidator() {
14760
12541
  if (!_schemaValidator) {
14761
- const schema = JSON.parse(readFileSync21(PACKAGED_SCHEMA_PATH, "utf-8"));
12542
+ const schema = JSON.parse(readFileSync18(PACKAGED_SCHEMA_PATH, "utf-8"));
14762
12543
  const ajv = new Ajv2({ strict: true });
14763
12544
  ajv.addKeyword("x-pourkit-schema-version");
14764
12545
  const validate = ajv.compile(schema);
@@ -14772,7 +12553,7 @@ function getSchemaValidator() {
14772
12553
  return _schemaValidator;
14773
12554
  }
14774
12555
  function readPackagedHash() {
14775
- return readFileSync21(PACKAGED_HASH_PATH, "utf-8");
12556
+ return readFileSync18(PACKAGED_HASH_PATH, "utf-8");
14776
12557
  }
14777
12558
  function localSchemaDir(repoRoot2) {
14778
12559
  return resolve4(repoRoot2, ".pourkit/schema");
@@ -14796,7 +12577,7 @@ function resolvePackagedReleaseAddonDocPath(docName) {
14796
12577
  }
14797
12578
  async function readPackagedTextFile(filePath) {
14798
12579
  try {
14799
- return await readFile6(filePath, "utf-8");
12580
+ return await readFile5(filePath, "utf-8");
14800
12581
  } catch {
14801
12582
  return null;
14802
12583
  }
@@ -14893,7 +12674,7 @@ async function validateWorkflowPack(cwd) {
14893
12674
  const baselineSkills = getBaselineManagedSkillNames();
14894
12675
  for (const docName of catalog.docs) {
14895
12676
  const localPath = resolve4(cwd, `.pourkit/managed/docs/agents/${docName}`);
14896
- if (!existsSync20(localPath)) {
12677
+ if (!existsSync17(localPath)) {
14897
12678
  failures.push({
14898
12679
  severity: "failure",
14899
12680
  kind: "missing_managed_asset",
@@ -14905,13 +12686,13 @@ async function validateWorkflowPack(cwd) {
14905
12686
  const packagedContent = await readPackagedTextFile(packagedPath);
14906
12687
  if (packagedContent !== null) {
14907
12688
  try {
14908
- const localContent = await readFile6(localPath, "utf-8");
12689
+ const localContent = await readFile5(localPath, "utf-8");
14909
12690
  if (localContent !== packagedContent) {
14910
12691
  const overridePath = resolve4(
14911
12692
  cwd,
14912
12693
  `.pourkit/overrides/docs/agents/${docName}`
14913
12694
  );
14914
- if (existsSync20(overridePath)) {
12695
+ if (existsSync17(overridePath)) {
14915
12696
  warnings.push({
14916
12697
  severity: "warning",
14917
12698
  kind: "overridden",
@@ -14934,7 +12715,7 @@ async function validateWorkflowPack(cwd) {
14934
12715
  }
14935
12716
  for (const skillName of baselineSkills) {
14936
12717
  const skillDir = resolve4(cwd, `.pourkit/managed/skills/${skillName}`);
14937
- if (!existsSync20(skillDir)) {
12718
+ if (!existsSync17(skillDir)) {
14938
12719
  failures.push({
14939
12720
  severity: "failure",
14940
12721
  kind: "missing_managed_asset",
@@ -14943,7 +12724,7 @@ async function validateWorkflowPack(cwd) {
14943
12724
  });
14944
12725
  } else {
14945
12726
  const skillSourcePath = resolve4(skillDir, "SKILL.md");
14946
- if (existsSync20(skillSourcePath)) {
12727
+ if (existsSync17(skillSourcePath)) {
14947
12728
  const packagedSkillPath = resolvePackagedManagedPath(
14948
12729
  "skills",
14949
12730
  skillName,
@@ -14952,13 +12733,13 @@ async function validateWorkflowPack(cwd) {
14952
12733
  const packagedContent = await readPackagedTextFile(packagedSkillPath);
14953
12734
  if (packagedContent !== null) {
14954
12735
  try {
14955
- const localContent = await readFile6(skillSourcePath, "utf-8");
12736
+ const localContent = await readFile5(skillSourcePath, "utf-8");
14956
12737
  if (localContent !== packagedContent) {
14957
12738
  const overridePath = resolve4(
14958
12739
  cwd,
14959
12740
  `.pourkit/overrides/skills/${skillName}/SKILL.md`
14960
12741
  );
14961
- if (existsSync20(overridePath)) {
12742
+ if (existsSync17(overridePath)) {
14962
12743
  warnings.push({
14963
12744
  severity: "warning",
14964
12745
  kind: "overridden",
@@ -14982,7 +12763,7 @@ async function validateWorkflowPack(cwd) {
14982
12763
  }
14983
12764
  for (const promptName of catalog.prompts) {
14984
12765
  const promptPath = resolve4(cwd, `.pourkit/managed/prompts/${promptName}`);
14985
- if (!existsSync20(promptPath)) {
12766
+ if (!existsSync17(promptPath)) {
14986
12767
  failures.push({
14987
12768
  severity: "failure",
14988
12769
  kind: "missing_managed_asset",
@@ -14993,7 +12774,7 @@ async function validateWorkflowPack(cwd) {
14993
12774
  }
14994
12775
  for (const skillName of baselineSkills) {
14995
12776
  const projectionDir = resolve4(cwd, `.agents/skills/${skillName}`);
14996
- if (!existsSync20(projectionDir)) {
12777
+ if (!existsSync17(projectionDir)) {
14997
12778
  warnings.push({
14998
12779
  severity: "warning",
14999
12780
  kind: "projection_stale",
@@ -15002,7 +12783,7 @@ async function validateWorkflowPack(cwd) {
15002
12783
  });
15003
12784
  } else {
15004
12785
  const projectionPath = resolve4(projectionDir, "SKILL.md");
15005
- if (existsSync20(projectionPath)) {
12786
+ if (existsSync17(projectionPath)) {
15006
12787
  const managedSourcePath = resolvePackagedManagedPath(
15007
12788
  "skills",
15008
12789
  skillName,
@@ -15011,7 +12792,7 @@ async function validateWorkflowPack(cwd) {
15011
12792
  const packagedContent = await readPackagedTextFile(managedSourcePath);
15012
12793
  if (packagedContent !== null) {
15013
12794
  try {
15014
- const projectionContent = await readFile6(projectionPath, "utf-8");
12795
+ const projectionContent = await readFile5(projectionPath, "utf-8");
15015
12796
  const managedSourceRelativePath = `.pourkit/managed/skills/${skillName}/SKILL.md`;
15016
12797
  if (projectionContent !== buildOpenCodeSkillProjectionContent(
15017
12798
  managedSourceRelativePath,
@@ -15031,9 +12812,9 @@ async function validateWorkflowPack(cwd) {
15031
12812
  }
15032
12813
  }
15033
12814
  const agentsPath = resolve4(cwd, "AGENTS.md");
15034
- if (existsSync20(agentsPath)) {
12815
+ if (existsSync17(agentsPath)) {
15035
12816
  try {
15036
- const agentsContent = await readFile6(agentsPath, "utf-8");
12817
+ const agentsContent = await readFile5(agentsPath, "utf-8");
15037
12818
  if (agentsContent.includes(OLD_DOCS_PATH_PATTERN)) {
15038
12819
  failures.push({
15039
12820
  severity: "failure",
@@ -15054,7 +12835,7 @@ async function validateWorkflowPack(cwd) {
15054
12835
  }
15055
12836
  }
15056
12837
  const overridesDir = resolve4(cwd, ".pourkit/overrides");
15057
- if (existsSync20(overridesDir)) {
12838
+ if (existsSync17(overridesDir)) {
15058
12839
  const overrideFiles = await walkDir2(overridesDir);
15059
12840
  for (const file of overrideFiles) {
15060
12841
  const relPath = relative2(cwd, file);
@@ -15069,9 +12850,9 @@ async function validateWorkflowPack(cwd) {
15069
12850
  }
15070
12851
  }
15071
12852
  const configPath = resolve4(cwd, ".pourkit/config.json");
15072
- if (existsSync20(configPath)) {
12853
+ if (existsSync17(configPath)) {
15073
12854
  try {
15074
- const configContent = await readFile6(configPath, "utf-8");
12855
+ const configContent = await readFile5(configPath, "utf-8");
15075
12856
  const parsed = JSON.parse(configContent);
15076
12857
  const releaseEnabled = parsed.releaseWorkflow?.enabled === true;
15077
12858
  if (releaseEnabled) {
@@ -15080,7 +12861,7 @@ async function validateWorkflowPack(cwd) {
15080
12861
  cwd,
15081
12862
  `.pourkit/managed/addons/release/skills/${skillName}`
15082
12863
  );
15083
- if (!existsSync20(addonDir)) {
12864
+ if (!existsSync17(addonDir)) {
15084
12865
  failures.push({
15085
12866
  severity: "failure",
15086
12867
  kind: "release_config_conflict",
@@ -15094,7 +12875,7 @@ async function validateWorkflowPack(cwd) {
15094
12875
  cwd,
15095
12876
  `.pourkit/managed/addons/release/docs/agents/${docName}`
15096
12877
  );
15097
- if (!existsSync20(addonDocPath)) {
12878
+ if (!existsSync17(addonDocPath)) {
15098
12879
  failures.push({
15099
12880
  severity: "failure",
15100
12881
  kind: "release_config_conflict",
@@ -15106,7 +12887,7 @@ async function validateWorkflowPack(cwd) {
15106
12887
  resolvePackagedReleaseAddonDocPath(docName)
15107
12888
  );
15108
12889
  if (packagedContent !== null) {
15109
- const localContent = await readFile6(addonDocPath, "utf-8");
12890
+ const localContent = await readFile5(addonDocPath, "utf-8");
15110
12891
  if (localContent !== packagedContent) {
15111
12892
  failures.push({
15112
12893
  severity: "failure",
@@ -15139,7 +12920,7 @@ async function validateWorkflowPack(cwd) {
15139
12920
  cwd,
15140
12921
  `.pourkit/managed/addons/release/skills/${skillName}`
15141
12922
  );
15142
- if (existsSync20(addonDir)) {
12923
+ if (existsSync17(addonDir)) {
15143
12924
  failures.push({
15144
12925
  severity: "failure",
15145
12926
  kind: "release_config_conflict",
@@ -15153,7 +12934,7 @@ async function validateWorkflowPack(cwd) {
15153
12934
  cwd,
15154
12935
  `.pourkit/managed/addons/release/docs/agents/${docName}`
15155
12936
  );
15156
- if (existsSync20(addonDocPath)) {
12937
+ if (existsSync17(addonDocPath)) {
15157
12938
  failures.push({
15158
12939
  severity: "failure",
15159
12940
  kind: "release_config_conflict",
@@ -15167,9 +12948,9 @@ async function validateWorkflowPack(cwd) {
15167
12948
  }
15168
12949
  }
15169
12950
  const manifestPath = resolve4(cwd, ".pourkit/manifest.json");
15170
- if (existsSync20(manifestPath)) {
12951
+ if (existsSync17(manifestPath)) {
15171
12952
  try {
15172
- const manifestContent = await readFile6(manifestPath, "utf-8");
12953
+ const manifestContent = await readFile5(manifestPath, "utf-8");
15173
12954
  const manifest = JSON.parse(manifestContent);
15174
12955
  const wp = manifest.workflowPack;
15175
12956
  if (wp?.projections) {
@@ -15190,7 +12971,7 @@ async function validateWorkflowPack(cwd) {
15190
12971
  }
15191
12972
  }
15192
12973
  const pathEscapeOverrideDir = resolve4(cwd, ".pourkit/overrides");
15193
- if (existsSync20(pathEscapeOverrideDir)) {
12974
+ if (existsSync17(pathEscapeOverrideDir)) {
15194
12975
  const overrideFiles = await walkDir2(pathEscapeOverrideDir);
15195
12976
  for (const file of overrideFiles) {
15196
12977
  if (!isPathContained(cwd, file)) {
@@ -15204,12 +12985,12 @@ async function validateWorkflowPack(cwd) {
15204
12985
  }
15205
12986
  }
15206
12987
  const managedDocsDir = resolve4(cwd, ".pourkit/managed/docs/agents");
15207
- if (existsSync20(managedDocsDir)) {
12988
+ if (existsSync17(managedDocsDir)) {
15208
12989
  const docFiles = await walkDir2(managedDocsDir);
15209
12990
  for (const file of docFiles) {
15210
12991
  if (!file.endsWith(".md")) continue;
15211
12992
  try {
15212
- const content = await readFile6(file, "utf-8");
12993
+ const content = await readFile5(file, "utf-8");
15213
12994
  const relPath = relative2(cwd, file);
15214
12995
  const violations = scanManagedPolicyText(content, relPath);
15215
12996
  for (const v of violations) {
@@ -15225,14 +13006,14 @@ async function validateWorkflowPack(cwd) {
15225
13006
  }
15226
13007
  }
15227
13008
  const managedSkillsDir = resolve4(cwd, ".pourkit/managed/skills");
15228
- if (existsSync20(managedSkillsDir)) {
13009
+ if (existsSync17(managedSkillsDir)) {
15229
13010
  const skillDirs = await readdir2(managedSkillsDir, { withFileTypes: true });
15230
13011
  for (const entry of skillDirs) {
15231
13012
  if (!entry.isDirectory()) continue;
15232
13013
  const skillFile = resolve4(managedSkillsDir, entry.name, "SKILL.md");
15233
- if (!existsSync20(skillFile)) continue;
13014
+ if (!existsSync17(skillFile)) continue;
15234
13015
  try {
15235
- const content = await readFile6(skillFile, "utf-8");
13016
+ const content = await readFile5(skillFile, "utf-8");
15236
13017
  const relPath = relative2(cwd, skillFile);
15237
13018
  const violations = scanManagedPolicyText(content, relPath);
15238
13019
  for (const v of violations) {
@@ -15248,12 +13029,12 @@ async function validateWorkflowPack(cwd) {
15248
13029
  }
15249
13030
  }
15250
13031
  const managedPromptsDir = resolve4(cwd, ".pourkit/managed/prompts");
15251
- if (existsSync20(managedPromptsDir)) {
13032
+ if (existsSync17(managedPromptsDir)) {
15252
13033
  for (const promptName of catalog.prompts) {
15253
13034
  const promptFile = resolve4(managedPromptsDir, promptName);
15254
- if (!existsSync20(promptFile)) continue;
13035
+ if (!existsSync17(promptFile)) continue;
15255
13036
  try {
15256
- const content = await readFile6(promptFile, "utf-8");
13037
+ const content = await readFile5(promptFile, "utf-8");
15257
13038
  const relPath = relative2(cwd, promptFile);
15258
13039
  const violations = scanManagedPolicyText(content, relPath);
15259
13040
  for (const v of violations) {
@@ -15273,9 +13054,9 @@ async function validateWorkflowPack(cwd) {
15273
13054
  cwd,
15274
13055
  `.pourkit/managed/addons/release/skills/${skillName}/SKILL.md`
15275
13056
  );
15276
- if (!existsSync20(addonSkillFile)) continue;
13057
+ if (!existsSync17(addonSkillFile)) continue;
15277
13058
  try {
15278
- const content = await readFile6(addonSkillFile, "utf-8");
13059
+ const content = await readFile5(addonSkillFile, "utf-8");
15279
13060
  const relPath = relative2(cwd, addonSkillFile);
15280
13061
  const violations = scanManagedPolicyText(content, relPath);
15281
13062
  for (const v of violations) {
@@ -15294,9 +13075,9 @@ async function validateWorkflowPack(cwd) {
15294
13075
  cwd,
15295
13076
  `.pourkit/managed/addons/release/docs/agents/${docName}`
15296
13077
  );
15297
- if (!existsSync20(addonDocFile)) continue;
13078
+ if (!existsSync17(addonDocFile)) continue;
15298
13079
  try {
15299
- const content = await readFile6(addonDocFile, "utf-8");
13080
+ const content = await readFile5(addonDocFile, "utf-8");
15300
13081
  const relPath = relative2(cwd, addonDocFile);
15301
13082
  const violations = scanManagedPolicyText(content, relPath);
15302
13083
  for (const v of violations) {
@@ -15328,7 +13109,7 @@ async function validateMemoryHealth(cwd, memoryConfig) {
15328
13109
  detail: icmPath !== null ? icmPath : "icm not found on PATH"
15329
13110
  });
15330
13111
  const gitignorePath = resolve4(cwd, ".gitignore");
15331
- const gitignoreContent = existsSync20(gitignorePath) ? readFileSync21(gitignorePath, "utf-8") : "";
13112
+ const gitignoreContent = existsSync17(gitignorePath) ? readFileSync18(gitignorePath, "utf-8") : "";
15332
13113
  const hasGitignoreEntry = gitignoreContent.includes(".pourkit/icm/");
15333
13114
  checks.push({
15334
13115
  name: "icm-gitignore",
@@ -15355,8 +13136,8 @@ async function runDoctorCommand(options) {
15355
13136
  const schemaDir = localSchemaDir(repoRootPath);
15356
13137
  const localSchemaPath = resolve4(schemaDir, "pourkit.schema.json");
15357
13138
  const localHashPath = resolve4(schemaDir, "pourkit.schema.hash");
15358
- const localSchemaExists = existsSync20(localSchemaPath);
15359
- const localHashExists = existsSync20(localHashPath);
13139
+ const localSchemaExists = existsSync17(localSchemaPath);
13140
+ const localHashExists = existsSync17(localHashPath);
15360
13141
  let packagedHash = null;
15361
13142
  try {
15362
13143
  packagedHash = readPackagedHash();
@@ -15365,7 +13146,7 @@ async function runDoctorCommand(options) {
15365
13146
  let localHashContent = null;
15366
13147
  if (localHashExists) {
15367
13148
  try {
15368
- localHashContent = await readFile6(localHashPath, "utf-8");
13149
+ localHashContent = await readFile5(localHashPath, "utf-8");
15369
13150
  } catch {
15370
13151
  }
15371
13152
  }
@@ -15375,9 +13156,9 @@ async function runDoctorCommand(options) {
15375
13156
  const configPath = resolve4(repoRootPath, ".pourkit/config.json");
15376
13157
  let configValidation;
15377
13158
  let rawMemoryConfig;
15378
- if (existsSync20(configPath)) {
13159
+ if (existsSync17(configPath)) {
15379
13160
  try {
15380
- const raw = JSON.parse(readFileSync21(configPath, "utf-8"));
13161
+ const raw = JSON.parse(readFileSync18(configPath, "utf-8"));
15381
13162
  rawMemoryConfig = raw.memory;
15382
13163
  const validate = getSchemaValidator();
15383
13164
  const valid2 = validate(raw);
@@ -15410,7 +13191,7 @@ async function runDoctorCommand(options) {
15410
13191
  "pourkit.config.mjs",
15411
13192
  "pourkit.config.js",
15412
13193
  "pourkit.json"
15413
- ].filter((p) => existsSync20(resolve4(repoRootPath, p)));
13194
+ ].filter((p) => existsSync17(resolve4(repoRootPath, p)));
15414
13195
  const workflowPack = await validateWorkflowPack(repoRootPath);
15415
13196
  const memory = await validateMemoryHealth(repoRootPath, rawMemoryConfig);
15416
13197
  let recommendation = null;
@@ -15453,31 +13234,31 @@ async function runDoctorCommand(options) {
15453
13234
  async function runConfigSyncSchemaCommand(options) {
15454
13235
  const repoRootPath = options.cwd ?? process.cwd();
15455
13236
  const schemaDir = localSchemaDir(repoRootPath);
15456
- await mkdir6(schemaDir, { recursive: true });
15457
- const packagedSchema = await readFile6(PACKAGED_SCHEMA_PATH, "utf-8");
15458
- const packagedHash = await readFile6(PACKAGED_HASH_PATH, "utf-8");
13237
+ await mkdir5(schemaDir, { recursive: true });
13238
+ const packagedSchema = await readFile5(PACKAGED_SCHEMA_PATH, "utf-8");
13239
+ const packagedHash = await readFile5(PACKAGED_HASH_PATH, "utf-8");
15459
13240
  const localSchemaPath = resolve4(schemaDir, "pourkit.schema.json");
15460
13241
  const localHashPath = resolve4(schemaDir, "pourkit.schema.hash");
15461
13242
  let schemaWritten = false;
15462
13243
  let hashWritten = false;
15463
- if (existsSync20(localSchemaPath)) {
15464
- const existing = await readFile6(localSchemaPath, "utf-8");
13244
+ if (existsSync17(localSchemaPath)) {
13245
+ const existing = await readFile5(localSchemaPath, "utf-8");
15465
13246
  if (existing !== packagedSchema) {
15466
- await writeFile3(localSchemaPath, packagedSchema, "utf-8");
13247
+ await writeFile2(localSchemaPath, packagedSchema, "utf-8");
15467
13248
  schemaWritten = true;
15468
13249
  }
15469
13250
  } else {
15470
- await writeFile3(localSchemaPath, packagedSchema, "utf-8");
13251
+ await writeFile2(localSchemaPath, packagedSchema, "utf-8");
15471
13252
  schemaWritten = true;
15472
13253
  }
15473
- if (existsSync20(localHashPath)) {
15474
- const existing = await readFile6(localHashPath, "utf-8");
13254
+ if (existsSync17(localHashPath)) {
13255
+ const existing = await readFile5(localHashPath, "utf-8");
15475
13256
  if (existing !== packagedHash) {
15476
- await writeFile3(localHashPath, packagedHash, "utf-8");
13257
+ await writeFile2(localHashPath, packagedHash, "utf-8");
15477
13258
  hashWritten = true;
15478
13259
  }
15479
13260
  } else {
15480
- await writeFile3(localHashPath, packagedHash, "utf-8");
13261
+ await writeFile2(localHashPath, packagedHash, "utf-8");
15481
13262
  hashWritten = true;
15482
13263
  }
15483
13264
  return {
@@ -15488,8 +13269,8 @@ async function runConfigSyncSchemaCommand(options) {
15488
13269
  }
15489
13270
 
15490
13271
  // commands/workflow-pack-sync.ts
15491
- import { existsSync as existsSync21, readdirSync as readdirSync5 } from "fs";
15492
- import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile4, readdir as readdir3 } from "fs/promises";
13272
+ import { existsSync as existsSync18, readdirSync as readdirSync4 } from "fs";
13273
+ import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir3 } from "fs/promises";
15493
13274
  import { resolve as resolve5, dirname as dirname6, relative as relative3, normalize as normalize2 } from "path";
15494
13275
  import { fileURLToPath as fileURLToPath4 } from "url";
15495
13276
  var __filename4 = fileURLToPath4(import.meta.url);
@@ -15527,7 +13308,7 @@ function resolvePackagedManagedPromptPath(promptName) {
15527
13308
  }
15528
13309
  async function readPackagedTextFile2(filePath) {
15529
13310
  try {
15530
- return await readFile7(filePath, "utf-8");
13311
+ return await readFile6(filePath, "utf-8");
15531
13312
  } catch {
15532
13313
  return null;
15533
13314
  }
@@ -15610,20 +13391,20 @@ async function syncFile(cwd, targetRelativePath, sourceContent, errors) {
15610
13391
  errors.push(escapeError);
15611
13392
  return false;
15612
13393
  }
15613
- await mkdir7(resolve5(targetPath, ".."), { recursive: true });
15614
- if (existsSync21(targetPath)) {
15615
- const existing = await readFile7(targetPath, "utf-8");
13394
+ await mkdir6(resolve5(targetPath, ".."), { recursive: true });
13395
+ if (existsSync18(targetPath)) {
13396
+ const existing = await readFile6(targetPath, "utf-8");
15616
13397
  if (existing === sourceContent) {
15617
13398
  return false;
15618
13399
  }
15619
13400
  }
15620
- await writeFile4(targetPath, sourceContent, "utf-8");
13401
+ await writeFile3(targetPath, sourceContent, "utf-8");
15621
13402
  return true;
15622
13403
  }
15623
13404
  function walkDirSync(dir) {
15624
13405
  const result = [];
15625
13406
  try {
15626
- const entries = readdirSync5(dir, { withFileTypes: true });
13407
+ const entries = readdirSync4(dir, { withFileTypes: true });
15627
13408
  for (const entry of entries) {
15628
13409
  const full = resolve5(dir, entry.name);
15629
13410
  if (entry.isDirectory()) {
@@ -15638,7 +13419,7 @@ function walkDirSync(dir) {
15638
13419
  }
15639
13420
  async function detectOverrides(cwd) {
15640
13421
  const overridesDir = resolve5(cwd, OVERRIDES_DIR);
15641
- if (!existsSync21(overridesDir)) {
13422
+ if (!existsSync18(overridesDir)) {
15642
13423
  return [];
15643
13424
  }
15644
13425
  const files = await walkDir3(overridesDir);
@@ -15648,13 +13429,13 @@ async function detectProjectOwnedFiles(cwd) {
15648
13429
  const found = [];
15649
13430
  for (const ownedPath of PROJECT_OWNED_PATHS) {
15650
13431
  const fullPath = resolve5(cwd, ownedPath);
15651
- if (existsSync21(fullPath)) {
13432
+ if (existsSync18(fullPath)) {
15652
13433
  found.push(ownedPath);
15653
13434
  }
15654
13435
  }
15655
13436
  for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
15656
13437
  const fullDir = resolve5(cwd, ownedDir);
15657
- if (existsSync21(fullDir)) {
13438
+ if (existsSync18(fullDir)) {
15658
13439
  const files = await walkDir3(fullDir);
15659
13440
  for (const file of files) {
15660
13441
  found.push(relative3(cwd, file));
@@ -15666,7 +13447,7 @@ async function detectProjectOwnedFiles(cwd) {
15666
13447
  async function isReleaseWorkflowEnabled(cwd) {
15667
13448
  try {
15668
13449
  const configPath = resolve5(cwd, ".pourkit", "config.json");
15669
- const content = await readFile7(configPath, "utf-8");
13450
+ const content = await readFile6(configPath, "utf-8");
15670
13451
  const parsed = JSON.parse(content);
15671
13452
  return parsed.releaseWorkflow?.enabled === true;
15672
13453
  } catch {
@@ -15806,12 +13587,12 @@ async function runWorkflowPackSyncCommand(options) {
15806
13587
  const fullManagedBlock = `${MANAGED_BLOCK_BEGIN3}${managedBlockContent}${MANAGED_BLOCK_END2}`;
15807
13588
  async function syncManagedAgentFile(fileName, options2) {
15808
13589
  const filePath = resolve5(cwd, fileName);
15809
- if (!existsSync21(filePath)) {
13590
+ if (!existsSync18(filePath)) {
15810
13591
  if (!options2.createIfMissing) return false;
15811
- await writeFile4(filePath, fullManagedBlock + "\n", "utf-8");
13592
+ await writeFile3(filePath, fullManagedBlock + "\n", "utf-8");
15812
13593
  return true;
15813
13594
  }
15814
- const existing = await readFile7(filePath, "utf-8");
13595
+ const existing = await readFile6(filePath, "utf-8");
15815
13596
  const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN3);
15816
13597
  const endIdx = existing.indexOf(MANAGED_BLOCK_END2);
15817
13598
  if (beginIdx !== -1 && endIdx !== -1) {
@@ -15819,7 +13600,7 @@ async function runWorkflowPackSyncCommand(options) {
15819
13600
  const afterBlock = existing.slice(endIdx + MANAGED_BLOCK_END2.length);
15820
13601
  const newContent = `${beforeBlock}${fullManagedBlock}${afterBlock}`;
15821
13602
  if (newContent !== existing) {
15822
- await writeFile4(filePath, newContent, "utf-8");
13603
+ await writeFile3(filePath, newContent, "utf-8");
15823
13604
  return true;
15824
13605
  }
15825
13606
  } else {
@@ -15828,7 +13609,7 @@ async function runWorkflowPackSyncCommand(options) {
15828
13609
  ${fullManagedBlock}
15829
13610
  `;
15830
13611
  if (newContent !== existing) {
15831
- await writeFile4(filePath, newContent, "utf-8");
13612
+ await writeFile3(filePath, newContent, "utf-8");
15832
13613
  return true;
15833
13614
  }
15834
13615
  }
@@ -15846,7 +13627,7 @@ ${fullManagedBlock}
15846
13627
  let manifestWritten = false;
15847
13628
  let previousManifestWorkflowPack = void 0;
15848
13629
  try {
15849
- const existingRaw = await readFile7(manifestPath, "utf-8").catch(() => null);
13630
+ const existingRaw = await readFile6(manifestPath, "utf-8").catch(() => null);
15850
13631
  if (existingRaw) {
15851
13632
  const existing = JSON.parse(existingRaw);
15852
13633
  previousManifestWorkflowPack = existing.workflowPack;
@@ -15855,13 +13636,13 @@ ${fullManagedBlock}
15855
13636
  }
15856
13637
  if (previousManifestWorkflowPack === void 0 || JSON.stringify(previousManifestWorkflowPack) !== JSON.stringify(manifestMeta)) {
15857
13638
  try {
15858
- const existingRaw = await readFile7(manifestPath, "utf-8").catch(
13639
+ const existingRaw = await readFile6(manifestPath, "utf-8").catch(
15859
13640
  () => null
15860
13641
  );
15861
13642
  let manifest = existingRaw ? JSON.parse(existingRaw) : {};
15862
13643
  manifest.workflowPack = manifestMeta;
15863
- await mkdir7(resolve5(manifestPath, ".."), { recursive: true });
15864
- await writeFile4(
13644
+ await mkdir6(resolve5(manifestPath, ".."), { recursive: true });
13645
+ await writeFile3(
15865
13646
  manifestPath,
15866
13647
  JSON.stringify(manifest, null, 2) + "\n",
15867
13648
  "utf-8"
@@ -16581,22 +14362,22 @@ function formatChecks2(checks) {
16581
14362
  init_common();
16582
14363
 
16583
14364
  // execution/sandcastle-execution.ts
16584
- import { existsSync as existsSync23, mkdirSync as mkdirSync10, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
16585
- import { join as join25 } from "path";
14365
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
14366
+ import { join as join20 } from "path";
16586
14367
  import { createWorktree, opencode } from "@ai-hero/sandcastle";
16587
14368
  import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
16588
14369
 
16589
14370
  // execution/execution-provider.ts
16590
14371
  init_common();
16591
14372
  import { mkdtempSync } from "fs";
16592
- import { writeFile as writeFile5 } from "fs/promises";
14373
+ import { writeFile as writeFile4 } from "fs/promises";
16593
14374
  import { tmpdir } from "os";
16594
- import { dirname as dirname7, join as join23 } from "path";
14375
+ import { dirname as dirname7, join as join18 } from "path";
16595
14376
  async function writeExecutionArtifacts(worktreePath, artifacts) {
16596
14377
  for (const artifact of artifacts) {
16597
- const filePath = join23(worktreePath, artifact.path);
14378
+ const filePath = join18(worktreePath, artifact.path);
16598
14379
  await ensureDir(dirname7(filePath));
16599
- await writeFile5(filePath, artifact.content, "utf-8");
14380
+ await writeFile4(filePath, artifact.content, "utf-8");
16600
14381
  }
16601
14382
  }
16602
14383
 
@@ -16608,19 +14389,19 @@ init_common();
16608
14389
  import path7 from "path";
16609
14390
 
16610
14391
  // execution/sandbox-image.ts
16611
- import { createHash as createHash3 } from "crypto";
16612
- import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
14392
+ import { createHash as createHash2 } from "crypto";
14393
+ import { existsSync as existsSync19, readFileSync as readFileSync19 } from "fs";
16613
14394
  import path6 from "path";
16614
14395
  function sandboxImageName(repoRoot2, installIcm) {
16615
14396
  const dirName = path6.basename(repoRoot2.replace(/[\\/]+$/, "")) || "local";
16616
14397
  const sanitized = dirName.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
16617
14398
  const baseName = sanitized || "local";
16618
14399
  const dockerfilePath = path6.join(repoRoot2, ".sandcastle", "Dockerfile");
16619
- if (!existsSync22(dockerfilePath)) {
14400
+ if (!existsSync19(dockerfilePath)) {
16620
14401
  const base2 = `sandcastle:${baseName}`;
16621
14402
  return installIcm ? `${base2}-icm` : base2;
16622
14403
  }
16623
- const fingerprint = createHash3("sha256").update(readFileSync22(dockerfilePath)).digest("hex").slice(0, 8);
14404
+ const fingerprint = createHash2("sha256").update(readFileSync19(dockerfilePath)).digest("hex").slice(0, 8);
16624
14405
  const base = `sandcastle:${baseName}-${fingerprint}`;
16625
14406
  return installIcm ? `${base}-icm` : base;
16626
14407
  }
@@ -16656,7 +14437,7 @@ async function createSandboxFromExistingWorktree(options) {
16656
14437
  }
16657
14438
 
16658
14439
  // execution/sandbox-options.ts
16659
- import { join as join24 } from "path";
14440
+ import { join as join19 } from "path";
16660
14441
  var POURKIT_ICM_CONTAINER_DIR = "/home/agent/.pourkit/icm";
16661
14442
  function buildSandboxOptions(repoRoot2, sandbox, memory) {
16662
14443
  const mounts = [];
@@ -16665,12 +14446,12 @@ function buildSandboxOptions(repoRoot2, sandbox, memory) {
16665
14446
  }
16666
14447
  if (memory?.available) {
16667
14448
  mounts.push({
16668
- hostPath: join24(repoRoot2, ".pourkit", "icm"),
14449
+ hostPath: join19(repoRoot2, ".pourkit", "icm"),
16669
14450
  sandboxPath: POURKIT_ICM_CONTAINER_DIR,
16670
14451
  readonly: false
16671
14452
  });
16672
14453
  mounts.push({
16673
- hostPath: join24(repoRoot2, ".pourkit", "icm", "cache"),
14454
+ hostPath: join19(repoRoot2, ".pourkit", "icm", "cache"),
16674
14455
  sandboxPath: "/home/agent/.cache/icm",
16675
14456
  readonly: false
16676
14457
  });
@@ -16804,13 +14585,13 @@ var SandcastleExecutionSession = class {
16804
14585
  "Memory enabled but memory context is invalid. Run `pourkit memory init` or install ICM for host planning use."
16805
14586
  );
16806
14587
  }
16807
- const hostMemoryDir = join25(repoRoot2, ".pourkit", "icm");
16808
- if (!existsSync23(hostMemoryDir) || !statSync2(hostMemoryDir).isDirectory()) {
14588
+ const hostMemoryDir = join20(repoRoot2, ".pourkit", "icm");
14589
+ if (!existsSync20(hostMemoryDir) || !statSync2(hostMemoryDir).isDirectory()) {
16809
14590
  throw new MissingHostMemoryDirError(
16810
14591
  "Memory enabled but host .pourkit/icm/ directory is missing. Run `pourkit memory init` to create the repo-scoped memory store."
16811
14592
  );
16812
14593
  }
16813
- mkdirSync10(join25(hostMemoryDir, "cache"), { recursive: true });
14594
+ mkdirSync9(join20(hostMemoryDir, "cache"), { recursive: true });
16814
14595
  }
16815
14596
  const sandboxOptions = buildSandboxOptions(
16816
14597
  repoRoot2,
@@ -16969,8 +14750,8 @@ function sanitizeBranch(branchName) {
16969
14750
  }
16970
14751
  function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
16971
14752
  return paths.filter((relativePath) => {
16972
- const source = join25(repoRoot2, relativePath);
16973
- if (!existsSync23(source)) {
14753
+ const source = join20(repoRoot2, relativePath);
14754
+ if (!existsSync20(source)) {
16974
14755
  return true;
16975
14756
  }
16976
14757
  try {
@@ -16980,8 +14761,8 @@ function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
16980
14761
  } catch {
16981
14762
  return true;
16982
14763
  }
16983
- const destination = join25(worktreePath, relativePath);
16984
- return !existsSync23(destination);
14764
+ const destination = join20(worktreePath, relativePath);
14765
+ return !existsSync20(destination);
16985
14766
  });
16986
14767
  }
16987
14768
  function formatAgentStreamEvent(event) {
@@ -17045,13 +14826,13 @@ function isPlainObject(value) {
17045
14826
  return typeof value === "object" && value !== null && !Array.isArray(value);
17046
14827
  }
17047
14828
  function savePromptToFile(repoRoot2, stage, iteration, prompt) {
17048
- const promptsDir = join25(repoRoot2, ".pourkit", ".tmp", "prompts");
17049
- mkdirSync10(promptsDir, { recursive: true });
14829
+ const promptsDir = join20(repoRoot2, ".pourkit", ".tmp", "prompts");
14830
+ mkdirSync9(promptsDir, { recursive: true });
17050
14831
  const timestamp2 = Date.now();
17051
14832
  const iterationSuffix = iteration !== void 0 ? `-iteration-${iteration}` : "";
17052
14833
  const filename = `${stage}${iterationSuffix}-${timestamp2}.md`;
17053
- const filePath = join25(promptsDir, filename);
17054
- writeFileSync8(filePath, prompt, "utf-8");
14834
+ const filePath = join20(promptsDir, filename);
14835
+ writeFileSync6(filePath, prompt, "utf-8");
17055
14836
  }
17056
14837
 
17057
14838
  // cli.ts
@@ -17151,8 +14932,8 @@ function createCliProgram(version) {
17151
14932
  });
17152
14933
  program.command("validate-artifact").description("Validate an agent handoff artifact").argument(
17153
14934
  "<kind>",
17154
- "artifact kind: reviewer, refactor, finalizer, conflict-resolution, failure-resolution, local-prd, local-issue, local-triage, or issue-final-review"
17155
- ).argument("<artifactPath>", "artifact path to validate").argument("[extraPaths...]", "additional artifact paths (for local-triage)").option("--iteration <number>", "review/refactor iteration", (value) => {
14935
+ "artifact kind: reviewer, refactor, finalizer, conflict-resolution, failure-resolution, or issue-final-review"
14936
+ ).argument("<artifactPath>", "artifact path to validate").argument("[extraPaths...]", "unused compatibility argument").option("--iteration <number>", "review/refactor iteration", (value) => {
17156
14937
  const parsed = Number.parseInt(value, 10);
17157
14938
  if (!Number.isInteger(parsed) || parsed < 1) {
17158
14939
  throw new CommanderError(
@@ -17205,16 +14986,13 @@ function createCliProgram(version) {
17205
14986
  "--base-ref <ref>",
17206
14987
  "canonical base ref for issue-final-review changedFiles coverage validation"
17207
14988
  ).option("--no-check-conflict-markers", "skip conflict marker scan").option("--cwd <path>", "target repository directory").action(
17208
- (kind, artifactPath, extraPaths, options) => {
14989
+ (kind, artifactPath, _extraPaths, options) => {
17209
14990
  const allowedKinds = /* @__PURE__ */ new Set([
17210
14991
  "reviewer",
17211
14992
  "refactor",
17212
14993
  "finalizer",
17213
14994
  "conflict-resolution",
17214
14995
  "failure-resolution",
17215
- "local-prd",
17216
- "local-issue",
17217
- "local-triage",
17218
14996
  "issue-final-review"
17219
14997
  ]);
17220
14998
  if (!allowedKinds.has(kind)) {
@@ -17224,18 +15002,8 @@ function createCliProgram(version) {
17224
15002
  `Unsupported artifact kind "${kind}"`
17225
15003
  );
17226
15004
  }
17227
- const LOCAL_KINDS = /* @__PURE__ */ new Set([
17228
- "local-prd",
17229
- "local-issue",
17230
- "local-triage"
17231
- ]);
17232
15005
  const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
17233
- const result = LOCAL_KINDS.has(kind) ? runLocalValidateArtifactCommand({
17234
- repoRoot: targetRepoRoot,
17235
- kind,
17236
- artifactPath,
17237
- extraArgs: extraPaths
17238
- }) : runValidateArtifactCommand({
15006
+ const result = runValidateArtifactCommand({
17239
15007
  repoRoot: targetRepoRoot,
17240
15008
  kind,
17241
15009
  artifactPath,
@@ -17518,15 +15286,14 @@ function createCliProgram(version) {
17518
15286
  const logger = createLogger("pourkit", logPath);
17519
15287
  try {
17520
15288
  const config = await loadRepoConfig(targetRepoRoot);
17521
- const target = resolveTarget(config, options.target);
17522
- const mode = resolvePrdRunMode(target).mode;
17523
- const client = mode === "local" ? void 0 : await requireGitHubClient({ cwd: targetRepoRoot });
17524
- const issueProvider = client ? new GitHubIssueProvider(client, {
15289
+ resolveTarget(config, options.target);
15290
+ const client = await requireGitHubClient({ cwd: targetRepoRoot });
15291
+ const issueProvider = new GitHubIssueProvider(client, {
17525
15292
  readyForAgentLabel: config.labels.readyForAgent,
17526
15293
  blockedLabel: config.labels.blocked,
17527
15294
  issueListLimit: config.checks.issueListLimit
17528
- }) : void 0;
17529
- const prProvider = client ? new GitHubPRProvider(client, logger) : void 0;
15295
+ });
15296
+ const prProvider = new GitHubPRProvider(client, logger);
17530
15297
  const executionProvider = new SandcastleExecutionProvider();
17531
15298
  const result = await runPrdRunLaunchCommand({
17532
15299
  repoRoot: targetRepoRoot,
@@ -17785,11 +15552,11 @@ function createCliProgram(version) {
17785
15552
  return program;
17786
15553
  }
17787
15554
  async function resolveCliVersion() {
17788
- if (isPackageVersion("0.0.0-next-20260619074943")) {
17789
- return "0.0.0-next-20260619074943";
15555
+ if (isPackageVersion("0.0.0-next-20260619094345")) {
15556
+ return "0.0.0-next-20260619094345";
17790
15557
  }
17791
- if (isReleaseVersion("0.0.0-next-20260619074943")) {
17792
- return "0.0.0-next-20260619074943";
15558
+ if (isReleaseVersion("0.0.0-next-20260619094345")) {
15559
+ return "0.0.0-next-20260619094345";
17793
15560
  }
17794
15561
  try {
17795
15562
  const root = repoRoot();