@danmoisan/drm-copilot-mcp 1.0.13 → 1.0.15

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 (131) hide show
  1. package/out/mcp-server.js +3160 -458
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +24 -0
  4. package/resources/claude-customizations/.claude/agents/epic-planner.md +121 -0
  5. package/resources/claude-customizations/.claude/agents/orchestrator.md +2 -2
  6. package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +246 -0
  7. package/resources/claude-customizations/.claude/settings.json +9 -2
  8. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +7 -0
  9. package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +189 -0
  10. package/resources/claude-customizations/.claude/skills/epic-run/SKILL.md +38 -0
  11. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +21 -2
  12. package/resources/claude-customizations/pack-manifests/core.json +4 -0
  13. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +0 -1
  14. package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/SKILL.md +100 -0
  15. package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/agents/openai.yaml +4 -0
  16. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +170 -0
  17. package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +230 -0
  18. package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +39 -0
  19. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +0 -1
  20. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +0 -1
  21. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +89 -9
  22. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +39 -4
  23. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +0 -1
  24. package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +0 -1
  25. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +153 -0
  26. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +153 -0
  27. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +153 -0
  28. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +153 -0
  29. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +153 -0
  30. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +2 -0
  31. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +95 -0
  32. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +95 -0
  33. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +95 -0
  34. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +95 -0
  35. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +95 -0
  36. package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +2 -0
  37. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +99 -0
  38. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +99 -0
  39. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +99 -0
  40. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +99 -0
  41. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +99 -0
  42. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +2 -0
  43. package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +96 -0
  44. package/resources/codex-and-agents-customizations/.codex/agents/epic-planner.toml +97 -0
  45. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +62 -0
  46. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +62 -0
  47. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +62 -0
  48. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +62 -0
  49. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +62 -0
  50. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +2 -0
  51. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +200 -0
  52. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +200 -0
  53. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +200 -0
  54. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +200 -0
  55. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +200 -0
  56. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +53 -3
  57. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +110 -0
  58. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +110 -0
  59. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +110 -0
  60. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +110 -0
  61. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +110 -0
  62. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +2 -0
  63. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c1.toml +28 -0
  64. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c2.toml +28 -0
  65. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c3-elevated.toml +28 -0
  66. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c3.toml +28 -0
  67. package/resources/codex-and-agents-customizations/.codex/agents/pr-author-c4.toml +28 -0
  68. package/resources/codex-and-agents-customizations/.codex/agents/pr-author.toml +2 -0
  69. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c1.toml +55 -0
  70. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c2.toml +55 -0
  71. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c3-elevated.toml +55 -0
  72. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c3.toml +55 -0
  73. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature-c4.toml +55 -0
  74. package/resources/codex-and-agents-customizations/.codex/agents/prd-feature.toml +2 -0
  75. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +102 -0
  76. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +102 -0
  77. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +102 -0
  78. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +102 -0
  79. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +102 -0
  80. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +2 -0
  81. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c1.toml +105 -0
  82. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c2.toml +105 -0
  83. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3-elevated.toml +105 -0
  84. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3.toml +105 -0
  85. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c4.toml +105 -0
  86. package/resources/codex-and-agents-customizations/.codex/agents/task-researcher.toml +2 -0
  87. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c1.toml +50 -0
  88. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c2.toml +50 -0
  89. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c3-elevated.toml +50 -0
  90. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c3.toml +50 -0
  91. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer-c4.toml +50 -0
  92. package/resources/codex-and-agents-customizations/.codex/agents/typescript-engineer.toml +2 -0
  93. package/resources/codex-and-agents-customizations/.codex/config.toml +202 -37
  94. package/resources/codex-and-agents-customizations/.codex/hooks/authorize-root-epic-invocation.ps1 +236 -0
  95. package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +178 -69
  96. package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +92 -19
  97. package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +199 -0
  98. package/resources/codex-and-agents-customizations/.codex/hooks/codex-authority-store.ps1 +182 -0
  99. package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +129 -0
  100. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +148 -31
  101. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +198 -0
  102. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +28 -19
  103. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +325 -0
  104. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +140 -0
  105. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +292 -0
  106. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +135 -0
  107. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +295 -0
  108. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +151 -0
  109. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +99 -34
  110. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +143 -27
  111. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +88 -43
  112. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +65 -20
  113. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +88 -42
  114. package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +414 -0
  115. package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +164 -51
  116. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +154 -0
  117. package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +58 -23
  118. package/resources/codex-and-agents-customizations/AGENTS.md +27 -0
  119. package/resources/codex-and-agents-customizations/pack-manifests/core.json +66 -1
  120. package/resources/codex-and-agents-customizations/pack-manifests/csharp-legacy.json +6 -1
  121. package/resources/codex-and-agents-customizations/pack-manifests/csharp-modern.json +6 -1
  122. package/resources/codex-and-agents-customizations/pack-manifests/powershell.json +6 -1
  123. package/resources/codex-and-agents-customizations/pack-manifests/python.json +6 -1
  124. package/resources/codex-and-agents-customizations/pack-manifests/typescript.json +6 -1
  125. package/resources/config/orchestration-routing.json +167 -0
  126. package/resources/powershell/PoshQC/PoshQC.Analyzer.psm1 +1 -1
  127. package/resources/powershell/PoshQC/PoshQC.ScanConfig.psm1 +125 -0
  128. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +14 -2
  129. package/resources/powershell/PoshQC/PoshQC.psd1 +0 -4
  130. package/resources/powershell/PoshQC/PoshQC.psm1 +26 -6
  131. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +34 -18
