@danmoisan/drm-copilot-mcp 1.1.18 → 1.1.20

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 (264) hide show
  1. package/out/mcp-server.js +1149 -661
  2. package/package.json +3 -2
  3. package/resources/claude-customizations/.claude/agents/atomic-executor.md +28 -6
  4. package/resources/claude-customizations/.claude/agents/atomic-planner.md +20 -2
  5. package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +17 -4
  6. package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
  7. package/resources/claude-customizations/.claude/agents/feature-review.md +6 -4
  8. package/resources/claude-customizations/.claude/agents/orchestrator.md +9 -5
  9. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +35 -13
  10. package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
  11. package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
  12. package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
  13. package/resources/claude-customizations/.claude/agents/task-researcher.md +8 -0
  14. package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
  15. package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
  16. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
  17. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
  18. package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
  20. package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
  21. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-command.ps1 +190 -0
  22. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
  23. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +78 -77
  24. package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
  25. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
  26. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
  27. package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
  28. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
  29. package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
  30. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
  31. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
  32. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
  33. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
  34. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
  35. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
  36. package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
  37. package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
  38. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
  39. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
  40. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
  41. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
  42. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
  43. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
  44. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
  45. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
  46. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
  47. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
  48. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
  49. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
  50. package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
  51. package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
  52. package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
  53. package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
  54. package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
  55. package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
  56. package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
  57. package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
  58. package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
  59. package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +497 -0
  60. package/resources/claude-customizations/.claude/hooks/premortem-section.ps1 +149 -0
  61. package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
  62. package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
  63. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
  64. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +267 -113
  65. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
  66. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
  67. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
  68. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
  69. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
  70. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
  71. package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +77 -33
  72. package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
  73. package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
  74. package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
  75. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +52 -36
  76. package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
  77. package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
  78. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
  79. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
  80. package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
  81. package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
  82. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
  83. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
  84. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
  85. package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-MergeConfirmationParser.ps1 +203 -0
  86. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
  87. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +24 -3
  88. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
  89. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
  90. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
  91. package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
  92. package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
  93. package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
  94. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +37 -4
  95. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
  96. package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +85 -10
  97. package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
  98. package/resources/claude-customizations/.claude/rules/shell.md +10 -8
  99. package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
  100. package/resources/claude-customizations/.claude/settings.json +3 -4
  101. package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +1 -1
  102. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +52 -16
  103. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +7 -3
  104. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
  105. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +2 -0
  106. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +2 -0
  107. package/resources/claude-customizations/.claude/skills/csharp-change-budget-router/SKILL.md +2 -2
  108. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -9
  109. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +5 -3
  110. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
  111. package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +134 -0
  112. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  113. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -3
  114. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +36 -15
  115. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
  116. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
  117. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +108 -21
  118. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
  119. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
  120. package/resources/claude-customizations/.claude/skills/powershell-change-budget-router/SKILL.md +1 -1
  121. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
  122. package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +1 -1
  123. package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
  124. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +16 -8
  125. package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +6 -0
  126. package/resources/claude-customizations/pack-manifests/core.json +27 -0
  127. package/resources/codex-and-agents-customizations/.agents/skills/README.md +1 -0
  128. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +1 -1
  129. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
  130. package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +19 -7
  131. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +43 -4
  132. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +18 -6
  133. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
  134. package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +2 -2
  135. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
  136. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +16 -1
  137. package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
  138. package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
  139. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
  140. package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +134 -0
  141. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +13 -5
  142. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
  143. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
  144. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +27 -8
  145. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +1 -1
  146. package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -1
  147. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -1
  148. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
  149. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
  150. package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +6 -0
  151. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
  152. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
  153. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
  154. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +21 -6
  155. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +21 -6
  156. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +21 -6
  157. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +21 -6
  158. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +21 -6
  159. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +21 -6
  160. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +15 -2
  161. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +15 -2
  162. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +15 -2
  163. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +15 -2
  164. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +15 -2
  165. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +15 -2
  166. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planning.toml +1 -1
  167. package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +1 -1
  168. package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +4 -1
  169. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
  170. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +7 -4
  171. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +7 -4
  172. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +7 -4
  173. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +7 -4
  174. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +7 -4
  175. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +7 -4
  176. package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +1 -1
  177. package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +1 -1
  178. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c1.toml +6 -0
  179. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c2.toml +6 -0
  180. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3-elevated.toml +6 -0
  181. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3.toml +6 -0
  182. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c4.toml +6 -0
  183. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher.toml +6 -0
  184. package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
  185. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  186. package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
  187. package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
  188. package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
  189. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
  190. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
  191. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
  192. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
  193. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
  194. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate-command.ps1 +190 -0
  195. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +54 -43
  196. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
  197. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
  198. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
  199. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
  200. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
  201. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
  202. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
  203. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
  204. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
  205. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
  206. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
  207. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
  208. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
  209. package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
  210. package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
  211. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
  212. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
  213. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
  214. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
  215. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
  216. package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
  217. package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
  218. package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +497 -0
  219. package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
  220. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
  221. package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
  222. package/resources/codex-and-agents-customizations/.codex/prompts/feature-review-remediate.md +6 -4
  223. package/resources/codex-and-agents-customizations/pack-manifests/core.json +11 -0
  224. package/resources/customizations/.github/agents/atomic_executor.agent.md +21 -11
  225. package/resources/customizations/.github/agents/atomic_planning.agent.md +8 -3
  226. package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +13 -9
  227. package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +2 -2
  228. package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +2 -2
  229. package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +5 -5
  230. package/resources/customizations/.github/agents/orchestrator.agent.md +8 -5
  231. package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +13 -9
  232. package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +2 -2
  233. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +2 -2
  234. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +3 -3
  235. package/resources/customizations/.github/agents/python-atomic-executor.agent.md +13 -9
  236. package/resources/customizations/.github/agents/python-atomic-planning.agent.md +2 -2
  237. package/resources/customizations/.github/agents/python-orchestrator.agent.md +2 -2
  238. package/resources/customizations/.github/agents/task-researcher.agent.md +6 -0
  239. package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
  240. package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
  241. package/resources/customizations/.github/prompts/generate-atomic-plan.prompt.md +16 -10
  242. package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +2 -2
  243. package/resources/customizations/.github/prompts/orchestrate-powershell-work.prompt.md +1 -1
  244. package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +1 -1
  245. package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +2 -2
  246. package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +1 -1
  247. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +43 -4
  248. package/resources/customizations/.github/skills/csharp-change-budget-router/SKILL.md +1 -1
  249. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
  250. package/resources/customizations/.github/skills/execution-environment/SKILL.md +134 -0
  251. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
  252. package/resources/customizations/.github/skills/powershell-change-budget-router/SKILL.md +1 -1
  253. package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
  254. package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +10 -0
  255. package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +11 -0
  256. package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +11 -0
  257. package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
  258. package/resources/powershell/PoshQC/PoshQC.CoverageMerge.psm1 +163 -0
  259. package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +296 -0
  260. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +48 -32
  261. package/resources/powershell/PoshQC/PoshQC.psd1 +7 -1
  262. package/resources/powershell/PoshQC/PoshQC.psm1 +18 -5
  263. package/resources/powershell/PoshQC/README.md +21 -3
  264. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +5 -319
