@danmoisan/drm-copilot-mcp 1.0.24 → 1.0.27

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 (68) hide show
  1. package/out/mcp-server.js +1045 -214
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agents/feature-review.md +5 -3
  4. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +11 -4
  5. package/resources/claude-customizations/.claude/agents/parallel-planner.md +5 -2
  6. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +28 -8
  7. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +109 -5
  8. package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +390 -0
  9. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +28 -8
  10. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +117 -46
  11. package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +115 -3
  12. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +105 -2
  13. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +32 -52
  14. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +107 -99
  15. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +295 -0
  16. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +9 -3
  17. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +312 -0
  18. package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +392 -0
  19. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +500 -0
  20. package/resources/claude-customizations/.claude/lib/mermaid/MermaidGrammar.psm1 +491 -0
  21. package/resources/claude-customizations/.claude/lib/mermaid/MermaidLineScanner.psm1 +488 -0
  22. package/resources/claude-customizations/.claude/lib/mermaid/MermaidMarkdownFences.psm1 +298 -0
  23. package/resources/claude-customizations/.claude/lib/mermaid/MermaidValidation.psm1 +496 -0
  24. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +58 -67
  25. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCheckpointValue.psm1 +383 -0
  26. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexModelReceipts.psm1 +297 -0
  27. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexTopologyReceipts.psm1 +298 -0
  28. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1 +232 -43
  29. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1 +416 -0
  30. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateModelReceipts.psm1 +366 -0
  31. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +408 -0
  32. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +428 -0
  33. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingMatrix.psm1 +377 -0
  34. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateUnconditional.psm1 +166 -0
  35. package/resources/claude-customizations/.claude/rules/general-unit-test.md +1 -1
  36. package/resources/claude-customizations/.claude/rules/mermaid.md +142 -0
  37. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +88 -3
  38. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +116 -0
  39. package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
  40. package/resources/claude-customizations/.claude/rules/quality-tiers.md +3 -3
  41. package/resources/claude-customizations/.claude/settings.json +5 -0
  42. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +15 -0
  43. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  44. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +6 -0
  45. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -4
  46. package/resources/claude-customizations/.claude/skills/mermaid-diagram/SKILL.md +184 -0
  47. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/c4.md +50 -0
  48. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/class.md +63 -0
  49. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/er.md +56 -0
  50. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/flowchart.md +68 -0
  51. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/gantt.md +51 -0
  52. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/other-types.md +82 -0
  53. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/pie.md +32 -0
  54. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/sequence.md +63 -0
  55. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/state.md +49 -0
  56. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +10 -5
  57. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +116 -41
  58. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +95 -13
  59. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +7 -3
  60. package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +1 -1
  61. package/resources/claude-customizations/config/blast-radius.json +9 -3
  62. package/resources/claude-customizations/pack-manifests/core.json +31 -1
  63. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  64. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +1 -1
  65. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +3 -3
  66. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  67. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  68. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +37 -1
