@danmoisan/drm-copilot-mcp 1.0.0 → 1.0.7

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 (52) hide show
  1. package/out/mcp-server.js +814 -194
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agents/commit-message.md +42 -0
  4. package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +127 -0
  5. package/resources/claude-customizations/.claude/agents/human-exception-runbook.md +48 -0
  6. package/resources/claude-customizations/.claude/agents/orchestrator.md +67 -2
  7. package/resources/claude-customizations/.claude/agents/pr-author.md +37 -21
  8. package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +103 -65
  9. package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +12 -9
  10. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +24 -16
  11. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +19 -13
  12. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +304 -0
  13. package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +304 -0
  14. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +237 -0
  15. package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +16 -12
  16. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +14 -10
  17. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +35 -8
  18. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +17 -14
  19. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +104 -0
  20. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +268 -93
  21. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +19 -11
  22. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +28 -6
  23. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +17 -14
  24. package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +146 -36
  25. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +19 -7
  26. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +36 -0
  27. package/resources/claude-customizations/.claude/settings.json +34 -1
  28. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +252 -0
  29. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -13
  30. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +28 -0
  31. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +22 -18
  32. package/resources/claude-customizations/pack-manifests/core.json +8 -0
  33. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +6 -3
  34. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +1 -1
  35. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +65 -0
  36. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +79 -0
  37. package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +66 -0
  38. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -25
  39. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-pr-author-skill.ps1 +257 -93
  40. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +98 -0
  41. package/resources/codex-and-agents-customizations/pack-manifests/core.json +24 -0
  42. package/resources/codex-and-agents-customizations/pack-manifests/csharp-legacy.json +11 -0
  43. package/resources/codex-and-agents-customizations/pack-manifests/csharp-modern.json +10 -0
  44. package/resources/codex-and-agents-customizations/pack-manifests/powershell.json +15 -0
  45. package/resources/codex-and-agents-customizations/pack-manifests/python.json +15 -0
  46. package/resources/codex-and-agents-customizations/pack-manifests/typescript.json +9 -0
  47. package/resources/config/orchestration-routing.json +92 -0
  48. package/resources/customizations/.github/agents/pr-author.agent.md +24 -18
  49. package/resources/icon.png +0 -0
  50. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +11 -0
  51. package/resources/codex-and-agents-customizations/.github/workflows/_validate-orchestrator-state.yml +0 -68
  52. package/resources/codex-and-agents-customizations/.github/workflows/validate-orchestrator-state.yml +0 -15
@@ -130,6 +130,36 @@ function Get-CheckpointContent {
130
130
  return Get-Content -Raw -LiteralPath $script:CheckpointPath
131
131
  }
132
132
 