@@ -0,0 +1,314 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Returns the non-blank string entries of one list in a Pester settings table.
4
+ .DESCRIPTION
5
+ Reads Settings[Section][Key] and returns its non-blank string entries in their original order.
6
+ Returns nothing when Settings or the section is not a dictionary or when the key is absent.
7
+ Used for 'CodeCoverage.Path' and 'Run.Path' (issue #527).
8
+ .PARAMETER Settings
9
+ Settings table, normally the hashtable loaded from the Pester runsettings file.
10
+ .PARAMETER Section
11
+ Top-level section name, for example 'CodeCoverage' or 'Run'.
12
+ .PARAMETER Key
13
+ Key inside the section, for example 'Path'.
14
+ #>
15
+ function Get-PoshQCSettingsList {
16
+ [CmdletBinding()]
17
+ [OutputType([string])]
18
+ param(
19
+ $Settings,
20
+ [string] $Section,
21
+ [string] $Key
22
+ )
23
+
24
+ if ($Settings -isnot [System.Collections.IDictionary]) {
25
+ return
26
+ }
27
+
28
+ $sectionValue = $Settings[$Section]
29
+ if ($sectionValue -isnot [System.Collections.IDictionary]) {
30
+ return
31
+ }
32
+
33
+ if (-not $sectionValue.Contains($Key)) {
34
+ return
35
+ }
36
+
37
+ foreach ($entry in @($sectionValue[$Key])) {
38
+ if ($entry -is [string] -and -not [string]::IsNullOrWhiteSpace($entry)) {
39
+ [string] $entry
40
+ }
41
+ }
42
+ }
43
+
44
+ <#
45
+ .SYNOPSIS
46
+ Reads and validates the workspace coverage configuration (issue #527).
47
+ .DESCRIPTION
48
+ Resolves the workspace-relative configuration file (default 'config/poshqc-coverage.json')
49
+ against Root. An absent file reports Present = $false. A present file must be a JSON object
50
+ with 'version' equal to 1 and a 'roots' array of workspace-relative paths; every validation
51
+ failure throws a message that names the configuration file. An empty 'roots' array is valid
52
+ and yields an empty coverage population.
53
+ .PARAMETER Root
54
+ Workspace root the configuration path resolves against.
55
+ .PARAMETER ConfigRelativePath
56
+ Workspace-relative path to the configuration file.
57
+ .PARAMETER TestPathExists
58
+ Injectable file-existence seam. Defaults to Test-Path -PathType Leaf.
59
+ .PARAMETER ReadContent
60
+ Injectable read seam returning the raw file text. Defaults to Get-Content -Raw.
61
+ #>
62
+ function Get-PoshQCCoverageConfigRoot {
63
+ [CmdletBinding()]
64
+ [OutputType([pscustomobject])]
65
+ param(
66
+ [string] $Root,
67
+ [string] $ConfigRelativePath = 'config/poshqc-coverage.json',
68
+ [scriptblock] $TestPathExists = { param([string] $Path) Test-Path -LiteralPath $Path -PathType Leaf },
69
+ [scriptblock] $ReadContent = { param([string] $Path) Get-Content -LiteralPath $Path -Raw }
70
+ )
71
+
72
+ $ErrorActionPreference = 'Stop'
73
+
74
+ $configPath = if ([IO.Path]::IsPathRooted($ConfigRelativePath)) {
75
+ $ConfigRelativePath
76
+ } else {
77
+ Join-Path -Path $Root -ChildPath $ConfigRelativePath
78
+ }
79
+
80
+ if (-not (& $TestPathExists $configPath)) {
81
+ return [pscustomobject]@{ Present = $false; Roots = [string[]] @() }
82
+ }
83
+
84
+ $raw = [string] (& $ReadContent $configPath)
85
+ if ([string]::IsNullOrWhiteSpace($raw)) {
86
+ throw "Coverage configuration '$ConfigRelativePath' is empty."
87
+ }
88
+
89
+ try {
90
+ $parsed = $raw | ConvertFrom-Json -ErrorAction Stop
91
+ } catch {
92
+ throw "Invalid JSON in coverage configuration '$ConfigRelativePath': $($_.Exception.Message)"
93
+ }
94
+
95
+ if ($parsed -isnot [System.Management.Automation.PSCustomObject]) {
96
+ throw "Coverage configuration '$ConfigRelativePath' must contain a JSON object."
97
+ }
98
+
99
+ # Read properties through PSObject so a missing property yields $null under StrictMode.
100
+ $versionProperty = $parsed.PSObject.Properties['version']
101
+ $versionIsInteger = $null -ne $versionProperty -and ($versionProperty.Value -is [long] -or $versionProperty.Value -is [int])
102
+ if (-not $versionIsInteger -or $versionProperty.Value -ne 1) {
103
+ throw "Coverage configuration '$ConfigRelativePath' must declare 'version' equal to 1."
104
+ }
105
+
106
+ $rootsProperty = $parsed.PSObject.Properties['roots']
107
+ if ($null -eq $rootsProperty) {
108
+ throw "Coverage configuration '$ConfigRelativePath' must declare a 'roots' array."
109
+ }
110
+ if ($rootsProperty.Value -isnot [System.Array]) {
111
+ throw "Coverage configuration '$ConfigRelativePath' must declare 'roots' as an array."
112
+ }
113
+
114
+ $validated = [System.Collections.Generic.List[string]]::new()
115
+ foreach ($entry in $rootsProperty.Value) {
116
+ if ($entry -isnot [string] -or [string]::IsNullOrWhiteSpace($entry)) {
117
+ throw "Coverage configuration '$ConfigRelativePath' contains a blank or non-string 'roots' entry."
118
+ }
119
+ if ([IO.Path]::IsPathRooted($entry)) {
120
+ throw "Coverage configuration '$ConfigRelativePath' entry '$entry' must be a workspace-relative path, not an absolute path."
121
+ }
122
+ if (@($entry -split '[\\/]+') -contains '..') {
123
+ throw "Coverage configuration '$ConfigRelativePath' entry '$entry' must not contain '..' segments."
124
+ }
125
+ $validated.Add($entry)
126
+ }
127
+
128
+ return [pscustomobject]@{ Present = $true; Roots = [string[]] $validated.ToArray() }
129
+ }
130
+
131
+ <#
132
+ .SYNOPSIS
133
+ Enumerates the PowerShell production files under a set of coverage roots (issue #527).
134
+ .DESCRIPTION
135
+ Joins each non-rooted root to Root, skips a nonexistent root with one warning, and keeps
136
+ files with a .ps1 or .psm1 extension (case-insensitive) whose name does not match
137
+ '*.Tests.ps1', whose first root-relative segment is not 'tests', and whose root-relative
138
+ directory segments are not in ExcludeDirs. Root-relative paths use forward slashes. The result
139
+ is sorted ordinally on RelativePath and de-duplicated case-insensitively, keeping the
140
+ ordinally smallest variant.
141
+ .PARAMETER Root
142
+ Workspace root that relative roots and relative paths are computed against.
143
+ .PARAMETER Roots
144
+ Coverage roots, workspace-relative or absolute.
145
+ .PARAMETER ExcludeDirs
146
+ Directory names excluded from the population.
147
+ .PARAMETER TestPathExists
148
+ Injectable directory-existence seam. Defaults to Test-Path -PathType Container.
149
+ .PARAMETER EnumerateFiles
150
+ Injectable recursive file enumeration seam. Defaults to Get-ChildItem -Recurse -File -Force.
151
+ .PARAMETER WarningLogger
152
+ Injectable warning seam for skipped roots. Defaults to Write-Warning.
153
+ #>
154
+ function Get-PoshQCCoverageFileSet {
155
+ [CmdletBinding()]
156
+ [OutputType([pscustomobject])]
157
+ param(
158
+ [string] $Root,
159
+ [string[]] $Roots,
160
+ [string[]] $ExcludeDirs = $script:DefaultExcludedDirs,
161
+ [scriptblock] $TestPathExists = { param([string] $Path) Test-Path -LiteralPath $Path -PathType Container },
162
+ [scriptblock] $EnumerateFiles = { param([string] $Path) Get-ChildItem -LiteralPath $Path -Recurse -File -Force },
163
+ [scriptblock] $WarningLogger = { param([string] $Message) Write-Warning $Message }
164
+ )
165
+
166
+ $ErrorActionPreference = 'Stop'
167
+
168
+ $rootPrefix = ([string] $Root -replace '\\', '/').TrimEnd('/')
169
+ $candidates = [System.Collections.Generic.Dictionary[string, object]]::new([StringComparer]::Ordinal)
170
+ foreach ($coverageRoot in @($Roots | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })) {
171
+ $rootPath = if ([IO.Path]::IsPathRooted($coverageRoot)) { $coverageRoot } else { Join-Path -Path $Root -ChildPath $coverageRoot }
172
+ if (-not (& $TestPathExists $rootPath)) {
173
+ & $WarningLogger "Coverage root '$coverageRoot' does not exist under '$Root'; skipping."
174
+ continue
175
+ }
176
+
177
+ foreach ($file in @(& $EnumerateFiles $rootPath)) {
178
+ if ($null -eq $file) { continue }
179
+ $extension = [string] $file.Extension
180
+ if (-not ($extension -ieq '.ps1' -or $extension -ieq '.psm1')) { continue }
181
+ if ([string] $file.Name -like '*.Tests.ps1') { continue }
182
+
183
+ $fullPath = [string] $file.FullName
184
+ $normalizedPath = $fullPath -replace '\\', '/'
185
+ $relativePath = $normalizedPath
186
+ if ($rootPrefix -and $normalizedPath.StartsWith("$rootPrefix/", [StringComparison]::OrdinalIgnoreCase)) {
187
+ $relativePath = $normalizedPath.Substring($rootPrefix.Length + 1)
188
+ }
189
+
190
+ $segments = @($relativePath -split '/' | Where-Object { $_ -ne '' })
191
+ if ($segments.Count -gt 0 -and $segments[0] -ieq 'tests') { continue }
192
+ $directorySegments = if ($segments.Count -gt 1) { @($segments[0..($segments.Count - 2)]) } else { @() }
193
+ $excludedSegments = @($directorySegments | Where-Object { $ExcludeDirs -contains $_ })
194
+ if ($excludedSegments.Count -gt 0) { continue }
195
+
196
+ if (-not $candidates.ContainsKey($relativePath)) {
197
+ $candidates[$relativePath] = [pscustomobject]@{ RelativePath = $relativePath; FullPath = $fullPath }
198
+ }
199
+ }
200
+ }
201
+
202
+ [string[]] $keys = @($candidates.Keys)
203
+ [Array]::Sort($keys, [StringComparer]::Ordinal)
204
+ $seen = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
205
+ foreach ($key in $keys) {
206
+ if ($seen.Add($key)) {
207
+ $candidates[$key]
208
+ }
209
+ }
210
+ }
211
+
212
+ <#
213
+ .SYNOPSIS
214
+ Resolves the code-coverage population for one Invoke-PoshQCTest run (issue #527).
215
+ .DESCRIPTION
216
+ Applies the coverage precedence and returns the source name and the absolute file paths:
217
+ (1) 'settings': a caller-supplied settings file (one whose full path differs from the
218
+ module-default settings file) with a non-empty CodeCoverage.Path; relative entries are joined
219
+ to Root, rooted entries are kept as written, and each nonexistent entry is pruned and logged.
220
+ A non-empty CodeCoverage.Path in the module-default settings file is ignored and logged.
221
+ (2) 'config': the workspace coverage configuration reports Present.
222
+ (3) 'fallback': the effective scan-folder roots when non-empty, else the settings Run.Path.
223
+ .PARAMETER Root
224
+ Absolute workspace root.
225
+ .PARAMETER Settings
226
+ Settings table loaded from the Pester runsettings file.
227
+ .PARAMETER SettingsFile
228
+ Path of the settings file the table was loaded from.
229
+ .PARAMETER ScanFolderRoots
230
+ Effective test scan folders of the run (explicit -ScanFolders or the scan configuration).
231
+ .PARAMETER ExcludeDirs
232
+ Directory names excluded from the population.
233
+ .PARAMETER DefaultSettingsFile
234
+ The module-default settings file; a list in it is not honored.
235
+ .PARAMETER SettingsPathExists
236
+ Injectable existence seam for caller-supplied settings entries. Defaults to Test-Path.
237
+ .PARAMETER Logger
238
+ Injectable information seam. Defaults to Write-Information.
239
+ .PARAMETER WarningLogger
240
+ Injectable warning seam passed to the file-set seam. Defaults to Write-Warning.
241
+ .PARAMETER ReadConfig
242
+ Injectable configuration seam. Defaults to Get-PoshQCCoverageConfigRoot.
243
+ .PARAMETER GetFileSet
244
+ Injectable file-set seam. Defaults to Get-PoshQCCoverageFileSet.
245
+ #>
246
+ function Resolve-PoshQCCoveragePopulation {
247
+ [CmdletBinding()]
248
+ [OutputType([pscustomobject])]
249
+ param(
250
+ [string] $Root,
251
+ $Settings,
252
+ [string] $SettingsFile,
253
+ [string[]] $ScanFolderRoots,
254
+ [string[]] $ExcludeDirs = $script:DefaultExcludedDirs,
255
+ [string] $DefaultSettingsFile = $script:PesterSettings,
256
+ [scriptblock] $SettingsPathExists = { param([string] $Path) Test-Path $Path },
257
+ [scriptblock] $Logger = { param([string] $Message) Write-Information $Message -InformationAction Continue },
258
+ [scriptblock] $WarningLogger = { param([string] $Message) Write-Warning $Message },
259
+ [scriptblock] $ReadConfig = { param([string] $RootPath) Get-PoshQCCoverageConfigRoot -Root $RootPath },
260
+ [scriptblock] $GetFileSet = {
261
+ param([string] $RootPath, [string[]] $Roots, [string[]] $Excluded, [scriptblock] $Warn)
262
+ Get-PoshQCCoverageFileSet -Root $RootPath -Roots $Roots -ExcludeDirs $Excluded -WarningLogger $Warn
263
+ }
264
+ )
265
+
266
+ $ErrorActionPreference = 'Stop'
267
+
268
+ $settingsPaths = @(Get-PoshQCSettingsList -Settings $Settings -Section 'CodeCoverage' -Key 'Path')
269
+ if ($settingsPaths.Count -gt 0) {
270
+ # A settings file is caller-supplied custom when its full path differs from the module default.
271
+ $isCustomSettingsFile = $false
272
+ if (-not [string]::IsNullOrWhiteSpace($SettingsFile)) {
273
+ $settingsFullPath = [IO.Path]::GetFullPath([IO.Path]::Combine($PWD.ProviderPath, $SettingsFile))
274
+ $defaultFullPath = ''
275
+ if (-not [string]::IsNullOrWhiteSpace($DefaultSettingsFile)) {
276
+ $defaultFullPath = [IO.Path]::GetFullPath([IO.Path]::Combine($PWD.ProviderPath, $DefaultSettingsFile))
277
+ }
278
+ $isCustomSettingsFile = -not [string]::Equals($settingsFullPath, $defaultFullPath, [StringComparison]::OrdinalIgnoreCase)
279
+ }
280
+
281
+ if ($isCustomSettingsFile) {
282
+ $survivingPaths = [System.Collections.Generic.List[string]]::new()
283
+ foreach ($entry in $settingsPaths) {
284
+ # Rooted entries are kept and tested as written; they are never re-joined to Root.
285
+ $candidate = if ([IO.Path]::IsPathRooted($entry)) { $entry } else { Join-Path -Path $Root -ChildPath $entry }
286
+ if (& $SettingsPathExists $candidate) {
287
+ $survivingPaths.Add($candidate)
288
+ } else {
289
+ & $Logger "Pruned nonexistent code coverage path: $candidate"
290
+ }
291
+ }
292
+
293
+ return [pscustomobject]@{ Source = 'settings'; Paths = [string[]] $survivingPaths.ToArray() }
294
+ }
295
+
296
+ & $Logger 'Ignored CodeCoverage.Path from the module-default settings file; the coverage population is derived from the workspace.'
297
+ }
298
+
299
+ $configRoot = & $ReadConfig $Root
300
+ if ($null -ne $configRoot -and $configRoot.Present) {
301
+ $source = 'config'
302
+ $coverageRoots = @($configRoot.Roots)
303
+ } else {
304
+ $source = 'fallback'
305
+ $coverageRoots = @($ScanFolderRoots | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
306
+ if ($coverageRoots.Count -eq 0) {
307
+ $coverageRoots = @(Get-PoshQCSettingsList -Settings $Settings -Section 'Run' -Key 'Path')
308
+ }
309
+ }
310
+
311
+ $files = @(& $GetFileSet $Root ([string[]] $coverageRoots) $ExcludeDirs $WarningLogger)
312
+ $paths = [string[]] @($files | Where-Object { $null -ne $_ } | ForEach-Object { $_.FullPath })
313
+ return [pscustomobject]@{ Source = $source; Paths = $paths }
314
+ }
@@ -0,0 +1,163 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Loads CoverageGutters (JaCoCo-structured) XML text into an XmlDocument (issue #953).
4
+ .DESCRIPTION
5
+ Disables external resolution, so the DOCTYPE reference to report.dtd is never fetched, and keeps
6
+ whitespace so the merged report serializes with the layout of the first input.
7
+ .PARAMETER CoverageXml
8
+ The XML text of one coverage report.
9
+ #>
10
+ function ConvertFrom-PoshQCCoverageXml {
11
+ [CmdletBinding()]
12
+ [OutputType([System.Xml.XmlDocument])]
13
+ param(
14
+ [Parameter(Mandatory)][string] $CoverageXml
15
+ )
16
+
17
+ $document = New-Object System.Xml.XmlDocument
18
+ $document.XmlResolver = $null
19
+ $document.PreserveWhitespace = $true
20
+ $document.LoadXml($CoverageXml)
21
+ $document
22
+ }
23
+
24
+ <#
25
+ .SYNOPSIS
26
+ Merges the coverage reports written by the shards of one test run (issue #953).
27
+ .DESCRIPTION
28
+ Takes XML text only (no file I/O). Every report must list the same set of
29
+ package/sourcefile/line-number triples, otherwise the merge throws. For each triple the merged
30
+ line carries ci = max(ci) and mi = (mi + ci of the first report) - max(ci). The LINE and
31
+ INSTRUCTION counters of every sourcefile, every package, and the report are then recomputed
32
+ bottom-up: LINE covered counts lines with ci greater than 0 and LINE missed counts lines with ci
33
+ equal to 0; INSTRUCTION covered is the sum of ci and INSTRUCTION missed is the sum of mi.
34
+ Class and method elements and every counter other than LINE and INSTRUCTION are removed, because they
35
+ cannot be recomputed from merged line hits (CR-8). No coverage threshold is enforced. Returns the merged XML text.
36
+ .PARAMETER CoverageXml
37
+ The XML text of each shard's coverage report; at least one is required.
38
+ #>
39
+ function Merge-PoshQCCoverageReport {
40
+ [CmdletBinding()]
41
+ [OutputType([string])]
42
+ param(
43
+ [Parameter(Mandatory)][AllowEmptyCollection()][string[]] $CoverageXml
44
+ )
45
+
46
+ if ($CoverageXml.Count -lt 1) {
47
+ throw 'Merge-PoshQCCoverageReport requires at least one coverage report.'
48
+ }
49
+
50
+ $indexLines = {
51
+ param([System.Xml.XmlDocument] $Document, [int] $Position)
52
+ $index = New-Object 'System.Collections.Generic.Dictionary[string,System.Xml.XmlElement]' ([System.StringComparer]::Ordinal)
53
+ foreach ($package in $Document.SelectNodes('/report/package')) {
54
+ foreach ($sourceFile in $package.SelectNodes('sourcefile')) {
55
+ foreach ($line in $sourceFile.SelectNodes('line')) {
56
+ $key = '{0}|{1}|{2}' -f $package.GetAttribute('name'), $sourceFile.GetAttribute('name'), $line.GetAttribute('nr')
57
+ if ($index.ContainsKey($key)) {
58
+ throw "Coverage report $Position lists line '$key' more than once."
59
+ }
60
+ $index.Add($key, $line)
61
+ }
62
+ }
63
+ }
64
+ , $index
65
+ }
66
+
67
+ $merged = ConvertFrom-PoshQCCoverageXml -CoverageXml $CoverageXml[0]
68
+ $mergedLines = & $indexLines $merged 1
69
+ for ($position = 1; $position -lt $CoverageXml.Count; $position++) {
70
+ $reportNumber = $position + 1
71
+ $otherLines = & $indexLines (ConvertFrom-PoshQCCoverageXml -CoverageXml $CoverageXml[$position]) $reportNumber
72
+ if ($otherLines.Count -ne $mergedLines.Count) {
73
+ throw "Coverage report $reportNumber lists $($otherLines.Count) lines; report 1 lists $($mergedLines.Count)."
74
+ }
75
+ foreach ($entry in $otherLines.GetEnumerator()) {
76
+ $line = $null
77
+ if (-not $mergedLines.TryGetValue($entry.Key, [ref] $line)) {
78
+ throw "Coverage report $reportNumber lists line '$($entry.Key)', which report 1 does not list."
79
+ }
80
+ $otherCovered = [long] $entry.Value.GetAttribute('ci')
81
+ $currentCovered = [long] $line.GetAttribute('ci')
82
+ if ($otherCovered -gt $currentCovered) {
83
+ $commandTotal = [long] $line.GetAttribute('mi') + $currentCovered
84
+ $line.SetAttribute('ci', [string] $otherCovered)
85
+ $line.SetAttribute('mi', [string] ($commandTotal - $otherCovered))
86
+ }
87
+ }
88
+ }
89
+
90
+ # Issue #953 (CR-8): class and method elements, and counters other than LINE and INSTRUCTION, cannot be
91
+ # recomputed from merged line hits and would keep the figures of report 1, so the merged report omits them.
92
+ foreach ($staleNode in @($merged.SelectNodes("//class | //counter[@type!='LINE' and @type!='INSTRUCTION']"))) {
93
+ [void] $staleNode.ParentNode.RemoveChild($staleNode)
94
+ }
95
+
96
+ $setCounter = {
97
+ param([System.Xml.XmlElement] $Node, [string] $Type, [long] $Covered, [long] $Missed)
98
+ $counter = $Node.SelectSingleNode("counter[@type='$Type']")
99
+ if ($counter) {
100
+ $counter.SetAttribute('missed', [string] $Missed)
101
+ $counter.SetAttribute('covered', [string] $Covered)
102
+ }
103
+ }
104
+ $setTotals = {
105
+ param([System.Xml.XmlElement] $Node, [long[]] $Totals)
106
+ & $setCounter $Node 'INSTRUCTION' $Totals[2] $Totals[3]
107
+ & $setCounter $Node 'LINE' $Totals[0] $Totals[1]
108
+ }
109
+
110
+ # Totals layout: 0 = LINE covered, 1 = LINE missed, 2 = INSTRUCTION covered, 3 = INSTRUCTION missed.
111
+ $reportTotals = New-Object 'long[]' 4
112
+ foreach ($package in $merged.DocumentElement.SelectNodes('package')) {
113
+ $packageTotals = New-Object 'long[]' 4
114
+ foreach ($sourceFile in $package.SelectNodes('sourcefile')) {
115
+ $fileTotals = New-Object 'long[]' 4
116
+ foreach ($line in $sourceFile.SelectNodes('line')) {
117
+ $lineCovered = [long] $line.GetAttribute('ci')
118
+ if ($lineCovered -gt 0) { $fileTotals[0]++ } else { $fileTotals[1]++ }
119
+ $fileTotals[2] += $lineCovered
120
+ $fileTotals[3] += [long] $line.GetAttribute('mi')
121
+ }
122
+ & $setTotals $sourceFile $fileTotals
123
+ for ($slot = 0; $slot -lt 4; $slot++) { $packageTotals[$slot] += $fileTotals[$slot] }
124
+ }
125
+ & $setTotals $package $packageTotals
126
+ for ($slot = 0; $slot -lt 4; $slot++) { $reportTotals[$slot] += $packageTotals[$slot] }
127
+ }
128
+ & $setTotals $merged.DocumentElement $reportTotals
129
+
130
+ $merged.OuterXml
131
+ }
132
+
133
+ <#
134
+ .SYNOPSIS
135
+ Summarizes the report-level LINE counter of a coverage report (issue #953).
136
+ .DESCRIPTION
137
+ Returns covered, missed, total, and percent (rounded to two decimals; 0 when total is 0) from the
138
+ report-level LINE counter. Takes XML text only and enforces no threshold.
139
+ .PARAMETER CoverageXml
140
+ The XML text of one coverage report.
141
+ #>
142
+ function Get-PoshQCCoverageLineSummary {
143
+ [CmdletBinding()]
144
+ param(
145
+ [Parameter(Mandatory)][string] $CoverageXml
146
+ )
147
+
148
+ $document = ConvertFrom-PoshQCCoverageXml -CoverageXml $CoverageXml
149
+ $counter = $document.SelectSingleNode("/report/counter[@type='LINE']")
150
+ if (-not $counter) {
151
+ throw 'The coverage report has no report-level LINE counter.'
152
+ }
153
+
154
+ $covered = [long] $counter.GetAttribute('covered')
155
+ $missed = [long] $counter.GetAttribute('missed')
156
+ $total = $covered + $missed
157
+ [pscustomobject]@{
158
+ covered = $covered
159
+ missed = $missed
160
+ total = $total
161
+ percent = if ($total -gt 0) { [math]::Round(100.0 * $covered / $total, 2) } else { 0 }
162
+ }
163
+ }