@@ -10,6 +10,11 @@
10
10
  ".codex/agents/python-typed-engineer.toml",
11
11
  ".codex/agents/python-orchestrator.toml",
12
12
  ".codex/agents/python-atomic-executor.toml",
13
- ".codex/agents/python-atomic-planning.toml"
13
+ ".codex/agents/python-atomic-planning.toml",
14
+ ".codex/agents/python-typed-engineer-c1.toml",
15
+ ".codex/agents/python-typed-engineer-c2.toml",
16
+ ".codex/agents/python-typed-engineer-c3.toml",
17
+ ".codex/agents/python-typed-engineer-c3-elevated.toml",
18
+ ".codex/agents/python-typed-engineer-c4.toml"
14
19
  ]
15
20
  }
@@ -4,6 +4,11 @@
4
4
  "paths": [
5
5
  ".agents/skills/typescript/SKILL.md",
6
6
  ".agents/skills/typescript-suppressions/SKILL.md",
7
- ".codex/agents/typescript-engineer.toml"
7
+ ".codex/agents/typescript-engineer.toml",
8
+ ".codex/agents/typescript-engineer-c1.toml",
9
+ ".codex/agents/typescript-engineer-c2.toml",
10
+ ".codex/agents/typescript-engineer-c3.toml",
11
+ ".codex/agents/typescript-engineer-c3-elevated.toml",
12
+ ".codex/agents/typescript-engineer-c4.toml"
8
13
  ]
9
14
  }
