@pourkit/cli 0.0.0-next-20260621045826 → 0.0.0-next-20260621094003
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 +361 -249
- package/dist/cli.js.map +1 -1
- package/dist/e2e/run-live-e2e.js +253 -151
- package/dist/e2e/run-live-e2e.js.map +1 -1
- package/dist/managed/prompts/issue-final-review.prompt.md +14 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -880,11 +880,11 @@ var OBSOLETE_CONFIG_PATHS = [
|
|
|
880
880
|
];
|
|
881
881
|
var CANONICAL_CONFIG_PATH = ".pourkit/config.json";
|
|
882
882
|
async function loadRepoConfig(repoRoot2, _configFileName) {
|
|
883
|
-
const { existsSync:
|
|
883
|
+
const { existsSync: existsSync22 } = await import("fs");
|
|
884
884
|
const { join: pjoin } = await import("path");
|
|
885
885
|
for (const obPath of OBSOLETE_CONFIG_PATHS) {
|
|
886
886
|
const fullPath = pjoin(repoRoot2, obPath);
|
|
887
|
-
if (
|
|
887
|
+
if (existsSync22(fullPath)) {
|
|
888
888
|
const isRootJson = obPath === "pourkit.json";
|
|
889
889
|
throw new Error(
|
|
890
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".`
|
|
@@ -892,7 +892,7 @@ async function loadRepoConfig(repoRoot2, _configFileName) {
|
|
|
892
892
|
}
|
|
893
893
|
}
|
|
894
894
|
const configPath = pjoin(repoRoot2, CANONICAL_CONFIG_PATH);
|
|
895
|
-
if (!
|
|
895
|
+
if (!existsSync22(configPath)) {
|
|
896
896
|
throw new Error(
|
|
897
897
|
`No Pourkit config found at ${CANONICAL_CONFIG_PATH}. Run pourkit init or create ${CANONICAL_CONFIG_PATH} with "$schema": "./schema/pourkit.schema.json".`
|
|
898
898
|
);
|
|
@@ -3491,8 +3491,23 @@ function validateIssueFinalReviewArtifact(parsed, options) {
|
|
|
3491
3491
|
};
|
|
3492
3492
|
}
|
|
3493
3493
|
diagnostics.push("verification: present");
|
|
3494
|
-
|
|
3494
|
+
const verificationWasRecorded = verification.required === true || Array.isArray(verification.commands) && verification.commands.length > 0;
|
|
3495
|
+
if (parsed.verdict === "pass" && verificationWasRecorded) {
|
|
3495
3496
|
if (verification.required !== true || verification.passed !== true) {
|
|
3497
|
+
return {
|
|
3498
|
+
ok: false,
|
|
3499
|
+
reason: "Issue Final Review pass with verification evidence requires verification.required === true and verification.passed === true",
|
|
3500
|
+
diagnostics: [
|
|
3501
|
+
...diagnostics,
|
|
3502
|
+
`verification.required: ${verification.required}`,
|
|
3503
|
+
`verification.passed: ${verification.passed}`
|
|
3504
|
+
]
|
|
3505
|
+
};
|
|
3506
|
+
}
|
|
3507
|
+
diagnostics.push("pass verification: valid");
|
|
3508
|
+
}
|
|
3509
|
+
if (parsed.selfRetouched === true && parsed.verdict === "pass") {
|
|
3510
|
+
if (!verificationWasRecorded) {
|
|
3496
3511
|
return {
|
|
3497
3512
|
ok: false,
|
|
3498
3513
|
reason: "Self-retouched pass requires verification.required === true and verification.passed === true",
|
|
@@ -3672,7 +3687,7 @@ function shellQuote(value) {
|
|
|
3672
3687
|
}
|
|
3673
3688
|
|
|
3674
3689
|
// commands/issue-run.ts
|
|
3675
|
-
import { existsSync as
|
|
3690
|
+
import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
|
|
3676
3691
|
import { isAbsolute as isAbsolute4, join as join15 } from "path";
|
|
3677
3692
|
|
|
3678
3693
|
// pr/templates.ts
|
|
@@ -4395,6 +4410,10 @@ function writeFailureState(options, message) {
|
|
|
4395
4410
|
}
|
|
4396
4411
|
}
|
|
4397
4412
|
|
|
4413
|
+
// issues/issue-builder.ts
|
|
4414
|
+
init_common();
|
|
4415
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11 } from "fs";
|
|
4416
|
+
|
|
4398
4417
|
// serena/baseline.ts
|
|
4399
4418
|
init_common();
|
|
4400
4419
|
import path3 from "path";
|
|
@@ -4712,9 +4731,177 @@ async function prepareSerenaForTarget(options) {
|
|
|
4712
4731
|
}
|
|
4713
4732
|
}
|
|
4714
4733
|
|
|
4734
|
+
// issues/issue-builder.ts
|
|
4735
|
+
async function runIssueBuilder(options) {
|
|
4736
|
+
const {
|
|
4737
|
+
repoRoot: repoRoot2,
|
|
4738
|
+
issueNumber,
|
|
4739
|
+
target,
|
|
4740
|
+
config,
|
|
4741
|
+
branchName,
|
|
4742
|
+
worktreePath,
|
|
4743
|
+
baseRef,
|
|
4744
|
+
worktreeState,
|
|
4745
|
+
restartBuilder,
|
|
4746
|
+
executionProvider,
|
|
4747
|
+
runContextArtifact,
|
|
4748
|
+
logger,
|
|
4749
|
+
memory,
|
|
4750
|
+
prepareSerena,
|
|
4751
|
+
onSerenaExecutionContext,
|
|
4752
|
+
timeoutMs
|
|
4753
|
+
} = options;
|
|
4754
|
+
const serenaRuntimeConfig = {
|
|
4755
|
+
enabled: target.serena?.enabled ?? config.serena.enabled,
|
|
4756
|
+
required: target.serena?.required ?? config.serena.required,
|
|
4757
|
+
autoStart: config.serena.autoStart,
|
|
4758
|
+
dataDir: config.serena.dataDir,
|
|
4759
|
+
mcpUrl: config.serena.mcpUrl,
|
|
4760
|
+
sandboxMcpUrl: config.serena.sandboxMcpUrl
|
|
4761
|
+
};
|
|
4762
|
+
let serenaExecutionContext;
|
|
4763
|
+
if (serenaRuntimeConfig.enabled || serenaRuntimeConfig.required) {
|
|
4764
|
+
const serenaPreflight = await (prepareSerena ?? prepareSerenaForTarget)({
|
|
4765
|
+
repoRoot: repoRoot2,
|
|
4766
|
+
targetName: target.name,
|
|
4767
|
+
baseBranch: target.baseBranch,
|
|
4768
|
+
dataDir: serenaRuntimeConfig.dataDir,
|
|
4769
|
+
mcpUrl: serenaRuntimeConfig.mcpUrl,
|
|
4770
|
+
enabled: serenaRuntimeConfig.enabled || serenaRuntimeConfig.required,
|
|
4771
|
+
required: serenaRuntimeConfig.required,
|
|
4772
|
+
autoStart: serenaRuntimeConfig.autoStart,
|
|
4773
|
+
logger
|
|
4774
|
+
});
|
|
4775
|
+
if (serenaPreflight.enabled && serenaPreflight.available) {
|
|
4776
|
+
serenaExecutionContext = {
|
|
4777
|
+
available: true,
|
|
4778
|
+
sandboxMcpUrl: serenaRuntimeConfig.sandboxMcpUrl
|
|
4779
|
+
};
|
|
4780
|
+
onSerenaExecutionContext?.(serenaExecutionContext);
|
|
4781
|
+
}
|
|
4782
|
+
if (serenaPreflight.enabled && !serenaPreflight.available) {
|
|
4783
|
+
const message = `Serena preflight unavailable for target ${target.name}: ${serenaPreflight.error}`;
|
|
4784
|
+
if (serenaRuntimeConfig.required) {
|
|
4785
|
+
throw new Error(message);
|
|
4786
|
+
}
|
|
4787
|
+
logger.step("warn", message);
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
const shouldRunBuilder = restartBuilder || worktreeState === null || !worktreeState.completedStages.builder;
|
|
4791
|
+
if (!shouldRunBuilder) {
|
|
4792
|
+
return {
|
|
4793
|
+
status: "skipped",
|
|
4794
|
+
...worktreePath ? { worktreePath } : {},
|
|
4795
|
+
worktreeState
|
|
4796
|
+
};
|
|
4797
|
+
}
|
|
4798
|
+
const strategy = target.strategy;
|
|
4799
|
+
const prompt = loadBuilderPrompt(
|
|
4800
|
+
repoRoot2,
|
|
4801
|
+
strategy.implement.builder.promptTemplate
|
|
4802
|
+
);
|
|
4803
|
+
const executionResult = await executionProvider.execute({
|
|
4804
|
+
stage: "builder",
|
|
4805
|
+
agent: strategy.implement.builder.agent,
|
|
4806
|
+
model: strategy.implement.builder.model,
|
|
4807
|
+
variant: strategy.implement.builder.variant,
|
|
4808
|
+
env: strategy.implement.builder.env,
|
|
4809
|
+
prompt,
|
|
4810
|
+
target,
|
|
4811
|
+
repoRoot: repoRoot2,
|
|
4812
|
+
branchName,
|
|
4813
|
+
...baseRef ? { baseRef } : {},
|
|
4814
|
+
sandbox: config.sandbox,
|
|
4815
|
+
...serenaExecutionContext ? { serena: serenaExecutionContext } : {},
|
|
4816
|
+
...memory ? { memory } : {},
|
|
4817
|
+
autoApprove: true,
|
|
4818
|
+
timeoutMs,
|
|
4819
|
+
...worktreePath ? { worktreePath } : {},
|
|
4820
|
+
artifacts: [runContextArtifact],
|
|
4821
|
+
logger
|
|
4822
|
+
});
|
|
4823
|
+
if (!executionResult.success) {
|
|
4824
|
+
throw new Error(`Sandcastle failed: ${executionResult.error}`);
|
|
4825
|
+
}
|
|
4826
|
+
const effectiveWorktreePath = worktreePath ?? executionResult.worktreePath;
|
|
4827
|
+
if (effectiveWorktreePath) {
|
|
4828
|
+
await assertCanonicalBaseAncestor({
|
|
4829
|
+
worktreePath: effectiveWorktreePath,
|
|
4830
|
+
baseRef: `origin/${target.baseBranch}`,
|
|
4831
|
+
stageName: "Builder",
|
|
4832
|
+
logger
|
|
4833
|
+
});
|
|
4834
|
+
if (worktreeState) {
|
|
4835
|
+
updateWorktreeRunState(effectiveWorktreePath, {
|
|
4836
|
+
completedStages: { builder: true }
|
|
4837
|
+
});
|
|
4838
|
+
} else {
|
|
4839
|
+
writeWorktreeRunState(effectiveWorktreePath, {
|
|
4840
|
+
issueNumber,
|
|
4841
|
+
targetName: target.name,
|
|
4842
|
+
branchName,
|
|
4843
|
+
baseBranch: target.baseBranch,
|
|
4844
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4845
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4846
|
+
completedStages: { builder: true },
|
|
4847
|
+
review: { lifetimeIterations: 0 }
|
|
4848
|
+
});
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4851
|
+
const refreshedState = effectiveWorktreePath ? readWorktreeRunState(effectiveWorktreePath) : worktreeState;
|
|
4852
|
+
return {
|
|
4853
|
+
status: "ran",
|
|
4854
|
+
...effectiveWorktreePath ? { worktreePath: effectiveWorktreePath } : {},
|
|
4855
|
+
worktreeState: refreshedState
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
function loadBuilderPrompt(repoRoot2, promptTemplate) {
|
|
4859
|
+
const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
|
|
4860
|
+
const promptBody = existsSync10(promptPath) ? readFileSync11(promptPath, "utf-8") : promptTemplate;
|
|
4861
|
+
return appendProtectedWorkGuidance(`${promptBody}
|
|
4862
|
+
|
|
4863
|
+
## Shared Run Context
|
|
4864
|
+
|
|
4865
|
+
Read the selected issue requirements, planning context (including plan and PRD content when present), comments, branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}`);
|
|
4866
|
+
}
|
|
4867
|
+
async function syncRemoteBaseRef(worktreePath, baseRef, logger) {
|
|
4868
|
+
const remoteBase = parseRemoteBaseRef(baseRef);
|
|
4869
|
+
if (!remoteBase) {
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4872
|
+
await execCapture("git", ["fetch", remoteBase.remote, remoteBase.branch], {
|
|
4873
|
+
cwd: worktreePath,
|
|
4874
|
+
logger,
|
|
4875
|
+
label: "git fetch target"
|
|
4876
|
+
});
|
|
4877
|
+
}
|
|
4878
|
+
function parseRemoteBaseRef(baseRef) {
|
|
4879
|
+
const [remote, ...branchParts] = baseRef.split("/");
|
|
4880
|
+
const branch = branchParts.join("/");
|
|
4881
|
+
if (!remote || !branch) {
|
|
4882
|
+
return null;
|
|
4883
|
+
}
|
|
4884
|
+
return { remote, branch };
|
|
4885
|
+
}
|
|
4886
|
+
async function assertCanonicalBaseAncestor(options) {
|
|
4887
|
+
const { worktreePath, baseRef, stageName, logger } = options;
|
|
4888
|
+
await syncRemoteBaseRef(worktreePath, baseRef, logger);
|
|
4889
|
+
try {
|
|
4890
|
+
await execCapture("git", ["merge-base", "--is-ancestor", baseRef, "HEAD"], {
|
|
4891
|
+
cwd: worktreePath,
|
|
4892
|
+
logger,
|
|
4893
|
+
label: "git merge-base --is-ancestor"
|
|
4894
|
+
});
|
|
4895
|
+
} catch {
|
|
4896
|
+
throw new Error(
|
|
4897
|
+
`Cannot continue after ${stageName}: ${baseRef} is not an ancestor of HEAD. An agent may have moved the issue branch behind the canonical base; refresh the branch onto the latest target base before continuing.`
|
|
4898
|
+
);
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
|
|
4715
4902
|
// commands/pr-description-agent.ts
|
|
4716
4903
|
import { join as join11 } from "path";
|
|
4717
|
-
import { readFileSync as
|
|
4904
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
4718
4905
|
|
|
4719
4906
|
// pr/pr-description-context.ts
|
|
4720
4907
|
init_common();
|
|
@@ -4909,7 +5096,7 @@ function runFinalizerAgent(options) {
|
|
|
4909
5096
|
logger: options.logger,
|
|
4910
5097
|
...options.memory ? { memory: options.memory } : {}
|
|
4911
5098
|
});
|
|
4912
|
-
const output =
|
|
5099
|
+
const output = readFileSync12(artifactPath, "utf-8");
|
|
4913
5100
|
yield* persistGeneratedArtifactEffect(options.worktreePath, output, fs);
|
|
4914
5101
|
return result;
|
|
4915
5102
|
});
|
|
@@ -5106,7 +5293,7 @@ function extractClosingRefs(body) {
|
|
|
5106
5293
|
|
|
5107
5294
|
// issues/github-issue-publication.ts
|
|
5108
5295
|
init_common();
|
|
5109
|
-
import { existsSync as
|
|
5296
|
+
import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
|
|
5110
5297
|
import { isAbsolute as isAbsolute3, join as join12 } from "path";
|
|
5111
5298
|
|
|
5112
5299
|
// issues/issue-transitions.ts
|
|
@@ -5583,10 +5770,10 @@ function readIssueFinalReviewArtifact(worktreeState, worktreePath) {
|
|
|
5583
5770
|
return null;
|
|
5584
5771
|
}
|
|
5585
5772
|
const artifactPath = isAbsolute3(configuredPath) ? configuredPath : join12(worktreePath, configuredPath);
|
|
5586
|
-
if (!
|
|
5773
|
+
if (!existsSync11(artifactPath)) return null;
|
|
5587
5774
|
let parsed;
|
|
5588
5775
|
try {
|
|
5589
|
-
parsed = JSON.parse(
|
|
5776
|
+
parsed = JSON.parse(readFileSync13(artifactPath, "utf-8"));
|
|
5590
5777
|
} catch {
|
|
5591
5778
|
return null;
|
|
5592
5779
|
}
|
|
@@ -5841,7 +6028,7 @@ function isAllowedSecretPlaceholder(value) {
|
|
|
5841
6028
|
}
|
|
5842
6029
|
|
|
5843
6030
|
// commands/issue-final-review-agent.ts
|
|
5844
|
-
import { existsSync as
|
|
6031
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
5845
6032
|
import { join as join13 } from "path";
|
|
5846
6033
|
var ISSUE_FINAL_REVIEW_ARTIFACT_PATH = join13(
|
|
5847
6034
|
".pourkit",
|
|
@@ -5966,7 +6153,7 @@ function extractChangedPaths(parsed) {
|
|
|
5966
6153
|
function loadIssueFinalReviewPrompt(options) {
|
|
5967
6154
|
const { repoRoot: repoRoot2, promptTemplate, validationCommand } = options;
|
|
5968
6155
|
const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
|
|
5969
|
-
const promptBody =
|
|
6156
|
+
const promptBody = existsSync12(promptPath) ? readFileSync14(promptPath, "utf-8") : promptTemplate;
|
|
5970
6157
|
return appendProtectedWorkGuidance(`${promptBody}
|
|
5971
6158
|
|
|
5972
6159
|
## Shared Run Context
|
|
@@ -5978,7 +6165,8 @@ Read the selected issue requirements, planning context (including plan and PRD c
|
|
|
5978
6165
|
- First read ${RUN_CONTEXT_PATH_IN_WORKTREE} only far enough to identify the configured verification commands.
|
|
5979
6166
|
- Before reviewing code, diffs, artifacts, or prior findings, run each configured verification command yourself from the Worktree.
|
|
5980
6167
|
- Run the commands exactly as configured. Do not substitute narrower commands unless the configured command cannot run.
|
|
5981
|
-
- If a configured command fails
|
|
6168
|
+
- If a configured verification command fails because of fixable Issue work, self-retouch the Worktree, then rerun all configured verification commands.
|
|
6169
|
+
- Do not return \`pass\` while any configured verification command is failing.
|
|
5982
6170
|
- If a command cannot run because the environment is missing required setup, dependencies, or scripts outside agent control, treat it as a human handoff blocker.
|
|
5983
6171
|
- If no verification commands are configured, note that and proceed with normal review.
|
|
5984
6172
|
|
|
@@ -6167,16 +6355,6 @@ function checkIssueGates(issue, config, force) {
|
|
|
6167
6355
|
}
|
|
6168
6356
|
return { allowed: true, gates };
|
|
6169
6357
|
}
|
|
6170
|
-
function resolveSerenaRuntimeConfig(config, target) {
|
|
6171
|
-
return {
|
|
6172
|
-
enabled: target.serena?.enabled ?? config.serena.enabled,
|
|
6173
|
-
required: target.serena?.required ?? config.serena.required,
|
|
6174
|
-
autoStart: config.serena.autoStart,
|
|
6175
|
-
dataDir: config.serena.dataDir,
|
|
6176
|
-
mcpUrl: config.serena.mcpUrl,
|
|
6177
|
-
sandboxMcpUrl: config.serena.sandboxMcpUrl
|
|
6178
|
-
};
|
|
6179
|
-
}
|
|
6180
6358
|
function assertIssueFinalReviewPassed(worktreeState) {
|
|
6181
6359
|
const ifr = worktreeState?.issueFinalReview;
|
|
6182
6360
|
if (!ifr || !ifr.completed || ifr.verdict !== "pass") {
|
|
@@ -6239,7 +6417,7 @@ async function advanceIssueFinalReview(options) {
|
|
|
6239
6417
|
reviewArtifactPath,
|
|
6240
6418
|
...options.memory ? { memory: options.memory } : {}
|
|
6241
6419
|
});
|
|
6242
|
-
await
|
|
6420
|
+
await assertCanonicalBaseAncestor2({
|
|
6243
6421
|
worktreePath,
|
|
6244
6422
|
baseRef: `origin/${target.baseBranch}`,
|
|
6245
6423
|
stageName: "Issue Final Review",
|
|
@@ -6292,35 +6470,7 @@ async function startIssueRun(options) {
|
|
|
6292
6470
|
const effectiveTarget = { ...target, baseBranch: effectiveBaseBranch };
|
|
6293
6471
|
const branchName = renderBranchName(target.branchTemplate, issue);
|
|
6294
6472
|
const strategy = target.strategy;
|
|
6295
|
-
const serenaRuntimeConfig = resolveSerenaRuntimeConfig(config, target);
|
|
6296
|
-
const shouldPrepareSerena = serenaRuntimeConfig.enabled || serenaRuntimeConfig.required;
|
|
6297
6473
|
let serenaExecutionContext;
|
|
6298
|
-
if (shouldPrepareSerena) {
|
|
6299
|
-
const serenaPreflight = await prepareSerenaForTarget({
|
|
6300
|
-
repoRoot: ROOT,
|
|
6301
|
-
targetName: target.name,
|
|
6302
|
-
baseBranch: target.baseBranch,
|
|
6303
|
-
dataDir: serenaRuntimeConfig.dataDir,
|
|
6304
|
-
mcpUrl: serenaRuntimeConfig.mcpUrl,
|
|
6305
|
-
enabled: shouldPrepareSerena,
|
|
6306
|
-
required: serenaRuntimeConfig.required,
|
|
6307
|
-
autoStart: serenaRuntimeConfig.autoStart,
|
|
6308
|
-
logger
|
|
6309
|
-
});
|
|
6310
|
-
if (serenaPreflight.enabled && serenaPreflight.available) {
|
|
6311
|
-
serenaExecutionContext = {
|
|
6312
|
-
available: true,
|
|
6313
|
-
sandboxMcpUrl: serenaRuntimeConfig.sandboxMcpUrl
|
|
6314
|
-
};
|
|
6315
|
-
}
|
|
6316
|
-
if (serenaPreflight.enabled && !serenaPreflight.available) {
|
|
6317
|
-
const message = `Serena preflight unavailable for target ${target.name}: ${serenaPreflight.error}`;
|
|
6318
|
-
if (serenaRuntimeConfig.required) {
|
|
6319
|
-
throw new Error(message);
|
|
6320
|
-
}
|
|
6321
|
-
logger.step("warn", message);
|
|
6322
|
-
}
|
|
6323
|
-
}
|
|
6324
6474
|
const memoryExecutionContext = config.memory?.enabled ? { available: true, sandboxDbPath: "/home/agent/.pourkit/icm/memories.db" } : void 0;
|
|
6325
6475
|
if (options.resetWorktree) {
|
|
6326
6476
|
const existingPr = await prProvider.getPr(branchName);
|
|
@@ -6332,10 +6482,6 @@ async function startIssueRun(options) {
|
|
|
6332
6482
|
await resetIssueWorktree(ROOT, branchName, logger);
|
|
6333
6483
|
await syncTargetBranch(ROOT, effectiveBaseBranch, logger);
|
|
6334
6484
|
}
|
|
6335
|
-
const prompt = loadBuilderPrompt(
|
|
6336
|
-
ROOT,
|
|
6337
|
-
strategy.implement.builder.promptTemplate
|
|
6338
|
-
);
|
|
6339
6485
|
const resolution = await resolveIssueWorktree(
|
|
6340
6486
|
ROOT,
|
|
6341
6487
|
branchName,
|
|
@@ -6380,68 +6526,33 @@ async function startIssueRun(options) {
|
|
|
6380
6526
|
});
|
|
6381
6527
|
await issueProvider.addLabels(issueNumber, [config.labels.agentInProgress]);
|
|
6382
6528
|
await issueProvider.removeLabel(issueNumber, config.labels.readyForAgent);
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
autoApprove: true,
|
|
6401
|
-
timeoutMs: EXECUTION_TIMEOUT_MS,
|
|
6402
|
-
...resolution.worktreePath ? { worktreePath: resolution.worktreePath } : {},
|
|
6403
|
-
artifacts: [runContextArtifact],
|
|
6404
|
-
logger
|
|
6405
|
-
});
|
|
6406
|
-
if (!executionResult.success) {
|
|
6407
|
-
throw new Error(`Sandcastle failed: ${executionResult.error}`);
|
|
6408
|
-
}
|
|
6409
|
-
} else {
|
|
6410
|
-
executionResult = {
|
|
6411
|
-
success: true,
|
|
6412
|
-
branch: branchName,
|
|
6413
|
-
worktreePath: resolution.worktreePath,
|
|
6414
|
-
commits: [],
|
|
6415
|
-
logPath: null
|
|
6416
|
-
};
|
|
6417
|
-
}
|
|
6418
|
-
if (executionResult.worktreePath) {
|
|
6419
|
-
if (shouldRunBuilder) {
|
|
6420
|
-
await assertCanonicalBaseAncestor({
|
|
6421
|
-
worktreePath: executionResult.worktreePath,
|
|
6422
|
-
baseRef: `origin/${effectiveBaseBranch}`,
|
|
6423
|
-
stageName: "Builder",
|
|
6424
|
-
logger
|
|
6425
|
-
});
|
|
6426
|
-
}
|
|
6427
|
-
if (worktreeState) {
|
|
6428
|
-
updateWorktreeRunState(executionResult.worktreePath, {
|
|
6429
|
-
completedStages: { builder: true }
|
|
6430
|
-
});
|
|
6431
|
-
} else {
|
|
6432
|
-
writeWorktreeRunState(executionResult.worktreePath, {
|
|
6433
|
-
issueNumber,
|
|
6434
|
-
targetName: target.name,
|
|
6435
|
-
branchName,
|
|
6436
|
-
baseBranch: effectiveBaseBranch,
|
|
6437
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6438
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6439
|
-
completedStages: { builder: true },
|
|
6440
|
-
review: { lifetimeIterations: 0 }
|
|
6441
|
-
});
|
|
6529
|
+
const builderResult = await runIssueBuilder({
|
|
6530
|
+
repoRoot: ROOT,
|
|
6531
|
+
issueNumber,
|
|
6532
|
+
target: effectiveTarget,
|
|
6533
|
+
config,
|
|
6534
|
+
branchName,
|
|
6535
|
+
...resolution.worktreePath ? { worktreePath: resolution.worktreePath } : {},
|
|
6536
|
+
...resolution.mode === "new" ? { baseRef: resolution.baseRef } : {},
|
|
6537
|
+
worktreeState,
|
|
6538
|
+
restartBuilder: resolution.mode === "new",
|
|
6539
|
+
executionProvider,
|
|
6540
|
+
runContextArtifact,
|
|
6541
|
+
logger,
|
|
6542
|
+
...memoryExecutionContext ? { memory: memoryExecutionContext } : {},
|
|
6543
|
+
timeoutMs: EXECUTION_TIMEOUT_MS,
|
|
6544
|
+
onSerenaExecutionContext: (context) => {
|
|
6545
|
+
serenaExecutionContext = context;
|
|
6442
6546
|
}
|
|
6443
|
-
}
|
|
6444
|
-
const
|
|
6547
|
+
});
|
|
6548
|
+
const executionResult = {
|
|
6549
|
+
success: true,
|
|
6550
|
+
branch: branchName,
|
|
6551
|
+
worktreePath: builderResult.worktreePath ?? issueWorktreePath(ROOT, branchName),
|
|
6552
|
+
commits: [],
|
|
6553
|
+
logPath: null
|
|
6554
|
+
};
|
|
6555
|
+
const finalWorktreeState = builderResult.worktreeState;
|
|
6445
6556
|
return {
|
|
6446
6557
|
issue,
|
|
6447
6558
|
parentPrdIssue,
|
|
@@ -6486,7 +6597,7 @@ async function advanceIssueRunReview(options) {
|
|
|
6486
6597
|
}
|
|
6487
6598
|
})
|
|
6488
6599
|
);
|
|
6489
|
-
await
|
|
6600
|
+
await assertCanonicalBaseAncestor2({
|
|
6490
6601
|
worktreePath: options.worktreePath,
|
|
6491
6602
|
baseRef: `origin/${options.target.baseBranch}`,
|
|
6492
6603
|
stageName: "Review/Refactor",
|
|
@@ -6552,12 +6663,12 @@ async function completeIssueRun(options) {
|
|
|
6552
6663
|
prTitle = finalizerFromState.title;
|
|
6553
6664
|
prBody = finalizerFromState.body;
|
|
6554
6665
|
} else if (finalizerFromState.artifactPath) {
|
|
6555
|
-
if (!
|
|
6666
|
+
if (!existsSync13(finalizerFromState.artifactPath)) {
|
|
6556
6667
|
throw new FinalizerFailure({
|
|
6557
6668
|
message: `Finalizer artifact missing at ${finalizerFromState.artifactPath}`
|
|
6558
6669
|
});
|
|
6559
6670
|
}
|
|
6560
|
-
const artifactContent =
|
|
6671
|
+
const artifactContent = readFileSync15(
|
|
6561
6672
|
finalizerFromState.artifactPath,
|
|
6562
6673
|
"utf-8"
|
|
6563
6674
|
);
|
|
@@ -6595,7 +6706,7 @@ async function completeIssueRun(options) {
|
|
|
6595
6706
|
prTitle = finalizerResult.title;
|
|
6596
6707
|
prBody = finalizerResult.body;
|
|
6597
6708
|
if (executionResult.worktreePath) {
|
|
6598
|
-
await
|
|
6709
|
+
await assertCanonicalBaseAncestor2({
|
|
6599
6710
|
worktreePath: executionResult.worktreePath,
|
|
6600
6711
|
baseRef: `origin/${effectiveBaseBranch}`,
|
|
6601
6712
|
stageName: "Finalizer",
|
|
@@ -6735,7 +6846,7 @@ function getRefactorArtifactDir(artifactPath) {
|
|
|
6735
6846
|
}
|
|
6736
6847
|
async function finalizeWorktreeCommit(options) {
|
|
6737
6848
|
const { worktreePath, baseRef, title, body, logger } = options;
|
|
6738
|
-
await
|
|
6849
|
+
await assertCanonicalBaseAncestor2({
|
|
6739
6850
|
worktreePath,
|
|
6740
6851
|
baseRef,
|
|
6741
6852
|
stageName: "final commit",
|
|
@@ -6757,9 +6868,9 @@ async function finalizeWorktreeCommit(options) {
|
|
|
6757
6868
|
label: "git commit"
|
|
6758
6869
|
});
|
|
6759
6870
|
}
|
|
6760
|
-
async function
|
|
6871
|
+
async function assertCanonicalBaseAncestor2(options) {
|
|
6761
6872
|
const { worktreePath, baseRef, stageName, logger } = options;
|
|
6762
|
-
await
|
|
6873
|
+
await syncRemoteBaseRef2(worktreePath, baseRef, logger);
|
|
6763
6874
|
try {
|
|
6764
6875
|
await execCapture("git", ["merge-base", "--is-ancestor", baseRef, "HEAD"], {
|
|
6765
6876
|
cwd: worktreePath,
|
|
@@ -6821,8 +6932,8 @@ function normalizeGitPath2(path9) {
|
|
|
6821
6932
|
function isIssueFinalReviewAuditedPath2(path9) {
|
|
6822
6933
|
return path9 !== "" && path9 !== WORKTREE_RUN_STATE_PATH && !path9.startsWith(".pourkit/.tmp/") && !path9.startsWith(".pourkit/logs/");
|
|
6823
6934
|
}
|
|
6824
|
-
async function
|
|
6825
|
-
const remoteBase =
|
|
6935
|
+
async function syncRemoteBaseRef2(worktreePath, baseRef, logger) {
|
|
6936
|
+
const remoteBase = parseRemoteBaseRef2(baseRef);
|
|
6826
6937
|
if (!remoteBase) {
|
|
6827
6938
|
return;
|
|
6828
6939
|
}
|
|
@@ -6832,7 +6943,7 @@ async function syncRemoteBaseRef(worktreePath, baseRef, logger) {
|
|
|
6832
6943
|
label: "git fetch target"
|
|
6833
6944
|
});
|
|
6834
6945
|
}
|
|
6835
|
-
function
|
|
6946
|
+
function parseRemoteBaseRef2(baseRef) {
|
|
6836
6947
|
const [remote, ...branchParts] = baseRef.split("/");
|
|
6837
6948
|
const branch = branchParts.join("/");
|
|
6838
6949
|
if (!remote || !branch) {
|
|
@@ -6911,15 +7022,6 @@ async function closeNoOpIssue(provider, issueNumber, config, logger) {
|
|
|
6911
7022
|
await maybeCloseParentAfterChildCompletion(provider, issueNumber, logger);
|
|
6912
7023
|
}
|
|
6913
7024
|
}
|
|
6914
|
-
function loadBuilderPrompt(repoRoot2, promptTemplate) {
|
|
6915
|
-
const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
|
|
6916
|
-
const promptBody = existsSync12(promptPath) ? readFileSync14(promptPath, "utf-8") : promptTemplate;
|
|
6917
|
-
return appendProtectedWorkGuidance(`${promptBody}
|
|
6918
|
-
|
|
6919
|
-
## Shared Run Context
|
|
6920
|
-
|
|
6921
|
-
Read the selected issue requirements, planning context (including plan and PRD content when present), comments, branch context, verification commands, and artifact paths from: ${RUN_CONTEXT_PATH_IN_WORKTREE}`);
|
|
6922
|
-
}
|
|
6923
7025
|
|
|
6924
7026
|
// issues/issue-run-lifecycle.ts
|
|
6925
7027
|
var IssueRunHumanHandoffStop = class extends Error {
|
|
@@ -7186,9 +7288,9 @@ import { join as join17 } from "path";
|
|
|
7186
7288
|
|
|
7187
7289
|
// prd-run/state.ts
|
|
7188
7290
|
import {
|
|
7189
|
-
existsSync as
|
|
7291
|
+
existsSync as existsSync14,
|
|
7190
7292
|
mkdirSync as mkdirSync7,
|
|
7191
|
-
readFileSync as
|
|
7293
|
+
readFileSync as readFileSync16,
|
|
7192
7294
|
readdirSync as readdirSync3,
|
|
7193
7295
|
writeFileSync as writeFileSync4
|
|
7194
7296
|
} from "fs";
|
|
@@ -7277,16 +7379,16 @@ function normalizePrdRunRef(ref) {
|
|
|
7277
7379
|
function readPrdRun(repoRoot2, prdRef) {
|
|
7278
7380
|
const normalized = normalizePrdRunRef(prdRef);
|
|
7279
7381
|
const recordPath = getRecordPath(repoRoot2, normalized);
|
|
7280
|
-
if (!
|
|
7382
|
+
if (!existsSync14(recordPath)) {
|
|
7281
7383
|
return { record: null, diagnostics: [] };
|
|
7282
7384
|
}
|
|
7283
7385
|
try {
|
|
7284
|
-
const raw = JSON.parse(
|
|
7386
|
+
const raw = JSON.parse(readFileSync16(recordPath, "utf-8"));
|
|
7285
7387
|
const parsed = PrdRunRecordSchema.parse(raw);
|
|
7286
7388
|
return { record: parsed, diagnostics: [] };
|
|
7287
7389
|
} catch (error) {
|
|
7288
7390
|
try {
|
|
7289
|
-
const raw = JSON.parse(
|
|
7391
|
+
const raw = JSON.parse(readFileSync16(recordPath, "utf-8"));
|
|
7290
7392
|
if (raw && typeof raw === "object" && raw.start && typeof raw.start === "object" && raw.start.startBaseBranch === void 0) {
|
|
7291
7393
|
return {
|
|
7292
7394
|
record: raw,
|
|
@@ -7308,7 +7410,7 @@ function readPrdRun(repoRoot2, prdRef) {
|
|
|
7308
7410
|
}
|
|
7309
7411
|
function listPrdRuns(repoRoot2) {
|
|
7310
7412
|
const stateDir = join16(repoRoot2, PRD_RUN_STATE_DIR);
|
|
7311
|
-
if (!
|
|
7413
|
+
if (!existsSync14(stateDir)) {
|
|
7312
7414
|
return { records: [], diagnostics: [] };
|
|
7313
7415
|
}
|
|
7314
7416
|
const records = [];
|
|
@@ -7320,7 +7422,7 @@ function listPrdRuns(repoRoot2) {
|
|
|
7320
7422
|
const recordPath = join16(stateDir, entry.name);
|
|
7321
7423
|
try {
|
|
7322
7424
|
const record = PrdRunRecordSchema.parse(
|
|
7323
|
-
JSON.parse(
|
|
7425
|
+
JSON.parse(readFileSync16(recordPath, "utf-8"))
|
|
7324
7426
|
);
|
|
7325
7427
|
records.push(record);
|
|
7326
7428
|
} catch (error) {
|
|
@@ -9103,7 +9205,7 @@ async function launchGithubQueueDrain(options, prdRef, startReceipt, targetName,
|
|
|
9103
9205
|
}
|
|
9104
9206
|
|
|
9105
9207
|
// prd-run/final-review-validation.ts
|
|
9106
|
-
import { existsSync as
|
|
9208
|
+
import { existsSync as existsSync15, readFileSync as readFileSync17 } from "fs";
|
|
9107
9209
|
|
|
9108
9210
|
// commands/prd-run.ts
|
|
9109
9211
|
async function runPrdRunLaunchCommand(options) {
|
|
@@ -9613,7 +9715,7 @@ async function runPrMergeCommand(args, logger, prProvider, config) {
|
|
|
9613
9715
|
}
|
|
9614
9716
|
|
|
9615
9717
|
// commands/init.ts
|
|
9616
|
-
import { existsSync as
|
|
9718
|
+
import { existsSync as existsSync16, statSync } from "fs";
|
|
9617
9719
|
import {
|
|
9618
9720
|
copyFile,
|
|
9619
9721
|
mkdir as mkdir4,
|
|
@@ -9819,7 +9921,17 @@ function buildManagedAgentInstructions(options) {
|
|
|
9819
9921
|
|
|
9820
9922
|
Use \`fd\` for file discovery, \`rg\` for text search, and direct file reads for focused context.
|
|
9821
9923
|
|
|
9822
|
-
|
|
9924
|
+
For multi-step exploration, prefer the dedicated subagents in \`.opencode/agents\`:
|
|
9925
|
+
|
|
9926
|
+
- Use \`codebase-locator\` when you need to find relevant files, directories, or entry points.
|
|
9927
|
+
- Use \`codebase-analyzer\` when you need to understand how a specific component or flow works.
|
|
9928
|
+
- Use \`codebase-pattern-finder\` when you need examples of similar implementations or test patterns.
|
|
9929
|
+
- Use \`pourkit-docs-locator\` when searching \`.pourkit/\` context docs or ADRs.
|
|
9930
|
+
- Use \`pourkit-docs-analyzer\` to explain specific context docs or ADRs after locating them.
|
|
9931
|
+
|
|
9932
|
+
Use direct \`fd\`/\`rg\`/reads for focused checks; use subagents when the search would otherwise require several discovery/read steps.
|
|
9933
|
+
|
|
9934
|
+
Use \`opensrc path <package-or-repo>\` whenever implementation requires reading external source code, not only package dependencies. If you would otherwise clone a repository to inspect its source, use \`opensrc\` first, then search or read files under the returned source path with \`rg\` and direct file reads.
|
|
9823
9935
|
|
|
9824
9936
|
Follow the project's domain docs and workflow routes documented in the Pourkit managed block below.
|
|
9825
9937
|
|
|
@@ -9928,7 +10040,7 @@ function resolveSourceAssetPath(sourceRoot, ...segments) {
|
|
|
9928
10040
|
path5.join(sourceRoot, "dist", ...segments)
|
|
9929
10041
|
];
|
|
9930
10042
|
for (const candidatePath of candidatePaths) {
|
|
9931
|
-
if (
|
|
10043
|
+
if (existsSync16(candidatePath)) return candidatePath;
|
|
9932
10044
|
}
|
|
9933
10045
|
return path5.join(sourceRoot, "pourkit", ...segments);
|
|
9934
10046
|
}
|
|
@@ -10291,7 +10403,7 @@ async function computeFileChecksum(filePath) {
|
|
|
10291
10403
|
return createHash("sha256").update(content).digest("hex");
|
|
10292
10404
|
}
|
|
10293
10405
|
function lockfileExists(root, name) {
|
|
10294
|
-
return
|
|
10406
|
+
return existsSync16(path5.join(root, name));
|
|
10295
10407
|
}
|
|
10296
10408
|
function detectPackageManager(root) {
|
|
10297
10409
|
if (lockfileExists(root, "pnpm-lock.yaml")) return "pnpm";
|
|
@@ -10335,7 +10447,7 @@ async function discoverLocalSource(sourcePath) {
|
|
|
10335
10447
|
async function discoverReadme(root) {
|
|
10336
10448
|
for (const name of ["README.md", "readme.md"]) {
|
|
10337
10449
|
const p = path5.join(root, name);
|
|
10338
|
-
if (
|
|
10450
|
+
if (existsSync16(p)) {
|
|
10339
10451
|
return p;
|
|
10340
10452
|
}
|
|
10341
10453
|
}
|
|
@@ -10345,7 +10457,7 @@ async function discoverAgentFiles(root) {
|
|
|
10345
10457
|
const files = [];
|
|
10346
10458
|
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
|
|
10347
10459
|
const p = path5.join(root, name);
|
|
10348
|
-
if (
|
|
10460
|
+
if (existsSync16(p)) {
|
|
10349
10461
|
files.push(p);
|
|
10350
10462
|
}
|
|
10351
10463
|
}
|
|
@@ -10353,7 +10465,7 @@ async function discoverAgentFiles(root) {
|
|
|
10353
10465
|
}
|
|
10354
10466
|
async function discoverMerlleState(root) {
|
|
10355
10467
|
const p = path5.join(root, ".pourkit", "state.json");
|
|
10356
|
-
return
|
|
10468
|
+
return existsSync16(p) ? p : null;
|
|
10357
10469
|
}
|
|
10358
10470
|
async function discoverAgentSkills(root) {
|
|
10359
10471
|
const dirs = [
|
|
@@ -10362,7 +10474,7 @@ async function discoverAgentSkills(root) {
|
|
|
10362
10474
|
];
|
|
10363
10475
|
const found = [];
|
|
10364
10476
|
for (const d of dirs) {
|
|
10365
|
-
if (
|
|
10477
|
+
if (existsSync16(d)) {
|
|
10366
10478
|
found.push(d);
|
|
10367
10479
|
}
|
|
10368
10480
|
}
|
|
@@ -10373,7 +10485,7 @@ async function discoverOpenCodeAgentFiles(sourceRoot) {
|
|
|
10373
10485
|
resolveSourceAssetPath(sourceRoot, ".opencode", "agents"),
|
|
10374
10486
|
path5.join(sourceRoot, "..", ".opencode", "agents")
|
|
10375
10487
|
].find(
|
|
10376
|
-
(candidate) =>
|
|
10488
|
+
(candidate) => existsSync16(candidate) && statSync(candidate).isDirectory()
|
|
10377
10489
|
);
|
|
10378
10490
|
if (!agentsDir) return [];
|
|
10379
10491
|
const entries = await readdir(agentsDir, { withFileTypes: true });
|
|
@@ -10383,12 +10495,12 @@ async function discoverRootDomainDocs(root) {
|
|
|
10383
10495
|
const docs = [];
|
|
10384
10496
|
for (const name of ["CONTEXT.md", "CONTEXT-MAP.md"]) {
|
|
10385
10497
|
const p = path5.join(root, name);
|
|
10386
|
-
if (
|
|
10498
|
+
if (existsSync16(p)) {
|
|
10387
10499
|
docs.push(p);
|
|
10388
10500
|
}
|
|
10389
10501
|
}
|
|
10390
10502
|
const adrDir = path5.join(root, "docs", "adr");
|
|
10391
|
-
if (
|
|
10503
|
+
if (existsSync16(adrDir)) {
|
|
10392
10504
|
const entries = await readdir(adrDir, { withFileTypes: true });
|
|
10393
10505
|
for (const entry of entries) {
|
|
10394
10506
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -10530,7 +10642,7 @@ async function planInit(options) {
|
|
|
10530
10642
|
for (const file of skillFiles) {
|
|
10531
10643
|
const relPath = path5.relative(s, file);
|
|
10532
10644
|
const destPath = path5.join(targetRoot, ".agents", "skills", relPath);
|
|
10533
|
-
if (!
|
|
10645
|
+
if (!existsSync16(destPath)) {
|
|
10534
10646
|
operations.push({
|
|
10535
10647
|
kind: "copy",
|
|
10536
10648
|
sourcePath: file,
|
|
@@ -10593,7 +10705,7 @@ async function planInit(options) {
|
|
|
10593
10705
|
});
|
|
10594
10706
|
}
|
|
10595
10707
|
if (sourceRoot) {
|
|
10596
|
-
if (!
|
|
10708
|
+
if (!existsSync16(sourceRoot) || !statSync(sourceRoot).isDirectory()) {
|
|
10597
10709
|
warnings.push(
|
|
10598
10710
|
`--from-local path does not exist or is not a directory: ${sourceRoot}`
|
|
10599
10711
|
);
|
|
@@ -10658,9 +10770,9 @@ async function planInit(options) {
|
|
|
10658
10770
|
"release",
|
|
10659
10771
|
"skills"
|
|
10660
10772
|
);
|
|
10661
|
-
const srcSkills =
|
|
10773
|
+
const srcSkills = existsSync16(packagedManagedSkills) ? [
|
|
10662
10774
|
packagedManagedSkills,
|
|
10663
|
-
...
|
|
10775
|
+
...existsSync16(packagedReleaseAddonSkills) ? [packagedReleaseAddonSkills] : []
|
|
10664
10776
|
] : await discoverAgentSkills(sourceRoot);
|
|
10665
10777
|
for (const s of srcSkills) {
|
|
10666
10778
|
const isOpenCode = s.includes(".opencode");
|
|
@@ -10683,7 +10795,7 @@ async function planInit(options) {
|
|
|
10683
10795
|
"skills",
|
|
10684
10796
|
relPath
|
|
10685
10797
|
);
|
|
10686
|
-
if (!
|
|
10798
|
+
if (!existsSync16(destPath)) {
|
|
10687
10799
|
operations.push({
|
|
10688
10800
|
kind: "copy",
|
|
10689
10801
|
sourcePath: file,
|
|
@@ -10815,7 +10927,7 @@ async function planInit(options) {
|
|
|
10815
10927
|
requiresConfirmation: false,
|
|
10816
10928
|
destructive: false
|
|
10817
10929
|
});
|
|
10818
|
-
} else if (
|
|
10930
|
+
} else if (existsSync16(destPath)) {
|
|
10819
10931
|
operations.push({
|
|
10820
10932
|
kind: "skip",
|
|
10821
10933
|
path: destPath,
|
|
@@ -10873,7 +10985,7 @@ async function planInit(options) {
|
|
|
10873
10985
|
}
|
|
10874
10986
|
}
|
|
10875
10987
|
const contextPath = path5.join(targetRoot, ".pourkit", "CONTEXT.md");
|
|
10876
|
-
if (!
|
|
10988
|
+
if (!existsSync16(contextPath) && !merleDestPaths.has(contextPath)) {
|
|
10877
10989
|
operations.push({
|
|
10878
10990
|
kind: "create",
|
|
10879
10991
|
path: contextPath,
|
|
@@ -10891,7 +11003,7 @@ async function planInit(options) {
|
|
|
10891
11003
|
"adr",
|
|
10892
11004
|
".gitkeep"
|
|
10893
11005
|
);
|
|
10894
|
-
if (!
|
|
11006
|
+
if (!existsSync16(adrGitkeep)) {
|
|
10895
11007
|
operations.push({
|
|
10896
11008
|
kind: "create",
|
|
10897
11009
|
path: adrGitkeep,
|
|
@@ -10913,7 +11025,7 @@ async function planInit(options) {
|
|
|
10913
11025
|
"docs",
|
|
10914
11026
|
"agents"
|
|
10915
11027
|
);
|
|
10916
|
-
const srcDocAgents =
|
|
11028
|
+
const srcDocAgents = existsSync16(packagedManagedDocAgents) ? packagedManagedDocAgents : legacyDocAgents;
|
|
10917
11029
|
const tgtManagedDocAgents = path5.join(
|
|
10918
11030
|
targetRoot,
|
|
10919
11031
|
".pourkit",
|
|
@@ -10927,12 +11039,12 @@ async function planInit(options) {
|
|
|
10927
11039
|
"docs",
|
|
10928
11040
|
"agents"
|
|
10929
11041
|
);
|
|
10930
|
-
if (
|
|
11042
|
+
if (existsSync16(srcDocAgents)) {
|
|
10931
11043
|
const docFiles = await walkDir(srcDocAgents);
|
|
10932
11044
|
for (const file of docFiles) {
|
|
10933
11045
|
const relPath = path5.relative(srcDocAgents, file);
|
|
10934
11046
|
const managedDocDest = path5.join(tgtManagedDocAgents, relPath);
|
|
10935
|
-
if (!
|
|
11047
|
+
if (!existsSync16(managedDocDest) && relPath === "triage-labels.md") {
|
|
10936
11048
|
operations.push({
|
|
10937
11049
|
kind: "create",
|
|
10938
11050
|
path: managedDocDest,
|
|
@@ -10944,7 +11056,7 @@ async function planInit(options) {
|
|
|
10944
11056
|
options.labels ?? DEFAULT_RUNNER_LABELS
|
|
10945
11057
|
)
|
|
10946
11058
|
});
|
|
10947
|
-
} else if (!
|
|
11059
|
+
} else if (!existsSync16(managedDocDest)) {
|
|
10948
11060
|
const checksum = await computeFileChecksum(file);
|
|
10949
11061
|
operations.push({
|
|
10950
11062
|
kind: "copy",
|
|
@@ -10966,7 +11078,7 @@ async function planInit(options) {
|
|
|
10966
11078
|
relPath
|
|
10967
11079
|
);
|
|
10968
11080
|
const stubDocDest = path5.join(tgtStubDocAgents, relPath);
|
|
10969
|
-
if (
|
|
11081
|
+
if (existsSync16(stubDocDest)) continue;
|
|
10970
11082
|
operations.push({
|
|
10971
11083
|
kind: "create",
|
|
10972
11084
|
path: stubDocDest,
|
|
@@ -11000,7 +11112,7 @@ Do not edit this file.
|
|
|
11000
11112
|
"docs",
|
|
11001
11113
|
"agents"
|
|
11002
11114
|
);
|
|
11003
|
-
if (
|
|
11115
|
+
if (existsSync16(packagedReleaseAddonDocs)) {
|
|
11004
11116
|
const docFiles = await walkDir(packagedReleaseAddonDocs);
|
|
11005
11117
|
for (const file of docFiles) {
|
|
11006
11118
|
const relPath = path5.relative(packagedReleaseAddonDocs, file);
|
|
@@ -11024,19 +11136,19 @@ Do not edit this file.
|
|
|
11024
11136
|
"prompts"
|
|
11025
11137
|
);
|
|
11026
11138
|
const legacyPrompts = path5.join(sourceRoot, ".pourkit", "prompts");
|
|
11027
|
-
const srcPrompts =
|
|
11139
|
+
const srcPrompts = existsSync16(packagedManagedPrompts) ? packagedManagedPrompts : legacyPrompts;
|
|
11028
11140
|
const tgtManagedPrompts = path5.join(
|
|
11029
11141
|
targetRoot,
|
|
11030
11142
|
".pourkit",
|
|
11031
11143
|
"managed",
|
|
11032
11144
|
"prompts"
|
|
11033
11145
|
);
|
|
11034
|
-
if (
|
|
11146
|
+
if (existsSync16(srcPrompts)) {
|
|
11035
11147
|
const promptFiles = await walkDir(srcPrompts);
|
|
11036
11148
|
for (const file of promptFiles) {
|
|
11037
11149
|
const relPath = path5.relative(srcPrompts, file);
|
|
11038
11150
|
const promptDest = path5.join(tgtManagedPrompts, relPath);
|
|
11039
|
-
if (
|
|
11151
|
+
if (existsSync16(promptDest)) continue;
|
|
11040
11152
|
const checksum = await computeFileChecksum(file);
|
|
11041
11153
|
operations.push({
|
|
11042
11154
|
kind: "copy",
|
|
@@ -11060,7 +11172,7 @@ Do not edit this file.
|
|
|
11060
11172
|
".sandcastle",
|
|
11061
11173
|
"Dockerfile"
|
|
11062
11174
|
);
|
|
11063
|
-
if (
|
|
11175
|
+
if (existsSync16(tgtSandboxDockerfile)) {
|
|
11064
11176
|
operations.push({
|
|
11065
11177
|
kind: "skip",
|
|
11066
11178
|
path: tgtSandboxDockerfile,
|
|
@@ -11069,7 +11181,7 @@ Do not edit this file.
|
|
|
11069
11181
|
requiresConfirmation: false,
|
|
11070
11182
|
destructive: false
|
|
11071
11183
|
});
|
|
11072
|
-
} else if (
|
|
11184
|
+
} else if (existsSync16(srcSandboxDockerfile)) {
|
|
11073
11185
|
const checksum = await computeFileChecksum(srcSandboxDockerfile);
|
|
11074
11186
|
operations.push({
|
|
11075
11187
|
kind: "copy",
|
|
@@ -11083,7 +11195,7 @@ Do not edit this file.
|
|
|
11083
11195
|
});
|
|
11084
11196
|
}
|
|
11085
11197
|
const configJsonPath = path5.join(targetRoot, ".pourkit", "config.json");
|
|
11086
|
-
if (!
|
|
11198
|
+
if (!existsSync16(configJsonPath)) {
|
|
11087
11199
|
const verifyCommands = inferVerificationCommands(
|
|
11088
11200
|
packageScripts,
|
|
11089
11201
|
pm || "npm"
|
|
@@ -11127,9 +11239,9 @@ Do not edit this file.
|
|
|
11127
11239
|
"schema",
|
|
11128
11240
|
"pourkit.schema.json"
|
|
11129
11241
|
);
|
|
11130
|
-
if (
|
|
11242
|
+
if (existsSync16(srcSchemaJson)) {
|
|
11131
11243
|
const checksum = await computeFileChecksum(srcSchemaJson);
|
|
11132
|
-
if (!
|
|
11244
|
+
if (!existsSync16(schemaJsonPath)) {
|
|
11133
11245
|
operations.push({
|
|
11134
11246
|
kind: "copy",
|
|
11135
11247
|
sourcePath: srcSchemaJson,
|
|
@@ -11162,9 +11274,9 @@ Do not edit this file.
|
|
|
11162
11274
|
"schema",
|
|
11163
11275
|
"pourkit.schema.hash"
|
|
11164
11276
|
);
|
|
11165
|
-
if (
|
|
11277
|
+
if (existsSync16(srcSchemaHash)) {
|
|
11166
11278
|
const checksum = await computeFileChecksum(srcSchemaHash);
|
|
11167
|
-
if (!
|
|
11279
|
+
if (!existsSync16(schemaHashPath)) {
|
|
11168
11280
|
operations.push({
|
|
11169
11281
|
kind: "copy",
|
|
11170
11282
|
sourcePath: srcSchemaHash,
|
|
@@ -11190,7 +11302,7 @@ Do not edit this file.
|
|
|
11190
11302
|
const hasExistingAgents = operations.some(
|
|
11191
11303
|
(op) => (op.kind === "skip" || op.kind === "update") && op.path?.endsWith("AGENTS.md")
|
|
11192
11304
|
);
|
|
11193
|
-
if ((agentFileMode === "agents" || agentFileMode === "both") && !hasExistingAgents && !
|
|
11305
|
+
if ((agentFileMode === "agents" || agentFileMode === "both") && !hasExistingAgents && !existsSync16(path5.join(targetRoot, "AGENTS.md"))) {
|
|
11194
11306
|
operations.push({
|
|
11195
11307
|
kind: "create",
|
|
11196
11308
|
path: path5.join(targetRoot, "AGENTS.md"),
|
|
@@ -11206,7 +11318,7 @@ ${managedAgentContent}${MANAGED_BLOCK_END}
|
|
|
11206
11318
|
const hasExistingClaude = operations.some(
|
|
11207
11319
|
(op) => (op.kind === "skip" || op.kind === "update") && op.path?.endsWith("CLAUDE.md")
|
|
11208
11320
|
);
|
|
11209
|
-
if ((agentFileMode === "claude" || agentFileMode === "both") && !hasExistingClaude && !
|
|
11321
|
+
if ((agentFileMode === "claude" || agentFileMode === "both") && !hasExistingClaude && !existsSync16(path5.join(targetRoot, "CLAUDE.md"))) {
|
|
11210
11322
|
operations.push({
|
|
11211
11323
|
kind: "create",
|
|
11212
11324
|
path: path5.join(targetRoot, "CLAUDE.md"),
|
|
@@ -11221,7 +11333,7 @@ ${managedAgentContent}${MANAGED_BLOCK_END}
|
|
|
11221
11333
|
}
|
|
11222
11334
|
const gitignoreTarget = path5.join(targetRoot, ".gitignore");
|
|
11223
11335
|
const gitignoreContent = generateGitignoreBlock();
|
|
11224
|
-
if (!
|
|
11336
|
+
if (!existsSync16(gitignoreTarget)) {
|
|
11225
11337
|
operations.push({
|
|
11226
11338
|
kind: "create",
|
|
11227
11339
|
path: gitignoreTarget,
|
|
@@ -11252,7 +11364,7 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
|
|
|
11252
11364
|
"agents",
|
|
11253
11365
|
path5.basename(agentFile)
|
|
11254
11366
|
);
|
|
11255
|
-
if (!
|
|
11367
|
+
if (!existsSync16(targetPath)) {
|
|
11256
11368
|
operations.push({
|
|
11257
11369
|
kind: "copy",
|
|
11258
11370
|
sourcePath: agentFile,
|
|
@@ -11275,7 +11387,7 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
|
|
|
11275
11387
|
}
|
|
11276
11388
|
}
|
|
11277
11389
|
const manifestPath = path5.join(targetRoot, ".pourkit", "manifest.json");
|
|
11278
|
-
if (
|
|
11390
|
+
if (existsSync16(manifestPath)) {
|
|
11279
11391
|
operations.push({
|
|
11280
11392
|
kind: "skip",
|
|
11281
11393
|
path: manifestPath,
|
|
@@ -11665,7 +11777,7 @@ async function updateManagedBlock(filePath, content) {
|
|
|
11665
11777
|
const blockContent = `${MANAGED_BLOCK_BEGIN}
|
|
11666
11778
|
${content}${MANAGED_BLOCK_END}
|
|
11667
11779
|
`;
|
|
11668
|
-
if (!
|
|
11780
|
+
if (!existsSync16(filePath)) {
|
|
11669
11781
|
const dir = path5.dirname(filePath);
|
|
11670
11782
|
await mkdir4(dir, { recursive: true });
|
|
11671
11783
|
await writeFileAtomic(filePath, blockContent);
|
|
@@ -11694,7 +11806,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
|
|
|
11694
11806
|
if (op.requiresConfirmation) continue;
|
|
11695
11807
|
const relPath = path5.relative(plan.targetRoot, op.path);
|
|
11696
11808
|
if (relPath === ".pourkit/manifest.json") continue;
|
|
11697
|
-
if (
|
|
11809
|
+
if (existsSync16(op.path)) {
|
|
11698
11810
|
const sha256 = await computeFileChecksum(op.path);
|
|
11699
11811
|
assets[relPath] = {
|
|
11700
11812
|
ownership: op.ownership || "managed",
|
|
@@ -11740,7 +11852,7 @@ async function applyInitPlan(plan, options) {
|
|
|
11740
11852
|
skipped++;
|
|
11741
11853
|
continue;
|
|
11742
11854
|
}
|
|
11743
|
-
if (
|
|
11855
|
+
if (existsSync16(op.path) && !op.destructive) {
|
|
11744
11856
|
skipped++;
|
|
11745
11857
|
continue;
|
|
11746
11858
|
}
|
|
@@ -11755,7 +11867,7 @@ async function applyInitPlan(plan, options) {
|
|
|
11755
11867
|
skipped++;
|
|
11756
11868
|
continue;
|
|
11757
11869
|
}
|
|
11758
|
-
if (
|
|
11870
|
+
if (existsSync16(op.path)) {
|
|
11759
11871
|
skipped++;
|
|
11760
11872
|
continue;
|
|
11761
11873
|
}
|
|
@@ -11784,7 +11896,7 @@ async function applyInitPlan(plan, options) {
|
|
|
11784
11896
|
skipped++;
|
|
11785
11897
|
continue;
|
|
11786
11898
|
}
|
|
11787
|
-
if (
|
|
11899
|
+
if (existsSync16(op.path)) {
|
|
11788
11900
|
skipped++;
|
|
11789
11901
|
continue;
|
|
11790
11902
|
}
|
|
@@ -11928,7 +12040,7 @@ async function applyInitFromSource(options) {
|
|
|
11928
12040
|
if (!manifestSkipped) {
|
|
11929
12041
|
const agentFiles = [];
|
|
11930
12042
|
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
|
|
11931
|
-
if (
|
|
12043
|
+
if (existsSync16(path5.join(targetRoot, name))) {
|
|
11932
12044
|
agentFiles.push(path5.join(targetRoot, name));
|
|
11933
12045
|
}
|
|
11934
12046
|
}
|
|
@@ -12104,18 +12216,18 @@ Init applied: ${result.applied} operations applied, ${result.skipped} skipped.`
|
|
|
12104
12216
|
}
|
|
12105
12217
|
|
|
12106
12218
|
// commands/memory-init.ts
|
|
12107
|
-
import { existsSync as
|
|
12219
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync18, writeFileSync as writeFileSync5 } from "fs";
|
|
12108
12220
|
import { join as join18 } from "path";
|
|
12109
12221
|
async function runMemoryInitCommand(options) {
|
|
12110
12222
|
const cwd = options.cwd ?? process.cwd();
|
|
12111
12223
|
const configPath = join18(cwd, ".pourkit", "config.json");
|
|
12112
|
-
if (!
|
|
12224
|
+
if (!existsSync17(configPath)) {
|
|
12113
12225
|
return {
|
|
12114
12226
|
ok: false,
|
|
12115
12227
|
message: "No .pourkit/config.json found. Run `pourkit init` first to initialize Pourkit, then run `pourkit memory init`."
|
|
12116
12228
|
};
|
|
12117
12229
|
}
|
|
12118
|
-
const raw = JSON.parse(
|
|
12230
|
+
const raw = JSON.parse(readFileSync18(configPath, "utf8"));
|
|
12119
12231
|
let alreadyEnabled = false;
|
|
12120
12232
|
if (Object.prototype.hasOwnProperty.call(raw, "memory")) {
|
|
12121
12233
|
const m = raw.memory;
|
|
@@ -12150,7 +12262,7 @@ async function runMemoryInitCommand(options) {
|
|
|
12150
12262
|
let updatedAgentFile = false;
|
|
12151
12263
|
for (const fileName of ["AGENTS.md", "CLAUDE.md"]) {
|
|
12152
12264
|
const agentPath = join18(cwd, fileName);
|
|
12153
|
-
if (
|
|
12265
|
+
if (existsSync17(agentPath)) {
|
|
12154
12266
|
updateManagedBlockSync(agentPath, managed);
|
|
12155
12267
|
updatedAgentFile = true;
|
|
12156
12268
|
}
|
|
@@ -12168,11 +12280,11 @@ function updateManagedBlockSync(filePath, content) {
|
|
|
12168
12280
|
const blockContent = `${MANAGED_BLOCK_BEGIN}
|
|
12169
12281
|
${content}${MANAGED_BLOCK_END}
|
|
12170
12282
|
`;
|
|
12171
|
-
if (!
|
|
12283
|
+
if (!existsSync17(filePath)) {
|
|
12172
12284
|
writeFileSync5(filePath, blockContent);
|
|
12173
12285
|
return;
|
|
12174
12286
|
}
|
|
12175
|
-
const existing =
|
|
12287
|
+
const existing = readFileSync18(filePath, "utf8");
|
|
12176
12288
|
const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN);
|
|
12177
12289
|
const endIdx = existing.indexOf(MANAGED_BLOCK_END);
|
|
12178
12290
|
if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
|
|
@@ -12301,7 +12413,7 @@ async function runSerenaStatusCommand(options) {
|
|
|
12301
12413
|
}
|
|
12302
12414
|
|
|
12303
12415
|
// commands/config-schema.ts
|
|
12304
|
-
import { readFileSync as
|
|
12416
|
+
import { readFileSync as readFileSync19, existsSync as existsSync18 } from "fs";
|
|
12305
12417
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile2, readdir as readdir2 } from "fs/promises";
|
|
12306
12418
|
import { resolve as resolve3, dirname as dirname5, relative as relative2 } from "path";
|
|
12307
12419
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -12314,7 +12426,7 @@ function resolvePackagedAssetPath2(fileName) {
|
|
|
12314
12426
|
resolve3(__dirname3, "schema", fileName),
|
|
12315
12427
|
resolve3(__dirname3, "../schema", fileName)
|
|
12316
12428
|
];
|
|
12317
|
-
return candidates.find((candidate) =>
|
|
12429
|
+
return candidates.find((candidate) => existsSync18(candidate)) ?? candidates[0];
|
|
12318
12430
|
}
|
|
12319
12431
|
var PACKAGED_SCHEMA_PATH = resolvePackagedAssetPath2("pourkit.schema.json");
|
|
12320
12432
|
var PACKAGED_HASH_PATH = resolvePackagedAssetPath2("pourkit.schema.hash");
|
|
@@ -12322,7 +12434,7 @@ var _schemaValidator = null;
|
|
|
12322
12434
|
var _schemaErrors = null;
|
|
12323
12435
|
function getSchemaValidator() {
|
|
12324
12436
|
if (!_schemaValidator) {
|
|
12325
|
-
const schema = JSON.parse(
|
|
12437
|
+
const schema = JSON.parse(readFileSync19(PACKAGED_SCHEMA_PATH, "utf-8"));
|
|
12326
12438
|
const ajv = new Ajv2({ strict: true });
|
|
12327
12439
|
ajv.addKeyword("x-pourkit-schema-version");
|
|
12328
12440
|
const validate = ajv.compile(schema);
|
|
@@ -12336,7 +12448,7 @@ function getSchemaValidator() {
|
|
|
12336
12448
|
return _schemaValidator;
|
|
12337
12449
|
}
|
|
12338
12450
|
function readPackagedHash() {
|
|
12339
|
-
return
|
|
12451
|
+
return readFileSync19(PACKAGED_HASH_PATH, "utf-8");
|
|
12340
12452
|
}
|
|
12341
12453
|
function localSchemaDir(repoRoot2) {
|
|
12342
12454
|
return resolve3(repoRoot2, ".pourkit/schema");
|
|
@@ -12457,7 +12569,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12457
12569
|
const baselineSkills = getBaselineManagedSkillNames();
|
|
12458
12570
|
for (const docName of catalog.docs) {
|
|
12459
12571
|
const localPath = resolve3(cwd, `.pourkit/managed/docs/agents/${docName}`);
|
|
12460
|
-
if (!
|
|
12572
|
+
if (!existsSync18(localPath)) {
|
|
12461
12573
|
failures.push({
|
|
12462
12574
|
severity: "failure",
|
|
12463
12575
|
kind: "missing_managed_asset",
|
|
@@ -12475,7 +12587,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12475
12587
|
cwd,
|
|
12476
12588
|
`.pourkit/overrides/docs/agents/${docName}`
|
|
12477
12589
|
);
|
|
12478
|
-
if (
|
|
12590
|
+
if (existsSync18(overridePath)) {
|
|
12479
12591
|
warnings.push({
|
|
12480
12592
|
severity: "warning",
|
|
12481
12593
|
kind: "overridden",
|
|
@@ -12498,7 +12610,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12498
12610
|
}
|
|
12499
12611
|
for (const skillName of baselineSkills) {
|
|
12500
12612
|
const skillDir = resolve3(cwd, `.pourkit/managed/skills/${skillName}`);
|
|
12501
|
-
if (!
|
|
12613
|
+
if (!existsSync18(skillDir)) {
|
|
12502
12614
|
failures.push({
|
|
12503
12615
|
severity: "failure",
|
|
12504
12616
|
kind: "missing_managed_asset",
|
|
@@ -12507,7 +12619,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12507
12619
|
});
|
|
12508
12620
|
} else {
|
|
12509
12621
|
const skillSourcePath = resolve3(skillDir, "SKILL.md");
|
|
12510
|
-
if (
|
|
12622
|
+
if (existsSync18(skillSourcePath)) {
|
|
12511
12623
|
const packagedSkillPath = resolvePackagedManagedPath(
|
|
12512
12624
|
"skills",
|
|
12513
12625
|
skillName,
|
|
@@ -12522,7 +12634,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12522
12634
|
cwd,
|
|
12523
12635
|
`.pourkit/overrides/skills/${skillName}/SKILL.md`
|
|
12524
12636
|
);
|
|
12525
|
-
if (
|
|
12637
|
+
if (existsSync18(overridePath)) {
|
|
12526
12638
|
warnings.push({
|
|
12527
12639
|
severity: "warning",
|
|
12528
12640
|
kind: "overridden",
|
|
@@ -12546,7 +12658,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12546
12658
|
}
|
|
12547
12659
|
for (const promptName of catalog.prompts) {
|
|
12548
12660
|
const promptPath = resolve3(cwd, `.pourkit/managed/prompts/${promptName}`);
|
|
12549
|
-
if (!
|
|
12661
|
+
if (!existsSync18(promptPath)) {
|
|
12550
12662
|
failures.push({
|
|
12551
12663
|
severity: "failure",
|
|
12552
12664
|
kind: "missing_managed_asset",
|
|
@@ -12557,7 +12669,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12557
12669
|
}
|
|
12558
12670
|
for (const skillName of baselineSkills) {
|
|
12559
12671
|
const projectionDir = resolve3(cwd, `.agents/skills/${skillName}`);
|
|
12560
|
-
if (!
|
|
12672
|
+
if (!existsSync18(projectionDir)) {
|
|
12561
12673
|
warnings.push({
|
|
12562
12674
|
severity: "warning",
|
|
12563
12675
|
kind: "projection_stale",
|
|
@@ -12566,7 +12678,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12566
12678
|
});
|
|
12567
12679
|
} else {
|
|
12568
12680
|
const projectionPath = resolve3(projectionDir, "SKILL.md");
|
|
12569
|
-
if (
|
|
12681
|
+
if (existsSync18(projectionPath)) {
|
|
12570
12682
|
const managedSourcePath = resolvePackagedManagedPath(
|
|
12571
12683
|
"skills",
|
|
12572
12684
|
skillName,
|
|
@@ -12595,7 +12707,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12595
12707
|
}
|
|
12596
12708
|
}
|
|
12597
12709
|
const agentsPath = resolve3(cwd, "AGENTS.md");
|
|
12598
|
-
if (
|
|
12710
|
+
if (existsSync18(agentsPath)) {
|
|
12599
12711
|
try {
|
|
12600
12712
|
const agentsContent = await readFile5(agentsPath, "utf-8");
|
|
12601
12713
|
if (agentsContent.includes(OLD_DOCS_PATH_PATTERN)) {
|
|
@@ -12618,7 +12730,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12618
12730
|
}
|
|
12619
12731
|
}
|
|
12620
12732
|
const overridesDir = resolve3(cwd, ".pourkit/overrides");
|
|
12621
|
-
if (
|
|
12733
|
+
if (existsSync18(overridesDir)) {
|
|
12622
12734
|
const overrideFiles = await walkDir2(overridesDir);
|
|
12623
12735
|
for (const file of overrideFiles) {
|
|
12624
12736
|
const relPath = relative2(cwd, file);
|
|
@@ -12633,7 +12745,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12633
12745
|
}
|
|
12634
12746
|
}
|
|
12635
12747
|
const configPath = resolve3(cwd, ".pourkit/config.json");
|
|
12636
|
-
if (
|
|
12748
|
+
if (existsSync18(configPath)) {
|
|
12637
12749
|
try {
|
|
12638
12750
|
const configContent = await readFile5(configPath, "utf-8");
|
|
12639
12751
|
const parsed = JSON.parse(configContent);
|
|
@@ -12644,7 +12756,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12644
12756
|
cwd,
|
|
12645
12757
|
`.pourkit/managed/addons/release/skills/${skillName}`
|
|
12646
12758
|
);
|
|
12647
|
-
if (!
|
|
12759
|
+
if (!existsSync18(addonDir)) {
|
|
12648
12760
|
failures.push({
|
|
12649
12761
|
severity: "failure",
|
|
12650
12762
|
kind: "release_config_conflict",
|
|
@@ -12658,7 +12770,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12658
12770
|
cwd,
|
|
12659
12771
|
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
12660
12772
|
);
|
|
12661
|
-
if (!
|
|
12773
|
+
if (!existsSync18(addonDocPath)) {
|
|
12662
12774
|
failures.push({
|
|
12663
12775
|
severity: "failure",
|
|
12664
12776
|
kind: "release_config_conflict",
|
|
@@ -12703,7 +12815,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12703
12815
|
cwd,
|
|
12704
12816
|
`.pourkit/managed/addons/release/skills/${skillName}`
|
|
12705
12817
|
);
|
|
12706
|
-
if (
|
|
12818
|
+
if (existsSync18(addonDir)) {
|
|
12707
12819
|
failures.push({
|
|
12708
12820
|
severity: "failure",
|
|
12709
12821
|
kind: "release_config_conflict",
|
|
@@ -12717,7 +12829,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12717
12829
|
cwd,
|
|
12718
12830
|
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
12719
12831
|
);
|
|
12720
|
-
if (
|
|
12832
|
+
if (existsSync18(addonDocPath)) {
|
|
12721
12833
|
failures.push({
|
|
12722
12834
|
severity: "failure",
|
|
12723
12835
|
kind: "release_config_conflict",
|
|
@@ -12731,7 +12843,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12731
12843
|
}
|
|
12732
12844
|
}
|
|
12733
12845
|
const manifestPath = resolve3(cwd, ".pourkit/manifest.json");
|
|
12734
|
-
if (
|
|
12846
|
+
if (existsSync18(manifestPath)) {
|
|
12735
12847
|
try {
|
|
12736
12848
|
const manifestContent = await readFile5(manifestPath, "utf-8");
|
|
12737
12849
|
const manifest = JSON.parse(manifestContent);
|
|
@@ -12754,7 +12866,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12754
12866
|
}
|
|
12755
12867
|
}
|
|
12756
12868
|
const pathEscapeOverrideDir = resolve3(cwd, ".pourkit/overrides");
|
|
12757
|
-
if (
|
|
12869
|
+
if (existsSync18(pathEscapeOverrideDir)) {
|
|
12758
12870
|
const overrideFiles = await walkDir2(pathEscapeOverrideDir);
|
|
12759
12871
|
for (const file of overrideFiles) {
|
|
12760
12872
|
if (!isPathContained(cwd, file)) {
|
|
@@ -12768,7 +12880,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12768
12880
|
}
|
|
12769
12881
|
}
|
|
12770
12882
|
const managedDocsDir = resolve3(cwd, ".pourkit/managed/docs/agents");
|
|
12771
|
-
if (
|
|
12883
|
+
if (existsSync18(managedDocsDir)) {
|
|
12772
12884
|
const docFiles = await walkDir2(managedDocsDir);
|
|
12773
12885
|
for (const file of docFiles) {
|
|
12774
12886
|
if (!file.endsWith(".md")) continue;
|
|
@@ -12789,12 +12901,12 @@ async function validateWorkflowPack(cwd) {
|
|
|
12789
12901
|
}
|
|
12790
12902
|
}
|
|
12791
12903
|
const managedSkillsDir = resolve3(cwd, ".pourkit/managed/skills");
|
|
12792
|
-
if (
|
|
12904
|
+
if (existsSync18(managedSkillsDir)) {
|
|
12793
12905
|
const skillDirs = await readdir2(managedSkillsDir, { withFileTypes: true });
|
|
12794
12906
|
for (const entry of skillDirs) {
|
|
12795
12907
|
if (!entry.isDirectory()) continue;
|
|
12796
12908
|
const skillFile = resolve3(managedSkillsDir, entry.name, "SKILL.md");
|
|
12797
|
-
if (!
|
|
12909
|
+
if (!existsSync18(skillFile)) continue;
|
|
12798
12910
|
try {
|
|
12799
12911
|
const content = await readFile5(skillFile, "utf-8");
|
|
12800
12912
|
const relPath = relative2(cwd, skillFile);
|
|
@@ -12812,10 +12924,10 @@ async function validateWorkflowPack(cwd) {
|
|
|
12812
12924
|
}
|
|
12813
12925
|
}
|
|
12814
12926
|
const managedPromptsDir = resolve3(cwd, ".pourkit/managed/prompts");
|
|
12815
|
-
if (
|
|
12927
|
+
if (existsSync18(managedPromptsDir)) {
|
|
12816
12928
|
for (const promptName of catalog.prompts) {
|
|
12817
12929
|
const promptFile = resolve3(managedPromptsDir, promptName);
|
|
12818
|
-
if (!
|
|
12930
|
+
if (!existsSync18(promptFile)) continue;
|
|
12819
12931
|
try {
|
|
12820
12932
|
const content = await readFile5(promptFile, "utf-8");
|
|
12821
12933
|
const relPath = relative2(cwd, promptFile);
|
|
@@ -12837,7 +12949,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12837
12949
|
cwd,
|
|
12838
12950
|
`.pourkit/managed/addons/release/skills/${skillName}/SKILL.md`
|
|
12839
12951
|
);
|
|
12840
|
-
if (!
|
|
12952
|
+
if (!existsSync18(addonSkillFile)) continue;
|
|
12841
12953
|
try {
|
|
12842
12954
|
const content = await readFile5(addonSkillFile, "utf-8");
|
|
12843
12955
|
const relPath = relative2(cwd, addonSkillFile);
|
|
@@ -12858,7 +12970,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12858
12970
|
cwd,
|
|
12859
12971
|
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
12860
12972
|
);
|
|
12861
|
-
if (!
|
|
12973
|
+
if (!existsSync18(addonDocFile)) continue;
|
|
12862
12974
|
try {
|
|
12863
12975
|
const content = await readFile5(addonDocFile, "utf-8");
|
|
12864
12976
|
const relPath = relative2(cwd, addonDocFile);
|
|
@@ -12892,7 +13004,7 @@ async function validateMemoryHealth(cwd, memoryConfig) {
|
|
|
12892
13004
|
detail: icmPath !== null ? icmPath : "icm not found on PATH"
|
|
12893
13005
|
});
|
|
12894
13006
|
const gitignorePath = resolve3(cwd, ".gitignore");
|
|
12895
|
-
const gitignoreContent =
|
|
13007
|
+
const gitignoreContent = existsSync18(gitignorePath) ? readFileSync19(gitignorePath, "utf-8") : "";
|
|
12896
13008
|
const hasGitignoreEntry = gitignoreContent.includes(".pourkit/icm/");
|
|
12897
13009
|
checks.push({
|
|
12898
13010
|
name: "icm-gitignore",
|
|
@@ -12919,8 +13031,8 @@ async function runDoctorCommand(options) {
|
|
|
12919
13031
|
const schemaDir = localSchemaDir(repoRootPath);
|
|
12920
13032
|
const localSchemaPath = resolve3(schemaDir, "pourkit.schema.json");
|
|
12921
13033
|
const localHashPath = resolve3(schemaDir, "pourkit.schema.hash");
|
|
12922
|
-
const localSchemaExists =
|
|
12923
|
-
const localHashExists =
|
|
13034
|
+
const localSchemaExists = existsSync18(localSchemaPath);
|
|
13035
|
+
const localHashExists = existsSync18(localHashPath);
|
|
12924
13036
|
let packagedHash = null;
|
|
12925
13037
|
try {
|
|
12926
13038
|
packagedHash = readPackagedHash();
|
|
@@ -12939,9 +13051,9 @@ async function runDoctorCommand(options) {
|
|
|
12939
13051
|
const configPath = resolve3(repoRootPath, ".pourkit/config.json");
|
|
12940
13052
|
let configValidation;
|
|
12941
13053
|
let rawMemoryConfig;
|
|
12942
|
-
if (
|
|
13054
|
+
if (existsSync18(configPath)) {
|
|
12943
13055
|
try {
|
|
12944
|
-
const raw = JSON.parse(
|
|
13056
|
+
const raw = JSON.parse(readFileSync19(configPath, "utf-8"));
|
|
12945
13057
|
rawMemoryConfig = raw.memory;
|
|
12946
13058
|
const validate = getSchemaValidator();
|
|
12947
13059
|
const valid2 = validate(raw);
|
|
@@ -12974,7 +13086,7 @@ async function runDoctorCommand(options) {
|
|
|
12974
13086
|
"pourkit.config.mjs",
|
|
12975
13087
|
"pourkit.config.js",
|
|
12976
13088
|
"pourkit.json"
|
|
12977
|
-
].filter((p) =>
|
|
13089
|
+
].filter((p) => existsSync18(resolve3(repoRootPath, p)));
|
|
12978
13090
|
const workflowPack = await validateWorkflowPack(repoRootPath);
|
|
12979
13091
|
const memory = await validateMemoryHealth(repoRootPath, rawMemoryConfig);
|
|
12980
13092
|
let recommendation = null;
|
|
@@ -13024,7 +13136,7 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
13024
13136
|
const localHashPath = resolve3(schemaDir, "pourkit.schema.hash");
|
|
13025
13137
|
let schemaWritten = false;
|
|
13026
13138
|
let hashWritten = false;
|
|
13027
|
-
if (
|
|
13139
|
+
if (existsSync18(localSchemaPath)) {
|
|
13028
13140
|
const existing = await readFile5(localSchemaPath, "utf-8");
|
|
13029
13141
|
if (existing !== packagedSchema) {
|
|
13030
13142
|
await writeFile2(localSchemaPath, packagedSchema, "utf-8");
|
|
@@ -13034,7 +13146,7 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
13034
13146
|
await writeFile2(localSchemaPath, packagedSchema, "utf-8");
|
|
13035
13147
|
schemaWritten = true;
|
|
13036
13148
|
}
|
|
13037
|
-
if (
|
|
13149
|
+
if (existsSync18(localHashPath)) {
|
|
13038
13150
|
const existing = await readFile5(localHashPath, "utf-8");
|
|
13039
13151
|
if (existing !== packagedHash) {
|
|
13040
13152
|
await writeFile2(localHashPath, packagedHash, "utf-8");
|
|
@@ -13052,7 +13164,7 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
13052
13164
|
}
|
|
13053
13165
|
|
|
13054
13166
|
// commands/workflow-pack-sync.ts
|
|
13055
|
-
import { existsSync as
|
|
13167
|
+
import { existsSync as existsSync19, readdirSync as readdirSync4 } from "fs";
|
|
13056
13168
|
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir3 } from "fs/promises";
|
|
13057
13169
|
import { resolve as resolve4, dirname as dirname6, relative as relative3, normalize as normalize2 } from "path";
|
|
13058
13170
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -13175,7 +13287,7 @@ async function syncFile(cwd, targetRelativePath, sourceContent, errors) {
|
|
|
13175
13287
|
return false;
|
|
13176
13288
|
}
|
|
13177
13289
|
await mkdir6(resolve4(targetPath, ".."), { recursive: true });
|
|
13178
|
-
if (
|
|
13290
|
+
if (existsSync19(targetPath)) {
|
|
13179
13291
|
const existing = await readFile6(targetPath, "utf-8");
|
|
13180
13292
|
if (existing === sourceContent) {
|
|
13181
13293
|
return false;
|
|
@@ -13202,7 +13314,7 @@ function walkDirSync(dir) {
|
|
|
13202
13314
|
}
|
|
13203
13315
|
async function detectOverrides(cwd) {
|
|
13204
13316
|
const overridesDir = resolve4(cwd, OVERRIDES_DIR);
|
|
13205
|
-
if (!
|
|
13317
|
+
if (!existsSync19(overridesDir)) {
|
|
13206
13318
|
return [];
|
|
13207
13319
|
}
|
|
13208
13320
|
const files = await walkDir3(overridesDir);
|
|
@@ -13212,13 +13324,13 @@ async function detectProjectOwnedFiles(cwd) {
|
|
|
13212
13324
|
const found = [];
|
|
13213
13325
|
for (const ownedPath of PROJECT_OWNED_PATHS) {
|
|
13214
13326
|
const fullPath = resolve4(cwd, ownedPath);
|
|
13215
|
-
if (
|
|
13327
|
+
if (existsSync19(fullPath)) {
|
|
13216
13328
|
found.push(ownedPath);
|
|
13217
13329
|
}
|
|
13218
13330
|
}
|
|
13219
13331
|
for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
|
|
13220
13332
|
const fullDir = resolve4(cwd, ownedDir);
|
|
13221
|
-
if (
|
|
13333
|
+
if (existsSync19(fullDir)) {
|
|
13222
13334
|
const files = await walkDir3(fullDir);
|
|
13223
13335
|
for (const file of files) {
|
|
13224
13336
|
found.push(relative3(cwd, file));
|
|
@@ -13370,7 +13482,7 @@ async function runWorkflowPackSyncCommand(options) {
|
|
|
13370
13482
|
const fullManagedBlock = `${MANAGED_BLOCK_BEGIN3}${managedBlockContent}${MANAGED_BLOCK_END2}`;
|
|
13371
13483
|
async function syncManagedAgentFile(fileName, options2) {
|
|
13372
13484
|
const filePath = resolve4(cwd, fileName);
|
|
13373
|
-
if (!
|
|
13485
|
+
if (!existsSync19(filePath)) {
|
|
13374
13486
|
if (!options2.createIfMissing) return false;
|
|
13375
13487
|
await writeFile3(filePath, fullManagedBlock + "\n", "utf-8");
|
|
13376
13488
|
return true;
|
|
@@ -14152,7 +14264,7 @@ function formatChecks2(checks) {
|
|
|
14152
14264
|
init_common();
|
|
14153
14265
|
|
|
14154
14266
|
// execution/sandcastle-execution.ts
|
|
14155
|
-
import { existsSync as
|
|
14267
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
14156
14268
|
import { join as join21 } from "path";
|
|
14157
14269
|
import { createWorktree, opencode } from "@ai-hero/sandcastle";
|
|
14158
14270
|
import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
|
|
@@ -14180,18 +14292,18 @@ import path7 from "path";
|
|
|
14180
14292
|
|
|
14181
14293
|
// execution/sandbox-image.ts
|
|
14182
14294
|
import { createHash as createHash2 } from "crypto";
|
|
14183
|
-
import { existsSync as
|
|
14295
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
|
|
14184
14296
|
import path6 from "path";
|
|
14185
14297
|
function sandboxImageName(repoRoot2, installIcm) {
|
|
14186
14298
|
const dirName = path6.basename(repoRoot2.replace(/[\\/]+$/, "")) || "local";
|
|
14187
14299
|
const sanitized = dirName.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
|
|
14188
14300
|
const baseName = sanitized || "local";
|
|
14189
14301
|
const dockerfilePath = path6.join(repoRoot2, ".sandcastle", "Dockerfile");
|
|
14190
|
-
if (!
|
|
14302
|
+
if (!existsSync20(dockerfilePath)) {
|
|
14191
14303
|
const base2 = `sandcastle:${baseName}`;
|
|
14192
14304
|
return installIcm ? `${base2}-icm` : base2;
|
|
14193
14305
|
}
|
|
14194
|
-
const fingerprint = createHash2("sha256").update(
|
|
14306
|
+
const fingerprint = createHash2("sha256").update(readFileSync20(dockerfilePath)).digest("hex").slice(0, 8);
|
|
14195
14307
|
const base = `sandcastle:${baseName}-${fingerprint}`;
|
|
14196
14308
|
return installIcm ? `${base}-icm` : base;
|
|
14197
14309
|
}
|
|
@@ -14376,7 +14488,7 @@ var SandcastleExecutionSession = class {
|
|
|
14376
14488
|
);
|
|
14377
14489
|
}
|
|
14378
14490
|
const hostMemoryDir = join21(repoRoot2, ".pourkit", "icm");
|
|
14379
|
-
if (!
|
|
14491
|
+
if (!existsSync21(hostMemoryDir) || !statSync2(hostMemoryDir).isDirectory()) {
|
|
14380
14492
|
throw new MissingHostMemoryDirError(
|
|
14381
14493
|
"Memory enabled but host .pourkit/icm/ directory is missing. Run `pourkit memory init` to create the repo-scoped memory store."
|
|
14382
14494
|
);
|
|
@@ -14541,7 +14653,7 @@ function sanitizeBranch(branchName) {
|
|
|
14541
14653
|
function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
|
|
14542
14654
|
return paths.filter((relativePath) => {
|
|
14543
14655
|
const source = join21(repoRoot2, relativePath);
|
|
14544
|
-
if (!
|
|
14656
|
+
if (!existsSync21(source)) {
|
|
14545
14657
|
return true;
|
|
14546
14658
|
}
|
|
14547
14659
|
try {
|
|
@@ -14552,7 +14664,7 @@ function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
|
|
|
14552
14664
|
return true;
|
|
14553
14665
|
}
|
|
14554
14666
|
const destination = join21(worktreePath, relativePath);
|
|
14555
|
-
return !
|
|
14667
|
+
return !existsSync21(destination);
|
|
14556
14668
|
});
|
|
14557
14669
|
}
|
|
14558
14670
|
function formatAgentStreamEvent(event) {
|
|
@@ -15342,11 +15454,11 @@ function createCliProgram(version) {
|
|
|
15342
15454
|
return program;
|
|
15343
15455
|
}
|
|
15344
15456
|
async function resolveCliVersion() {
|
|
15345
|
-
if (isPackageVersion("0.0.0-next-
|
|
15346
|
-
return "0.0.0-next-
|
|
15457
|
+
if (isPackageVersion("0.0.0-next-20260621094003")) {
|
|
15458
|
+
return "0.0.0-next-20260621094003";
|
|
15347
15459
|
}
|
|
15348
|
-
if (isReleaseVersion("0.0.0-next-
|
|
15349
|
-
return "0.0.0-next-
|
|
15460
|
+
if (isReleaseVersion("0.0.0-next-20260621094003")) {
|
|
15461
|
+
return "0.0.0-next-20260621094003";
|
|
15350
15462
|
}
|
|
15351
15463
|
try {
|
|
15352
15464
|
const root = repoRoot();
|