@pourkit/cli 0.0.0-next-20260620182746 → 0.0.0-next-20260621003351
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 +227 -253
- package/dist/cli.js.map +1 -1
- package/dist/e2e/run-live-e2e.js +169 -193
- package/dist/e2e/run-live-e2e.js.map +1 -1
- package/dist/managed/skills/to-issues/SKILL.md +4 -9
- package/dist/managed/skills/to-prd/SKILL.md +91 -82
- package/package.json +1 -1
- package/dist/managed/skills/to-plan/SKILL.md +0 -115
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((resolve5) => {
|
|
62
62
|
if (!fileStream) {
|
|
63
|
-
|
|
63
|
+
resolve5();
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
const timer = setTimeout(() => {
|
|
67
67
|
if (!fileStream.destroyed) {
|
|
68
68
|
fileStream.destroy();
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
resolve5();
|
|
71
71
|
}, 2e3);
|
|
72
72
|
fileStream.end(() => {
|
|
73
73
|
clearTimeout(timer);
|
|
74
|
-
|
|
74
|
+
resolve5();
|
|
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((resolve5) => setTimeout(resolve5, ms));
|
|
270
270
|
}
|
|
271
271
|
async function execCaptureWithRetry(command, args, options = {}) {
|
|
272
272
|
const retries = options.retries ?? 3;
|
|
@@ -1136,7 +1136,7 @@ async function cleanupRepository(options) {
|
|
|
1136
1136
|
// commands/artifact-validation.ts
|
|
1137
1137
|
import { execSync } from "child_process";
|
|
1138
1138
|
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
1139
|
-
import { isAbsolute as
|
|
1139
|
+
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
|
|
1140
1140
|
|
|
1141
1141
|
// pr/review-verdict.ts
|
|
1142
1142
|
var ReviewVerdictProtocolError = class extends Error {
|
|
@@ -1252,7 +1252,7 @@ function prepareArtifactPath(artifactPath) {
|
|
|
1252
1252
|
|
|
1253
1253
|
// shared/run-context.ts
|
|
1254
1254
|
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync } from "fs";
|
|
1255
|
-
import {
|
|
1255
|
+
import { join as join5, relative } from "path";
|
|
1256
1256
|
|
|
1257
1257
|
// commands/run-verification.ts
|
|
1258
1258
|
init_common();
|
|
@@ -1420,20 +1420,19 @@ function buildRunContextMarkdown(options) {
|
|
|
1420
1420
|
} = options;
|
|
1421
1421
|
const parts = ["# Pourkit Run Context", ""];
|
|
1422
1422
|
if (sections.includes("issue")) {
|
|
1423
|
+
const issueBody = stripIssueSections(issue.body, [
|
|
1424
|
+
"Parent",
|
|
1425
|
+
"Plan Documents"
|
|
1426
|
+
]);
|
|
1423
1427
|
parts.push(
|
|
1424
|
-
|
|
1425
|
-
"",
|
|
1426
|
-
`- Number: #${issue.number}`,
|
|
1427
|
-
`- Title: ${issue.title}`,
|
|
1428
|
+
`## Issue #${issue.number}: ${issue.title}`,
|
|
1428
1429
|
"",
|
|
1429
|
-
"
|
|
1430
|
-
"",
|
|
1431
|
-
issue.body.trim() || "(empty issue body)",
|
|
1430
|
+
issueBody.trim() || "(empty issue body)",
|
|
1432
1431
|
""
|
|
1433
1432
|
);
|
|
1434
1433
|
}
|
|
1435
1434
|
if (sections.includes("prd")) {
|
|
1436
|
-
parts.push(...
|
|
1435
|
+
parts.push(...renderParentPrdContext(issue, parentPrdIssue, repoRoot2));
|
|
1437
1436
|
}
|
|
1438
1437
|
if (sections.includes("comments")) {
|
|
1439
1438
|
parts.push("## Comments", "");
|
|
@@ -1504,98 +1503,63 @@ function renderCommandList(target, heading) {
|
|
|
1504
1503
|
}
|
|
1505
1504
|
return parts;
|
|
1506
1505
|
}
|
|
1507
|
-
function
|
|
1506
|
+
function renderParentPrdContext(issue, parentPrdIssue, repoRoot2) {
|
|
1508
1507
|
const parent = extractIssueSection(issue.body, "Parent");
|
|
1509
|
-
const
|
|
1510
|
-
const parentRef = parent?.match(/\bPRD-\d+\b/i)?.[0]?.toUpperCase();
|
|
1508
|
+
const parentRef = parent?.match(/\bPRD-\d+\b/i)?.[0]?.toUpperCase() ?? issue.title.match(/^\s*(PRD-\d+)\s*\/\s*I-\d+\b/i)?.[1]?.toUpperCase();
|
|
1511
1509
|
const parentPlanWorkspace = parentRef && repoRoot2 ? findParentPlanWorkspace(repoRoot2, parentRef) : null;
|
|
1512
1510
|
const parentPrdPath = parentPlanWorkspace?.prdPath ?? null;
|
|
1513
|
-
|
|
1514
|
-
const documentPaths = repoRoot2 ? extractRepoPaths(documents) : [];
|
|
1515
|
-
const planDocumentPaths = new Set(documentPaths);
|
|
1516
|
-
if (discoveredPlanPath && repoRoot2) {
|
|
1517
|
-
planDocumentPaths.add(relative(repoRoot2, discoveredPlanPath));
|
|
1518
|
-
}
|
|
1519
|
-
if (!parent && !documents && planDocumentPaths.size === 0) {
|
|
1511
|
+
if (!parent && !parentPrdPath && !parentPrdIssue && !parentRef) {
|
|
1520
1512
|
return [];
|
|
1521
1513
|
}
|
|
1522
|
-
const parts = ["##
|
|
1514
|
+
const parts = ["---", "", "## Parent PRD", ""];
|
|
1523
1515
|
if (parent) {
|
|
1524
|
-
parts.push("
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
parts.push("### Parent", "");
|
|
1528
|
-
parts.push("(not declared in issue body)", "");
|
|
1516
|
+
parts.push(...parent.split("\n").map((line) => `- ${line}`));
|
|
1517
|
+
} else if (parentRef) {
|
|
1518
|
+
parts.push(`- Parent: ${parentRef}`);
|
|
1529
1519
|
}
|
|
1530
1520
|
if (parentPrdPath && repoRoot2) {
|
|
1531
1521
|
parts.push(
|
|
1532
|
-
|
|
1522
|
+
`- Source: \`${relative(repoRoot2, parentPrdPath)}\``,
|
|
1533
1523
|
"",
|
|
1534
|
-
"```markdown",
|
|
1535
1524
|
readFileSync4(parentPrdPath, "utf-8").trimEnd(),
|
|
1536
|
-
"```",
|
|
1537
1525
|
""
|
|
1538
1526
|
);
|
|
1539
1527
|
} else if (parentPrdIssue) {
|
|
1540
1528
|
parts.push(
|
|
1541
|
-
|
|
1529
|
+
`- Source: #${parentPrdIssue.number} ${parentPrdIssue.title}`,
|
|
1542
1530
|
"",
|
|
1543
|
-
"```markdown",
|
|
1544
1531
|
parentPrdIssue.body.trimEnd() || "(empty PRD body)",
|
|
1545
|
-
"```",
|
|
1546
|
-
""
|
|
1547
|
-
);
|
|
1548
|
-
}
|
|
1549
|
-
parts.push("### Plan Documents", "");
|
|
1550
|
-
if (documents) {
|
|
1551
|
-
parts.push(documents, "");
|
|
1552
|
-
} else if (planDocumentPaths.size > 0) {
|
|
1553
|
-
parts.push(
|
|
1554
|
-
...Array.from(planDocumentPaths).map(
|
|
1555
|
-
(documentPath) => `- \`${documentPath}\``
|
|
1556
|
-
),
|
|
1557
|
-
""
|
|
1558
|
-
);
|
|
1559
|
-
} else {
|
|
1560
|
-
parts.push("(not declared in issue body)", "");
|
|
1561
|
-
}
|
|
1562
|
-
for (const documentPath of planDocumentPaths) {
|
|
1563
|
-
const absolutePath = resolveRepoPath(repoRoot2, documentPath);
|
|
1564
|
-
if (!absolutePath || !existsSync4(absolutePath)) continue;
|
|
1565
|
-
parts.push(
|
|
1566
|
-
`### Document Content: \`${documentPath}\``,
|
|
1567
|
-
"",
|
|
1568
|
-
"```markdown",
|
|
1569
|
-
readFileSync4(absolutePath, "utf-8").trimEnd(),
|
|
1570
|
-
"```",
|
|
1571
1532
|
""
|
|
1572
1533
|
);
|
|
1534
|
+
} else if (parent || parentRef) {
|
|
1535
|
+
parts.push("", "(parent PRD body unavailable)", "");
|
|
1573
1536
|
}
|
|
1574
1537
|
return parts;
|
|
1575
1538
|
}
|
|
1576
1539
|
function extractIssueSection(body, heading) {
|
|
1577
1540
|
const escapedHeading = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1578
1541
|
const section = body.match(
|
|
1579
|
-
new RegExp(
|
|
1542
|
+
new RegExp(
|
|
1543
|
+
`(?:^|\\n)## ${escapedHeading}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`,
|
|
1544
|
+
"i"
|
|
1545
|
+
)
|
|
1580
1546
|
)?.[1];
|
|
1581
1547
|
const trimmed = section?.trim();
|
|
1582
1548
|
return trimmed ? trimmed : null;
|
|
1583
1549
|
}
|
|
1584
|
-
function
|
|
1585
|
-
|
|
1586
|
-
const
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1550
|
+
function stripIssueSections(body, headings) {
|
|
1551
|
+
let stripped = body;
|
|
1552
|
+
for (const heading of headings) {
|
|
1553
|
+
const escapedHeading = heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1554
|
+
stripped = stripped.replace(
|
|
1555
|
+
new RegExp(
|
|
1556
|
+
`(?:^|\\n)## ${escapedHeading}\\s*\\n[\\s\\S]*?(?=\\n## |$)`,
|
|
1557
|
+
"gi"
|
|
1558
|
+
),
|
|
1559
|
+
""
|
|
1560
|
+
);
|
|
1590
1561
|
}
|
|
1591
|
-
return
|
|
1592
|
-
}
|
|
1593
|
-
function resolveRepoPath(repoRoot2, path9) {
|
|
1594
|
-
if (isAbsolute2(path9) || path9.includes("\0")) return null;
|
|
1595
|
-
const resolved = resolve2(repoRoot2, path9);
|
|
1596
|
-
const repoRelative2 = relative(repoRoot2, resolved);
|
|
1597
|
-
if (repoRelative2.startsWith("..") || isAbsolute2(repoRelative2)) return null;
|
|
1598
|
-
return resolved;
|
|
1562
|
+
return stripped.trim();
|
|
1599
1563
|
}
|
|
1600
1564
|
function findParentPlanWorkspace(repoRoot2, parentRef) {
|
|
1601
1565
|
const plansRoot = join5(repoRoot2, ".pourkit", "plans");
|
|
@@ -1609,11 +1573,9 @@ function findPlanWorkspaceInPlans(directory, parentRef) {
|
|
|
1609
1573
|
const prdNumber = parentRef.match(/^PRD-(\d+)$/)?.[1];
|
|
1610
1574
|
if (entry.name.startsWith(parentRef) || prdNumber && entry.name.startsWith(`${prdNumber}-`)) {
|
|
1611
1575
|
const prdPath = join5(entryPath, "PRD.md");
|
|
1612
|
-
|
|
1613
|
-
if (existsSync4(prdPath) || existsSync4(planPath)) {
|
|
1576
|
+
if (existsSync4(prdPath)) {
|
|
1614
1577
|
return {
|
|
1615
|
-
prdPath
|
|
1616
|
-
planPath: existsSync4(planPath) ? planPath : null
|
|
1578
|
+
prdPath
|
|
1617
1579
|
};
|
|
1618
1580
|
}
|
|
1619
1581
|
}
|
|
@@ -3244,7 +3206,7 @@ function validateRepoRelativePathField(pathValue, fieldName) {
|
|
|
3244
3206
|
}
|
|
3245
3207
|
const normalized = pathValue.replace(/\\/g, "/");
|
|
3246
3208
|
const segments = normalized.split("/");
|
|
3247
|
-
if (normalized.trim() === "" || normalized === "." || normalized === ".." ||
|
|
3209
|
+
if (normalized.trim() === "" || normalized === "." || normalized === ".." || isAbsolute2(pathValue) || normalized.startsWith("/") || segments.some((segment) => segment === "..")) {
|
|
3248
3210
|
return {
|
|
3249
3211
|
ok: false,
|
|
3250
3212
|
reason: `${fieldName} must not contain absolute paths or path traversal: ${pathValue}`
|
|
@@ -3597,7 +3559,7 @@ function validateAgentArtifact(options) {
|
|
|
3597
3559
|
if (options.checkConflictMarkers !== false && parsed.status === "resolved") {
|
|
3598
3560
|
const base = options.worktreePath ?? process.cwd();
|
|
3599
3561
|
const filesWithMarkers = parsed.files.filter((file) => {
|
|
3600
|
-
const filePath =
|
|
3562
|
+
const filePath = resolve2(base, file);
|
|
3601
3563
|
try {
|
|
3602
3564
|
return CONFLICT_MARKER_PATTERN.test(
|
|
3603
3565
|
readFileSync7(filePath, "utf-8")
|
|
@@ -3664,8 +3626,8 @@ function validateAgentArtifact(options) {
|
|
|
3664
3626
|
}
|
|
3665
3627
|
}
|
|
3666
3628
|
function runValidateArtifactCommand(options) {
|
|
3667
|
-
const artifactPath =
|
|
3668
|
-
const latestReviewArtifactPath = options.latestReviewArtifactPath ?
|
|
3629
|
+
const artifactPath = resolve2(options.repoRoot, options.artifactPath);
|
|
3630
|
+
const latestReviewArtifactPath = options.latestReviewArtifactPath ? resolve2(options.repoRoot, options.latestReviewArtifactPath) : void 0;
|
|
3669
3631
|
return validateAgentArtifact({
|
|
3670
3632
|
...options,
|
|
3671
3633
|
artifactPath,
|
|
@@ -3711,7 +3673,7 @@ function shellQuote(value) {
|
|
|
3711
3673
|
|
|
3712
3674
|
// commands/issue-run.ts
|
|
3713
3675
|
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
3714
|
-
import { isAbsolute as
|
|
3676
|
+
import { isAbsolute as isAbsolute4, join as join14 } from "path";
|
|
3715
3677
|
|
|
3716
3678
|
// pr/templates.ts
|
|
3717
3679
|
init_common();
|
|
@@ -4266,7 +4228,7 @@ async function canReachMcp(url) {
|
|
|
4266
4228
|
return true;
|
|
4267
4229
|
} catch {
|
|
4268
4230
|
if (attempt < 9) {
|
|
4269
|
-
await new Promise((
|
|
4231
|
+
await new Promise((resolve5) => setTimeout(resolve5, 100));
|
|
4270
4232
|
}
|
|
4271
4233
|
}
|
|
4272
4234
|
}
|
|
@@ -4959,7 +4921,7 @@ function extractClosingRefs(body) {
|
|
|
4959
4921
|
// issues/github-issue-publication.ts
|
|
4960
4922
|
init_common();
|
|
4961
4923
|
import { existsSync as existsSync10, readFileSync as readFileSync12 } from "fs";
|
|
4962
|
-
import { isAbsolute as
|
|
4924
|
+
import { isAbsolute as isAbsolute3, join as join12 } from "path";
|
|
4963
4925
|
|
|
4964
4926
|
// issues/issue-transitions.ts
|
|
4965
4927
|
function createIssueTransitions(deps, labels) {
|
|
@@ -5434,7 +5396,7 @@ function readIssueFinalReviewArtifact(worktreeState, worktreePath) {
|
|
|
5434
5396
|
if (!configuredPath) {
|
|
5435
5397
|
return null;
|
|
5436
5398
|
}
|
|
5437
|
-
const artifactPath =
|
|
5399
|
+
const artifactPath = isAbsolute3(configuredPath) ? configuredPath : join12(worktreePath, configuredPath);
|
|
5438
5400
|
if (!existsSync10(artifactPath)) return null;
|
|
5439
5401
|
let parsed;
|
|
5440
5402
|
try {
|
|
@@ -5929,7 +5891,7 @@ async function advanceIssueFinalReview(options) {
|
|
|
5929
5891
|
"Issue Final Review state is incomplete: missing artifactPath"
|
|
5930
5892
|
);
|
|
5931
5893
|
}
|
|
5932
|
-
const artifactPath =
|
|
5894
|
+
const artifactPath = isAbsolute4(ifrFromState.artifactPath) ? ifrFromState.artifactPath : join14(worktreePath, ifrFromState.artifactPath);
|
|
5933
5895
|
const validation = validateAgentArtifact({
|
|
5934
5896
|
kind: "issue-final-review",
|
|
5935
5897
|
artifactPath,
|
|
@@ -7075,157 +7037,171 @@ async function handlePublishedHistoryRisk(failure, context) {
|
|
|
7075
7037
|
throw new Error(message);
|
|
7076
7038
|
}
|
|
7077
7039
|
|
|
7078
|
-
//
|
|
7079
|
-
var
|
|
7040
|
+
// issues/issue-run-lifecycle.ts
|
|
7041
|
+
var IssueRunHumanHandoffStop = class extends Error {
|
|
7080
7042
|
constructor(message) {
|
|
7081
7043
|
super(message);
|
|
7082
7044
|
this.name = "HumanHandoffStop";
|
|
7083
7045
|
}
|
|
7084
7046
|
};
|
|
7085
|
-
async function
|
|
7086
|
-
const {
|
|
7087
|
-
issueNumber,
|
|
7088
|
-
config,
|
|
7089
|
-
issueProvider,
|
|
7090
|
-
prProvider,
|
|
7091
|
-
executionProvider,
|
|
7092
|
-
logger
|
|
7093
|
-
} = options;
|
|
7094
|
-
const ROOT = options.repoRoot;
|
|
7095
|
-
let executionSession;
|
|
7047
|
+
async function runIssueLifecycle(options) {
|
|
7096
7048
|
try {
|
|
7097
|
-
|
|
7098
|
-
const
|
|
7099
|
-
const startResult = await startIssueRun(runOptions);
|
|
7100
|
-
const {
|
|
7101
|
-
issue,
|
|
7102
|
-
parentPrdIssue,
|
|
7103
|
-
target,
|
|
7104
|
-
effectiveTarget,
|
|
7105
|
-
branchName,
|
|
7106
|
-
worktreeState,
|
|
7107
|
-
executionResult
|
|
7108
|
-
} = startResult;
|
|
7049
|
+
const startResult = await options.deps.startIssueRun(options.runOptions);
|
|
7050
|
+
const reviewAlreadyPassed = startResult.worktreeState?.review.lastVerdict && !startResult.worktreeState.review.exhaustedPreviousRun && (startResult.worktreeState.review.lastVerdict === "PASS" || startResult.worktreeState.review.lastVerdict === "PASS_WITH_NOTES");
|
|
7109
7051
|
let reviewArtifactPath;
|
|
7110
|
-
const reviewAlreadyPassed = worktreeState?.review.lastVerdict && ["PASS", "PASS_WITH_NOTES"].includes(worktreeState.review.lastVerdict) && !worktreeState.review.exhaustedPreviousRun;
|
|
7111
7052
|
if (reviewAlreadyPassed) {
|
|
7112
|
-
reviewArtifactPath = worktreeState.review.lastArtifactPath;
|
|
7053
|
+
reviewArtifactPath = startResult.worktreeState.review.lastArtifactPath;
|
|
7113
7054
|
} else {
|
|
7114
|
-
const
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
startingLifetimeIteration: lifetimeIterationsFromState,
|
|
7127
|
-
humanHandoffResolved,
|
|
7055
|
+
const reviewResult = await options.deps.advanceIssueRunReview({
|
|
7056
|
+
executionProvider: options.runOptions.executionProvider,
|
|
7057
|
+
config: options.config,
|
|
7058
|
+
target: startResult.effectiveTarget,
|
|
7059
|
+
issue: startResult.issue,
|
|
7060
|
+
parentPrdIssue: startResult.parentPrdIssue,
|
|
7061
|
+
builderBranch: startResult.branchName,
|
|
7062
|
+
worktreePath: startResult.executionResult.worktreePath,
|
|
7063
|
+
repoRoot: options.repoRoot,
|
|
7064
|
+
logger: options.logger,
|
|
7065
|
+
startingLifetimeIteration: startResult.worktreeState?.review.lifetimeIterations ?? 0,
|
|
7066
|
+
humanHandoffResolved: startResult.worktreeState?.review.lastVerdict === "NEEDS_HUMAN",
|
|
7128
7067
|
serena: startResult.serena,
|
|
7129
7068
|
memory: startResult.memory
|
|
7130
7069
|
});
|
|
7131
7070
|
if (reviewResult.exhaustedMaxIterations) {
|
|
7132
7071
|
throw new Error(
|
|
7133
|
-
|
|
7072
|
+
"Review loop exhausted maximum iterations without passing"
|
|
7134
7073
|
);
|
|
7135
7074
|
}
|
|
7136
7075
|
if (reviewResult.verdict === "FAIL") {
|
|
7137
|
-
|
|
7076
|
+
const summary = reviewResult.output?.trim() || "no summary provided";
|
|
7077
|
+
throw new Error(`Review loop failed: ${summary}`);
|
|
7138
7078
|
}
|
|
7139
7079
|
if (reviewResult.verdict === "NEEDS_HUMAN") {
|
|
7140
|
-
await
|
|
7141
|
-
issueProvider,
|
|
7142
|
-
issueNumber,
|
|
7143
|
-
config,
|
|
7144
|
-
logger,
|
|
7080
|
+
await options.deps.transitionReviewNeedsHumanToHandoff({
|
|
7081
|
+
issueProvider: options.issueProvider,
|
|
7082
|
+
issueNumber: options.issueNumber,
|
|
7083
|
+
config: options.config,
|
|
7084
|
+
logger: options.logger,
|
|
7145
7085
|
reviewResult
|
|
7146
7086
|
});
|
|
7147
|
-
throw new
|
|
7148
|
-
|
|
7087
|
+
throw new IssueRunHumanHandoffStop(
|
|
7088
|
+
"Review requires human handoff: NEEDS_HUMAN verdict"
|
|
7149
7089
|
);
|
|
7150
7090
|
}
|
|
7151
7091
|
reviewArtifactPath = reviewResult.artifactPath;
|
|
7152
7092
|
}
|
|
7153
|
-
const finalReviewResult = await advanceIssueFinalReview({
|
|
7154
|
-
executionProvider: runOptions.executionProvider,
|
|
7155
|
-
config,
|
|
7156
|
-
target: effectiveTarget,
|
|
7157
|
-
issue,
|
|
7158
|
-
parentPrdIssue,
|
|
7159
|
-
builderBranch: branchName,
|
|
7160
|
-
worktreePath: executionResult.worktreePath,
|
|
7161
|
-
repoRoot:
|
|
7162
|
-
logger,
|
|
7093
|
+
const finalReviewResult = await options.deps.advanceIssueFinalReview({
|
|
7094
|
+
executionProvider: options.runOptions.executionProvider,
|
|
7095
|
+
config: options.config,
|
|
7096
|
+
target: startResult.effectiveTarget,
|
|
7097
|
+
issue: startResult.issue,
|
|
7098
|
+
parentPrdIssue: startResult.parentPrdIssue,
|
|
7099
|
+
builderBranch: startResult.branchName,
|
|
7100
|
+
worktreePath: startResult.executionResult.worktreePath,
|
|
7101
|
+
repoRoot: options.repoRoot,
|
|
7102
|
+
logger: options.logger,
|
|
7163
7103
|
reviewArtifactPath,
|
|
7164
|
-
worktreeState,
|
|
7104
|
+
worktreeState: startResult.worktreeState,
|
|
7165
7105
|
memory: startResult.memory
|
|
7166
7106
|
});
|
|
7167
7107
|
if (finalReviewResult.verdict === "needs_human_review") {
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
closeIssue: issueProvider.closeIssue.bind(issueProvider)
|
|
7174
|
-
},
|
|
7175
|
-
{
|
|
7176
|
-
blocked: config.labels.blocked,
|
|
7177
|
-
readyForAgent: config.labels.readyForAgent,
|
|
7178
|
-
needsTriage: config.labels.needsTriage,
|
|
7179
|
-
agentInProgress: config.labels.agentInProgress,
|
|
7180
|
-
readyForHuman: config.labels.readyForHuman,
|
|
7181
|
-
prOpenAwaitingMerge: config.labels.prOpenAwaitingMerge
|
|
7182
|
-
}
|
|
7183
|
-
);
|
|
7184
|
-
await transitions.moveToReadyForHuman(issueNumber);
|
|
7185
|
-
const comment = [
|
|
7186
|
-
"Pourkit stopped the Issue Final Review because human review is needed.",
|
|
7187
|
-
"",
|
|
7188
|
-
finalReviewResult.needsHumanReason,
|
|
7189
|
-
"",
|
|
7190
|
-
"Artifacts:",
|
|
7191
|
-
`- Issue Final Review: ${finalReviewResult.artifactPath}`
|
|
7192
|
-
].join("\n");
|
|
7193
|
-
await issueProvider.commentIssue(issueNumber, comment);
|
|
7194
|
-
logger.step(
|
|
7195
|
-
"info",
|
|
7196
|
-
`Issue Final Review requires human handoff for issue ${issueNumber}`
|
|
7197
|
-
);
|
|
7198
|
-
throw new HumanHandoffStop(
|
|
7108
|
+
await options.deps.transitionIssueFinalReviewNeedsHumanToHandoff({
|
|
7109
|
+
issueNumber: options.issueNumber,
|
|
7110
|
+
finalReviewResult
|
|
7111
|
+
});
|
|
7112
|
+
throw new IssueRunHumanHandoffStop(
|
|
7199
7113
|
`Issue Final Review requires human handoff: ${finalReviewResult.needsHumanReason}`
|
|
7200
7114
|
);
|
|
7201
7115
|
}
|
|
7202
|
-
return await completeIssueRun({
|
|
7203
|
-
...runOptions,
|
|
7116
|
+
return await options.deps.completeIssueRun({
|
|
7117
|
+
...options.runOptions,
|
|
7204
7118
|
startResult,
|
|
7205
7119
|
reviewArtifactPath
|
|
7206
7120
|
});
|
|
7207
7121
|
} catch (error) {
|
|
7208
|
-
if (error instanceof
|
|
7122
|
+
if (error instanceof IssueRunHumanHandoffStop) {
|
|
7209
7123
|
throw error;
|
|
7210
7124
|
}
|
|
7211
7125
|
if (error instanceof Error && "_tag" in error) {
|
|
7212
|
-
await failIssueRun({
|
|
7213
|
-
issueProvider,
|
|
7214
|
-
issueNumber,
|
|
7215
|
-
config,
|
|
7216
|
-
logger,
|
|
7126
|
+
await options.deps.failIssueRun({
|
|
7127
|
+
issueProvider: options.issueProvider,
|
|
7128
|
+
issueNumber: options.issueNumber,
|
|
7129
|
+
config: options.config,
|
|
7130
|
+
logger: options.logger,
|
|
7217
7131
|
error: `[${error._tag}] ${error.message}`
|
|
7218
7132
|
});
|
|
7219
7133
|
} else {
|
|
7220
|
-
await failIssueRun({
|
|
7221
|
-
issueProvider,
|
|
7222
|
-
issueNumber,
|
|
7223
|
-
config,
|
|
7224
|
-
logger,
|
|
7134
|
+
await options.deps.failIssueRun({
|
|
7135
|
+
issueProvider: options.issueProvider,
|
|
7136
|
+
issueNumber: options.issueNumber,
|
|
7137
|
+
config: options.config,
|
|
7138
|
+
logger: options.logger,
|
|
7225
7139
|
error: error instanceof Error ? error : String(error)
|
|
7226
7140
|
});
|
|
7227
7141
|
}
|
|
7228
7142
|
throw error;
|
|
7143
|
+
}
|
|
7144
|
+
}
|
|
7145
|
+
|
|
7146
|
+
// commands/issue.ts
|
|
7147
|
+
async function runIssueCommand(options) {
|
|
7148
|
+
const { issueNumber, config, issueProvider, executionProvider, logger } = options;
|
|
7149
|
+
const ROOT = options.repoRoot;
|
|
7150
|
+
let executionSession;
|
|
7151
|
+
try {
|
|
7152
|
+
executionSession = await executionProvider.createSession?.();
|
|
7153
|
+
const runOptions = executionSession ? { ...options, executionProvider: executionSession } : options;
|
|
7154
|
+
return await runIssueLifecycle({
|
|
7155
|
+
issueNumber,
|
|
7156
|
+
config,
|
|
7157
|
+
issueProvider,
|
|
7158
|
+
logger,
|
|
7159
|
+
repoRoot: ROOT,
|
|
7160
|
+
runOptions,
|
|
7161
|
+
deps: {
|
|
7162
|
+
startIssueRun,
|
|
7163
|
+
advanceIssueRunReview,
|
|
7164
|
+
advanceIssueFinalReview,
|
|
7165
|
+
completeIssueRun,
|
|
7166
|
+
failIssueRun,
|
|
7167
|
+
transitionReviewNeedsHumanToHandoff: transitionIssueToHumanHandoff,
|
|
7168
|
+
transitionIssueFinalReviewNeedsHumanToHandoff: async ({
|
|
7169
|
+
issueNumber: issueNumber2,
|
|
7170
|
+
finalReviewResult
|
|
7171
|
+
}) => {
|
|
7172
|
+
const transitions = createIssueTransitions(
|
|
7173
|
+
{
|
|
7174
|
+
fetchIssue: issueProvider.fetchIssue.bind(issueProvider),
|
|
7175
|
+
addLabels: issueProvider.addLabels.bind(issueProvider),
|
|
7176
|
+
removeLabel: issueProvider.removeLabel.bind(issueProvider),
|
|
7177
|
+
closeIssue: issueProvider.closeIssue.bind(issueProvider)
|
|
7178
|
+
},
|
|
7179
|
+
{
|
|
7180
|
+
blocked: config.labels.blocked,
|
|
7181
|
+
readyForAgent: config.labels.readyForAgent,
|
|
7182
|
+
needsTriage: config.labels.needsTriage,
|
|
7183
|
+
agentInProgress: config.labels.agentInProgress,
|
|
7184
|
+
readyForHuman: config.labels.readyForHuman,
|
|
7185
|
+
prOpenAwaitingMerge: config.labels.prOpenAwaitingMerge
|
|
7186
|
+
}
|
|
7187
|
+
);
|
|
7188
|
+
await transitions.moveToReadyForHuman(issueNumber2);
|
|
7189
|
+
const comment = [
|
|
7190
|
+
"Pourkit stopped the Issue Final Review because human review is needed.",
|
|
7191
|
+
"",
|
|
7192
|
+
finalReviewResult.needsHumanReason,
|
|
7193
|
+
"",
|
|
7194
|
+
"Artifacts:",
|
|
7195
|
+
`- Issue Final Review: ${finalReviewResult.artifactPath}`
|
|
7196
|
+
].join("\n");
|
|
7197
|
+
await issueProvider.commentIssue(issueNumber2, comment);
|
|
7198
|
+
logger.step(
|
|
7199
|
+
"info",
|
|
7200
|
+
`Issue Final Review requires human handoff for issue ${issueNumber2}`
|
|
7201
|
+
);
|
|
7202
|
+
}
|
|
7203
|
+
}
|
|
7204
|
+
});
|
|
7229
7205
|
} finally {
|
|
7230
7206
|
await executionSession?.close();
|
|
7231
7207
|
}
|
|
@@ -9866,7 +9842,6 @@ var BASELINE_MANAGED_SKILLS = [
|
|
|
9866
9842
|
"ship-current-changes",
|
|
9867
9843
|
"tdd",
|
|
9868
9844
|
"to-issues",
|
|
9869
|
-
"to-plan",
|
|
9870
9845
|
"to-prd",
|
|
9871
9846
|
"triage",
|
|
9872
9847
|
"write-a-skill",
|
|
@@ -10086,7 +10061,6 @@ var BASELINE_SKILL_NAMES = [
|
|
|
10086
10061
|
"ship-current-changes",
|
|
10087
10062
|
"tdd",
|
|
10088
10063
|
"to-issues",
|
|
10089
|
-
"to-plan",
|
|
10090
10064
|
"to-prd",
|
|
10091
10065
|
"triage",
|
|
10092
10066
|
"write-a-skill",
|
|
@@ -12445,7 +12419,7 @@ async function runSerenaStatusCommand(options) {
|
|
|
12445
12419
|
// commands/config-schema.ts
|
|
12446
12420
|
import { readFileSync as readFileSync18, existsSync as existsSync17 } from "fs";
|
|
12447
12421
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile2, readdir as readdir2 } from "fs/promises";
|
|
12448
|
-
import { resolve as
|
|
12422
|
+
import { resolve as resolve3, dirname as dirname5, relative as relative2 } from "path";
|
|
12449
12423
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
12450
12424
|
import Ajv2 from "ajv";
|
|
12451
12425
|
init_common();
|
|
@@ -12453,8 +12427,8 @@ var __filename3 = fileURLToPath3(import.meta.url);
|
|
|
12453
12427
|
var __dirname3 = dirname5(__filename3);
|
|
12454
12428
|
function resolvePackagedAssetPath2(fileName) {
|
|
12455
12429
|
const candidates = [
|
|
12456
|
-
|
|
12457
|
-
|
|
12430
|
+
resolve3(__dirname3, "schema", fileName),
|
|
12431
|
+
resolve3(__dirname3, "../schema", fileName)
|
|
12458
12432
|
];
|
|
12459
12433
|
return candidates.find((candidate) => existsSync17(candidate)) ?? candidates[0];
|
|
12460
12434
|
}
|
|
@@ -12481,12 +12455,12 @@ function readPackagedHash() {
|
|
|
12481
12455
|
return readFileSync18(PACKAGED_HASH_PATH, "utf-8");
|
|
12482
12456
|
}
|
|
12483
12457
|
function localSchemaDir(repoRoot2) {
|
|
12484
|
-
return
|
|
12458
|
+
return resolve3(repoRoot2, ".pourkit/schema");
|
|
12485
12459
|
}
|
|
12486
12460
|
var MANAGED_BLOCK_BEGIN2 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
|
|
12487
12461
|
var OLD_DOCS_PATH_PATTERN = ".pourkit/docs/agents/";
|
|
12488
12462
|
function resolvePackagedManagedPath(...segments) {
|
|
12489
|
-
return
|
|
12463
|
+
return resolve3(__dirname3, "..", "managed", ...segments);
|
|
12490
12464
|
}
|
|
12491
12465
|
function resolvePackagedManagedDocPath(docName) {
|
|
12492
12466
|
return resolvePackagedManagedPath("docs", "agents", docName);
|
|
@@ -12516,7 +12490,7 @@ async function walkDir2(dir) {
|
|
|
12516
12490
|
try {
|
|
12517
12491
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
12518
12492
|
for (const entry of entries) {
|
|
12519
|
-
const full =
|
|
12493
|
+
const full = resolve3(dir, entry.name);
|
|
12520
12494
|
if (entry.isDirectory()) {
|
|
12521
12495
|
files.push(...await walkDir2(full));
|
|
12522
12496
|
} else {
|
|
@@ -12598,7 +12572,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12598
12572
|
const catalog = getWorkflowPackCatalog();
|
|
12599
12573
|
const baselineSkills = getBaselineManagedSkillNames();
|
|
12600
12574
|
for (const docName of catalog.docs) {
|
|
12601
|
-
const localPath =
|
|
12575
|
+
const localPath = resolve3(cwd, `.pourkit/managed/docs/agents/${docName}`);
|
|
12602
12576
|
if (!existsSync17(localPath)) {
|
|
12603
12577
|
failures.push({
|
|
12604
12578
|
severity: "failure",
|
|
@@ -12613,7 +12587,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12613
12587
|
try {
|
|
12614
12588
|
const localContent = await readFile5(localPath, "utf-8");
|
|
12615
12589
|
if (localContent !== packagedContent) {
|
|
12616
|
-
const overridePath =
|
|
12590
|
+
const overridePath = resolve3(
|
|
12617
12591
|
cwd,
|
|
12618
12592
|
`.pourkit/overrides/docs/agents/${docName}`
|
|
12619
12593
|
);
|
|
@@ -12639,7 +12613,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12639
12613
|
}
|
|
12640
12614
|
}
|
|
12641
12615
|
for (const skillName of baselineSkills) {
|
|
12642
|
-
const skillDir =
|
|
12616
|
+
const skillDir = resolve3(cwd, `.pourkit/managed/skills/${skillName}`);
|
|
12643
12617
|
if (!existsSync17(skillDir)) {
|
|
12644
12618
|
failures.push({
|
|
12645
12619
|
severity: "failure",
|
|
@@ -12648,7 +12622,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12648
12622
|
message: `Missing managed skill: ${skillName}`
|
|
12649
12623
|
});
|
|
12650
12624
|
} else {
|
|
12651
|
-
const skillSourcePath =
|
|
12625
|
+
const skillSourcePath = resolve3(skillDir, "SKILL.md");
|
|
12652
12626
|
if (existsSync17(skillSourcePath)) {
|
|
12653
12627
|
const packagedSkillPath = resolvePackagedManagedPath(
|
|
12654
12628
|
"skills",
|
|
@@ -12660,7 +12634,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12660
12634
|
try {
|
|
12661
12635
|
const localContent = await readFile5(skillSourcePath, "utf-8");
|
|
12662
12636
|
if (localContent !== packagedContent) {
|
|
12663
|
-
const overridePath =
|
|
12637
|
+
const overridePath = resolve3(
|
|
12664
12638
|
cwd,
|
|
12665
12639
|
`.pourkit/overrides/skills/${skillName}/SKILL.md`
|
|
12666
12640
|
);
|
|
@@ -12687,7 +12661,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12687
12661
|
}
|
|
12688
12662
|
}
|
|
12689
12663
|
for (const promptName of catalog.prompts) {
|
|
12690
|
-
const promptPath =
|
|
12664
|
+
const promptPath = resolve3(cwd, `.pourkit/managed/prompts/${promptName}`);
|
|
12691
12665
|
if (!existsSync17(promptPath)) {
|
|
12692
12666
|
failures.push({
|
|
12693
12667
|
severity: "failure",
|
|
@@ -12698,7 +12672,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12698
12672
|
}
|
|
12699
12673
|
}
|
|
12700
12674
|
for (const skillName of baselineSkills) {
|
|
12701
|
-
const projectionDir =
|
|
12675
|
+
const projectionDir = resolve3(cwd, `.agents/skills/${skillName}`);
|
|
12702
12676
|
if (!existsSync17(projectionDir)) {
|
|
12703
12677
|
warnings.push({
|
|
12704
12678
|
severity: "warning",
|
|
@@ -12707,7 +12681,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12707
12681
|
message: `Missing skill projection for ${skillName}. Run 'pourkit sync workflow-pack' to regenerate.`
|
|
12708
12682
|
});
|
|
12709
12683
|
} else {
|
|
12710
|
-
const projectionPath =
|
|
12684
|
+
const projectionPath = resolve3(projectionDir, "SKILL.md");
|
|
12711
12685
|
if (existsSync17(projectionPath)) {
|
|
12712
12686
|
const managedSourcePath = resolvePackagedManagedPath(
|
|
12713
12687
|
"skills",
|
|
@@ -12736,7 +12710,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12736
12710
|
}
|
|
12737
12711
|
}
|
|
12738
12712
|
}
|
|
12739
|
-
const agentsPath =
|
|
12713
|
+
const agentsPath = resolve3(cwd, "AGENTS.md");
|
|
12740
12714
|
if (existsSync17(agentsPath)) {
|
|
12741
12715
|
try {
|
|
12742
12716
|
const agentsContent = await readFile5(agentsPath, "utf-8");
|
|
@@ -12759,7 +12733,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12759
12733
|
} catch {
|
|
12760
12734
|
}
|
|
12761
12735
|
}
|
|
12762
|
-
const overridesDir =
|
|
12736
|
+
const overridesDir = resolve3(cwd, ".pourkit/overrides");
|
|
12763
12737
|
if (existsSync17(overridesDir)) {
|
|
12764
12738
|
const overrideFiles = await walkDir2(overridesDir);
|
|
12765
12739
|
for (const file of overrideFiles) {
|
|
@@ -12774,7 +12748,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12774
12748
|
}
|
|
12775
12749
|
}
|
|
12776
12750
|
}
|
|
12777
|
-
const configPath =
|
|
12751
|
+
const configPath = resolve3(cwd, ".pourkit/config.json");
|
|
12778
12752
|
if (existsSync17(configPath)) {
|
|
12779
12753
|
try {
|
|
12780
12754
|
const configContent = await readFile5(configPath, "utf-8");
|
|
@@ -12782,7 +12756,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12782
12756
|
const releaseEnabled = parsed.releaseWorkflow?.enabled === true;
|
|
12783
12757
|
if (releaseEnabled) {
|
|
12784
12758
|
for (const skillName of catalog.releaseAddonSkills) {
|
|
12785
|
-
const addonDir =
|
|
12759
|
+
const addonDir = resolve3(
|
|
12786
12760
|
cwd,
|
|
12787
12761
|
`.pourkit/managed/addons/release/skills/${skillName}`
|
|
12788
12762
|
);
|
|
@@ -12796,7 +12770,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12796
12770
|
}
|
|
12797
12771
|
}
|
|
12798
12772
|
for (const docName of catalog.releaseAddonDocs) {
|
|
12799
|
-
const addonDocPath =
|
|
12773
|
+
const addonDocPath = resolve3(
|
|
12800
12774
|
cwd,
|
|
12801
12775
|
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
12802
12776
|
);
|
|
@@ -12841,7 +12815,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12841
12815
|
}
|
|
12842
12816
|
} else {
|
|
12843
12817
|
for (const skillName of catalog.releaseAddonSkills) {
|
|
12844
|
-
const addonDir =
|
|
12818
|
+
const addonDir = resolve3(
|
|
12845
12819
|
cwd,
|
|
12846
12820
|
`.pourkit/managed/addons/release/skills/${skillName}`
|
|
12847
12821
|
);
|
|
@@ -12855,7 +12829,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12855
12829
|
}
|
|
12856
12830
|
}
|
|
12857
12831
|
for (const docName of catalog.releaseAddonDocs) {
|
|
12858
|
-
const addonDocPath =
|
|
12832
|
+
const addonDocPath = resolve3(
|
|
12859
12833
|
cwd,
|
|
12860
12834
|
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
12861
12835
|
);
|
|
@@ -12872,7 +12846,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12872
12846
|
} catch {
|
|
12873
12847
|
}
|
|
12874
12848
|
}
|
|
12875
|
-
const manifestPath =
|
|
12849
|
+
const manifestPath = resolve3(cwd, ".pourkit/manifest.json");
|
|
12876
12850
|
if (existsSync17(manifestPath)) {
|
|
12877
12851
|
try {
|
|
12878
12852
|
const manifestContent = await readFile5(manifestPath, "utf-8");
|
|
@@ -12881,7 +12855,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12881
12855
|
if (wp?.projections) {
|
|
12882
12856
|
for (const proj of wp.projections) {
|
|
12883
12857
|
if (proj.path) {
|
|
12884
|
-
const resolved =
|
|
12858
|
+
const resolved = resolve3(cwd, proj.path);
|
|
12885
12859
|
if (!isPathContained(cwd, resolved)) {
|
|
12886
12860
|
failures.push({
|
|
12887
12861
|
severity: "failure",
|
|
@@ -12895,7 +12869,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12895
12869
|
} catch {
|
|
12896
12870
|
}
|
|
12897
12871
|
}
|
|
12898
|
-
const pathEscapeOverrideDir =
|
|
12872
|
+
const pathEscapeOverrideDir = resolve3(cwd, ".pourkit/overrides");
|
|
12899
12873
|
if (existsSync17(pathEscapeOverrideDir)) {
|
|
12900
12874
|
const overrideFiles = await walkDir2(pathEscapeOverrideDir);
|
|
12901
12875
|
for (const file of overrideFiles) {
|
|
@@ -12909,7 +12883,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12909
12883
|
}
|
|
12910
12884
|
}
|
|
12911
12885
|
}
|
|
12912
|
-
const managedDocsDir =
|
|
12886
|
+
const managedDocsDir = resolve3(cwd, ".pourkit/managed/docs/agents");
|
|
12913
12887
|
if (existsSync17(managedDocsDir)) {
|
|
12914
12888
|
const docFiles = await walkDir2(managedDocsDir);
|
|
12915
12889
|
for (const file of docFiles) {
|
|
@@ -12930,12 +12904,12 @@ async function validateWorkflowPack(cwd) {
|
|
|
12930
12904
|
}
|
|
12931
12905
|
}
|
|
12932
12906
|
}
|
|
12933
|
-
const managedSkillsDir =
|
|
12907
|
+
const managedSkillsDir = resolve3(cwd, ".pourkit/managed/skills");
|
|
12934
12908
|
if (existsSync17(managedSkillsDir)) {
|
|
12935
12909
|
const skillDirs = await readdir2(managedSkillsDir, { withFileTypes: true });
|
|
12936
12910
|
for (const entry of skillDirs) {
|
|
12937
12911
|
if (!entry.isDirectory()) continue;
|
|
12938
|
-
const skillFile =
|
|
12912
|
+
const skillFile = resolve3(managedSkillsDir, entry.name, "SKILL.md");
|
|
12939
12913
|
if (!existsSync17(skillFile)) continue;
|
|
12940
12914
|
try {
|
|
12941
12915
|
const content = await readFile5(skillFile, "utf-8");
|
|
@@ -12953,10 +12927,10 @@ async function validateWorkflowPack(cwd) {
|
|
|
12953
12927
|
}
|
|
12954
12928
|
}
|
|
12955
12929
|
}
|
|
12956
|
-
const managedPromptsDir =
|
|
12930
|
+
const managedPromptsDir = resolve3(cwd, ".pourkit/managed/prompts");
|
|
12957
12931
|
if (existsSync17(managedPromptsDir)) {
|
|
12958
12932
|
for (const promptName of catalog.prompts) {
|
|
12959
|
-
const promptFile =
|
|
12933
|
+
const promptFile = resolve3(managedPromptsDir, promptName);
|
|
12960
12934
|
if (!existsSync17(promptFile)) continue;
|
|
12961
12935
|
try {
|
|
12962
12936
|
const content = await readFile5(promptFile, "utf-8");
|
|
@@ -12975,7 +12949,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12975
12949
|
}
|
|
12976
12950
|
}
|
|
12977
12951
|
for (const skillName of catalog.releaseAddonSkills) {
|
|
12978
|
-
const addonSkillFile =
|
|
12952
|
+
const addonSkillFile = resolve3(
|
|
12979
12953
|
cwd,
|
|
12980
12954
|
`.pourkit/managed/addons/release/skills/${skillName}/SKILL.md`
|
|
12981
12955
|
);
|
|
@@ -12996,7 +12970,7 @@ async function validateWorkflowPack(cwd) {
|
|
|
12996
12970
|
}
|
|
12997
12971
|
}
|
|
12998
12972
|
for (const docName of catalog.releaseAddonDocs) {
|
|
12999
|
-
const addonDocFile =
|
|
12973
|
+
const addonDocFile = resolve3(
|
|
13000
12974
|
cwd,
|
|
13001
12975
|
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
13002
12976
|
);
|
|
@@ -13033,7 +13007,7 @@ async function validateMemoryHealth(cwd, memoryConfig) {
|
|
|
13033
13007
|
ok: icmPath !== null,
|
|
13034
13008
|
detail: icmPath !== null ? icmPath : "icm not found on PATH"
|
|
13035
13009
|
});
|
|
13036
|
-
const gitignorePath =
|
|
13010
|
+
const gitignorePath = resolve3(cwd, ".gitignore");
|
|
13037
13011
|
const gitignoreContent = existsSync17(gitignorePath) ? readFileSync18(gitignorePath, "utf-8") : "";
|
|
13038
13012
|
const hasGitignoreEntry = gitignoreContent.includes(".pourkit/icm/");
|
|
13039
13013
|
checks.push({
|
|
@@ -13059,8 +13033,8 @@ async function validateMemoryHealth(cwd, memoryConfig) {
|
|
|
13059
13033
|
async function runDoctorCommand(options) {
|
|
13060
13034
|
const repoRootPath = options.cwd ?? process.cwd();
|
|
13061
13035
|
const schemaDir = localSchemaDir(repoRootPath);
|
|
13062
|
-
const localSchemaPath =
|
|
13063
|
-
const localHashPath =
|
|
13036
|
+
const localSchemaPath = resolve3(schemaDir, "pourkit.schema.json");
|
|
13037
|
+
const localHashPath = resolve3(schemaDir, "pourkit.schema.hash");
|
|
13064
13038
|
const localSchemaExists = existsSync17(localSchemaPath);
|
|
13065
13039
|
const localHashExists = existsSync17(localHashPath);
|
|
13066
13040
|
let packagedHash = null;
|
|
@@ -13078,7 +13052,7 @@ async function runDoctorCommand(options) {
|
|
|
13078
13052
|
const schema = !localSchemaExists ? "missing" : !packagedHash || !localHashContent ? "missing" : localHashContent.trim() === packagedHash.trim() ? "fresh" : "stale";
|
|
13079
13053
|
const hash = !localHashExists ? "missing" : !packagedHash ? "missing" : localHashContent && localHashContent.trim() === packagedHash.trim() ? "fresh" : "stale";
|
|
13080
13054
|
const overall = schema === "fresh" && hash === "fresh" ? "fresh" : schema === "missing" || hash === "missing" ? "missing" : "stale";
|
|
13081
|
-
const configPath =
|
|
13055
|
+
const configPath = resolve3(repoRootPath, ".pourkit/config.json");
|
|
13082
13056
|
let configValidation;
|
|
13083
13057
|
let rawMemoryConfig;
|
|
13084
13058
|
if (existsSync17(configPath)) {
|
|
@@ -13116,7 +13090,7 @@ async function runDoctorCommand(options) {
|
|
|
13116
13090
|
"pourkit.config.mjs",
|
|
13117
13091
|
"pourkit.config.js",
|
|
13118
13092
|
"pourkit.json"
|
|
13119
|
-
].filter((p) => existsSync17(
|
|
13093
|
+
].filter((p) => existsSync17(resolve3(repoRootPath, p)));
|
|
13120
13094
|
const workflowPack = await validateWorkflowPack(repoRootPath);
|
|
13121
13095
|
const memory = await validateMemoryHealth(repoRootPath, rawMemoryConfig);
|
|
13122
13096
|
let recommendation = null;
|
|
@@ -13162,8 +13136,8 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
13162
13136
|
await mkdir5(schemaDir, { recursive: true });
|
|
13163
13137
|
const packagedSchema = await readFile5(PACKAGED_SCHEMA_PATH, "utf-8");
|
|
13164
13138
|
const packagedHash = await readFile5(PACKAGED_HASH_PATH, "utf-8");
|
|
13165
|
-
const localSchemaPath =
|
|
13166
|
-
const localHashPath =
|
|
13139
|
+
const localSchemaPath = resolve3(schemaDir, "pourkit.schema.json");
|
|
13140
|
+
const localHashPath = resolve3(schemaDir, "pourkit.schema.hash");
|
|
13167
13141
|
let schemaWritten = false;
|
|
13168
13142
|
let hashWritten = false;
|
|
13169
13143
|
if (existsSync17(localSchemaPath)) {
|
|
@@ -13196,7 +13170,7 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
13196
13170
|
// commands/workflow-pack-sync.ts
|
|
13197
13171
|
import { existsSync as existsSync18, readdirSync as readdirSync4 } from "fs";
|
|
13198
13172
|
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir3 } from "fs/promises";
|
|
13199
|
-
import { resolve as
|
|
13173
|
+
import { resolve as resolve4, dirname as dirname6, relative as relative3, normalize as normalize2 } from "path";
|
|
13200
13174
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13201
13175
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
13202
13176
|
var __dirname4 = dirname6(__filename4);
|
|
@@ -13210,7 +13184,7 @@ var OVERRIDES_DIR = ".pourkit/overrides";
|
|
|
13210
13184
|
var MANAGED_BLOCK_BEGIN3 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
|
|
13211
13185
|
var MANAGED_BLOCK_END2 = "\n<!-- END POURKIT MANAGED BLOCK -->";
|
|
13212
13186
|
function resolvePackagedManagedPath2(...segments) {
|
|
13213
|
-
const candidates = [
|
|
13187
|
+
const candidates = [resolve4(__dirname4, "..", "managed", ...segments)];
|
|
13214
13188
|
return candidates[0];
|
|
13215
13189
|
}
|
|
13216
13190
|
function resolvePackagedManagedDocPath2(docName) {
|
|
@@ -13292,7 +13266,7 @@ async function walkDir3(dir) {
|
|
|
13292
13266
|
try {
|
|
13293
13267
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
13294
13268
|
for (const entry of entries) {
|
|
13295
|
-
const full =
|
|
13269
|
+
const full = resolve4(dir, entry.name);
|
|
13296
13270
|
if (entry.isDirectory()) {
|
|
13297
13271
|
files.push(...await walkDir3(full));
|
|
13298
13272
|
} else {
|
|
@@ -13310,13 +13284,13 @@ async function syncFile(cwd, targetRelativePath, sourceContent, errors) {
|
|
|
13310
13284
|
if (sourceContent === null) {
|
|
13311
13285
|
return false;
|
|
13312
13286
|
}
|
|
13313
|
-
const targetPath =
|
|
13287
|
+
const targetPath = resolve4(cwd, targetRelativePath);
|
|
13314
13288
|
const escapeError = checkForPathEscape(cwd, targetPath);
|
|
13315
13289
|
if (escapeError) {
|
|
13316
13290
|
errors.push(escapeError);
|
|
13317
13291
|
return false;
|
|
13318
13292
|
}
|
|
13319
|
-
await mkdir6(
|
|
13293
|
+
await mkdir6(resolve4(targetPath, ".."), { recursive: true });
|
|
13320
13294
|
if (existsSync18(targetPath)) {
|
|
13321
13295
|
const existing = await readFile6(targetPath, "utf-8");
|
|
13322
13296
|
if (existing === sourceContent) {
|
|
@@ -13331,7 +13305,7 @@ function walkDirSync(dir) {
|
|
|
13331
13305
|
try {
|
|
13332
13306
|
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
13333
13307
|
for (const entry of entries) {
|
|
13334
|
-
const full =
|
|
13308
|
+
const full = resolve4(dir, entry.name);
|
|
13335
13309
|
if (entry.isDirectory()) {
|
|
13336
13310
|
result.push(...walkDirSync(full));
|
|
13337
13311
|
} else {
|
|
@@ -13343,7 +13317,7 @@ function walkDirSync(dir) {
|
|
|
13343
13317
|
return result;
|
|
13344
13318
|
}
|
|
13345
13319
|
async function detectOverrides(cwd) {
|
|
13346
|
-
const overridesDir =
|
|
13320
|
+
const overridesDir = resolve4(cwd, OVERRIDES_DIR);
|
|
13347
13321
|
if (!existsSync18(overridesDir)) {
|
|
13348
13322
|
return [];
|
|
13349
13323
|
}
|
|
@@ -13353,13 +13327,13 @@ async function detectOverrides(cwd) {
|
|
|
13353
13327
|
async function detectProjectOwnedFiles(cwd) {
|
|
13354
13328
|
const found = [];
|
|
13355
13329
|
for (const ownedPath of PROJECT_OWNED_PATHS) {
|
|
13356
|
-
const fullPath =
|
|
13330
|
+
const fullPath = resolve4(cwd, ownedPath);
|
|
13357
13331
|
if (existsSync18(fullPath)) {
|
|
13358
13332
|
found.push(ownedPath);
|
|
13359
13333
|
}
|
|
13360
13334
|
}
|
|
13361
13335
|
for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
|
|
13362
|
-
const fullDir =
|
|
13336
|
+
const fullDir = resolve4(cwd, ownedDir);
|
|
13363
13337
|
if (existsSync18(fullDir)) {
|
|
13364
13338
|
const files = await walkDir3(fullDir);
|
|
13365
13339
|
for (const file of files) {
|
|
@@ -13371,7 +13345,7 @@ async function detectProjectOwnedFiles(cwd) {
|
|
|
13371
13345
|
}
|
|
13372
13346
|
async function isReleaseWorkflowEnabled(cwd) {
|
|
13373
13347
|
try {
|
|
13374
|
-
const configPath =
|
|
13348
|
+
const configPath = resolve4(cwd, ".pourkit", "config.json");
|
|
13375
13349
|
const content = await readFile6(configPath, "utf-8");
|
|
13376
13350
|
const parsed = JSON.parse(content);
|
|
13377
13351
|
return parsed.releaseWorkflow?.enabled === true;
|
|
@@ -13501,7 +13475,7 @@ async function runWorkflowPackSyncCommand(options) {
|
|
|
13501
13475
|
const schemaResult = await runConfigSyncSchemaCommand({ cwd });
|
|
13502
13476
|
let configMemory;
|
|
13503
13477
|
try {
|
|
13504
|
-
const configPath =
|
|
13478
|
+
const configPath = resolve4(cwd, ".pourkit", "config.json");
|
|
13505
13479
|
const config = await loadConfig(configPath);
|
|
13506
13480
|
if (config.memory?.enabled === true && config.memory?.provider === "icm") {
|
|
13507
13481
|
configMemory = config.memory;
|
|
@@ -13511,7 +13485,7 @@ async function runWorkflowPackSyncCommand(options) {
|
|
|
13511
13485
|
const managedBlockContent = generateManagedBlockContent(configMemory);
|
|
13512
13486
|
const fullManagedBlock = `${MANAGED_BLOCK_BEGIN3}${managedBlockContent}${MANAGED_BLOCK_END2}`;
|
|
13513
13487
|
async function syncManagedAgentFile(fileName, options2) {
|
|
13514
|
-
const filePath =
|
|
13488
|
+
const filePath = resolve4(cwd, fileName);
|
|
13515
13489
|
if (!existsSync18(filePath)) {
|
|
13516
13490
|
if (!options2.createIfMissing) return false;
|
|
13517
13491
|
await writeFile3(filePath, fullManagedBlock + "\n", "utf-8");
|
|
@@ -13548,7 +13522,7 @@ ${fullManagedBlock}
|
|
|
13548
13522
|
}
|
|
13549
13523
|
const enabledAddons = releaseEnabled ? ["release"] : [];
|
|
13550
13524
|
const manifestMeta = buildWorkflowPackMetadata(enabledAddons);
|
|
13551
|
-
const manifestPath =
|
|
13525
|
+
const manifestPath = resolve4(cwd, ".pourkit", "manifest.json");
|
|
13552
13526
|
let manifestWritten = false;
|
|
13553
13527
|
let previousManifestWorkflowPack = void 0;
|
|
13554
13528
|
try {
|
|
@@ -13566,7 +13540,7 @@ ${fullManagedBlock}
|
|
|
13566
13540
|
);
|
|
13567
13541
|
let manifest = existingRaw ? JSON.parse(existingRaw) : {};
|
|
13568
13542
|
manifest.workflowPack = manifestMeta;
|
|
13569
|
-
await mkdir6(
|
|
13543
|
+
await mkdir6(resolve4(manifestPath, ".."), { recursive: true });
|
|
13570
13544
|
await writeFile3(
|
|
13571
13545
|
manifestPath,
|
|
13572
13546
|
JSON.stringify(manifest, null, 2) + "\n",
|
|
@@ -15484,11 +15458,11 @@ function createCliProgram(version) {
|
|
|
15484
15458
|
return program;
|
|
15485
15459
|
}
|
|
15486
15460
|
async function resolveCliVersion() {
|
|
15487
|
-
if (isPackageVersion("0.0.0-next-
|
|
15488
|
-
return "0.0.0-next-
|
|
15461
|
+
if (isPackageVersion("0.0.0-next-20260621003351")) {
|
|
15462
|
+
return "0.0.0-next-20260621003351";
|
|
15489
15463
|
}
|
|
15490
|
-
if (isReleaseVersion("0.0.0-next-
|
|
15491
|
-
return "0.0.0-next-
|
|
15464
|
+
if (isReleaseVersion("0.0.0-next-20260621003351")) {
|
|
15465
|
+
return "0.0.0-next-20260621003351";
|
|
15492
15466
|
}
|
|
15493
15467
|
try {
|
|
15494
15468
|
const root = repoRoot();
|