@@ -4,6 +4,12 @@
4
4
  "routes": {
5
5
  "small": {
6
6
  "description": "Minor-audit path for work inside the applicable language budget.",
7
+ "codex_topology_requirement": {
8
+ "receipt_key": "codex_topology_receipts",
9
+ "required_execution_context": "standalone",
10
+ "required_route": "small",
11
+ "delegation_agent_source": "resolved_language_typed_engineer"
12
+ },
7
13
  "required_agents": [
8
14
  "atomic-planner",
9
15
  "atomic-executor",
@@ -72,6 +78,27 @@
72
78
  "validate_orchestration_artifacts"
73
79
  ]
74
80
  },
81
+ "preparation": {
82
+ "description": "Epic preparation path driven by epic-planner: promotion, research, feature documents, atomic planning, and preflight clearance only. Atomic execution, PR authoring, and CI monitoring are out of scope and deferred to the epic execution phase, so this route requires no CI gate at completion.",
83
+ "requires_ci_gate": false,
84
+ "required_agents": [
85
+ "task-researcher",
86
+ "prd-feature",
87
+ "atomic-planner",
88
+ "atomic-executor"
89
+ ],
90
+ "required_skills": [
91
+ "orchestrate",
92
+ "feature-promotion-lifecycle",
93
+ "atomic-plan-contract"
94
+ ],
95
+ "required_mcp_tools": [
96
+ "new_potential_entry",
97
+ "potential_to_issue",
98
+ "new_active_feature_folder",
99
+ "validate_orchestration_artifacts"
100
+ ]
101
+ },
75
102
  "epic": {
76
103
  "description": "Epic path for scheduling a dependency graph of child features across parallel worktrees with fan-in via a shared integration branch.",
77
104
  "requires_pr_gate": true,
@@ -164,5 +191,145 @@
164
191
  "model_budget": {
165
192
  "description": "Session-level model budget. fable_policy is a three-way switch controlling whether the fable tier is disabled (removed and clamped to opus), available (used as-is), or preferred (applies the preferred_overlay).",
166
193
  "fable_policy": "preferred"
194
+ },
195
+ "codex_topology_policy": {
196
+ "description": "Codex-native production-file-count routing. This axis selects the initial implementation topology independently from C1-C4 model selection.",
197
+ "execution_contexts": [
198
+ "standalone",
199
+ "epic_preparation_child",
200
+ "epic_execution_child"
201
+ ],
202
+ "language_budgets": {
203
+ "python": {
204
+ "direct_mode_enabled": true,
205
+ "max_production_files": 3,
206
+ "max_test_files": 3,
207
+ "logical_agent": "python-typed-engineer"
208
+ },
209
+ "powershell": {
210
+ "direct_mode_enabled": true,
211
+ "max_production_files": 2,
212
+ "max_test_files": 3,
213
+ "logical_agent": "powershell-typed-engineer"
214
+ },
215
+ "csharp": {
216
+ "direct_mode_enabled": true,
217
+ "max_production_files": 3,
218
+ "max_test_files": 3,
219
+ "logical_agent": "csharp-typed-engineer"
220
+ },
221
+ "typescript": {
222
+ "direct_mode_enabled": false,
223
+ "max_production_files": 0,
224
+ "max_test_files": 0,
225
+ "logical_agent": "typescript-engineer"
226
+ }
227
+ },
228
+ "orchestrator_logical_agent": "orchestrator",
229
+ "epic_child_contexts": [
230
+ "epic_preparation_child",
231
+ "epic_execution_child"
232
+ ],
233
+ "forced_root_personas": [
234
+ "epic-planner",
235
+ "epic-orchestrator"
236
+ ],
237
+ "parallelism": {
238
+ "default_max_parallel_features": 4,
239
+ "hard_max_parallel_features": 8
240
+ },
241
+ "escalation_precedence": [
242
+ "epic_child_context",
243
+ "invalid_estimate",
244
+ "cross_language",
245
+ "unsupported_language",
246
+ "cross_cutting",
247
+ "direct_mode_disabled",
248
+ "production_budget_exceeded"
249
+ ],
250
+ "receipt_key": "codex_topology_receipts"
251
+ },
252
+ "codex_model_policy": {
253
+ "description": "Codex-native deployment profiles. Complexity selects model and reasoning independently from the file-count route; exact model slugs are mandatory and unavailable profiles do not fall back silently.",
254
+ "profile_order": [
255
+ "c1",
256
+ "c2",
257
+ "c3",
258
+ "c3-elevated",
259
+ "c4"
260
+ ],
261
+ "execution_contexts": [
262
+ "standalone",
263
+ "epic_preparation_child",
264
+ "epic_execution_child"
265
+ ],
266
+ "logical_agent_aliases": {
267
+ "feature-review": "feature-reviewer"
268
+ },
269
+ "complexity_to_profile": {
270
+ "C1": {
271
+ "suffix": "c1",
272
+ "model": "gpt-5.6-luna",
273
+ "model_reasoning_effort": "low"
274
+ },
275
+ "C2": {
276
+ "suffix": "c2",
277
+ "model": "gpt-5.6-terra",
278
+ "model_reasoning_effort": "medium"
279
+ },
280
+ "C3": {
281
+ "suffix": "c3",
282
+ "model": "gpt-5.6-terra",
283
+ "model_reasoning_effort": "high"
284
+ },
285
+ "C4": {
286
+ "suffix": "c4",
287
+ "model": "gpt-5.6-sol",
288
+ "model_reasoning_effort": "max"
289
+ }
290
+ },
291
+ "c3_elevated_profile": {
292
+ "suffix": "c3-elevated",
293
+ "model": "gpt-5.6-sol",
294
+ "model_reasoning_effort": "high",
295
+ "activation": {
296
+ "operator": "any",
297
+ "execution_contexts": [
298
+ "epic_execution_child",
299
+ "epic_preparation_child"
300
+ ],
301
+ "orchestration_complexity_ceiling": "C4"
302
+ }
303
+ },
304
+ "ceiling_transition_policy": {
305
+ "monotonic": true,
306
+ "receipt_key": "ceiling_transition",
307
+ "affected_delegation_ids_required_on_increase": true
308
+ },
309
+ "forced_personas": {
310
+ "epic-planner": {
311
+ "suffix": "",
312
+ "model": "gpt-5.6-sol",
313
+ "model_reasoning_effort": "ultra"
314
+ },
315
+ "epic-orchestrator": {
316
+ "suffix": "",
317
+ "model": "gpt-5.6-sol",
318
+ "model_reasoning_effort": "ultra"
319
+ }
320
+ },
321
+ "generated_agent_families": [
322
+ "orchestrator",
323
+ "atomic-planner",
324
+ "atomic-executor",
325
+ "feature-reviewer",
326
+ "task-researcher",
327
+ "prd-feature",
328
+ "pr-author",
329
+ "python-typed-engineer",
330
+ "powershell-typed-engineer",
331
+ "csharp-typed-engineer",
332
+ "typescript-engineer"
333
+ ]
167
334
  }
168
335
  }
@@ -27,7 +27,7 @@ function Invoke-PoshQCFormat {
27
27
  [scriptblock] $TestPathExists = { param([string] $Path) Test-Path $Path },
28
28
  [scriptblock] $GetFileList = { param([string] $RootPath, [string[]] $ScanFoldersPath, [string[]] $Excluded) Get-PoshQCFileList -Root $RootPath -ScanFolders $ScanFoldersPath -ExcludeDirs $Excluded },
29
29
  [scriptblock] $ReadFile = { param([string] $Path) Get-Content -Raw -Path $Path },
30
- [scriptblock] $WriteFile = { param([string] $Path, [string] $Content) Set-Content -Path $Path -Value $Content -Encoding UTF8 },
30
+ [scriptblock] $WriteFile = { param([string] $Path, [string] $Content) Set-Content -Path $Path -Value $Content -Encoding UTF8 -NoNewline },
31
31
  [scriptblock] $FormatContent = { param([string] $Content, [string] $Settings) Invoke-Formatter -ScriptDefinition $Content -Settings $Settings },
32
32
  [scriptblock] $Logger = {
33
33
  param([string] $Message)
@@ -0,0 +1,125 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Resolves the persisted PoshQC test scan-folder configuration.
4
+ .DESCRIPTION
5
+ Reads and validates the repo-local scan configuration file (default
6
+ 'config/poshqc-scan.json') and returns the validated, workspace-relative
7
+ folder list from 'test.scanFolders'. Returns an empty array when the file is
8
+ absent or when 'test.scanFolders' is absent or empty, so that an absent
9
+ configuration preserves the settings 'Run.Path' defaults downstream.
10
+
11
+ Validation is fail-fast and names the configuration file: malformed JSON, a
12
+ 'version' value other than 1, blank entries, absolute-path entries, and
13
+ entries containing '..' segments are errors. Config-sourced folders that do
14
+ not exist are skipped with a logged warning; if a non-empty configuration
15
+ lists only folders that do not exist, the function fails fast with a clear
16
+ error. This function never weakens Resolve-PoshQCScanFolder; the throw-on-missing
17
+ behavior for explicitly supplied folders is unaffected because it is not used
18
+ on this path.
19
+ .PARAMETER Root
20
+ Workspace root the relative configuration path and folder entries resolve against.
21
+ .PARAMETER ConfigRelativePath
22
+ Workspace-relative path to the configuration file. Defaults to
23
+ 'config/poshqc-scan.json'.
24
+ .PARAMETER TestPathExists
25
+ Injectable existence-check seam (config file and folder existence). Defaults to Test-Path.
26
+ .PARAMETER ReadContent
27
+ Injectable read seam returning the raw file text. Defaults to Get-Content -Raw.
28
+ .PARAMETER Logger
29
+ Injectable warning seam for skip-with-warning messages. Defaults to Write-Warning.
30
+ #>
31
+ function Get-PoshQCScanConfigFolder {
32
+ [CmdletBinding()]
33
+ [OutputType([System.Object[]])]
34
+ param(
35
+ [Parameter(Mandatory = $true)]
36
+ [string] $Root,
37
+ [string] $ConfigRelativePath = 'config/poshqc-scan.json',
38
+ [scriptblock] $TestPathExists = { param([string] $Path) Test-Path $Path },
39
+ [scriptblock] $ReadContent = { param([string] $Path) Get-Content -Path $Path -Raw },
40
+ [scriptblock] $Logger = { param([string] $Message) Write-Warning $Message }
41
+ )
42
+
43
+ $ErrorActionPreference = 'Stop'
44
+
45
+ # Resolve the configuration path against the workspace root unless it is already absolute.
46
+ $configPath = if ([IO.Path]::IsPathRooted($ConfigRelativePath)) {
47
+ $ConfigRelativePath
48
+ } else {
49
+ Join-Path -Path $Root -ChildPath $ConfigRelativePath
50
+ }
51
+
52
+ # Absent configuration file means defaults apply (empty result, no error).
53
+ if (-not (& $TestPathExists $configPath)) {
54
+ return @()
55
+ }
56
+
57
+ $raw = & $ReadContent $configPath
58
+ # Absent or whitespace-only content is treated the same as an absent file.
59
+ if ([string]::IsNullOrWhiteSpace([string] $raw)) {
60
+ return @()
61
+ }
62
+
63
+ try {
64
+ $parsed = $raw | ConvertFrom-Json -ErrorAction Stop
65
+ } catch {
66
+ throw "Invalid JSON in scan configuration '$ConfigRelativePath': $($_.Exception.Message)"
67
+ }
68
+
69
+ # StrictMode-safe property access: read properties through PSObject so a
70
+ # missing property yields $null rather than a strict-mode failure.
71
+ $versionProperty = $parsed.PSObject.Properties['version']
72
+ if (-not $versionProperty -or $versionProperty.Value -ne 1) {
73
+ throw "Scan configuration '$ConfigRelativePath' must declare 'version' equal to 1."
74
+ }
75
+
76
+ # Absent 'test' section, or absent/empty 'test.scanFolders', means defaults apply.
77
+ $testProperty = $parsed.PSObject.Properties['test']
78
+ if (-not $testProperty -or $null -eq $testProperty.Value) {
79
+ return @()
80
+ }
81
+ $scanFoldersProperty = $testProperty.Value.PSObject.Properties['scanFolders']
82
+ if (-not $scanFoldersProperty -or $null -eq $scanFoldersProperty.Value) {
83
+ return @()
84
+ }
85
+ $scanFolders = @($scanFoldersProperty.Value)
86
+ if ($scanFolders.Count -eq 0) {
87
+ return @()
88
+ }
89
+
90
+ # Validate every entry; each failure is fail-fast and names the configuration file.
91
+ $validated = foreach ($folder in $scanFolders) {
92
+ $folderText = [string] $folder
93
+ if ([string]::IsNullOrWhiteSpace($folderText)) {
94
+ throw "Scan configuration '$ConfigRelativePath' contains a blank 'test.scanFolders' entry."
95
+ }
96
+ if ([IO.Path]::IsPathRooted($folderText)) {
97
+ throw "Scan configuration '$ConfigRelativePath' entry '$folderText' must be a workspace-relative path, not an absolute path."
98
+ }
99
+ # Reject parent-directory traversal in any path segment.
100
+ $segments = $folderText -split '[\\/]+'
101
+ if ($segments -contains '..') {
102
+ throw "Scan configuration '$ConfigRelativePath' entry '$folderText' must not contain '..' segments."
103
+ }
104
+ $folderText
105
+ }
106
+ $validated = @($validated)
107
+
108
+ # Filter out config-sourced folders that do not exist, skipping each with a warning.
109
+ $existing = foreach ($folder in $validated) {
110
+ $candidate = Join-Path -Path $Root -ChildPath $folder
111
+ if (& $TestPathExists $candidate) {
112
+ $folder
113
+ } else {
114
+ & $Logger "Scan configuration '$ConfigRelativePath' folder '$folder' does not exist under root '$Root'; skipping."
115
+ }
116
+ }
117
+ $existing = @($existing)
118
+
119
+ # A non-empty configuration whose folders were all filtered out is a hard error.
120
+ if ($existing.Count -eq 0) {
121
+ throw "Scan configuration '$ConfigRelativePath' lists only folders that do not exist under root '$Root'."
122
+ }
123
+
124
+ return @($existing)
125
+ }
@@ -206,6 +206,10 @@ function Invoke-PoshQCTest {
206
206
  param([string] $RootPath, [string[]] $Folders)
207
207
  Resolve-PoshQCScanFolder -Root $RootPath -ScanFolders $Folders
208
208
  },
209
+ [scriptblock] $ResolveScanConfig = {
210
+ param([string] $RootPath)
211
+ Get-PoshQCScanConfigFolder -Root $RootPath
212
+ },
209
213
  [scriptblock] $ExpandCoveragePaths = {
210
214
  param($Config, [string] $RootPath)
211
215
  if (-not $Config.CodeCoverage) { return $Config }
@@ -276,8 +280,16 @@ function Invoke-PoshQCTest {
276
280
  $config = & $ExpandRunPaths $config $Root $ExcludeDirs
277
281
  $config = & $EnsureResultPath $config $Root
278
282
  $config = & $ExpandCoveragePaths $config $Root
279
- if ($ScanFolders -and $ScanFolders.Count -gt 0) {
280
- $resolvedScanFolders = @(& $ResolveScanFolders $Root $ScanFolders)
283
+ # Scan-folder precedence: explicit -ScanFolders always wins; otherwise the
284
+ # persisted scan configuration is consulted; an absent or empty configuration
285
+ # leaves the settings Run.Path defaults in place.
286
+ $effectiveScanFolders = if ($ScanFolders -and $ScanFolders.Count -gt 0) {
287
+ @($ScanFolders)
288
+ } else {
289
+ @(& $ResolveScanConfig $Root)
290
+ }
291
+ if ($effectiveScanFolders -and $effectiveScanFolders.Count -gt 0) {
292
+ $resolvedScanFolders = @(& $ResolveScanFolders $Root $effectiveScanFolders)
281
293
  if ($resolvedScanFolders.Count -gt 0) {
282
294
  $config.Run.Path = $resolvedScanFolders
283
295
  }
@@ -8,10 +8,6 @@
8
8
  Description = 'Reusable PowerShell QC helpers (format, analyze, test) using Invoke-Formatter, PSScriptAnalyzer, and Pester.'
9
9
  PowerShellVersion = '5.1'
10
10
  CompatiblePSEditions = @('Desktop', 'Core')
11
- RequiredModules = @(
12
- @{ ModuleName = 'PSScriptAnalyzer'; ModuleVersion = '1.22.0' },
13
- @{ ModuleName = 'Pester'; ModuleVersion = '5.6.1' }
14
- )
15
11
  FunctionsToExport = @(
16
12
  'Convert-PoshQCCoverageToRelative',
17
13
  'Get-PoshQCFileList',
@@ -80,11 +80,30 @@ function Install-PoshQCTool {
80
80
  }
81
81
 
82
82
  # PowerShell 7.6+ treats dot-sourced .psm1 files as isolated modules, so
83
- # functions defined in them do not enter the parent module scope. Loading the
84
- # file content as a scriptblock bypasses that behaviour.
85
- . ([scriptblock]::Create((Get-Content (Join-Path $script:ModuleRoot 'PoshQC.FileDiscovery.psm1') -Raw)))
86
- . ([scriptblock]::Create((Get-Content (Join-Path $script:ModuleRoot 'PoshQC.Analyzer.psm1') -Raw)))
87
- . ([scriptblock]::Create((Get-Content (Join-Path $script:ModuleRoot 'PoshQC.Testing.psm1') -Raw)))
83
+ # functions defined in them do not enter the parent module scope. A scriptblock
84
+ # obtained from [Parser]::ParseFile(...).GetScriptBlock() still executes in the
85
+ # caller's (module) scope when dot-sourced, preserving that workaround, while
86
+ # also retaining the on-disk file association. The file association is required
87
+ # so Pester code-coverage breakpoints can bind to the sub-module source files
88
+ # (issue #344 remediation cycle 1, R2); the previous fileless
89
+ # [scriptblock]::Create((Get-Content -Raw)) approach produced scriptblocks with
90
+ # no source file, so breakpoints never bound and PoshQC.ScanConfig.psm1 fell
91
+ # outside the coverage denominator. Parse errors fail module import fast.
92
+ foreach ($subModuleName in @(
93
+ 'PoshQC.FileDiscovery.psm1',
94
+ 'PoshQC.ScanConfig.psm1',
95
+ 'PoshQC.Analyzer.psm1',
96
+ 'PoshQC.Testing.psm1'
97
+ )) {
98
+ $subModulePath = Join-Path $script:ModuleRoot $subModuleName
99
+ $parseErrors = $null
100
+ $ast = [System.Management.Automation.Language.Parser]::ParseFile(
101
+ $subModulePath, [ref]$null, [ref]$parseErrors)
102
+ if ($parseErrors) {
103
+ throw "Failed to parse sub-module '$subModuleName': $($parseErrors -join '; ')"
104
+ }
105
+ . ($ast.GetScriptBlock())
106
+ }
88
107
 
89
108
  Set-Alias -Name Install-PoshQCTools -Value Install-PoshQCTool
90
109
 
@@ -96,6 +115,7 @@ Export-ModuleMember -Function @(
96
115
  'Invoke-PoshQCAnalyzeAutofix',
97
116
  'Invoke-PoshQCSuite',
98
117
  'Invoke-PoshQCTest',
99
- 'Convert-PoshQCCoverageToRelative'
118
+ 'Convert-PoshQCCoverageToRelative',
119
+ 'Get-PoshQCScanConfigFolder'
100
120
  ) -Alias @('Install-PoshQCTools')
101
121
 
@@ -21,6 +21,9 @@
21
21
  OutputFormat = 'CoverageGutters'
22
22
  OutputPath = 'artifacts/pester/powershell-coverage.xml'
23
23
  Path = @(
24
+ # Scope coverage to hook files with deterministic Pester coverage in this branch.
25
+ # Broader script/module globs include bootstrap and one-shot automation paths that
26
+ # are validated by their own suites but not meaningfully covered by this hook batch.
24
27
  '.claude/hooks/validate-bash.ps1'
25
28
  '.claude/hooks/check-python-test-purity.ps1'
26
29
  '.claude/hooks/check-powershell-test-purity.ps1'
@@ -44,27 +47,41 @@
44
47
  '.claude/hooks/enforce-pr-author-skill.ps1'
45
48
  '.claude/hooks/validate-orchestrator-output.ps1'
46
49
  '.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1'
50
+ # Issue #301 remediation cycle 1 (fix #1): measure the completion-consistency
51
+ # hook set (Claude and Codex variants) so their Pester coverage is captured.
52
+ '.claude/hooks/enforce-completion-consistency.ps1'
53
+ '.claude/hooks/enforce-completion-helpers.ps1'
54
+ '.codex/hooks/enforce-completion-consistency.ps1'
55
+ '.codex/hooks/enforce-completion-helpers.ps1'
56
+ # Issue #298 fixed ConvertTo-CommandResult's handling of an empty array Output
57
+ # parameter in this script; measured here so the change produces real per-file
58
+ # coverage evidence going forward.
59
+ 'scripts/dev-tools/Invoke-FullReleaseFlow.ps1'
60
+ # Issue #305 added this PreToolUse model-routing-receipt deterrent hook; measured
61
+ # here so the new production hook is not excluded from coverage.
62
+ '.claude/hooks/enforce-model-routing-receipt.ps1'
63
+ # Issue #312 added the .claude-resident PowerShell model-routing library so the
64
+ # push-down bundle no longer cites missing scripts/dev_tools references; measured
65
+ # here so the new production module is not excluded from coverage.
66
+ '.claude/lib/model-routing/ModelRouting.psm1'
67
+ # The portable orchestrator-state modules make the pushed-down enforcement hooks
68
+ # work in consumer repos without scripts/dev_tools; measured here so the new
69
+ # production modules are not excluded from coverage.
70
+ '.claude/lib/orchestrator-state/OrchestratorState.psm1'
71
+ '.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1'
72
+ # Issue #328 added this dev-tools worktree launcher script; measured here so the
73
+ # changed production file is in the coverage denominator (R1). The test suite
74
+ # dot-sources the file (guarded body) so line attribution is valid.
75
+ 'scripts/dev-tools/new-claude-worktree-session.ps1'
47
76
  # Issue #334 added this SessionStart hook that persists the current session id;
48
77
  # measured here so the new production hook is not excluded from coverage. The
49
78
  # test suite dot-sources the file (guarded body) so line attribution is valid.
50
79
  '.claude/hooks/persist-session-id.ps1'
51
- )
52
- ExcludedPath = @(
53
- '.claude/hooks/validate-feature-review-coverage.ps1' # Feature-review wrapper around repository evidence; not deterministic in normal unit-test execution.
54
- 'scripts/dev-tools/bootstrap-host.ps1' # Host bootstrap entrypoint for external setup; not deterministic in normal unit-test execution.
55
- 'scripts/dev-tools/bootstrap-host.helpers.ps1' # Bootstrap helper for host setup; not deterministic in normal unit-test execution.
56
- 'scripts/dev-tools/format-powershell.ps1' # Thin formatter wrapper around external tooling; not deterministic in normal unit-test execution.
57
- 'scripts/dev-tools/load-openai-key.ps1' # Local secret-loading wrapper; not deterministic in normal unit-test execution.
58
- 'scripts/dev-tools/publish-sideloaded-extension.ps1' # VS Code extension publication wrapper; not deterministic in normal unit-test execution.
59
- 'scripts/dev-tools/run-actionlint.ps1' # External actionlint wrapper; not deterministic in normal unit-test execution.
60
- 'scripts/dev-tools/run-pester.ps1' # Pester CLI wrapper; not deterministic in normal unit-test execution.
61
- 'scripts/dev-tools/run-poshqc-suite.ps1' # PoshQC CLI wrapper; not deterministic in normal unit-test execution.
62
- 'scripts/dev-tools/run-psscriptanalyzer.ps1' # PSScriptAnalyzer CLI wrapper; not deterministic in normal unit-test execution.
63
- 'scripts/dev-tools/verify-host.ps1' # Host verification wrapper for local tools; not deterministic in normal unit-test execution.
64
- 'scripts/dev-tools/vscode-cli.helpers.ps1' # VS Code CLI helper around external processes; not deterministic in normal unit-test execution.
65
- 'scripts/powershell/PoshQC/PoshQC.Analyzer.psm1' # Analyzer orchestration module over external tooling; not deterministic in normal unit-test execution.
66
- 'scripts/powershell/PoshQC/PoshQC.FileDiscovery.psm1' # File-discovery module coupled to workspace traversal; not deterministic in normal unit-test execution.
67
- 'scripts/powershell/PoshQC/PoshQC.Testing.psm1' # Pester orchestration module over external tooling; not deterministic in normal unit-test execution.
80
+ # Issue #344 remediation cycle 1 (R2): measure the new production ScanConfig module
81
+ # so it is not excluded from coverage; PoshQC.psm1 sub-module loading was refactored
82
+ # to AST-based scriptblocks (Parser::ParseFile(...).GetScriptBlock()) so Pester
83
+ # coverage breakpoints bind to the on-disk source file.
84
+ 'scripts/powershell/PoshQC/PoshQC.ScanConfig.psm1'
68
85
  )
69
86
  # Optional: don't fail the run on coverage percentage
70
87
  CoveragePercentTarget = 0
@@ -78,4 +95,3 @@
78
95
 
79
96
 
80
97
 
81
-