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