package/out/mcp-server.js CHANGED
@@ -6904,12 +6904,12 @@ var require_dist = __commonJS({
6904
6904
  throw new Error(`Unknown format "${name}"`);
6905
6905
  return f;
6906
6906
  };
6907
- function addFormats(ajv, list, fs9, exportName) {
6907
+ function addFormats(ajv, list, fs10, exportName) {
6908
6908
  var _a3;
6909
6909
  var _b;
6910
6910
  (_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6911
6911
  for (const f of list)
6912
- ajv.addFormat(f, fs9[f]);
6912
+ ajv.addFormat(f, fs10[f]);
6913
6913
  }
6914
6914
  module2.exports = exports2 = formatsPlugin;
6915
6915
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -6932,7 +6932,7 @@ __export(mcp_server_exports, {
6932
6932
  main: () => main
6933
6933
  });
6934
6934
  module.exports = __toCommonJS(mcp_server_exports);
6935
- var fs8 = __toESM(require("node:fs"));
6935
+ var fs9 = __toESM(require("node:fs"));
6936
6936
  var path10 = __toESM(require("node:path"));
6937
6937
 
6938
6938
  // node_modules/zod/v4/core/core.js
@@ -17260,7 +17260,8 @@ function toMcpToolResult(result) {
17260
17260
  ...result.assetId === void 0 ? {} : { asset_id: result.assetId },
17261
17261
  ...result.bundledSourcePath === void 0 ? {} : { bundled_source_path: result.bundledSourcePath },
17262
17262
  ...result.destinationPath === void 0 ? {} : { destination_path: result.destinationPath },
17263
- ...result.renderedTree === void 0 ? {} : { rendered_tree: result.renderedTree }
17263
+ ...result.renderedTree === void 0 ? {} : { rendered_tree: result.renderedTree },
17264
+ ...result.warnings === void 0 ? {} : { warnings: result.warnings }
17264
17265
  };
17265
17266
  }
17266
17267
  function toFailureToolResult(tool, workspaceRoot, error2) {
@@ -17907,11 +17908,11 @@ function relativeToPosix(path11, root) {
17907
17908
  }
17908
17909
  return null;
17909
17910
  }
17910
- function enumerateSourceFiles(fs9, sourceRoot, rootFolders) {
17911
+ function enumerateSourceFiles(fs10, sourceRoot, rootFolders) {
17911
17912
  const orderedFiles = [];
17912
17913
  for (const root of rootFolders) {
17913
17914
  const rootPath = joinPosix2(sourceRoot, root);
17914
- const rootFiles = fs9.listFiles(rootPath);
17915
+ const rootFiles = fs10.listFiles(rootPath);
17915
17916
  const sorted = [...rootFiles].sort((left, right) => {
17916
17917
  const leftRel = relativeToPosix(left, rootPath) ?? left;
17917
17918
  const rightRel = relativeToPosix(right, rootPath) ?? right;
@@ -17921,8 +17922,8 @@ function enumerateSourceFiles(fs9, sourceRoot, rootFolders) {
17921
17922
  }
17922
17923
  return orderedFiles;
17923
17924
  }
17924
- function validateDestination(destinationRoot, repoRoot, fs9) {
17925
- if (!fs9.isDir(destinationRoot)) {
17925
+ function validateDestination(destinationRoot, repoRoot, fs10) {
17926
+ if (!fs10.isDir(destinationRoot)) {
17926
17927
  throw new Error(
17927
17928
  `Invalid destination: destination directory does not exist: ${destinationRoot}`
17928
17929
  );
@@ -17985,22 +17986,22 @@ function stringifySorted(value, indent) {
17985
17986
  };
17986
17987
  return JSON.stringify(sortKeys(value), null, indent);
17987
17988
  }
17988
- function writeSummaryArtifact(fs9, summary, artifactRoot, artifactDirectory) {
17989
+ function writeSummaryArtifact(fs10, summary, artifactRoot, artifactDirectory) {
17989
17990
  const artifactPath = buildArtifactPath(
17990
17991
  summary.startedAt,
17991
17992
  artifactRoot,
17992
17993
  artifactDirectory
17993
17994
  );
17994
17995
  const parent = artifactPath.slice(0, artifactPath.lastIndexOf("/"));
17995
- fs9.ensureDir(parent);
17996
- fs9.writeTextFile(artifactPath, renderPushDownSummary(summary));
17996
+ fs10.ensureDir(parent);
17997
+ fs10.writeTextFile(artifactPath, renderPushDownSummary(summary));
17997
17998
  return artifactPath;
17998
17999
  }
17999
18000
  function pushDownCustomizations(options) {
18000
18001
  const {
18001
18002
  repoRoot,
18002
18003
  destinationRoot,
18003
- fs: fs9,
18004
+ fs: fs10,
18004
18005
  sourceRoot,
18005
18006
  artifactRoot,
18006
18007
  rootFolders,
@@ -18014,7 +18015,7 @@ function pushDownCustomizations(options) {
18014
18015
  const effectiveArtifactDir = artifactDirectory ?? ARTIFACT_DIRECTORY;
18015
18016
  const rewrite = rewriteReferences ?? rewriteTextReferences;
18016
18017
  const now = clock ?? (() => /* @__PURE__ */ new Date());
18017
- validateDestination(destinationRoot, repoRoot, fs9);
18018
+ validateDestination(destinationRoot, repoRoot, fs10);
18018
18019
  const startedAt = now();
18019
18020
  let createdCount = 0;
18020
18021
  let overwrittenCount = 0;
@@ -18023,7 +18024,7 @@ function pushDownCustomizations(options) {
18023
18024
  const unmatchedReferences = [];
18024
18025
  const fileResults = [];
18025
18026
  for (const sourcePath of enumerateSourceFiles(
18026
- fs9,
18027
+ fs10,
18027
18028
  effectiveSource,
18028
18029
  effectiveRoots
18029
18030
  )) {
@@ -18032,7 +18033,7 @@ function pushDownCustomizations(options) {
18032
18033
  continue;
18033
18034
  }
18034
18035
  const destinationPath = joinPosix2(destinationRoot, relativePath2);
18035
- const destinationStatus = fs9.isFile(
18036
+ const destinationStatus = fs10.isFile(
18036
18037
  destinationPath
18037
18038
  ) ? "overwritten" : "created";
18038
18039
  if (destinationStatus === "created") {
@@ -18040,7 +18041,7 @@ function pushDownCustomizations(options) {
18040
18041
  } else {
18041
18042
  overwrittenCount += 1;
18042
18043
  }
18043
- const sourceText = fs9.readTextFile(sourcePath);
18044
+ const sourceText = fs10.readTextFile(sourcePath);
18044
18045
  const [rewrittenText, rewrittenDelta, placeholderDelta, unmatched] = rewrite(sourceText);
18045
18046
  rewrittenReferenceCount += rewrittenDelta;
18046
18047
  placeholderRewriteCount += placeholderDelta;
@@ -18053,8 +18054,8 @@ function pushDownCustomizations(options) {
18053
18054
  0,
18054
18055
  destinationPath.lastIndexOf("/")
18055
18056
  );
18056
- fs9.ensureDir(destParent);
18057
- fs9.writeTextFile(destinationPath, rewrittenText);
18057
+ fs10.ensureDir(destParent);
18058
+ fs10.writeTextFile(destinationPath, rewrittenText);
18058
18059
  fileResults.push({
18059
18060
  relativePath: relativePath2,
18060
18061
  destinationStatus,
@@ -18078,7 +18079,7 @@ function pushDownCustomizations(options) {
18078
18079
  artifactPath: ""
18079
18080
  };
18080
18081
  const artifactPath = writeSummaryArtifact(
18081
- fs9,
18082
+ fs10,
18082
18083
  provisionalSummary,
18083
18084
  effectiveArtifact,
18084
18085
  effectiveArtifactDir
@@ -18142,7 +18143,7 @@ function joinPosix3(dir, name) {
18142
18143
  const normalizedDir = dir.replace(/\\/g, "/").replace(/\/+$/, "");
18143
18144
  return normalizedDir === "" ? name : `${normalizedDir}/${name}`;
18144
18145
  }
18145
- function loadPackManifests(manifestDir, selectedPackNames, fs9) {
18146
+ function loadPackManifests(manifestDir, selectedPackNames, fs10) {
18146
18147
  const unknown2 = [...selectedPackNames].filter(
18147
18148
  (name) => !MANIFEST_PACK_NAMES.has(name)
18148
18149
  );
@@ -18154,14 +18155,14 @@ function loadPackManifests(manifestDir, selectedPackNames, fs9) {
18154
18155
  const manifests = /* @__PURE__ */ new Map();
18155
18156
  for (const name of [...namesToLoad].sort()) {
18156
18157
  const manifestPath = joinPosix3(manifestDir, `${name}.json`);
18157
- if (!fs9.isFile(manifestPath)) {
18158
+ if (!fs10.isFile(manifestPath)) {
18158
18159
  throw new ManifestError(
18159
18160
  `Codex pack manifest is missing for pack '${name}': ${manifestPath}`
18160
18161
  );
18161
18162
  }
18162
18163
  manifests.set(
18163
18164
  name,
18164
- parseManifest(name, manifestPath, fs9.readTextFile(manifestPath))
18165
+ parseManifest(name, manifestPath, fs10.readTextFile(manifestPath))
18165
18166
  );
18166
18167
  }
18167
18168
  return manifests;
@@ -18418,7 +18419,7 @@ var RoutingConfigFileSystem = class {
18418
18419
  this.inner.ensureDir(path11);
18419
18420
  }
18420
18421
  };
18421
- function resolvePublishedPaths(packs, csharpVariant, bundleRoot, fs9) {
18422
+ function resolvePublishedPaths(packs, csharpVariant, bundleRoot, fs10) {
18422
18423
  const manifestPacks = resolveManifestPackNames(packs ?? null, csharpVariant);
18423
18424
  if (manifestPacks === null || manifestPacks.size === 0) {
18424
18425
  return null;
@@ -18426,7 +18427,7 @@ function resolvePublishedPaths(packs, csharpVariant, bundleRoot, fs9) {
18426
18427
  const manifests = loadPackManifests(
18427
18428
  joinPosix4(bundleRoot, PACK_MANIFEST_SUBDIR),
18428
18429
  manifestPacks,
18429
- fs9
18430
+ fs10
18430
18431
  );
18431
18432
  const published = computePublishedPaths(manifestPacks, manifests) ?? /* @__PURE__ */ new Set();
18432
18433
  assertSingleCsharpToolchain(published, manifestPacks);
@@ -18531,18 +18532,18 @@ function joinPosix5(dir, name) {
18531
18532
  const normalizedDir = dir.replace(/\\/g, "/").replace(/\/+$/, "");
18532
18533
  return normalizedDir === "" ? name : `${normalizedDir}/${name}`;
18533
18534
  }
18534
- function loadPackManifests2(manifestDir, selectedPackNames, fs9) {
18535
+ function loadPackManifests2(manifestDir, selectedPackNames, fs10) {
18535
18536
  const namesToLoad = new Set(selectedPackNames);
18536
18537
  namesToLoad.add(CORE_PACK_NAME2);
18537
18538
  const manifests = /* @__PURE__ */ new Map();
18538
18539
  for (const name of [...namesToLoad].sort()) {
18539
18540
  const manifestPath = joinPosix5(manifestDir, `${name}.json`);
18540
- if (!fs9.isFile(manifestPath)) {
18541
+ if (!fs10.isFile(manifestPath)) {
18541
18542
  throw new ManifestError2(
18542
18543
  `Pack manifest is missing for pack '${name}': ${manifestPath}`
18543
18544
  );
18544
18545
  }
18545
- const rawText = fs9.readTextFile(manifestPath);
18546
+ const rawText = fs10.readTextFile(manifestPath);
18546
18547
  manifests.set(name, parseManifest2(name, manifestPath, rawText));
18547
18548
  }
18548
18549
  return manifests;
@@ -18962,6 +18963,332 @@ var RoutingMergeFileSystem = class {
18962
18963
  }
18963
18964
  };
18964
18965
 
18966
+ // ../../extensions/drm-copilot/src/lib/push-down/claude-blast-radius-derive.ts
18967
+ var fs3 = __toESM(require("node:fs"));
18968
+
18969
+ // ../../extensions/drm-copilot/src/lib/push-down/claude-blast-radius-derive-core.ts
18970
+ var BLAST_RADIUS_RELATIVE_PATH = "config/blast-radius.json";
18971
+ var MANIFEST_FILENAMES = /* @__PURE__ */ new Set([
18972
+ "build.gradle",
18973
+ "build.gradle.kts",
18974
+ "Cargo.toml",
18975
+ "go.mod",
18976
+ "package.json",
18977
+ "pom.xml",
18978
+ "pyproject.toml",
18979
+ "setup.py"
18980
+ ]);
18981
+ var MANIFEST_SUFFIXES = [
18982
+ ".csproj",
18983
+ ".fsproj",
18984
+ ".vbproj",
18985
+ ".sln",
18986
+ ".slnx"
18987
+ ];
18988
+ var EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([
18989
+ "__pycache__",
18990
+ "artifacts",
18991
+ "bin",
18992
+ "build",
18993
+ "coverage",
18994
+ "dist",
18995
+ "doc",
18996
+ "docs",
18997
+ "node_modules",
18998
+ "obj",
18999
+ "out",
19000
+ "target",
19001
+ "test",
19002
+ "tests",
19003
+ "venv"
19004
+ ]);
19005
+ var SCAN_DEPTH_LIMIT = 3;
19006
+ var PAYLOAD_MODULES = {
19007
+ "claude-runtime": [".claude/**"],
19008
+ config: ["config/**"]
19009
+ };
19010
+ var FORBIDDEN_GLOBS = [
19011
+ "**",
19012
+ "docs/**",
19013
+ "tests/**"
19014
+ ];
19015
+ var CARRIED_KEYS = [
19016
+ "version",
19017
+ "shared_surfaces",
19018
+ "shared_surface_globs",
19019
+ "over_breadth_fraction",
19020
+ "mandate_reads"
19021
+ ];
19022
+ var BlastRadiusDeriveError = class extends Error {
19023
+ /** Destination-relative path of the document that failed to parse. */
19024
+ path;
19025
+ /**
19026
+ * @param path Path named in the message.
19027
+ * @param detail Parser detail appended to the message.
19028
+ */
19029
+ constructor(path11, detail) {
19030
+ super(
19031
+ `Bundled blast-radius document is not valid JSON and was not written: ${path11} (${detail})`
19032
+ );
19033
+ this.name = "BlastRadiusDeriveError";
19034
+ this.path = path11;
19035
+ }
19036
+ };
19037
+ var BlastRadiusGuardError = class extends Error {
19038
+ /** The forbidden glob that tripped the guard. */
19039
+ glob;
19040
+ /** Name of the module that would have carried the forbidden glob. */
19041
+ moduleName;
19042
+ /**
19043
+ * @param moduleName Module the forbidden glob was assigned to.
19044
+ * @param glob The forbidden glob.
19045
+ */
19046
+ constructor(moduleName, glob) {
19047
+ super(
19048
+ `Derived blast-radius module ${moduleName} would emit the forbidden glob ${glob}; the derivation was aborted before writing.`
19049
+ );
19050
+ this.name = "BlastRadiusGuardError";
19051
+ this.glob = glob;
19052
+ this.moduleName = moduleName;
19053
+ }
19054
+ };
19055
+ function compareOrdinal(left, right) {
19056
+ return left < right ? -1 : left > right ? 1 : 0;
19057
+ }
19058
+ function isExcludedDirectoryName(name) {
19059
+ return name.startsWith(".") || EXCLUDED_DIR_NAMES.has(name);
19060
+ }
19061
+ function isManifestFileName(fileName) {
19062
+ if (MANIFEST_FILENAMES.has(fileName)) {
19063
+ return true;
19064
+ }
19065
+ return MANIFEST_SUFFIXES.some((suffix2) => fileName.endsWith(suffix2));
19066
+ }
19067
+ function classifyProjectDirectories(observations) {
19068
+ const projectPaths = [];
19069
+ for (const observation of observations) {
19070
+ if (observation.relativePath === "") {
19071
+ continue;
19072
+ }
19073
+ if (observation.fileNames.some(isManifestFileName)) {
19074
+ projectPaths.push(observation.relativePath);
19075
+ }
19076
+ }
19077
+ return projectPaths.sort(compareOrdinal);
19078
+ }
19079
+ function pruneAncestors(paths) {
19080
+ return paths.filter(
19081
+ (candidate) => !paths.some(
19082
+ (other) => other !== candidate && other.startsWith(`${candidate}/`)
19083
+ )
19084
+ );
19085
+ }
19086
+ function topLevelDirectories(observations) {
19087
+ const names = [];
19088
+ for (const observation of observations) {
19089
+ const relativePath2 = observation.relativePath;
19090
+ if (relativePath2 !== "" && !relativePath2.includes("/")) {
19091
+ names.push(relativePath2);
19092
+ }
19093
+ }
19094
+ return names.sort(compareOrdinal);
19095
+ }
19096
+ function assembleModules(derivedPaths) {
19097
+ const combined = /* @__PURE__ */ new Map();
19098
+ for (const path11 of derivedPaths) {
19099
+ combined.set(path11, [`${path11}/**`]);
19100
+ }
19101
+ for (const [name, globs] of Object.entries(PAYLOAD_MODULES)) {
19102
+ combined.set(name, [...globs]);
19103
+ }
19104
+ const modules = {};
19105
+ for (const name of [...combined.keys()].sort(compareOrdinal)) {
19106
+ const globs = combined.get(name);
19107
+ if (globs !== void 0) {
19108
+ modules[name] = globs;
19109
+ }
19110
+ }
19111
+ return modules;
19112
+ }
19113
+ function assertNoForbiddenGlob(modules) {
19114
+ for (const [name, globs] of Object.entries(modules)) {
19115
+ for (const glob of globs) {
19116
+ if (FORBIDDEN_GLOBS.includes(glob)) {
19117
+ throw new BlastRadiusGuardError(name, glob);
19118
+ }
19119
+ }
19120
+ }
19121
+ }
19122
+ function parseSourceDocument(text) {
19123
+ let parsed;
19124
+ try {
19125
+ parsed = JSON.parse(text);
19126
+ } catch (error2) {
19127
+ const detail = error2 instanceof Error ? error2.message : String(error2);
19128
+ throw new BlastRadiusDeriveError(BLAST_RADIUS_RELATIVE_PATH, detail);
19129
+ }
19130
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
19131
+ throw new BlastRadiusDeriveError(
19132
+ BLAST_RADIUS_RELATIVE_PATH,
19133
+ "document root is not a JSON object"
19134
+ );
19135
+ }
19136
+ return parsed;
19137
+ }
19138
+ function deriveDestinationModuleMap(observations, sourceDocumentText) {
19139
+ const source = parseSourceDocument(sourceDocumentText);
19140
+ const projectPaths = pruneAncestors(classifyProjectDirectories(observations));
19141
+ const derivedPaths = projectPaths.length > 0 ? projectPaths : topLevelDirectories(observations);
19142
+ const modules = assembleModules(derivedPaths);
19143
+ assertNoForbiddenGlob(modules);
19144
+ const document = {
19145
+ version: source[CARRIED_KEYS[0]],
19146
+ shared_surfaces: source[CARRIED_KEYS[1]],
19147
+ shared_surface_globs: source[CARRIED_KEYS[2]],
19148
+ mandate_reads: source[CARRIED_KEYS[4]],
19149
+ modules,
19150
+ over_breadth_fraction: source[CARRIED_KEYS[3]]
19151
+ };
19152
+ return `${JSON.stringify(document, null, 2)}
19153
+ `;
19154
+ }
19155
+
19156
+ // ../../extensions/drm-copilot/src/lib/push-down/claude-blast-radius-derive.ts
19157
+ function normalizePosix5(value) {
19158
+ return value.replace(/\\/g, "/").replace(/\/+$/, "");
19159
+ }
19160
+ function relativeToPosix5(path11, root) {
19161
+ const normalizedPath = normalizePosix5(path11);
19162
+ const normalizedRoot = normalizePosix5(root);
19163
+ if (normalizedPath === normalizedRoot) {
19164
+ return "";
19165
+ }
19166
+ const prefix = `${normalizedRoot}/`;
19167
+ return normalizedPath.startsWith(prefix) ? normalizedPath.slice(prefix.length) : null;
19168
+ }
19169
+ var realDirectoryLister = (root) => {
19170
+ let entries;
19171
+ try {
19172
+ entries = fs3.readdirSync(root, { withFileTypes: true });
19173
+ } catch {
19174
+ return [];
19175
+ }
19176
+ return entries.map((entry) => ({ name: entry.name, isDir: entry.isDirectory() })).sort(
19177
+ (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0
19178
+ );
19179
+ };
19180
+ function listTolerantly(lister, path11) {
19181
+ try {
19182
+ return lister(path11);
19183
+ } catch {
19184
+ return [];
19185
+ }
19186
+ }
19187
+ function collectDestinationObservations(destinationRoot, lister) {
19188
+ const root = normalizePosix5(destinationRoot);
19189
+ const observations = [];
19190
+ let queue = [
19191
+ { path: root, relativePath: "" }
19192
+ ];
19193
+ for (let depth = 1; depth <= SCAN_DEPTH_LIMIT && queue.length > 0; depth++) {
19194
+ const nextQueue = [];
19195
+ for (const current of queue) {
19196
+ const entries = listTolerantly(lister, current.path);
19197
+ const fileNames = [];
19198
+ for (const entry of entries) {
19199
+ if (!entry.isDir) {
19200
+ fileNames.push(entry.name);
19201
+ continue;
19202
+ }
19203
+ if (isExcludedDirectoryName(entry.name)) {
19204
+ continue;
19205
+ }
19206
+ nextQueue.push({
19207
+ path: `${current.path}/${entry.name}`,
19208
+ relativePath: current.relativePath === "" ? entry.name : `${current.relativePath}/${entry.name}`
19209
+ });
19210
+ }
19211
+ observations.push({
19212
+ relativePath: current.relativePath,
19213
+ fileNames
19214
+ });
19215
+ }
19216
+ queue = nextQueue;
19217
+ }
19218
+ return observations;
19219
+ }
19220
+ var BlastRadiusDeriveFileSystem = class {
19221
+ inner;
19222
+ destinationRoot;
19223
+ deriveRelativePath;
19224
+ lister;
19225
+ /**
19226
+ * @param inner The wrapped adapter performing real I/O.
19227
+ * @param destinationRoot Destination workspace root (POSIX path).
19228
+ * @param lister Shallow directory lister; defaults to the real filesystem.
19229
+ * @param deriveRelativePath Destination-relative path to derive; defaults to
19230
+ * `config/blast-radius.json`.
19231
+ */
19232
+ constructor(inner, destinationRoot, lister = realDirectoryLister, deriveRelativePath = BLAST_RADIUS_RELATIVE_PATH) {
19233
+ this.inner = inner;
19234
+ this.destinationRoot = normalizePosix5(destinationRoot);
19235
+ this.lister = lister;
19236
+ this.deriveRelativePath = deriveRelativePath;
19237
+ }
19238
+ /** @inheritdoc */
19239
+ listFiles(root) {
19240
+ return this.inner.listFiles(root);
19241
+ }
19242
+ /** @inheritdoc */
19243
+ isDir(path11) {
19244
+ return this.inner.isDir(path11);
19245
+ }
19246
+ /** @inheritdoc */
19247
+ isFile(path11) {
19248
+ return this.inner.isFile(path11);
19249
+ }
19250
+ /** @inheritdoc */
19251
+ readTextFile(path11) {
19252
+ return this.inner.readTextFile(path11);
19253
+ }
19254
+ /** @inheritdoc */
19255
+ ensureDir(path11) {
19256
+ this.inner.ensureDir(path11);
19257
+ }
19258
+ /**
19259
+ * Write a file, deriving the one configured blast-radius path.
19260
+ *
19261
+ * @param path Absolute destination POSIX path.
19262
+ * @param content Bundled source content the engine wants to publish, used as
19263
+ * the derivation's base document rather than written verbatim.
19264
+ * @throws BlastRadiusDeriveError When the bundled document is not parseable.
19265
+ * @throws BlastRadiusGuardError When a forbidden glob would be emitted. Both
19266
+ * errors are raised before the inner write, so the destination bytes are
19267
+ * left untouched.
19268
+ */
19269
+ writeTextFile(path11, content) {
19270
+ if (!this.isDeriveTarget(path11)) {
19271
+ this.inner.writeTextFile(path11, content);
19272
+ return;
19273
+ }
19274
+ const observations = collectDestinationObservations(
19275
+ this.destinationRoot,
19276
+ this.lister
19277
+ );
19278
+ const derived = deriveDestinationModuleMap(observations, content);
19279
+ this.inner.writeTextFile(path11, derived);
19280
+ }
19281
+ /**
19282
+ * Return whether a destination path is the configured derivation target.
19283
+ *
19284
+ * @param path Absolute destination POSIX path.
19285
+ * @returns True when the path resolves to the derive-target relative path.
19286
+ */
19287
+ isDeriveTarget(path11) {
19288
+ return relativeToPosix5(path11, this.destinationRoot) === this.deriveRelativePath;
19289
+ }
19290
+ };
19291
+
18965
19292
  // ../../extensions/drm-copilot/src/lib/push-down/claude-customizations.ts
18966
19293
  var ARTIFACT_DIRECTORY4 = "artifacts/claude-customizations";
18967
19294
  var ROOT_FOLDERS2 = [".claude", "config"];
@@ -18979,7 +19306,7 @@ function joinPosix7(root, relative2) {
18979
19306
  const normalizedRelative = relative2.replace(/\\/g, "/").replace(/^\/+/, "");
18980
19307
  return normalizedRoot === "" ? normalizedRelative : `${normalizedRoot}/${normalizedRelative}`;
18981
19308
  }
18982
- function resolvePublishedPaths2(packs, bundleRoot, fs9) {
19309
+ function resolvePublishedPaths2(packs, bundleRoot, fs10) {
18983
19310
  if (packs === null || packs.size === 0) {
18984
19311
  return null;
18985
19312
  }
@@ -18987,7 +19314,7 @@ function resolvePublishedPaths2(packs, bundleRoot, fs9) {
18987
19314
  const manifests = loadPackManifests2(
18988
19315
  manifestDir,
18989
19316
  packs,
18990
- fs9
19317
+ fs10
18991
19318
  );
18992
19319
  const published = computePublishedPaths2(packs, manifests);
18993
19320
  const effectivePublished = published ?? /* @__PURE__ */ new Set();
@@ -18998,29 +19325,35 @@ function pushDownCustomizations4(options) {
18998
19325
  const {
18999
19326
  repoRoot,
19000
19327
  destinationRoot,
19001
- fs: fs9,
19328
+ fs: fs10,
19002
19329
  sourceRoot,
19003
19330
  artifactRoot,
19004
19331
  packs,
19005
19332
  csharpVariant,
19006
19333
  memoryMode,
19007
19334
  bundleRoot,
19008
- clock
19335
+ clock,
19336
+ listEntries
19009
19337
  } = options;
19010
19338
  const effectiveSource = sourceRoot ?? repoRoot;
19011
19339
  const effectiveBundle = bundleRoot ?? joinPosix7(effectiveSource, BUNDLE_ROOT_RELATIVE_DIR);
19012
19340
  const publishedPaths = resolvePublishedPaths2(
19013
19341
  packs ?? null,
19014
19342
  effectiveBundle,
19015
- fs9
19343
+ fs10
19016
19344
  );
19017
19345
  const mergingFs = new RoutingMergeFileSystem(
19018
- fs9,
19346
+ fs10,
19019
19347
  destinationRoot,
19020
19348
  ROUTING_MERGE_RELATIVE_PATH
19021
19349
  );
19022
- const excludingFs = new ExcludingFileSystem(
19350
+ const derivingFs = listEntries === void 0 ? new BlastRadiusDeriveFileSystem(mergingFs, destinationRoot) : new BlastRadiusDeriveFileSystem(
19023
19351
  mergingFs,
19352
+ destinationRoot,
19353
+ listEntries
19354
+ );
19355
+ const excludingFs = new ExcludingFileSystem(
19356
+ derivingFs,
19024
19357
  repoRoot,
19025
19358
  EXCLUDED_RELATIVE_PATHS,
19026
19359
  {
@@ -19178,7 +19511,7 @@ function runPushDownClaudeCustomizations(input, deps) {
19178
19511
  var path7 = __toESM(require("node:path"));
19179
19512
 
19180
19513
  // ../../extensions/drm-copilot/src/policy-audit-template-assets.ts
19181
- var fs3 = __toESM(require("node:fs"));
19514
+ var fs4 = __toESM(require("node:fs"));
19182
19515
  var path5 = __toESM(require("node:path"));
19183
19516
  var POLICY_AUDIT_TEMPLATE_ASSET_METADATA = {
19184
19517
  template: {
@@ -19222,8 +19555,8 @@ function copyBundledPolicyAuditTemplateAsset(bundledSourcePath, targetPath) {
19222
19555
  if (normalizedTargetPath === bundledSourcePath) {
19223
19556
  return normalizedTargetPath;
19224
19557
  }
19225
- fs3.mkdirSync(path5.dirname(normalizedTargetPath), { recursive: true });
19226
- fs3.copyFileSync(bundledSourcePath, normalizedTargetPath);
19558
+ fs4.mkdirSync(path5.dirname(normalizedTargetPath), { recursive: true });
19559
+ fs4.copyFileSync(bundledSourcePath, normalizedTargetPath);
19227
19560
  return normalizedTargetPath;
19228
19561
  }
19229
19562
 
@@ -19231,7 +19564,7 @@ function copyBundledPolicyAuditTemplateAsset(bundledSourcePath, targetPath) {
19231
19564
  var path6 = __toESM(require("node:path"));
19232
19565
 
19233
19566
  // ../../extensions/drm-copilot/src/lib/file-system.ts
19234
- var fs4 = __toESM(require("node:fs"));
19567
+ var fs5 = __toESM(require("node:fs"));
19235
19568
  var nodePath3 = __toESM(require("node:path"));
19236
19569
  function toPosixPath2(value) {
19237
19570
  return value.replace(/\\/g, "/");
@@ -19302,7 +19635,7 @@ var RealFileSystem = class {
19302
19635
  const walk = (currentDir, relativePrefix) => {
19303
19636
  let entries;
19304
19637
  try {
19305
- entries = fs4.readdirSync(currentDir, { withFileTypes: true });
19638
+ entries = fs5.readdirSync(currentDir, { withFileTypes: true });
19306
19639
  } catch {
19307
19640
  return;
19308
19641
  }
@@ -19325,7 +19658,7 @@ var RealFileSystem = class {
19325
19658
  */
19326
19659
  isFile(path11) {
19327
19660
  try {
19328
- return fs4.statSync(path11).isFile();
19661
+ return fs5.statSync(path11).isFile();
19329
19662
  } catch {
19330
19663
  return false;
19331
19664
  }
@@ -19335,7 +19668,7 @@ var RealFileSystem = class {
19335
19668
  * @returns True when `path` exists; false on any access error.
19336
19669
  */
19337
19670
  exists(path11) {
19338
- return fs4.existsSync(path11);
19671
+ return fs5.existsSync(path11);
19339
19672
  }
19340
19673
  /**
19341
19674
  * @param path Path to test.
@@ -19343,7 +19676,7 @@ var RealFileSystem = class {
19343
19676
  */
19344
19677
  isDirectory(path11) {
19345
19678
  try {
19346
- return fs4.statSync(path11).isDirectory();
19679
+ return fs5.statSync(path11).isDirectory();
19347
19680
  } catch {
19348
19681
  return false;
19349
19682
  }
@@ -19355,7 +19688,7 @@ var RealFileSystem = class {
19355
19688
  */
19356
19689
  listDirectory(path11) {
19357
19690
  try {
19358
- return fs4.readdirSync(path11).sort((left, right) => left.localeCompare(right));
19691
+ return fs5.readdirSync(path11).sort((left, right) => left.localeCompare(right));
19359
19692
  } catch {
19360
19693
  return [];
19361
19694
  }
@@ -19365,14 +19698,14 @@ var RealFileSystem = class {
19365
19698
  * @returns The file content decoded as UTF-8.
19366
19699
  */
19367
19700
  readTextFile(path11) {
19368
- return fs4.readFileSync(path11, "utf8");
19701
+ return fs5.readFileSync(path11, "utf8");
19369
19702
  }
19370
19703
  /**
19371
19704
  * @param path File to write.
19372
19705
  * @param content Text content to write as UTF-8.
19373
19706
  */
19374
19707
  writeTextFile(path11, content) {
19375
- fs4.writeFileSync(path11, content, "utf8");
19708
+ fs5.writeFileSync(path11, content, "utf8");
19376
19709
  }
19377
19710
  /**
19378
19711
  * Create the directory at `path`, including any missing parents.
@@ -19384,7 +19717,7 @@ var RealFileSystem = class {
19384
19717
  * @param path Directory path to create.
19385
19718
  */
19386
19719
  ensureDir(path11) {
19387
- fs4.mkdirSync(path11, { recursive: true });
19720
+ fs5.mkdirSync(path11, { recursive: true });
19388
19721
  }
19389
19722
  };
19390
19723
 
@@ -19464,7 +19797,7 @@ function buildFallbackReason(issueContent) {
19464
19797
  function resolveTemplateName(templateKind) {
19465
19798
  return templateKind === "execute" ? "execute-hard-lock.prompt.md" : "resume-hard-lock.prompt.md";
19466
19799
  }
19467
- function resolveTemplatePath(templateName, workspaceRoot, templateRoot, fs9) {
19800
+ function resolveTemplatePath(templateName, workspaceRoot, templateRoot, fs10) {
19468
19801
  const candidates = [];
19469
19802
  if (templateRoot !== null) {
19470
19803
  candidates.push(joinPosix9(templateRoot, templateName));
@@ -19476,18 +19809,18 @@ function resolveTemplatePath(templateName, workspaceRoot, templateRoot, fs9) {
19476
19809
  )
19477
19810
  );
19478
19811
  for (const candidate of candidates) {
19479
- if (fs9.isFile(candidate)) {
19812
+ if (fs10.isFile(candidate)) {
19480
19813
  return { path: candidate, checked: candidates };
19481
19814
  }
19482
19815
  }
19483
19816
  return { path: null, checked: candidates };
19484
19817
  }
19485
- function resolveIssueFileForTarget(targetPath, workspaceRoot, fs9) {
19818
+ function resolveIssueFileForTarget(targetPath, workspaceRoot, fs10) {
19486
19819
  const normalizedRoot = toPosixPath2(workspaceRoot).replace(/\/+$/, "");
19487
19820
  const relativeTarget = tryRelativeToWorkspace(targetPath, workspaceRoot);
19488
19821
  const planDir = parentOf(relativeTarget);
19489
19822
  const directIssue = joinPosix9(joinPosix9(normalizedRoot, planDir), "issue.md");
19490
- if (fs9.isFile(directIssue)) {
19823
+ if (fs10.isFile(directIssue)) {
19491
19824
  return directIssue;
19492
19825
  }
19493
19826
  const planDirParts = splitParts(planDir);
@@ -19497,15 +19830,15 @@ function resolveIssueFileForTarget(targetPath, workspaceRoot, fs9) {
19497
19830
  joinPosix9(normalizedRoot, parentOf(planDir)),
19498
19831
  "issue.md"
19499
19832
  );
19500
- if (fs9.isFile(parentIssue)) {
19833
+ if (fs10.isFile(parentIssue)) {
19501
19834
  return parentIssue;
19502
19835
  }
19503
19836
  }
19504
19837
  return directIssue;
19505
19838
  }
19506
- function resolveWorkModeFromIssue(targetPath, workspaceRoot, fs9) {
19507
- const issuePath = resolveIssueFileForTarget(targetPath, workspaceRoot, fs9);
19508
- if (!fs9.isFile(issuePath)) {
19839
+ function resolveWorkModeFromIssue(targetPath, workspaceRoot, fs10) {
19840
+ const issuePath = resolveIssueFileForTarget(targetPath, workspaceRoot, fs10);
19841
+ if (!fs10.isFile(issuePath)) {
19509
19842
  return {
19510
19843
  mode: resolveSelectedWorkMode(null),
19511
19844
  fallbackReason: buildFallbackReason(null)
@@ -19513,7 +19846,7 @@ function resolveWorkModeFromIssue(targetPath, workspaceRoot, fs9) {
19513
19846
  }
19514
19847
  let issueContent;
19515
19848
  try {
19516
- issueContent = fs9.readTextFile(issuePath);
19849
+ issueContent = fs10.readTextFile(issuePath);
19517
19850
  } catch {
19518
19851
  return {
19519
19852
  mode: resolveSelectedWorkMode(null),
@@ -19525,13 +19858,13 @@ function resolveWorkModeFromIssue(targetPath, workspaceRoot, fs9) {
19525
19858
  fallbackReason: buildFallbackReason(issueContent)
19526
19859
  };
19527
19860
  }
19528
- function resolveHardLockPrompt(templateContent, targetPath, workspaceRoot, fs9) {
19861
+ function resolveHardLockPrompt(templateContent, targetPath, workspaceRoot, fs10) {
19529
19862
  const relativeTarget = tryRelativeToWorkspace(targetPath, workspaceRoot);
19530
19863
  const planPathValue = toPosixPath2(relativeTarget);
19531
19864
  const { mode, fallbackReason } = resolveWorkModeFromIssue(
19532
19865
  targetPath,
19533
19866
  workspaceRoot,
19534
- fs9
19867
+ fs10
19535
19868
  );
19536
19869
  let resolved = templateContent.split("${plan-path}").join(planPathValue);
19537
19870
  resolved = resolved.split("${work-mode}").join(mode);
@@ -19789,18 +20122,18 @@ function isAllDigits(value) {
19789
20122
  function resolveSpecPath(folderpath) {
19790
20123
  return joinFolder(folderpath, "spec.md");
19791
20124
  }
19792
- function resolveUserStoryValue(folderpath, workspaceRoot, fs9) {
20125
+ function resolveUserStoryValue(folderpath, workspaceRoot, fs10) {
19793
20126
  const relativeStory = joinFolder(folderpath, "user-story.md");
19794
20127
  const fullStory = joinFolder(toPosixPath2(workspaceRoot), relativeStory);
19795
- if (fs9.isFile(fullStory)) {
20128
+ if (fs10.isFile(fullStory)) {
19796
20129
  return relativeStory;
19797
20130
  }
19798
20131
  return `${relativeStory} (missing)`;
19799
20132
  }
19800
- function resolveResearchValue(folderpath, workspaceRoot, fs9) {
20133
+ function resolveResearchValue(folderpath, workspaceRoot, fs10) {
19801
20134
  const relativeResearch = joinFolder(folderpath, "research.md");
19802
20135
  const fullResearch = joinFolder(toPosixPath2(workspaceRoot), relativeResearch);
19803
- if (fs9.isFile(fullResearch)) {
20136
+ if (fs10.isFile(fullResearch)) {
19804
20137
  return relativeResearch;
19805
20138
  }
19806
20139
  return null;
@@ -19812,12 +20145,12 @@ function joinFolder(folder, leaf) {
19812
20145
  }
19813
20146
  return `${normalizedFolder}/${leaf}`;
19814
20147
  }
19815
- function resolveWorkModeFromIssue2(folderpath, workspaceRoot, fs9) {
20148
+ function resolveWorkModeFromIssue2(folderpath, workspaceRoot, fs10) {
19816
20149
  const issuePath = joinFolder(
19817
20150
  joinFolder(toPosixPath2(workspaceRoot), folderpath),
19818
20151
  "issue.md"
19819
20152
  );
19820
- if (!fs9.isFile(issuePath)) {
20153
+ if (!fs10.isFile(issuePath)) {
19821
20154
  return {
19822
20155
  mode: resolveSelectedWorkMode(null),
19823
20156
  fallbackReason: buildFallbackReason(null)
@@ -19825,7 +20158,7 @@ function resolveWorkModeFromIssue2(folderpath, workspaceRoot, fs9) {
19825
20158
  }
19826
20159
  let issueContent;
19827
20160
  try {
19828
- issueContent = fs9.readTextFile(issuePath);
20161
+ issueContent = fs10.readTextFile(issuePath);
19829
20162
  } catch {
19830
20163
  return {
19831
20164
  mode: resolveSelectedWorkMode(null),
@@ -19839,7 +20172,7 @@ function resolveWorkModeFromIssue2(folderpath, workspaceRoot, fs9) {
19839
20172
  }
19840
20173
 
19841
20174
  // ../../extensions/drm-copilot/src/lib/resolve/file-prompt-core.ts
19842
- function resolvePrompt(templateContent, targetPath, workspaceRoot, fs9) {
20175
+ function resolvePrompt(templateContent, targetPath, workspaceRoot, fs10) {
19843
20176
  let content = stripFrontMatter(templateContent);
19844
20177
  const relativeTarget = tryRelativeToWorkspace2(targetPath, workspaceRoot);
19845
20178
  const fileValue = toPosixPath2(relativeTarget);
@@ -19851,19 +20184,19 @@ function resolvePrompt(templateContent, targetPath, workspaceRoot, fs9) {
19851
20184
  folderpath,
19852
20185
  name,
19853
20186
  spec: resolveSpecPath(folderpath),
19854
- "user-story": resolveUserStoryValue(folderpath, workspaceRoot, fs9)
20187
+ "user-story": resolveUserStoryValue(folderpath, workspaceRoot, fs10)
19855
20188
  };
19856
20189
  const { mode, fallbackReason } = resolveWorkModeFromIssue2(
19857
20190
  folderpath,
19858
20191
  workspaceRoot,
19859
- fs9
20192
+ fs10
19860
20193
  );
19861
20194
  variables["work-mode"] = mode;
19862
20195
  variables["fallback-reason"] = fallbackReason;
19863
20196
  if (mode === "minor-audit") {
19864
20197
  content = applyMinorAuditOverrides(content);
19865
20198
  }
19866
- const researchValue = resolveResearchValue(folderpath, workspaceRoot, fs9);
20199
+ const researchValue = resolveResearchValue(folderpath, workspaceRoot, fs10);
19867
20200
  if (researchValue === null) {
19868
20201
  content = removeLinesReferencingVariable(content, "research");
19869
20202
  } else {
@@ -25518,9 +25851,9 @@ function validatePhaseCompleteness(state) {
25518
25851
  (phase) => `Checkpoint completion validation failed: route ${routeId} is missing mandatory phase ${phase}.`
25519
25852
  );
25520
25853
  }
25521
- function loadRoutingMatrix(fs9, root) {
25854
+ function loadRoutingMatrix(fs10, root) {
25522
25855
  const path11 = `${toPosixPath2(root).replace(/\/+$/, "")}/${ROUTING_MATRIX_RELATIVE_PATH}`;
25523
- return JSON.parse(fs9.readTextFile(path11));
25856
+ return JSON.parse(fs10.readTextFile(path11));
25524
25857
  }
25525
25858
  function stringList(value) {
25526
25859
  if (!Array.isArray(value)) {
@@ -26516,6 +26849,417 @@ function validateParallelKickoffText(text) {
26516
26849
  return parseParallelKickoff(text).errors;
26517
26850
  }
26518
26851
 
26852
+ // ../../extensions/drm-copilot/src/lib/validate/plan-gate-commands.ts
26853
+ var SHELL_WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\r", "\n"]);
26854
+ var ESCAPE = "\\";
26855
+ var COV_FLAG = "--cov";
26856
+ var COV_FLAG_PREFIX = "--cov=";
26857
+ var GREP_EXECUTABLES = /* @__PURE__ */ new Set(["grep", "egrep", "fgrep", "rg"]);
26858
+ var EXECUTABLE_SCAN_LIMIT = 4;
26859
+ var PLAN_GATE_TASK_PATTERN = /^- \[(?<state>[ xX])\] \[P(?<phase>\d+)-T(?<task>\d+)\] (?<title>.+)$/;
26860
+ var PLAN_GATE_HEADING_PATTERN = /^#{1,6} /;
26861
+ var INLINE_SPAN_RE = /`([^`]+)`/g;
26862
+ var FENCE_RE = /^\s*```/;
26863
+ var MINIMUM_ARGV_LENGTH = 2;
26864
+ function splitShellWords(span) {
26865
+ const words2 = [];
26866
+ let token = null;
26867
+ let quote = null;
26868
+ let index = 0;
26869
+ while (index < span.length) {
26870
+ const char = span[index] ?? "";
26871
+ index += 1;
26872
+ if (quote === null) {
26873
+ if (SHELL_WHITESPACE.has(char)) {
26874
+ if (token !== null) {
26875
+ words2.push(token);
26876
+ token = null;
26877
+ }
26878
+ continue;
26879
+ }
26880
+ if (char === ESCAPE) {
26881
+ const next = span[index];
26882
+ if (next === void 0) {
26883
+ return null;
26884
+ }
26885
+ index += 1;
26886
+ token = (token ?? "") + next;
26887
+ continue;
26888
+ }
26889
+ if (char === '"' || char === "'") {
26890
+ quote = char;
26891
+ token = token ?? "";
26892
+ continue;
26893
+ }
26894
+ token = (token ?? "") + char;
26895
+ continue;
26896
+ }
26897
+ if (char === quote) {
26898
+ quote = null;
26899
+ continue;
26900
+ }
26901
+ if (quote === '"' && char === ESCAPE) {
26902
+ const next = span[index];
26903
+ if (next === void 0) {
26904
+ return null;
26905
+ }
26906
+ index += 1;
26907
+ if (next !== quote && next !== ESCAPE) {
26908
+ token = (token ?? "") + ESCAPE;
26909
+ }
26910
+ token = (token ?? "") + next;
26911
+ continue;
26912
+ }
26913
+ token = (token ?? "") + char;
26914
+ }
26915
+ if (quote !== null) {
26916
+ return null;
26917
+ }
26918
+ if (token !== null) {
26919
+ words2.push(token);
26920
+ }
26921
+ return words2;
26922
+ }
26923
+ function isCovFlagToken(token) {
26924
+ return token === COV_FLAG || token.startsWith(COV_FLAG_PREFIX);
26925
+ }
26926
+ function grepExecutableIndex(argv) {
26927
+ const limit = Math.min(argv.length, EXECUTABLE_SCAN_LIMIT);
26928
+ for (let index = 0; index < limit; index += 1) {
26929
+ const word = argv[index];
26930
+ if (word === void 0) {
26931
+ continue;
26932
+ }
26933
+ if (GREP_EXECUTABLES.has(word)) {
26934
+ return index;
26935
+ }
26936
+ if (word === "git" && argv[index + 1] === "grep") {
26937
+ return index + 1;
26938
+ }
26939
+ }
26940
+ return null;
26941
+ }
26942
+ function classifyKind(argv) {
26943
+ if (grepExecutableIndex(argv) !== null) {
26944
+ return "grep";
26945
+ }
26946
+ if (argv.some((word) => isCovFlagToken(word))) {
26947
+ return "pytest_cov";
26948
+ }
26949
+ return "other";
26950
+ }
26951
+ function splitLines2(text) {
26952
+ return text.split(/\r\n|\n|\r/);
26953
+ }
26954
+ function inlineSpans(line) {
26955
+ const spans = [];
26956
+ for (const match of line.matchAll(INLINE_SPAN_RE)) {
26957
+ const body = match[1];
26958
+ if (body !== void 0) {
26959
+ spans.push(body);
26960
+ }
26961
+ }
26962
+ return spans;
26963
+ }
26964
+ function appendCommand(commands, taskId, sourceLine, rawSpan) {
26965
+ const argv = splitShellWords(rawSpan);
26966
+ if (argv === null || argv.length < MINIMUM_ARGV_LENGTH) {
26967
+ return;
26968
+ }
26969
+ commands.push({
26970
+ taskId,
26971
+ sourceLine,
26972
+ rawSpan,
26973
+ argv,
26974
+ kind: classifyKind(argv)
26975
+ });
26976
+ }
26977
+ function extractPlanCommands(text) {
26978
+ const commands = [];
26979
+ let currentTask = null;
26980
+ let inFence = false;
26981
+ const lines = splitLines2(text);
26982
+ for (let index = 0; index < lines.length; index += 1) {
26983
+ const line = lines[index] ?? "";
26984
+ const lineNumber = index + 1;
26985
+ if (FENCE_RE.test(line)) {
26986
+ inFence = !inFence;
26987
+ continue;
26988
+ }
26989
+ if (inFence) {
26990
+ const fenced = line.trim();
26991
+ if (currentTask !== null && fenced !== "") {
26992
+ appendCommand(commands, currentTask, lineNumber, fenced);
26993
+ }
26994
+ continue;
26995
+ }
26996
+ if (PLAN_GATE_HEADING_PATTERN.test(line)) {
26997
+ currentTask = null;
26998
+ continue;
26999
+ }
27000
+ const taskMatch = PLAN_GATE_TASK_PATTERN.exec(line);
27001
+ if (taskMatch !== null) {
27002
+ const phase = taskMatch.groups?.["phase"] ?? "";
27003
+ const task = taskMatch.groups?.["task"] ?? "";
27004
+ currentTask = `P${phase}-T${task}`;
27005
+ }
27006
+ if (currentTask === null) {
27007
+ continue;
27008
+ }
27009
+ for (const span of inlineSpans(line)) {
27010
+ appendCommand(commands, currentTask, lineNumber, span);
27011
+ }
27012
+ }
27013
+ return commands;
27014
+ }
27015
+
27016
+ // ../../extensions/drm-copilot/src/lib/validate/plan-gate-rules.ts
27017
+ function emptyPlanGateReport() {
27018
+ return { blocking: [], warnings: [] };
27019
+ }
27020
+ var BLOCKING_CHANNEL = "blocking";
27021
+ var PLACEHOLDER_MARKERS = ["<", ">", "${", "$(", "%"];
27022
+ var PATH_SEPARATORS = ["/", "\\"];
27023
+ var PYTHON_SUFFIX = ".py";
27024
+ var PYTEST_NODE_SEPARATOR = "::";
27025
+ var REGEX_METACHARACTERS = /* @__PURE__ */ new Set([...".*[]^$\\(){}|+?"]);
27026
+ var FIXED_STRING_FLAG = "-F";
27027
+ var WINDOW_SIZE = 4;
27028
+ function isPlaceholder(value) {
27029
+ return PLACEHOLDER_MARKERS.some((marker) => value.includes(marker));
27030
+ }
27031
+ function dottedRemedy(value) {
27032
+ const stem2 = value.endsWith(PYTHON_SUFFIX) ? value.slice(0, value.length - PYTHON_SUFFIX.length) : value;
27033
+ return stem2.split("/").join(".").split("\\").join(".");
27034
+ }
27035
+ function covValues(command) {
27036
+ const values = [];
27037
+ const argv = command.argv;
27038
+ for (let index = 0; index < argv.length; index += 1) {
27039
+ const word = argv[index];
27040
+ if (word === void 0) {
27041
+ continue;
27042
+ }
27043
+ if (word === COV_FLAG) {
27044
+ const next = argv[index + 1];
27045
+ if (next !== void 0) {
27046
+ values.push({ value: next, spaceSeparated: true });
27047
+ }
27048
+ continue;
27049
+ }
27050
+ if (word.startsWith(COV_FLAG_PREFIX)) {
27051
+ values.push({
27052
+ value: word.slice(COV_FLAG_PREFIX.length),
27053
+ spaceSeparated: false
27054
+ });
27055
+ }
27056
+ }
27057
+ return values;
27058
+ }
27059
+ function evaluateCovValue(report, command, cov, context) {
27060
+ const task = command.taskId;
27061
+ if (cov.spaceSeparated) {
27062
+ report.warnings.push(
27063
+ `[${task}] --cov argument value \`${cov.value}\` is supplied space-separated; the ambiguous form can bind the following positional argument. Use the --cov=<module> form.`
27064
+ );
27065
+ }
27066
+ if (isPlaceholder(cov.value)) {
27067
+ return;
27068
+ }
27069
+ const truncated = cov.value.split(PYTEST_NODE_SEPARATOR)[0] ?? "";
27070
+ if (truncated.endsWith(PYTHON_SUFFIX)) {
27071
+ report.blocking.push(
27072
+ `[${task}] --cov argument \`${cov.value}\` names a filesystem path; coverage.py accepts only directories or importable names. Use --cov=${dottedRemedy(truncated)}.`
27073
+ );
27074
+ return;
27075
+ }
27076
+ if (!PATH_SEPARATORS.some((separator) => cov.value.includes(separator))) {
27077
+ return;
27078
+ }
27079
+ if (context === void 0) {
27080
+ return;
27081
+ }
27082
+ try {
27083
+ evaluateTrackedCovValue(report, task, cov, truncated, context);
27084
+ } catch {
27085
+ }
27086
+ }
27087
+ function evaluateTrackedCovValue(report, task, cov, truncated, context) {
27088
+ if (context.git.isTrackedFile(truncated + PYTHON_SUFFIX)) {
27089
+ report.blocking.push(
27090
+ `[${task}] --cov argument \`${cov.value}\` names a tracked module file path; coverage.py accepts only directories or importable names. Use --cov=${dottedRemedy(truncated)}.`
27091
+ );
27092
+ return;
27093
+ }
27094
+ if (context.git.isTrackedDirectory(truncated)) {
27095
+ return;
27096
+ }
27097
+ report.warnings.push(
27098
+ `[${task}] --cov argument \`${cov.value}\` contains a path separator but resolves to neither a tracked file nor a tracked directory; coverage may collect no data. Use the importable dotted form or a tracked directory.`
27099
+ );
27100
+ }
27101
+ function patternOperand(argv) {
27102
+ const executable = grepExecutableIndex(argv);
27103
+ if (executable === null) {
27104
+ return null;
27105
+ }
27106
+ for (let index = executable + 1; index < argv.length; index += 1) {
27107
+ const word = argv[index];
27108
+ if (word === void 0 || word.startsWith("-")) {
27109
+ continue;
27110
+ }
27111
+ return word;
27112
+ }
27113
+ return null;
27114
+ }
27115
+ function isCheckableLiteral(argv, pattern) {
27116
+ if (isPlaceholder(pattern)) {
27117
+ return false;
27118
+ }
27119
+ if (argv.includes(FIXED_STRING_FLAG)) {
27120
+ return true;
27121
+ }
27122
+ return ![...pattern].some((character) => REGEX_METACHARACTERS.has(character));
27123
+ }
27124
+ function normalizeWhitespace(value) {
27125
+ return value.split(/\s+/).filter((word) => word !== "").join(" ");
27126
+ }
27127
+ function planQuotesLiteral(text, literal2, excludeSpan) {
27128
+ const remainder = text.split(excludeSpan).join(" ");
27129
+ const needle = normalizeWhitespace(literal2);
27130
+ if (needle === "") {
27131
+ return false;
27132
+ }
27133
+ return normalizeWhitespace(remainder).includes(needle);
27134
+ }
27135
+ function windowJoin(lines, size = WINDOW_SIZE) {
27136
+ const dense = lines.filter((line) => line.trim() !== "").map((line) => normalizeWhitespace(line));
27137
+ const windows = [];
27138
+ for (let index = 0; index < dense.length; index += 1) {
27139
+ windows.push(dense.slice(index, index + size).join(" "));
27140
+ }
27141
+ return windows;
27142
+ }
27143
+ function hasCrossLinePresence(context, literal2) {
27144
+ const words2 = literal2.split(/\s+/).filter((word) => word !== "");
27145
+ if (words2.length < 2) {
27146
+ return false;
27147
+ }
27148
+ const needle = words2.join(" ");
27149
+ const firstWord = words2[0] ?? "";
27150
+ for (const path11 of context.git.filesContaining(firstWord)) {
27151
+ const lines = context.git.readTrackedText(path11).split(/\r\n|\n|\r/);
27152
+ if (lines.some((line) => normalizeWhitespace(line).includes(needle))) {
27153
+ continue;
27154
+ }
27155
+ if (windowJoin(lines).some((window2) => window2.includes(needle))) {
27156
+ return true;
27157
+ }
27158
+ }
27159
+ return false;
27160
+ }
27161
+
27162
+ // ../../extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts
27163
+ var G5_SEVERITY = "warning";
27164
+ var CommandRunnerPlanGateRepository = class {
27165
+ constructor(workspaceRoot, runner) {
27166
+ this.workspaceRoot = workspaceRoot;
27167
+ this.runner = runner;
27168
+ }
27169
+ workspaceRoot;
27170
+ runner;
27171
+ /** Run one `git` invocation and return its exit code and trimmed stdout. */
27172
+ run(arguments_) {
27173
+ const result = this.runner.run(["git", ...arguments_], {
27174
+ cwd: this.workspaceRoot,
27175
+ allowError: true
27176
+ });
27177
+ return { code: result.code, stdout: result.stdout.trim() };
27178
+ }
27179
+ /** Return tracked paths carrying the literal on a single line. */
27180
+ filesContaining(literal2) {
27181
+ const result = this.run(["grep", "-F", "-l", "--", literal2]);
27182
+ if (result.code !== 0 || result.stdout === "") {
27183
+ return [];
27184
+ }
27185
+ return result.stdout.split(/\r\n|\n|\r/).map((line) => line.trim()).filter((line) => line !== "");
27186
+ }
27187
+ /** Return whether `git ls-files` lists the path itself. */
27188
+ isTrackedFile(path11) {
27189
+ const normalized = path11.split("\\").join("/");
27190
+ const result = this.run(["ls-files", "--", normalized]);
27191
+ if (result.code !== 0 || result.stdout === "") {
27192
+ return false;
27193
+ }
27194
+ return result.stdout.split(/\r\n|\n|\r/).some((line) => line.trim() === normalized);
27195
+ }
27196
+ /** Return whether entries exist beneath the path but none equals it. */
27197
+ isTrackedDirectory(path11) {
27198
+ const normalized = path11.split("\\").join("/").replace(/\/+$/, "");
27199
+ const result = this.run(["ls-files", "--", normalized]);
27200
+ if (result.code !== 0 || result.stdout === "") {
27201
+ return false;
27202
+ }
27203
+ const listed = result.stdout.split(/\r\n|\n|\r/).map((line) => line.trim()).filter((line) => line !== "");
27204
+ return listed.length > 0 && listed.every((entry) => entry !== normalized);
27205
+ }
27206
+ /** Return the committed text of the path at `HEAD`, or an empty string. */
27207
+ readTrackedText(path11) {
27208
+ const normalized = path11.split("\\").join("/");
27209
+ const result = this.run(["show", `HEAD:${normalized}`]);
27210
+ return result.code === 0 ? result.stdout : "";
27211
+ }
27212
+ };
27213
+ function evaluateLiteral(report, text, command, context) {
27214
+ const pattern = patternOperand(command.argv);
27215
+ if (pattern === null || !isCheckableLiteral(command.argv, pattern)) {
27216
+ return;
27217
+ }
27218
+ if (context.git.filesContaining(pattern).length > 0) {
27219
+ return;
27220
+ }
27221
+ if (planQuotesLiteral(text, pattern, command.rawSpan)) {
27222
+ return;
27223
+ }
27224
+ if (hasCrossLinePresence(context, pattern)) {
27225
+ report.warnings.push(
27226
+ `[${command.taskId}] search literal \`${pattern}\` is present only across adjacent lines of a tracked file and matches no single line; a line-oriented search returns zero matches. Search a shorter single-line token.`
27227
+ );
27228
+ return;
27229
+ }
27230
+ const finding = `[${command.taskId}] search literal \`${pattern}\` is absent from the tracked tree and is not quoted in the plan; the search returns zero matches whatever the executor does. Quote the exact literal the task will create, or assert a literal that exists.`;
27231
+ const channel = G5_SEVERITY === BLOCKING_CHANNEL ? report.blocking : report.warnings;
27232
+ channel.push(finding);
27233
+ }
27234
+ function evaluateLiteralRules(report, text, commands, context) {
27235
+ const literalFindings = emptyPlanGateReport();
27236
+ try {
27237
+ for (const command of commands) {
27238
+ if (command.kind !== "grep") {
27239
+ continue;
27240
+ }
27241
+ evaluateLiteral(literalFindings, text, command, context);
27242
+ }
27243
+ } catch {
27244
+ return;
27245
+ }
27246
+ report.blocking.push(...literalFindings.blocking);
27247
+ report.warnings.push(...literalFindings.warnings);
27248
+ }
27249
+ function evaluatePlanGates(text, context) {
27250
+ const report = emptyPlanGateReport();
27251
+ const commands = extractPlanCommands(text);
27252
+ for (const command of commands) {
27253
+ for (const cov of covValues(command)) {
27254
+ evaluateCovValue(report, command, cov, context);
27255
+ }
27256
+ }
27257
+ if (context !== void 0) {
27258
+ evaluateLiteralRules(report, text, commands, context);
27259
+ }
27260
+ return report;
27261
+ }
27262
+
26519
27263
  // ../../extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts
26520
27264
  function words(text) {
26521
27265
  return text.split(" ");
@@ -27301,7 +28045,7 @@ function validateReceiptArrays(state, context) {
27301
28045
  var CONTEXT = "Parallel checkpoint";
27302
28046
  var EXPECTED_ROUTE_ID2 = "parallel";
27303
28047
  var MIN_CONCURRENCY = 1;
27304
- var MAX_CONCURRENCY = 8;
28048
+ var MAX_CONCURRENCY = 32;
27305
28049
  var REQUIRED_KEYS4 = [
27306
28050
  "objective",
27307
28051
  "completed_steps",
@@ -27451,7 +28195,7 @@ function validateParallelOrchestratorStateText(text, options = {}) {
27451
28195
  // ../../extensions/drm-copilot/src/lib/validate/parallel-planner-state-core.ts
27452
28196
  var CONTEXT2 = "Parallel planner checkpoint";
27453
28197
  var MIN_CONCURRENCY2 = 1;
27454
- var MAX_CONCURRENCY2 = 8;
28198
+ var MAX_CONCURRENCY2 = 32;
27455
28199
  var REQUIRED_KEYS5 = [
27456
28200
  "objective",
27457
28201
  "parallel_slug",
@@ -27690,7 +28434,7 @@ var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
27690
28434
  "Per-language comparison summary:"
27691
28435
  ];
27692
28436
  var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
27693
- var PLACEHOLDER_MARKERS = [
28437
+ var PLACEHOLDER_MARKERS2 = [
27694
28438
  "[n]",
27695
28439
  "[path",
27696
28440
  "[artifact",
@@ -27716,7 +28460,7 @@ function isNaValue(value) {
27716
28460
  }
27717
28461
  function hasPlaceholderMarker(value) {
27718
28462
  const lowered = value.toLowerCase();
27719
- return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
28463
+ return PLACEHOLDER_MARKERS2.some((marker) => lowered.includes(marker));
27720
28464
  }
27721
28465
  function reportsMissingTemplateResolverSuccess(text) {
27722
28466
  const lowered = text.toLowerCase();
@@ -28023,10 +28767,28 @@ function validatePlanText(text) {
28023
28767
  }
28024
28768
  return errors;
28025
28769
  }
28026
- function validateArtifact(input) {
28770
+ function buildPlanGateContext(input) {
28771
+ if (input.fs === void 0 || input.root === void 0 || input.artifactPath === void 0 || input.runner === void 0) {
28772
+ return void 0;
28773
+ }
28774
+ return {
28775
+ workspaceRoot: input.root,
28776
+ fileSystem: input.fs,
28777
+ git: new CommandRunnerPlanGateRepository(input.root, input.runner)
28778
+ };
28779
+ }
28780
+ function validateArtifactWithWarnings(input) {
28781
+ if (input.artifactType === "plan") {
28782
+ const report = evaluatePlanGates(input.text, buildPlanGateContext(input));
28783
+ return {
28784
+ errors: [...validatePlanText(input.text), ...report.blocking],
28785
+ warnings: report.warnings
28786
+ };
28787
+ }
28788
+ return { errors: dispatchValidatorErrors(input), warnings: [] };
28789
+ }
28790
+ function dispatchValidatorErrors(input) {
28027
28791
  switch (input.artifactType) {
28028
- case "plan":
28029
- return validatePlanText(input.text);
28030
28792
  case "policy-audit":
28031
28793
  return validatePolicyAuditText(input.text);
28032
28794
  case "code-review":
@@ -28089,12 +28851,13 @@ function validateArtifact(input) {
28089
28851
  }
28090
28852
 
28091
28853
  // ../../extensions/drm-copilot/src/lib/validate/validate-orchestration-service-call.ts
28854
+ var PLAN_GATE_WARNING_PREFIX = "PLAN GATE WARNING: ";
28092
28855
  function validateOrchestrationServiceCall(input) {
28093
28856
  const artifactFullPath = toPosixPath2(
28094
28857
  path9.join(input.workspaceRoot, input.artifactPath)
28095
28858
  );
28096
28859
  const text = input.fileSystem.readTextFile(artifactFullPath);
28097
- const errors = validateArtifact({
28860
+ const { errors, warnings } = validateArtifactWithWarnings({
28098
28861
  artifactType: input.artifactType,
28099
28862
  text,
28100
28863
  ...input.requireComplete === void 0 ? {} : { requireComplete: input.requireComplete },
@@ -28108,15 +28871,17 @@ function validateOrchestrationServiceCall(input) {
28108
28871
  root: input.workspaceRoot
28109
28872
  });
28110
28873
  if (errors.length > 0) {
28874
+ const warningBlock = warnings.length === 0 ? "" : "\n" + warnings.map((warning) => `${PLAN_GATE_WARNING_PREFIX}${warning}`).join("\n");
28111
28875
  throw new Error(
28112
28876
  `Validation failed for ${input.artifactType} artifact at '${input.artifactPath}':
28113
- ${errors.join("\n")}`
28877
+ ${errors.join("\n")}${warningBlock}`
28114
28878
  );
28115
28879
  }
28116
28880
  return {
28117
28881
  tool: "validate_orchestration_artifacts",
28118
28882
  workspaceRoot: input.workspaceRoot,
28119
- summary: `Validated ${input.artifactType} artifact at '${input.artifactPath}'.`
28883
+ summary: `Validated ${input.artifactType} artifact at '${input.artifactPath}'.`,
28884
+ ...warnings.length === 0 ? {} : { warnings }
28120
28885
  };
28121
28886
  }
28122
28887
 
@@ -28137,7 +28902,7 @@ function buildValidateOrchestrationServiceCallInput(fileSystem, input, runner) {
28137
28902
  }
28138
28903
 
28139
28904
  // ../../extensions/drm-copilot/src/lib/new-potential-bug-entry.ts
28140
- var fs5 = __toESM(require("node:fs"));
28905
+ var fs6 = __toESM(require("node:fs"));
28141
28906
  var nodePath4 = __toESM(require("node:path"));
28142
28907
  var SHORT_NAME_PATTERN2 = /^[a-z0-9]+(-[a-z0-9]+)*$/;
28143
28908
  var INSIDERS_SIGNAL_NAMES = [
@@ -28210,7 +28975,7 @@ function defaultWhichLookup(executable) {
28210
28975
  directory,
28211
28976
  process.platform === "win32" ? `${executable}${extension}` : executable
28212
28977
  );
28213
- if (fs5.existsSync(candidate)) {
28978
+ if (fs6.existsSync(candidate)) {
28214
28979
  return candidate;
28215
28980
  }
28216
28981
  }
@@ -28339,7 +29104,7 @@ function truncate(text, limit = 800) {
28339
29104
  }
28340
29105
  return rstrip3(text.slice(0, limit - 3)) + "...";
28341
29106
  }
28342
- function splitLines2(value) {
29107
+ function splitLines3(value) {
28343
29108
  if (value === "") {
28344
29109
  return [];
28345
29110
  }
@@ -28350,7 +29115,7 @@ function splitLines2(value) {
28350
29115
  return lines;
28351
29116
  }
28352
29117
  function truncateLines(text, limit) {
28353
- const lines = splitLines2(text);
29118
+ const lines = splitLines3(text);
28354
29119
  if (lines.length <= limit) {
28355
29120
  return text;
28356
29121
  }
@@ -29114,7 +29879,7 @@ function convertNumstat(numstatText) {
29114
29879
  let adds = 0;
29115
29880
  let dels = 0;
29116
29881
  const files = [];
29117
- for (const rawLine of splitLines3(numstatText)) {
29882
+ for (const rawLine of splitLines4(numstatText)) {
29118
29883
  if (!rawLine.trim()) {
29119
29884
  continue;
29120
29885
  }
@@ -29177,7 +29942,7 @@ function summarizeConventionalCommits(subjects) {
29177
29942
  }
29178
29943
  counts.set("other", 0);
29179
29944
  const typePattern = /^(feat|fix|refactor|perf|docs|test|chore|build|ci|style)(\(|!|:)/u;
29180
- for (const rawLine of splitLines3(subjects)) {
29945
+ for (const rawLine of splitLines4(subjects)) {
29181
29946
  const line = rawLine.trim();
29182
29947
  if (!line) {
29183
29948
  continue;
@@ -29232,7 +29997,7 @@ function buildIssuesToAutocloseSection(params) {
29232
29997
  function extractChangedPaths(contextText) {
29233
29998
  const paths = [];
29234
29999
  let capture = false;
29235
- for (const line of splitLines3(contextText)) {
30000
+ for (const line of splitLines4(contextText)) {
29236
30001
  if (line.startsWith("===== Changed files")) {
29237
30002
  capture = true;
29238
30003
  continue;
@@ -29278,7 +30043,7 @@ function compareCodePoint2(left, right) {
29278
30043
  }
29279
30044
  return 0;
29280
30045
  }
29281
- function splitLines3(value) {
30046
+ function splitLines4(value) {
29282
30047
  if (value === "") {
29283
30048
  return [];
29284
30049
  }
@@ -29348,7 +30113,7 @@ function buildPrContext(options) {
29348
30113
  const subjects = git.log("--pretty=%s", revRange);
29349
30114
  const authors = git.log("--format=%an <%ae>", revRange);
29350
30115
  const authorsList = sortedSet2(
29351
- splitLines4(authors).map((line) => line.trim()).filter((line) => line)
30116
+ splitLines5(authors).map((line) => line.trim()).filter((line) => line)
29352
30117
  );
29353
30118
  const nameStatus = git.diffRange(["--name-status", mergeBase, headSha]);
29354
30119
  const numstat = git.diffRange(["--numstat", mergeBase, headSha]);
@@ -29356,7 +30121,7 @@ function buildPrContext(options) {
29356
30121
  const stat = git.diffRange(["--stat", mergeBase, headSha]);
29357
30122
  const [additions, deletions, files] = convertNumstat(numstat);
29358
30123
  const extSummary = extensionSummary(files);
29359
- const mergePrs = extractMergePrNumbers(splitLines4(oneline));
30124
+ const mergePrs = extractMergePrNumbers(splitLines5(oneline));
29360
30125
  const issueCandidates = extractIssueReferences(
29361
30126
  oneline + "\n" + subjects
29362
30127
  ).filter((ref) => !mergePrs.includes(ref));
@@ -29515,7 +30280,7 @@ function compareCodePoint3(left, right) {
29515
30280
  }
29516
30281
  return 0;
29517
30282
  }
29518
- function splitLines4(value) {
30283
+ function splitLines5(value) {
29519
30284
  if (value === "") {
29520
30285
  return [];
29521
30286
  }
@@ -29541,7 +30306,7 @@ function parseSection2(markdown, heading) {
29541
30306
  }
29542
30307
  function completedPlanTasks2(markdown, limit = 10) {
29543
30308
  const tasks = [];
29544
- for (const line of splitLines2(markdown)) {
30309
+ for (const line of splitLines3(markdown)) {
29545
30310
  if (/\[x\]/iu.test(line)) {
29546
30311
  const cleaned = line.replace(/^[-*]\s*\[[xX]\]\s*/u, "").trim();
29547
30312
  tasks.push(cleaned);
@@ -29567,9 +30332,9 @@ function extractIssueReferences2(text) {
29567
30332
  }
29568
30333
  return ordered;
29569
30334
  }
29570
- function resolveFeatureDir2(fs9, baseDir, feature) {
30335
+ function resolveFeatureDir2(fs10, baseDir, feature) {
29571
30336
  const direct = `${baseDir}/${feature}`;
29572
- if (fs9.exists(direct)) {
30337
+ if (fs10.exists(direct)) {
29573
30338
  return direct;
29574
30339
  }
29575
30340
  const pattern = new RegExp(
@@ -29578,9 +30343,9 @@ function resolveFeatureDir2(fs9, baseDir, feature) {
29578
30343
  );
29579
30344
  const strongMatches = [];
29580
30345
  const weakMatches = [];
29581
- for (const name of fs9.listDirectory(baseDir)) {
30346
+ for (const name of fs10.listDirectory(baseDir)) {
29582
30347
  const candidate = `${baseDir}/${name}`;
29583
- if (!fs9.isDirectory(candidate)) {
30348
+ if (!fs10.isDirectory(candidate)) {
29584
30349
  continue;
29585
30350
  }
29586
30351
  if (pattern.test(name)) {
@@ -29597,11 +30362,11 @@ function resolveFeatureDir2(fs9, baseDir, feature) {
29597
30362
  }
29598
30363
  return null;
29599
30364
  }
29600
- function readText(fs9, path11) {
29601
- return fs9.exists(path11) ? fs9.readTextFile(path11) : "";
30365
+ function readText(fs10, path11) {
30366
+ return fs10.exists(path11) ? fs10.readTextFile(path11) : "";
29602
30367
  }
29603
- function latestGlobPath(fs9, directory, pattern) {
29604
- const matches = [...fs9.glob(directory, pattern)].sort(compareCodePoint4);
30368
+ function latestGlobPath(fs10, directory, pattern) {
30369
+ const matches = [...fs10.glob(directory, pattern)].sort(compareCodePoint4);
29605
30370
  return matches.length > 0 ? matches[matches.length - 1] : null;
29606
30371
  }
29607
30372
  function verificationText(planText) {
@@ -29620,7 +30385,7 @@ function parsePrimaryIssueFromMetadata(params) {
29620
30385
  params.storyText,
29621
30386
  params.issueText
29622
30387
  ]) {
29623
- for (const line of splitLines2(sourceText)) {
30388
+ for (const line of splitLines3(sourceText)) {
29624
30389
  const match = pattern.exec(line);
29625
30390
  if (match) {
29626
30391
  return match[1];
@@ -29643,20 +30408,20 @@ function parseReadinessValue(text) {
29643
30408
  }
29644
30409
  return null;
29645
30410
  }
29646
- function resolveReadinessSignal(fs9, featureDir) {
29647
- const auditFiles = [...fs9.glob(featureDir, "feature-audit.*.md")].sort(
30411
+ function resolveReadinessSignal(fs10, featureDir) {
30412
+ const auditFiles = [...fs10.glob(featureDir, "feature-audit.*.md")].sort(
29648
30413
  compareCodePoint4
29649
30414
  );
29650
30415
  for (let index = auditFiles.length - 1; index >= 0; index -= 1) {
29651
30416
  const auditPath = auditFiles[index];
29652
- const readiness = parseReadinessValue(readText(fs9, auditPath));
30417
+ const readiness = parseReadinessValue(readText(fs10, auditPath));
29653
30418
  if (readiness) {
29654
30419
  return [readiness, auditPath];
29655
30420
  }
29656
30421
  }
29657
30422
  return [null, null];
29658
30423
  }
29659
- function relativeToPosix5(root, path11) {
30424
+ function relativeToPosix6(root, path11) {
29660
30425
  const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
29661
30426
  const normalized = toPosixPath2(path11);
29662
30427
  if (normalized.startsWith(`${normalizedRoot}/`)) {
@@ -29679,22 +30444,26 @@ function escapeRegExp4(value) {
29679
30444
 
29680
30445
  // ../../extensions/drm-copilot/src/lib/pr-context/verification-evidence.ts
29681
30446
  var REQUIRED_FIELDS = ["Timestamp", "Command", "EXIT_CODE"];
30447
+ var EXPECTED_EXIT_CODE_FIELD = "ExpectedExitCode";
29682
30448
  var CANONICAL_GLOBS = [
29683
30449
  "evidence/qa-gates/**/*.md",
29684
30450
  "evidence/regression-testing/**/*.md",
29685
30451
  "evidence/other/**/*.md"
29686
30452
  ];
29687
- function discoverCanonicalEvidenceFiles(fs9, root, feature) {
30453
+ function normalizeResult(exitCode, expectedExitCode) {
30454
+ return exitCode === expectedExitCode ? "pass" : "fail";
30455
+ }
30456
+ function discoverCanonicalEvidenceFiles(fs10, root, feature) {
29688
30457
  const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
29689
30458
  const featureRoot = `${normalizedRoot}/docs/features/active/${feature}`;
29690
- if (!fs9.exists(featureRoot) || !fs9.isDirectory(featureRoot)) {
30459
+ if (!fs10.exists(featureRoot) || !fs10.isDirectory(featureRoot)) {
29691
30460
  return [];
29692
30461
  }
29693
30462
  const discovered = /* @__PURE__ */ new Set();
29694
30463
  for (const pattern of CANONICAL_GLOBS) {
29695
- for (const candidate of fs9.glob(featureRoot, pattern)) {
29696
- if (fs9.isFile(candidate)) {
29697
- discovered.add(relativeToPosix6(normalizedRoot, candidate));
30464
+ for (const candidate of fs10.glob(featureRoot, pattern)) {
30465
+ if (fs10.isFile(candidate)) {
30466
+ discovered.add(relativeToPosix7(normalizedRoot, candidate));
29698
30467
  }
29699
30468
  }
29700
30469
  }
@@ -29703,7 +30472,7 @@ function discoverCanonicalEvidenceFiles(fs9, root, feature) {
29703
30472
  function parseVerificationEvidenceMarkdown(params) {
29704
30473
  const { feature, sourceFile, markdown } = params;
29705
30474
  const parsed = /* @__PURE__ */ new Map();
29706
- for (const rawLine of splitLines5(markdown)) {
30475
+ for (const rawLine of splitLines6(markdown)) {
29707
30476
  const colonIndex = rawLine.indexOf(":");
29708
30477
  if (colonIndex === -1) {
29709
30478
  continue;
@@ -29713,10 +30482,14 @@ function parseVerificationEvidenceMarkdown(params) {
29713
30482
  if (REQUIRED_FIELDS.includes(key) && !parsed.has(key)) {
29714
30483
  parsed.set(key, value);
29715
30484
  }
30485
+ if (key === EXPECTED_EXIT_CODE_FIELD && !parsed.has(key)) {
30486
+ parsed.set(key, value);
30487
+ }
29716
30488
  }
29717
30489
  const timestamp = parsed.get("Timestamp") ?? null;
29718
30490
  const command = parsed.get("Command") ?? null;
29719
30491
  const exitCodeRaw = parsed.get("EXIT_CODE");
30492
+ const expectedExitCodeRaw = parsed.get(EXPECTED_EXIT_CODE_FIELD);
29720
30493
  if (!timestamp || !command || exitCodeRaw === void 0) {
29721
30494
  return {
29722
30495
  feature,
@@ -29724,7 +30497,8 @@ function parseVerificationEvidenceMarkdown(params) {
29724
30497
  timestamp,
29725
30498
  command,
29726
30499
  exitCode: null,
29727
- normalizedResult: "unparseable"
30500
+ normalizedResult: "unparseable",
30501
+ expectedExitCode: 0
29728
30502
  };
29729
30503
  }
29730
30504
  const exitCode = parseIntegerStrict(exitCodeRaw);
@@ -29735,24 +30509,41 @@ function parseVerificationEvidenceMarkdown(params) {
29735
30509
  timestamp,
29736
30510
  command,
29737
30511
  exitCode: null,
29738
- normalizedResult: "unparseable"
30512
+ normalizedResult: "unparseable",
30513
+ expectedExitCode: 0
30514
+ };
30515
+ }
30516
+ const expectedExitCode = expectedExitCodeRaw === void 0 ? 0 : parseIntegerStrict(expectedExitCodeRaw);
30517
+ if (expectedExitCode === null) {
30518
+ return {
30519
+ feature,
30520
+ sourceFile,
30521
+ timestamp,
30522
+ command,
30523
+ exitCode: null,
30524
+ normalizedResult: "unparseable",
30525
+ expectedExitCode: 0
29739
30526
  };
29740
30527
  }
29741
- const normalizedResult = exitCode === 0 ? "pass" : "fail";
30528
+ const normalizedResult = normalizeResult(
30529
+ exitCode,
30530
+ expectedExitCode
30531
+ );
29742
30532
  return {
29743
30533
  feature,
29744
30534
  sourceFile,
29745
30535
  timestamp,
29746
30536
  command,
29747
30537
  exitCode,
29748
- normalizedResult
30538
+ normalizedResult,
30539
+ expectedExitCode
29749
30540
  };
29750
30541
  }
29751
30542
  function parseVerificationEvidenceFile(params) {
29752
- const { fs: fs9, root, feature, relativePath: relativePath2 } = params;
30543
+ const { fs: fs10, root, feature, relativePath: relativePath2 } = params;
29753
30544
  const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
29754
30545
  const relPosix = toPosixPath2(relativePath2).replace(/^\/+/u, "");
29755
- const markdown = fs9.readTextFile(`${normalizedRoot}/${relPosix}`);
30546
+ const markdown = fs10.readTextFile(`${normalizedRoot}/${relPosix}`);
29756
30547
  return parseVerificationEvidenceMarkdown({
29757
30548
  feature,
29758
30549
  sourceFile: relPosix,
@@ -29765,7 +30556,7 @@ function parseIntegerStrict(value) {
29765
30556
  }
29766
30557
  return Number.parseInt(value, 10);
29767
30558
  }
29768
- function relativeToPosix6(root, absolute) {
30559
+ function relativeToPosix7(root, absolute) {
29769
30560
  const normalized = toPosixPath2(absolute);
29770
30561
  if (normalized.startsWith(`${root}/`)) {
29771
30562
  return normalized.slice(root.length + 1);
@@ -29781,7 +30572,7 @@ function compareCodePoint5(left, right) {
29781
30572
  }
29782
30573
  return 0;
29783
30574
  }
29784
- function splitLines5(value) {
30575
+ function splitLines6(value) {
29785
30576
  if (value === "") {
29786
30577
  return [];
29787
30578
  }
@@ -29814,15 +30605,15 @@ function extractFeatures3(changedFiles) {
29814
30605
  }
29815
30606
  return features;
29816
30607
  }
29817
- function gatherFeatureExcerpts2(fs9, root, changedFiles) {
30608
+ function gatherFeatureExcerpts2(fs10, root, changedFiles) {
29818
30609
  const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
29819
30610
  const features = extractFeatures3(changedFiles);
29820
30611
  const excerpts = [];
29821
30612
  const baseDir = `${normalizedRoot}/docs/features/active`;
29822
30613
  const promotedDir = `${normalizedRoot}/docs/features/potential/promoted`;
29823
30614
  for (const feature of [...features].sort(compareCodePoint4)) {
29824
- const featureDir = resolveFeatureDir2(fs9, baseDir, feature);
29825
- const promotedFeatureDir = resolveFeatureDir2(fs9, promotedDir, feature);
30615
+ const featureDir = resolveFeatureDir2(fs10, baseDir, feature);
30616
+ const promotedFeatureDir = resolveFeatureDir2(fs10, promotedDir, feature);
29826
30617
  if (featureDir === null && promotedFeatureDir === null) {
29827
30618
  continue;
29828
30619
  }
@@ -29833,33 +30624,33 @@ function gatherFeatureExcerpts2(fs9, root, changedFiles) {
29833
30624
  const specPath = `${activeDir}/spec.md`;
29834
30625
  const issuePath = `${activeDir}/issue.md`;
29835
30626
  let planPath = `${activeDir}/plan.md`;
29836
- if (!fs9.exists(planPath)) {
29837
- const latestPlan = latestGlobPath(fs9, activeDir, "plan.*.md");
30627
+ if (!fs10.exists(planPath)) {
30628
+ const latestPlan = latestGlobPath(fs10, activeDir, "plan.*.md");
29838
30629
  if (latestPlan !== null) {
29839
30630
  planPath = latestPlan;
29840
30631
  }
29841
30632
  }
29842
30633
  let userStoryPath = `${activeDir}/user-story.md`;
29843
30634
  const promotedStoryPath = promotedFeatureDir !== null ? `${promotedFeatureDir}/user-story.md` : null;
29844
- const promotedStoryText = promotedStoryPath !== null ? readText(fs9, promotedStoryPath) : "";
29845
- if (promotedStoryPath !== null && !fs9.exists(userStoryPath)) {
30635
+ const promotedStoryText = promotedStoryPath !== null ? readText(fs10, promotedStoryPath) : "";
30636
+ if (promotedStoryPath !== null && !fs10.exists(userStoryPath)) {
29846
30637
  userStoryPath = promotedStoryPath;
29847
30638
  }
29848
- let userStoryText = readText(fs9, userStoryPath);
30639
+ let userStoryText = readText(fs10, userStoryPath);
29849
30640
  if (!userStoryText && promotedStoryText && promotedStoryPath !== null) {
29850
30641
  userStoryText = promotedStoryText;
29851
30642
  userStoryPath = promotedStoryPath;
29852
30643
  }
29853
- const specText = readText(fs9, specPath);
29854
- const issueText = readText(fs9, issuePath);
29855
- const planText = readText(fs9, planPath);
30644
+ const specText = readText(fs10, specPath);
30645
+ const issueText = readText(fs10, issuePath);
30646
+ const planText = readText(fs10, planPath);
29856
30647
  const primaryIssueRef = parsePrimaryIssueFromMetadata({
29857
30648
  specText,
29858
30649
  storyText: userStoryText,
29859
30650
  issueText
29860
30651
  });
29861
30652
  const [readinessSignal, readinessSource] = resolveReadinessSignal(
29862
- fs9,
30653
+ fs10,
29863
30654
  activeDir
29864
30655
  );
29865
30656
  const specParts = buildSpecParts(specText);
@@ -29874,7 +30665,7 @@ function gatherFeatureExcerpts2(fs9, root, changedFiles) {
29874
30665
  verificationBlock
29875
30666
  );
29876
30667
  const contextFiles = buildContextFiles({
29877
- fs: fs9,
30668
+ fs: fs10,
29878
30669
  root: normalizedRoot,
29879
30670
  feature,
29880
30671
  candidatePaths: [specPath, issuePath, planPath, userStoryPath],
@@ -29958,18 +30749,18 @@ function buildExcerpt(feature, storyParts, specParts, planSection, verificationB
29958
30749
  return lines.join("\n");
29959
30750
  }
29960
30751
  function buildContextFiles(params) {
29961
- const { fs: fs9, root, feature, candidatePaths, readinessSource } = params;
30752
+ const { fs: fs10, root, feature, candidatePaths, readinessSource } = params;
29962
30753
  const contextFiles = [];
29963
30754
  for (const path11 of candidatePaths) {
29964
- if (fs9.exists(path11)) {
29965
- contextFiles.push(relativeToPosix5(root, path11));
30755
+ if (fs10.exists(path11)) {
30756
+ contextFiles.push(relativeToPosix6(root, path11));
29966
30757
  }
29967
30758
  }
29968
30759
  if (readinessSource !== null) {
29969
- contextFiles.push(relativeToPosix5(root, readinessSource));
30760
+ contextFiles.push(relativeToPosix6(root, readinessSource));
29970
30761
  }
29971
30762
  const evidenceContextFiles = discoverCanonicalEvidenceFiles(
29972
- fs9,
30763
+ fs10,
29973
30764
  root,
29974
30765
  feature
29975
30766
  );
@@ -30003,7 +30794,7 @@ function extractDigestBullets(body, headings, limit) {
30003
30794
  if (!sectionText) {
30004
30795
  continue;
30005
30796
  }
30006
- for (const line of splitLines2(sectionText)) {
30797
+ for (const line of splitLines3(sectionText)) {
30007
30798
  if (!line.trim()) {
30008
30799
  continue;
30009
30800
  }
@@ -30144,7 +30935,7 @@ function parseNumstatDetailed(numstatText) {
30144
30935
  let addsTotal = 0;
30145
30936
  let delsTotal = 0;
30146
30937
  const perFile = /* @__PURE__ */ new Map();
30147
- for (const rawLine of splitLines2(numstatText)) {
30938
+ for (const rawLine of splitLines3(numstatText)) {
30148
30939
  if (!rawLine.trim()) {
30149
30940
  continue;
30150
30941
  }
@@ -30163,7 +30954,7 @@ function parseNumstatDetailed(numstatText) {
30163
30954
  }
30164
30955
  function parseNameStatusMap(nameStatusText) {
30165
30956
  const mapping = /* @__PURE__ */ new Map();
30166
- for (const rawLine of splitLines2(nameStatusText)) {
30957
+ for (const rawLine of splitLines3(nameStatusText)) {
30167
30958
  if (!rawLine.trim()) {
30168
30959
  continue;
30169
30960
  }
@@ -30182,7 +30973,7 @@ function isScopingDoc(path11) {
30182
30973
  return lowered.startsWith("docs/features/") && (lowered.endsWith("/spec.md") || lowered.endsWith("/plan.md") || lowered.endsWith("/bug-remediation-plan.md") || lowered.endsWith("/user-story.md") || lowered.endsWith("/readme.md"));
30183
30974
  }
30184
30975
  function scopingDocChanges(options) {
30185
- const { git, fs: fs9, mergeBase, headSha, root, nameStatusText, numstatDetails } = options;
30976
+ const { git, fs: fs10, mergeBase, headSha, root, nameStatusText, numstatDetails } = options;
30186
30977
  if (!mergeBase || !headSha) {
30187
30978
  return [];
30188
30979
  }
@@ -30211,7 +31002,7 @@ function scopingDocChanges(options) {
30211
31002
  path11
30212
31003
  ]);
30213
31004
  let headingTouched = false;
30214
- for (const line of splitLines2(diffText)) {
31005
+ for (const line of splitLines3(diffText)) {
30215
31006
  if (!line.startsWith("+") || line.startsWith("+++")) {
30216
31007
  continue;
30217
31008
  }
@@ -30227,7 +31018,7 @@ function scopingDocChanges(options) {
30227
31018
  material = true;
30228
31019
  reasons.push("key section touched");
30229
31020
  }
30230
- const addedLines = splitLines2(diffText).filter((line) => line.startsWith("+") && !line.startsWith("+++")).map((line) => line.replace(/^\++/u, "").trim());
31021
+ const addedLines = splitLines3(diffText).filter((line) => line.startsWith("+") && !line.startsWith("+++")).map((line) => line.replace(/^\++/u, "").trim());
30231
31022
  if (addedLines.length > 0 && addedLines.every(
30232
31023
  (line) => !line || line.startsWith("[") || line.startsWith("http")
30233
31024
  )) {
@@ -30238,8 +31029,8 @@ function scopingDocChanges(options) {
30238
31029
  }
30239
31030
  let excerpt = null;
30240
31031
  const docPath = `${stripTrailingSlash(root)}/${path11}`;
30241
- if (material && fs9.exists(docPath)) {
30242
- const content = fs9.readTextFile(docPath);
31032
+ if (material && fs10.exists(docPath)) {
31033
+ const content = fs10.readTextFile(docPath);
30243
31034
  const excerptParts = [];
30244
31035
  for (const heading of SCOPING_EXCERPT_HEADINGS) {
30245
31036
  const sectionText = parseSection3(content, heading);
@@ -30315,16 +31106,16 @@ function isDigits2(value) {
30315
31106
  var SUMMARY_CHAR_BUDGET = 16e4;
30316
31107
  var APPENDIX_CHAR_BUDGET = 48e4;
30317
31108
  function collectPrContext(options) {
30318
- const { base, repoRoot, includeUntracked, fs: fs9, runner } = options;
31109
+ const { base, repoRoot, includeUntracked, fs: fs10, runner } = options;
30319
31110
  const head = options.head ?? null;
30320
31111
  const whichGh = options.whichGh;
30321
- let git = new GitClient(runner, repoRoot, fs9);
31112
+ let git = new GitClient(runner, repoRoot, fs10);
30322
31113
  const resolvedRoot = git.resolveRoot();
30323
- git = new GitClient(runner, resolvedRoot, fs9);
31114
+ git = new GitClient(runner, resolvedRoot, fs10);
30324
31115
  const gh = new GhClient({
30325
31116
  runner,
30326
31117
  cwd: resolvedRoot,
30327
- fileSystem: fs9,
31118
+ fileSystem: fs10,
30328
31119
  ...whichGh === void 0 ? {} : { whichGh }
30329
31120
  });
30330
31121
  let ghAvailable = true;
@@ -30347,7 +31138,7 @@ function collectPrContext(options) {
30347
31138
  ghAvailable
30348
31139
  });
30349
31140
  const changedPaths = extractChangedPaths(contextResult.text);
30350
- const featureDocs = gatherFeatureExcerpts2(fs9, resolvedRoot, changedPaths);
31141
+ const featureDocs = gatherFeatureExcerpts2(fs10, resolvedRoot, changedPaths);
30351
31142
  const additionalContextFiles = sortedSet3(
30352
31143
  featureDocs.flatMap((doc) => doc.contextFiles).filter((path11) => path11)
30353
31144
  );
@@ -30460,7 +31251,7 @@ function collectPrContext(options) {
30460
31251
  const statusMap = parseNameStatusMap(nameStatusText);
30461
31252
  const scopingChanges = scopingDocChanges({
30462
31253
  git,
30463
- fs: fs9,
31254
+ fs: fs10,
30464
31255
  mergeBase: contextResult.mergeBase,
30465
31256
  headSha: contextResult.headSha,
30466
31257
  root: resolvedRoot,
@@ -30594,7 +31385,7 @@ function compareCodePoint6(left, right) {
30594
31385
  }
30595
31386
 
30596
31387
  // ../../extensions/drm-copilot/src/lib/pr-context/collector-output.ts
30597
- function renderVerificationEvidenceSection(fs9, resolvedRoot, featureDocs) {
31388
+ function renderVerificationEvidenceSection(fs10, resolvedRoot, featureDocs) {
30598
31389
  const records = [];
30599
31390
  for (const doc of featureDocs) {
30600
31391
  for (const rawPath of doc.contextFiles) {
@@ -30605,7 +31396,7 @@ function renderVerificationEvidenceSection(fs9, resolvedRoot, featureDocs) {
30605
31396
  try {
30606
31397
  records.push(
30607
31398
  parseVerificationEvidenceFile({
30608
- fs: fs9,
31399
+ fs: fs10,
30609
31400
  root: resolvedRoot,
30610
31401
  feature: doc.feature,
30611
31402
  relativePath: normalized
@@ -30627,18 +31418,21 @@ function renderVerificationEvidenceSection(fs9, resolvedRoot, featureDocs) {
30627
31418
  (left, right) => left.sourceFile < right.sourceFile ? -1 : left.sourceFile > right.sourceFile ? 1 : 0
30628
31419
  );
30629
31420
  for (const record2 of sorted) {
31421
+ const expected = record2.expectedExitCode;
31422
+ const expectedRows = expected === 0 ? [] : [` - Expected EXIT_CODE: ${String(expected)}`];
30630
31423
  lines.push(
30631
31424
  `- Feature: ${record2.feature}`,
30632
31425
  ` - Source: ${record2.sourceFile}`,
30633
31426
  ` - Timestamp: ${record2.timestamp}`,
30634
31427
  ` - Command: ${record2.command}`,
30635
31428
  ` - EXIT_CODE: ${record2.exitCode}`,
31429
+ ...expectedRows,
30636
31430
  ` - Normalized result: ${record2.normalizedResult}`
30637
31431
  );
30638
31432
  }
30639
31433
  return lines.join("\n");
30640
31434
  }
30641
- function buildSummaryText(collected, fs9, appendixPath) {
31435
+ function buildSummaryText(collected, fs10, appendixPath) {
30642
31436
  const ctx = collected.contextResult;
30643
31437
  const ghStatusText = resolveGhStatusText(collected);
30644
31438
  const intentBlock = [
@@ -30668,7 +31462,7 @@ function buildSummaryText(collected, fs9, appendixPath) {
30668
31462
  const prDigests = collected.prDetailsList.map((detail) => prDigest(detail)).join("\n\n");
30669
31463
  const featureSummary = buildFeatureSummary(collected.featureDocs);
30670
31464
  const verificationEvidenceSection = renderVerificationEvidenceSection(
30671
- fs9,
31465
+ fs10,
30672
31466
  collected.resolvedRoot,
30673
31467
  collected.featureDocs
30674
31468
  );
@@ -30753,16 +31547,16 @@ function buildAppendixText(collected, clock) {
30753
31547
  }
30754
31548
  return appendixText;
30755
31549
  }
30756
- function writeOutput(fs9, text, outPath, append) {
31550
+ function writeOutput(fs10, text, outPath, append) {
30757
31551
  const parent = parentDir(outPath);
30758
31552
  if (parent) {
30759
- fs9.ensureDir(parent);
31553
+ fs10.ensureDir(parent);
30760
31554
  }
30761
- if (append && fs9.isFile(outPath)) {
30762
- const existing = fs9.readTextFile(outPath);
30763
- fs9.writeTextFile(outPath, existing + text);
31555
+ if (append && fs10.isFile(outPath)) {
31556
+ const existing = fs10.readTextFile(outPath);
31557
+ fs10.writeTextFile(outPath, existing + text);
30764
31558
  } else {
30765
- fs9.writeTextFile(outPath, text);
31559
+ fs10.writeTextFile(outPath, text);
30766
31560
  }
30767
31561
  }
30768
31562
  function collectAndWrite(options) {
@@ -31206,7 +32000,7 @@ function normalizeSmartPunctuation(text) {
31206
32000
  var nodePath7 = __toESM(require("node:path"));
31207
32001
 
31208
32002
  // ../../extensions/drm-copilot/src/lib/potential-to-issue/promotion-filesystem.ts
31209
- var fs6 = __toESM(require("node:fs"));
32003
+ var fs7 = __toESM(require("node:fs"));
31210
32004
  var nodeOs = __toESM(require("node:os"));
31211
32005
  var nodePath6 = __toESM(require("node:path"));
31212
32006
  var RealPotentialFileSystem = class {
@@ -31223,24 +32017,24 @@ var RealPotentialFileSystem = class {
31223
32017
  }
31224
32018
  /** @returns True when `path` exists. */
31225
32019
  exists(path11) {
31226
- return fs6.existsSync(path11);
32020
+ return fs7.existsSync(path11);
31227
32021
  }
31228
32022
  /** @returns The UTF-8 file content. */
31229
32023
  readText(path11) {
31230
- return fs6.readFileSync(path11, "utf8");
32024
+ return fs7.readFileSync(path11, "utf8");
31231
32025
  }
31232
32026
  /** Write `lines` joined with `\n` as UTF-8 text. */
31233
32027
  writeLines(path11, lines) {
31234
- fs6.writeFileSync(path11, lines.join("\n"), "utf8");
32028
+ fs7.writeFileSync(path11, lines.join("\n"), "utf8");
31235
32029
  }
31236
32030
  /** Create `path` and any missing parents (idempotent). */
31237
32031
  ensureDir(path11) {
31238
- fs6.mkdirSync(path11, { recursive: true });
32032
+ fs7.mkdirSync(path11, { recursive: true });
31239
32033
  }
31240
32034
  /** Move `src` to `dest`, ensuring the destination parent exists first. */
31241
32035
  move(src, dest) {
31242
- fs6.mkdirSync(nodePath6.dirname(dest), { recursive: true });
31243
- fs6.renameSync(src, dest);
32036
+ fs7.mkdirSync(nodePath6.dirname(dest), { recursive: true });
32037
+ fs7.renameSync(src, dest);
31244
32038
  }
31245
32039
  };
31246
32040
 
@@ -31465,12 +32259,13 @@ var CommandRunnerGhAdapter = class {
31465
32259
  };
31466
32260
  function potentialToIssueServiceCall(input) {
31467
32261
  const ghClient = input.gh ?? new RealGhClient({ runner: new CommandRunnerGhAdapter(input.runner) });
32262
+ const fileSystem = input.fileSystem ?? new RealPotentialFileSystem();
31468
32263
  const outcome = promotePotential({
31469
32264
  potentialPath: input.potentialPath,
31470
32265
  promotionType: input.promotionType,
31471
32266
  workMode: input.workMode,
31472
32267
  workspace: input.workspaceRoot,
31473
- fs: input.fileSystem ?? new RealPotentialFileSystem(),
32268
+ fs: fileSystem,
31474
32269
  gh: ghClient,
31475
32270
  ...input.log === void 0 ? {} : { emit: input.log }
31476
32271
  });
@@ -31481,6 +32276,11 @@ ${outcome.messages.join("\n")}` : "";
31481
32276
  }
31482
32277
  const summary = `Promoted '${input.potentialPath}' as a ${input.promotionType} workflow in ${input.workMode} mode.`;
31483
32278
  const [issueUrl] = parseIssueReference(outcome.messages);
32279
+ if (outcome.destination !== void 0 && !fileSystem.exists(outcome.destination)) {
32280
+ throw new Error(
32281
+ `potential_to_issue reported a path that does not exist: ${outcome.destination}`
32282
+ );
32283
+ }
31484
32284
  return {
31485
32285
  tool: "potential_to_issue",
31486
32286
  workspaceRoot: input.workspaceRoot,
@@ -31667,12 +32467,12 @@ function validateFeatureName2(featureName) {
31667
32467
  function escapeRegExp6(value) {
31668
32468
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
31669
32469
  }
31670
- function splitLines6(text) {
32470
+ function splitLines7(text) {
31671
32471
  return text.split(/\r\n|\r|\n/);
31672
32472
  }
31673
32473
  function formatChecklist(text) {
31674
32474
  const lines = [];
31675
- for (const rawLine of splitLines6(text)) {
32475
+ for (const rawLine of splitLines7(text)) {
31676
32476
  const trimmed = rawLine.trim();
31677
32477
  if (!trimmed) {
31678
32478
  continue;
@@ -31701,7 +32501,7 @@ function getSection2(content, name) {
31701
32501
  function upsertWorkModeMarker(content, mode) {
31702
32502
  const markerLine = `- Work Mode: ${mode}`;
31703
32503
  const markerPattern = /^- Work Mode:\s*(minor-audit|full-feature|full-bug|full)\s*$/;
31704
- const lines = splitLines6(content).filter((line) => !markerPattern.test(line));
32504
+ const lines = splitLines7(content).filter((line) => !markerPattern.test(line));
31705
32505
  for (let idx = 0; idx < lines.length; idx += 1) {
31706
32506
  const line = lines[idx] ?? "";
31707
32507
  if (line.replace(/^\s+/, "").startsWith("## ")) {
@@ -31886,7 +32686,7 @@ function replaceRegexLiteral(source, pattern, replacement) {
31886
32686
  }
31887
32687
 
31888
32688
  // ../../extensions/drm-copilot/src/lib/new-active-feature-folder/io-launcher.ts
31889
- var fs7 = __toESM(require("node:fs"));
32689
+ var fs8 = __toESM(require("node:fs"));
31890
32690
  var nodePath9 = __toESM(require("node:path"));
31891
32691
  var INSIDERS_SIGNAL_NAMES2 = [
31892
32692
  "TERM_PROGRAM_VERSION",
@@ -31904,7 +32704,7 @@ function defaultWhichLookup2(executable) {
31904
32704
  directory,
31905
32705
  process.platform === "win32" ? `${executable}${extension}` : executable
31906
32706
  );
31907
- if (fs7.existsSync(candidate)) {
32707
+ if (fs8.existsSync(candidate)) {
31908
32708
  return candidate;
31909
32709
  }
31910
32710
  }
@@ -31973,14 +32773,14 @@ function stem(path11) {
31973
32773
  const ext = suffix(path11);
31974
32774
  return ext ? name.slice(0, name.length - ext.length) : name;
31975
32775
  }
31976
- function findPotentialFile(featureName, workspace2, fs9) {
32776
+ function findPotentialFile(featureName, workspace2, fs10) {
31977
32777
  const normalized = featureName.replace(/_/g, "-");
31978
32778
  const potentialDirs = [
31979
32779
  joinPosix13(workspace2, "docs/features/potential"),
31980
32780
  joinPosix13(workspace2, "docs/features/potential/promoted")
31981
32781
  ];
31982
32782
  for (const directory of potentialDirs) {
31983
- const candidates = fs9.listFiles(directory).filter(
32783
+ const candidates = fs10.listFiles(directory).filter(
31984
32784
  (file) => suffix(file) === ".md" && baseName(file).includes(normalized) && !EXCLUDED_POTENTIAL_NAMES.has(baseName(file))
31985
32785
  );
31986
32786
  if (candidates.length > 0) {
@@ -32011,12 +32811,12 @@ function buildFolderSlug(featureName, potentialFile, issueNumber) {
32011
32811
  }
32012
32812
  return slug;
32013
32813
  }
32014
- function copyTemplate(featureType, templateDir, targetDir, fs9) {
32814
+ function copyTemplate(featureType, templateDir, targetDir, fs10) {
32015
32815
  if (featureType === "bug") {
32016
32816
  for (const name of ["spec.md", PLAN_TIMESTAMP_TEMPLATE_NAME, "plan.md"]) {
32017
32817
  const src = joinPosix13(templateDir, name);
32018
- if (fs9.exists(src)) {
32019
- fs9.copyFile(src, joinPosix13(targetDir, name));
32818
+ if (fs10.exists(src)) {
32819
+ fs10.copyFile(src, joinPosix13(targetDir, name));
32020
32820
  if (name === PLAN_TIMESTAMP_TEMPLATE_NAME) {
32021
32821
  break;
32022
32822
  }
@@ -32025,35 +32825,35 @@ function copyTemplate(featureType, templateDir, targetDir, fs9) {
32025
32825
  } else if (featureType === "epic") {
32026
32826
  for (const name of ["epic.md", "epic-status.md"]) {
32027
32827
  const src = joinPosix13(templateDir, name);
32028
- if (fs9.exists(src)) {
32029
- fs9.copyFile(src, joinPosix13(targetDir, name));
32828
+ if (fs10.exists(src)) {
32829
+ fs10.copyFile(src, joinPosix13(targetDir, name));
32030
32830
  }
32031
32831
  }
32032
32832
  } else {
32033
- fs9.copyTree(templateDir, targetDir);
32833
+ fs10.copyTree(templateDir, targetDir);
32034
32834
  }
32035
32835
  }
32036
- function copyFeatureTemplateForMinorAudit(templateDir, targetDir, fs9) {
32836
+ function copyFeatureTemplateForMinorAudit(templateDir, targetDir, fs10) {
32037
32837
  const timestampedPlan = joinPosix13(templateDir, PLAN_TIMESTAMP_TEMPLATE_NAME);
32038
- if (fs9.exists(timestampedPlan)) {
32039
- fs9.copyFile(
32838
+ if (fs10.exists(timestampedPlan)) {
32839
+ fs10.copyFile(
32040
32840
  timestampedPlan,
32041
32841
  joinPosix13(targetDir, PLAN_TIMESTAMP_TEMPLATE_NAME)
32042
32842
  );
32043
32843
  return;
32044
32844
  }
32045
32845
  const legacyPlan = joinPosix13(templateDir, "plan.md");
32046
- if (fs9.exists(legacyPlan)) {
32047
- fs9.copyFile(legacyPlan, joinPosix13(targetDir, "plan.md"));
32846
+ if (fs10.exists(legacyPlan)) {
32847
+ fs10.copyFile(legacyPlan, joinPosix13(targetDir, "plan.md"));
32048
32848
  }
32049
32849
  }
32050
- function materializePlanFile(featureType, targetDir, featureName, issueField, ownerField, parentField, statusField, versionField, planTimestamp, fs9) {
32850
+ function materializePlanFile(featureType, targetDir, featureName, issueField, ownerField, parentField, statusField, versionField, planTimestamp, fs10) {
32051
32851
  void featureType;
32052
32852
  const templatePlan = joinPosix13(targetDir, PLAN_TIMESTAMP_TEMPLATE_NAME);
32053
- if (fs9.exists(templatePlan)) {
32853
+ if (fs10.exists(templatePlan)) {
32054
32854
  const targetPlan = joinPosix13(targetDir, `plan.${planTimestamp}.md`);
32055
- fs9.move(templatePlan, targetPlan);
32056
- let content = fs9.readText(targetPlan);
32855
+ fs10.move(templatePlan, targetPlan);
32856
+ let content = fs10.readText(targetPlan);
32057
32857
  const updatedField = planTimestamp;
32058
32858
  content = setHeaderPlaceholder(
32059
32859
  content,
@@ -32065,11 +32865,11 @@ function materializePlanFile(featureType, targetDir, featureName, issueField, ow
32065
32865
  parentField,
32066
32866
  versionField
32067
32867
  );
32068
- fs9.writeText(targetPlan, content);
32868
+ fs10.writeText(targetPlan, content);
32069
32869
  return targetPlan;
32070
32870
  }
32071
32871
  const legacy = joinPosix13(targetDir, "plan.md");
32072
- if (fs9.exists(legacy)) {
32872
+ if (fs10.exists(legacy)) {
32073
32873
  return legacy;
32074
32874
  }
32075
32875
  return null;
@@ -32114,11 +32914,11 @@ function defaultIssueFetcher(issueNumber, runner, ghLookup = defaultGhLookup) {
32114
32914
  }
32115
32915
 
32116
32916
  // ../../extensions/drm-copilot/src/lib/new-active-feature-folder/docs.ts
32117
- function applyHeaderAndSections(path11, featureName, issueField, ownerField, updatedField, parentField, statusField, versionField, fs9, updates) {
32118
- if (!fs9.exists(path11)) {
32917
+ function applyHeaderAndSections(path11, featureName, issueField, ownerField, updatedField, parentField, statusField, versionField, fs10, updates) {
32918
+ if (!fs10.exists(path11)) {
32119
32919
  return;
32120
32920
  }
32121
- let content = fs9.readText(path11);
32921
+ let content = fs10.readText(path11);
32122
32922
  content = setHeaderPlaceholder(
32123
32923
  content,
32124
32924
  featureName,
@@ -32132,9 +32932,9 @@ function applyHeaderAndSections(path11, featureName, issueField, ownerField, upd
32132
32932
  for (const [sectionName, body] of updates) {
32133
32933
  content = setSection(content, sectionName, body);
32134
32934
  }
32135
- fs9.writeText(path11, content);
32935
+ fs10.writeText(path11, content);
32136
32936
  }
32137
- function updateFeatureDocs(featureType, featureName, targetDir, issueField, ownerField, updatedField, parentField, statusField, versionField, planUpdatedField, fs9, sections, planPath) {
32937
+ function updateFeatureDocs(featureType, featureName, targetDir, issueField, ownerField, updatedField, parentField, statusField, versionField, planUpdatedField, fs10, sections, planPath) {
32138
32938
  const filesToOpen = [];
32139
32939
  const get = (key) => sections[key] ?? "";
32140
32940
  if (featureType === "feature") {
@@ -32150,7 +32950,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
32150
32950
  parentField,
32151
32951
  statusField,
32152
32952
  versionField,
32153
- fs9,
32953
+ fs10,
32154
32954
  [
32155
32955
  ["Problem / Why", get("problem")],
32156
32956
  ["Acceptance Criteria", formatChecklist(get("criteria"))]
@@ -32165,7 +32965,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
32165
32965
  parentField,
32166
32966
  statusField,
32167
32967
  versionField,
32168
- fs9,
32968
+ fs10,
32169
32969
  [
32170
32970
  ["Overview", get("problem")],
32171
32971
  ["Behavior", get("behavior")],
@@ -32185,7 +32985,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
32185
32985
  parentField,
32186
32986
  statusField,
32187
32987
  versionField,
32188
- fs9,
32988
+ fs10,
32189
32989
  []
32190
32990
  );
32191
32991
  filesToOpen.push(userStory, spec, plan);
@@ -32201,7 +33001,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
32201
33001
  parentField,
32202
33002
  statusField,
32203
33003
  versionField,
32204
- fs9,
33004
+ fs10,
32205
33005
  [
32206
33006
  ["Intent & Outcomes", get("problem")],
32207
33007
  ["Scope (structural changes)", get("behavior")],
@@ -32221,7 +33021,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
32221
33021
  parentField,
32222
33022
  statusField,
32223
33023
  versionField,
32224
- fs9,
33024
+ fs10,
32225
33025
  []
32226
33026
  );
32227
33027
  filesToOpen.push(spec, plan);
@@ -32236,7 +33036,7 @@ function updateFeatureDocs(featureType, featureName, targetDir, issueField, owne
32236
33036
  parentField,
32237
33037
  statusField,
32238
33038
  versionField,
32239
- fs9,
33039
+ fs10,
32240
33040
  []
32241
33041
  );
32242
33042
  filesToOpen.push(epic);
@@ -32298,11 +33098,11 @@ ${get("bug_logs")}`);
32298
33098
  parentField,
32299
33099
  statusField,
32300
33100
  versionField,
32301
- fs9,
33101
+ fs10,
32302
33102
  updates
32303
33103
  );
32304
33104
  if (bugValidation) {
32305
- let specContent = fs9.readText(spec);
33105
+ let specContent = fs10.readText(spec);
32306
33106
  const updateTestStrategy = (body) => prependToSectionBody(body, `Seeded from issue:
32307
33107
 
32308
33108
  ${bugValidation}`);
@@ -32311,7 +33111,7 @@ ${bugValidation}`);
32311
33111
  "Test Strategy",
32312
33112
  updateTestStrategy
32313
33113
  );
32314
- fs9.writeText(spec, specContent);
33114
+ fs10.writeText(spec, specContent);
32315
33115
  }
32316
33116
  applyHeaderAndSections(
32317
33117
  plan,
@@ -32322,7 +33122,7 @@ ${bugValidation}`);
32322
33122
  parentField,
32323
33123
  statusField,
32324
33124
  versionField,
32325
- fs9,
33125
+ fs10,
32326
33126
  []
32327
33127
  );
32328
33128
  filesToOpen.push(spec, plan);
@@ -32393,6 +33193,7 @@ function createActiveFolder(options) {
32393
33193
  filesystem
32394
33194
  );
32395
33195
  const potentialContent = potentialFile ? filesystem.readText(potentialFile) : "";
33196
+ const retainsPotentialSource = potentialFile !== null && isPromotedPotentialSource(potentialFile, workspacePath);
32396
33197
  const selectedWorkMode = normalizeRequestedWorkMode(workMode, featureType);
32397
33198
  const [useMinorAudit, fallbackReason] = shouldUseMinorAuditMode(
32398
33199
  selectedWorkMode,
@@ -32480,7 +33281,11 @@ function createActiveFolder(options) {
32480
33281
  if (useMinorAudit) {
32481
33282
  if (potentialFile) {
32482
33283
  potentialIssuePath = joinPosix13(targetDir, "issue.md");
32483
- filesystem.move(potentialFile, potentialIssuePath);
33284
+ if (retainsPotentialSource) {
33285
+ filesystem.copyFile(potentialFile, potentialIssuePath);
33286
+ } else {
33287
+ filesystem.move(potentialFile, potentialIssuePath);
33288
+ }
32484
33289
  const movedContent = filesystem.readText(potentialIssuePath);
32485
33290
  filesystem.writeText(
32486
33291
  potentialIssuePath,
@@ -32536,17 +33341,25 @@ function createActiveFolder(options) {
32536
33341
  if (potentialFile) {
32537
33342
  if (useMinorAudit) {
32538
33343
  if (potentialIssuePath !== null) {
32539
- emit(`Moved potential file to ${potentialIssuePath}`);
33344
+ emit(
33345
+ retainsPotentialSource ? `Copied potential file to ${potentialIssuePath}` : `Moved potential file to ${potentialIssuePath}`
33346
+ );
32540
33347
  }
32541
33348
  } else {
32542
33349
  potentialIssuePath = joinPosix13(targetDir, "issue.md");
32543
- filesystem.move(potentialFile, potentialIssuePath);
33350
+ if (retainsPotentialSource) {
33351
+ filesystem.copyFile(potentialFile, potentialIssuePath);
33352
+ } else {
33353
+ filesystem.move(potentialFile, potentialIssuePath);
33354
+ }
32544
33355
  const movedContent = filesystem.readText(potentialIssuePath);
32545
33356
  filesystem.writeText(
32546
33357
  potentialIssuePath,
32547
33358
  upsertWorkModeMarker(movedContent, selectedWorkMode)
32548
33359
  );
32549
- emit(`Moved potential file to ${potentialIssuePath}`);
33360
+ emit(
33361
+ retainsPotentialSource ? `Copied potential file to ${potentialIssuePath}` : `Moved potential file to ${potentialIssuePath}`
33362
+ );
32550
33363
  }
32551
33364
  }
32552
33365
  if (potentialFile) {
@@ -32585,6 +33398,12 @@ function isRelativeTo(child, root) {
32585
33398
  const normalizedRoot = toPosixPath2(root);
32586
33399
  return normalizedChild === normalizedRoot || normalizedChild.startsWith(`${normalizedRoot}/`);
32587
33400
  }
33401
+ function isPromotedPotentialSource(potentialPath, workspacePath) {
33402
+ return isRelativeTo(
33403
+ potentialPath,
33404
+ joinPosix13(workspacePath, "docs/features/potential/promoted")
33405
+ );
33406
+ }
32588
33407
  function posixBaseName(path11) {
32589
33408
  const normalized = toPosixPath2(path11).replace(/\/+$/, "");
32590
33409
  const slash = normalized.lastIndexOf("/");
@@ -32597,7 +33416,15 @@ function posixStem2(path11) {
32597
33416
  }
32598
33417
 
32599
33418
  // ../../extensions/drm-copilot/src/lib/new-active-feature-folder/new-active-feature-folder-service-call.ts
33419
+ function requireReportedPathExists(fileSystem, path11) {
33420
+ if (!fileSystem.exists(path11)) {
33421
+ throw new Error(
33422
+ `new_active_feature_folder reported a path that does not exist: ${path11}`
33423
+ );
33424
+ }
33425
+ }
32600
33426
  function newActiveFeatureFolderServiceCall(input) {
33427
+ const fileSystem = input.fileSystem ?? new RealFolderFileSystem();
32601
33428
  const result = createActiveFolder({
32602
33429
  featureName: input.featureName,
32603
33430
  featureType: input.type,
@@ -32605,13 +33432,17 @@ function newActiveFeatureFolderServiceCall(input) {
32605
33432
  workMode: input.workMode,
32606
33433
  workspace: input.workspaceRoot,
32607
33434
  templateRoot: input.templateRoot,
32608
- fs: input.fileSystem ?? new RealFolderFileSystem(),
33435
+ fs: fileSystem,
32609
33436
  // Route the guarded gh issue fetch through the injected F1 runner.
32610
33437
  issueFetcher: (issueNumber) => defaultIssueFetcher(issueNumber, input.runner),
32611
33438
  // No-op launcher: the MCP/non-interactive path must never open an editor.
32612
33439
  codeLauncher: () => false,
32613
33440
  ...input.log === void 0 ? {} : { emit: input.log }
32614
33441
  });
33442
+ requireReportedPathExists(fileSystem, result.target);
33443
+ if (result.potentialIssuePath !== null) {
33444
+ requireReportedPathExists(fileSystem, result.potentialIssuePath);
33445
+ }
32615
33446
  return {
32616
33447
  tool: "new_active_feature_folder",
32617
33448
  workspaceRoot: input.workspaceRoot,
@@ -33388,7 +34219,7 @@ function readPackageVersion(extensionRoot) {
33388
34219
  const packageJsonPath = path10.join(extensionRoot, "package.json");
33389
34220
  try {
33390
34221
  const packageJson = JSON.parse(
33391
- fs8.readFileSync(packageJsonPath, "utf-8")
34222
+ fs9.readFileSync(packageJsonPath, "utf-8")
33392
34223
  );
33393
34224
  return packageJson.version ?? "0.0.1";
33394
34225
  } catch {