@pourkit/cli 0.0.0-next-20260615184943 → 0.0.0-next-20260617183635
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 +1797 -149
- package/dist/cli.js.map +1 -1
- package/dist/e2e/run-live-e2e.js +112 -20
- package/dist/e2e/run-live-e2e.js.map +1 -1
- package/dist/managed/addons/release/docs/agents/release-workflow.md +33 -0
- package/dist/managed/addons/release/skills/changeset/SKILL.md +76 -0
- package/dist/managed/addons/release/skills/promote-release/SKILL.md +94 -0
- package/dist/managed/docs/agents/commit-style.md +75 -0
- package/dist/managed/docs/agents/domain.md +57 -0
- package/dist/managed/docs/agents/git-workflow.md +197 -0
- package/dist/managed/docs/agents/issue-tracker.md +33 -0
- package/dist/managed/docs/agents/naming.md +58 -0
- package/dist/managed/docs/agents/triage-labels.md +28 -0
- package/dist/managed/prompts/builder.prompt.md +89 -0
- package/dist/managed/prompts/conflict-resolution.prompt.md +70 -0
- package/dist/managed/prompts/failure-resolution.prompt.md +68 -0
- package/dist/managed/prompts/finalizer.prompt.md +77 -0
- package/dist/managed/prompts/issue-final-review.prompt.md +122 -0
- package/dist/managed/prompts/pr-description.prompt.md +77 -0
- package/dist/managed/prompts/refactor.prompt.md +114 -0
- package/dist/managed/prompts/reviewer-correctness.snippet.md +5 -0
- package/dist/managed/prompts/reviewer-quality.snippet.md +3 -0
- package/dist/managed/prompts/reviewer-scope.snippet.md +5 -0
- package/dist/managed/prompts/reviewer-tests.snippet.md +5 -0
- package/dist/managed/prompts/reviewer.prompt.md +169 -0
- package/dist/managed/skills/code-review/SKILL.md +152 -0
- package/dist/managed/skills/code-review/references/thermo-nuclear-code-quality-review.md +147 -0
- package/dist/managed/skills/diagnose/SKILL.md +119 -0
- package/dist/managed/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
- package/dist/managed/skills/explain/EXAMPLES.md +227 -0
- package/dist/managed/skills/explain/SKILL.md +106 -0
- package/dist/managed/skills/explain/references/mermaid.md +136 -0
- package/dist/managed/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/dist/managed/skills/grill-with-docs/CONTEXT-FORMAT.md +77 -0
- package/dist/managed/skills/grill-with-docs/SKILL.md +88 -0
- package/dist/managed/skills/handoff/SKILL.md +13 -0
- package/dist/managed/skills/improve-codebase-architecture/DEEPENING.md +37 -0
- package/dist/managed/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +44 -0
- package/dist/managed/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
- package/dist/managed/skills/improve-codebase-architecture/SKILL.md +71 -0
- package/dist/managed/skills/publish-prd/SKILL.md +130 -0
- package/dist/managed/skills/secret-commit-guard/SKILL.md +54 -0
- package/dist/managed/skills/security-review/SKILL.md +495 -0
- package/dist/managed/skills/security-review/cloud-infrastructure-security.md +361 -0
- package/dist/managed/skills/ship-current-changes/SKILL.md +199 -0
- package/dist/managed/skills/tdd/SKILL.md +110 -0
- package/dist/managed/skills/tdd/deep-modules.md +33 -0
- package/dist/managed/skills/tdd/interface-design.md +31 -0
- package/dist/managed/skills/tdd/mocking.md +59 -0
- package/dist/managed/skills/tdd/refactoring.md +10 -0
- package/dist/managed/skills/tdd/tests.md +61 -0
- package/dist/managed/skills/to-issues/SKILL.md +442 -0
- package/dist/managed/skills/to-plan/SKILL.md +20 -0
- package/dist/managed/skills/to-prd/SKILL.md +129 -0
- package/dist/managed/skills/triage/AGENT-BRIEF.md +168 -0
- package/dist/managed/skills/triage/OUT-OF-SCOPE.md +101 -0
- package/dist/managed/skills/triage/SKILL.md +162 -0
- package/dist/managed/skills/write-a-skill/SKILL.md +117 -0
- package/dist/managed/skills/zoom-out/SKILL.md +7 -0
- package/dist/schema/pourkit.schema.hash +1 -1
- package/dist/schema/pourkit.schema.json +32 -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((resolve6) => {
|
|
62
62
|
if (!fileStream) {
|
|
63
|
-
|
|
63
|
+
resolve6();
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
const timer = setTimeout(() => {
|
|
67
67
|
if (!fileStream.destroyed) {
|
|
68
68
|
fileStream.destroy();
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
resolve6();
|
|
71
71
|
}, 2e3);
|
|
72
72
|
fileStream.end(() => {
|
|
73
73
|
clearTimeout(timer);
|
|
74
|
-
|
|
74
|
+
resolve6();
|
|
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((resolve6) => setTimeout(resolve6, ms));
|
|
270
270
|
}
|
|
271
271
|
async function execCaptureWithRetry(command, args, options = {}) {
|
|
272
272
|
const retries = options.retries ?? 3;
|
|
@@ -892,11 +892,11 @@ var OBSOLETE_CONFIG_PATHS = [
|
|
|
892
892
|
];
|
|
893
893
|
var CANONICAL_CONFIG_PATH = ".pourkit/config.json";
|
|
894
894
|
async function loadRepoConfig(repoRoot2, _configFileName) {
|
|
895
|
-
const { existsSync:
|
|
895
|
+
const { existsSync: existsSync23 } = await import("fs");
|
|
896
896
|
const { join: pjoin } = await import("path");
|
|
897
897
|
for (const obPath of OBSOLETE_CONFIG_PATHS) {
|
|
898
898
|
const fullPath = pjoin(repoRoot2, obPath);
|
|
899
|
-
if (
|
|
899
|
+
if (existsSync23(fullPath)) {
|
|
900
900
|
const isRootJson = obPath === "pourkit.json";
|
|
901
901
|
throw new Error(
|
|
902
902
|
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".`
|
|
@@ -904,13 +904,13 @@ async function loadRepoConfig(repoRoot2, _configFileName) {
|
|
|
904
904
|
}
|
|
905
905
|
}
|
|
906
906
|
const configPath = pjoin(repoRoot2, CANONICAL_CONFIG_PATH);
|
|
907
|
-
if (!
|
|
907
|
+
if (!existsSync23(configPath)) {
|
|
908
908
|
throw new Error(
|
|
909
909
|
`No Pourkit config found at ${CANONICAL_CONFIG_PATH}. Run pourkit init or create ${CANONICAL_CONFIG_PATH} with "$schema": "./schema/pourkit.schema.json".`
|
|
910
910
|
);
|
|
911
911
|
}
|
|
912
|
-
const { readFile:
|
|
913
|
-
const raw = await
|
|
912
|
+
const { readFile: readFile8 } = await import("fs/promises");
|
|
913
|
+
const raw = await readFile8(configPath, "utf-8");
|
|
914
914
|
let parsed;
|
|
915
915
|
try {
|
|
916
916
|
parsed = JSON.parse(raw);
|
|
@@ -924,7 +924,7 @@ function resolvePromptTemplatePath(repoRoot2, promptTemplate) {
|
|
|
924
924
|
if (promptTemplate.includes("/")) {
|
|
925
925
|
return join(repoRoot2, promptTemplate);
|
|
926
926
|
}
|
|
927
|
-
return join(repoRoot2, ".pourkit", "prompts", promptTemplate);
|
|
927
|
+
return join(repoRoot2, ".pourkit", "managed", "prompts", promptTemplate);
|
|
928
928
|
}
|
|
929
929
|
function resolveTarget(config, explicitTarget) {
|
|
930
930
|
if (config.targets.length === 0) {
|
|
@@ -1067,10 +1067,10 @@ async function removeStaleWorktree(candidate, repoRoot2, logger) {
|
|
|
1067
1067
|
}
|
|
1068
1068
|
}
|
|
1069
1069
|
async function removeExpiredFiles(dirPath, retentionDays) {
|
|
1070
|
-
const { readdir:
|
|
1070
|
+
const { readdir: readdir4, stat, unlink, access: access2 } = await import("fs/promises");
|
|
1071
1071
|
let entries;
|
|
1072
1072
|
try {
|
|
1073
|
-
entries = await
|
|
1073
|
+
entries = await readdir4(dirPath);
|
|
1074
1074
|
} catch {
|
|
1075
1075
|
return;
|
|
1076
1076
|
}
|
|
@@ -2505,6 +2505,7 @@ function renderReviewCriteriaEffect(repoRoot2, criteria, fs) {
|
|
|
2505
2505
|
const snippetPath = join6(
|
|
2506
2506
|
repoRoot2,
|
|
2507
2507
|
".pourkit",
|
|
2508
|
+
"managed",
|
|
2508
2509
|
"prompts",
|
|
2509
2510
|
`reviewer-${criterion}.snippet.md`
|
|
2510
2511
|
);
|
|
@@ -3345,6 +3346,34 @@ function validateIssueFinalReviewArtifact(parsed, options) {
|
|
|
3345
3346
|
diagnostics.push(
|
|
3346
3347
|
`changedFiles: ${parsed.changedFiles.length} files`
|
|
3347
3348
|
);
|
|
3349
|
+
if (options.baseRef && parsed.verdict === "pass") {
|
|
3350
|
+
const expectedChangedFiles = listIssueFinalReviewChangedPaths({
|
|
3351
|
+
worktreePath: options.worktreePath ?? process.cwd(),
|
|
3352
|
+
baseRef: options.baseRef
|
|
3353
|
+
});
|
|
3354
|
+
const declaredChangedFiles = new Set(
|
|
3355
|
+
parsed.changedFiles.map(
|
|
3356
|
+
(file) => normalizeGitPath(String(file.path))
|
|
3357
|
+
)
|
|
3358
|
+
);
|
|
3359
|
+
const missing = expectedChangedFiles.filter(
|
|
3360
|
+
(path9) => !declaredChangedFiles.has(path9)
|
|
3361
|
+
);
|
|
3362
|
+
if (missing.length > 0) {
|
|
3363
|
+
return {
|
|
3364
|
+
ok: false,
|
|
3365
|
+
reason: `pass verdict changedFiles is missing ${missing.length} changed file(s): ${missing.join(", ")}`,
|
|
3366
|
+
diagnostics: [
|
|
3367
|
+
...diagnostics,
|
|
3368
|
+
`baseRef: ${options.baseRef}`,
|
|
3369
|
+
`missingChangedFiles: ${missing.join(", ")}`
|
|
3370
|
+
]
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
diagnostics.push(
|
|
3374
|
+
`changedFiles coverage: ${expectedChangedFiles.length} files from ${options.baseRef}`
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3348
3377
|
if (!Array.isArray(parsed.outOfScopeFiles) || !parsed.outOfScopeFiles.every((p) => typeof p === "string")) {
|
|
3349
3378
|
return {
|
|
3350
3379
|
ok: false,
|
|
@@ -3627,9 +3656,44 @@ function runValidateArtifactCommand(options) {
|
|
|
3627
3656
|
...options,
|
|
3628
3657
|
artifactPath,
|
|
3629
3658
|
latestReviewArtifactPath,
|
|
3630
|
-
worktreePath: options.repoRoot
|
|
3659
|
+
worktreePath: options.repoRoot,
|
|
3660
|
+
baseRef: options.baseRef
|
|
3631
3661
|
});
|
|
3632
3662
|
}
|
|
3663
|
+
function listIssueFinalReviewChangedPaths(options) {
|
|
3664
|
+
const trackedDiff = String(
|
|
3665
|
+
execSync(`git diff-index --name-only ${shellQuote(options.baseRef)} --`, {
|
|
3666
|
+
cwd: options.worktreePath,
|
|
3667
|
+
encoding: "utf-8",
|
|
3668
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3669
|
+
})
|
|
3670
|
+
);
|
|
3671
|
+
const untrackedFiles = String(
|
|
3672
|
+
execSync("git ls-files --others --exclude-standard", {
|
|
3673
|
+
cwd: options.worktreePath,
|
|
3674
|
+
encoding: "utf-8",
|
|
3675
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3676
|
+
})
|
|
3677
|
+
);
|
|
3678
|
+
return Array.from(
|
|
3679
|
+
/* @__PURE__ */ new Set([
|
|
3680
|
+
...parseGitPathList(trackedDiff),
|
|
3681
|
+
...parseGitPathList(untrackedFiles)
|
|
3682
|
+
])
|
|
3683
|
+
).filter(isIssueFinalReviewAuditedPath);
|
|
3684
|
+
}
|
|
3685
|
+
function parseGitPathList(output) {
|
|
3686
|
+
return output.split(/\r?\n/).map(normalizeGitPath).filter((path9) => path9.length > 0);
|
|
3687
|
+
}
|
|
3688
|
+
function normalizeGitPath(path9) {
|
|
3689
|
+
return path9.replace(/^"|"$/g, "").replace(/\\/g, "/").replace(/^\.\/+/g, "").replace(/\/+$/g, "");
|
|
3690
|
+
}
|
|
3691
|
+
function isIssueFinalReviewAuditedPath(path9) {
|
|
3692
|
+
return path9 !== "" && path9 !== ".pourkit/state.json" && !path9.startsWith(".pourkit/.tmp/") && !path9.startsWith(".pourkit/logs/");
|
|
3693
|
+
}
|
|
3694
|
+
function shellQuote(value) {
|
|
3695
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
3696
|
+
}
|
|
3633
3697
|
function runLocalValidateArtifactCommand(options) {
|
|
3634
3698
|
const resolvedPath = resolve3(options.repoRoot, options.artifactPath);
|
|
3635
3699
|
const resolvedExtra = (options.extraArgs ?? []).map(
|
|
@@ -4935,7 +4999,7 @@ async function canReachMcp(url) {
|
|
|
4935
4999
|
return true;
|
|
4936
5000
|
} catch {
|
|
4937
5001
|
if (attempt < 9) {
|
|
4938
|
-
await new Promise((
|
|
5002
|
+
await new Promise((resolve6) => setTimeout(resolve6, 100));
|
|
4939
5003
|
}
|
|
4940
5004
|
}
|
|
4941
5005
|
}
|
|
@@ -6671,7 +6735,11 @@ async function runIssueFinalReviewAgent(options) {
|
|
|
6671
6735
|
const strategy = target.strategy;
|
|
6672
6736
|
const issueFinalReview = strategy.issueFinalReview;
|
|
6673
6737
|
const agent = issueFinalReview;
|
|
6674
|
-
const prompt = loadIssueFinalReviewPrompt(
|
|
6738
|
+
const prompt = loadIssueFinalReviewPrompt({
|
|
6739
|
+
repoRoot: repoRoot2,
|
|
6740
|
+
promptTemplate: agent.promptTemplate,
|
|
6741
|
+
validationCommand: `pourkit validate-artifact issue-final-review ${artifactPathInWorktree} --issue-number ${issue.number} --branch-name ${builderBranch} --base-ref origin/${target.baseBranch}`
|
|
6742
|
+
});
|
|
6675
6743
|
const entry = await executeWithMissingOrEmptyArtifactRetry({
|
|
6676
6744
|
executionProvider,
|
|
6677
6745
|
missingOrEmptyRetries: resolveMissingOrEmptyOutputRetries(agent),
|
|
@@ -6764,7 +6832,8 @@ function extractChangedPaths(parsed) {
|
|
|
6764
6832
|
(file) => file && typeof file === "object" ? file.path : void 0
|
|
6765
6833
|
).filter((path9) => typeof path9 === "string") : [];
|
|
6766
6834
|
}
|
|
6767
|
-
function loadIssueFinalReviewPrompt(
|
|
6835
|
+
function loadIssueFinalReviewPrompt(options) {
|
|
6836
|
+
const { repoRoot: repoRoot2, promptTemplate, validationCommand } = options;
|
|
6768
6837
|
const promptPath = resolvePromptTemplatePath(repoRoot2, promptTemplate);
|
|
6769
6838
|
const promptBody = existsSync12(promptPath) ? readFileSync14(promptPath, "utf-8") : promptTemplate;
|
|
6770
6839
|
return appendProtectedWorkGuidance(`${promptBody}
|
|
@@ -6780,7 +6849,24 @@ Read the selected issue requirements, PRD context, comments, branch context, ver
|
|
|
6780
6849
|
- Run the commands exactly as configured. Do not substitute narrower commands unless the configured command cannot run.
|
|
6781
6850
|
- If a configured command fails, keep reviewing after recording the failure details; use the failure output as review evidence.
|
|
6782
6851
|
- If a command cannot run because the environment is missing required setup, dependencies, or scripts outside agent control, treat it as a human handoff blocker.
|
|
6783
|
-
- If no verification commands are configured, note that and proceed with normal review
|
|
6852
|
+
- If no verification commands are configured, note that and proceed with normal review.
|
|
6853
|
+
|
|
6854
|
+
## Changed Files Audit
|
|
6855
|
+
|
|
6856
|
+
- Read the Branch section of ${RUN_CONTEXT_PATH_IN_WORKTREE} and use its Canonical Base Ref for the changed-file inventory.
|
|
6857
|
+
- Before writing \`changedFiles\`, run \`git diff-index --name-only <canonical-base-ref> --\` from the Worktree to enumerate tracked files changed by the Issue.
|
|
6858
|
+
- Also run \`git ls-files --others --exclude-standard\` from the Worktree to enumerate untracked files changed by the Issue.
|
|
6859
|
+
- Treat the union of those command outputs, excluding only \`.pourkit/.tmp/**\`, \`.pourkit/logs/**\`, and \`.pourkit/state.json\`, as the required \`changedFiles\` inventory.
|
|
6860
|
+
- Include every file from that inventory in \`changedFiles\`, including generated files, managed operating assets, docs, prompts, schema files, and large batches.
|
|
6861
|
+
- If any file from the inventory is out-of-scope, mark it \`out-of-scope\` and either self-retouch it away or return \`needs_human_review\`; do not omit it.
|
|
6862
|
+
- Do not return \`pass\` until \`changedFiles\` covers the full inventory.
|
|
6863
|
+
|
|
6864
|
+
## Required Artifact Validation
|
|
6865
|
+
|
|
6866
|
+
- Before handoff, run exactly: \`${validationCommand}\`
|
|
6867
|
+
- This validation checks both the artifact shape and \`changedFiles\` coverage against the canonical Git diff.
|
|
6868
|
+
- If validation fails, fix the artifact or safely retouch the worktree as needed, then rerun the same command.
|
|
6869
|
+
- Do not finish until the validation command passes.`);
|
|
6784
6870
|
}
|
|
6785
6871
|
|
|
6786
6872
|
// commands/issue-run.ts
|
|
@@ -6899,7 +6985,7 @@ async function advanceIssueFinalReview(options) {
|
|
|
6899
6985
|
logger
|
|
6900
6986
|
});
|
|
6901
6987
|
if (result.verdict === "pass") {
|
|
6902
|
-
await
|
|
6988
|
+
const changedPaths = await completeIssueFinalReviewChangedPaths({
|
|
6903
6989
|
worktreePath,
|
|
6904
6990
|
baseRef: `origin/${target.baseBranch}`,
|
|
6905
6991
|
declaredChangedPaths: result.changedPaths,
|
|
@@ -6911,10 +6997,14 @@ async function advanceIssueFinalReview(options) {
|
|
|
6911
6997
|
verdict: "pass",
|
|
6912
6998
|
artifactPath: result.artifactPath,
|
|
6913
6999
|
selfRetouched: result.selfRetouched,
|
|
6914
|
-
changedPaths
|
|
7000
|
+
changedPaths,
|
|
6915
7001
|
verificationPassed: result.verificationPassed
|
|
6916
7002
|
}
|
|
6917
7003
|
});
|
|
7004
|
+
return {
|
|
7005
|
+
...result,
|
|
7006
|
+
changedPaths
|
|
7007
|
+
};
|
|
6918
7008
|
}
|
|
6919
7009
|
return result;
|
|
6920
7010
|
}
|
|
@@ -7629,18 +7719,21 @@ async function assertCanonicalBaseAncestor(options) {
|
|
|
7629
7719
|
);
|
|
7630
7720
|
}
|
|
7631
7721
|
}
|
|
7632
|
-
async function
|
|
7633
|
-
const actualChangedPaths = await
|
|
7634
|
-
const declared = new Set(options.declaredChangedPaths.map(
|
|
7722
|
+
async function completeIssueFinalReviewChangedPaths(options) {
|
|
7723
|
+
const actualChangedPaths = await listIssueFinalReviewChangedPaths2(options);
|
|
7724
|
+
const declared = new Set(options.declaredChangedPaths.map(normalizeGitPath2));
|
|
7635
7725
|
const missing = actualChangedPaths.filter((path9) => !declared.has(path9));
|
|
7636
7726
|
if (missing.length === 0) {
|
|
7637
|
-
return;
|
|
7727
|
+
return actualChangedPaths;
|
|
7638
7728
|
}
|
|
7639
|
-
|
|
7640
|
-
|
|
7729
|
+
options.logger.step(
|
|
7730
|
+
"warn",
|
|
7731
|
+
`Issue Final Review pass omitted ${missing.length} changed file(s) from changedFiles; using git inventory for finalization state.`
|
|
7641
7732
|
);
|
|
7733
|
+
options.logger.kv("MISSING_CHANGED_FILES", missing.join(", "));
|
|
7734
|
+
return actualChangedPaths;
|
|
7642
7735
|
}
|
|
7643
|
-
async function
|
|
7736
|
+
async function listIssueFinalReviewChangedPaths2(options) {
|
|
7644
7737
|
const trackedDiff = await execCapture(
|
|
7645
7738
|
"git",
|
|
7646
7739
|
["diff-index", "--name-only", options.baseRef, "--"],
|
|
@@ -7661,18 +7754,18 @@ async function listIssueFinalReviewChangedPaths(options) {
|
|
|
7661
7754
|
);
|
|
7662
7755
|
return Array.from(
|
|
7663
7756
|
/* @__PURE__ */ new Set([
|
|
7664
|
-
...
|
|
7665
|
-
...
|
|
7757
|
+
...parseGitPathList2(trackedDiff.stdout),
|
|
7758
|
+
...parseGitPathList2(untrackedFiles.stdout)
|
|
7666
7759
|
])
|
|
7667
|
-
).filter(
|
|
7760
|
+
).filter(isIssueFinalReviewAuditedPath2);
|
|
7668
7761
|
}
|
|
7669
|
-
function
|
|
7670
|
-
return output.split(/\r?\n/).map(
|
|
7762
|
+
function parseGitPathList2(output) {
|
|
7763
|
+
return output.split(/\r?\n/).map(normalizeGitPath2).filter((path9) => path9.length > 0);
|
|
7671
7764
|
}
|
|
7672
|
-
function
|
|
7765
|
+
function normalizeGitPath2(path9) {
|
|
7673
7766
|
return path9.replace(/^"|"$/g, "").replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
7674
7767
|
}
|
|
7675
|
-
function
|
|
7768
|
+
function isIssueFinalReviewAuditedPath2(path9) {
|
|
7676
7769
|
return path9 !== "" && path9 !== WORKTREE_RUN_STATE_PATH && !path9.startsWith(".pourkit/.tmp/") && !path9.startsWith(".pourkit/logs/");
|
|
7677
7770
|
}
|
|
7678
7771
|
async function syncRemoteBaseRef(worktreePath, baseRef, logger) {
|
|
@@ -11933,8 +12026,124 @@ async function tryCreateGitHubClient(options) {
|
|
|
11933
12026
|
return { ok: true, client: { octokit, ...repo } };
|
|
11934
12027
|
}
|
|
11935
12028
|
|
|
12029
|
+
// workflow-pack.ts
|
|
12030
|
+
var BASELINE_MANAGED_SKILLS = [
|
|
12031
|
+
"code-review",
|
|
12032
|
+
"diagnose",
|
|
12033
|
+
"explain",
|
|
12034
|
+
"grill-with-docs",
|
|
12035
|
+
"handoff",
|
|
12036
|
+
"improve-codebase-architecture",
|
|
12037
|
+
"publish-prd",
|
|
12038
|
+
"secret-commit-guard",
|
|
12039
|
+
"security-review",
|
|
12040
|
+
"ship-current-changes",
|
|
12041
|
+
"tdd",
|
|
12042
|
+
"to-issues",
|
|
12043
|
+
"to-plan",
|
|
12044
|
+
"to-prd",
|
|
12045
|
+
"triage",
|
|
12046
|
+
"write-a-skill",
|
|
12047
|
+
"zoom-out"
|
|
12048
|
+
];
|
|
12049
|
+
var RELEASE_ADDON_SKILLS = ["changeset", "promote-release"];
|
|
12050
|
+
var RELEASE_ADDON_DOCS = ["release-workflow.md"];
|
|
12051
|
+
var MANAGED_DOCS = [
|
|
12052
|
+
"git-workflow.md",
|
|
12053
|
+
"issue-tracker.md",
|
|
12054
|
+
"naming.md",
|
|
12055
|
+
"triage-labels.md",
|
|
12056
|
+
"commit-style.md",
|
|
12057
|
+
"domain.md"
|
|
12058
|
+
];
|
|
12059
|
+
var MANAGED_PROMPTS = [
|
|
12060
|
+
"builder.prompt.md",
|
|
12061
|
+
"conflict-resolution.prompt.md",
|
|
12062
|
+
"failure-resolution.prompt.md",
|
|
12063
|
+
"finalizer.prompt.md",
|
|
12064
|
+
"issue-final-review.prompt.md",
|
|
12065
|
+
"pr-description.prompt.md",
|
|
12066
|
+
"refactor.prompt.md",
|
|
12067
|
+
"reviewer.prompt.md",
|
|
12068
|
+
"reviewer-correctness.snippet.md",
|
|
12069
|
+
"reviewer-quality.snippet.md",
|
|
12070
|
+
"reviewer-scope.snippet.md",
|
|
12071
|
+
"reviewer-tests.snippet.md"
|
|
12072
|
+
];
|
|
12073
|
+
var OPENCODE_PROJECTION = {
|
|
12074
|
+
harness: "opencode",
|
|
12075
|
+
path: ".agents/skills"
|
|
12076
|
+
};
|
|
12077
|
+
var CURRENT_VERSION = "0.0.0-next";
|
|
12078
|
+
function getWorkflowPackCatalog() {
|
|
12079
|
+
return {
|
|
12080
|
+
docs: [...MANAGED_DOCS],
|
|
12081
|
+
prompts: [...MANAGED_PROMPTS],
|
|
12082
|
+
baselineSkills: [...BASELINE_MANAGED_SKILLS],
|
|
12083
|
+
releaseAddonDocs: [...RELEASE_ADDON_DOCS],
|
|
12084
|
+
releaseAddonSkills: [...RELEASE_ADDON_SKILLS],
|
|
12085
|
+
projections: [OPENCODE_PROJECTION]
|
|
12086
|
+
};
|
|
12087
|
+
}
|
|
12088
|
+
function buildOpenCodeSkillProjectionContent(managedSourcePath, sourceContent) {
|
|
12089
|
+
const generatedNotice = `Generated from ${managedSourcePath}. Do not edit directly.`;
|
|
12090
|
+
if (managedSourcePath.endsWith(".md") || managedSourcePath.endsWith(".mdx")) {
|
|
12091
|
+
return `<!-- ${generatedNotice} -->
|
|
12092
|
+
${sourceContent}`;
|
|
12093
|
+
}
|
|
12094
|
+
if (managedSourcePath.endsWith(".sh") || managedSourcePath.endsWith(".bash") || managedSourcePath.endsWith(".zsh") || managedSourcePath.endsWith(".py") || managedSourcePath.endsWith(".rb") || managedSourcePath.endsWith(".yml") || managedSourcePath.endsWith(".yaml") || managedSourcePath.endsWith(".toml")) {
|
|
12095
|
+
const comment = `# ${generatedNotice}`;
|
|
12096
|
+
if (sourceContent.startsWith("#!")) {
|
|
12097
|
+
const lineBreakIndex = sourceContent.indexOf("\n");
|
|
12098
|
+
if (lineBreakIndex === -1) {
|
|
12099
|
+
return `${sourceContent}
|
|
12100
|
+
${comment}
|
|
12101
|
+
`;
|
|
12102
|
+
}
|
|
12103
|
+
return `${sourceContent.slice(0, lineBreakIndex + 1)}${comment}
|
|
12104
|
+
${sourceContent.slice(lineBreakIndex + 1)}`;
|
|
12105
|
+
}
|
|
12106
|
+
return `${comment}
|
|
12107
|
+
${sourceContent}`;
|
|
12108
|
+
}
|
|
12109
|
+
return sourceContent;
|
|
12110
|
+
}
|
|
12111
|
+
function getBaselineManagedSkillNames() {
|
|
12112
|
+
return BASELINE_MANAGED_SKILLS;
|
|
12113
|
+
}
|
|
12114
|
+
function getWorkflowPackVersion() {
|
|
12115
|
+
return CURRENT_VERSION;
|
|
12116
|
+
}
|
|
12117
|
+
function buildWorkflowPackMetadata(enabledAddons) {
|
|
12118
|
+
return {
|
|
12119
|
+
version: getWorkflowPackVersion(),
|
|
12120
|
+
enabledAddons,
|
|
12121
|
+
projections: [OPENCODE_PROJECTION]
|
|
12122
|
+
};
|
|
12123
|
+
}
|
|
12124
|
+
|
|
11936
12125
|
// commands/init.ts
|
|
11937
12126
|
var execFileAsync2 = promisify2(execFile2);
|
|
12127
|
+
var RELEASE_ADDON_SKILL_NAMES = ["changeset", "promote-release"];
|
|
12128
|
+
var BASELINE_SKILL_NAMES = [
|
|
12129
|
+
"code-review",
|
|
12130
|
+
"diagnose",
|
|
12131
|
+
"explain",
|
|
12132
|
+
"grill-with-docs",
|
|
12133
|
+
"handoff",
|
|
12134
|
+
"improve-codebase-architecture",
|
|
12135
|
+
"publish-prd",
|
|
12136
|
+
"secret-commit-guard",
|
|
12137
|
+
"security-review",
|
|
12138
|
+
"ship-current-changes",
|
|
12139
|
+
"tdd",
|
|
12140
|
+
"to-issues",
|
|
12141
|
+
"to-plan",
|
|
12142
|
+
"to-prd",
|
|
12143
|
+
"triage",
|
|
12144
|
+
"write-a-skill",
|
|
12145
|
+
"zoom-out"
|
|
12146
|
+
];
|
|
11938
12147
|
var NO_TOKEN_LABEL_PROVISIONING_WARNING = "Skipped GitHub label provisioning because no GitHub token was provided.";
|
|
11939
12148
|
var ALLOWED_VERIFICATION_SCRIPTS = [
|
|
11940
12149
|
"typecheck",
|
|
@@ -12077,26 +12286,26 @@ function generateConfigTemplate(options) {
|
|
|
12077
12286
|
builder: {
|
|
12078
12287
|
agent: "pourkit-builder",
|
|
12079
12288
|
model: "opencode-go/deepseek-v4-flash",
|
|
12080
|
-
promptTemplate: ".pourkit/prompts/builder.prompt.md"
|
|
12289
|
+
promptTemplate: ".pourkit/managed/prompts/builder.prompt.md"
|
|
12081
12290
|
}
|
|
12082
12291
|
},
|
|
12083
12292
|
failureResolution: {
|
|
12084
12293
|
agent: "pourkit-failure-resolution-agent",
|
|
12085
12294
|
model: "opencode-go/mimo-v2.5",
|
|
12086
|
-
promptTemplate: ".pourkit/prompts/failure-resolution.prompt.md",
|
|
12295
|
+
promptTemplate: ".pourkit/managed/prompts/failure-resolution.prompt.md",
|
|
12087
12296
|
maxAttemptsPerFailure: 1
|
|
12088
12297
|
},
|
|
12089
12298
|
review: {
|
|
12090
12299
|
reviewer: {
|
|
12091
12300
|
agent: "pourkit-reviewer",
|
|
12092
12301
|
model: "opencode-go/deepseek-v4-pro",
|
|
12093
|
-
promptTemplate: ".pourkit/prompts/reviewer.prompt.md",
|
|
12302
|
+
promptTemplate: ".pourkit/managed/prompts/reviewer.prompt.md",
|
|
12094
12303
|
criteria: ["correctness", "scope", "tests", "quality"]
|
|
12095
12304
|
},
|
|
12096
12305
|
refactor: {
|
|
12097
12306
|
agent: "pourkit-refactor",
|
|
12098
12307
|
model: "opencode-go/qwen3.6-plus",
|
|
12099
|
-
promptTemplate: ".pourkit/prompts/refactor.prompt.md"
|
|
12308
|
+
promptTemplate: ".pourkit/managed/prompts/refactor.prompt.md"
|
|
12100
12309
|
},
|
|
12101
12310
|
maxIterations: 3,
|
|
12102
12311
|
passWithNotesRefactorAttempts: 2
|
|
@@ -12104,14 +12313,14 @@ function generateConfigTemplate(options) {
|
|
|
12104
12313
|
issueFinalReview: {
|
|
12105
12314
|
agent: "pourkit-reviewer",
|
|
12106
12315
|
model: "opencode-go/deepseek-v4-pro",
|
|
12107
|
-
promptTemplate: ".pourkit/prompts/issue-final-review.prompt.md",
|
|
12316
|
+
promptTemplate: ".pourkit/managed/prompts/issue-final-review.prompt.md",
|
|
12108
12317
|
maxAttempts: 3
|
|
12109
12318
|
},
|
|
12110
12319
|
finalize: {
|
|
12111
12320
|
prDescriptionAgent: {
|
|
12112
12321
|
agent: "pourkit-pr-description",
|
|
12113
12322
|
model: "opencode-go/deepseek-v4-flash",
|
|
12114
|
-
promptTemplate: ".pourkit/prompts/pr-description.prompt.md"
|
|
12323
|
+
promptTemplate: ".pourkit/managed/prompts/pr-description.prompt.md"
|
|
12115
12324
|
},
|
|
12116
12325
|
maxAttempts: 2
|
|
12117
12326
|
}
|
|
@@ -12131,6 +12340,17 @@ function generateConfigTemplate(options) {
|
|
|
12131
12340
|
$schema: "./schema/pourkit.schema.json",
|
|
12132
12341
|
schemaVersion: 1,
|
|
12133
12342
|
targets: [target],
|
|
12343
|
+
workflowPack: {
|
|
12344
|
+
version: "1.0.0",
|
|
12345
|
+
skillProjections: [{ harness: "opencode", path: ".agents/skills" }]
|
|
12346
|
+
},
|
|
12347
|
+
releaseWorkflow: options.releaseWorkflow?.enabled ? {
|
|
12348
|
+
enabled: true,
|
|
12349
|
+
integrationBranch: options.releaseWorkflow.integrationBranch ?? "integration",
|
|
12350
|
+
developmentReleaseBranch: options.releaseWorkflow.developmentReleaseBranch ?? "preview",
|
|
12351
|
+
stableReleaseBranch: options.releaseWorkflow.stableReleaseBranch ?? "stable",
|
|
12352
|
+
changesets: options.releaseWorkflow.changesets ?? true
|
|
12353
|
+
} : { enabled: false },
|
|
12134
12354
|
labels: {
|
|
12135
12355
|
readyForAgent: labels.readyForAgent,
|
|
12136
12356
|
agentInProgress: labels.agentInProgress,
|
|
@@ -12278,18 +12498,33 @@ _Avoid_: Alternative terms
|
|
|
12278
12498
|
- <Document ambiguous terms and their resolution here.>
|
|
12279
12499
|
`;
|
|
12280
12500
|
}
|
|
12281
|
-
async function generateManagedAgentInstructions(
|
|
12282
|
-
|
|
12283
|
-
try {
|
|
12284
|
-
return await readFile5(sourcePath, "utf-8");
|
|
12285
|
-
} catch {
|
|
12286
|
-
return `## Codebase exploration
|
|
12501
|
+
async function generateManagedAgentInstructions(_options) {
|
|
12502
|
+
return `## Codebase exploration
|
|
12287
12503
|
|
|
12288
12504
|
Use \`fd\` for file discovery, \`rg\` for text search, and direct file reads for focused context.
|
|
12289
12505
|
|
|
12290
|
-
Follow the project's domain docs and conventions documented in \`.pourkit/docs/agents/*\`.
|
|
12506
|
+
Follow the project's domain docs and conventions documented in \`.pourkit/managed/docs/agents/*\`.
|
|
12507
|
+
|
|
12508
|
+
### Managed operating docs
|
|
12509
|
+
|
|
12510
|
+
- \`.pourkit/managed/docs/agents/issue-tracker.md\`
|
|
12511
|
+
- \`.pourkit/managed/docs/agents/triage-labels.md\`
|
|
12512
|
+
- \`.pourkit/managed/docs/agents/naming.md\`
|
|
12513
|
+
- \`.pourkit/managed/docs/agents/git-workflow.md\`
|
|
12514
|
+
- \`.pourkit/managed/docs/agents/commit-style.md\`
|
|
12515
|
+
- \`.pourkit/managed/docs/agents/domain.md\`
|
|
12516
|
+
|
|
12517
|
+
### Project-owned context
|
|
12518
|
+
|
|
12519
|
+
- \`.pourkit/CONTEXT.md\`
|
|
12520
|
+
- \`.pourkit/CONTEXT-MAP.md\`
|
|
12521
|
+
- \`.pourkit/docs/adr/*\`
|
|
12522
|
+
|
|
12523
|
+
### Important
|
|
12524
|
+
|
|
12525
|
+
- Do not edit \`.pourkit/managed/*\` unless explicitly updating Pourkit-managed assets.
|
|
12526
|
+
- Do not edit generated harness projections directly.
|
|
12291
12527
|
`;
|
|
12292
|
-
}
|
|
12293
12528
|
}
|
|
12294
12529
|
function generateGitignoreBlock() {
|
|
12295
12530
|
const lines = [
|
|
@@ -12655,11 +12890,28 @@ async function planInit(options) {
|
|
|
12655
12890
|
}
|
|
12656
12891
|
const plannedSkillDests = /* @__PURE__ */ new Set();
|
|
12657
12892
|
for (const op of operations) {
|
|
12658
|
-
if (op.
|
|
12893
|
+
if (op.path?.includes(".agents/skills")) {
|
|
12659
12894
|
plannedSkillDests.add(op.path);
|
|
12660
12895
|
}
|
|
12661
12896
|
}
|
|
12662
|
-
const
|
|
12897
|
+
const packagedManagedSkills = path5.join(
|
|
12898
|
+
sourceRoot,
|
|
12899
|
+
"pourkit",
|
|
12900
|
+
"managed",
|
|
12901
|
+
"skills"
|
|
12902
|
+
);
|
|
12903
|
+
const packagedReleaseAddonSkills = path5.join(
|
|
12904
|
+
sourceRoot,
|
|
12905
|
+
"pourkit",
|
|
12906
|
+
"managed",
|
|
12907
|
+
"addons",
|
|
12908
|
+
"release",
|
|
12909
|
+
"skills"
|
|
12910
|
+
);
|
|
12911
|
+
const srcSkills = existsSync18(packagedManagedSkills) ? [
|
|
12912
|
+
packagedManagedSkills,
|
|
12913
|
+
...existsSync18(packagedReleaseAddonSkills) ? [packagedReleaseAddonSkills] : []
|
|
12914
|
+
] : await discoverAgentSkills(sourceRoot);
|
|
12663
12915
|
for (const s of srcSkills) {
|
|
12664
12916
|
const isOpenCode = s.includes(".opencode");
|
|
12665
12917
|
if (isOpenCode && !options.legacySkills) {
|
|
@@ -12671,35 +12923,118 @@ async function planInit(options) {
|
|
|
12671
12923
|
});
|
|
12672
12924
|
continue;
|
|
12673
12925
|
}
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12926
|
+
if (isOpenCode) {
|
|
12927
|
+
const skillFiles = await walkDir(s);
|
|
12928
|
+
for (const file of skillFiles) {
|
|
12929
|
+
const relPath = path5.relative(s, file);
|
|
12930
|
+
const destPath = path5.join(
|
|
12931
|
+
targetRoot,
|
|
12932
|
+
".agents",
|
|
12933
|
+
"skills",
|
|
12934
|
+
relPath
|
|
12935
|
+
);
|
|
12936
|
+
if (!existsSync18(destPath)) {
|
|
12937
|
+
operations.push({
|
|
12938
|
+
kind: "copy",
|
|
12939
|
+
sourcePath: file,
|
|
12940
|
+
path: destPath,
|
|
12941
|
+
ownership: "project-owned",
|
|
12942
|
+
reason: `Migrate legacy skill: ${path5.join(".opencode/skills", relPath)}`,
|
|
12943
|
+
requiresConfirmation: false,
|
|
12944
|
+
destructive: false
|
|
12945
|
+
});
|
|
12946
|
+
}
|
|
12947
|
+
}
|
|
12948
|
+
continue;
|
|
12949
|
+
}
|
|
12950
|
+
const managedSkillsDir = path5.join(
|
|
12951
|
+
targetRoot,
|
|
12952
|
+
".pourkit",
|
|
12953
|
+
"managed",
|
|
12954
|
+
"skills"
|
|
12955
|
+
);
|
|
12956
|
+
const projectionSkillsDir = path5.join(targetRoot, ".agents", "skills");
|
|
12957
|
+
const entries = await readdir(s, { withFileTypes: true });
|
|
12958
|
+
const skillNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
12959
|
+
const addonManagedDir = path5.join(
|
|
12960
|
+
targetRoot,
|
|
12961
|
+
".pourkit",
|
|
12962
|
+
"managed",
|
|
12963
|
+
"addons",
|
|
12964
|
+
"release",
|
|
12965
|
+
"skills"
|
|
12966
|
+
);
|
|
12967
|
+
for (const skillName of skillNames) {
|
|
12968
|
+
const isReleaseAddon = RELEASE_ADDON_SKILL_NAMES.includes(skillName);
|
|
12969
|
+
const isBaseline = BASELINE_SKILL_NAMES.includes(skillName);
|
|
12970
|
+
if (isReleaseAddon) {
|
|
12971
|
+
if (!options.releaseWorkflow?.enabled) {
|
|
12972
|
+
operations.push({
|
|
12973
|
+
kind: "skip",
|
|
12974
|
+
reason: `Release add-on skill not enabled: ${skillName}`,
|
|
12975
|
+
requiresConfirmation: false,
|
|
12976
|
+
destructive: false
|
|
12977
|
+
});
|
|
12978
|
+
continue;
|
|
12979
|
+
}
|
|
12980
|
+
} else if (!isBaseline) {
|
|
12681
12981
|
operations.push({
|
|
12682
12982
|
kind: "skip",
|
|
12683
|
-
|
|
12684
|
-
ownership: "project-owned",
|
|
12685
|
-
reason: `Skill destination conflict, skipping source copy: ${path5.join(targetDirName, relPath)}`,
|
|
12983
|
+
reason: `Non-baseline skill not installed: ${skillName}`,
|
|
12686
12984
|
requiresConfirmation: false,
|
|
12687
|
-
destructive: false
|
|
12688
|
-
conflict: "destination already planned"
|
|
12985
|
+
destructive: false
|
|
12689
12986
|
});
|
|
12690
12987
|
continue;
|
|
12691
12988
|
}
|
|
12692
|
-
const
|
|
12693
|
-
|
|
12694
|
-
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12989
|
+
const skillSourceDir = path5.join(s, skillName);
|
|
12990
|
+
const skillFiles = await walkDir(skillSourceDir);
|
|
12991
|
+
for (const file of skillFiles) {
|
|
12992
|
+
const relPath = path5.relative(skillSourceDir, file);
|
|
12993
|
+
const managedDest = isReleaseAddon ? path5.join(addonManagedDir, skillName, relPath) : path5.join(managedSkillsDir, skillName, relPath);
|
|
12994
|
+
const checksum = await computeFileChecksum(file);
|
|
12995
|
+
const installLabel = isReleaseAddon ? `Install release add-on skill: ${skillName}/${relPath}` : `Install managed skill: ${skillName}/${relPath}`;
|
|
12996
|
+
operations.push({
|
|
12997
|
+
kind: "copy",
|
|
12998
|
+
sourcePath: file,
|
|
12999
|
+
path: managedDest,
|
|
13000
|
+
ownership: "managed",
|
|
13001
|
+
reason: installLabel,
|
|
13002
|
+
requiresConfirmation: false,
|
|
13003
|
+
destructive: false,
|
|
13004
|
+
checksum
|
|
13005
|
+
});
|
|
13006
|
+
const projectionDest = path5.join(
|
|
13007
|
+
projectionSkillsDir,
|
|
13008
|
+
skillName,
|
|
13009
|
+
relPath
|
|
13010
|
+
);
|
|
13011
|
+
if (plannedSkillDests.has(projectionDest)) {
|
|
13012
|
+
operations.push({
|
|
13013
|
+
kind: "skip",
|
|
13014
|
+
path: projectionDest,
|
|
13015
|
+
ownership: "project-owned",
|
|
13016
|
+
reason: `Skill destination conflict, skipping projection: ${skillName}/${relPath}`,
|
|
13017
|
+
requiresConfirmation: false,
|
|
13018
|
+
destructive: false,
|
|
13019
|
+
conflict: "destination already planned"
|
|
13020
|
+
});
|
|
13021
|
+
continue;
|
|
13022
|
+
}
|
|
13023
|
+
const sourceContent = await readFile5(file, "utf-8");
|
|
13024
|
+
const managedSourcePath = isReleaseAddon ? `.pourkit/managed/addons/release/skills/${skillName}/${relPath}` : `.pourkit/managed/skills/${skillName}/${relPath}`;
|
|
13025
|
+
operations.push({
|
|
13026
|
+
kind: "create",
|
|
13027
|
+
path: projectionDest,
|
|
13028
|
+
ownership: "managed",
|
|
13029
|
+
reason: `Project skill: ${skillName}/${relPath}`,
|
|
13030
|
+
requiresConfirmation: false,
|
|
13031
|
+
destructive: false,
|
|
13032
|
+
content: buildOpenCodeSkillProjectionContent(
|
|
13033
|
+
managedSourcePath,
|
|
13034
|
+
sourceContent
|
|
13035
|
+
)
|
|
13036
|
+
});
|
|
13037
|
+
}
|
|
12703
13038
|
}
|
|
12704
13039
|
}
|
|
12705
13040
|
const srcReadme = await discoverReadme(sourceRoot);
|
|
@@ -12792,7 +13127,7 @@ async function planInit(options) {
|
|
|
12792
13127
|
operations.push({
|
|
12793
13128
|
kind: "create",
|
|
12794
13129
|
path: contextPath,
|
|
12795
|
-
ownership: "
|
|
13130
|
+
ownership: "project-owned",
|
|
12796
13131
|
reason: "Init CONTEXT.md scaffold",
|
|
12797
13132
|
requiresConfirmation: false,
|
|
12798
13133
|
destructive: false,
|
|
@@ -12816,16 +13151,41 @@ async function planInit(options) {
|
|
|
12816
13151
|
destructive: false
|
|
12817
13152
|
});
|
|
12818
13153
|
}
|
|
12819
|
-
const
|
|
12820
|
-
|
|
12821
|
-
|
|
13154
|
+
const packagedManagedDocAgents = path5.join(
|
|
13155
|
+
sourceRoot,
|
|
13156
|
+
"pourkit",
|
|
13157
|
+
"managed",
|
|
13158
|
+
"docs",
|
|
13159
|
+
"agents"
|
|
13160
|
+
);
|
|
13161
|
+
const legacyDocAgents = path5.join(
|
|
13162
|
+
sourceRoot,
|
|
13163
|
+
".pourkit",
|
|
13164
|
+
"docs",
|
|
13165
|
+
"agents"
|
|
13166
|
+
);
|
|
13167
|
+
const srcDocAgents = existsSync18(packagedManagedDocAgents) ? packagedManagedDocAgents : legacyDocAgents;
|
|
13168
|
+
const tgtManagedDocAgents = path5.join(
|
|
13169
|
+
targetRoot,
|
|
13170
|
+
".pourkit",
|
|
13171
|
+
"managed",
|
|
13172
|
+
"docs",
|
|
13173
|
+
"agents"
|
|
13174
|
+
);
|
|
13175
|
+
const tgtStubDocAgents = path5.join(
|
|
13176
|
+
targetRoot,
|
|
13177
|
+
".pourkit",
|
|
13178
|
+
"docs",
|
|
13179
|
+
"agents"
|
|
13180
|
+
);
|
|
13181
|
+
if (existsSync18(srcDocAgents) && !existsSync18(tgtManagedDocAgents)) {
|
|
12822
13182
|
const docFiles = await walkDir(srcDocAgents);
|
|
12823
13183
|
for (const file of docFiles) {
|
|
12824
13184
|
const relPath = path5.relative(srcDocAgents, file);
|
|
12825
13185
|
if (relPath === "triage-labels.md") {
|
|
12826
13186
|
operations.push({
|
|
12827
13187
|
kind: "create",
|
|
12828
|
-
path: path5.join(
|
|
13188
|
+
path: path5.join(tgtManagedDocAgents, relPath),
|
|
12829
13189
|
ownership: "managed",
|
|
12830
13190
|
reason: "Init triage labels doc",
|
|
12831
13191
|
requiresConfirmation: false,
|
|
@@ -12834,24 +13194,94 @@ async function planInit(options) {
|
|
|
12834
13194
|
options.labels ?? DEFAULT_RUNNER_LABELS
|
|
12835
13195
|
)
|
|
12836
13196
|
});
|
|
12837
|
-
|
|
13197
|
+
} else {
|
|
13198
|
+
const checksum = await computeFileChecksum(file);
|
|
13199
|
+
operations.push({
|
|
13200
|
+
kind: "copy",
|
|
13201
|
+
sourcePath: file,
|
|
13202
|
+
path: path5.join(tgtManagedDocAgents, relPath),
|
|
13203
|
+
ownership: "managed",
|
|
13204
|
+
reason: `Copy agent doc: ${relPath}`,
|
|
13205
|
+
requiresConfirmation: false,
|
|
13206
|
+
destructive: false,
|
|
13207
|
+
checksum
|
|
13208
|
+
});
|
|
12838
13209
|
}
|
|
12839
|
-
|
|
13210
|
+
if (relPath === "triage-labels.md") continue;
|
|
13211
|
+
const managedRelPath = path5.join(
|
|
13212
|
+
".pourkit",
|
|
13213
|
+
"managed",
|
|
13214
|
+
"docs",
|
|
13215
|
+
"agents",
|
|
13216
|
+
relPath
|
|
13217
|
+
);
|
|
12840
13218
|
operations.push({
|
|
12841
|
-
kind: "
|
|
12842
|
-
|
|
12843
|
-
path: path5.join(tgtDocAgents, relPath),
|
|
13219
|
+
kind: "create",
|
|
13220
|
+
path: path5.join(tgtStubDocAgents, relPath),
|
|
12844
13221
|
ownership: "managed",
|
|
12845
|
-
reason: `
|
|
13222
|
+
reason: `Create moved stub for: ${relPath}`,
|
|
12846
13223
|
requiresConfirmation: false,
|
|
12847
13224
|
destructive: false,
|
|
12848
|
-
|
|
13225
|
+
content: `# Moved
|
|
13226
|
+
|
|
13227
|
+
This Pourkit operating doc moved to \`${managedRelPath}\`.
|
|
13228
|
+
Do not edit this file.
|
|
13229
|
+
`
|
|
12849
13230
|
});
|
|
12850
13231
|
}
|
|
12851
13232
|
}
|
|
12852
|
-
|
|
12853
|
-
|
|
12854
|
-
|
|
13233
|
+
if (options.releaseWorkflow?.enabled) {
|
|
13234
|
+
const packagedReleaseAddonDocs = path5.join(
|
|
13235
|
+
sourceRoot,
|
|
13236
|
+
"pourkit",
|
|
13237
|
+
"managed",
|
|
13238
|
+
"addons",
|
|
13239
|
+
"release",
|
|
13240
|
+
"docs",
|
|
13241
|
+
"agents"
|
|
13242
|
+
);
|
|
13243
|
+
const tgtReleaseAddonDocs = path5.join(
|
|
13244
|
+
targetRoot,
|
|
13245
|
+
".pourkit",
|
|
13246
|
+
"managed",
|
|
13247
|
+
"addons",
|
|
13248
|
+
"release",
|
|
13249
|
+
"docs",
|
|
13250
|
+
"agents"
|
|
13251
|
+
);
|
|
13252
|
+
if (existsSync18(packagedReleaseAddonDocs)) {
|
|
13253
|
+
const docFiles = await walkDir(packagedReleaseAddonDocs);
|
|
13254
|
+
for (const file of docFiles) {
|
|
13255
|
+
const relPath = path5.relative(packagedReleaseAddonDocs, file);
|
|
13256
|
+
const checksum = await computeFileChecksum(file);
|
|
13257
|
+
operations.push({
|
|
13258
|
+
kind: "copy",
|
|
13259
|
+
sourcePath: file,
|
|
13260
|
+
path: path5.join(tgtReleaseAddonDocs, relPath),
|
|
13261
|
+
ownership: "managed",
|
|
13262
|
+
reason: `Install release add-on doc: ${relPath}`,
|
|
13263
|
+
requiresConfirmation: false,
|
|
13264
|
+
destructive: false,
|
|
13265
|
+
checksum
|
|
13266
|
+
});
|
|
13267
|
+
}
|
|
13268
|
+
}
|
|
13269
|
+
}
|
|
13270
|
+
const packagedManagedPrompts = path5.join(
|
|
13271
|
+
sourceRoot,
|
|
13272
|
+
"pourkit",
|
|
13273
|
+
"managed",
|
|
13274
|
+
"prompts"
|
|
13275
|
+
);
|
|
13276
|
+
const legacyPrompts = path5.join(sourceRoot, ".pourkit", "prompts");
|
|
13277
|
+
const srcPrompts = existsSync18(packagedManagedPrompts) ? packagedManagedPrompts : legacyPrompts;
|
|
13278
|
+
const tgtManagedPrompts = path5.join(
|
|
13279
|
+
targetRoot,
|
|
13280
|
+
".pourkit",
|
|
13281
|
+
"managed",
|
|
13282
|
+
"prompts"
|
|
13283
|
+
);
|
|
13284
|
+
if (existsSync18(srcPrompts) && !existsSync18(tgtManagedPrompts)) {
|
|
12855
13285
|
const promptFiles = await walkDir(srcPrompts);
|
|
12856
13286
|
for (const file of promptFiles) {
|
|
12857
13287
|
const relPath = path5.relative(srcPrompts, file);
|
|
@@ -12859,7 +13289,7 @@ async function planInit(options) {
|
|
|
12859
13289
|
operations.push({
|
|
12860
13290
|
kind: "copy",
|
|
12861
13291
|
sourcePath: file,
|
|
12862
|
-
path: path5.join(
|
|
13292
|
+
path: path5.join(tgtManagedPrompts, relPath),
|
|
12863
13293
|
ownership: "managed",
|
|
12864
13294
|
reason: `Copy prompt: ${relPath}`,
|
|
12865
13295
|
requiresConfirmation: false,
|
|
@@ -12911,7 +13341,8 @@ async function planInit(options) {
|
|
|
12911
13341
|
baseBranch,
|
|
12912
13342
|
verificationCommands: verifyCommands,
|
|
12913
13343
|
hasPackageJson,
|
|
12914
|
-
labels: options.labels
|
|
13344
|
+
labels: options.labels,
|
|
13345
|
+
releaseWorkflow: options.releaseWorkflow
|
|
12915
13346
|
});
|
|
12916
13347
|
operations.push({
|
|
12917
13348
|
kind: "create",
|
|
@@ -13156,7 +13587,8 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
|
|
|
13156
13587
|
sourceRoot: sourceRoot ?? "",
|
|
13157
13588
|
operations,
|
|
13158
13589
|
warnings,
|
|
13159
|
-
hasLabelConflicts
|
|
13590
|
+
hasLabelConflicts,
|
|
13591
|
+
enabledAddons: options.releaseWorkflow?.enabled ? ["release"] : []
|
|
13160
13592
|
};
|
|
13161
13593
|
}
|
|
13162
13594
|
var GROUP_LABELS = {
|
|
@@ -13228,6 +13660,7 @@ async function promptForInitChoices(plan, current) {
|
|
|
13228
13660
|
let packageManager = current.packageManager;
|
|
13229
13661
|
let legacySkills = current.legacySkills ?? false;
|
|
13230
13662
|
let noGitCheck = current.noGitCheck ?? false;
|
|
13663
|
+
let releaseWorkflow;
|
|
13231
13664
|
const labels = current.labels ? { ...current.labels } : { ...DEFAULT_RUNNER_LABELS };
|
|
13232
13665
|
if (!packageManager && plan.warnings.some((w) => w.toLowerCase().includes("lockfile"))) {
|
|
13233
13666
|
const result = await select({
|
|
@@ -13247,6 +13680,7 @@ async function promptForInitChoices(plan, current) {
|
|
|
13247
13680
|
legacySkills,
|
|
13248
13681
|
noGitCheck,
|
|
13249
13682
|
labels,
|
|
13683
|
+
releaseWorkflow,
|
|
13250
13684
|
cancelled: true
|
|
13251
13685
|
};
|
|
13252
13686
|
}
|
|
@@ -13270,6 +13704,7 @@ async function promptForInitChoices(plan, current) {
|
|
|
13270
13704
|
legacySkills,
|
|
13271
13705
|
noGitCheck,
|
|
13272
13706
|
labels,
|
|
13707
|
+
releaseWorkflow,
|
|
13273
13708
|
cancelled: true
|
|
13274
13709
|
};
|
|
13275
13710
|
}
|
|
@@ -13295,6 +13730,7 @@ async function promptForInitChoices(plan, current) {
|
|
|
13295
13730
|
legacySkills,
|
|
13296
13731
|
noGitCheck,
|
|
13297
13732
|
labels,
|
|
13733
|
+
releaseWorkflow,
|
|
13298
13734
|
cancelled: true
|
|
13299
13735
|
};
|
|
13300
13736
|
}
|
|
@@ -13413,11 +13849,84 @@ async function promptForInitChoices(plan, current) {
|
|
|
13413
13849
|
legacySkills,
|
|
13414
13850
|
noGitCheck,
|
|
13415
13851
|
labels,
|
|
13852
|
+
releaseWorkflow,
|
|
13416
13853
|
cancelled: true
|
|
13417
13854
|
};
|
|
13418
13855
|
}
|
|
13419
13856
|
noGitCheck = true;
|
|
13420
13857
|
}
|
|
13858
|
+
const releaseEnabledResult = await confirm({
|
|
13859
|
+
message: "Enable the Release Workflow Add-On for Changesets and Promotion PR orchestration?",
|
|
13860
|
+
initialValue: false
|
|
13861
|
+
});
|
|
13862
|
+
if (isCancel(releaseEnabledResult)) {
|
|
13863
|
+
return {
|
|
13864
|
+
docsMigration: docsMigration ?? "copy",
|
|
13865
|
+
agentFile: agentFile ?? "both",
|
|
13866
|
+
packageManager,
|
|
13867
|
+
legacySkills,
|
|
13868
|
+
noGitCheck,
|
|
13869
|
+
labels,
|
|
13870
|
+
releaseWorkflow: void 0,
|
|
13871
|
+
cancelled: true
|
|
13872
|
+
};
|
|
13873
|
+
}
|
|
13874
|
+
if (releaseEnabledResult) {
|
|
13875
|
+
const integrationBranchResult = await text({
|
|
13876
|
+
message: "Integration Branch name (e.g. dev)?",
|
|
13877
|
+
placeholder: "integration"
|
|
13878
|
+
});
|
|
13879
|
+
if (isCancel(integrationBranchResult)) {
|
|
13880
|
+
return {
|
|
13881
|
+
docsMigration: docsMigration ?? "copy",
|
|
13882
|
+
agentFile: agentFile ?? "both",
|
|
13883
|
+
packageManager,
|
|
13884
|
+
legacySkills,
|
|
13885
|
+
noGitCheck,
|
|
13886
|
+
labels,
|
|
13887
|
+
releaseWorkflow: void 0,
|
|
13888
|
+
cancelled: true
|
|
13889
|
+
};
|
|
13890
|
+
}
|
|
13891
|
+
const devReleaseBranchResult = await text({
|
|
13892
|
+
message: "Development Release Branch name (e.g. next)?",
|
|
13893
|
+
placeholder: "preview"
|
|
13894
|
+
});
|
|
13895
|
+
if (isCancel(devReleaseBranchResult)) {
|
|
13896
|
+
return {
|
|
13897
|
+
docsMigration: docsMigration ?? "copy",
|
|
13898
|
+
agentFile: agentFile ?? "both",
|
|
13899
|
+
packageManager,
|
|
13900
|
+
legacySkills,
|
|
13901
|
+
noGitCheck,
|
|
13902
|
+
labels,
|
|
13903
|
+
releaseWorkflow: void 0,
|
|
13904
|
+
cancelled: true
|
|
13905
|
+
};
|
|
13906
|
+
}
|
|
13907
|
+
const stableReleaseBranchResult = await text({
|
|
13908
|
+
message: "Stable Release Branch name (e.g. main)?",
|
|
13909
|
+
placeholder: "stable"
|
|
13910
|
+
});
|
|
13911
|
+
if (isCancel(stableReleaseBranchResult)) {
|
|
13912
|
+
return {
|
|
13913
|
+
docsMigration: docsMigration ?? "copy",
|
|
13914
|
+
agentFile: agentFile ?? "both",
|
|
13915
|
+
packageManager,
|
|
13916
|
+
legacySkills,
|
|
13917
|
+
noGitCheck,
|
|
13918
|
+
labels,
|
|
13919
|
+
releaseWorkflow: void 0,
|
|
13920
|
+
cancelled: true
|
|
13921
|
+
};
|
|
13922
|
+
}
|
|
13923
|
+
releaseWorkflow = {
|
|
13924
|
+
enabled: true,
|
|
13925
|
+
integrationBranch: typeof integrationBranchResult === "string" && integrationBranchResult.trim().length > 0 ? integrationBranchResult.trim() : "integration",
|
|
13926
|
+
developmentReleaseBranch: typeof devReleaseBranchResult === "string" && devReleaseBranchResult.trim().length > 0 ? devReleaseBranchResult.trim() : "preview",
|
|
13927
|
+
stableReleaseBranch: typeof stableReleaseBranchResult === "string" && stableReleaseBranchResult.trim().length > 0 ? stableReleaseBranchResult.trim() : "stable"
|
|
13928
|
+
};
|
|
13929
|
+
}
|
|
13421
13930
|
return {
|
|
13422
13931
|
docsMigration: docsMigration ?? "copy",
|
|
13423
13932
|
agentFile: agentFile ?? "both",
|
|
@@ -13425,6 +13934,7 @@ async function promptForInitChoices(plan, current) {
|
|
|
13425
13934
|
legacySkills,
|
|
13426
13935
|
noGitCheck,
|
|
13427
13936
|
labels,
|
|
13937
|
+
releaseWorkflow,
|
|
13428
13938
|
cancelled: false
|
|
13429
13939
|
};
|
|
13430
13940
|
}
|
|
@@ -13490,6 +14000,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
|
|
|
13490
14000
|
},
|
|
13491
14001
|
agentFiles,
|
|
13492
14002
|
packageManager,
|
|
14003
|
+
workflowPack: buildWorkflowPackMetadata(plan.enabledAddons ?? []),
|
|
13493
14004
|
assets
|
|
13494
14005
|
};
|
|
13495
14006
|
await mkdir5(manifestDir, { recursive: true });
|
|
@@ -13766,7 +14277,8 @@ async function runInitCommand(options) {
|
|
|
13766
14277
|
agentFile: options.agentFile ?? promptResult.agentFile,
|
|
13767
14278
|
packageManager: options.packageManager ?? promptResult.packageManager,
|
|
13768
14279
|
legacySkills: options.legacySkills ?? promptResult.legacySkills,
|
|
13769
|
-
noGitCheck: options.noGitCheck ?? promptResult.noGitCheck
|
|
14280
|
+
noGitCheck: options.noGitCheck ?? promptResult.noGitCheck,
|
|
14281
|
+
releaseWorkflow: options.releaseWorkflow ?? promptResult.releaseWorkflow
|
|
13770
14282
|
};
|
|
13771
14283
|
promptLabels = promptResult.labels;
|
|
13772
14284
|
}
|
|
@@ -13784,7 +14296,8 @@ async function runInitCommand(options) {
|
|
|
13784
14296
|
packageManager: options.packageManager,
|
|
13785
14297
|
noGitCheck: options.noGitCheck,
|
|
13786
14298
|
skipInstall: options.skipInstall,
|
|
13787
|
-
labels: planLabels
|
|
14299
|
+
labels: planLabels,
|
|
14300
|
+
releaseWorkflow: options.releaseWorkflow
|
|
13788
14301
|
});
|
|
13789
14302
|
let planLabelConflictPolicy = "skip-metadata-changes";
|
|
13790
14303
|
if (isInteractive && plan.hasLabelConflicts) {
|
|
@@ -13990,8 +14503,8 @@ async function runSerenaStatusCommand(options) {
|
|
|
13990
14503
|
|
|
13991
14504
|
// commands/config-schema.ts
|
|
13992
14505
|
import { readFileSync as readFileSync20, existsSync as existsSync19 } from "fs";
|
|
13993
|
-
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
|
|
13994
|
-
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
14506
|
+
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
|
|
14507
|
+
import { resolve as resolve4, dirname as dirname5, relative as relative2 } from "path";
|
|
13995
14508
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13996
14509
|
import Ajv2 from "ajv";
|
|
13997
14510
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
@@ -14028,33 +14541,569 @@ function readPackagedHash() {
|
|
|
14028
14541
|
function localSchemaDir(repoRoot2) {
|
|
14029
14542
|
return resolve4(repoRoot2, ".pourkit/schema");
|
|
14030
14543
|
}
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
14544
|
+
var MANAGED_BLOCK_BEGIN2 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
|
|
14545
|
+
var OLD_DOCS_PATH_PATTERN = ".pourkit/docs/agents/";
|
|
14546
|
+
function resolvePackagedManagedPath(...segments) {
|
|
14547
|
+
return resolve4(__dirname2, "..", "managed", ...segments);
|
|
14548
|
+
}
|
|
14549
|
+
function resolvePackagedManagedDocPath(docName) {
|
|
14550
|
+
return resolvePackagedManagedPath("docs", "agents", docName);
|
|
14551
|
+
}
|
|
14552
|
+
function resolvePackagedReleaseAddonDocPath(docName) {
|
|
14553
|
+
return resolvePackagedManagedPath(
|
|
14554
|
+
"addons",
|
|
14555
|
+
"release",
|
|
14556
|
+
"docs",
|
|
14557
|
+
"agents",
|
|
14558
|
+
docName
|
|
14559
|
+
);
|
|
14560
|
+
}
|
|
14561
|
+
async function readPackagedTextFile(filePath) {
|
|
14039
14562
|
try {
|
|
14040
|
-
|
|
14563
|
+
return await readFile6(filePath, "utf-8");
|
|
14041
14564
|
} catch {
|
|
14565
|
+
return null;
|
|
14042
14566
|
}
|
|
14043
|
-
|
|
14044
|
-
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
|
|
14567
|
+
}
|
|
14568
|
+
function isPathContained(parent, child) {
|
|
14569
|
+
const relativePath = relative2(parent, child);
|
|
14570
|
+
return !relativePath.startsWith("..") && !relativePath.startsWith("../");
|
|
14571
|
+
}
|
|
14572
|
+
async function walkDir2(dir) {
|
|
14573
|
+
const files = [];
|
|
14574
|
+
try {
|
|
14575
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
14576
|
+
for (const entry of entries) {
|
|
14577
|
+
const full = resolve4(dir, entry.name);
|
|
14578
|
+
if (entry.isDirectory()) {
|
|
14579
|
+
files.push(...await walkDir2(full));
|
|
14580
|
+
} else {
|
|
14581
|
+
files.push(full);
|
|
14582
|
+
}
|
|
14048
14583
|
}
|
|
14584
|
+
} catch {
|
|
14585
|
+
return [];
|
|
14049
14586
|
}
|
|
14050
|
-
|
|
14051
|
-
|
|
14052
|
-
|
|
14053
|
-
|
|
14054
|
-
|
|
14055
|
-
|
|
14056
|
-
|
|
14057
|
-
|
|
14587
|
+
return files;
|
|
14588
|
+
}
|
|
14589
|
+
function removeCodeFences(content) {
|
|
14590
|
+
return content.replace(/```[\s\S]*?```/g, "");
|
|
14591
|
+
}
|
|
14592
|
+
function isInsideBacktick(content, index) {
|
|
14593
|
+
const before = content.slice(0, index);
|
|
14594
|
+
const backtickCount = (before.match(/`/g) || []).length;
|
|
14595
|
+
return backtickCount % 2 === 1;
|
|
14596
|
+
}
|
|
14597
|
+
var BRANCH_NAME_PATTERN = /\b(dev|next|main)\b/g;
|
|
14598
|
+
var OBSOLETE_PRD_PATTERN = /PRD-\d{3}(?![\dNn])/g;
|
|
14599
|
+
var OVERWIDE_PRD_PATTERN = /PRD-\d{5,}/g;
|
|
14600
|
+
function isExampleLine(content, matchIndex) {
|
|
14601
|
+
return /^(?:[-*]\s+)?Example:/i.test(getLine(content, matchIndex).trim());
|
|
14602
|
+
}
|
|
14603
|
+
function getLine(content, matchIndex) {
|
|
14604
|
+
const lineStart = content.lastIndexOf("\n", matchIndex - 1) + 1;
|
|
14605
|
+
const lineEnd = content.indexOf("\n", matchIndex);
|
|
14606
|
+
return content.slice(lineStart, lineEnd === -1 ? content.length : lineEnd);
|
|
14607
|
+
}
|
|
14608
|
+
function isBranchPolicyLine(content, matchIndex) {
|
|
14609
|
+
const line = getLine(content, matchIndex).toLowerCase();
|
|
14610
|
+
return /->|\b(branch|branches|lane|release|promotion|promote|target|base|merge|push|hotfix|changeset|origin)\b/.test(
|
|
14611
|
+
line
|
|
14612
|
+
);
|
|
14613
|
+
}
|
|
14614
|
+
function scanManagedPolicyText(content, filePath, allowlist) {
|
|
14615
|
+
const violations = [];
|
|
14616
|
+
const noFences = removeCodeFences(content);
|
|
14617
|
+
let match;
|
|
14618
|
+
BRANCH_NAME_PATTERN.lastIndex = 0;
|
|
14619
|
+
while ((match = BRANCH_NAME_PATTERN.exec(noFences)) !== null) {
|
|
14620
|
+
if (isExampleLine(noFences, match.index)) continue;
|
|
14621
|
+
if (!isBranchPolicyLine(noFences, match.index)) continue;
|
|
14622
|
+
if (allowlist?.includes(match[0])) continue;
|
|
14623
|
+
violations.push({
|
|
14624
|
+
path: filePath,
|
|
14625
|
+
phrase: match[0],
|
|
14626
|
+
reason: "hardcoded_branch_policy"
|
|
14627
|
+
});
|
|
14628
|
+
}
|
|
14629
|
+
OBSOLETE_PRD_PATTERN.lastIndex = 0;
|
|
14630
|
+
while ((match = OBSOLETE_PRD_PATTERN.exec(noFences)) !== null) {
|
|
14631
|
+
if (allowlist?.includes(match[0])) continue;
|
|
14632
|
+
if (!isInsideBacktick(noFences, match.index)) {
|
|
14633
|
+
violations.push({
|
|
14634
|
+
path: filePath,
|
|
14635
|
+
phrase: match[0],
|
|
14636
|
+
reason: "obsolete_prd_placeholder"
|
|
14637
|
+
});
|
|
14638
|
+
}
|
|
14639
|
+
}
|
|
14640
|
+
OVERWIDE_PRD_PATTERN.lastIndex = 0;
|
|
14641
|
+
while ((match = OVERWIDE_PRD_PATTERN.exec(noFences)) !== null) {
|
|
14642
|
+
if (allowlist?.includes(match[0])) continue;
|
|
14643
|
+
if (!isInsideBacktick(noFences, match.index)) {
|
|
14644
|
+
violations.push({
|
|
14645
|
+
path: filePath,
|
|
14646
|
+
phrase: match[0],
|
|
14647
|
+
reason: "obsolete_prd_placeholder"
|
|
14648
|
+
});
|
|
14649
|
+
}
|
|
14650
|
+
}
|
|
14651
|
+
return violations;
|
|
14652
|
+
}
|
|
14653
|
+
async function validateWorkflowPack(cwd) {
|
|
14654
|
+
const failures = [];
|
|
14655
|
+
const warnings = [];
|
|
14656
|
+
const catalog = getWorkflowPackCatalog();
|
|
14657
|
+
const baselineSkills = getBaselineManagedSkillNames();
|
|
14658
|
+
for (const docName of catalog.docs) {
|
|
14659
|
+
const localPath = resolve4(cwd, `.pourkit/managed/docs/agents/${docName}`);
|
|
14660
|
+
if (!existsSync19(localPath)) {
|
|
14661
|
+
failures.push({
|
|
14662
|
+
severity: "failure",
|
|
14663
|
+
kind: "missing_managed_asset",
|
|
14664
|
+
path: `.pourkit/managed/docs/agents/${docName}`,
|
|
14665
|
+
message: `Missing managed doc: ${docName}`
|
|
14666
|
+
});
|
|
14667
|
+
} else {
|
|
14668
|
+
const packagedPath = resolvePackagedManagedDocPath(docName);
|
|
14669
|
+
const packagedContent = await readPackagedTextFile(packagedPath);
|
|
14670
|
+
if (packagedContent !== null) {
|
|
14671
|
+
try {
|
|
14672
|
+
const localContent = await readFile6(localPath, "utf-8");
|
|
14673
|
+
if (localContent !== packagedContent) {
|
|
14674
|
+
const overridePath = resolve4(
|
|
14675
|
+
cwd,
|
|
14676
|
+
`.pourkit/overrides/docs/agents/${docName}`
|
|
14677
|
+
);
|
|
14678
|
+
if (existsSync19(overridePath)) {
|
|
14679
|
+
warnings.push({
|
|
14680
|
+
severity: "warning",
|
|
14681
|
+
kind: "overridden",
|
|
14682
|
+
path: `.pourkit/overrides/docs/agents/${docName}`,
|
|
14683
|
+
message: `Managed doc ${docName} is overridden by explicit override.`
|
|
14684
|
+
});
|
|
14685
|
+
} else {
|
|
14686
|
+
failures.push({
|
|
14687
|
+
severity: "failure",
|
|
14688
|
+
kind: "managed_asset_drift",
|
|
14689
|
+
path: `.pourkit/managed/docs/agents/${docName}`,
|
|
14690
|
+
message: `Managed doc ${docName} content differs from packaged source. Run 'pourkit sync workflow-pack' to repair.`
|
|
14691
|
+
});
|
|
14692
|
+
}
|
|
14693
|
+
}
|
|
14694
|
+
} catch {
|
|
14695
|
+
}
|
|
14696
|
+
}
|
|
14697
|
+
}
|
|
14698
|
+
}
|
|
14699
|
+
for (const skillName of baselineSkills) {
|
|
14700
|
+
const skillDir = resolve4(cwd, `.pourkit/managed/skills/${skillName}`);
|
|
14701
|
+
if (!existsSync19(skillDir)) {
|
|
14702
|
+
failures.push({
|
|
14703
|
+
severity: "failure",
|
|
14704
|
+
kind: "missing_managed_asset",
|
|
14705
|
+
path: `.pourkit/managed/skills/${skillName}`,
|
|
14706
|
+
message: `Missing managed skill: ${skillName}`
|
|
14707
|
+
});
|
|
14708
|
+
} else {
|
|
14709
|
+
const skillSourcePath = resolve4(skillDir, "SKILL.md");
|
|
14710
|
+
if (existsSync19(skillSourcePath)) {
|
|
14711
|
+
const packagedSkillPath = resolvePackagedManagedPath(
|
|
14712
|
+
"skills",
|
|
14713
|
+
skillName,
|
|
14714
|
+
"SKILL.md"
|
|
14715
|
+
);
|
|
14716
|
+
const packagedContent = await readPackagedTextFile(packagedSkillPath);
|
|
14717
|
+
if (packagedContent !== null) {
|
|
14718
|
+
try {
|
|
14719
|
+
const localContent = await readFile6(skillSourcePath, "utf-8");
|
|
14720
|
+
if (localContent !== packagedContent) {
|
|
14721
|
+
const overridePath = resolve4(
|
|
14722
|
+
cwd,
|
|
14723
|
+
`.pourkit/overrides/skills/${skillName}/SKILL.md`
|
|
14724
|
+
);
|
|
14725
|
+
if (existsSync19(overridePath)) {
|
|
14726
|
+
warnings.push({
|
|
14727
|
+
severity: "warning",
|
|
14728
|
+
kind: "overridden",
|
|
14729
|
+
path: `.pourkit/overrides/skills/${skillName}/SKILL.md`,
|
|
14730
|
+
message: `Managed skill ${skillName} is overridden by explicit override.`
|
|
14731
|
+
});
|
|
14732
|
+
} else {
|
|
14733
|
+
failures.push({
|
|
14734
|
+
severity: "failure",
|
|
14735
|
+
kind: "managed_asset_drift",
|
|
14736
|
+
path: `.pourkit/managed/skills/${skillName}/SKILL.md`,
|
|
14737
|
+
message: `Managed skill ${skillName} content differs from packaged source. Run 'pourkit sync workflow-pack' to repair.`
|
|
14738
|
+
});
|
|
14739
|
+
}
|
|
14740
|
+
}
|
|
14741
|
+
} catch {
|
|
14742
|
+
}
|
|
14743
|
+
}
|
|
14744
|
+
}
|
|
14745
|
+
}
|
|
14746
|
+
}
|
|
14747
|
+
for (const promptName of catalog.prompts) {
|
|
14748
|
+
const promptPath = resolve4(cwd, `.pourkit/managed/prompts/${promptName}`);
|
|
14749
|
+
if (!existsSync19(promptPath)) {
|
|
14750
|
+
failures.push({
|
|
14751
|
+
severity: "failure",
|
|
14752
|
+
kind: "missing_managed_asset",
|
|
14753
|
+
path: `.pourkit/managed/prompts/${promptName}`,
|
|
14754
|
+
message: `Missing managed prompt: ${promptName}`
|
|
14755
|
+
});
|
|
14756
|
+
}
|
|
14757
|
+
}
|
|
14758
|
+
for (const skillName of baselineSkills) {
|
|
14759
|
+
const projectionDir = resolve4(cwd, `.agents/skills/${skillName}`);
|
|
14760
|
+
if (!existsSync19(projectionDir)) {
|
|
14761
|
+
warnings.push({
|
|
14762
|
+
severity: "warning",
|
|
14763
|
+
kind: "projection_stale",
|
|
14764
|
+
path: `.agents/skills/${skillName}`,
|
|
14765
|
+
message: `Missing skill projection for ${skillName}. Run 'pourkit sync workflow-pack' to regenerate.`
|
|
14766
|
+
});
|
|
14767
|
+
} else {
|
|
14768
|
+
const projectionPath = resolve4(projectionDir, "SKILL.md");
|
|
14769
|
+
if (existsSync19(projectionPath)) {
|
|
14770
|
+
const managedSourcePath = resolvePackagedManagedPath(
|
|
14771
|
+
"skills",
|
|
14772
|
+
skillName,
|
|
14773
|
+
"SKILL.md"
|
|
14774
|
+
);
|
|
14775
|
+
const packagedContent = await readPackagedTextFile(managedSourcePath);
|
|
14776
|
+
if (packagedContent !== null) {
|
|
14777
|
+
try {
|
|
14778
|
+
const projectionContent = await readFile6(projectionPath, "utf-8");
|
|
14779
|
+
const managedSourceRelativePath = `.pourkit/managed/skills/${skillName}/SKILL.md`;
|
|
14780
|
+
if (projectionContent !== buildOpenCodeSkillProjectionContent(
|
|
14781
|
+
managedSourceRelativePath,
|
|
14782
|
+
packagedContent
|
|
14783
|
+
)) {
|
|
14784
|
+
warnings.push({
|
|
14785
|
+
severity: "warning",
|
|
14786
|
+
kind: "projection_stale",
|
|
14787
|
+
path: `.agents/skills/${skillName}/SKILL.md`,
|
|
14788
|
+
message: `Projection for ${skillName} differs from managed source. Run 'pourkit sync workflow-pack' to regenerate.`
|
|
14789
|
+
});
|
|
14790
|
+
}
|
|
14791
|
+
} catch {
|
|
14792
|
+
}
|
|
14793
|
+
}
|
|
14794
|
+
}
|
|
14795
|
+
}
|
|
14796
|
+
}
|
|
14797
|
+
const agentsPath = resolve4(cwd, "AGENTS.md");
|
|
14798
|
+
if (existsSync19(agentsPath)) {
|
|
14799
|
+
try {
|
|
14800
|
+
const agentsContent = await readFile6(agentsPath, "utf-8");
|
|
14801
|
+
if (agentsContent.includes(OLD_DOCS_PATH_PATTERN)) {
|
|
14802
|
+
failures.push({
|
|
14803
|
+
severity: "failure",
|
|
14804
|
+
kind: "router_drift",
|
|
14805
|
+
path: "AGENTS.md",
|
|
14806
|
+
message: "AGENTS.md references old .pourkit/docs/agents/ paths. Update to .pourkit/managed/docs/agents/."
|
|
14807
|
+
});
|
|
14808
|
+
}
|
|
14809
|
+
if (!agentsContent.includes(MANAGED_BLOCK_BEGIN2.trim())) {
|
|
14810
|
+
failures.push({
|
|
14811
|
+
severity: "failure",
|
|
14812
|
+
kind: "router_drift",
|
|
14813
|
+
path: "AGENTS.md",
|
|
14814
|
+
message: "AGENTS.md is missing the Pourkit managed block. Run 'pourkit sync workflow-pack' to add it."
|
|
14815
|
+
});
|
|
14816
|
+
}
|
|
14817
|
+
} catch {
|
|
14818
|
+
}
|
|
14819
|
+
}
|
|
14820
|
+
const overridesDir = resolve4(cwd, ".pourkit/overrides");
|
|
14821
|
+
if (existsSync19(overridesDir)) {
|
|
14822
|
+
const overrideFiles = await walkDir2(overridesDir);
|
|
14823
|
+
for (const file of overrideFiles) {
|
|
14824
|
+
const relPath = relative2(cwd, file);
|
|
14825
|
+
if (!warnings.some((w) => w.kind === "overridden" && w.path === relPath)) {
|
|
14826
|
+
warnings.push({
|
|
14827
|
+
severity: "warning",
|
|
14828
|
+
kind: "overridden",
|
|
14829
|
+
path: relPath,
|
|
14830
|
+
message: `Explicit override present: ${relPath}`
|
|
14831
|
+
});
|
|
14832
|
+
}
|
|
14833
|
+
}
|
|
14834
|
+
}
|
|
14835
|
+
const configPath = resolve4(cwd, ".pourkit/config.json");
|
|
14836
|
+
if (existsSync19(configPath)) {
|
|
14837
|
+
try {
|
|
14838
|
+
const configContent = await readFile6(configPath, "utf-8");
|
|
14839
|
+
const parsed = JSON.parse(configContent);
|
|
14840
|
+
const releaseEnabled = parsed.releaseWorkflow?.enabled === true;
|
|
14841
|
+
if (releaseEnabled) {
|
|
14842
|
+
for (const skillName of catalog.releaseAddonSkills) {
|
|
14843
|
+
const addonDir = resolve4(
|
|
14844
|
+
cwd,
|
|
14845
|
+
`.pourkit/managed/addons/release/skills/${skillName}`
|
|
14846
|
+
);
|
|
14847
|
+
if (!existsSync19(addonDir)) {
|
|
14848
|
+
failures.push({
|
|
14849
|
+
severity: "failure",
|
|
14850
|
+
kind: "release_config_conflict",
|
|
14851
|
+
path: `.pourkit/managed/addons/release/skills/${skillName}`,
|
|
14852
|
+
message: `Release workflow is enabled but release addon skill ${skillName} is not installed. Run 'pourkit sync workflow-pack' to install.`
|
|
14853
|
+
});
|
|
14854
|
+
}
|
|
14855
|
+
}
|
|
14856
|
+
for (const docName of catalog.releaseAddonDocs) {
|
|
14857
|
+
const addonDocPath = resolve4(
|
|
14858
|
+
cwd,
|
|
14859
|
+
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
14860
|
+
);
|
|
14861
|
+
if (!existsSync19(addonDocPath)) {
|
|
14862
|
+
failures.push({
|
|
14863
|
+
severity: "failure",
|
|
14864
|
+
kind: "release_config_conflict",
|
|
14865
|
+
path: `.pourkit/managed/addons/release/docs/agents/${docName}`,
|
|
14866
|
+
message: `Release workflow is enabled but release addon doc ${docName} is not installed. Run 'pourkit sync workflow-pack' to install.`
|
|
14867
|
+
});
|
|
14868
|
+
} else {
|
|
14869
|
+
const packagedContent = await readPackagedTextFile(
|
|
14870
|
+
resolvePackagedReleaseAddonDocPath(docName)
|
|
14871
|
+
);
|
|
14872
|
+
if (packagedContent !== null) {
|
|
14873
|
+
const localContent = await readFile6(addonDocPath, "utf-8");
|
|
14874
|
+
if (localContent !== packagedContent) {
|
|
14875
|
+
failures.push({
|
|
14876
|
+
severity: "failure",
|
|
14877
|
+
kind: "managed_asset_drift",
|
|
14878
|
+
path: `.pourkit/managed/addons/release/docs/agents/${docName}`,
|
|
14879
|
+
message: `Release addon doc ${docName} content differs from packaged source. Run 'pourkit sync workflow-pack' to repair.`
|
|
14880
|
+
});
|
|
14881
|
+
}
|
|
14882
|
+
}
|
|
14883
|
+
}
|
|
14884
|
+
}
|
|
14885
|
+
const rw = parsed.releaseWorkflow;
|
|
14886
|
+
const requiredFields = [
|
|
14887
|
+
["integrationBranch", rw?.integrationBranch],
|
|
14888
|
+
["developmentReleaseBranch", rw?.developmentReleaseBranch],
|
|
14889
|
+
["stableReleaseBranch", rw?.stableReleaseBranch]
|
|
14890
|
+
];
|
|
14891
|
+
for (const [fieldName, value] of requiredFields) {
|
|
14892
|
+
if (!value || typeof value === "string" && value.trim() === "") {
|
|
14893
|
+
failures.push({
|
|
14894
|
+
severity: "failure",
|
|
14895
|
+
kind: "release_config_conflict",
|
|
14896
|
+
message: `Release workflow is enabled but required field releaseWorkflow.${fieldName} is missing or empty.`
|
|
14897
|
+
});
|
|
14898
|
+
}
|
|
14899
|
+
}
|
|
14900
|
+
} else {
|
|
14901
|
+
for (const skillName of catalog.releaseAddonSkills) {
|
|
14902
|
+
const addonDir = resolve4(
|
|
14903
|
+
cwd,
|
|
14904
|
+
`.pourkit/managed/addons/release/skills/${skillName}`
|
|
14905
|
+
);
|
|
14906
|
+
if (existsSync19(addonDir)) {
|
|
14907
|
+
failures.push({
|
|
14908
|
+
severity: "failure",
|
|
14909
|
+
kind: "release_config_conflict",
|
|
14910
|
+
path: `.pourkit/managed/addons/release/skills/${skillName}`,
|
|
14911
|
+
message: `Release workflow is disabled but release addon skill ${skillName} is present as active baseline policy. Disable or remove the addon skill.`
|
|
14912
|
+
});
|
|
14913
|
+
}
|
|
14914
|
+
}
|
|
14915
|
+
for (const docName of catalog.releaseAddonDocs) {
|
|
14916
|
+
const addonDocPath = resolve4(
|
|
14917
|
+
cwd,
|
|
14918
|
+
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
14919
|
+
);
|
|
14920
|
+
if (existsSync19(addonDocPath)) {
|
|
14921
|
+
failures.push({
|
|
14922
|
+
severity: "failure",
|
|
14923
|
+
kind: "release_config_conflict",
|
|
14924
|
+
path: `.pourkit/managed/addons/release/docs/agents/${docName}`,
|
|
14925
|
+
message: `Release workflow is disabled but release addon doc ${docName} is present as active baseline policy. Disable or remove the addon doc.`
|
|
14926
|
+
});
|
|
14927
|
+
}
|
|
14928
|
+
}
|
|
14929
|
+
}
|
|
14930
|
+
} catch {
|
|
14931
|
+
}
|
|
14932
|
+
}
|
|
14933
|
+
const manifestPath = resolve4(cwd, ".pourkit/manifest.json");
|
|
14934
|
+
if (existsSync19(manifestPath)) {
|
|
14935
|
+
try {
|
|
14936
|
+
const manifestContent = await readFile6(manifestPath, "utf-8");
|
|
14937
|
+
const manifest = JSON.parse(manifestContent);
|
|
14938
|
+
const wp = manifest.workflowPack;
|
|
14939
|
+
if (wp?.projections) {
|
|
14940
|
+
for (const proj of wp.projections) {
|
|
14941
|
+
if (proj.path) {
|
|
14942
|
+
const resolved = resolve4(cwd, proj.path);
|
|
14943
|
+
if (!isPathContained(cwd, resolved)) {
|
|
14944
|
+
failures.push({
|
|
14945
|
+
severity: "failure",
|
|
14946
|
+
kind: "path_escape",
|
|
14947
|
+
message: `Manifest projection path escapes repository: ${proj.path}`
|
|
14948
|
+
});
|
|
14949
|
+
}
|
|
14950
|
+
}
|
|
14951
|
+
}
|
|
14952
|
+
}
|
|
14953
|
+
} catch {
|
|
14954
|
+
}
|
|
14955
|
+
}
|
|
14956
|
+
const pathEscapeOverrideDir = resolve4(cwd, ".pourkit/overrides");
|
|
14957
|
+
if (existsSync19(pathEscapeOverrideDir)) {
|
|
14958
|
+
const overrideFiles = await walkDir2(pathEscapeOverrideDir);
|
|
14959
|
+
for (const file of overrideFiles) {
|
|
14960
|
+
if (!isPathContained(cwd, file)) {
|
|
14961
|
+
failures.push({
|
|
14962
|
+
severity: "failure",
|
|
14963
|
+
kind: "path_escape",
|
|
14964
|
+
path: relative2(cwd, file),
|
|
14965
|
+
message: `Override file path escapes repository: ${relative2(cwd, file)}`
|
|
14966
|
+
});
|
|
14967
|
+
}
|
|
14968
|
+
}
|
|
14969
|
+
}
|
|
14970
|
+
const managedDocsDir = resolve4(cwd, ".pourkit/managed/docs/agents");
|
|
14971
|
+
if (existsSync19(managedDocsDir)) {
|
|
14972
|
+
const docFiles = await walkDir2(managedDocsDir);
|
|
14973
|
+
for (const file of docFiles) {
|
|
14974
|
+
if (!file.endsWith(".md")) continue;
|
|
14975
|
+
try {
|
|
14976
|
+
const content = await readFile6(file, "utf-8");
|
|
14977
|
+
const relPath = relative2(cwd, file);
|
|
14978
|
+
const violations = scanManagedPolicyText(content, relPath);
|
|
14979
|
+
for (const v of violations) {
|
|
14980
|
+
failures.push({
|
|
14981
|
+
severity: "failure",
|
|
14982
|
+
kind: "terminology_policy_violation",
|
|
14983
|
+
path: v.path,
|
|
14984
|
+
message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
|
|
14985
|
+
});
|
|
14986
|
+
}
|
|
14987
|
+
} catch {
|
|
14988
|
+
}
|
|
14989
|
+
}
|
|
14990
|
+
}
|
|
14991
|
+
const managedSkillsDir = resolve4(cwd, ".pourkit/managed/skills");
|
|
14992
|
+
if (existsSync19(managedSkillsDir)) {
|
|
14993
|
+
const skillDirs = await readdir2(managedSkillsDir, { withFileTypes: true });
|
|
14994
|
+
for (const entry of skillDirs) {
|
|
14995
|
+
if (!entry.isDirectory()) continue;
|
|
14996
|
+
const skillFile = resolve4(managedSkillsDir, entry.name, "SKILL.md");
|
|
14997
|
+
if (!existsSync19(skillFile)) continue;
|
|
14998
|
+
try {
|
|
14999
|
+
const content = await readFile6(skillFile, "utf-8");
|
|
15000
|
+
const relPath = relative2(cwd, skillFile);
|
|
15001
|
+
const violations = scanManagedPolicyText(content, relPath);
|
|
15002
|
+
for (const v of violations) {
|
|
15003
|
+
failures.push({
|
|
15004
|
+
severity: "failure",
|
|
15005
|
+
kind: "terminology_policy_violation",
|
|
15006
|
+
path: v.path,
|
|
15007
|
+
message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
|
|
15008
|
+
});
|
|
15009
|
+
}
|
|
15010
|
+
} catch {
|
|
15011
|
+
}
|
|
15012
|
+
}
|
|
15013
|
+
}
|
|
15014
|
+
const managedPromptsDir = resolve4(cwd, ".pourkit/managed/prompts");
|
|
15015
|
+
if (existsSync19(managedPromptsDir)) {
|
|
15016
|
+
for (const promptName of catalog.prompts) {
|
|
15017
|
+
const promptFile = resolve4(managedPromptsDir, promptName);
|
|
15018
|
+
if (!existsSync19(promptFile)) continue;
|
|
15019
|
+
try {
|
|
15020
|
+
const content = await readFile6(promptFile, "utf-8");
|
|
15021
|
+
const relPath = relative2(cwd, promptFile);
|
|
15022
|
+
const violations = scanManagedPolicyText(content, relPath);
|
|
15023
|
+
for (const v of violations) {
|
|
15024
|
+
failures.push({
|
|
15025
|
+
severity: "failure",
|
|
15026
|
+
kind: "terminology_policy_violation",
|
|
15027
|
+
path: v.path,
|
|
15028
|
+
message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
|
|
15029
|
+
});
|
|
15030
|
+
}
|
|
15031
|
+
} catch {
|
|
15032
|
+
}
|
|
15033
|
+
}
|
|
15034
|
+
}
|
|
15035
|
+
for (const skillName of catalog.releaseAddonSkills) {
|
|
15036
|
+
const addonSkillFile = resolve4(
|
|
15037
|
+
cwd,
|
|
15038
|
+
`.pourkit/managed/addons/release/skills/${skillName}/SKILL.md`
|
|
15039
|
+
);
|
|
15040
|
+
if (!existsSync19(addonSkillFile)) continue;
|
|
15041
|
+
try {
|
|
15042
|
+
const content = await readFile6(addonSkillFile, "utf-8");
|
|
15043
|
+
const relPath = relative2(cwd, addonSkillFile);
|
|
15044
|
+
const violations = scanManagedPolicyText(content, relPath);
|
|
15045
|
+
for (const v of violations) {
|
|
15046
|
+
failures.push({
|
|
15047
|
+
severity: "failure",
|
|
15048
|
+
kind: "terminology_policy_violation",
|
|
15049
|
+
path: v.path,
|
|
15050
|
+
message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
|
|
15051
|
+
});
|
|
15052
|
+
}
|
|
15053
|
+
} catch {
|
|
15054
|
+
}
|
|
15055
|
+
}
|
|
15056
|
+
for (const docName of catalog.releaseAddonDocs) {
|
|
15057
|
+
const addonDocFile = resolve4(
|
|
15058
|
+
cwd,
|
|
15059
|
+
`.pourkit/managed/addons/release/docs/agents/${docName}`
|
|
15060
|
+
);
|
|
15061
|
+
if (!existsSync19(addonDocFile)) continue;
|
|
15062
|
+
try {
|
|
15063
|
+
const content = await readFile6(addonDocFile, "utf-8");
|
|
15064
|
+
const relPath = relative2(cwd, addonDocFile);
|
|
15065
|
+
const violations = scanManagedPolicyText(content, relPath);
|
|
15066
|
+
for (const v of violations) {
|
|
15067
|
+
failures.push({
|
|
15068
|
+
severity: "failure",
|
|
15069
|
+
kind: "terminology_policy_violation",
|
|
15070
|
+
path: v.path,
|
|
15071
|
+
message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
|
|
15072
|
+
});
|
|
15073
|
+
}
|
|
15074
|
+
} catch {
|
|
15075
|
+
}
|
|
15076
|
+
}
|
|
15077
|
+
const status = failures.length > 0 ? "failed" : warnings.length > 0 ? "warning" : "fresh";
|
|
15078
|
+
return { status, failures, warnings };
|
|
15079
|
+
}
|
|
15080
|
+
async function runDoctorCommand(options) {
|
|
15081
|
+
const repoRootPath = options.cwd ?? process.cwd();
|
|
15082
|
+
const schemaDir = localSchemaDir(repoRootPath);
|
|
15083
|
+
const localSchemaPath = resolve4(schemaDir, "pourkit.schema.json");
|
|
15084
|
+
const localHashPath = resolve4(schemaDir, "pourkit.schema.hash");
|
|
15085
|
+
const localSchemaExists = existsSync19(localSchemaPath);
|
|
15086
|
+
const localHashExists = existsSync19(localHashPath);
|
|
15087
|
+
let packagedHash = null;
|
|
15088
|
+
try {
|
|
15089
|
+
packagedHash = readPackagedHash();
|
|
15090
|
+
} catch {
|
|
15091
|
+
}
|
|
15092
|
+
let localHashContent = null;
|
|
15093
|
+
if (localHashExists) {
|
|
15094
|
+
try {
|
|
15095
|
+
localHashContent = await readFile6(localHashPath, "utf-8");
|
|
15096
|
+
} catch {
|
|
15097
|
+
}
|
|
15098
|
+
}
|
|
15099
|
+
const schema = !localSchemaExists ? "missing" : !packagedHash || !localHashContent ? "missing" : localHashContent.trim() === packagedHash.trim() ? "fresh" : "stale";
|
|
15100
|
+
const hash = !localHashExists ? "missing" : !packagedHash ? "missing" : localHashContent && localHashContent.trim() === packagedHash.trim() ? "fresh" : "stale";
|
|
15101
|
+
const overall = schema === "fresh" && hash === "fresh" ? "fresh" : schema === "missing" || hash === "missing" ? "missing" : "stale";
|
|
15102
|
+
const configPath = resolve4(repoRootPath, ".pourkit/config.json");
|
|
15103
|
+
let configValidation;
|
|
15104
|
+
if (existsSync19(configPath)) {
|
|
15105
|
+
try {
|
|
15106
|
+
const raw = JSON.parse(readFileSync20(configPath, "utf-8"));
|
|
14058
15107
|
const validate = getSchemaValidator();
|
|
14059
15108
|
const valid2 = validate(raw);
|
|
14060
15109
|
if (valid2) {
|
|
@@ -14087,30 +15136,37 @@ async function runDoctorCommand(options) {
|
|
|
14087
15136
|
"pourkit.config.js",
|
|
14088
15137
|
"pourkit.json"
|
|
14089
15138
|
].filter((p) => existsSync19(resolve4(repoRootPath, p)));
|
|
15139
|
+
const workflowPack = await validateWorkflowPack(repoRootPath);
|
|
14090
15140
|
let recommendation = null;
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
|
|
14094
|
-
|
|
14095
|
-
|
|
14096
|
-
|
|
14097
|
-
|
|
14098
|
-
|
|
14099
|
-
|
|
14100
|
-
|
|
14101
|
-
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
|
|
14107
|
-
|
|
14108
|
-
|
|
15141
|
+
const recParts = [];
|
|
15142
|
+
if (obsoleteConfigs.length > 0) {
|
|
15143
|
+
recParts.push(
|
|
15144
|
+
`Found obsolete config files: ${obsoleteConfigs.join(", ")}. Move configuration to .pourkit/config.json with "$schema": "./schema/pourkit.schema.json".`
|
|
15145
|
+
);
|
|
15146
|
+
}
|
|
15147
|
+
if (!configValidation.ok) {
|
|
15148
|
+
recParts.push(
|
|
15149
|
+
"Config validation failed; fix errors in .pourkit/config.json."
|
|
15150
|
+
);
|
|
15151
|
+
}
|
|
15152
|
+
if (overall !== "fresh") {
|
|
15153
|
+
recParts.push(
|
|
15154
|
+
'Run "pourkit config sync-schema" to update local schema assets.'
|
|
15155
|
+
);
|
|
15156
|
+
}
|
|
15157
|
+
if (workflowPack.status === "failed" || workflowPack.status === "warning") {
|
|
15158
|
+
recParts.push(
|
|
15159
|
+
'Run "pourkit sync workflow-pack" to repair workflow pack issues.'
|
|
15160
|
+
);
|
|
15161
|
+
}
|
|
15162
|
+
if (recParts.length > 0) {
|
|
15163
|
+
recommendation = recParts.join(" ");
|
|
14109
15164
|
}
|
|
14110
15165
|
return {
|
|
14111
15166
|
configValidation,
|
|
14112
15167
|
obsoleteConfigs,
|
|
14113
15168
|
schemaAssets: { schema, hash, overall },
|
|
15169
|
+
workflowPack,
|
|
14114
15170
|
recommendation
|
|
14115
15171
|
};
|
|
14116
15172
|
}
|
|
@@ -14151,6 +15207,576 @@ async function runConfigSyncSchemaCommand(options) {
|
|
|
14151
15207
|
};
|
|
14152
15208
|
}
|
|
14153
15209
|
|
|
15210
|
+
// commands/workflow-pack-sync.ts
|
|
15211
|
+
import { existsSync as existsSync20, readdirSync as readdirSync5 } from "fs";
|
|
15212
|
+
import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile4, readdir as readdir3 } from "fs/promises";
|
|
15213
|
+
import { resolve as resolve5, dirname as dirname6, relative as relative3, normalize as normalize2 } from "path";
|
|
15214
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15215
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
15216
|
+
var __dirname3 = dirname6(__filename3);
|
|
15217
|
+
var PROJECT_OWNED_PATHS = [".pourkit/CONTEXT.md", ".pourkit/CONTEXT-MAP.md"];
|
|
15218
|
+
var PROJECT_OWNED_DIRECTORIES = [
|
|
15219
|
+
".pourkit/docs/adr",
|
|
15220
|
+
".pourkit/plans",
|
|
15221
|
+
".pourkit/handoffs"
|
|
15222
|
+
];
|
|
15223
|
+
var OVERRIDES_DIR = ".pourkit/overrides";
|
|
15224
|
+
var MANAGED_BLOCK_BEGIN3 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
|
|
15225
|
+
var MANAGED_BLOCK_END2 = "\n<!-- END POURKIT MANAGED BLOCK -->";
|
|
15226
|
+
function resolvePackagedManagedPath2(...segments) {
|
|
15227
|
+
const candidates = [resolve5(__dirname3, "..", "managed", ...segments)];
|
|
15228
|
+
return candidates[0];
|
|
15229
|
+
}
|
|
15230
|
+
function resolvePackagedManagedDocPath2(docName) {
|
|
15231
|
+
return resolvePackagedManagedPath2("docs", "agents", docName);
|
|
15232
|
+
}
|
|
15233
|
+
function resolvePackagedReleaseAddonDocPath2(docName) {
|
|
15234
|
+
return resolvePackagedManagedPath2(
|
|
15235
|
+
"addons",
|
|
15236
|
+
"release",
|
|
15237
|
+
"docs",
|
|
15238
|
+
"agents",
|
|
15239
|
+
docName
|
|
15240
|
+
);
|
|
15241
|
+
}
|
|
15242
|
+
function resolvePackagedManagedSkillDir(skillName) {
|
|
15243
|
+
return resolvePackagedManagedPath2("skills", skillName);
|
|
15244
|
+
}
|
|
15245
|
+
function resolvePackagedManagedPromptPath(promptName) {
|
|
15246
|
+
return resolvePackagedManagedPath2("prompts", promptName);
|
|
15247
|
+
}
|
|
15248
|
+
async function readPackagedTextFile2(filePath) {
|
|
15249
|
+
try {
|
|
15250
|
+
return await readFile7(filePath, "utf-8");
|
|
15251
|
+
} catch {
|
|
15252
|
+
return null;
|
|
15253
|
+
}
|
|
15254
|
+
}
|
|
15255
|
+
function isPathContained2(parent, child) {
|
|
15256
|
+
const relativePath = relative3(parent, child);
|
|
15257
|
+
return !relativePath.startsWith("..") && !relativePath.startsWith("../");
|
|
15258
|
+
}
|
|
15259
|
+
function isProjectOwnedPath(relativePath) {
|
|
15260
|
+
for (const owned of PROJECT_OWNED_PATHS) {
|
|
15261
|
+
if (relativePath === owned || relativePath.startsWith(owned + "/")) {
|
|
15262
|
+
return true;
|
|
15263
|
+
}
|
|
15264
|
+
}
|
|
15265
|
+
for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
|
|
15266
|
+
if (relativePath.startsWith(ownedDir + "/") || relativePath === ownedDir + "/") {
|
|
15267
|
+
return true;
|
|
15268
|
+
}
|
|
15269
|
+
}
|
|
15270
|
+
return false;
|
|
15271
|
+
}
|
|
15272
|
+
function getManagedRelativePath(overrideRelativePath) {
|
|
15273
|
+
if (!overrideRelativePath.startsWith(OVERRIDES_DIR + "/")) {
|
|
15274
|
+
return null;
|
|
15275
|
+
}
|
|
15276
|
+
const managedPath = overrideRelativePath.slice(OVERRIDES_DIR.length + 1);
|
|
15277
|
+
if (managedPath.startsWith("skills/") || managedPath.startsWith("docs/") || managedPath.startsWith("prompts/")) {
|
|
15278
|
+
return `.pourkit/managed/${managedPath}`;
|
|
15279
|
+
}
|
|
15280
|
+
return null;
|
|
15281
|
+
}
|
|
15282
|
+
function findOverrideForManagedPath(existingOverrides, targetRelativePath, overridePath) {
|
|
15283
|
+
if (existingOverrides.some(
|
|
15284
|
+
(o) => o === overridePath || o.startsWith(overridePath + "/")
|
|
15285
|
+
)) {
|
|
15286
|
+
return overridePath;
|
|
15287
|
+
}
|
|
15288
|
+
if (existingOverrides.some((o) => {
|
|
15289
|
+
const managedPath = getManagedRelativePath(o);
|
|
15290
|
+
return managedPath === targetRelativePath;
|
|
15291
|
+
})) {
|
|
15292
|
+
return overridePath;
|
|
15293
|
+
}
|
|
15294
|
+
return null;
|
|
15295
|
+
}
|
|
15296
|
+
function checkForPathEscape(cwd, resolvedPath) {
|
|
15297
|
+
const normalizedCwd = normalize2(cwd);
|
|
15298
|
+
const normalizedPath = normalize2(resolvedPath);
|
|
15299
|
+
if (!isPathContained2(normalizedCwd, normalizedPath)) {
|
|
15300
|
+
return `Path escape detected: ${resolvedPath} is outside ${cwd}`;
|
|
15301
|
+
}
|
|
15302
|
+
return null;
|
|
15303
|
+
}
|
|
15304
|
+
async function walkDir3(dir) {
|
|
15305
|
+
const files = [];
|
|
15306
|
+
try {
|
|
15307
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
15308
|
+
for (const entry of entries) {
|
|
15309
|
+
const full = resolve5(dir, entry.name);
|
|
15310
|
+
if (entry.isDirectory()) {
|
|
15311
|
+
files.push(...await walkDir3(full));
|
|
15312
|
+
} else {
|
|
15313
|
+
files.push(full);
|
|
15314
|
+
}
|
|
15315
|
+
}
|
|
15316
|
+
} catch {
|
|
15317
|
+
}
|
|
15318
|
+
return files;
|
|
15319
|
+
}
|
|
15320
|
+
function generateManagedBlockContent() {
|
|
15321
|
+
return [
|
|
15322
|
+
"This repository uses Pourkit.",
|
|
15323
|
+
"",
|
|
15324
|
+
"## Managed operating docs",
|
|
15325
|
+
"",
|
|
15326
|
+
"Follow the managed operating docs under `.pourkit/managed/docs/agents/*`:",
|
|
15327
|
+
"",
|
|
15328
|
+
"- `.pourkit/managed/docs/agents/issue-tracker.md`",
|
|
15329
|
+
"- `.pourkit/managed/docs/agents/triage-labels.md`",
|
|
15330
|
+
"- `.pourkit/managed/docs/agents/naming.md`",
|
|
15331
|
+
"- `.pourkit/managed/docs/agents/git-workflow.md`",
|
|
15332
|
+
"- `.pourkit/managed/docs/agents/commit-style.md`",
|
|
15333
|
+
"- `.pourkit/managed/docs/agents/domain.md`",
|
|
15334
|
+
"",
|
|
15335
|
+
"### Project-owned context",
|
|
15336
|
+
"",
|
|
15337
|
+
"- `.pourkit/CONTEXT.md`",
|
|
15338
|
+
"- `.pourkit/CONTEXT-MAP.md`",
|
|
15339
|
+
"- `.pourkit/docs/adr/*`",
|
|
15340
|
+
"- `.pourkit/plans/*`",
|
|
15341
|
+
"- `.pourkit/handoffs/*`",
|
|
15342
|
+
"",
|
|
15343
|
+
"### Important",
|
|
15344
|
+
"",
|
|
15345
|
+
"- Do not edit `.pourkit/managed/*` unless explicitly updating Pourkit-managed assets.",
|
|
15346
|
+
"- Do not edit generated harness projections directly.",
|
|
15347
|
+
""
|
|
15348
|
+
].join("\n");
|
|
15349
|
+
}
|
|
15350
|
+
async function syncFile(cwd, targetRelativePath, sourceContent, errors) {
|
|
15351
|
+
if (sourceContent === null) {
|
|
15352
|
+
return false;
|
|
15353
|
+
}
|
|
15354
|
+
const targetPath = resolve5(cwd, targetRelativePath);
|
|
15355
|
+
const escapeError = checkForPathEscape(cwd, targetPath);
|
|
15356
|
+
if (escapeError) {
|
|
15357
|
+
errors.push(escapeError);
|
|
15358
|
+
return false;
|
|
15359
|
+
}
|
|
15360
|
+
await mkdir7(resolve5(targetPath, ".."), { recursive: true });
|
|
15361
|
+
if (existsSync20(targetPath)) {
|
|
15362
|
+
const existing = await readFile7(targetPath, "utf-8");
|
|
15363
|
+
if (existing === sourceContent) {
|
|
15364
|
+
return false;
|
|
15365
|
+
}
|
|
15366
|
+
}
|
|
15367
|
+
await writeFile4(targetPath, sourceContent, "utf-8");
|
|
15368
|
+
return true;
|
|
15369
|
+
}
|
|
15370
|
+
function walkDirSync(dir) {
|
|
15371
|
+
const result = [];
|
|
15372
|
+
try {
|
|
15373
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
15374
|
+
for (const entry of entries) {
|
|
15375
|
+
const full = resolve5(dir, entry.name);
|
|
15376
|
+
if (entry.isDirectory()) {
|
|
15377
|
+
result.push(...walkDirSync(full));
|
|
15378
|
+
} else {
|
|
15379
|
+
result.push(full);
|
|
15380
|
+
}
|
|
15381
|
+
}
|
|
15382
|
+
} catch {
|
|
15383
|
+
}
|
|
15384
|
+
return result;
|
|
15385
|
+
}
|
|
15386
|
+
async function detectOverrides(cwd) {
|
|
15387
|
+
const overridesDir = resolve5(cwd, OVERRIDES_DIR);
|
|
15388
|
+
if (!existsSync20(overridesDir)) {
|
|
15389
|
+
return [];
|
|
15390
|
+
}
|
|
15391
|
+
const files = await walkDir3(overridesDir);
|
|
15392
|
+
return files.map((f) => relative3(cwd, f));
|
|
15393
|
+
}
|
|
15394
|
+
async function detectProjectOwnedFiles(cwd) {
|
|
15395
|
+
const found = [];
|
|
15396
|
+
for (const ownedPath of PROJECT_OWNED_PATHS) {
|
|
15397
|
+
const fullPath = resolve5(cwd, ownedPath);
|
|
15398
|
+
if (existsSync20(fullPath)) {
|
|
15399
|
+
found.push(ownedPath);
|
|
15400
|
+
}
|
|
15401
|
+
}
|
|
15402
|
+
for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
|
|
15403
|
+
const fullDir = resolve5(cwd, ownedDir);
|
|
15404
|
+
if (existsSync20(fullDir)) {
|
|
15405
|
+
const files = await walkDir3(fullDir);
|
|
15406
|
+
for (const file of files) {
|
|
15407
|
+
found.push(relative3(cwd, file));
|
|
15408
|
+
}
|
|
15409
|
+
}
|
|
15410
|
+
}
|
|
15411
|
+
return found;
|
|
15412
|
+
}
|
|
15413
|
+
async function isReleaseWorkflowEnabled(cwd) {
|
|
15414
|
+
try {
|
|
15415
|
+
const configPath = resolve5(cwd, ".pourkit", "config.json");
|
|
15416
|
+
const content = await readFile7(configPath, "utf-8");
|
|
15417
|
+
const parsed = JSON.parse(content);
|
|
15418
|
+
return parsed.releaseWorkflow?.enabled === true;
|
|
15419
|
+
} catch {
|
|
15420
|
+
return false;
|
|
15421
|
+
}
|
|
15422
|
+
}
|
|
15423
|
+
async function runWorkflowPackSyncCommand(options) {
|
|
15424
|
+
const cwd = options.cwd ?? process.cwd();
|
|
15425
|
+
const catalog = getWorkflowPackCatalog();
|
|
15426
|
+
const updated = [];
|
|
15427
|
+
const regeneratedProjections = [];
|
|
15428
|
+
const skippedProjectOwned = [];
|
|
15429
|
+
const overrides = [];
|
|
15430
|
+
const errors = [];
|
|
15431
|
+
const existingOverrides = await detectOverrides(cwd);
|
|
15432
|
+
const existingProjectOwned = await detectProjectOwnedFiles(cwd);
|
|
15433
|
+
for (const docName of catalog.docs) {
|
|
15434
|
+
const targetRelativePath = `.pourkit/managed/docs/agents/${docName}`;
|
|
15435
|
+
if (isProjectOwnedPath(targetRelativePath)) {
|
|
15436
|
+
skippedProjectOwned.push(targetRelativePath);
|
|
15437
|
+
continue;
|
|
15438
|
+
}
|
|
15439
|
+
const overridePath = `.pourkit/overrides/docs/agents/${docName}`;
|
|
15440
|
+
if (findOverrideForManagedPath(
|
|
15441
|
+
existingOverrides,
|
|
15442
|
+
targetRelativePath,
|
|
15443
|
+
overridePath
|
|
15444
|
+
)) {
|
|
15445
|
+
overrides.push(overridePath);
|
|
15446
|
+
continue;
|
|
15447
|
+
}
|
|
15448
|
+
const sourcePath = resolvePackagedManagedDocPath2(docName);
|
|
15449
|
+
const sourceContent = await readPackagedTextFile2(sourcePath);
|
|
15450
|
+
if (sourceContent === null) {
|
|
15451
|
+
errors.push(`Missing packaged managed doc: ${docName}`);
|
|
15452
|
+
continue;
|
|
15453
|
+
}
|
|
15454
|
+
const written = await syncFile(
|
|
15455
|
+
cwd,
|
|
15456
|
+
targetRelativePath,
|
|
15457
|
+
sourceContent,
|
|
15458
|
+
errors
|
|
15459
|
+
);
|
|
15460
|
+
if (written) {
|
|
15461
|
+
updated.push(targetRelativePath);
|
|
15462
|
+
}
|
|
15463
|
+
}
|
|
15464
|
+
const baselineSkills = getBaselineManagedSkillNames();
|
|
15465
|
+
const syncAcc = {
|
|
15466
|
+
updated,
|
|
15467
|
+
regeneratedProjections,
|
|
15468
|
+
skippedProjectOwned,
|
|
15469
|
+
overrides,
|
|
15470
|
+
errors
|
|
15471
|
+
};
|
|
15472
|
+
const syncCtx = { cwd, existingOverrides };
|
|
15473
|
+
for (const skillName of baselineSkills) {
|
|
15474
|
+
await syncSkill(skillName, catalog, syncAcc, syncCtx);
|
|
15475
|
+
}
|
|
15476
|
+
const releaseEnabled = await isReleaseWorkflowEnabled(cwd);
|
|
15477
|
+
if (releaseEnabled) {
|
|
15478
|
+
for (const skillName of catalog.releaseAddonSkills) {
|
|
15479
|
+
await syncAddonSkill(skillName, syncAcc, syncCtx);
|
|
15480
|
+
}
|
|
15481
|
+
}
|
|
15482
|
+
if (releaseEnabled) {
|
|
15483
|
+
for (const docName of catalog.releaseAddonDocs) {
|
|
15484
|
+
const targetRelativePath = `.pourkit/managed/addons/release/docs/agents/${docName}`;
|
|
15485
|
+
const overridePath = `.pourkit/overrides/addons/release/docs/agents/${docName}`;
|
|
15486
|
+
if (findOverrideForManagedPath(
|
|
15487
|
+
existingOverrides,
|
|
15488
|
+
targetRelativePath,
|
|
15489
|
+
overridePath
|
|
15490
|
+
)) {
|
|
15491
|
+
overrides.push(overridePath);
|
|
15492
|
+
continue;
|
|
15493
|
+
}
|
|
15494
|
+
const sourcePath = resolvePackagedReleaseAddonDocPath2(docName);
|
|
15495
|
+
const sourceContent = await readPackagedTextFile2(sourcePath);
|
|
15496
|
+
if (sourceContent === null) {
|
|
15497
|
+
errors.push(`Missing packaged release addon doc: ${docName}`);
|
|
15498
|
+
continue;
|
|
15499
|
+
}
|
|
15500
|
+
const written = await syncFile(
|
|
15501
|
+
cwd,
|
|
15502
|
+
targetRelativePath,
|
|
15503
|
+
sourceContent,
|
|
15504
|
+
errors
|
|
15505
|
+
);
|
|
15506
|
+
if (written) {
|
|
15507
|
+
updated.push(targetRelativePath);
|
|
15508
|
+
}
|
|
15509
|
+
}
|
|
15510
|
+
}
|
|
15511
|
+
for (const promptName of catalog.prompts) {
|
|
15512
|
+
const targetRelativePath = `.pourkit/managed/prompts/${promptName}`;
|
|
15513
|
+
if (isProjectOwnedPath(targetRelativePath)) {
|
|
15514
|
+
skippedProjectOwned.push(targetRelativePath);
|
|
15515
|
+
continue;
|
|
15516
|
+
}
|
|
15517
|
+
const overridePath = `.pourkit/overrides/prompts/${promptName}`;
|
|
15518
|
+
if (findOverrideForManagedPath(
|
|
15519
|
+
existingOverrides,
|
|
15520
|
+
targetRelativePath,
|
|
15521
|
+
overridePath
|
|
15522
|
+
)) {
|
|
15523
|
+
overrides.push(overridePath);
|
|
15524
|
+
continue;
|
|
15525
|
+
}
|
|
15526
|
+
const sourcePath = resolvePackagedManagedPromptPath(promptName);
|
|
15527
|
+
const sourceContent = await readPackagedTextFile2(sourcePath);
|
|
15528
|
+
if (sourceContent === null) {
|
|
15529
|
+
errors.push(`Missing packaged managed prompt: ${promptName}`);
|
|
15530
|
+
continue;
|
|
15531
|
+
}
|
|
15532
|
+
const written = await syncFile(
|
|
15533
|
+
cwd,
|
|
15534
|
+
targetRelativePath,
|
|
15535
|
+
sourceContent,
|
|
15536
|
+
errors
|
|
15537
|
+
);
|
|
15538
|
+
if (written) {
|
|
15539
|
+
updated.push(targetRelativePath);
|
|
15540
|
+
}
|
|
15541
|
+
}
|
|
15542
|
+
const schemaResult = await runConfigSyncSchemaCommand({ cwd });
|
|
15543
|
+
const agentsPath = resolve5(cwd, "AGENTS.md");
|
|
15544
|
+
const managedBlockContent = generateManagedBlockContent();
|
|
15545
|
+
const fullManagedBlock = `${MANAGED_BLOCK_BEGIN3}${managedBlockContent}${MANAGED_BLOCK_END2}`;
|
|
15546
|
+
let agentsUpdated = false;
|
|
15547
|
+
if (existsSync20(agentsPath)) {
|
|
15548
|
+
const existing = await readFile7(agentsPath, "utf-8");
|
|
15549
|
+
const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN3);
|
|
15550
|
+
const endIdx = existing.indexOf(MANAGED_BLOCK_END2);
|
|
15551
|
+
if (beginIdx !== -1 && endIdx !== -1) {
|
|
15552
|
+
const beforeBlock = existing.slice(0, beginIdx);
|
|
15553
|
+
const afterBlock = existing.slice(endIdx + MANAGED_BLOCK_END2.length);
|
|
15554
|
+
const newContent = `${beforeBlock}${fullManagedBlock}${afterBlock}`;
|
|
15555
|
+
if (newContent !== existing) {
|
|
15556
|
+
await writeFile4(agentsPath, newContent, "utf-8");
|
|
15557
|
+
agentsUpdated = true;
|
|
15558
|
+
}
|
|
15559
|
+
} else {
|
|
15560
|
+
const newContent = `${existing}
|
|
15561
|
+
|
|
15562
|
+
${fullManagedBlock}
|
|
15563
|
+
`;
|
|
15564
|
+
if (newContent !== existing) {
|
|
15565
|
+
await writeFile4(agentsPath, newContent, "utf-8");
|
|
15566
|
+
agentsUpdated = true;
|
|
15567
|
+
}
|
|
15568
|
+
}
|
|
15569
|
+
} else {
|
|
15570
|
+
await writeFile4(agentsPath, fullManagedBlock + "\n", "utf-8");
|
|
15571
|
+
agentsUpdated = true;
|
|
15572
|
+
}
|
|
15573
|
+
if (agentsUpdated) {
|
|
15574
|
+
updated.push("AGENTS.md");
|
|
15575
|
+
}
|
|
15576
|
+
const enabledAddons = releaseEnabled ? ["release"] : [];
|
|
15577
|
+
const manifestMeta = buildWorkflowPackMetadata(enabledAddons);
|
|
15578
|
+
const manifestPath = resolve5(cwd, ".pourkit", "manifest.json");
|
|
15579
|
+
let manifestWritten = false;
|
|
15580
|
+
let previousManifestWorkflowPack = void 0;
|
|
15581
|
+
try {
|
|
15582
|
+
const existingRaw = await readFile7(manifestPath, "utf-8").catch(() => null);
|
|
15583
|
+
if (existingRaw) {
|
|
15584
|
+
const existing = JSON.parse(existingRaw);
|
|
15585
|
+
previousManifestWorkflowPack = existing.workflowPack;
|
|
15586
|
+
}
|
|
15587
|
+
} catch {
|
|
15588
|
+
}
|
|
15589
|
+
if (previousManifestWorkflowPack === void 0 || JSON.stringify(previousManifestWorkflowPack) !== JSON.stringify(manifestMeta)) {
|
|
15590
|
+
try {
|
|
15591
|
+
const existingRaw = await readFile7(manifestPath, "utf-8").catch(
|
|
15592
|
+
() => null
|
|
15593
|
+
);
|
|
15594
|
+
let manifest = existingRaw ? JSON.parse(existingRaw) : {};
|
|
15595
|
+
manifest.workflowPack = manifestMeta;
|
|
15596
|
+
await mkdir7(resolve5(manifestPath, ".."), { recursive: true });
|
|
15597
|
+
await writeFile4(
|
|
15598
|
+
manifestPath,
|
|
15599
|
+
JSON.stringify(manifest, null, 2) + "\n",
|
|
15600
|
+
"utf-8"
|
|
15601
|
+
);
|
|
15602
|
+
manifestWritten = true;
|
|
15603
|
+
} catch {
|
|
15604
|
+
errors.push("Failed to write manifest metadata");
|
|
15605
|
+
}
|
|
15606
|
+
}
|
|
15607
|
+
for (const owned of existingProjectOwned) {
|
|
15608
|
+
if (!skippedProjectOwned.includes(owned)) {
|
|
15609
|
+
skippedProjectOwned.push(owned);
|
|
15610
|
+
}
|
|
15611
|
+
}
|
|
15612
|
+
for (const overridePath of existingOverrides) {
|
|
15613
|
+
const displayPath = overridePath;
|
|
15614
|
+
if (!overrides.includes(displayPath)) {
|
|
15615
|
+
overrides.push(displayPath);
|
|
15616
|
+
}
|
|
15617
|
+
}
|
|
15618
|
+
const changed = updated.length > 0 || regeneratedProjections.length > 0 || schemaResult.changed || agentsUpdated || manifestWritten;
|
|
15619
|
+
return {
|
|
15620
|
+
changed,
|
|
15621
|
+
updated,
|
|
15622
|
+
regeneratedProjections,
|
|
15623
|
+
skippedProjectOwned,
|
|
15624
|
+
overrides,
|
|
15625
|
+
errors,
|
|
15626
|
+
schema: schemaResult,
|
|
15627
|
+
manifestWritten
|
|
15628
|
+
};
|
|
15629
|
+
}
|
|
15630
|
+
async function syncSkill(skillName, catalog, acc, ctx) {
|
|
15631
|
+
const { cwd, existingOverrides } = ctx;
|
|
15632
|
+
const {
|
|
15633
|
+
updated,
|
|
15634
|
+
regeneratedProjections,
|
|
15635
|
+
skippedProjectOwned,
|
|
15636
|
+
overrides,
|
|
15637
|
+
errors
|
|
15638
|
+
} = acc;
|
|
15639
|
+
const skillDir = resolvePackagedManagedSkillDir(skillName);
|
|
15640
|
+
const skillFiles = walkDirSync(skillDir);
|
|
15641
|
+
if (skillFiles.length === 0) {
|
|
15642
|
+
errors.push(`Missing packaged managed skill: ${skillName}`);
|
|
15643
|
+
return;
|
|
15644
|
+
}
|
|
15645
|
+
for (const sourceFile of skillFiles) {
|
|
15646
|
+
const relPath = relative3(skillDir, sourceFile);
|
|
15647
|
+
const targetRelativePath = `.pourkit/managed/skills/${skillName}/${relPath}`;
|
|
15648
|
+
if (isProjectOwnedPath(targetRelativePath)) {
|
|
15649
|
+
skippedProjectOwned.push(targetRelativePath);
|
|
15650
|
+
continue;
|
|
15651
|
+
}
|
|
15652
|
+
const overridePath = `.pourkit/overrides/skills/${skillName}/${relPath}`;
|
|
15653
|
+
if (findOverrideForManagedPath(
|
|
15654
|
+
existingOverrides,
|
|
15655
|
+
targetRelativePath,
|
|
15656
|
+
overridePath
|
|
15657
|
+
)) {
|
|
15658
|
+
if (!overrides.includes(overridePath)) {
|
|
15659
|
+
overrides.push(overridePath);
|
|
15660
|
+
}
|
|
15661
|
+
continue;
|
|
15662
|
+
}
|
|
15663
|
+
const sourceContent = await readPackagedTextFile2(sourceFile);
|
|
15664
|
+
if (sourceContent === null) {
|
|
15665
|
+
errors.push(`Cannot read packaged skill file: ${skillName}/${relPath}`);
|
|
15666
|
+
continue;
|
|
15667
|
+
}
|
|
15668
|
+
const written = await syncFile(
|
|
15669
|
+
cwd,
|
|
15670
|
+
targetRelativePath,
|
|
15671
|
+
sourceContent,
|
|
15672
|
+
errors
|
|
15673
|
+
);
|
|
15674
|
+
if (written) {
|
|
15675
|
+
updated.push(targetRelativePath);
|
|
15676
|
+
}
|
|
15677
|
+
const projectionRelativePath = `.agents/skills/${skillName}/${relPath}`;
|
|
15678
|
+
const projectionOverridePath = `.pourkit/overrides/${projectionRelativePath}`;
|
|
15679
|
+
if (existingOverrides.some((o) => o === projectionOverridePath)) {
|
|
15680
|
+
if (!overrides.includes(projectionOverridePath)) {
|
|
15681
|
+
overrides.push(projectionOverridePath);
|
|
15682
|
+
}
|
|
15683
|
+
continue;
|
|
15684
|
+
}
|
|
15685
|
+
const managedSourcePath = `.pourkit/managed/skills/${skillName}/${relPath}`;
|
|
15686
|
+
const projectionContent = buildOpenCodeSkillProjectionContent(
|
|
15687
|
+
managedSourcePath,
|
|
15688
|
+
sourceContent
|
|
15689
|
+
);
|
|
15690
|
+
const projectionWritten = await syncFile(
|
|
15691
|
+
cwd,
|
|
15692
|
+
projectionRelativePath,
|
|
15693
|
+
projectionContent,
|
|
15694
|
+
errors
|
|
15695
|
+
);
|
|
15696
|
+
if (projectionWritten) {
|
|
15697
|
+
regeneratedProjections.push(projectionRelativePath);
|
|
15698
|
+
}
|
|
15699
|
+
}
|
|
15700
|
+
}
|
|
15701
|
+
async function syncAddonSkill(skillName, acc, ctx) {
|
|
15702
|
+
const { cwd, existingOverrides } = ctx;
|
|
15703
|
+
const {
|
|
15704
|
+
updated,
|
|
15705
|
+
regeneratedProjections,
|
|
15706
|
+
skippedProjectOwned,
|
|
15707
|
+
overrides,
|
|
15708
|
+
errors
|
|
15709
|
+
} = acc;
|
|
15710
|
+
const addonSkillDir = resolvePackagedManagedPath2(
|
|
15711
|
+
"addons",
|
|
15712
|
+
"release",
|
|
15713
|
+
"skills",
|
|
15714
|
+
skillName
|
|
15715
|
+
);
|
|
15716
|
+
const skillFiles = walkDirSync(addonSkillDir);
|
|
15717
|
+
if (skillFiles.length === 0) {
|
|
15718
|
+
errors.push(`Missing packaged release addon skill: ${skillName}`);
|
|
15719
|
+
return;
|
|
15720
|
+
}
|
|
15721
|
+
for (const sourceFile of skillFiles) {
|
|
15722
|
+
const relPath = relative3(addonSkillDir, sourceFile);
|
|
15723
|
+
const targetRelativePath = `.pourkit/managed/addons/release/skills/${skillName}/${relPath}`;
|
|
15724
|
+
if (isProjectOwnedPath(targetRelativePath)) {
|
|
15725
|
+
skippedProjectOwned.push(targetRelativePath);
|
|
15726
|
+
continue;
|
|
15727
|
+
}
|
|
15728
|
+
const overridePath = `.pourkit/overrides/addons/release/skills/${skillName}/${relPath}`;
|
|
15729
|
+
if (findOverrideForManagedPath(
|
|
15730
|
+
existingOverrides,
|
|
15731
|
+
targetRelativePath,
|
|
15732
|
+
overridePath
|
|
15733
|
+
)) {
|
|
15734
|
+
if (!overrides.includes(overridePath)) {
|
|
15735
|
+
overrides.push(overridePath);
|
|
15736
|
+
}
|
|
15737
|
+
continue;
|
|
15738
|
+
}
|
|
15739
|
+
const sourceContent = await readPackagedTextFile2(sourceFile);
|
|
15740
|
+
if (sourceContent === null) {
|
|
15741
|
+
errors.push(
|
|
15742
|
+
`Cannot read packaged addon skill file: ${skillName}/${relPath}`
|
|
15743
|
+
);
|
|
15744
|
+
continue;
|
|
15745
|
+
}
|
|
15746
|
+
const written = await syncFile(
|
|
15747
|
+
cwd,
|
|
15748
|
+
targetRelativePath,
|
|
15749
|
+
sourceContent,
|
|
15750
|
+
errors
|
|
15751
|
+
);
|
|
15752
|
+
if (written) {
|
|
15753
|
+
updated.push(targetRelativePath);
|
|
15754
|
+
}
|
|
15755
|
+
const projectionRelativePath = `.agents/skills/${skillName}/${relPath}`;
|
|
15756
|
+
const projectionOverridePath = `.pourkit/overrides/${projectionRelativePath}`;
|
|
15757
|
+
if (existingOverrides.some((o) => o === projectionOverridePath)) {
|
|
15758
|
+
if (!overrides.includes(projectionOverridePath)) {
|
|
15759
|
+
overrides.push(projectionOverridePath);
|
|
15760
|
+
}
|
|
15761
|
+
continue;
|
|
15762
|
+
}
|
|
15763
|
+
const managedSourcePath = `.pourkit/managed/addons/release/skills/${skillName}/${relPath}`;
|
|
15764
|
+
const projectionContent = buildOpenCodeSkillProjectionContent(
|
|
15765
|
+
managedSourcePath,
|
|
15766
|
+
sourceContent
|
|
15767
|
+
);
|
|
15768
|
+
const projectionWritten = await syncFile(
|
|
15769
|
+
cwd,
|
|
15770
|
+
projectionRelativePath,
|
|
15771
|
+
projectionContent,
|
|
15772
|
+
errors
|
|
15773
|
+
);
|
|
15774
|
+
if (projectionWritten) {
|
|
15775
|
+
regeneratedProjections.push(projectionRelativePath);
|
|
15776
|
+
}
|
|
15777
|
+
}
|
|
15778
|
+
}
|
|
15779
|
+
|
|
14154
15780
|
// providers/github-provider.ts
|
|
14155
15781
|
var GitHubIssueProvider = class {
|
|
14156
15782
|
client;
|
|
@@ -14688,7 +16314,7 @@ function formatChecks2(checks) {
|
|
|
14688
16314
|
init_common();
|
|
14689
16315
|
|
|
14690
16316
|
// execution/sandcastle-execution.ts
|
|
14691
|
-
import { existsSync as
|
|
16317
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
14692
16318
|
import { join as join23 } from "path";
|
|
14693
16319
|
import { createWorktree, opencode } from "@ai-hero/sandcastle";
|
|
14694
16320
|
import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
|
|
@@ -14696,14 +16322,14 @@ import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
|
|
|
14696
16322
|
// execution/execution-provider.ts
|
|
14697
16323
|
init_common();
|
|
14698
16324
|
import { mkdtempSync } from "fs";
|
|
14699
|
-
import { writeFile as
|
|
16325
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
14700
16326
|
import { tmpdir } from "os";
|
|
14701
|
-
import { dirname as
|
|
16327
|
+
import { dirname as dirname7, join as join22 } from "path";
|
|
14702
16328
|
async function writeExecutionArtifacts(worktreePath, artifacts) {
|
|
14703
16329
|
for (const artifact of artifacts) {
|
|
14704
16330
|
const filePath = join22(worktreePath, artifact.path);
|
|
14705
|
-
await ensureDir(
|
|
14706
|
-
await
|
|
16331
|
+
await ensureDir(dirname7(filePath));
|
|
16332
|
+
await writeFile5(filePath, artifact.content, "utf-8");
|
|
14707
16333
|
}
|
|
14708
16334
|
}
|
|
14709
16335
|
|
|
@@ -14713,14 +16339,14 @@ import path7 from "path";
|
|
|
14713
16339
|
|
|
14714
16340
|
// execution/sandbox-image.ts
|
|
14715
16341
|
import { createHash as createHash3 } from "crypto";
|
|
14716
|
-
import { existsSync as
|
|
16342
|
+
import { existsSync as existsSync21, readFileSync as readFileSync21 } from "fs";
|
|
14717
16343
|
import path6 from "path";
|
|
14718
16344
|
function sandboxImageName(repoRoot2) {
|
|
14719
16345
|
const dirName = path6.basename(repoRoot2.replace(/[\\/]+$/, "")) || "local";
|
|
14720
16346
|
const sanitized = dirName.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
|
|
14721
16347
|
const baseName = sanitized || "local";
|
|
14722
16348
|
const dockerfilePath = path6.join(repoRoot2, ".sandcastle", "Dockerfile");
|
|
14723
|
-
if (!
|
|
16349
|
+
if (!existsSync21(dockerfilePath)) {
|
|
14724
16350
|
return `sandcastle:${baseName}`;
|
|
14725
16351
|
}
|
|
14726
16352
|
const fingerprint = createHash3("sha256").update(readFileSync21(dockerfilePath)).digest("hex").slice(0, 8);
|
|
@@ -14970,7 +16596,7 @@ function sanitizeBranch(branchName) {
|
|
|
14970
16596
|
function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
|
|
14971
16597
|
return paths.filter((relativePath) => {
|
|
14972
16598
|
const source = join23(repoRoot2, relativePath);
|
|
14973
|
-
if (!
|
|
16599
|
+
if (!existsSync22(source)) {
|
|
14974
16600
|
return true;
|
|
14975
16601
|
}
|
|
14976
16602
|
try {
|
|
@@ -14981,7 +16607,7 @@ function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
|
|
|
14981
16607
|
return true;
|
|
14982
16608
|
}
|
|
14983
16609
|
const destination = join23(worktreePath, relativePath);
|
|
14984
|
-
return !
|
|
16610
|
+
return !existsSync22(destination);
|
|
14985
16611
|
});
|
|
14986
16612
|
}
|
|
14987
16613
|
function formatAgentStreamEvent(event) {
|
|
@@ -15201,6 +16827,9 @@ function createCliProgram(version) {
|
|
|
15201
16827
|
).option(
|
|
15202
16828
|
"--branch-name <name>",
|
|
15203
16829
|
"branch name for issue-final-review artifacts"
|
|
16830
|
+
).option(
|
|
16831
|
+
"--base-ref <ref>",
|
|
16832
|
+
"canonical base ref for issue-final-review changedFiles coverage validation"
|
|
15204
16833
|
).option("--no-check-conflict-markers", "skip conflict marker scan").option("--cwd <path>", "target repository directory").action(
|
|
15205
16834
|
(kind, artifactPath, extraPaths, options) => {
|
|
15206
16835
|
const allowedKinds = /* @__PURE__ */ new Set([
|
|
@@ -15243,6 +16872,7 @@ function createCliProgram(version) {
|
|
|
15243
16872
|
allowedDecisions: options.allowedDecision,
|
|
15244
16873
|
issueNumber: options.issueNumber,
|
|
15245
16874
|
branchName: options.branchName,
|
|
16875
|
+
baseRef: options.baseRef,
|
|
15246
16876
|
checkConflictMarkers: options.checkConflictMarkers
|
|
15247
16877
|
});
|
|
15248
16878
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -15603,7 +17233,7 @@ function createCliProgram(version) {
|
|
|
15603
17233
|
const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
|
|
15604
17234
|
const report = await runDoctorCommand({ cwd: targetRepoRoot });
|
|
15605
17235
|
console.log(JSON.stringify(report, null, 2));
|
|
15606
|
-
if (!report.configValidation.ok || report.obsoleteConfigs.length > 0 || report.schemaAssets.overall !== "fresh") {
|
|
17236
|
+
if (!report.configValidation.ok || report.obsoleteConfigs.length > 0 || report.schemaAssets.overall !== "fresh" || report.workflowPack.status === "failed") {
|
|
15607
17237
|
process.exitCode = 1;
|
|
15608
17238
|
}
|
|
15609
17239
|
});
|
|
@@ -15619,6 +17249,24 @@ function createCliProgram(version) {
|
|
|
15619
17249
|
console.log("Schema assets are up to date.");
|
|
15620
17250
|
}
|
|
15621
17251
|
});
|
|
17252
|
+
const syncCommand = program.command("sync").description("Sync commands for refreshing managed assets");
|
|
17253
|
+
syncCommand.command("workflow-pack").description("Refresh managed workflow pack assets from packaged sources").option("--cwd <path>", "target repository directory").action(async (options) => {
|
|
17254
|
+
const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
|
|
17255
|
+
const result = await runWorkflowPackSyncCommand({ cwd: targetRepoRoot });
|
|
17256
|
+
if (result.changed) {
|
|
17257
|
+
console.log(
|
|
17258
|
+
`Workflow pack sync complete: ${result.updated.length} updated, ${result.regeneratedProjections.length} projections regenerated, ${result.overrides.length} overrides, ${result.skippedProjectOwned.length} project-owned files skipped.`
|
|
17259
|
+
);
|
|
17260
|
+
} else {
|
|
17261
|
+
console.log("Workflow pack is up to date.");
|
|
17262
|
+
}
|
|
17263
|
+
if (result.errors.length > 0) {
|
|
17264
|
+
for (const err of result.errors) {
|
|
17265
|
+
console.error(` Error: ${err}`);
|
|
17266
|
+
}
|
|
17267
|
+
process.exitCode = 1;
|
|
17268
|
+
}
|
|
17269
|
+
});
|
|
15622
17270
|
const serena = program.command("serena").description("Serena baseline and sidecar commands");
|
|
15623
17271
|
serena.command("init").requiredOption("--target <name>", "target name").option("--cwd <path>", "target repository directory").action(async (options) => {
|
|
15624
17272
|
await runSerenaInitCommand({
|
|
@@ -15744,11 +17392,11 @@ function createCliProgram(version) {
|
|
|
15744
17392
|
return program;
|
|
15745
17393
|
}
|
|
15746
17394
|
async function resolveCliVersion() {
|
|
15747
|
-
if (isPackageVersion("0.0.0-next-
|
|
15748
|
-
return "0.0.0-next-
|
|
17395
|
+
if (isPackageVersion("0.0.0-next-20260617183635")) {
|
|
17396
|
+
return "0.0.0-next-20260617183635";
|
|
15749
17397
|
}
|
|
15750
|
-
if (isReleaseVersion("0.0.0-next-
|
|
15751
|
-
return "0.0.0-next-
|
|
17398
|
+
if (isReleaseVersion("0.0.0-next-20260617183635")) {
|
|
17399
|
+
return "0.0.0-next-20260617183635";
|
|
15752
17400
|
}
|
|
15753
17401
|
try {
|
|
15754
17402
|
const root = repoRoot();
|