@pourkit/cli 0.0.0-next-20260615184943 → 0.0.0-next-20260617195445

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.
Files changed (62) hide show
  1. package/dist/cli.js +1873 -231
  2. package/dist/cli.js.map +1 -1
  3. package/dist/e2e/run-live-e2e.js +112 -20
  4. package/dist/e2e/run-live-e2e.js.map +1 -1
  5. package/dist/managed/addons/release/docs/agents/release-workflow.md +33 -0
  6. package/dist/managed/addons/release/skills/changeset/SKILL.md +76 -0
  7. package/dist/managed/addons/release/skills/promote-release/SKILL.md +94 -0
  8. package/dist/managed/docs/agents/commit-style.md +75 -0
  9. package/dist/managed/docs/agents/domain.md +57 -0
  10. package/dist/managed/docs/agents/git-workflow.md +197 -0
  11. package/dist/managed/docs/agents/issue-tracker.md +33 -0
  12. package/dist/managed/docs/agents/naming.md +58 -0
  13. package/dist/managed/docs/agents/triage-labels.md +28 -0
  14. package/dist/managed/prompts/builder.prompt.md +89 -0
  15. package/dist/managed/prompts/conflict-resolution.prompt.md +70 -0
  16. package/dist/managed/prompts/failure-resolution.prompt.md +68 -0
  17. package/dist/managed/prompts/finalizer.prompt.md +77 -0
  18. package/dist/managed/prompts/issue-final-review.prompt.md +122 -0
  19. package/dist/managed/prompts/pr-description.prompt.md +77 -0
  20. package/dist/managed/prompts/refactor.prompt.md +114 -0
  21. package/dist/managed/prompts/reviewer-correctness.snippet.md +5 -0
  22. package/dist/managed/prompts/reviewer-quality.snippet.md +3 -0
  23. package/dist/managed/prompts/reviewer-scope.snippet.md +5 -0
  24. package/dist/managed/prompts/reviewer-tests.snippet.md +5 -0
  25. package/dist/managed/prompts/reviewer.prompt.md +169 -0
  26. package/dist/managed/skills/code-review/SKILL.md +152 -0
  27. package/dist/managed/skills/code-review/references/thermo-nuclear-code-quality-review.md +147 -0
  28. package/dist/managed/skills/diagnose/SKILL.md +119 -0
  29. package/dist/managed/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
  30. package/dist/managed/skills/explain/EXAMPLES.md +227 -0
  31. package/dist/managed/skills/explain/SKILL.md +106 -0
  32. package/dist/managed/skills/explain/references/mermaid.md +136 -0
  33. package/dist/managed/skills/grill-with-docs/ADR-FORMAT.md +47 -0
  34. package/dist/managed/skills/grill-with-docs/CONTEXT-FORMAT.md +77 -0
  35. package/dist/managed/skills/grill-with-docs/SKILL.md +88 -0
  36. package/dist/managed/skills/handoff/SKILL.md +13 -0
  37. package/dist/managed/skills/improve-codebase-architecture/DEEPENING.md +37 -0
  38. package/dist/managed/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +44 -0
  39. package/dist/managed/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
  40. package/dist/managed/skills/improve-codebase-architecture/SKILL.md +71 -0
  41. package/dist/managed/skills/publish-prd/SKILL.md +130 -0
  42. package/dist/managed/skills/secret-commit-guard/SKILL.md +54 -0
  43. package/dist/managed/skills/security-review/SKILL.md +495 -0
  44. package/dist/managed/skills/security-review/cloud-infrastructure-security.md +361 -0
  45. package/dist/managed/skills/ship-current-changes/SKILL.md +199 -0
  46. package/dist/managed/skills/tdd/SKILL.md +110 -0
  47. package/dist/managed/skills/tdd/deep-modules.md +33 -0
  48. package/dist/managed/skills/tdd/interface-design.md +31 -0
  49. package/dist/managed/skills/tdd/mocking.md +59 -0
  50. package/dist/managed/skills/tdd/refactoring.md +10 -0
  51. package/dist/managed/skills/tdd/tests.md +61 -0
  52. package/dist/managed/skills/to-issues/SKILL.md +442 -0
  53. package/dist/managed/skills/to-plan/SKILL.md +20 -0
  54. package/dist/managed/skills/to-prd/SKILL.md +129 -0
  55. package/dist/managed/skills/triage/AGENT-BRIEF.md +168 -0
  56. package/dist/managed/skills/triage/OUT-OF-SCOPE.md +101 -0
  57. package/dist/managed/skills/triage/SKILL.md +162 -0
  58. package/dist/managed/skills/write-a-skill/SKILL.md +117 -0
  59. package/dist/managed/skills/zoom-out/SKILL.md +7 -0
  60. package/dist/schema/pourkit.schema.hash +1 -1
  61. package/dist/schema/pourkit.schema.json +32 -1
  62. 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((resolve5) => {
61
+ await new Promise((resolve6) => {
62
62
  if (!fileStream) {
63
- resolve5();
63
+ resolve6();
64
64
  return;
65
65
  }
66
66
  const timer = setTimeout(() => {
67
67
  if (!fileStream.destroyed) {
68
68
  fileStream.destroy();
69
69
  }
70
- resolve5();
70
+ resolve6();
71
71
  }, 2e3);
72
72
  fileStream.end(() => {
73
73
  clearTimeout(timer);
74
- resolve5();
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((resolve5) => setTimeout(resolve5, ms));
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: existsSync22 } = await import("fs");
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 (existsSync22(fullPath)) {
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 (!existsSync22(configPath)) {
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: readFile7 } = await import("fs/promises");
913
- const raw = await readFile7(configPath, "utf-8");
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: readdir2, stat, unlink, access: access2 } = await import("fs/promises");
1070
+ const { readdir: readdir4, stat, unlink, access: access2 } = await import("fs/promises");
1071
1071
  let entries;
1072
1072
  try {
1073
- entries = await readdir2(dirPath);
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((resolve5) => setTimeout(resolve5, 100));
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(repoRoot2, agent.promptTemplate);
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(repoRoot2, promptTemplate) {
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 assertIssueFinalReviewCoversActualDiff({
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: result.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 assertIssueFinalReviewCoversActualDiff(options) {
7633
- const actualChangedPaths = await listIssueFinalReviewChangedPaths(options);
7634
- const declared = new Set(options.declaredChangedPaths.map(normalizeGitPath));
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
- throw new Error(
7640
- `Issue Final Review pass did not enumerate all changed files. Missing from changedFiles: ${missing.join(", ")}. Re-run Issue Final Review or remove out-of-scope files before finalization.`
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 listIssueFinalReviewChangedPaths(options) {
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
- ...parseGitPathList(trackedDiff.stdout),
7665
- ...parseGitPathList(untrackedFiles.stdout)
7757
+ ...parseGitPathList2(trackedDiff.stdout),
7758
+ ...parseGitPathList2(untrackedFiles.stdout)
7666
7759
  ])
7667
- ).filter(isIssueFinalReviewAuditedPath);
7760
+ ).filter(isIssueFinalReviewAuditedPath2);
7668
7761
  }
7669
- function parseGitPathList(output) {
7670
- return output.split(/\r?\n/).map(normalizeGitPath).filter((path9) => path9.length > 0);
7762
+ function parseGitPathList2(output) {
7763
+ return output.split(/\r?\n/).map(normalizeGitPath2).filter((path9) => path9.length > 0);
7671
7764
  }
7672
- function normalizeGitPath(path9) {
7765
+ function normalizeGitPath2(path9) {
7673
7766
  return path9.replace(/^"|"$/g, "").replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
7674
7767
  }
7675
- function isIssueFinalReviewAuditedPath(path9) {
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) {
@@ -11848,6 +11941,7 @@ import { createHash as createHash2, randomUUID } from "crypto";
11848
11941
  import path5 from "path";
11849
11942
  import { execFile as execFile2 } from "child_process";
11850
11943
  import { promisify as promisify2 } from "util";
11944
+ import { fileURLToPath as fileURLToPath2 } from "url";
11851
11945
  import { confirm, isCancel, log, select, text } from "@clack/prompts";
11852
11946
 
11853
11947
  // providers/github-client.ts
@@ -11933,8 +12027,134 @@ async function tryCreateGitHubClient(options) {
11933
12027
  return { ok: true, client: { octokit, ...repo } };
11934
12028
  }
11935
12029
 
12030
+ // workflow-pack.ts
12031
+ var BASELINE_MANAGED_SKILLS = [
12032
+ "code-review",
12033
+ "diagnose",
12034
+ "explain",
12035
+ "grill-with-docs",
12036
+ "handoff",
12037
+ "improve-codebase-architecture",
12038
+ "publish-prd",
12039
+ "secret-commit-guard",
12040
+ "security-review",
12041
+ "ship-current-changes",
12042
+ "tdd",
12043
+ "to-issues",
12044
+ "to-plan",
12045
+ "to-prd",
12046
+ "triage",
12047
+ "write-a-skill",
12048
+ "zoom-out"
12049
+ ];
12050
+ var RELEASE_ADDON_SKILLS = ["changeset", "promote-release"];
12051
+ var RELEASE_ADDON_DOCS = ["release-workflow.md"];
12052
+ var MANAGED_DOCS = [
12053
+ "git-workflow.md",
12054
+ "issue-tracker.md",
12055
+ "naming.md",
12056
+ "triage-labels.md",
12057
+ "commit-style.md",
12058
+ "domain.md"
12059
+ ];
12060
+ var MANAGED_PROMPTS = [
12061
+ "builder.prompt.md",
12062
+ "conflict-resolution.prompt.md",
12063
+ "failure-resolution.prompt.md",
12064
+ "finalizer.prompt.md",
12065
+ "issue-final-review.prompt.md",
12066
+ "pr-description.prompt.md",
12067
+ "refactor.prompt.md",
12068
+ "reviewer.prompt.md",
12069
+ "reviewer-correctness.snippet.md",
12070
+ "reviewer-quality.snippet.md",
12071
+ "reviewer-scope.snippet.md",
12072
+ "reviewer-tests.snippet.md"
12073
+ ];
12074
+ var OPENCODE_PROJECTION = {
12075
+ harness: "opencode",
12076
+ path: ".agents/skills"
12077
+ };
12078
+ var CURRENT_VERSION = "0.0.0-next";
12079
+ function getWorkflowPackCatalog() {
12080
+ return {
12081
+ docs: [...MANAGED_DOCS],
12082
+ prompts: [...MANAGED_PROMPTS],
12083
+ baselineSkills: [...BASELINE_MANAGED_SKILLS],
12084
+ releaseAddonDocs: [...RELEASE_ADDON_DOCS],
12085
+ releaseAddonSkills: [...RELEASE_ADDON_SKILLS],
12086
+ projections: [OPENCODE_PROJECTION]
12087
+ };
12088
+ }
12089
+ function buildOpenCodeSkillProjectionContent(managedSourcePath, sourceContent) {
12090
+ const generatedNotice = `Generated from ${managedSourcePath}. Do not edit directly.`;
12091
+ if (managedSourcePath.endsWith(".md") || managedSourcePath.endsWith(".mdx")) {
12092
+ return `<!-- ${generatedNotice} -->
12093
+ ${sourceContent}`;
12094
+ }
12095
+ 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")) {
12096
+ const comment = `# ${generatedNotice}`;
12097
+ if (sourceContent.startsWith("#!")) {
12098
+ const lineBreakIndex = sourceContent.indexOf("\n");
12099
+ if (lineBreakIndex === -1) {
12100
+ return `${sourceContent}
12101
+ ${comment}
12102
+ `;
12103
+ }
12104
+ return `${sourceContent.slice(0, lineBreakIndex + 1)}${comment}
12105
+ ${sourceContent.slice(lineBreakIndex + 1)}`;
12106
+ }
12107
+ return `${comment}
12108
+ ${sourceContent}`;
12109
+ }
12110
+ return sourceContent;
12111
+ }
12112
+ function getBaselineManagedSkillNames() {
12113
+ return BASELINE_MANAGED_SKILLS;
12114
+ }
12115
+ function getWorkflowPackVersion() {
12116
+ return CURRENT_VERSION;
12117
+ }
12118
+ function buildWorkflowPackMetadata(enabledAddons) {
12119
+ return {
12120
+ version: getWorkflowPackVersion(),
12121
+ enabledAddons,
12122
+ projections: [OPENCODE_PROJECTION]
12123
+ };
12124
+ }
12125
+
11936
12126
  // commands/init.ts
11937
12127
  var execFileAsync2 = promisify2(execFile2);
12128
+ var __filename2 = fileURLToPath2(import.meta.url);
12129
+ var __dirname2 = path5.dirname(__filename2);
12130
+ var RELEASE_ADDON_SKILL_NAMES = ["changeset", "promote-release"];
12131
+ function resolvePackagedSourceRoot() {
12132
+ return path5.resolve(__dirname2, "..");
12133
+ }
12134
+ function resolveSourceAssetPath(sourceRoot, ...segments) {
12135
+ const packagedPath = path5.join(sourceRoot, ...segments);
12136
+ if (existsSync18(packagedPath)) return packagedPath;
12137
+ return path5.join(sourceRoot, "pourkit", ...segments);
12138
+ }
12139
+ var BASELINE_SKILL_NAMES = [
12140
+ "code-review",
12141
+ "diagnose",
12142
+ "explain",
12143
+ "grill-with-docs",
12144
+ "handoff",
12145
+ "improve-codebase-architecture",
12146
+ "publish-prd",
12147
+ "secret-commit-guard",
12148
+ "security-review",
12149
+ "ship-current-changes",
12150
+ "tdd",
12151
+ "to-issues",
12152
+ "to-plan",
12153
+ "to-prd",
12154
+ "triage",
12155
+ "write-a-skill",
12156
+ "zoom-out"
12157
+ ];
11938
12158
  var NO_TOKEN_LABEL_PROVISIONING_WARNING = "Skipped GitHub label provisioning because no GitHub token was provided.";
11939
12159
  var ALLOWED_VERIFICATION_SCRIPTS = [
11940
12160
  "typecheck",
@@ -12077,26 +12297,26 @@ function generateConfigTemplate(options) {
12077
12297
  builder: {
12078
12298
  agent: "pourkit-builder",
12079
12299
  model: "opencode-go/deepseek-v4-flash",
12080
- promptTemplate: ".pourkit/prompts/builder.prompt.md"
12300
+ promptTemplate: ".pourkit/managed/prompts/builder.prompt.md"
12081
12301
  }
12082
12302
  },
12083
12303
  failureResolution: {
12084
12304
  agent: "pourkit-failure-resolution-agent",
12085
12305
  model: "opencode-go/mimo-v2.5",
12086
- promptTemplate: ".pourkit/prompts/failure-resolution.prompt.md",
12306
+ promptTemplate: ".pourkit/managed/prompts/failure-resolution.prompt.md",
12087
12307
  maxAttemptsPerFailure: 1
12088
12308
  },
12089
12309
  review: {
12090
12310
  reviewer: {
12091
12311
  agent: "pourkit-reviewer",
12092
12312
  model: "opencode-go/deepseek-v4-pro",
12093
- promptTemplate: ".pourkit/prompts/reviewer.prompt.md",
12313
+ promptTemplate: ".pourkit/managed/prompts/reviewer.prompt.md",
12094
12314
  criteria: ["correctness", "scope", "tests", "quality"]
12095
12315
  },
12096
12316
  refactor: {
12097
12317
  agent: "pourkit-refactor",
12098
12318
  model: "opencode-go/qwen3.6-plus",
12099
- promptTemplate: ".pourkit/prompts/refactor.prompt.md"
12319
+ promptTemplate: ".pourkit/managed/prompts/refactor.prompt.md"
12100
12320
  },
12101
12321
  maxIterations: 3,
12102
12322
  passWithNotesRefactorAttempts: 2
@@ -12104,14 +12324,14 @@ function generateConfigTemplate(options) {
12104
12324
  issueFinalReview: {
12105
12325
  agent: "pourkit-reviewer",
12106
12326
  model: "opencode-go/deepseek-v4-pro",
12107
- promptTemplate: ".pourkit/prompts/issue-final-review.prompt.md",
12327
+ promptTemplate: ".pourkit/managed/prompts/issue-final-review.prompt.md",
12108
12328
  maxAttempts: 3
12109
12329
  },
12110
12330
  finalize: {
12111
12331
  prDescriptionAgent: {
12112
12332
  agent: "pourkit-pr-description",
12113
12333
  model: "opencode-go/deepseek-v4-flash",
12114
- promptTemplate: ".pourkit/prompts/pr-description.prompt.md"
12334
+ promptTemplate: ".pourkit/managed/prompts/pr-description.prompt.md"
12115
12335
  },
12116
12336
  maxAttempts: 2
12117
12337
  }
@@ -12131,6 +12351,17 @@ function generateConfigTemplate(options) {
12131
12351
  $schema: "./schema/pourkit.schema.json",
12132
12352
  schemaVersion: 1,
12133
12353
  targets: [target],
12354
+ workflowPack: {
12355
+ version: "1.0.0",
12356
+ skillProjections: [{ harness: "opencode", path: ".agents/skills" }]
12357
+ },
12358
+ releaseWorkflow: options.releaseWorkflow?.enabled ? {
12359
+ enabled: true,
12360
+ integrationBranch: options.releaseWorkflow.integrationBranch ?? "integration",
12361
+ developmentReleaseBranch: options.releaseWorkflow.developmentReleaseBranch ?? "preview",
12362
+ stableReleaseBranch: options.releaseWorkflow.stableReleaseBranch ?? "stable",
12363
+ changesets: options.releaseWorkflow.changesets ?? true
12364
+ } : { enabled: false },
12134
12365
  labels: {
12135
12366
  readyForAgent: labels.readyForAgent,
12136
12367
  agentInProgress: labels.agentInProgress,
@@ -12278,18 +12509,33 @@ _Avoid_: Alternative terms
12278
12509
  - <Document ambiguous terms and their resolution here.>
12279
12510
  `;
12280
12511
  }
12281
- async function generateManagedAgentInstructions(options) {
12282
- const sourcePath = path5.join(options.sourceRoot, "AGENTS.md");
12283
- try {
12284
- return await readFile5(sourcePath, "utf-8");
12285
- } catch {
12286
- return `## Codebase exploration
12512
+ async function generateManagedAgentInstructions(_options) {
12513
+ return `## Codebase exploration
12287
12514
 
12288
12515
  Use \`fd\` for file discovery, \`rg\` for text search, and direct file reads for focused context.
12289
12516
 
12290
- Follow the project's domain docs and conventions documented in \`.pourkit/docs/agents/*\`.
12517
+ Follow the project's domain docs and conventions documented in \`.pourkit/managed/docs/agents/*\`.
12518
+
12519
+ ### Managed operating docs
12520
+
12521
+ - \`.pourkit/managed/docs/agents/issue-tracker.md\`
12522
+ - \`.pourkit/managed/docs/agents/triage-labels.md\`
12523
+ - \`.pourkit/managed/docs/agents/naming.md\`
12524
+ - \`.pourkit/managed/docs/agents/git-workflow.md\`
12525
+ - \`.pourkit/managed/docs/agents/commit-style.md\`
12526
+ - \`.pourkit/managed/docs/agents/domain.md\`
12527
+
12528
+ ### Project-owned context
12529
+
12530
+ - \`.pourkit/CONTEXT.md\`
12531
+ - \`.pourkit/CONTEXT-MAP.md\`
12532
+ - \`.pourkit/docs/adr/*\`
12533
+
12534
+ ### Important
12535
+
12536
+ - Do not edit \`.pourkit/managed/*\` unless explicitly updating Pourkit-managed assets.
12537
+ - Do not edit generated harness projections directly.
12291
12538
  `;
12292
- }
12293
12539
  }
12294
12540
  function generateGitignoreBlock() {
12295
12541
  const lines = [
@@ -12455,16 +12701,24 @@ async function checkExistingLabelConflicts(client, canonicalLabels) {
12455
12701
  }
12456
12702
  }
12457
12703
  async function planInit(options) {
12458
- const { targetRoot, sourceRoot } = options;
12704
+ const { targetRoot } = options;
12705
+ let sourceRoot = options.sourceRoot ?? resolvePackagedSourceRoot();
12706
+ let usingExplicitSource = Boolean(options.sourceRoot);
12459
12707
  const operations = [];
12460
12708
  const warnings = [];
12461
12709
  let hasLabelConflicts = false;
12462
- let managedAgentContent;
12463
- if (sourceRoot) {
12464
- managedAgentContent = await generateManagedAgentInstructions({
12465
- sourceRoot
12710
+ if (options.sourceRoot) {
12711
+ warnings.push("--from-local is deprecated; omit it to use packaged assets");
12712
+ operations.push({
12713
+ kind: "warn",
12714
+ reason: "--from-local is deprecated; omit it to use packaged assets",
12715
+ destructive: false,
12716
+ requiresConfirmation: false
12466
12717
  });
12467
12718
  }
12719
+ const managedAgentContent = await generateManagedAgentInstructions({
12720
+ sourceRoot
12721
+ });
12468
12722
  const pm = options.packageManager ?? detectPackageManager(targetRoot);
12469
12723
  if (pm) {
12470
12724
  operations.push({
@@ -12495,39 +12749,28 @@ async function planInit(options) {
12495
12749
  const agentFiles = await discoverAgentFiles(targetRoot);
12496
12750
  if (agentFiles.length > 0) {
12497
12751
  for (const f of agentFiles) {
12498
- if (sourceRoot) {
12499
- const agentFileMode = options.conflictPolicy?.agentFile ?? "both";
12500
- const basename = path5.basename(f);
12501
- if (agentFileMode === "skip" || agentFileMode === "agents" && basename !== "AGENTS.md" || agentFileMode === "claude" && basename !== "CLAUDE.md") {
12502
- operations.push({
12503
- kind: "skip",
12504
- path: f,
12505
- ownership: "project-owned",
12506
- reason: `Existing agent file skipped per policy: ${basename}`,
12507
- requiresConfirmation: false,
12508
- destructive: false
12509
- });
12510
- continue;
12511
- }
12512
- operations.push({
12513
- kind: "update",
12514
- path: f,
12515
- ownership: "managed",
12516
- reason: `Update existing ${basename} with Pourkit managed block`,
12517
- requiresConfirmation: false,
12518
- destructive: false,
12519
- content: managedAgentContent
12520
- });
12521
- } else {
12752
+ const agentFileMode = options.conflictPolicy?.agentFile ?? "both";
12753
+ const basename = path5.basename(f);
12754
+ if (agentFileMode === "skip" || agentFileMode === "agents" && basename !== "AGENTS.md" || agentFileMode === "claude" && basename !== "CLAUDE.md") {
12522
12755
  operations.push({
12523
12756
  kind: "skip",
12524
12757
  path: f,
12525
12758
  ownership: "project-owned",
12526
- reason: `Existing agent file: ${path5.basename(f)}`,
12759
+ reason: `Existing agent file skipped per policy: ${basename}`,
12527
12760
  requiresConfirmation: false,
12528
12761
  destructive: false
12529
12762
  });
12763
+ continue;
12530
12764
  }
12765
+ operations.push({
12766
+ kind: "update",
12767
+ path: f,
12768
+ ownership: "managed",
12769
+ reason: `Update existing ${basename} with Pourkit managed block`,
12770
+ requiresConfirmation: false,
12771
+ destructive: false,
12772
+ content: managedAgentContent
12773
+ });
12531
12774
  }
12532
12775
  }
12533
12776
  const merlleState = await discoverMerlleState(targetRoot);
@@ -12621,7 +12864,10 @@ async function planInit(options) {
12621
12864
  destructive: false,
12622
12865
  requiresConfirmation: false
12623
12866
  });
12624
- } else {
12867
+ sourceRoot = resolvePackagedSourceRoot();
12868
+ usingExplicitSource = false;
12869
+ }
12870
+ {
12625
12871
  let sourceMeta;
12626
12872
  try {
12627
12873
  sourceMeta = await discoverLocalSource(sourceRoot);
@@ -12634,17 +12880,19 @@ async function planInit(options) {
12634
12880
  releaseChannel: "unknown",
12635
12881
  latestTag: null
12636
12882
  };
12637
- warnings.push(
12638
- "Source is not a Git repository; version metadata unavailable"
12639
- );
12640
- operations.push({
12641
- kind: "warn",
12642
- reason: "Source is not a Git repository; version metadata unavailable",
12643
- destructive: false,
12644
- requiresConfirmation: false
12645
- });
12883
+ if (usingExplicitSource) {
12884
+ warnings.push(
12885
+ "Source is not a Git repository; version metadata unavailable"
12886
+ );
12887
+ operations.push({
12888
+ kind: "warn",
12889
+ reason: "Source is not a Git repository; version metadata unavailable",
12890
+ destructive: false,
12891
+ requiresConfirmation: false
12892
+ });
12893
+ }
12646
12894
  }
12647
- if (sourceMeta.sourceDirty) {
12895
+ if (usingExplicitSource && sourceMeta.sourceDirty) {
12648
12896
  warnings.push("Local source has uncommitted changes");
12649
12897
  operations.push({
12650
12898
  kind: "warn",
@@ -12655,11 +12903,26 @@ async function planInit(options) {
12655
12903
  }
12656
12904
  const plannedSkillDests = /* @__PURE__ */ new Set();
12657
12905
  for (const op of operations) {
12658
- if (op.kind === "copy" && op.path?.includes(".agents/skills")) {
12906
+ if (op.path?.includes(".agents/skills")) {
12659
12907
  plannedSkillDests.add(op.path);
12660
12908
  }
12661
12909
  }
12662
- const srcSkills = await discoverAgentSkills(sourceRoot);
12910
+ const packagedManagedSkills = resolveSourceAssetPath(
12911
+ sourceRoot,
12912
+ "managed",
12913
+ "skills"
12914
+ );
12915
+ const packagedReleaseAddonSkills = resolveSourceAssetPath(
12916
+ sourceRoot,
12917
+ "managed",
12918
+ "addons",
12919
+ "release",
12920
+ "skills"
12921
+ );
12922
+ const srcSkills = existsSync18(packagedManagedSkills) ? [
12923
+ packagedManagedSkills,
12924
+ ...existsSync18(packagedReleaseAddonSkills) ? [packagedReleaseAddonSkills] : []
12925
+ ] : await discoverAgentSkills(sourceRoot);
12663
12926
  for (const s of srcSkills) {
12664
12927
  const isOpenCode = s.includes(".opencode");
12665
12928
  if (isOpenCode && !options.legacySkills) {
@@ -12671,35 +12934,118 @@ async function planInit(options) {
12671
12934
  });
12672
12935
  continue;
12673
12936
  }
12674
- const targetDirName = ".agents/skills";
12675
- const targetPath = path5.join(targetRoot, targetDirName);
12676
- const skillFiles = await walkDir(s);
12677
- for (const file of skillFiles) {
12678
- const relPath = path5.relative(s, file);
12679
- const destPath = path5.join(targetPath, relPath);
12680
- if (plannedSkillDests.has(destPath)) {
12937
+ if (isOpenCode) {
12938
+ const skillFiles = await walkDir(s);
12939
+ for (const file of skillFiles) {
12940
+ const relPath = path5.relative(s, file);
12941
+ const destPath = path5.join(
12942
+ targetRoot,
12943
+ ".agents",
12944
+ "skills",
12945
+ relPath
12946
+ );
12947
+ if (!existsSync18(destPath)) {
12948
+ operations.push({
12949
+ kind: "copy",
12950
+ sourcePath: file,
12951
+ path: destPath,
12952
+ ownership: "project-owned",
12953
+ reason: `Migrate legacy skill: ${path5.join(".opencode/skills", relPath)}`,
12954
+ requiresConfirmation: false,
12955
+ destructive: false
12956
+ });
12957
+ }
12958
+ }
12959
+ continue;
12960
+ }
12961
+ const managedSkillsDir = path5.join(
12962
+ targetRoot,
12963
+ ".pourkit",
12964
+ "managed",
12965
+ "skills"
12966
+ );
12967
+ const projectionSkillsDir = path5.join(targetRoot, ".agents", "skills");
12968
+ const entries = await readdir(s, { withFileTypes: true });
12969
+ const skillNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
12970
+ const addonManagedDir = path5.join(
12971
+ targetRoot,
12972
+ ".pourkit",
12973
+ "managed",
12974
+ "addons",
12975
+ "release",
12976
+ "skills"
12977
+ );
12978
+ for (const skillName of skillNames) {
12979
+ const isReleaseAddon = RELEASE_ADDON_SKILL_NAMES.includes(skillName);
12980
+ const isBaseline = BASELINE_SKILL_NAMES.includes(skillName);
12981
+ if (isReleaseAddon) {
12982
+ if (!options.releaseWorkflow?.enabled) {
12983
+ operations.push({
12984
+ kind: "skip",
12985
+ reason: `Release add-on skill not enabled: ${skillName}`,
12986
+ requiresConfirmation: false,
12987
+ destructive: false
12988
+ });
12989
+ continue;
12990
+ }
12991
+ } else if (!isBaseline) {
12681
12992
  operations.push({
12682
12993
  kind: "skip",
12683
- path: destPath,
12684
- ownership: "project-owned",
12685
- reason: `Skill destination conflict, skipping source copy: ${path5.join(targetDirName, relPath)}`,
12994
+ reason: `Non-baseline skill not installed: ${skillName}`,
12686
12995
  requiresConfirmation: false,
12687
- destructive: false,
12688
- conflict: "destination already planned"
12996
+ destructive: false
12689
12997
  });
12690
12998
  continue;
12691
12999
  }
12692
- const checksum = await computeFileChecksum(file);
12693
- operations.push({
12694
- kind: "copy",
12695
- sourcePath: file,
12696
- path: destPath,
12697
- ownership: "copied-customizable",
12698
- reason: `Copy skill: ${path5.join(targetDirName, relPath)}`,
12699
- requiresConfirmation: false,
12700
- destructive: false,
12701
- checksum
12702
- });
13000
+ const skillSourceDir = path5.join(s, skillName);
13001
+ const skillFiles = await walkDir(skillSourceDir);
13002
+ for (const file of skillFiles) {
13003
+ const relPath = path5.relative(skillSourceDir, file);
13004
+ const managedDest = isReleaseAddon ? path5.join(addonManagedDir, skillName, relPath) : path5.join(managedSkillsDir, skillName, relPath);
13005
+ const checksum = await computeFileChecksum(file);
13006
+ const installLabel = isReleaseAddon ? `Install release add-on skill: ${skillName}/${relPath}` : `Install managed skill: ${skillName}/${relPath}`;
13007
+ operations.push({
13008
+ kind: "copy",
13009
+ sourcePath: file,
13010
+ path: managedDest,
13011
+ ownership: "managed",
13012
+ reason: installLabel,
13013
+ requiresConfirmation: false,
13014
+ destructive: false,
13015
+ checksum
13016
+ });
13017
+ const projectionDest = path5.join(
13018
+ projectionSkillsDir,
13019
+ skillName,
13020
+ relPath
13021
+ );
13022
+ if (plannedSkillDests.has(projectionDest)) {
13023
+ operations.push({
13024
+ kind: "skip",
13025
+ path: projectionDest,
13026
+ ownership: "project-owned",
13027
+ reason: `Skill destination conflict, skipping projection: ${skillName}/${relPath}`,
13028
+ requiresConfirmation: false,
13029
+ destructive: false,
13030
+ conflict: "destination already planned"
13031
+ });
13032
+ continue;
13033
+ }
13034
+ const sourceContent = await readFile5(file, "utf-8");
13035
+ const managedSourcePath = isReleaseAddon ? `.pourkit/managed/addons/release/skills/${skillName}/${relPath}` : `.pourkit/managed/skills/${skillName}/${relPath}`;
13036
+ operations.push({
13037
+ kind: "create",
13038
+ path: projectionDest,
13039
+ ownership: "managed",
13040
+ reason: `Project skill: ${skillName}/${relPath}`,
13041
+ requiresConfirmation: false,
13042
+ destructive: false,
13043
+ content: buildOpenCodeSkillProjectionContent(
13044
+ managedSourcePath,
13045
+ sourceContent
13046
+ )
13047
+ });
13048
+ }
12703
13049
  }
12704
13050
  }
12705
13051
  const srcReadme = await discoverReadme(sourceRoot);
@@ -12792,7 +13138,7 @@ async function planInit(options) {
12792
13138
  operations.push({
12793
13139
  kind: "create",
12794
13140
  path: contextPath,
12795
- ownership: "managed",
13141
+ ownership: "project-owned",
12796
13142
  reason: "Init CONTEXT.md scaffold",
12797
13143
  requiresConfirmation: false,
12798
13144
  destructive: false,
@@ -12816,16 +13162,40 @@ async function planInit(options) {
12816
13162
  destructive: false
12817
13163
  });
12818
13164
  }
12819
- const srcDocAgents = path5.join(sourceRoot, ".pourkit", "docs", "agents");
12820
- const tgtDocAgents = path5.join(targetRoot, ".pourkit", "docs", "agents");
12821
- if (existsSync18(srcDocAgents) && !existsSync18(tgtDocAgents)) {
13165
+ const packagedManagedDocAgents = resolveSourceAssetPath(
13166
+ sourceRoot,
13167
+ "managed",
13168
+ "docs",
13169
+ "agents"
13170
+ );
13171
+ const legacyDocAgents = path5.join(
13172
+ sourceRoot,
13173
+ ".pourkit",
13174
+ "docs",
13175
+ "agents"
13176
+ );
13177
+ const srcDocAgents = existsSync18(packagedManagedDocAgents) ? packagedManagedDocAgents : legacyDocAgents;
13178
+ const tgtManagedDocAgents = path5.join(
13179
+ targetRoot,
13180
+ ".pourkit",
13181
+ "managed",
13182
+ "docs",
13183
+ "agents"
13184
+ );
13185
+ const tgtStubDocAgents = path5.join(
13186
+ targetRoot,
13187
+ ".pourkit",
13188
+ "docs",
13189
+ "agents"
13190
+ );
13191
+ if (existsSync18(srcDocAgents) && !existsSync18(tgtManagedDocAgents)) {
12822
13192
  const docFiles = await walkDir(srcDocAgents);
12823
13193
  for (const file of docFiles) {
12824
13194
  const relPath = path5.relative(srcDocAgents, file);
12825
13195
  if (relPath === "triage-labels.md") {
12826
13196
  operations.push({
12827
13197
  kind: "create",
12828
- path: path5.join(tgtDocAgents, relPath),
13198
+ path: path5.join(tgtManagedDocAgents, relPath),
12829
13199
  ownership: "managed",
12830
13200
  reason: "Init triage labels doc",
12831
13201
  requiresConfirmation: false,
@@ -12834,24 +13204,92 @@ async function planInit(options) {
12834
13204
  options.labels ?? DEFAULT_RUNNER_LABELS
12835
13205
  )
12836
13206
  });
12837
- continue;
13207
+ } else {
13208
+ const checksum = await computeFileChecksum(file);
13209
+ operations.push({
13210
+ kind: "copy",
13211
+ sourcePath: file,
13212
+ path: path5.join(tgtManagedDocAgents, relPath),
13213
+ ownership: "managed",
13214
+ reason: `Copy agent doc: ${relPath}`,
13215
+ requiresConfirmation: false,
13216
+ destructive: false,
13217
+ checksum
13218
+ });
12838
13219
  }
12839
- const checksum = await computeFileChecksum(file);
13220
+ if (relPath === "triage-labels.md") continue;
13221
+ const managedRelPath = path5.join(
13222
+ ".pourkit",
13223
+ "managed",
13224
+ "docs",
13225
+ "agents",
13226
+ relPath
13227
+ );
12840
13228
  operations.push({
12841
- kind: "copy",
12842
- sourcePath: file,
12843
- path: path5.join(tgtDocAgents, relPath),
13229
+ kind: "create",
13230
+ path: path5.join(tgtStubDocAgents, relPath),
12844
13231
  ownership: "managed",
12845
- reason: `Copy agent doc: ${relPath}`,
13232
+ reason: `Create moved stub for: ${relPath}`,
12846
13233
  requiresConfirmation: false,
12847
13234
  destructive: false,
12848
- checksum
13235
+ content: `# Moved
13236
+
13237
+ This Pourkit operating doc moved to \`${managedRelPath}\`.
13238
+ Do not edit this file.
13239
+ `
12849
13240
  });
12850
13241
  }
12851
13242
  }
12852
- const srcPrompts = path5.join(sourceRoot, ".pourkit", "prompts");
12853
- const tgtPrompts = path5.join(targetRoot, ".pourkit", "prompts");
12854
- if (existsSync18(srcPrompts) && !existsSync18(tgtPrompts)) {
13243
+ if (options.releaseWorkflow?.enabled) {
13244
+ const packagedReleaseAddonDocs = resolveSourceAssetPath(
13245
+ sourceRoot,
13246
+ "managed",
13247
+ "addons",
13248
+ "release",
13249
+ "docs",
13250
+ "agents"
13251
+ );
13252
+ const tgtReleaseAddonDocs = path5.join(
13253
+ targetRoot,
13254
+ ".pourkit",
13255
+ "managed",
13256
+ "addons",
13257
+ "release",
13258
+ "docs",
13259
+ "agents"
13260
+ );
13261
+ if (existsSync18(packagedReleaseAddonDocs)) {
13262
+ const docFiles = await walkDir(packagedReleaseAddonDocs);
13263
+ for (const file of docFiles) {
13264
+ const relPath = path5.relative(packagedReleaseAddonDocs, file);
13265
+ const checksum = await computeFileChecksum(file);
13266
+ operations.push({
13267
+ kind: "copy",
13268
+ sourcePath: file,
13269
+ path: path5.join(tgtReleaseAddonDocs, relPath),
13270
+ ownership: "managed",
13271
+ reason: `Install release add-on doc: ${relPath}`,
13272
+ requiresConfirmation: false,
13273
+ destructive: false,
13274
+ checksum
13275
+ });
13276
+ }
13277
+ }
13278
+ }
13279
+ const packagedManagedPrompts = resolveSourceAssetPath(
13280
+ sourceRoot,
13281
+ "managed",
13282
+ "prompts"
13283
+ );
13284
+ const legacyPrompts = path5.join(sourceRoot, ".pourkit", "prompts");
13285
+ const srcPrompts = existsSync18(packagedManagedPrompts) ? packagedManagedPrompts : legacyPrompts;
13286
+ const tgtManagedPrompts = path5.join(
13287
+ targetRoot,
13288
+ ".pourkit",
13289
+ "managed",
13290
+ "prompts"
13291
+ );
13292
+ if (existsSync18(srcPrompts) && !existsSync18(tgtManagedPrompts)) {
12855
13293
  const promptFiles = await walkDir(srcPrompts);
12856
13294
  for (const file of promptFiles) {
12857
13295
  const relPath = path5.relative(srcPrompts, file);
@@ -12859,7 +13297,7 @@ async function planInit(options) {
12859
13297
  operations.push({
12860
13298
  kind: "copy",
12861
13299
  sourcePath: file,
12862
- path: path5.join(tgtPrompts, relPath),
13300
+ path: path5.join(tgtManagedPrompts, relPath),
12863
13301
  ownership: "managed",
12864
13302
  reason: `Copy prompt: ${relPath}`,
12865
13303
  requiresConfirmation: false,
@@ -12911,7 +13349,8 @@ async function planInit(options) {
12911
13349
  baseBranch,
12912
13350
  verificationCommands: verifyCommands,
12913
13351
  hasPackageJson,
12914
- labels: options.labels
13352
+ labels: options.labels,
13353
+ releaseWorkflow: options.releaseWorkflow
12915
13354
  });
12916
13355
  operations.push({
12917
13356
  kind: "create",
@@ -12938,9 +13377,8 @@ async function planInit(options) {
12938
13377
  "schema",
12939
13378
  "pourkit.schema.json"
12940
13379
  );
12941
- const srcSchemaJson = path5.join(
13380
+ const srcSchemaJson = resolveSourceAssetPath(
12942
13381
  sourceRoot,
12943
- "pourkit",
12944
13382
  "schema",
12945
13383
  "pourkit.schema.json"
12946
13384
  );
@@ -12974,9 +13412,8 @@ async function planInit(options) {
12974
13412
  "schema",
12975
13413
  "pourkit.schema.hash"
12976
13414
  );
12977
- const srcSchemaHash = path5.join(
13415
+ const srcSchemaHash = resolveSourceAssetPath(
12978
13416
  sourceRoot,
12979
- "pourkit",
12980
13417
  "schema",
12981
13418
  "pourkit.schema.hash"
12982
13419
  );
@@ -13131,7 +13568,7 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
13131
13568
  conflict: "already exists"
13132
13569
  });
13133
13570
  }
13134
- const sourceLabel = sourceMeta.versionSource === "local-git" ? `Init from local source (${sourceMeta.branch}@${sourceMeta.sha.slice(0, 7)})` : "Init from local source (non-Git)";
13571
+ const sourceLabel = usingExplicitSource ? sourceMeta.versionSource === "local-git" ? `Init from local source (${sourceMeta.branch}@${sourceMeta.sha.slice(0, 7)})` : "Init from local source (non-Git)" : "Init from packaged assets";
13135
13572
  operations.push({
13136
13573
  kind: "copy",
13137
13574
  sourcePath: sourceRoot,
@@ -13142,21 +13579,14 @@ ${gitignoreContent}${MANAGED_BLOCK_END}
13142
13579
  destructive: false
13143
13580
  });
13144
13581
  }
13145
- } else {
13146
- warnings.push("No --from-local source provided");
13147
- operations.push({
13148
- kind: "warn",
13149
- reason: "No --from-local source provided",
13150
- destructive: false,
13151
- requiresConfirmation: false
13152
- });
13153
13582
  }
13154
13583
  return {
13155
13584
  targetRoot,
13156
- sourceRoot: sourceRoot ?? "",
13585
+ sourceRoot,
13157
13586
  operations,
13158
13587
  warnings,
13159
- hasLabelConflicts
13588
+ hasLabelConflicts,
13589
+ enabledAddons: options.releaseWorkflow?.enabled ? ["release"] : []
13160
13590
  };
13161
13591
  }
13162
13592
  var GROUP_LABELS = {
@@ -13228,6 +13658,7 @@ async function promptForInitChoices(plan, current) {
13228
13658
  let packageManager = current.packageManager;
13229
13659
  let legacySkills = current.legacySkills ?? false;
13230
13660
  let noGitCheck = current.noGitCheck ?? false;
13661
+ let releaseWorkflow;
13231
13662
  const labels = current.labels ? { ...current.labels } : { ...DEFAULT_RUNNER_LABELS };
13232
13663
  if (!packageManager && plan.warnings.some((w) => w.toLowerCase().includes("lockfile"))) {
13233
13664
  const result = await select({
@@ -13247,6 +13678,7 @@ async function promptForInitChoices(plan, current) {
13247
13678
  legacySkills,
13248
13679
  noGitCheck,
13249
13680
  labels,
13681
+ releaseWorkflow,
13250
13682
  cancelled: true
13251
13683
  };
13252
13684
  }
@@ -13270,6 +13702,7 @@ async function promptForInitChoices(plan, current) {
13270
13702
  legacySkills,
13271
13703
  noGitCheck,
13272
13704
  labels,
13705
+ releaseWorkflow,
13273
13706
  cancelled: true
13274
13707
  };
13275
13708
  }
@@ -13295,6 +13728,7 @@ async function promptForInitChoices(plan, current) {
13295
13728
  legacySkills,
13296
13729
  noGitCheck,
13297
13730
  labels,
13731
+ releaseWorkflow,
13298
13732
  cancelled: true
13299
13733
  };
13300
13734
  }
@@ -13413,45 +13847,119 @@ async function promptForInitChoices(plan, current) {
13413
13847
  legacySkills,
13414
13848
  noGitCheck,
13415
13849
  labels,
13850
+ releaseWorkflow,
13416
13851
  cancelled: true
13417
13852
  };
13418
13853
  }
13419
13854
  noGitCheck = true;
13420
13855
  }
13421
- return {
13422
- docsMigration: docsMigration ?? "copy",
13423
- agentFile: agentFile ?? "both",
13424
- packageManager,
13425
- legacySkills,
13426
- noGitCheck,
13427
- labels,
13428
- cancelled: false
13429
- };
13430
- }
13431
- async function writeFileAtomic(filePath, content) {
13432
- const tmpPath = `${filePath}.tmp.${randomUUID()}`;
13433
- await writeFile2(tmpPath, content, "utf-8");
13434
- await rename(tmpPath, filePath);
13435
- }
13436
- var MANAGED_BLOCK_BEGIN = "<!-- BEGIN POURKIT MANAGED BLOCK -->";
13437
- var MANAGED_BLOCK_END = "<!-- END POURKIT MANAGED BLOCK -->";
13438
- async function updateManagedBlock(filePath, content) {
13439
- const blockContent = `${MANAGED_BLOCK_BEGIN}
13440
- ${content}${MANAGED_BLOCK_END}
13441
- `;
13442
- if (!existsSync18(filePath)) {
13443
- const dir = path5.dirname(filePath);
13444
- await mkdir5(dir, { recursive: true });
13445
- await writeFileAtomic(filePath, blockContent);
13446
- return;
13447
- }
13448
- const existing = await readFile5(filePath, "utf-8");
13449
- const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN);
13450
- const endIdx = existing.indexOf(MANAGED_BLOCK_END);
13451
- if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
13452
- const before = existing.slice(0, beginIdx);
13453
- const after = existing.slice(endIdx + MANAGED_BLOCK_END.length);
13454
- await writeFileAtomic(filePath, before + blockContent + after);
13856
+ const releaseEnabledResult = await confirm({
13857
+ message: "Enable the Release Workflow Add-On for Changesets and Promotion PR orchestration?",
13858
+ initialValue: false
13859
+ });
13860
+ if (isCancel(releaseEnabledResult)) {
13861
+ return {
13862
+ docsMigration: docsMigration ?? "copy",
13863
+ agentFile: agentFile ?? "both",
13864
+ packageManager,
13865
+ legacySkills,
13866
+ noGitCheck,
13867
+ labels,
13868
+ releaseWorkflow: void 0,
13869
+ cancelled: true
13870
+ };
13871
+ }
13872
+ if (releaseEnabledResult) {
13873
+ const integrationBranchResult = await text({
13874
+ message: "Integration Branch name (e.g. dev)?",
13875
+ placeholder: "integration"
13876
+ });
13877
+ if (isCancel(integrationBranchResult)) {
13878
+ return {
13879
+ docsMigration: docsMigration ?? "copy",
13880
+ agentFile: agentFile ?? "both",
13881
+ packageManager,
13882
+ legacySkills,
13883
+ noGitCheck,
13884
+ labels,
13885
+ releaseWorkflow: void 0,
13886
+ cancelled: true
13887
+ };
13888
+ }
13889
+ const devReleaseBranchResult = await text({
13890
+ message: "Development Release Branch name (e.g. next)?",
13891
+ placeholder: "preview"
13892
+ });
13893
+ if (isCancel(devReleaseBranchResult)) {
13894
+ return {
13895
+ docsMigration: docsMigration ?? "copy",
13896
+ agentFile: agentFile ?? "both",
13897
+ packageManager,
13898
+ legacySkills,
13899
+ noGitCheck,
13900
+ labels,
13901
+ releaseWorkflow: void 0,
13902
+ cancelled: true
13903
+ };
13904
+ }
13905
+ const stableReleaseBranchResult = await text({
13906
+ message: "Stable Release Branch name (e.g. main)?",
13907
+ placeholder: "stable"
13908
+ });
13909
+ if (isCancel(stableReleaseBranchResult)) {
13910
+ return {
13911
+ docsMigration: docsMigration ?? "copy",
13912
+ agentFile: agentFile ?? "both",
13913
+ packageManager,
13914
+ legacySkills,
13915
+ noGitCheck,
13916
+ labels,
13917
+ releaseWorkflow: void 0,
13918
+ cancelled: true
13919
+ };
13920
+ }
13921
+ releaseWorkflow = {
13922
+ enabled: true,
13923
+ integrationBranch: typeof integrationBranchResult === "string" && integrationBranchResult.trim().length > 0 ? integrationBranchResult.trim() : "integration",
13924
+ developmentReleaseBranch: typeof devReleaseBranchResult === "string" && devReleaseBranchResult.trim().length > 0 ? devReleaseBranchResult.trim() : "preview",
13925
+ stableReleaseBranch: typeof stableReleaseBranchResult === "string" && stableReleaseBranchResult.trim().length > 0 ? stableReleaseBranchResult.trim() : "stable"
13926
+ };
13927
+ }
13928
+ return {
13929
+ docsMigration: docsMigration ?? "copy",
13930
+ agentFile: agentFile ?? "both",
13931
+ packageManager,
13932
+ legacySkills,
13933
+ noGitCheck,
13934
+ labels,
13935
+ releaseWorkflow,
13936
+ cancelled: false
13937
+ };
13938
+ }
13939
+ async function writeFileAtomic(filePath, content) {
13940
+ const tmpPath = `${filePath}.tmp.${randomUUID()}`;
13941
+ await writeFile2(tmpPath, content, "utf-8");
13942
+ await rename(tmpPath, filePath);
13943
+ }
13944
+ var MANAGED_BLOCK_BEGIN = "<!-- BEGIN POURKIT MANAGED BLOCK -->";
13945
+ var MANAGED_BLOCK_END = "<!-- END POURKIT MANAGED BLOCK -->";
13946
+ async function updateManagedBlock(filePath, content) {
13947
+ const blockContent = `${MANAGED_BLOCK_BEGIN}
13948
+ ${content}${MANAGED_BLOCK_END}
13949
+ `;
13950
+ if (!existsSync18(filePath)) {
13951
+ const dir = path5.dirname(filePath);
13952
+ await mkdir5(dir, { recursive: true });
13953
+ await writeFileAtomic(filePath, blockContent);
13954
+ return;
13955
+ }
13956
+ const existing = await readFile5(filePath, "utf-8");
13957
+ const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN);
13958
+ const endIdx = existing.indexOf(MANAGED_BLOCK_END);
13959
+ if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
13960
+ const before = existing.slice(0, beginIdx);
13961
+ const after = existing.slice(endIdx + MANAGED_BLOCK_END.length);
13962
+ await writeFileAtomic(filePath, before + blockContent + after);
13455
13963
  } else {
13456
13964
  const suffix = existing.endsWith("\n") ? "" : "\n";
13457
13965
  await writeFileAtomic(filePath, existing + suffix + blockContent + "\n");
@@ -13480,7 +13988,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
13480
13988
  schemaVersion: 1,
13481
13989
  initializedAt: (/* @__PURE__ */ new Date()).toISOString(),
13482
13990
  pourkit: {
13483
- versionSource: "local-git",
13991
+ versionSource: sourceMeta.versionSource,
13484
13992
  releaseVersion: sourceMeta.latestTag,
13485
13993
  releaseChannel: sourceMeta.releaseChannel,
13486
13994
  sourceBranch: sourceMeta.branch,
@@ -13490,6 +13998,7 @@ async function writeManifest(plan, sourceMeta, agentFiles, packageManager) {
13490
13998
  },
13491
13999
  agentFiles,
13492
14000
  packageManager,
14001
+ workflowPack: buildWorkflowPackMetadata(plan.enabledAddons ?? []),
13493
14002
  assets
13494
14003
  };
13495
14004
  await mkdir5(manifestDir, { recursive: true });
@@ -13674,7 +14183,7 @@ async function applyInitFromSource(options) {
13674
14183
  }
13675
14184
  let sourceMeta;
13676
14185
  try {
13677
- sourceMeta = await discoverLocalSource(fromLocal);
14186
+ sourceMeta = await discoverLocalSource(plan.sourceRoot);
13678
14187
  } catch {
13679
14188
  sourceMeta = {
13680
14189
  versionSource: "local-path",
@@ -13720,7 +14229,6 @@ async function runInitCommand(options) {
13720
14229
  }
13721
14230
  if (!isInteractive && !options.yes && !options.dryRun) {
13722
14231
  const missing = [];
13723
- if (!options.fromLocal) missing.push("--from-local");
13724
14232
  if (!options.docsMigration) missing.push("--docs-migration");
13725
14233
  if (!options.agentFile) missing.push("--agent-file");
13726
14234
  if (!options.packageManager) {
@@ -13766,7 +14274,8 @@ async function runInitCommand(options) {
13766
14274
  agentFile: options.agentFile ?? promptResult.agentFile,
13767
14275
  packageManager: options.packageManager ?? promptResult.packageManager,
13768
14276
  legacySkills: options.legacySkills ?? promptResult.legacySkills,
13769
- noGitCheck: options.noGitCheck ?? promptResult.noGitCheck
14277
+ noGitCheck: options.noGitCheck ?? promptResult.noGitCheck,
14278
+ releaseWorkflow: options.releaseWorkflow ?? promptResult.releaseWorkflow
13770
14279
  };
13771
14280
  promptLabels = promptResult.labels;
13772
14281
  }
@@ -13784,7 +14293,8 @@ async function runInitCommand(options) {
13784
14293
  packageManager: options.packageManager,
13785
14294
  noGitCheck: options.noGitCheck,
13786
14295
  skipInstall: options.skipInstall,
13787
- labels: planLabels
14296
+ labels: planLabels,
14297
+ releaseWorkflow: options.releaseWorkflow
13788
14298
  });
13789
14299
  let planLabelConflictPolicy = "skip-metadata-changes";
13790
14300
  if (isInteractive && plan.hasLabelConflicts) {
@@ -13828,12 +14338,6 @@ ${plan.warnings.length} warning(s) \u2014 review above before applying.`
13828
14338
  }
13829
14339
  return;
13830
14340
  }
13831
- if (!options.fromLocal) {
13832
- console.error(
13833
- "\nError: --from-local <path> is required to apply the init plan."
13834
- );
13835
- process.exit(1);
13836
- }
13837
14341
  const result = await applyInitFromSource({
13838
14342
  targetRoot,
13839
14343
  fromLocal: options.fromLocal,
@@ -13990,16 +14494,16 @@ async function runSerenaStatusCommand(options) {
13990
14494
 
13991
14495
  // commands/config-schema.ts
13992
14496
  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";
13995
- import { fileURLToPath as fileURLToPath2 } from "url";
14497
+ import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
14498
+ import { resolve as resolve4, dirname as dirname5, relative as relative2 } from "path";
14499
+ import { fileURLToPath as fileURLToPath3 } from "url";
13996
14500
  import Ajv2 from "ajv";
13997
- var __filename2 = fileURLToPath2(import.meta.url);
13998
- var __dirname2 = dirname5(__filename2);
14501
+ var __filename3 = fileURLToPath3(import.meta.url);
14502
+ var __dirname3 = dirname5(__filename3);
13999
14503
  function resolvePackagedAssetPath2(fileName) {
14000
14504
  const candidates = [
14001
- resolve4(__dirname2, "schema", fileName),
14002
- resolve4(__dirname2, "../schema", fileName)
14505
+ resolve4(__dirname3, "schema", fileName),
14506
+ resolve4(__dirname3, "../schema", fileName)
14003
14507
  ];
14004
14508
  return candidates.find((candidate) => existsSync19(candidate)) ?? candidates[0];
14005
14509
  }
@@ -14028,6 +14532,542 @@ function readPackagedHash() {
14028
14532
  function localSchemaDir(repoRoot2) {
14029
14533
  return resolve4(repoRoot2, ".pourkit/schema");
14030
14534
  }
14535
+ var MANAGED_BLOCK_BEGIN2 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
14536
+ var OLD_DOCS_PATH_PATTERN = ".pourkit/docs/agents/";
14537
+ function resolvePackagedManagedPath(...segments) {
14538
+ return resolve4(__dirname3, "..", "managed", ...segments);
14539
+ }
14540
+ function resolvePackagedManagedDocPath(docName) {
14541
+ return resolvePackagedManagedPath("docs", "agents", docName);
14542
+ }
14543
+ function resolvePackagedReleaseAddonDocPath(docName) {
14544
+ return resolvePackagedManagedPath(
14545
+ "addons",
14546
+ "release",
14547
+ "docs",
14548
+ "agents",
14549
+ docName
14550
+ );
14551
+ }
14552
+ async function readPackagedTextFile(filePath) {
14553
+ try {
14554
+ return await readFile6(filePath, "utf-8");
14555
+ } catch {
14556
+ return null;
14557
+ }
14558
+ }
14559
+ function isPathContained(parent, child) {
14560
+ const relativePath = relative2(parent, child);
14561
+ return !relativePath.startsWith("..") && !relativePath.startsWith("../");
14562
+ }
14563
+ async function walkDir2(dir) {
14564
+ const files = [];
14565
+ try {
14566
+ const entries = await readdir2(dir, { withFileTypes: true });
14567
+ for (const entry of entries) {
14568
+ const full = resolve4(dir, entry.name);
14569
+ if (entry.isDirectory()) {
14570
+ files.push(...await walkDir2(full));
14571
+ } else {
14572
+ files.push(full);
14573
+ }
14574
+ }
14575
+ } catch {
14576
+ return [];
14577
+ }
14578
+ return files;
14579
+ }
14580
+ function removeCodeFences(content) {
14581
+ return content.replace(/```[\s\S]*?```/g, "");
14582
+ }
14583
+ function isInsideBacktick(content, index) {
14584
+ const before = content.slice(0, index);
14585
+ const backtickCount = (before.match(/`/g) || []).length;
14586
+ return backtickCount % 2 === 1;
14587
+ }
14588
+ var BRANCH_NAME_PATTERN = /\b(dev|next|main)\b/g;
14589
+ var OBSOLETE_PRD_PATTERN = /PRD-\d{3}(?![\dNn])/g;
14590
+ var OVERWIDE_PRD_PATTERN = /PRD-\d{5,}/g;
14591
+ function isExampleLine(content, matchIndex) {
14592
+ return /^(?:[-*]\s+)?Example:/i.test(getLine(content, matchIndex).trim());
14593
+ }
14594
+ function getLine(content, matchIndex) {
14595
+ const lineStart = content.lastIndexOf("\n", matchIndex - 1) + 1;
14596
+ const lineEnd = content.indexOf("\n", matchIndex);
14597
+ return content.slice(lineStart, lineEnd === -1 ? content.length : lineEnd);
14598
+ }
14599
+ function isBranchPolicyLine(content, matchIndex) {
14600
+ const line = getLine(content, matchIndex).toLowerCase();
14601
+ return /->|\b(branch|branches|lane|release|promotion|promote|target|base|merge|push|hotfix|changeset|origin)\b/.test(
14602
+ line
14603
+ );
14604
+ }
14605
+ function scanManagedPolicyText(content, filePath, allowlist) {
14606
+ const violations = [];
14607
+ const noFences = removeCodeFences(content);
14608
+ let match;
14609
+ BRANCH_NAME_PATTERN.lastIndex = 0;
14610
+ while ((match = BRANCH_NAME_PATTERN.exec(noFences)) !== null) {
14611
+ if (isExampleLine(noFences, match.index)) continue;
14612
+ if (!isBranchPolicyLine(noFences, match.index)) continue;
14613
+ if (allowlist?.includes(match[0])) continue;
14614
+ violations.push({
14615
+ path: filePath,
14616
+ phrase: match[0],
14617
+ reason: "hardcoded_branch_policy"
14618
+ });
14619
+ }
14620
+ OBSOLETE_PRD_PATTERN.lastIndex = 0;
14621
+ while ((match = OBSOLETE_PRD_PATTERN.exec(noFences)) !== null) {
14622
+ if (allowlist?.includes(match[0])) continue;
14623
+ if (!isInsideBacktick(noFences, match.index)) {
14624
+ violations.push({
14625
+ path: filePath,
14626
+ phrase: match[0],
14627
+ reason: "obsolete_prd_placeholder"
14628
+ });
14629
+ }
14630
+ }
14631
+ OVERWIDE_PRD_PATTERN.lastIndex = 0;
14632
+ while ((match = OVERWIDE_PRD_PATTERN.exec(noFences)) !== null) {
14633
+ if (allowlist?.includes(match[0])) continue;
14634
+ if (!isInsideBacktick(noFences, match.index)) {
14635
+ violations.push({
14636
+ path: filePath,
14637
+ phrase: match[0],
14638
+ reason: "obsolete_prd_placeholder"
14639
+ });
14640
+ }
14641
+ }
14642
+ return violations;
14643
+ }
14644
+ async function validateWorkflowPack(cwd) {
14645
+ const failures = [];
14646
+ const warnings = [];
14647
+ const catalog = getWorkflowPackCatalog();
14648
+ const baselineSkills = getBaselineManagedSkillNames();
14649
+ for (const docName of catalog.docs) {
14650
+ const localPath = resolve4(cwd, `.pourkit/managed/docs/agents/${docName}`);
14651
+ if (!existsSync19(localPath)) {
14652
+ failures.push({
14653
+ severity: "failure",
14654
+ kind: "missing_managed_asset",
14655
+ path: `.pourkit/managed/docs/agents/${docName}`,
14656
+ message: `Missing managed doc: ${docName}`
14657
+ });
14658
+ } else {
14659
+ const packagedPath = resolvePackagedManagedDocPath(docName);
14660
+ const packagedContent = await readPackagedTextFile(packagedPath);
14661
+ if (packagedContent !== null) {
14662
+ try {
14663
+ const localContent = await readFile6(localPath, "utf-8");
14664
+ if (localContent !== packagedContent) {
14665
+ const overridePath = resolve4(
14666
+ cwd,
14667
+ `.pourkit/overrides/docs/agents/${docName}`
14668
+ );
14669
+ if (existsSync19(overridePath)) {
14670
+ warnings.push({
14671
+ severity: "warning",
14672
+ kind: "overridden",
14673
+ path: `.pourkit/overrides/docs/agents/${docName}`,
14674
+ message: `Managed doc ${docName} is overridden by explicit override.`
14675
+ });
14676
+ } else {
14677
+ failures.push({
14678
+ severity: "failure",
14679
+ kind: "managed_asset_drift",
14680
+ path: `.pourkit/managed/docs/agents/${docName}`,
14681
+ message: `Managed doc ${docName} content differs from packaged source. Run 'pourkit sync workflow-pack' to repair.`
14682
+ });
14683
+ }
14684
+ }
14685
+ } catch {
14686
+ }
14687
+ }
14688
+ }
14689
+ }
14690
+ for (const skillName of baselineSkills) {
14691
+ const skillDir = resolve4(cwd, `.pourkit/managed/skills/${skillName}`);
14692
+ if (!existsSync19(skillDir)) {
14693
+ failures.push({
14694
+ severity: "failure",
14695
+ kind: "missing_managed_asset",
14696
+ path: `.pourkit/managed/skills/${skillName}`,
14697
+ message: `Missing managed skill: ${skillName}`
14698
+ });
14699
+ } else {
14700
+ const skillSourcePath = resolve4(skillDir, "SKILL.md");
14701
+ if (existsSync19(skillSourcePath)) {
14702
+ const packagedSkillPath = resolvePackagedManagedPath(
14703
+ "skills",
14704
+ skillName,
14705
+ "SKILL.md"
14706
+ );
14707
+ const packagedContent = await readPackagedTextFile(packagedSkillPath);
14708
+ if (packagedContent !== null) {
14709
+ try {
14710
+ const localContent = await readFile6(skillSourcePath, "utf-8");
14711
+ if (localContent !== packagedContent) {
14712
+ const overridePath = resolve4(
14713
+ cwd,
14714
+ `.pourkit/overrides/skills/${skillName}/SKILL.md`
14715
+ );
14716
+ if (existsSync19(overridePath)) {
14717
+ warnings.push({
14718
+ severity: "warning",
14719
+ kind: "overridden",
14720
+ path: `.pourkit/overrides/skills/${skillName}/SKILL.md`,
14721
+ message: `Managed skill ${skillName} is overridden by explicit override.`
14722
+ });
14723
+ } else {
14724
+ failures.push({
14725
+ severity: "failure",
14726
+ kind: "managed_asset_drift",
14727
+ path: `.pourkit/managed/skills/${skillName}/SKILL.md`,
14728
+ message: `Managed skill ${skillName} content differs from packaged source. Run 'pourkit sync workflow-pack' to repair.`
14729
+ });
14730
+ }
14731
+ }
14732
+ } catch {
14733
+ }
14734
+ }
14735
+ }
14736
+ }
14737
+ }
14738
+ for (const promptName of catalog.prompts) {
14739
+ const promptPath = resolve4(cwd, `.pourkit/managed/prompts/${promptName}`);
14740
+ if (!existsSync19(promptPath)) {
14741
+ failures.push({
14742
+ severity: "failure",
14743
+ kind: "missing_managed_asset",
14744
+ path: `.pourkit/managed/prompts/${promptName}`,
14745
+ message: `Missing managed prompt: ${promptName}`
14746
+ });
14747
+ }
14748
+ }
14749
+ for (const skillName of baselineSkills) {
14750
+ const projectionDir = resolve4(cwd, `.agents/skills/${skillName}`);
14751
+ if (!existsSync19(projectionDir)) {
14752
+ warnings.push({
14753
+ severity: "warning",
14754
+ kind: "projection_stale",
14755
+ path: `.agents/skills/${skillName}`,
14756
+ message: `Missing skill projection for ${skillName}. Run 'pourkit sync workflow-pack' to regenerate.`
14757
+ });
14758
+ } else {
14759
+ const projectionPath = resolve4(projectionDir, "SKILL.md");
14760
+ if (existsSync19(projectionPath)) {
14761
+ const managedSourcePath = resolvePackagedManagedPath(
14762
+ "skills",
14763
+ skillName,
14764
+ "SKILL.md"
14765
+ );
14766
+ const packagedContent = await readPackagedTextFile(managedSourcePath);
14767
+ if (packagedContent !== null) {
14768
+ try {
14769
+ const projectionContent = await readFile6(projectionPath, "utf-8");
14770
+ const managedSourceRelativePath = `.pourkit/managed/skills/${skillName}/SKILL.md`;
14771
+ if (projectionContent !== buildOpenCodeSkillProjectionContent(
14772
+ managedSourceRelativePath,
14773
+ packagedContent
14774
+ )) {
14775
+ warnings.push({
14776
+ severity: "warning",
14777
+ kind: "projection_stale",
14778
+ path: `.agents/skills/${skillName}/SKILL.md`,
14779
+ message: `Projection for ${skillName} differs from managed source. Run 'pourkit sync workflow-pack' to regenerate.`
14780
+ });
14781
+ }
14782
+ } catch {
14783
+ }
14784
+ }
14785
+ }
14786
+ }
14787
+ }
14788
+ const agentsPath = resolve4(cwd, "AGENTS.md");
14789
+ if (existsSync19(agentsPath)) {
14790
+ try {
14791
+ const agentsContent = await readFile6(agentsPath, "utf-8");
14792
+ if (agentsContent.includes(OLD_DOCS_PATH_PATTERN)) {
14793
+ failures.push({
14794
+ severity: "failure",
14795
+ kind: "router_drift",
14796
+ path: "AGENTS.md",
14797
+ message: "AGENTS.md references old .pourkit/docs/agents/ paths. Update to .pourkit/managed/docs/agents/."
14798
+ });
14799
+ }
14800
+ if (!agentsContent.includes(MANAGED_BLOCK_BEGIN2.trim())) {
14801
+ failures.push({
14802
+ severity: "failure",
14803
+ kind: "router_drift",
14804
+ path: "AGENTS.md",
14805
+ message: "AGENTS.md is missing the Pourkit managed block. Run 'pourkit sync workflow-pack' to add it."
14806
+ });
14807
+ }
14808
+ } catch {
14809
+ }
14810
+ }
14811
+ const overridesDir = resolve4(cwd, ".pourkit/overrides");
14812
+ if (existsSync19(overridesDir)) {
14813
+ const overrideFiles = await walkDir2(overridesDir);
14814
+ for (const file of overrideFiles) {
14815
+ const relPath = relative2(cwd, file);
14816
+ if (!warnings.some((w) => w.kind === "overridden" && w.path === relPath)) {
14817
+ warnings.push({
14818
+ severity: "warning",
14819
+ kind: "overridden",
14820
+ path: relPath,
14821
+ message: `Explicit override present: ${relPath}`
14822
+ });
14823
+ }
14824
+ }
14825
+ }
14826
+ const configPath = resolve4(cwd, ".pourkit/config.json");
14827
+ if (existsSync19(configPath)) {
14828
+ try {
14829
+ const configContent = await readFile6(configPath, "utf-8");
14830
+ const parsed = JSON.parse(configContent);
14831
+ const releaseEnabled = parsed.releaseWorkflow?.enabled === true;
14832
+ if (releaseEnabled) {
14833
+ for (const skillName of catalog.releaseAddonSkills) {
14834
+ const addonDir = resolve4(
14835
+ cwd,
14836
+ `.pourkit/managed/addons/release/skills/${skillName}`
14837
+ );
14838
+ if (!existsSync19(addonDir)) {
14839
+ failures.push({
14840
+ severity: "failure",
14841
+ kind: "release_config_conflict",
14842
+ path: `.pourkit/managed/addons/release/skills/${skillName}`,
14843
+ message: `Release workflow is enabled but release addon skill ${skillName} is not installed. Run 'pourkit sync workflow-pack' to install.`
14844
+ });
14845
+ }
14846
+ }
14847
+ for (const docName of catalog.releaseAddonDocs) {
14848
+ const addonDocPath = resolve4(
14849
+ cwd,
14850
+ `.pourkit/managed/addons/release/docs/agents/${docName}`
14851
+ );
14852
+ if (!existsSync19(addonDocPath)) {
14853
+ failures.push({
14854
+ severity: "failure",
14855
+ kind: "release_config_conflict",
14856
+ path: `.pourkit/managed/addons/release/docs/agents/${docName}`,
14857
+ message: `Release workflow is enabled but release addon doc ${docName} is not installed. Run 'pourkit sync workflow-pack' to install.`
14858
+ });
14859
+ } else {
14860
+ const packagedContent = await readPackagedTextFile(
14861
+ resolvePackagedReleaseAddonDocPath(docName)
14862
+ );
14863
+ if (packagedContent !== null) {
14864
+ const localContent = await readFile6(addonDocPath, "utf-8");
14865
+ if (localContent !== packagedContent) {
14866
+ failures.push({
14867
+ severity: "failure",
14868
+ kind: "managed_asset_drift",
14869
+ path: `.pourkit/managed/addons/release/docs/agents/${docName}`,
14870
+ message: `Release addon doc ${docName} content differs from packaged source. Run 'pourkit sync workflow-pack' to repair.`
14871
+ });
14872
+ }
14873
+ }
14874
+ }
14875
+ }
14876
+ const rw = parsed.releaseWorkflow;
14877
+ const requiredFields = [
14878
+ ["integrationBranch", rw?.integrationBranch],
14879
+ ["developmentReleaseBranch", rw?.developmentReleaseBranch],
14880
+ ["stableReleaseBranch", rw?.stableReleaseBranch]
14881
+ ];
14882
+ for (const [fieldName, value] of requiredFields) {
14883
+ if (!value || typeof value === "string" && value.trim() === "") {
14884
+ failures.push({
14885
+ severity: "failure",
14886
+ kind: "release_config_conflict",
14887
+ message: `Release workflow is enabled but required field releaseWorkflow.${fieldName} is missing or empty.`
14888
+ });
14889
+ }
14890
+ }
14891
+ } else {
14892
+ for (const skillName of catalog.releaseAddonSkills) {
14893
+ const addonDir = resolve4(
14894
+ cwd,
14895
+ `.pourkit/managed/addons/release/skills/${skillName}`
14896
+ );
14897
+ if (existsSync19(addonDir)) {
14898
+ failures.push({
14899
+ severity: "failure",
14900
+ kind: "release_config_conflict",
14901
+ path: `.pourkit/managed/addons/release/skills/${skillName}`,
14902
+ message: `Release workflow is disabled but release addon skill ${skillName} is present as active baseline policy. Disable or remove the addon skill.`
14903
+ });
14904
+ }
14905
+ }
14906
+ for (const docName of catalog.releaseAddonDocs) {
14907
+ const addonDocPath = resolve4(
14908
+ cwd,
14909
+ `.pourkit/managed/addons/release/docs/agents/${docName}`
14910
+ );
14911
+ if (existsSync19(addonDocPath)) {
14912
+ failures.push({
14913
+ severity: "failure",
14914
+ kind: "release_config_conflict",
14915
+ path: `.pourkit/managed/addons/release/docs/agents/${docName}`,
14916
+ message: `Release workflow is disabled but release addon doc ${docName} is present as active baseline policy. Disable or remove the addon doc.`
14917
+ });
14918
+ }
14919
+ }
14920
+ }
14921
+ } catch {
14922
+ }
14923
+ }
14924
+ const manifestPath = resolve4(cwd, ".pourkit/manifest.json");
14925
+ if (existsSync19(manifestPath)) {
14926
+ try {
14927
+ const manifestContent = await readFile6(manifestPath, "utf-8");
14928
+ const manifest = JSON.parse(manifestContent);
14929
+ const wp = manifest.workflowPack;
14930
+ if (wp?.projections) {
14931
+ for (const proj of wp.projections) {
14932
+ if (proj.path) {
14933
+ const resolved = resolve4(cwd, proj.path);
14934
+ if (!isPathContained(cwd, resolved)) {
14935
+ failures.push({
14936
+ severity: "failure",
14937
+ kind: "path_escape",
14938
+ message: `Manifest projection path escapes repository: ${proj.path}`
14939
+ });
14940
+ }
14941
+ }
14942
+ }
14943
+ }
14944
+ } catch {
14945
+ }
14946
+ }
14947
+ const pathEscapeOverrideDir = resolve4(cwd, ".pourkit/overrides");
14948
+ if (existsSync19(pathEscapeOverrideDir)) {
14949
+ const overrideFiles = await walkDir2(pathEscapeOverrideDir);
14950
+ for (const file of overrideFiles) {
14951
+ if (!isPathContained(cwd, file)) {
14952
+ failures.push({
14953
+ severity: "failure",
14954
+ kind: "path_escape",
14955
+ path: relative2(cwd, file),
14956
+ message: `Override file path escapes repository: ${relative2(cwd, file)}`
14957
+ });
14958
+ }
14959
+ }
14960
+ }
14961
+ const managedDocsDir = resolve4(cwd, ".pourkit/managed/docs/agents");
14962
+ if (existsSync19(managedDocsDir)) {
14963
+ const docFiles = await walkDir2(managedDocsDir);
14964
+ for (const file of docFiles) {
14965
+ if (!file.endsWith(".md")) continue;
14966
+ try {
14967
+ const content = await readFile6(file, "utf-8");
14968
+ const relPath = relative2(cwd, file);
14969
+ const violations = scanManagedPolicyText(content, relPath);
14970
+ for (const v of violations) {
14971
+ failures.push({
14972
+ severity: "failure",
14973
+ kind: "terminology_policy_violation",
14974
+ path: v.path,
14975
+ message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
14976
+ });
14977
+ }
14978
+ } catch {
14979
+ }
14980
+ }
14981
+ }
14982
+ const managedSkillsDir = resolve4(cwd, ".pourkit/managed/skills");
14983
+ if (existsSync19(managedSkillsDir)) {
14984
+ const skillDirs = await readdir2(managedSkillsDir, { withFileTypes: true });
14985
+ for (const entry of skillDirs) {
14986
+ if (!entry.isDirectory()) continue;
14987
+ const skillFile = resolve4(managedSkillsDir, entry.name, "SKILL.md");
14988
+ if (!existsSync19(skillFile)) continue;
14989
+ try {
14990
+ const content = await readFile6(skillFile, "utf-8");
14991
+ const relPath = relative2(cwd, skillFile);
14992
+ const violations = scanManagedPolicyText(content, relPath);
14993
+ for (const v of violations) {
14994
+ failures.push({
14995
+ severity: "failure",
14996
+ kind: "terminology_policy_violation",
14997
+ path: v.path,
14998
+ message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
14999
+ });
15000
+ }
15001
+ } catch {
15002
+ }
15003
+ }
15004
+ }
15005
+ const managedPromptsDir = resolve4(cwd, ".pourkit/managed/prompts");
15006
+ if (existsSync19(managedPromptsDir)) {
15007
+ for (const promptName of catalog.prompts) {
15008
+ const promptFile = resolve4(managedPromptsDir, promptName);
15009
+ if (!existsSync19(promptFile)) continue;
15010
+ try {
15011
+ const content = await readFile6(promptFile, "utf-8");
15012
+ const relPath = relative2(cwd, promptFile);
15013
+ const violations = scanManagedPolicyText(content, relPath);
15014
+ for (const v of violations) {
15015
+ failures.push({
15016
+ severity: "failure",
15017
+ kind: "terminology_policy_violation",
15018
+ path: v.path,
15019
+ message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
15020
+ });
15021
+ }
15022
+ } catch {
15023
+ }
15024
+ }
15025
+ }
15026
+ for (const skillName of catalog.releaseAddonSkills) {
15027
+ const addonSkillFile = resolve4(
15028
+ cwd,
15029
+ `.pourkit/managed/addons/release/skills/${skillName}/SKILL.md`
15030
+ );
15031
+ if (!existsSync19(addonSkillFile)) continue;
15032
+ try {
15033
+ const content = await readFile6(addonSkillFile, "utf-8");
15034
+ const relPath = relative2(cwd, addonSkillFile);
15035
+ const violations = scanManagedPolicyText(content, relPath);
15036
+ for (const v of violations) {
15037
+ failures.push({
15038
+ severity: "failure",
15039
+ kind: "terminology_policy_violation",
15040
+ path: v.path,
15041
+ message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
15042
+ });
15043
+ }
15044
+ } catch {
15045
+ }
15046
+ }
15047
+ for (const docName of catalog.releaseAddonDocs) {
15048
+ const addonDocFile = resolve4(
15049
+ cwd,
15050
+ `.pourkit/managed/addons/release/docs/agents/${docName}`
15051
+ );
15052
+ if (!existsSync19(addonDocFile)) continue;
15053
+ try {
15054
+ const content = await readFile6(addonDocFile, "utf-8");
15055
+ const relPath = relative2(cwd, addonDocFile);
15056
+ const violations = scanManagedPolicyText(content, relPath);
15057
+ for (const v of violations) {
15058
+ failures.push({
15059
+ severity: "failure",
15060
+ kind: "terminology_policy_violation",
15061
+ path: v.path,
15062
+ message: `Policy violation: "${v.phrase}" is a ${v.reason === "hardcoded_branch_policy" ? "hardcoded branch name in policy context" : "obsolete or over-wide PRD placeholder"}.`
15063
+ });
15064
+ }
15065
+ } catch {
15066
+ }
15067
+ }
15068
+ const status = failures.length > 0 ? "failed" : warnings.length > 0 ? "warning" : "fresh";
15069
+ return { status, failures, warnings };
15070
+ }
14031
15071
  async function runDoctorCommand(options) {
14032
15072
  const repoRootPath = options.cwd ?? process.cwd();
14033
15073
  const schemaDir = localSchemaDir(repoRootPath);
@@ -14087,30 +15127,37 @@ async function runDoctorCommand(options) {
14087
15127
  "pourkit.config.js",
14088
15128
  "pourkit.json"
14089
15129
  ].filter((p) => existsSync19(resolve4(repoRootPath, p)));
15130
+ const workflowPack = await validateWorkflowPack(repoRootPath);
14090
15131
  let recommendation = null;
14091
- if (!configValidation.ok || overall !== "fresh" || obsoleteConfigs.length > 0) {
14092
- const parts = [];
14093
- if (obsoleteConfigs.length > 0) {
14094
- parts.push(
14095
- `Found obsolete config files: ${obsoleteConfigs.join(", ")}. Move configuration to .pourkit/config.json with "$schema": "./schema/pourkit.schema.json".`
14096
- );
14097
- }
14098
- if (!configValidation.ok) {
14099
- parts.push(
14100
- "Config validation failed; fix errors in .pourkit/config.json."
14101
- );
14102
- }
14103
- if (overall !== "fresh") {
14104
- parts.push(
14105
- 'Run "pourkit config sync-schema" to update local schema assets.'
14106
- );
14107
- }
14108
- recommendation = parts.join(" ");
15132
+ const recParts = [];
15133
+ if (obsoleteConfigs.length > 0) {
15134
+ recParts.push(
15135
+ `Found obsolete config files: ${obsoleteConfigs.join(", ")}. Move configuration to .pourkit/config.json with "$schema": "./schema/pourkit.schema.json".`
15136
+ );
15137
+ }
15138
+ if (!configValidation.ok) {
15139
+ recParts.push(
15140
+ "Config validation failed; fix errors in .pourkit/config.json."
15141
+ );
15142
+ }
15143
+ if (overall !== "fresh") {
15144
+ recParts.push(
15145
+ 'Run "pourkit config sync-schema" to update local schema assets.'
15146
+ );
15147
+ }
15148
+ if (workflowPack.status === "failed" || workflowPack.status === "warning") {
15149
+ recParts.push(
15150
+ 'Run "pourkit sync workflow-pack" to repair workflow pack issues.'
15151
+ );
15152
+ }
15153
+ if (recParts.length > 0) {
15154
+ recommendation = recParts.join(" ");
14109
15155
  }
14110
15156
  return {
14111
15157
  configValidation,
14112
15158
  obsoleteConfigs,
14113
15159
  schemaAssets: { schema, hash, overall },
15160
+ workflowPack,
14114
15161
  recommendation
14115
15162
  };
14116
15163
  }
@@ -14151,6 +15198,576 @@ async function runConfigSyncSchemaCommand(options) {
14151
15198
  };
14152
15199
  }
14153
15200
 
15201
+ // commands/workflow-pack-sync.ts
15202
+ import { existsSync as existsSync20, readdirSync as readdirSync5 } from "fs";
15203
+ import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile4, readdir as readdir3 } from "fs/promises";
15204
+ import { resolve as resolve5, dirname as dirname6, relative as relative3, normalize as normalize2 } from "path";
15205
+ import { fileURLToPath as fileURLToPath4 } from "url";
15206
+ var __filename4 = fileURLToPath4(import.meta.url);
15207
+ var __dirname4 = dirname6(__filename4);
15208
+ var PROJECT_OWNED_PATHS = [".pourkit/CONTEXT.md", ".pourkit/CONTEXT-MAP.md"];
15209
+ var PROJECT_OWNED_DIRECTORIES = [
15210
+ ".pourkit/docs/adr",
15211
+ ".pourkit/plans",
15212
+ ".pourkit/handoffs"
15213
+ ];
15214
+ var OVERRIDES_DIR = ".pourkit/overrides";
15215
+ var MANAGED_BLOCK_BEGIN3 = "<!-- BEGIN POURKIT MANAGED BLOCK -->\n";
15216
+ var MANAGED_BLOCK_END2 = "\n<!-- END POURKIT MANAGED BLOCK -->";
15217
+ function resolvePackagedManagedPath2(...segments) {
15218
+ const candidates = [resolve5(__dirname4, "..", "managed", ...segments)];
15219
+ return candidates[0];
15220
+ }
15221
+ function resolvePackagedManagedDocPath2(docName) {
15222
+ return resolvePackagedManagedPath2("docs", "agents", docName);
15223
+ }
15224
+ function resolvePackagedReleaseAddonDocPath2(docName) {
15225
+ return resolvePackagedManagedPath2(
15226
+ "addons",
15227
+ "release",
15228
+ "docs",
15229
+ "agents",
15230
+ docName
15231
+ );
15232
+ }
15233
+ function resolvePackagedManagedSkillDir(skillName) {
15234
+ return resolvePackagedManagedPath2("skills", skillName);
15235
+ }
15236
+ function resolvePackagedManagedPromptPath(promptName) {
15237
+ return resolvePackagedManagedPath2("prompts", promptName);
15238
+ }
15239
+ async function readPackagedTextFile2(filePath) {
15240
+ try {
15241
+ return await readFile7(filePath, "utf-8");
15242
+ } catch {
15243
+ return null;
15244
+ }
15245
+ }
15246
+ function isPathContained2(parent, child) {
15247
+ const relativePath = relative3(parent, child);
15248
+ return !relativePath.startsWith("..") && !relativePath.startsWith("../");
15249
+ }
15250
+ function isProjectOwnedPath(relativePath) {
15251
+ for (const owned of PROJECT_OWNED_PATHS) {
15252
+ if (relativePath === owned || relativePath.startsWith(owned + "/")) {
15253
+ return true;
15254
+ }
15255
+ }
15256
+ for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
15257
+ if (relativePath.startsWith(ownedDir + "/") || relativePath === ownedDir + "/") {
15258
+ return true;
15259
+ }
15260
+ }
15261
+ return false;
15262
+ }
15263
+ function getManagedRelativePath(overrideRelativePath) {
15264
+ if (!overrideRelativePath.startsWith(OVERRIDES_DIR + "/")) {
15265
+ return null;
15266
+ }
15267
+ const managedPath = overrideRelativePath.slice(OVERRIDES_DIR.length + 1);
15268
+ if (managedPath.startsWith("skills/") || managedPath.startsWith("docs/") || managedPath.startsWith("prompts/")) {
15269
+ return `.pourkit/managed/${managedPath}`;
15270
+ }
15271
+ return null;
15272
+ }
15273
+ function findOverrideForManagedPath(existingOverrides, targetRelativePath, overridePath) {
15274
+ if (existingOverrides.some(
15275
+ (o) => o === overridePath || o.startsWith(overridePath + "/")
15276
+ )) {
15277
+ return overridePath;
15278
+ }
15279
+ if (existingOverrides.some((o) => {
15280
+ const managedPath = getManagedRelativePath(o);
15281
+ return managedPath === targetRelativePath;
15282
+ })) {
15283
+ return overridePath;
15284
+ }
15285
+ return null;
15286
+ }
15287
+ function checkForPathEscape(cwd, resolvedPath) {
15288
+ const normalizedCwd = normalize2(cwd);
15289
+ const normalizedPath = normalize2(resolvedPath);
15290
+ if (!isPathContained2(normalizedCwd, normalizedPath)) {
15291
+ return `Path escape detected: ${resolvedPath} is outside ${cwd}`;
15292
+ }
15293
+ return null;
15294
+ }
15295
+ async function walkDir3(dir) {
15296
+ const files = [];
15297
+ try {
15298
+ const entries = await readdir3(dir, { withFileTypes: true });
15299
+ for (const entry of entries) {
15300
+ const full = resolve5(dir, entry.name);
15301
+ if (entry.isDirectory()) {
15302
+ files.push(...await walkDir3(full));
15303
+ } else {
15304
+ files.push(full);
15305
+ }
15306
+ }
15307
+ } catch {
15308
+ }
15309
+ return files;
15310
+ }
15311
+ function generateManagedBlockContent() {
15312
+ return [
15313
+ "This repository uses Pourkit.",
15314
+ "",
15315
+ "## Managed operating docs",
15316
+ "",
15317
+ "Follow the managed operating docs under `.pourkit/managed/docs/agents/*`:",
15318
+ "",
15319
+ "- `.pourkit/managed/docs/agents/issue-tracker.md`",
15320
+ "- `.pourkit/managed/docs/agents/triage-labels.md`",
15321
+ "- `.pourkit/managed/docs/agents/naming.md`",
15322
+ "- `.pourkit/managed/docs/agents/git-workflow.md`",
15323
+ "- `.pourkit/managed/docs/agents/commit-style.md`",
15324
+ "- `.pourkit/managed/docs/agents/domain.md`",
15325
+ "",
15326
+ "### Project-owned context",
15327
+ "",
15328
+ "- `.pourkit/CONTEXT.md`",
15329
+ "- `.pourkit/CONTEXT-MAP.md`",
15330
+ "- `.pourkit/docs/adr/*`",
15331
+ "- `.pourkit/plans/*`",
15332
+ "- `.pourkit/handoffs/*`",
15333
+ "",
15334
+ "### Important",
15335
+ "",
15336
+ "- Do not edit `.pourkit/managed/*` unless explicitly updating Pourkit-managed assets.",
15337
+ "- Do not edit generated harness projections directly.",
15338
+ ""
15339
+ ].join("\n");
15340
+ }
15341
+ async function syncFile(cwd, targetRelativePath, sourceContent, errors) {
15342
+ if (sourceContent === null) {
15343
+ return false;
15344
+ }
15345
+ const targetPath = resolve5(cwd, targetRelativePath);
15346
+ const escapeError = checkForPathEscape(cwd, targetPath);
15347
+ if (escapeError) {
15348
+ errors.push(escapeError);
15349
+ return false;
15350
+ }
15351
+ await mkdir7(resolve5(targetPath, ".."), { recursive: true });
15352
+ if (existsSync20(targetPath)) {
15353
+ const existing = await readFile7(targetPath, "utf-8");
15354
+ if (existing === sourceContent) {
15355
+ return false;
15356
+ }
15357
+ }
15358
+ await writeFile4(targetPath, sourceContent, "utf-8");
15359
+ return true;
15360
+ }
15361
+ function walkDirSync(dir) {
15362
+ const result = [];
15363
+ try {
15364
+ const entries = readdirSync5(dir, { withFileTypes: true });
15365
+ for (const entry of entries) {
15366
+ const full = resolve5(dir, entry.name);
15367
+ if (entry.isDirectory()) {
15368
+ result.push(...walkDirSync(full));
15369
+ } else {
15370
+ result.push(full);
15371
+ }
15372
+ }
15373
+ } catch {
15374
+ }
15375
+ return result;
15376
+ }
15377
+ async function detectOverrides(cwd) {
15378
+ const overridesDir = resolve5(cwd, OVERRIDES_DIR);
15379
+ if (!existsSync20(overridesDir)) {
15380
+ return [];
15381
+ }
15382
+ const files = await walkDir3(overridesDir);
15383
+ return files.map((f) => relative3(cwd, f));
15384
+ }
15385
+ async function detectProjectOwnedFiles(cwd) {
15386
+ const found = [];
15387
+ for (const ownedPath of PROJECT_OWNED_PATHS) {
15388
+ const fullPath = resolve5(cwd, ownedPath);
15389
+ if (existsSync20(fullPath)) {
15390
+ found.push(ownedPath);
15391
+ }
15392
+ }
15393
+ for (const ownedDir of PROJECT_OWNED_DIRECTORIES) {
15394
+ const fullDir = resolve5(cwd, ownedDir);
15395
+ if (existsSync20(fullDir)) {
15396
+ const files = await walkDir3(fullDir);
15397
+ for (const file of files) {
15398
+ found.push(relative3(cwd, file));
15399
+ }
15400
+ }
15401
+ }
15402
+ return found;
15403
+ }
15404
+ async function isReleaseWorkflowEnabled(cwd) {
15405
+ try {
15406
+ const configPath = resolve5(cwd, ".pourkit", "config.json");
15407
+ const content = await readFile7(configPath, "utf-8");
15408
+ const parsed = JSON.parse(content);
15409
+ return parsed.releaseWorkflow?.enabled === true;
15410
+ } catch {
15411
+ return false;
15412
+ }
15413
+ }
15414
+ async function runWorkflowPackSyncCommand(options) {
15415
+ const cwd = options.cwd ?? process.cwd();
15416
+ const catalog = getWorkflowPackCatalog();
15417
+ const updated = [];
15418
+ const regeneratedProjections = [];
15419
+ const skippedProjectOwned = [];
15420
+ const overrides = [];
15421
+ const errors = [];
15422
+ const existingOverrides = await detectOverrides(cwd);
15423
+ const existingProjectOwned = await detectProjectOwnedFiles(cwd);
15424
+ for (const docName of catalog.docs) {
15425
+ const targetRelativePath = `.pourkit/managed/docs/agents/${docName}`;
15426
+ if (isProjectOwnedPath(targetRelativePath)) {
15427
+ skippedProjectOwned.push(targetRelativePath);
15428
+ continue;
15429
+ }
15430
+ const overridePath = `.pourkit/overrides/docs/agents/${docName}`;
15431
+ if (findOverrideForManagedPath(
15432
+ existingOverrides,
15433
+ targetRelativePath,
15434
+ overridePath
15435
+ )) {
15436
+ overrides.push(overridePath);
15437
+ continue;
15438
+ }
15439
+ const sourcePath = resolvePackagedManagedDocPath2(docName);
15440
+ const sourceContent = await readPackagedTextFile2(sourcePath);
15441
+ if (sourceContent === null) {
15442
+ errors.push(`Missing packaged managed doc: ${docName}`);
15443
+ continue;
15444
+ }
15445
+ const written = await syncFile(
15446
+ cwd,
15447
+ targetRelativePath,
15448
+ sourceContent,
15449
+ errors
15450
+ );
15451
+ if (written) {
15452
+ updated.push(targetRelativePath);
15453
+ }
15454
+ }
15455
+ const baselineSkills = getBaselineManagedSkillNames();
15456
+ const syncAcc = {
15457
+ updated,
15458
+ regeneratedProjections,
15459
+ skippedProjectOwned,
15460
+ overrides,
15461
+ errors
15462
+ };
15463
+ const syncCtx = { cwd, existingOverrides };
15464
+ for (const skillName of baselineSkills) {
15465
+ await syncSkill(skillName, catalog, syncAcc, syncCtx);
15466
+ }
15467
+ const releaseEnabled = await isReleaseWorkflowEnabled(cwd);
15468
+ if (releaseEnabled) {
15469
+ for (const skillName of catalog.releaseAddonSkills) {
15470
+ await syncAddonSkill(skillName, syncAcc, syncCtx);
15471
+ }
15472
+ }
15473
+ if (releaseEnabled) {
15474
+ for (const docName of catalog.releaseAddonDocs) {
15475
+ const targetRelativePath = `.pourkit/managed/addons/release/docs/agents/${docName}`;
15476
+ const overridePath = `.pourkit/overrides/addons/release/docs/agents/${docName}`;
15477
+ if (findOverrideForManagedPath(
15478
+ existingOverrides,
15479
+ targetRelativePath,
15480
+ overridePath
15481
+ )) {
15482
+ overrides.push(overridePath);
15483
+ continue;
15484
+ }
15485
+ const sourcePath = resolvePackagedReleaseAddonDocPath2(docName);
15486
+ const sourceContent = await readPackagedTextFile2(sourcePath);
15487
+ if (sourceContent === null) {
15488
+ errors.push(`Missing packaged release addon doc: ${docName}`);
15489
+ continue;
15490
+ }
15491
+ const written = await syncFile(
15492
+ cwd,
15493
+ targetRelativePath,
15494
+ sourceContent,
15495
+ errors
15496
+ );
15497
+ if (written) {
15498
+ updated.push(targetRelativePath);
15499
+ }
15500
+ }
15501
+ }
15502
+ for (const promptName of catalog.prompts) {
15503
+ const targetRelativePath = `.pourkit/managed/prompts/${promptName}`;
15504
+ if (isProjectOwnedPath(targetRelativePath)) {
15505
+ skippedProjectOwned.push(targetRelativePath);
15506
+ continue;
15507
+ }
15508
+ const overridePath = `.pourkit/overrides/prompts/${promptName}`;
15509
+ if (findOverrideForManagedPath(
15510
+ existingOverrides,
15511
+ targetRelativePath,
15512
+ overridePath
15513
+ )) {
15514
+ overrides.push(overridePath);
15515
+ continue;
15516
+ }
15517
+ const sourcePath = resolvePackagedManagedPromptPath(promptName);
15518
+ const sourceContent = await readPackagedTextFile2(sourcePath);
15519
+ if (sourceContent === null) {
15520
+ errors.push(`Missing packaged managed prompt: ${promptName}`);
15521
+ continue;
15522
+ }
15523
+ const written = await syncFile(
15524
+ cwd,
15525
+ targetRelativePath,
15526
+ sourceContent,
15527
+ errors
15528
+ );
15529
+ if (written) {
15530
+ updated.push(targetRelativePath);
15531
+ }
15532
+ }
15533
+ const schemaResult = await runConfigSyncSchemaCommand({ cwd });
15534
+ const agentsPath = resolve5(cwd, "AGENTS.md");
15535
+ const managedBlockContent = generateManagedBlockContent();
15536
+ const fullManagedBlock = `${MANAGED_BLOCK_BEGIN3}${managedBlockContent}${MANAGED_BLOCK_END2}`;
15537
+ let agentsUpdated = false;
15538
+ if (existsSync20(agentsPath)) {
15539
+ const existing = await readFile7(agentsPath, "utf-8");
15540
+ const beginIdx = existing.indexOf(MANAGED_BLOCK_BEGIN3);
15541
+ const endIdx = existing.indexOf(MANAGED_BLOCK_END2);
15542
+ if (beginIdx !== -1 && endIdx !== -1) {
15543
+ const beforeBlock = existing.slice(0, beginIdx);
15544
+ const afterBlock = existing.slice(endIdx + MANAGED_BLOCK_END2.length);
15545
+ const newContent = `${beforeBlock}${fullManagedBlock}${afterBlock}`;
15546
+ if (newContent !== existing) {
15547
+ await writeFile4(agentsPath, newContent, "utf-8");
15548
+ agentsUpdated = true;
15549
+ }
15550
+ } else {
15551
+ const newContent = `${existing}
15552
+
15553
+ ${fullManagedBlock}
15554
+ `;
15555
+ if (newContent !== existing) {
15556
+ await writeFile4(agentsPath, newContent, "utf-8");
15557
+ agentsUpdated = true;
15558
+ }
15559
+ }
15560
+ } else {
15561
+ await writeFile4(agentsPath, fullManagedBlock + "\n", "utf-8");
15562
+ agentsUpdated = true;
15563
+ }
15564
+ if (agentsUpdated) {
15565
+ updated.push("AGENTS.md");
15566
+ }
15567
+ const enabledAddons = releaseEnabled ? ["release"] : [];
15568
+ const manifestMeta = buildWorkflowPackMetadata(enabledAddons);
15569
+ const manifestPath = resolve5(cwd, ".pourkit", "manifest.json");
15570
+ let manifestWritten = false;
15571
+ let previousManifestWorkflowPack = void 0;
15572
+ try {
15573
+ const existingRaw = await readFile7(manifestPath, "utf-8").catch(() => null);
15574
+ if (existingRaw) {
15575
+ const existing = JSON.parse(existingRaw);
15576
+ previousManifestWorkflowPack = existing.workflowPack;
15577
+ }
15578
+ } catch {
15579
+ }
15580
+ if (previousManifestWorkflowPack === void 0 || JSON.stringify(previousManifestWorkflowPack) !== JSON.stringify(manifestMeta)) {
15581
+ try {
15582
+ const existingRaw = await readFile7(manifestPath, "utf-8").catch(
15583
+ () => null
15584
+ );
15585
+ let manifest = existingRaw ? JSON.parse(existingRaw) : {};
15586
+ manifest.workflowPack = manifestMeta;
15587
+ await mkdir7(resolve5(manifestPath, ".."), { recursive: true });
15588
+ await writeFile4(
15589
+ manifestPath,
15590
+ JSON.stringify(manifest, null, 2) + "\n",
15591
+ "utf-8"
15592
+ );
15593
+ manifestWritten = true;
15594
+ } catch {
15595
+ errors.push("Failed to write manifest metadata");
15596
+ }
15597
+ }
15598
+ for (const owned of existingProjectOwned) {
15599
+ if (!skippedProjectOwned.includes(owned)) {
15600
+ skippedProjectOwned.push(owned);
15601
+ }
15602
+ }
15603
+ for (const overridePath of existingOverrides) {
15604
+ const displayPath = overridePath;
15605
+ if (!overrides.includes(displayPath)) {
15606
+ overrides.push(displayPath);
15607
+ }
15608
+ }
15609
+ const changed = updated.length > 0 || regeneratedProjections.length > 0 || schemaResult.changed || agentsUpdated || manifestWritten;
15610
+ return {
15611
+ changed,
15612
+ updated,
15613
+ regeneratedProjections,
15614
+ skippedProjectOwned,
15615
+ overrides,
15616
+ errors,
15617
+ schema: schemaResult,
15618
+ manifestWritten
15619
+ };
15620
+ }
15621
+ async function syncSkill(skillName, catalog, acc, ctx) {
15622
+ const { cwd, existingOverrides } = ctx;
15623
+ const {
15624
+ updated,
15625
+ regeneratedProjections,
15626
+ skippedProjectOwned,
15627
+ overrides,
15628
+ errors
15629
+ } = acc;
15630
+ const skillDir = resolvePackagedManagedSkillDir(skillName);
15631
+ const skillFiles = walkDirSync(skillDir);
15632
+ if (skillFiles.length === 0) {
15633
+ errors.push(`Missing packaged managed skill: ${skillName}`);
15634
+ return;
15635
+ }
15636
+ for (const sourceFile of skillFiles) {
15637
+ const relPath = relative3(skillDir, sourceFile);
15638
+ const targetRelativePath = `.pourkit/managed/skills/${skillName}/${relPath}`;
15639
+ if (isProjectOwnedPath(targetRelativePath)) {
15640
+ skippedProjectOwned.push(targetRelativePath);
15641
+ continue;
15642
+ }
15643
+ const overridePath = `.pourkit/overrides/skills/${skillName}/${relPath}`;
15644
+ if (findOverrideForManagedPath(
15645
+ existingOverrides,
15646
+ targetRelativePath,
15647
+ overridePath
15648
+ )) {
15649
+ if (!overrides.includes(overridePath)) {
15650
+ overrides.push(overridePath);
15651
+ }
15652
+ continue;
15653
+ }
15654
+ const sourceContent = await readPackagedTextFile2(sourceFile);
15655
+ if (sourceContent === null) {
15656
+ errors.push(`Cannot read packaged skill file: ${skillName}/${relPath}`);
15657
+ continue;
15658
+ }
15659
+ const written = await syncFile(
15660
+ cwd,
15661
+ targetRelativePath,
15662
+ sourceContent,
15663
+ errors
15664
+ );
15665
+ if (written) {
15666
+ updated.push(targetRelativePath);
15667
+ }
15668
+ const projectionRelativePath = `.agents/skills/${skillName}/${relPath}`;
15669
+ const projectionOverridePath = `.pourkit/overrides/${projectionRelativePath}`;
15670
+ if (existingOverrides.some((o) => o === projectionOverridePath)) {
15671
+ if (!overrides.includes(projectionOverridePath)) {
15672
+ overrides.push(projectionOverridePath);
15673
+ }
15674
+ continue;
15675
+ }
15676
+ const managedSourcePath = `.pourkit/managed/skills/${skillName}/${relPath}`;
15677
+ const projectionContent = buildOpenCodeSkillProjectionContent(
15678
+ managedSourcePath,
15679
+ sourceContent
15680
+ );
15681
+ const projectionWritten = await syncFile(
15682
+ cwd,
15683
+ projectionRelativePath,
15684
+ projectionContent,
15685
+ errors
15686
+ );
15687
+ if (projectionWritten) {
15688
+ regeneratedProjections.push(projectionRelativePath);
15689
+ }
15690
+ }
15691
+ }
15692
+ async function syncAddonSkill(skillName, acc, ctx) {
15693
+ const { cwd, existingOverrides } = ctx;
15694
+ const {
15695
+ updated,
15696
+ regeneratedProjections,
15697
+ skippedProjectOwned,
15698
+ overrides,
15699
+ errors
15700
+ } = acc;
15701
+ const addonSkillDir = resolvePackagedManagedPath2(
15702
+ "addons",
15703
+ "release",
15704
+ "skills",
15705
+ skillName
15706
+ );
15707
+ const skillFiles = walkDirSync(addonSkillDir);
15708
+ if (skillFiles.length === 0) {
15709
+ errors.push(`Missing packaged release addon skill: ${skillName}`);
15710
+ return;
15711
+ }
15712
+ for (const sourceFile of skillFiles) {
15713
+ const relPath = relative3(addonSkillDir, sourceFile);
15714
+ const targetRelativePath = `.pourkit/managed/addons/release/skills/${skillName}/${relPath}`;
15715
+ if (isProjectOwnedPath(targetRelativePath)) {
15716
+ skippedProjectOwned.push(targetRelativePath);
15717
+ continue;
15718
+ }
15719
+ const overridePath = `.pourkit/overrides/addons/release/skills/${skillName}/${relPath}`;
15720
+ if (findOverrideForManagedPath(
15721
+ existingOverrides,
15722
+ targetRelativePath,
15723
+ overridePath
15724
+ )) {
15725
+ if (!overrides.includes(overridePath)) {
15726
+ overrides.push(overridePath);
15727
+ }
15728
+ continue;
15729
+ }
15730
+ const sourceContent = await readPackagedTextFile2(sourceFile);
15731
+ if (sourceContent === null) {
15732
+ errors.push(
15733
+ `Cannot read packaged addon skill file: ${skillName}/${relPath}`
15734
+ );
15735
+ continue;
15736
+ }
15737
+ const written = await syncFile(
15738
+ cwd,
15739
+ targetRelativePath,
15740
+ sourceContent,
15741
+ errors
15742
+ );
15743
+ if (written) {
15744
+ updated.push(targetRelativePath);
15745
+ }
15746
+ const projectionRelativePath = `.agents/skills/${skillName}/${relPath}`;
15747
+ const projectionOverridePath = `.pourkit/overrides/${projectionRelativePath}`;
15748
+ if (existingOverrides.some((o) => o === projectionOverridePath)) {
15749
+ if (!overrides.includes(projectionOverridePath)) {
15750
+ overrides.push(projectionOverridePath);
15751
+ }
15752
+ continue;
15753
+ }
15754
+ const managedSourcePath = `.pourkit/managed/addons/release/skills/${skillName}/${relPath}`;
15755
+ const projectionContent = buildOpenCodeSkillProjectionContent(
15756
+ managedSourcePath,
15757
+ sourceContent
15758
+ );
15759
+ const projectionWritten = await syncFile(
15760
+ cwd,
15761
+ projectionRelativePath,
15762
+ projectionContent,
15763
+ errors
15764
+ );
15765
+ if (projectionWritten) {
15766
+ regeneratedProjections.push(projectionRelativePath);
15767
+ }
15768
+ }
15769
+ }
15770
+
14154
15771
  // providers/github-provider.ts
14155
15772
  var GitHubIssueProvider = class {
14156
15773
  client;
@@ -14688,7 +16305,7 @@ function formatChecks2(checks) {
14688
16305
  init_common();
14689
16306
 
14690
16307
  // execution/sandcastle-execution.ts
14691
- import { existsSync as existsSync21, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
16308
+ import { existsSync as existsSync22, mkdirSync as mkdirSync9, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
14692
16309
  import { join as join23 } from "path";
14693
16310
  import { createWorktree, opencode } from "@ai-hero/sandcastle";
14694
16311
  import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
@@ -14696,14 +16313,14 @@ import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
14696
16313
  // execution/execution-provider.ts
14697
16314
  init_common();
14698
16315
  import { mkdtempSync } from "fs";
14699
- import { writeFile as writeFile4 } from "fs/promises";
16316
+ import { writeFile as writeFile5 } from "fs/promises";
14700
16317
  import { tmpdir } from "os";
14701
- import { dirname as dirname6, join as join22 } from "path";
16318
+ import { dirname as dirname7, join as join22 } from "path";
14702
16319
  async function writeExecutionArtifacts(worktreePath, artifacts) {
14703
16320
  for (const artifact of artifacts) {
14704
16321
  const filePath = join22(worktreePath, artifact.path);
14705
- await ensureDir(dirname6(filePath));
14706
- await writeFile4(filePath, artifact.content, "utf-8");
16322
+ await ensureDir(dirname7(filePath));
16323
+ await writeFile5(filePath, artifact.content, "utf-8");
14707
16324
  }
14708
16325
  }
14709
16326
 
@@ -14713,14 +16330,14 @@ import path7 from "path";
14713
16330
 
14714
16331
  // execution/sandbox-image.ts
14715
16332
  import { createHash as createHash3 } from "crypto";
14716
- import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
16333
+ import { existsSync as existsSync21, readFileSync as readFileSync21 } from "fs";
14717
16334
  import path6 from "path";
14718
16335
  function sandboxImageName(repoRoot2) {
14719
16336
  const dirName = path6.basename(repoRoot2.replace(/[\\/]+$/, "")) || "local";
14720
16337
  const sanitized = dirName.toLowerCase().replace(/[^a-z0-9_.-]/g, "-");
14721
16338
  const baseName = sanitized || "local";
14722
16339
  const dockerfilePath = path6.join(repoRoot2, ".sandcastle", "Dockerfile");
14723
- if (!existsSync20(dockerfilePath)) {
16340
+ if (!existsSync21(dockerfilePath)) {
14724
16341
  return `sandcastle:${baseName}`;
14725
16342
  }
14726
16343
  const fingerprint = createHash3("sha256").update(readFileSync21(dockerfilePath)).digest("hex").slice(0, 8);
@@ -14970,7 +16587,7 @@ function sanitizeBranch(branchName) {
14970
16587
  function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
14971
16588
  return paths.filter((relativePath) => {
14972
16589
  const source = join23(repoRoot2, relativePath);
14973
- if (!existsSync21(source)) {
16590
+ if (!existsSync22(source)) {
14974
16591
  return true;
14975
16592
  }
14976
16593
  try {
@@ -14981,7 +16598,7 @@ function safeCopyToWorktreePaths(paths, repoRoot2, worktreePath) {
14981
16598
  return true;
14982
16599
  }
14983
16600
  const destination = join23(worktreePath, relativePath);
14984
- return !existsSync21(destination);
16601
+ return !existsSync22(destination);
14985
16602
  });
14986
16603
  }
14987
16604
  function formatAgentStreamEvent(event) {
@@ -15201,6 +16818,9 @@ function createCliProgram(version) {
15201
16818
  ).option(
15202
16819
  "--branch-name <name>",
15203
16820
  "branch name for issue-final-review artifacts"
16821
+ ).option(
16822
+ "--base-ref <ref>",
16823
+ "canonical base ref for issue-final-review changedFiles coverage validation"
15204
16824
  ).option("--no-check-conflict-markers", "skip conflict marker scan").option("--cwd <path>", "target repository directory").action(
15205
16825
  (kind, artifactPath, extraPaths, options) => {
15206
16826
  const allowedKinds = /* @__PURE__ */ new Set([
@@ -15243,6 +16863,7 @@ function createCliProgram(version) {
15243
16863
  allowedDecisions: options.allowedDecision,
15244
16864
  issueNumber: options.issueNumber,
15245
16865
  branchName: options.branchName,
16866
+ baseRef: options.baseRef,
15246
16867
  checkConflictMarkers: options.checkConflictMarkers
15247
16868
  });
15248
16869
  console.log(JSON.stringify(result, null, 2));
@@ -15563,7 +17184,10 @@ function createCliProgram(version) {
15563
17184
  const result = runPrdRunListCommand({ repoRoot: targetRepoRoot });
15564
17185
  console.log(JSON.stringify(result, null, 2));
15565
17186
  });
15566
- program.command("init").description("Initialize .pourkit layout in a target repo").option("--dry-run", "print the init plan without applying changes").option("--json", "output machine-readable JSON plan").option("--from-local <path>", "local source repo to copy artifacts from").option("--cwd <path>", "target repository directory").addOption(
17187
+ program.command("init").description("Initialize .pourkit layout in a target repo").option("--dry-run", "print the init plan without applying changes").option("--json", "output machine-readable JSON plan").option(
17188
+ "--from-local <path>",
17189
+ "deprecated: local source repo to copy artifacts from"
17190
+ ).option("--cwd <path>", "target repository directory").addOption(
15567
17191
  new Option(
15568
17192
  "--docs-migration <mode>",
15569
17193
  "docs migration mode: copy, move, skip"
@@ -15603,7 +17227,7 @@ function createCliProgram(version) {
15603
17227
  const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
15604
17228
  const report = await runDoctorCommand({ cwd: targetRepoRoot });
15605
17229
  console.log(JSON.stringify(report, null, 2));
15606
- if (!report.configValidation.ok || report.obsoleteConfigs.length > 0 || report.schemaAssets.overall !== "fresh") {
17230
+ if (!report.configValidation.ok || report.obsoleteConfigs.length > 0 || report.schemaAssets.overall !== "fresh" || report.workflowPack.status === "failed") {
15607
17231
  process.exitCode = 1;
15608
17232
  }
15609
17233
  });
@@ -15619,6 +17243,24 @@ function createCliProgram(version) {
15619
17243
  console.log("Schema assets are up to date.");
15620
17244
  }
15621
17245
  });
17246
+ const syncCommand = program.command("sync").description("Sync commands for refreshing managed assets");
17247
+ syncCommand.command("workflow-pack").description("Refresh managed workflow pack assets from packaged sources").option("--cwd <path>", "target repository directory").action(async (options) => {
17248
+ const targetRepoRoot = options.cwd ? repoRoot(options.cwd) : repoRoot();
17249
+ const result = await runWorkflowPackSyncCommand({ cwd: targetRepoRoot });
17250
+ if (result.changed) {
17251
+ console.log(
17252
+ `Workflow pack sync complete: ${result.updated.length} updated, ${result.regeneratedProjections.length} projections regenerated, ${result.overrides.length} overrides, ${result.skippedProjectOwned.length} project-owned files skipped.`
17253
+ );
17254
+ } else {
17255
+ console.log("Workflow pack is up to date.");
17256
+ }
17257
+ if (result.errors.length > 0) {
17258
+ for (const err of result.errors) {
17259
+ console.error(` Error: ${err}`);
17260
+ }
17261
+ process.exitCode = 1;
17262
+ }
17263
+ });
15622
17264
  const serena = program.command("serena").description("Serena baseline and sidecar commands");
15623
17265
  serena.command("init").requiredOption("--target <name>", "target name").option("--cwd <path>", "target repository directory").action(async (options) => {
15624
17266
  await runSerenaInitCommand({
@@ -15744,11 +17386,11 @@ function createCliProgram(version) {
15744
17386
  return program;
15745
17387
  }
15746
17388
  async function resolveCliVersion() {
15747
- if (isPackageVersion("0.0.0-next-20260615184943")) {
15748
- return "0.0.0-next-20260615184943";
17389
+ if (isPackageVersion("0.0.0-next-20260617195445")) {
17390
+ return "0.0.0-next-20260617195445";
15749
17391
  }
15750
- if (isReleaseVersion("0.0.0-next-20260615184943")) {
15751
- return "0.0.0-next-20260615184943";
17392
+ if (isReleaseVersion("0.0.0-next-20260617195445")) {
17393
+ return "0.0.0-next-20260617195445";
15752
17394
  }
15753
17395
  try {
15754
17396
  const root = repoRoot();