@danmoisan/drm-copilot-mcp 1.0.26 → 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 (38) hide show
  1. package/out/mcp-server.js +542 -41
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +109 -5
  4. package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +390 -0
  5. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +105 -2
  6. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +32 -52
  7. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +107 -99
  8. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +295 -0
  9. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +9 -3
  10. package/resources/claude-customizations/.claude/lib/mermaid/MermaidGrammar.psm1 +491 -0
  11. package/resources/claude-customizations/.claude/lib/mermaid/MermaidLineScanner.psm1 +488 -0
  12. package/resources/claude-customizations/.claude/lib/mermaid/MermaidMarkdownFences.psm1 +298 -0
  13. package/resources/claude-customizations/.claude/lib/mermaid/MermaidValidation.psm1 +496 -0
  14. package/resources/claude-customizations/.claude/rules/mermaid.md +142 -0
  15. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +61 -1
  16. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +116 -0
  17. package/resources/claude-customizations/.claude/settings.json +5 -0
  18. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +15 -0
  19. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  20. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +6 -0
  21. package/resources/claude-customizations/.claude/skills/mermaid-diagram/SKILL.md +184 -0
  22. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/c4.md +50 -0
  23. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/class.md +63 -0
  24. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/er.md +56 -0
  25. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/flowchart.md +68 -0
  26. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/gantt.md +51 -0
  27. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/other-types.md +82 -0
  28. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/pie.md +32 -0
  29. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/sequence.md +63 -0
  30. package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/state.md +49 -0
  31. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +8 -7
  32. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +24 -4
  33. package/resources/claude-customizations/config/blast-radius.json +8 -0
  34. package/resources/claude-customizations/pack-manifests/core.json +19 -1
  35. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  36. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  37. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
  38. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +16 -1