133
+ function Get-OrchestrationPreimplementationGateAllowDecision {
134
+ [CmdletBinding()]
135
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
136
+ param()
137
+
138
+ return [ordered]@{
139
+ hookSpecificOutput = [ordered]@{
140
+ hookEventName = 'PreToolUse'
141
+ permissionDecision = 'allow'
142
+ }
143
+ }
144
+ }
145
+
146
+ function Get-OrchestrationPreimplementationGateBlockDecision {
147
+ [CmdletBinding()]
148
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
149
+ param(
150
+ [Parameter(Mandatory)]
151
+ [string] $Reason
152
+ )
153
+
154
+ return [ordered]@{
155
+ hookSpecificOutput = [ordered]@{
156
+ hookEventName = 'PreToolUse'
157
+ permissionDecision = 'deny'
158
+ permissionDecisionReason = $Reason
159
+ }
160
+ }
161
+ }
162
+
133
163
  function Invoke-OrchestrationPreimplementationGateDecision {
134
164
  [CmdletBinding()]
135
165
  [OutputType([System.Collections.Specialized.OrderedDictionary])]
@@ -139,7 +169,7 @@ function Invoke-OrchestrationPreimplementationGateDecision {
139
169
  )
140
170
 
141
171
  if (-not $ToolInputRaw) {
142
- return [ordered]@{ decision = 'allow' }
172
+ return Get-OrchestrationPreimplementationGateAllowDecision
143
173
  }
144
174
  try {
145
175
  $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
@@ -162,7 +192,7 @@ function Invoke-OrchestrationPreimplementationGateDecision {
162
192
  }
163
193
 
164
194
  if (-not $requiresReadyCheckpoint) {
165
- return [ordered]@{ decision = 'allow' }
195
+ return Get-OrchestrationPreimplementationGateAllowDecision
166
196
  }
167
197
 
168
198
  if (-not $CheckpointRaw) {
@@ -175,12 +205,9 @@ function Invoke-OrchestrationPreimplementationGateDecision {
175
205
  }
176
206
 
177
207
  if (Test-OrchestrationReady -Payload $checkpoint) {
178
- return [ordered]@{ decision = 'allow' }
179
- }
180
- return [ordered]@{
181
- decision = 'block'
182
- reason = 'PREIMPLEMENTATION_GATE_BLOCKED: Implementation operations require artifacts/orchestration/orchestrator-state.json to contain issue number, feature folder, route metadata, lifecycle readiness, and checkpoint state before implementation begins.'
208
+ return Get-OrchestrationPreimplementationGateAllowDecision
183
209
  }
210
+ return Get-OrchestrationPreimplementationGateBlockDecision -Reason 'PREIMPLEMENTATION_GATE_BLOCKED: Implementation operations require artifacts/orchestration/orchestrator-state.json to contain issue number, feature folder, route metadata, lifecycle readiness, and checkpoint state before implementation begins.'
184
211
  }
185
212
 
186
213
  if ($MyInvocation.InvocationName -eq '.') {
@@ -194,5 +221,5 @@ try {
194
221
  exit 1
195
222
  }
196
223
 
197
- $decision | ConvertTo-Json -Compress | Write-Output
224
+ $decision | ConvertTo-Json -Compress -Depth 5 | Write-Output
198
225
  exit 0
@@ -26,10 +26,10 @@
26
26
  before the session starts, or by writing {"prodCap": N, "testCap": M} into the
27
27
  state file.
28
28
 
29
- When the cap would be exceeded by a new file, the script emits a JSON response with
30
- 'decision': 'block' and exits 0. The session must explicitly reset the counter by
31
- deleting the state file before starting a new batch. Files already counted are
32
- always allowed through.
29
+ When the cap would be exceeded by a new file, the script emits a PreToolUse JSON
30
+ response with hookSpecificOutput.permissionDecision = 'deny' and exits 0. The session
31
+ must explicitly reset the counter by deleting the state file before starting a new
32
+ batch. Files already counted are always allowed through.
33
33
 
34
34
  .NOTES
35
35
  Compatible with PowerShell 7+.
@@ -90,8 +90,11 @@ function Get-PowerShellBatchBudgetBlockDecision {
90
90
  )
91
91
 
92
92
  $decision = [ordered]@{
93
- decision = 'block'
94
- reason = $Reason
93
+ hookSpecificOutput = [ordered]@{
94
+ hookEventName = 'PreToolUse'
95
+ permissionDecision = 'deny'
96
+ permissionDecisionReason = $Reason
97
+ }
95
98
  }
96
99
  if ($State) {
97
100
  $decision.state = $State
@@ -116,7 +119,7 @@ function Invoke-PowerShellBatchBudgetDecision {
116
119
 
117
120
  $normalized = $FilePath -replace '\\', '/'
118
121
  if ($normalized -notmatch '\.(ps1|psm1|psd1)$') {
119
- return [ordered]@{ decision = 'allow'; state = $State; shouldWriteState = $false }
122
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' }; state = $State; shouldWriteState = $false }
120
123
  }
121
124
 
122
125
  $isTestFile = ($normalized -match '(^|/)tests/.*\.ps1$') -or ($normalized -match '\.Tests\.ps1$')
@@ -125,7 +128,7 @@ function Invoke-PowerShellBatchBudgetDecision {
125
128
  $kind = if ($isTestFile) { 'test' } else { 'production' }
126
129
 
127
130
  if ($targetList -contains $normalized) {
128
- return [ordered]@{ decision = 'allow'; state = $State; shouldWriteState = $false }
131
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' }; state = $State; shouldWriteState = $false }
129
132
  }
130
133
 
131
134
  if ($targetList.Count -ge $cap) {
@@ -141,7 +144,7 @@ function Invoke-PowerShellBatchBudgetDecision {
141
144
  $State.prodFiles = @($State.prodFiles) + @($normalized)
142
145
  }
143
146
 
144
- return [ordered]@{ decision = 'allow'; state = $State; shouldWriteState = $true }
147
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' }; state = $State; shouldWriteState = $true }
145
148
  }
146
149
 
147
150
  function Invoke-PowerShellBatchBudgetHook {
@@ -163,7 +166,7 @@ function Invoke-PowerShellBatchBudgetHook {
163
166
  )
164
167
 
165
168
  if (-not $ToolInputRaw) {
166
- return [ordered]@{ decision = 'allow' }
169
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
167
170
  }
168
171
 
169
172
  try {
@@ -174,12 +177,12 @@ function Invoke-PowerShellBatchBudgetHook {
174
177
 
175
178
  $filePath = $toolInput.file_path
176
179
  if (-not $filePath) {
177
- return [ordered]@{ decision = 'allow' }
180
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
178
181
  }
179
182
 
180
183
  $normalized = $filePath -replace '\\', '/'
181
184
  if ($normalized -notmatch '\.(ps1|psm1|psd1)$') {
182
- return [ordered]@{ decision = 'allow' }
185
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
183
186
  }
184
187
 
185
188
  $stateDir = Join-Path -Path $Root -ChildPath '.claude/state'
@@ -230,9 +233,9 @@ if ($env:CLAUDE_POWERSHELL_BUDGET_TEST -match '^\d+$') {
230
233
  }
231
234
 
232
235
  $decision = Invoke-PowerShellBatchBudgetHook -ToolInputRaw $env:CLAUDE_TOOL_INPUT -SessionId $sessionId -ProdCap $prodCap -TestCap $testCap
233
- if ($decision.decision -eq 'block') {
236
+ if ($decision.hookSpecificOutput.permissionDecision -eq 'deny') {
234
237
  $decision.Remove('state')
235
- $decision | ConvertTo-Json -Compress | Write-Output
238
+ $decision | ConvertTo-Json -Compress -Depth 5 | Write-Output
236
239
  }
237
240
 
238
241
  exit 0
@@ -0,0 +1,104 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Dot-sourced by enforce-pr-author-skill.ps1 to keep that file under the repository's
4
+ 500-line hard cap.
5
+
6
+ .DESCRIPTION
7
+ Contains the epic-mode base-branch override check (Get-PrAuthorCheckpointContent and
8
+ Test-EpicBaseBranchOverride) extracted verbatim from enforce-pr-author-skill.ps1. This is a
9
+ structural extraction only: no logic, decision behavior, or reason-string wording changed.
10
+ #>
11
+
12
+ function Get-PrAuthorCheckpointContent {
13
+ <#
14
+ .SYNOPSIS
15
+ Read the raw JSON text of the per-feature orchestrator checkpoint. Tests mock this
16
+ function (read seam) for the epic-mode base-branch override check.
17
+ .DESCRIPTION
18
+ Returns the raw text content of artifacts/orchestration/orchestrator-state.json, or
19
+ $null when the file is absent. This is the injectable boundary for checkpoint content
20
+ used by Test-EpicBaseBranchOverride; no test writes the checkpoint file to disk.
21
+ .PARAMETER CheckpointPath
22
+ The relative path to the per-feature orchestrator checkpoint.
23
+ .OUTPUTS
24
+ System.String or $null
25
+ #>
26
+ [CmdletBinding()]
27
+ [OutputType([string])]
28
+ param(
29
+ [Parameter(Mandatory = $false)]
30
+ [string] $CheckpointPath = 'artifacts/orchestration/orchestrator-state.json'
31
+ )
32
+
33
+ if (-not (Test-Path -LiteralPath $CheckpointPath)) {
34
+ return $null
35
+ }
36
+
37
+ return (Get-Content -LiteralPath $CheckpointPath -Raw)
38
+ }
39
+
40
+ function Test-EpicBaseBranchOverride {
41
+ <#
42
+ .SYNOPSIS
43
+ Sixth ordered check: enforce the epic-mode --base override for gh pr create.
44
+ .DESCRIPTION
45
+ Reads the per-feature checkpoint via the injectable Get-PrAuthorCheckpointContent
46
+ seam. When the checkpoint has epic_mode == true, a gh pr create command text MUST
47
+ contain --base <epic_context.integration_branch> with the exact branch value recorded
48
+ in the checkpoint; a missing --base, or a --base value that does not match, is denied
49
+ with reason EPIC_BASE_BRANCH_MISMATCH. When epic_mode is absent or false, when the
50
+ checkpoint is unreadable, or when the command is not gh pr create (the base branch is
51
+ set at create time, not edit time), this check is a no-op and standalone behavior is
52
+ unchanged.
53
+ .PARAMETER CommandText
54
+ The Bash command text under evaluation.
55
+ .OUTPUTS
56
+ System.String or $null
57
+ #>
58
+ [CmdletBinding()]
59
+ [OutputType([string])]
60
+ param(
61
+ [Parameter(Mandatory)]
62
+ [string] $CommandText
63
+ )
64
+
65
+ # The epic-mode base-branch override only constrains gh pr create; gh pr edit does not
66
+ # re-target the base branch, so non-create commands are out of scope for this check.
67
+ if ($CommandText -notmatch '(?i)\bgh\s+pr\s+create\b') {
68
+ return $null
69
+ }
70
+
71
+ $checkpointRaw = Get-PrAuthorCheckpointContent
72
+ if ([string]::IsNullOrWhiteSpace($checkpointRaw)) {
73
+ return $null
74
+ }
75
+
76
+ try {
77
+ $checkpoint = $checkpointRaw | ConvertFrom-Json -ErrorAction Stop
78
+ } catch {
79
+ return $null
80
+ }
81
+
82
+ $checkpointProps = @($checkpoint.PSObject.Properties.Name)
83
+ if ($checkpointProps -notcontains 'epic_mode' -or -not [bool]$checkpoint.epic_mode) {
84
+ return $null
85
+ }
86
+
87
+ $integrationBranch = $null
88
+ if ($checkpointProps -contains 'epic_context' -and $null -ne $checkpoint.epic_context) {
89
+ $epicContextProps = @($checkpoint.epic_context.PSObject.Properties.Name)
90
+ if ($epicContextProps -contains 'integration_branch') {
91
+ $integrationBranch = [string]$checkpoint.epic_context.integration_branch
92
+ }
93
+ }
94
+
95
+ if ([string]::IsNullOrWhiteSpace($integrationBranch)) {
96
+ return "EPIC_BASE_BRANCH_MISMATCH: checkpoint has epic_mode == true but no ``epic_context.integration_branch`` is recorded; ``gh pr create`` cannot be verified against the required ``--base`` value."
97
+ }
98
+
99
+ if ($CommandText -cnotmatch [regex]::Escape("--base $integrationBranch")) {
100
+ return "EPIC_BASE_BRANCH_MISMATCH: ``gh pr create`` must pass ``--base $integrationBranch`` (``epic_context.integration_branch``) under ``epic_mode``; the command does not carry a matching ``--base`` argument."
101
+ }
102
+
103
+ return $null
104
+ }