@danmoisan/drm-copilot-mcp 1.1.4 → 1.1.6

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 +335 -24
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +163 -18
  4. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +477 -0
  5. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +120 -12
  6. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +11 -0
  7. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +1 -0
  8. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +131 -2
  9. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +37 -0
  10. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +136 -4
  11. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +3 -1
  12. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +18 -9
  13. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +8 -1
  14. package/resources/claude-customizations/.claude/skills/pr-context-artifacts/SKILL.md +22 -0
  15. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +10 -0
  16. package/resources/claude-customizations/config/orchestration-routing.json +1 -0
  17. package/resources/claude-customizations/pack-manifests/core.json +1 -0
  18. package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/SKILL.md +10 -0
  19. package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +22 -0
  20. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c1.toml +22 -0
  21. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c2.toml +22 -0
  22. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c3-elevated.toml +22 -0
  23. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c3.toml +22 -0
  24. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c4.toml +22 -0
  25. package/resources/codex-and-agents-customizations/.codex/agents/commit-steward.toml +2 -0
  26. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +7 -0
  27. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +7 -0
  28. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +7 -0
  29. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +7 -0
  30. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +7 -0
  31. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +7 -0
  32. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  33. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +477 -0
  34. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +125 -12
  35. package/resources/codex-and-agents-customizations/pack-manifests/core.json +8 -1
  36. package/resources/config/orchestration-routing.json +1 -0
  37. package/resources/customizations/.github/skills/pr-context-artifacts/SKILL.md +22 -0
  38. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +10 -2