package/out/mcp-server.js CHANGED
@@ -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) {
@@ -19015,7 +19016,8 @@ var CARRIED_KEYS = [
19015
19016
  "version",
19016
19017
  "shared_surfaces",
19017
19018
  "shared_surface_globs",
19018
- "over_breadth_fraction"
19019
+ "over_breadth_fraction",
19020
+ "mandate_reads"
19019
19021
  ];
19020
19022
  var BlastRadiusDeriveError = class extends Error {
19021
19023
  /** Destination-relative path of the document that failed to parse. */
@@ -19143,6 +19145,7 @@ function deriveDestinationModuleMap(observations, sourceDocumentText) {
19143
19145
  version: source[CARRIED_KEYS[0]],
19144
19146
  shared_surfaces: source[CARRIED_KEYS[1]],
19145
19147
  shared_surface_globs: source[CARRIED_KEYS[2]],
19148
+ mandate_reads: source[CARRIED_KEYS[4]],
19146
19149
  modules,
19147
19150
  over_breadth_fraction: source[CARRIED_KEYS[3]]
19148
19151
  };
@@ -26846,6 +26849,417 @@ function validateParallelKickoffText(text) {
26846
26849
  return parseParallelKickoff(text).errors;
26847
26850
  }
26848
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
+
26849
27263
  // ../../extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts
26850
27264
  function words(text) {
26851
27265
  return text.split(" ");
@@ -28020,7 +28434,7 @@ var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
28020
28434
  "Per-language comparison summary:"
28021
28435
  ];
28022
28436
  var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
28023
- var PLACEHOLDER_MARKERS = [
28437
+ var PLACEHOLDER_MARKERS2 = [
28024
28438
  "[n]",
28025
28439
  "[path",
28026
28440
  "[artifact",
@@ -28046,7 +28460,7 @@ function isNaValue(value) {
28046
28460
  }
28047
28461
  function hasPlaceholderMarker(value) {
28048
28462
  const lowered = value.toLowerCase();
28049
- return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
28463
+ return PLACEHOLDER_MARKERS2.some((marker) => lowered.includes(marker));
28050
28464
  }
28051
28465
  function reportsMissingTemplateResolverSuccess(text) {
28052
28466
  const lowered = text.toLowerCase();
@@ -28353,10 +28767,28 @@ function validatePlanText(text) {
28353
28767
  }
28354
28768
  return errors;
28355
28769
  }
28356
- 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) {
28357
28791
  switch (input.artifactType) {
28358
- case "plan":
28359
- return validatePlanText(input.text);
28360
28792
  case "policy-audit":
28361
28793
  return validatePolicyAuditText(input.text);
28362
28794
  case "code-review":
@@ -28419,12 +28851,13 @@ function validateArtifact(input) {
28419
28851
  }
28420
28852
 
28421
28853
  // ../../extensions/drm-copilot/src/lib/validate/validate-orchestration-service-call.ts
28854
+ var PLAN_GATE_WARNING_PREFIX = "PLAN GATE WARNING: ";
28422
28855
  function validateOrchestrationServiceCall(input) {
28423
28856
  const artifactFullPath = toPosixPath2(
28424
28857
  path9.join(input.workspaceRoot, input.artifactPath)
28425
28858
  );
28426
28859
  const text = input.fileSystem.readTextFile(artifactFullPath);
28427
- const errors = validateArtifact({
28860
+ const { errors, warnings } = validateArtifactWithWarnings({
28428
28861
  artifactType: input.artifactType,
28429
28862
  text,
28430
28863
  ...input.requireComplete === void 0 ? {} : { requireComplete: input.requireComplete },
@@ -28438,15 +28871,17 @@ function validateOrchestrationServiceCall(input) {
28438
28871
  root: input.workspaceRoot
28439
28872
  });
28440
28873
  if (errors.length > 0) {
28874
+ const warningBlock = warnings.length === 0 ? "" : "\n" + warnings.map((warning) => `${PLAN_GATE_WARNING_PREFIX}${warning}`).join("\n");
28441
28875
  throw new Error(
28442
28876
  `Validation failed for ${input.artifactType} artifact at '${input.artifactPath}':
28443
- ${errors.join("\n")}`
28877
+ ${errors.join("\n")}${warningBlock}`
28444
28878
  );
28445
28879
  }
28446
28880
  return {
28447
28881
  tool: "validate_orchestration_artifacts",
28448
28882
  workspaceRoot: input.workspaceRoot,
28449
- summary: `Validated ${input.artifactType} artifact at '${input.artifactPath}'.`
28883
+ summary: `Validated ${input.artifactType} artifact at '${input.artifactPath}'.`,
28884
+ ...warnings.length === 0 ? {} : { warnings }
28450
28885
  };
28451
28886
  }
28452
28887
 
@@ -28669,7 +29104,7 @@ function truncate(text, limit = 800) {
28669
29104
  }
28670
29105
  return rstrip3(text.slice(0, limit - 3)) + "...";
28671
29106
  }
28672
- function splitLines2(value) {
29107
+ function splitLines3(value) {
28673
29108
  if (value === "") {
28674
29109
  return [];
28675
29110
  }
@@ -28680,7 +29115,7 @@ function splitLines2(value) {
28680
29115
  return lines;
28681
29116
  }
28682
29117
  function truncateLines(text, limit) {
28683
- const lines = splitLines2(text);
29118
+ const lines = splitLines3(text);
28684
29119
  if (lines.length <= limit) {
28685
29120
  return text;
28686
29121
  }
@@ -29444,7 +29879,7 @@ function convertNumstat(numstatText) {
29444
29879
  let adds = 0;
29445
29880
  let dels = 0;
29446
29881
  const files = [];
29447
- for (const rawLine of splitLines3(numstatText)) {
29882
+ for (const rawLine of splitLines4(numstatText)) {
29448
29883
  if (!rawLine.trim()) {
29449
29884
  continue;
29450
29885
  }
@@ -29507,7 +29942,7 @@ function summarizeConventionalCommits(subjects) {
29507
29942
  }
29508
29943
  counts.set("other", 0);
29509
29944
  const typePattern = /^(feat|fix|refactor|perf|docs|test|chore|build|ci|style)(\(|!|:)/u;
29510
- for (const rawLine of splitLines3(subjects)) {
29945
+ for (const rawLine of splitLines4(subjects)) {
29511
29946
  const line = rawLine.trim();
29512
29947
  if (!line) {
29513
29948
  continue;
@@ -29562,7 +29997,7 @@ function buildIssuesToAutocloseSection(params) {
29562
29997
  function extractChangedPaths(contextText) {
29563
29998
  const paths = [];
29564
29999
  let capture = false;
29565
- for (const line of splitLines3(contextText)) {
30000
+ for (const line of splitLines4(contextText)) {
29566
30001
  if (line.startsWith("===== Changed files")) {
29567
30002
  capture = true;
29568
30003
  continue;
@@ -29608,7 +30043,7 @@ function compareCodePoint2(left, right) {
29608
30043
  }
29609
30044
  return 0;
29610
30045
  }
29611
- function splitLines3(value) {
30046
+ function splitLines4(value) {
29612
30047
  if (value === "") {
29613
30048
  return [];
29614
30049
  }
@@ -29678,7 +30113,7 @@ function buildPrContext(options) {
29678
30113
  const subjects = git.log("--pretty=%s", revRange);
29679
30114
  const authors = git.log("--format=%an <%ae>", revRange);
29680
30115
  const authorsList = sortedSet2(
29681
- splitLines4(authors).map((line) => line.trim()).filter((line) => line)
30116
+ splitLines5(authors).map((line) => line.trim()).filter((line) => line)
29682
30117
  );
29683
30118
  const nameStatus = git.diffRange(["--name-status", mergeBase, headSha]);
29684
30119
  const numstat = git.diffRange(["--numstat", mergeBase, headSha]);
@@ -29686,7 +30121,7 @@ function buildPrContext(options) {
29686
30121
  const stat = git.diffRange(["--stat", mergeBase, headSha]);
29687
30122
  const [additions, deletions, files] = convertNumstat(numstat);
29688
30123
  const extSummary = extensionSummary(files);
29689
- const mergePrs = extractMergePrNumbers(splitLines4(oneline));
30124
+ const mergePrs = extractMergePrNumbers(splitLines5(oneline));
29690
30125
  const issueCandidates = extractIssueReferences(
29691
30126
  oneline + "\n" + subjects
29692
30127
  ).filter((ref) => !mergePrs.includes(ref));
@@ -29845,7 +30280,7 @@ function compareCodePoint3(left, right) {
29845
30280
  }
29846
30281
  return 0;
29847
30282
  }
29848
- function splitLines4(value) {
30283
+ function splitLines5(value) {
29849
30284
  if (value === "") {
29850
30285
  return [];
29851
30286
  }
@@ -29871,7 +30306,7 @@ function parseSection2(markdown, heading) {
29871
30306
  }
29872
30307
  function completedPlanTasks2(markdown, limit = 10) {
29873
30308
  const tasks = [];
29874
- for (const line of splitLines2(markdown)) {
30309
+ for (const line of splitLines3(markdown)) {
29875
30310
  if (/\[x\]/iu.test(line)) {
29876
30311
  const cleaned = line.replace(/^[-*]\s*\[[xX]\]\s*/u, "").trim();
29877
30312
  tasks.push(cleaned);
@@ -29950,7 +30385,7 @@ function parsePrimaryIssueFromMetadata(params) {
29950
30385
  params.storyText,
29951
30386
  params.issueText
29952
30387
  ]) {
29953
- for (const line of splitLines2(sourceText)) {
30388
+ for (const line of splitLines3(sourceText)) {
29954
30389
  const match = pattern.exec(line);
29955
30390
  if (match) {
29956
30391
  return match[1];
@@ -30009,11 +30444,15 @@ function escapeRegExp4(value) {
30009
30444
 
30010
30445
  // ../../extensions/drm-copilot/src/lib/pr-context/verification-evidence.ts
30011
30446
  var REQUIRED_FIELDS = ["Timestamp", "Command", "EXIT_CODE"];
30447
+ var EXPECTED_EXIT_CODE_FIELD = "ExpectedExitCode";
30012
30448
  var CANONICAL_GLOBS = [
30013
30449
  "evidence/qa-gates/**/*.md",
30014
30450
  "evidence/regression-testing/**/*.md",
30015
30451
  "evidence/other/**/*.md"
30016
30452
  ];
30453
+ function normalizeResult(exitCode, expectedExitCode) {
30454
+ return exitCode === expectedExitCode ? "pass" : "fail";
30455
+ }
30017
30456
  function discoverCanonicalEvidenceFiles(fs10, root, feature) {
30018
30457
  const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
30019
30458
  const featureRoot = `${normalizedRoot}/docs/features/active/${feature}`;
@@ -30033,7 +30472,7 @@ function discoverCanonicalEvidenceFiles(fs10, root, feature) {
30033
30472
  function parseVerificationEvidenceMarkdown(params) {
30034
30473
  const { feature, sourceFile, markdown } = params;
30035
30474
  const parsed = /* @__PURE__ */ new Map();
30036
- for (const rawLine of splitLines5(markdown)) {
30475
+ for (const rawLine of splitLines6(markdown)) {
30037
30476
  const colonIndex = rawLine.indexOf(":");
30038
30477
  if (colonIndex === -1) {
30039
30478
  continue;
@@ -30043,10 +30482,14 @@ function parseVerificationEvidenceMarkdown(params) {
30043
30482
  if (REQUIRED_FIELDS.includes(key) && !parsed.has(key)) {
30044
30483
  parsed.set(key, value);
30045
30484
  }
30485
+ if (key === EXPECTED_EXIT_CODE_FIELD && !parsed.has(key)) {
30486
+ parsed.set(key, value);
30487
+ }
30046
30488
  }
30047
30489
  const timestamp = parsed.get("Timestamp") ?? null;
30048
30490
  const command = parsed.get("Command") ?? null;
30049
30491
  const exitCodeRaw = parsed.get("EXIT_CODE");
30492
+ const expectedExitCodeRaw = parsed.get(EXPECTED_EXIT_CODE_FIELD);
30050
30493
  if (!timestamp || !command || exitCodeRaw === void 0) {
30051
30494
  return {
30052
30495
  feature,
@@ -30054,7 +30497,8 @@ function parseVerificationEvidenceMarkdown(params) {
30054
30497
  timestamp,
30055
30498
  command,
30056
30499
  exitCode: null,
30057
- normalizedResult: "unparseable"
30500
+ normalizedResult: "unparseable",
30501
+ expectedExitCode: 0
30058
30502
  };
30059
30503
  }
30060
30504
  const exitCode = parseIntegerStrict(exitCodeRaw);
@@ -30065,17 +30509,34 @@ function parseVerificationEvidenceMarkdown(params) {
30065
30509
  timestamp,
30066
30510
  command,
30067
30511
  exitCode: null,
30068
- normalizedResult: "unparseable"
30512
+ normalizedResult: "unparseable",
30513
+ expectedExitCode: 0
30069
30514
  };
30070
30515
  }
30071
- const normalizedResult = exitCode === 0 ? "pass" : "fail";
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
30526
+ };
30527
+ }
30528
+ const normalizedResult = normalizeResult(
30529
+ exitCode,
30530
+ expectedExitCode
30531
+ );
30072
30532
  return {
30073
30533
  feature,
30074
30534
  sourceFile,
30075
30535
  timestamp,
30076
30536
  command,
30077
30537
  exitCode,
30078
- normalizedResult
30538
+ normalizedResult,
30539
+ expectedExitCode
30079
30540
  };
30080
30541
  }
30081
30542
  function parseVerificationEvidenceFile(params) {
@@ -30111,7 +30572,7 @@ function compareCodePoint5(left, right) {
30111
30572
  }
30112
30573
  return 0;
30113
30574
  }
30114
- function splitLines5(value) {
30575
+ function splitLines6(value) {
30115
30576
  if (value === "") {
30116
30577
  return [];
30117
30578
  }
@@ -30333,7 +30794,7 @@ function extractDigestBullets(body, headings, limit) {
30333
30794
  if (!sectionText) {
30334
30795
  continue;
30335
30796
  }
30336
- for (const line of splitLines2(sectionText)) {
30797
+ for (const line of splitLines3(sectionText)) {
30337
30798
  if (!line.trim()) {
30338
30799
  continue;
30339
30800
  }
@@ -30474,7 +30935,7 @@ function parseNumstatDetailed(numstatText) {
30474
30935
  let addsTotal = 0;
30475
30936
  let delsTotal = 0;
30476
30937
  const perFile = /* @__PURE__ */ new Map();
30477
- for (const rawLine of splitLines2(numstatText)) {
30938
+ for (const rawLine of splitLines3(numstatText)) {
30478
30939
  if (!rawLine.trim()) {
30479
30940
  continue;
30480
30941
  }
@@ -30493,7 +30954,7 @@ function parseNumstatDetailed(numstatText) {
30493
30954
  }
30494
30955
  function parseNameStatusMap(nameStatusText) {
30495
30956
  const mapping = /* @__PURE__ */ new Map();
30496
- for (const rawLine of splitLines2(nameStatusText)) {
30957
+ for (const rawLine of splitLines3(nameStatusText)) {
30497
30958
  if (!rawLine.trim()) {
30498
30959
  continue;
30499
30960
  }
@@ -30541,7 +31002,7 @@ function scopingDocChanges(options) {
30541
31002
  path11
30542
31003
  ]);
30543
31004
  let headingTouched = false;
30544
- for (const line of splitLines2(diffText)) {
31005
+ for (const line of splitLines3(diffText)) {
30545
31006
  if (!line.startsWith("+") || line.startsWith("+++")) {
30546
31007
  continue;
30547
31008
  }
@@ -30557,7 +31018,7 @@ function scopingDocChanges(options) {
30557
31018
  material = true;
30558
31019
  reasons.push("key section touched");
30559
31020
  }
30560
- 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());
30561
31022
  if (addedLines.length > 0 && addedLines.every(
30562
31023
  (line) => !line || line.startsWith("[") || line.startsWith("http")
30563
31024
  )) {
@@ -30957,12 +31418,15 @@ function renderVerificationEvidenceSection(fs10, resolvedRoot, featureDocs) {
30957
31418
  (left, right) => left.sourceFile < right.sourceFile ? -1 : left.sourceFile > right.sourceFile ? 1 : 0
30958
31419
  );
30959
31420
  for (const record2 of sorted) {
31421
+ const expected = record2.expectedExitCode;
31422
+ const expectedRows = expected === 0 ? [] : [` - Expected EXIT_CODE: ${String(expected)}`];
30960
31423
  lines.push(
30961
31424
  `- Feature: ${record2.feature}`,
30962
31425
  ` - Source: ${record2.sourceFile}`,
30963
31426
  ` - Timestamp: ${record2.timestamp}`,
30964
31427
  ` - Command: ${record2.command}`,
30965
31428
  ` - EXIT_CODE: ${record2.exitCode}`,
31429
+ ...expectedRows,
30966
31430
  ` - Normalized result: ${record2.normalizedResult}`
30967
31431
  );
30968
31432
  }
@@ -31795,12 +32259,13 @@ var CommandRunnerGhAdapter = class {
31795
32259
  };
31796
32260
  function potentialToIssueServiceCall(input) {
31797
32261
  const ghClient = input.gh ?? new RealGhClient({ runner: new CommandRunnerGhAdapter(input.runner) });
32262
+ const fileSystem = input.fileSystem ?? new RealPotentialFileSystem();
31798
32263
  const outcome = promotePotential({
31799
32264
  potentialPath: input.potentialPath,
31800
32265
  promotionType: input.promotionType,
31801
32266
  workMode: input.workMode,
31802
32267
  workspace: input.workspaceRoot,
31803
- fs: input.fileSystem ?? new RealPotentialFileSystem(),
32268
+ fs: fileSystem,
31804
32269
  gh: ghClient,
31805
32270
  ...input.log === void 0 ? {} : { emit: input.log }
31806
32271
  });
@@ -31811,6 +32276,11 @@ ${outcome.messages.join("\n")}` : "";
31811
32276
  }
31812
32277
  const summary = `Promoted '${input.potentialPath}' as a ${input.promotionType} workflow in ${input.workMode} mode.`;
31813
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
+ }
31814
32284
  return {
31815
32285
  tool: "potential_to_issue",
31816
32286
  workspaceRoot: input.workspaceRoot,
@@ -31997,12 +32467,12 @@ function validateFeatureName2(featureName) {
31997
32467
  function escapeRegExp6(value) {
31998
32468
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
31999
32469
  }
32000
- function splitLines6(text) {
32470
+ function splitLines7(text) {
32001
32471
  return text.split(/\r\n|\r|\n/);
32002
32472
  }
32003
32473
  function formatChecklist(text) {
32004
32474
  const lines = [];
32005
- for (const rawLine of splitLines6(text)) {
32475
+ for (const rawLine of splitLines7(text)) {
32006
32476
  const trimmed = rawLine.trim();
32007
32477
  if (!trimmed) {
32008
32478
  continue;
@@ -32031,7 +32501,7 @@ function getSection2(content, name) {
32031
32501
  function upsertWorkModeMarker(content, mode) {
32032
32502
  const markerLine = `- Work Mode: ${mode}`;
32033
32503
  const markerPattern = /^- Work Mode:\s*(minor-audit|full-feature|full-bug|full)\s*$/;
32034
- const lines = splitLines6(content).filter((line) => !markerPattern.test(line));
32504
+ const lines = splitLines7(content).filter((line) => !markerPattern.test(line));
32035
32505
  for (let idx = 0; idx < lines.length; idx += 1) {
32036
32506
  const line = lines[idx] ?? "";
32037
32507
  if (line.replace(/^\s+/, "").startsWith("## ")) {
@@ -32723,6 +33193,7 @@ function createActiveFolder(options) {
32723
33193
  filesystem
32724
33194
  );
32725
33195
  const potentialContent = potentialFile ? filesystem.readText(potentialFile) : "";
33196
+ const retainsPotentialSource = potentialFile !== null && isPromotedPotentialSource(potentialFile, workspacePath);
32726
33197
  const selectedWorkMode = normalizeRequestedWorkMode(workMode, featureType);
32727
33198
  const [useMinorAudit, fallbackReason] = shouldUseMinorAuditMode(
32728
33199
  selectedWorkMode,
@@ -32810,7 +33281,11 @@ function createActiveFolder(options) {
32810
33281
  if (useMinorAudit) {
32811
33282
  if (potentialFile) {
32812
33283
  potentialIssuePath = joinPosix13(targetDir, "issue.md");
32813
- filesystem.move(potentialFile, potentialIssuePath);
33284
+ if (retainsPotentialSource) {
33285
+ filesystem.copyFile(potentialFile, potentialIssuePath);
33286
+ } else {
33287
+ filesystem.move(potentialFile, potentialIssuePath);
33288
+ }
32814
33289
  const movedContent = filesystem.readText(potentialIssuePath);
32815
33290
  filesystem.writeText(
32816
33291
  potentialIssuePath,
@@ -32866,17 +33341,25 @@ function createActiveFolder(options) {
32866
33341
  if (potentialFile) {
32867
33342
  if (useMinorAudit) {
32868
33343
  if (potentialIssuePath !== null) {
32869
- emit(`Moved potential file to ${potentialIssuePath}`);
33344
+ emit(
33345
+ retainsPotentialSource ? `Copied potential file to ${potentialIssuePath}` : `Moved potential file to ${potentialIssuePath}`
33346
+ );
32870
33347
  }
32871
33348
  } else {
32872
33349
  potentialIssuePath = joinPosix13(targetDir, "issue.md");
32873
- filesystem.move(potentialFile, potentialIssuePath);
33350
+ if (retainsPotentialSource) {
33351
+ filesystem.copyFile(potentialFile, potentialIssuePath);
33352
+ } else {
33353
+ filesystem.move(potentialFile, potentialIssuePath);
33354
+ }
32874
33355
  const movedContent = filesystem.readText(potentialIssuePath);
32875
33356
  filesystem.writeText(
32876
33357
  potentialIssuePath,
32877
33358
  upsertWorkModeMarker(movedContent, selectedWorkMode)
32878
33359
  );
32879
- emit(`Moved potential file to ${potentialIssuePath}`);
33360
+ emit(
33361
+ retainsPotentialSource ? `Copied potential file to ${potentialIssuePath}` : `Moved potential file to ${potentialIssuePath}`
33362
+ );
32880
33363
  }
32881
33364
  }
32882
33365
  if (potentialFile) {
@@ -32915,6 +33398,12 @@ function isRelativeTo(child, root) {
32915
33398
  const normalizedRoot = toPosixPath2(root);
32916
33399
  return normalizedChild === normalizedRoot || normalizedChild.startsWith(`${normalizedRoot}/`);
32917
33400
  }
33401
+ function isPromotedPotentialSource(potentialPath, workspacePath) {
33402
+ return isRelativeTo(
33403
+ potentialPath,
33404
+ joinPosix13(workspacePath, "docs/features/potential/promoted")
33405
+ );
33406
+ }
32918
33407
  function posixBaseName(path11) {
32919
33408
  const normalized = toPosixPath2(path11).replace(/\/+$/, "");
32920
33409
  const slash = normalized.lastIndexOf("/");
@@ -32927,7 +33416,15 @@ function posixStem2(path11) {
32927
33416
  }
32928
33417
 
32929
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
+ }
32930
33426
  function newActiveFeatureFolderServiceCall(input) {
33427
+ const fileSystem = input.fileSystem ?? new RealFolderFileSystem();
32931
33428
  const result = createActiveFolder({
32932
33429
  featureName: input.featureName,
32933
33430
  featureType: input.type,
@@ -32935,13 +33432,17 @@ function newActiveFeatureFolderServiceCall(input) {
32935
33432
  workMode: input.workMode,
32936
33433
  workspace: input.workspaceRoot,
32937
33434
  templateRoot: input.templateRoot,
32938
- fs: input.fileSystem ?? new RealFolderFileSystem(),
33435
+ fs: fileSystem,
32939
33436
  // Route the guarded gh issue fetch through the injected F1 runner.
32940
33437
  issueFetcher: (issueNumber) => defaultIssueFetcher(issueNumber, input.runner),
32941
33438
  // No-op launcher: the MCP/non-interactive path must never open an editor.
32942
33439
  codeLauncher: () => false,
32943
33440
  ...input.log === void 0 ? {} : { emit: input.log }
32944
33441
  });
33442
+ requireReportedPathExists(fileSystem, result.target);
33443
+ if (result.potentialIssuePath !== null) {
33444
+ requireReportedPathExists(fileSystem, result.potentialIssuePath);
33445
+ }
32945
33446
  return {
32946
33447
  tool: "new_active_feature_folder",
32947
33448
  workspaceRoot: input.workspaceRoot,