package/out/mcp-server.js CHANGED
@@ -2671,18 +2671,18 @@ var require_validate = __commonJS({
2671
2671
  const { schemaCode } = this;
2672
2672
  this.fail((0, codegen_1._)`${schemaCode} !== undefined && (${(0, codegen_1.or)(this.invalid$data(), condition)})`);
2673
2673
  }
2674
- error(append, errorParams, errorPaths) {
2674
+ error(append2, errorParams, errorPaths) {
2675
2675
  if (errorParams) {
2676
2676
  this.setParams(errorParams);
2677
- this._error(append, errorPaths);
2677
+ this._error(append2, errorPaths);
2678
2678
  this.setParams({});
2679
2679
  return;
2680
2680
  }
2681
- this._error(append, errorPaths);
2681
+ this._error(append2, errorPaths);
2682
2682
  }
2683
- _error(append, errorPaths) {
2683
+ _error(append2, errorPaths) {
2684
2684
  ;
2685
- (append ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error, errorPaths);
2685
+ (append2 ? errors_1.reportExtraError : errors_1.reportError)(this, this.def.error, errorPaths);
2686
2686
  }
2687
2687
  $dataError() {
2688
2688
  (0, errors_1.reportError)(this, this.def.$dataError || errors_1.keyword$DataError);
@@ -23551,6 +23551,7 @@ var GENERATED_AGENT_FAMILIES = /* @__PURE__ */ new Set([
23551
23551
  "atomic-planner",
23552
23552
  "atomic-executor",
23553
23553
  "feature-reviewer",
23554
+ "commit-steward",
23554
23555
  "task-researcher",
23555
23556
  "prd-feature",
23556
23557
  "pr-author",
@@ -26957,7 +26958,14 @@ function classifyKind(argv) {
26957
26958
  return "other";
26958
26959
  }
26959
26960
  function splitLines2(text) {
26960
- return text.split(/\r\n|\n|\r/);
26961
+ if (text === "") {
26962
+ return [];
26963
+ }
26964
+ const lines = text.split(/\r\n|\n|\r/);
26965
+ if (lines[lines.length - 1] === "") {
26966
+ lines.pop();
26967
+ }
26968
+ return lines;
26961
26969
  }
26962
26970
  function inlineSpans(line) {
26963
26971
  const spans = [];
@@ -26979,34 +26987,63 @@ function appendCommand(commands, taskId, sourceLine, rawSpan) {
26979
26987
  sourceLine,
26980
26988
  rawSpan,
26981
26989
  argv,
26982
- kind: classifyKind(argv)
26990
+ kind: classifyKind(argv),
26991
+ taskText: ""
26983
26992
  });
26984
26993
  }
26994
+ function closeWindow(commands, windowStart, windowLines) {
26995
+ if (windowStart >= commands.length) {
26996
+ return;
26997
+ }
26998
+ const taskText = windowLines.join("\n");
26999
+ for (let index = windowStart; index < commands.length; index += 1) {
27000
+ const record2 = commands[index];
27001
+ if (record2 === void 0) {
27002
+ continue;
27003
+ }
27004
+ commands[index] = { ...record2, taskText };
27005
+ }
27006
+ }
26985
27007
  function extractPlanCommands(text) {
26986
27008
  const commands = [];
26987
27009
  let currentTask = null;
26988
27010
  let inFence = false;
27011
+ let windowLines = [];
27012
+ let windowStart = 0;
26989
27013
  const lines = splitLines2(text);
26990
27014
  for (let index = 0; index < lines.length; index += 1) {
26991
27015
  const line = lines[index] ?? "";
26992
27016
  const lineNumber = index + 1;
26993
27017
  if (FENCE_RE.test(line)) {
26994
27018
  inFence = !inFence;
27019
+ if (currentTask !== null) {
27020
+ windowLines.push(line);
27021
+ }
26995
27022
  continue;
26996
27023
  }
26997
27024
  if (inFence) {
27025
+ if (currentTask === null) {
27026
+ continue;
27027
+ }
27028
+ windowLines.push(line);
26998
27029
  const fenced = line.trim();
26999
- if (currentTask !== null && fenced !== "") {
27030
+ if (fenced !== "") {
27000
27031
  appendCommand(commands, currentTask, lineNumber, fenced);
27001
27032
  }
27002
27033
  continue;
27003
27034
  }
27004
27035
  if (PLAN_GATE_HEADING_PATTERN.test(line)) {
27036
+ closeWindow(commands, windowStart, windowLines);
27037
+ windowStart = commands.length;
27038
+ windowLines = [];
27005
27039
  currentTask = null;
27006
27040
  continue;
27007
27041
  }
27008
27042
  const taskMatch = PLAN_GATE_TASK_PATTERN.exec(line);
27009
27043
  if (taskMatch !== null) {
27044
+ closeWindow(commands, windowStart, windowLines);
27045
+ windowStart = commands.length;
27046
+ windowLines = [];
27010
27047
  const phase = taskMatch.groups?.["phase"] ?? "";
27011
27048
  const task = taskMatch.groups?.["task"] ?? "";
27012
27049
  currentTask = `P${phase}-T${task}`;
@@ -27014,10 +27051,12 @@ function extractPlanCommands(text) {
27014
27051
  if (currentTask === null) {
27015
27052
  continue;
27016
27053
  }
27054
+ windowLines.push(line);
27017
27055
  for (const span of inlineSpans(line)) {
27018
27056
  appendCommand(commands, currentTask, lineNumber, span);
27019
27057
  }
27020
27058
  }
27059
+ closeWindow(commands, windowStart, windowLines);
27021
27060
  return commands;
27022
27061
  }
27023
27062
 
@@ -27167,6 +27206,242 @@ function hasCrossLinePresence(context, literal2) {
27167
27206
  return false;
27168
27207
  }
27169
27208
 
27209
+ // ../../extensions/drm-copilot/src/lib/validate/plan-gate-observability.ts
27210
+ var G7_SEVERITY = "warning";
27211
+ var G8_SEVERITY = "warning";
27212
+ var G8B_SEVERITY = "warning";
27213
+ var G9_SEVERITY = "warning";
27214
+ var WRITE_MODE_REGISTER = [
27215
+ {
27216
+ name: "black-write",
27217
+ shapes: [{ words: ["black"] }],
27218
+ excludes: ["--check", "--diff"],
27219
+ markers: ["reformatted", "left unchanged", "unchanged"]
27220
+ },
27221
+ {
27222
+ name: "ruff-fix",
27223
+ shapes: [{ words: ["ruff", "check"] }],
27224
+ excludes: ["--no-fix"],
27225
+ markers: ["Fixed", "All checks passed", "fixes applied"]
27226
+ },
27227
+ {
27228
+ name: "prettier-write",
27229
+ shapes: [
27230
+ { words: ["prettier"], requires: ["--write"] },
27231
+ { words: ["npm", "run", "format"] }
27232
+ ],
27233
+ excludes: [],
27234
+ markers: ["(unchanged)", "unchanged", "rewrote"]
27235
+ },
27236
+ {
27237
+ name: "poshqc-format",
27238
+ shapes: [{ suffix: "run_poshqc_format" }],
27239
+ excludes: [],
27240
+ markers: ["formatted", "unchanged"]
27241
+ },
27242
+ {
27243
+ name: "poshqc-analyze-autofix",
27244
+ shapes: [{ suffix: "run_poshqc_analyze_autofix" }],
27245
+ excludes: [],
27246
+ markers: ["autofix", "Fixed", "unchanged"]
27247
+ },
27248
+ {
27249
+ name: "poshqc-suite",
27250
+ shapes: [{ suffix: "run_poshqc_suite" }],
27251
+ excludes: [],
27252
+ markers: ["formatted", "unchanged"]
27253
+ }
27254
+ ];
27255
+ var EXECUTABLE_SCAN_LIMIT2 = 4;
27256
+ var PATHSPEC_SEPARATOR = "--";
27257
+ var INDEX_FLAGS = ["--cached", "--staged"];
27258
+ var NAME_LISTING_FLAGS = ["--name-only", "--name-status"];
27259
+ var GIT_DIFF_SPAN = "git diff";
27260
+ var GIT_STATUS_SPAN = "git status";
27261
+ var GIT_ADD_SPAN = "git add";
27262
+ var GIT_PORCELAIN_SPAN = "git status --porcelain";
27263
+ var PROJECT_CONFIG_PATH = "pyproject.toml";
27264
+ var TERMINAL_REPORTER_PREFIX = "--cov-report=term";
27265
+ var FAIL_UNDER_PREFIX = "--cov-fail-under";
27266
+ var ADDOPTS_PATTERNS = [
27267
+ /addopts[ \t]*=[ \t]*"([^"]*)"/,
27268
+ /addopts[ \t]*=[ \t]*'([^']*)'/
27269
+ ];
27270
+ function append(report, severity, finding) {
27271
+ const channel = severity === BLOCKING_CHANNEL ? report.blocking : report.warnings;
27272
+ channel.push(finding);
27273
+ }
27274
+ function executablePositions(argv) {
27275
+ const limit = Math.min(argv.length, EXECUTABLE_SCAN_LIMIT2);
27276
+ const positions = [];
27277
+ for (let index = 0; index < limit; index += 1) {
27278
+ if (index === 0 || !(argv[index - 1] ?? "").startsWith("-")) {
27279
+ positions.push(index);
27280
+ }
27281
+ }
27282
+ return positions;
27283
+ }
27284
+ function shapeMatches(argv, shape) {
27285
+ const requires = shape.requires ?? [];
27286
+ if (requires.some((required2) => !argv.includes(required2))) {
27287
+ return false;
27288
+ }
27289
+ const words2 = shape.words ?? [];
27290
+ for (const index of executablePositions(argv)) {
27291
+ if (shape.suffix !== void 0 && shape.suffix !== "") {
27292
+ if ((argv[index] ?? "").endsWith(shape.suffix)) {
27293
+ return true;
27294
+ }
27295
+ continue;
27296
+ }
27297
+ const end = index + words2.length;
27298
+ if (end <= argv.length && words2.every((word, offset) => argv[index + offset] === word)) {
27299
+ return true;
27300
+ }
27301
+ }
27302
+ return false;
27303
+ }
27304
+ function matchingEntry(argv) {
27305
+ for (const entry of WRITE_MODE_REGISTER) {
27306
+ if (entry.excludes.some((excluded) => argv.includes(excluded))) {
27307
+ continue;
27308
+ }
27309
+ if (entry.shapes.some((shape) => shapeMatches(argv, shape))) {
27310
+ return entry;
27311
+ }
27312
+ }
27313
+ return null;
27314
+ }
27315
+ function taskTextWithoutSpan(command) {
27316
+ return command.taskText.replace(command.rawSpan, " ");
27317
+ }
27318
+ function evaluateWriteMode(report, command) {
27319
+ const entry = matchingEntry(command.argv);
27320
+ if (entry === null) {
27321
+ return;
27322
+ }
27323
+ const remainder = taskTextWithoutSpan(command);
27324
+ if (entry.markers.some((marker) => remainder.includes(marker))) {
27325
+ return;
27326
+ }
27327
+ append(
27328
+ report,
27329
+ G7_SEVERITY,
27330
+ `[${command.taskId}] write-mode command \`${command.rawSpan}\` rewrites tracked source and exits 0 after rewriting; the attributed task text carries none of its observation markers. Record an observation beyond the exit code.`
27331
+ );
27332
+ }
27333
+ function gitDiffIndex(argv) {
27334
+ const limit = Math.min(argv.length, EXECUTABLE_SCAN_LIMIT2);
27335
+ for (let index = 0; index < limit; index += 1) {
27336
+ if (argv[index] === "git" && argv[index + 1] === "diff") {
27337
+ return index + 1;
27338
+ }
27339
+ }
27340
+ return null;
27341
+ }
27342
+ function diffOperands(argv, diffIndex) {
27343
+ const operands = [];
27344
+ for (const word of argv.slice(diffIndex + 1)) {
27345
+ if (word === PATHSPEC_SEPARATOR) {
27346
+ break;
27347
+ }
27348
+ operands.push(word);
27349
+ }
27350
+ return operands;
27351
+ }
27352
+ function carriesPairingCompanion(command) {
27353
+ const remainder = taskTextWithoutSpan(command);
27354
+ return remainder.includes(GIT_DIFF_SPAN) || remainder.includes(GIT_STATUS_SPAN);
27355
+ }
27356
+ function carriesListingCompanion(command) {
27357
+ const remainder = taskTextWithoutSpan(command);
27358
+ return remainder.includes(GIT_ADD_SPAN) || remainder.includes(GIT_PORCELAIN_SPAN);
27359
+ }
27360
+ function evaluateGitDiff(report, command) {
27361
+ const argv = command.argv;
27362
+ const diffIndex = gitDiffIndex(argv);
27363
+ if (diffIndex === null) {
27364
+ return;
27365
+ }
27366
+ const operands = diffOperands(argv, diffIndex);
27367
+ const hasRefOperand = operands.some((word) => !word.startsWith("-"));
27368
+ const hasIndexFlag = INDEX_FLAGS.some((flag) => argv.includes(flag));
27369
+ if (!hasRefOperand && !hasIndexFlag) {
27370
+ if (!carriesPairingCompanion(command)) {
27371
+ append(
27372
+ report,
27373
+ G8_SEVERITY,
27374
+ `[${command.taskId}] git diff span \`${command.rawSpan}\` carries no ref operand and no --cached flag; it compares the worktree against the index and passes vacuously once the change is committed. Anchor the diff to a ref.`
27375
+ );
27376
+ }
27377
+ return;
27378
+ }
27379
+ if (hasRefOperand && NAME_LISTING_FLAGS.some((flag) => argv.includes(flag))) {
27380
+ if (!carriesListingCompanion(command)) {
27381
+ append(
27382
+ report,
27383
+ G8B_SEVERITY,
27384
+ `[${command.taskId}] name-listing diff \`${command.rawSpan}\` never reports an untracked file, and the attributed task text carries neither a staging span nor a porcelain-status span; a path the plan creates is invisible to it. Add a staging or porcelain-status companion.`
27385
+ );
27386
+ }
27387
+ }
27388
+ }
27389
+ function projectAddopts(context) {
27390
+ const text = context.git.readTrackedText(PROJECT_CONFIG_PATH);
27391
+ if (text === "") {
27392
+ return null;
27393
+ }
27394
+ for (const pattern of ADDOPTS_PATTERNS) {
27395
+ const match = pattern.exec(text);
27396
+ if (match !== null) {
27397
+ return match[1] ?? "";
27398
+ }
27399
+ }
27400
+ return "";
27401
+ }
27402
+ function collectCoverageReporter(pending, command, addopts) {
27403
+ const argv = command.argv;
27404
+ if (!argv.some((word) => isCovFlagToken(word))) {
27405
+ return;
27406
+ }
27407
+ if (argv.some((word) => word.startsWith(TERMINAL_REPORTER_PREFIX))) {
27408
+ return;
27409
+ }
27410
+ if (argv.some((word) => word.startsWith(FAIL_UNDER_PREFIX))) {
27411
+ return;
27412
+ }
27413
+ if (addopts.includes(TERMINAL_REPORTER_PREFIX)) {
27414
+ return;
27415
+ }
27416
+ pending.push(
27417
+ `[${command.taskId}] coverage command \`${command.rawSpan}\` supplies no terminal reporter and the project addopts supplies none either, so no coverage table is printed. Add --cov-report=term-missing.`
27418
+ );
27419
+ }
27420
+ function evaluateObservabilityGates(report, commands, context) {
27421
+ for (const command of commands) {
27422
+ evaluateWriteMode(report, command);
27423
+ evaluateGitDiff(report, command);
27424
+ }
27425
+ if (context === void 0) {
27426
+ return;
27427
+ }
27428
+ const pending = [];
27429
+ try {
27430
+ const addopts = projectAddopts(context);
27431
+ if (addopts === null) {
27432
+ return;
27433
+ }
27434
+ for (const command of commands) {
27435
+ collectCoverageReporter(pending, command, addopts);
27436
+ }
27437
+ } catch {
27438
+ return;
27439
+ }
27440
+ for (const finding of pending) {
27441
+ append(report, G9_SEVERITY, finding);
27442
+ }
27443
+ }
27444
+
27170
27445
  // ../../extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts
27171
27446
  var G5_SEVERITY = "warning";
27172
27447
  var CommandRunnerPlanGateRepository = class {
@@ -27262,6 +27537,7 @@ function evaluatePlanGates(text, context) {
27262
27537
  evaluateCovValue(report, command, cov, context);
27263
27538
  }
27264
27539
  }
27540
+ evaluateObservabilityGates(report, commands, context);
27265
27541
  if (context !== void 0) {
27266
27542
  evaluateLiteralRules(report, text, commands, context);
27267
27543
  }
@@ -31089,10 +31365,16 @@ function parseSection3(markdown, heading) {
31089
31365
  function formatDiffPath2(pathText) {
31090
31366
  return pathText !== null ? formatDiffPath(pathText) : "";
31091
31367
  }
31092
- function appendGenerationTimestamp(clock = () => /* @__PURE__ */ new Date()) {
31368
+ var GENERATED_CONTEXT_SECTION_TITLE = "Context generated";
31369
+ var HEAD_SHA_LABEL = "Head SHA:";
31370
+ var UNKNOWN_HEAD_SHA_PLACEHOLDER = "(unknown)";
31371
+ function appendGenerationTimestamp(clock = () => /* @__PURE__ */ new Date(), headSha = null) {
31093
31372
  const now = clock();
31094
31373
  const timestamp = formatUtcTimestamp(now);
31095
- return section("Context generated") + "\n" + timestamp + "\n";
31374
+ const shaText = headSha !== null && headSha !== "" ? headSha : UNKNOWN_HEAD_SHA_PLACEHOLDER;
31375
+ return section(GENERATED_CONTEXT_SECTION_TITLE) + "\n" + timestamp + `
31376
+ ${HEAD_SHA_LABEL} ${shaText}
31377
+ `;
31096
31378
  }
31097
31379
  function formatUtcTimestamp(date3) {
31098
31380
  const year = date3.getUTCFullYear().toString().padStart(4, "0");
@@ -31440,7 +31722,7 @@ function renderVerificationEvidenceSection(fs10, resolvedRoot, featureDocs) {
31440
31722
  }
31441
31723
  return lines.join("\n");
31442
31724
  }
31443
- function buildSummaryText(collected, fs10, appendixPath) {
31725
+ function buildSummaryText(collected, fs10, appendixPath, generatedSection) {
31444
31726
  const ctx = collected.contextResult;
31445
31727
  const ghStatusText = resolveGhStatusText(collected);
31446
31728
  const intentBlock = [
@@ -31451,6 +31733,7 @@ function buildSummaryText(collected, fs10, appendixPath) {
31451
31733
  "Author-asserted autoclose issues:"
31452
31734
  ].join("\n");
31453
31735
  const summarySections = [
31736
+ generatedSection,
31454
31737
  section("GitHub CLI status"),
31455
31738
  ghStatusText,
31456
31739
  intentBlock,
@@ -31528,7 +31811,7 @@ function buildSummaryText(collected, fs10, appendixPath) {
31528
31811
  }
31529
31812
  return summaryText;
31530
31813
  }
31531
- function buildAppendixText(collected, clock) {
31814
+ function buildAppendixText(collected, generatedSection) {
31532
31815
  const featureBlock = collected.featureDocs.map((doc) => doc.excerpt).join("\n");
31533
31816
  const issueSections = collected.issueDetails.map(
31534
31817
  (detail) => issueAppendix(detail)
@@ -31537,7 +31820,7 @@ function buildAppendixText(collected, clock) {
31537
31820
  (detail) => prAppendix(detail)
31538
31821
  );
31539
31822
  const appendixParts = [
31540
- appendGenerationTimestamp(clock),
31823
+ generatedSection,
31541
31824
  collected.contextResult.text,
31542
31825
  "",
31543
31826
  section("Issue details"),
@@ -31555,12 +31838,12 @@ function buildAppendixText(collected, clock) {
31555
31838
  }
31556
31839
  return appendixText;
31557
31840
  }
31558
- function writeOutput(fs10, text, outPath, append) {
31841
+ function writeOutput(fs10, text, outPath, append2) {
31559
31842
  const parent = parentDir(outPath);
31560
31843
  if (parent) {
31561
31844
  fs10.ensureDir(parent);
31562
31845
  }
31563
- if (append && fs10.isFile(outPath)) {
31846
+ if (append2 && fs10.isFile(outPath)) {
31564
31847
  const existing = fs10.readTextFile(outPath);
31565
31848
  fs10.writeTextFile(outPath, existing + text);
31566
31849
  } else {
@@ -31570,17 +31853,23 @@ function writeOutput(fs10, text, outPath, append) {
31570
31853
  function collectAndWrite(options) {
31571
31854
  const clock = options.clock ?? (() => /* @__PURE__ */ new Date());
31572
31855
  const collected = collectPrContext(options);
31856
+ const generatedSection = appendGenerationTimestamp(
31857
+ clock,
31858
+ collected.contextResult.headSha
31859
+ );
31573
31860
  const summaryText = buildSummaryText(
31574
31861
  collected,
31575
31862
  options.fs,
31576
- options.appendixOut
31863
+ options.appendixOut,
31864
+ generatedSection
31577
31865
  );
31578
- const appendixText = buildAppendixText(collected, clock);
31866
+ const appendixText = buildAppendixText(collected, generatedSection);
31579
31867
  writeOutput(options.fs, summaryText, options.out, options.append);
31580
31868
  writeOutput(options.fs, appendixText, options.appendixOut, options.append);
31581
31869
  const log = options.log ?? (() => void 0);
31582
31870
  log(`Wrote context summary to: ${options.out}`);
31583
31871
  log(`Wrote context appendix to: ${options.appendixOut}`);
31872
+ return { summaryText, appendixText };
31584
31873
  }
31585
31874
  function resolveGhStatusText(collected) {
31586
31875
  let ghStatusText = collected.ghStatusOverride || collected.ghStatusMessage || "GitHub CLI authenticated.";
@@ -31652,26 +31941,48 @@ function parentDir(path11) {
31652
31941
  // ../../extensions/drm-copilot/src/lib/pr-context/pr-context-service-call.ts
31653
31942
  var SUMMARY_OUT = "artifacts/pr_context.summary.txt";
31654
31943
  var APPENDIX_OUT = "artifacts/pr_context.appendix.txt";
31944
+ function verifyWrittenArtifact(fileSystem, artifactPath, expected) {
31945
+ let actual;
31946
+ try {
31947
+ actual = fileSystem.readTextFile(artifactPath);
31948
+ } catch (error2) {
31949
+ const detail = error2 instanceof Error ? error2.message : String(error2);
31950
+ throw new Error(
31951
+ `Failed to verify PR context artifact '${artifactPath}': the file could not be read back after writing (${detail}).`,
31952
+ { cause: error2 }
31953
+ );
31954
+ }
31955
+ if (actual !== expected) {
31956
+ throw new Error(
31957
+ `Failed to verify PR context artifact '${artifactPath}': the content read back is not the content this invocation rendered (expected ${String(expected.length)} characters, read back ${String(actual.length)}).`
31958
+ );
31959
+ }
31960
+ }
31655
31961
  function collectPrContextServiceCall(input) {
31656
- collectAndWrite({
31962
+ const summaryOut = normalizeGeneratedPath(
31963
+ (0, import_node_path.join)(input.workspaceRoot, SUMMARY_OUT)
31964
+ );
31965
+ const appendixOut = normalizeGeneratedPath(
31966
+ (0, import_node_path.join)(input.workspaceRoot, APPENDIX_OUT)
31967
+ );
31968
+ const rendered = collectAndWrite({
31657
31969
  base: input.base,
31658
31970
  repoRoot: input.workspaceRoot,
31659
- out: SUMMARY_OUT,
31660
- appendixOut: APPENDIX_OUT,
31971
+ out: summaryOut,
31972
+ appendixOut,
31661
31973
  append: false,
31662
31974
  includeUntracked: true,
31663
31975
  fs: input.fileSystem,
31664
31976
  runner: input.runner,
31665
31977
  ...input.log === void 0 ? {} : { log: input.log }
31666
31978
  });
31979
+ verifyWrittenArtifact(input.fileSystem, summaryOut, rendered.summaryText);
31980
+ verifyWrittenArtifact(input.fileSystem, appendixOut, rendered.appendixText);
31667
31981
  return {
31668
31982
  tool: "collect_pr_context",
31669
31983
  workspaceRoot: input.workspaceRoot,
31670
31984
  summary: `Collected PR context against base '${input.base}'.`,
31671
- artifacts: [
31672
- normalizeGeneratedPath((0, import_node_path.join)(input.workspaceRoot, SUMMARY_OUT)),
31673
- normalizeGeneratedPath((0, import_node_path.join)(input.workspaceRoot, APPENDIX_OUT))
31674
- ]
31985
+ artifacts: [summaryOut, appendixOut]
31675
31986
  };
31676
31987
  }
31677
31988
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danmoisan/drm-copilot-mcp",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Stdio MCP server exposing drm-copilot repo-automation tools.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",