@danmoisan/drm-copilot-mcp 1.0.21 → 1.0.23

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 (43) hide show
  1. package/out/mcp-server.js +1730 -139
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +5 -1
  4. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +48 -2
  5. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_no_sendmessage_tool.md +35 -0
  6. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_worktree_isolation_branches_from_main.md +45 -0
  7. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +257 -0
  8. package/resources/claude-customizations/.claude/agents/parallel-planner.md +183 -0
  9. package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +23 -11
  10. package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +259 -0
  11. package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +499 -0
  12. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate-helpers.ps1 +302 -0
  13. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +359 -0
  14. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +244 -0
  15. package/resources/claude-customizations/.claude/lib/bash/compute-cohorts.sh +143 -0
  16. package/resources/claude-customizations/.claude/lib/bash/compute-concurrency-batches.sh +122 -0
  17. package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +330 -0
  18. package/resources/claude-customizations/.claude/lib/bash/parallel-common.sh +238 -0
  19. package/resources/claude-customizations/.claude/lib/bash/parallel-items-validate.sh +244 -0
  20. package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +187 -0
  21. package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-emit.sh +340 -0
  22. package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-scan.sh +335 -0
  23. package/resources/claude-customizations/.claude/lib/bash/validate-parallel-manifest.sh +134 -0
  24. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +379 -0
  25. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +491 -0
  26. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +490 -0
  27. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +429 -0
  28. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +366 -0
  29. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +184 -0
  30. package/resources/claude-customizations/.claude/rules/shell.md +7 -2
  31. package/resources/claude-customizations/.claude/settings.json +28 -0
  32. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +152 -0
  33. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +93 -0
  34. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +971 -0
  35. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +461 -0
  36. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +176 -0
  37. package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +56 -0
  38. package/resources/claude-customizations/config/blast-radius.json +16 -0
  39. package/resources/claude-customizations/config/orchestration-routing.json +355 -0
  40. package/resources/claude-customizations/pack-manifests/core.json +32 -1
  41. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  42. package/resources/config/orchestration-routing.json +22 -0
  43. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +29 -0
@@ -1,12 +1,14 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- Pre-tool-use hook that blocks epic-planner and epic-orchestrator delegations
4
- originating from an orchestrator agent.
3
+ Pre-tool-use hook that blocks epic-planner, epic-orchestrator,
4
+ parallel-planner, and parallel-orchestrator delegations originating from an
5
+ orchestrator agent.
5
6
 
6
7
  .DESCRIPTION
7
8
  Invoked by the Claude Code PreToolUse hook on the "Agent" matcher before any
8
9
  Agent (Task) call runs. Activates only when the delegation target
9
- subagent_type is 'epic-planner' or 'epic-orchestrator'.
10
+ subagent_type is 'epic-planner', 'epic-orchestrator', 'parallel-planner',
11
+ or 'parallel-orchestrator'.
10
12
 
11
13
  Caller identity resolution:
12
14
  - The full PreToolUse payload (CLAUDE_HOOK_INPUT) carries a top-level
@@ -17,13 +19,15 @@
17
19
 
18
20
  Decision procedure:
19
21
  1. Resolve the target subagent_type from CLAUDE_TOOL_INPUT, falling back
20
- to the payload's tool_input object. A non-epic target allows.
22
+ to the payload's tool_input object. A non-gated target allows.
21
23
  2. Resolve the calling agent_type from the payload. An absent or empty
22
24
  agent_type indicates a main-thread invocation, which allows.
23
- 3. Deny with reason EPIC_INVOCATION_ORIGIN_BLOCKED when the calling
24
- agent_type is exactly 'orchestrator'. Both epic agents delegate to
25
- Agent(orchestrator); an orchestrator-originated invocation would nest
26
- orchestrator inside its own delegation chain.
25
+ 3. Deny when the calling agent_type is exactly 'orchestrator', with the
26
+ reason variant selected by target: EPIC_INVOCATION_ORIGIN_BLOCKED for
27
+ an epic target, PARALLEL_INVOCATION_ORIGIN_BLOCKED for a parallel
28
+ target. All four gated agents delegate to Agent(orchestrator); an
29
+ orchestrator-originated invocation would nest orchestrator inside its
30
+ own delegation chain.
27
31
 
28
32
  .NOTES
29
33
  Compatible with PowerShell 7+. No external module dependencies. Read-only
@@ -33,7 +37,8 @@
33
37
  [CmdletBinding()]
34
38
  param()
35
39
 
36
- $script:GatedSubagentTypes = @('epic-planner', 'epic-orchestrator')
40
+ $script:GatedSubagentTypes = @('epic-planner', 'epic-orchestrator', 'parallel-planner', 'parallel-orchestrator')
41
+ $script:ParallelSubagentTypes = @('parallel-planner', 'parallel-orchestrator')
37
42
  $script:ProhibitedCallerAgentType = 'orchestrator'
38
43
 
39
44
  function Get-EpicInvocationOriginAllowDecision {
@@ -194,7 +199,7 @@ function Invoke-EpicInvocationOriginDecision {
194
199
  [string] $ToolInputRaw
195
200
  )
196
201
 
197
- # The tool input identifies the delegation target; a non-epic target is
202
+ # The tool input identifies the delegation target; a non-gated target is
198
203
  # outside this hook's scope, so the hook input is not parsed for it.
199
204
  $toolInput = ConvertFrom-EpicInvocationOriginPayload -RawPayload $ToolInputRaw -PayloadName 'CLAUDE_TOOL_INPUT'
200
205
  $hookInputParsed = $false
@@ -218,13 +223,20 @@ function Invoke-EpicInvocationOriginDecision {
218
223
  }
219
224
 
220
225
  # An absent agent_type marks a main-thread invocation, which is the
221
- # intended entry point for both epic agents; only an orchestrator-context
226
+ # intended entry point for every gated agent; only an orchestrator-context
222
227
  # invocation is prohibited.
223
228
  $caller = Get-EpicInvocationOriginCallerAgentType -HookInput $hookInput
224
229
  if ($caller -ne $script:ProhibitedCallerAgentType) {
225
230
  return Get-EpicInvocationOriginAllowDecision
226
231
  }
227
232
 
233
+ # The parallel family carries its own reason variant because the epic reason
234
+ # names the two epic agents literally; the deny prose is selected by target.
235
+ if ($script:ParallelSubagentTypes -contains $target) {
236
+ $parallelReason = "PARALLEL_INVOCATION_ORIGIN_BLOCKED: Agent($target) must not be invoked from an orchestrator agent. Both parallel-planner and parallel-orchestrator delegate to Agent(orchestrator), so an orchestrator-originated invocation would nest orchestrator inside its own delegation chain. Invoke $target from the main session instead."
237
+ return Get-EpicInvocationOriginBlockDecision -Reason $parallelReason
238
+ }
239
+
228
240
  $reason = "EPIC_INVOCATION_ORIGIN_BLOCKED: Agent($target) must not be invoked from an orchestrator agent. Both epic-planner and epic-orchestrator delegate to Agent(orchestrator), so an orchestrator-originated invocation would nest orchestrator inside its own delegation chain. Invoke $target from the main session instead."
229
241
  return Get-EpicInvocationOriginBlockDecision -Reason $reason
230
242
  }
@@ -0,0 +1,259 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Pre-tool-use hook that gates the destructive parallel abandon disposition behind an
4
+ explicit confirmation marker.
5
+
6
+ .DESCRIPTION
7
+ Invoked by the Claude Code PreToolUse hook on the "Bash" matcher before any Bash
8
+ command runs. Reads CLAUDE_TOOL_INPUT, extracts the command text, and matches it
9
+ against the two tokens declared at the top of this file: the abandon disposition
10
+ token and the confirmation marker. A command carrying the abandon disposition token
11
+ without the confirmation marker in the SAME command is denied with reason prefix
12
+ PARALLEL_ABANDON_BLOCKED. A command carrying both is allowed. A command carrying no
13
+ abandon disposition token is out of scope and is allowed unchanged.
14
+
15
+ The gate exists because the abandon disposition of /parallel-remove closes a pull
16
+ request and removes a worktree. Both side effects are irreversible from the run's
17
+ point of view, so the destructive path must be confirmed deliberately rather than
18
+ reached by a command that merely looked like a removal.
19
+
20
+ .NOTES
21
+ Compatible with PowerShell 7+. No external module dependencies. Tool-input retrieval
22
+ goes through an injectable wrapper function so tests can mock the boundary with
23
+ literal JSON without writing temporary files, following the read-seam pattern of
24
+ .claude/hooks/enforce-epic-worktree-removal-gate.ps1.
25
+
26
+ The two token values are declared ONCE EACH below and every match in this file reads
27
+ those variables rather than repeating a literal. The producer side of the same pair is
28
+ scripts/dev_tools/parallel_mutation_abandon_cli.py, and
29
+ tests/scripts/dev_tools/test_parallel_abandon_token_seam.py parses both sides at run
30
+ time so a rename on one side without the other fails.
31
+ #>
32
+ [CmdletBinding()]
33
+ param()
34
+
35
+ # The two tokens this gate matches on. These are the ONLY places either token literal
36
+ # appears in this file; the seam test extracts the consumer-side values from exactly
37
+ # these two named assignments.
38
+ $script:AbandonDispositionToken = '--disposition abandon'
39
+ $script:AbandonConfirmToken = '--confirm-abandon'
40
+
41
+ # Literal prefix on the deny reason, so the reason code is greppable in transcripts.
42
+ $script:AbandonBlockedReasonCode = 'PARALLEL_ABANDON_BLOCKED'
43
+
44
+ function Get-ParallelAbandonGateToolInput {
45
+ <#
46
+ .SYNOPSIS
47
+ Read the raw JSON tool payload supplied by Claude Code. Tests mock this
48
+ function (read seam).
49
+ .OUTPUTS
50
+ System.String or $null
51
+ #>
52
+ [CmdletBinding()]
53
+ [OutputType([string])]
54
+ param()
55
+
56
+ return $env:CLAUDE_TOOL_INPUT
57
+ }
58
+
59
+ function Get-ParallelAbandonNormalizedCommand {
60
+ <#
61
+ .SYNOPSIS
62
+ Collapse whitespace runs in a command so token matching is not defeated by
63
+ extra spacing or a line continuation.
64
+ .PARAMETER CommandText
65
+ The Bash command text under evaluation.
66
+ .OUTPUTS
67
+ System.String
68
+ #>
69
+ [CmdletBinding()]
70
+ [OutputType([string])]
71
+ param(
72
+ [AllowNull()]
73
+ [AllowEmptyString()]
74
+ [string] $CommandText
75
+ )
76
+
77
+ if ([string]::IsNullOrWhiteSpace($CommandText)) {
78
+ return ''
79
+ }
80
+ # A single space between tokens is the shape the declared tokens are written in, so
81
+ # normalizing here lets the tokens stay exactly as the producer declares them.
82
+ return ($CommandText -replace '\s+', ' ').Trim()
83
+ }
84
+
85
+ function Test-ParallelAbandonCommandInScope {
86
+ <#
87
+ .SYNOPSIS
88
+ Report whether a command carries the abandon disposition token at all.
89
+ .PARAMETER NormalizedCommand
90
+ The whitespace-normalized command text.
91
+ .OUTPUTS
92
+ System.Boolean
93
+ #>
94
+ [CmdletBinding()]
95
+ [OutputType([bool])]
96
+ param(
97
+ [AllowNull()]
98
+ [AllowEmptyString()]
99
+ [string] $NormalizedCommand
100
+ )
101
+
102
+ if ([string]::IsNullOrWhiteSpace($NormalizedCommand)) {
103
+ return $false
104
+ }
105
+ return $NormalizedCommand.Contains(
106
+ $script:AbandonDispositionToken,
107
+ [System.StringComparison]::OrdinalIgnoreCase)
108
+ }
109
+
110
+ function Test-ParallelAbandonCommandConfirmed {
111
+ <#
112
+ .SYNOPSIS
113
+ Report whether a command carries the confirmation marker.
114
+ .PARAMETER NormalizedCommand
115
+ The whitespace-normalized command text.
116
+ .OUTPUTS
117
+ System.Boolean
118
+ #>
119
+ [CmdletBinding()]
120
+ [OutputType([bool])]
121
+ param(
122
+ [AllowNull()]
123
+ [AllowEmptyString()]
124
+ [string] $NormalizedCommand
125
+ )
126
+
127
+ if ([string]::IsNullOrWhiteSpace($NormalizedCommand)) {
128
+ return $false
129
+ }
130
+ return $NormalizedCommand.Contains(
131
+ $script:AbandonConfirmToken,
132
+ [System.StringComparison]::OrdinalIgnoreCase)
133
+ }
134
+
135
+ function Get-ParallelAbandonGateAllowDecision {
136
+ <#
137
+ .SYNOPSIS
138
+ Build the allow decision payload.
139
+ .OUTPUTS
140
+ System.Collections.Specialized.OrderedDictionary
141
+ #>
142
+ [CmdletBinding()]
143
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
144
+ param()
145
+
146
+ return [ordered]@{
147
+ hookSpecificOutput = [ordered]@{
148
+ hookEventName = 'PreToolUse'
149
+ permissionDecision = 'allow'
150
+ }
151
+ }
152
+ }
153
+
154
+ function Get-ParallelAbandonGateBlockDecision {
155
+ <#
156
+ .SYNOPSIS
157
+ Build the deny decision payload carrying the supplied reason.
158
+ .PARAMETER Reason
159
+ The deny reason surfaced to the caller.
160
+ .OUTPUTS
161
+ System.Collections.Specialized.OrderedDictionary
162
+ #>
163
+ [CmdletBinding()]
164
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
165
+ param(
166
+ [Parameter(Mandatory)]
167
+ [string] $Reason
168
+ )
169
+
170
+ return [ordered]@{
171
+ hookSpecificOutput = [ordered]@{
172
+ hookEventName = 'PreToolUse'
173
+ permissionDecision = 'deny'
174
+ permissionDecisionReason = $Reason
175
+ }
176
+ }
177
+ }
178
+
179
+ function Get-ParallelAbandonGateBlockReason {
180
+ <#
181
+ .SYNOPSIS
182
+ Build the deny reason text from the two declared tokens.
183
+ .OUTPUTS
184
+ System.String
185
+ #>
186
+ [CmdletBinding()]
187
+ [OutputType([string])]
188
+ param()
189
+
190
+ return @(
191
+ "$($script:AbandonBlockedReasonCode): this command carries"
192
+ "'$($script:AbandonDispositionToken)' without the explicit"
193
+ "'$($script:AbandonConfirmToken)' confirmation marker in the same command."
194
+ 'The abandon disposition closes the item pull request and removes its worktree,'
195
+ 'so it must be confirmed deliberately. Add the confirmation marker to the same'
196
+ 'command, or use the detach disposition instead. Do not reformulate the command'
197
+ 'to evade this gate.'
198
+ ) -join ' '
199
+ }
200
+
201
+ function Invoke-ParallelAbandonGateDecision {
202
+ <#
203
+ .SYNOPSIS
204
+ Parses CLAUDE_TOOL_INPUT and returns an allow-or-block decision.
205
+ .PARAMETER ToolInputRaw
206
+ The raw JSON tool payload supplied by Claude Code.
207
+ .OUTPUTS
208
+ System.Collections.Specialized.OrderedDictionary
209
+ #>
210
+ [CmdletBinding()]
211
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
212
+ param(
213
+ [AllowNull()]
214
+ [AllowEmptyString()]
215
+ [string] $ToolInputRaw
216
+ )
217
+
218
+ # An absent payload carries no command to gate, so there is nothing in scope. This is
219
+ # allow rather than deny because the gate constrains one specific destructive command
220
+ # shape and must not become a blanket Bash block.
221
+ if (-not $ToolInputRaw) {
222
+ return Get-ParallelAbandonGateAllowDecision
223
+ }
224
+
225
+ try {
226
+ $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
227
+ } catch {
228
+ throw "enforce-parallel-abandon-gate hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
229
+ }
230
+
231
+ $normalizedCommand = Get-ParallelAbandonNormalizedCommand -CommandText ([string]$toolInput.command)
232
+ if (-not (Test-ParallelAbandonCommandInScope -NormalizedCommand $normalizedCommand)) {
233
+ return Get-ParallelAbandonGateAllowDecision
234
+ }
235
+
236
+ # In scope: the command asks for the destructive disposition, so the confirmation
237
+ # marker decides. Its presence is the caller's explicit acknowledgement.
238
+ if (Test-ParallelAbandonCommandConfirmed -NormalizedCommand $normalizedCommand) {
239
+ return Get-ParallelAbandonGateAllowDecision
240
+ }
241
+
242
+ return Get-ParallelAbandonGateBlockDecision -Reason (Get-ParallelAbandonGateBlockReason)
243
+ }
244
+
245
+ # Guard allows dot-sourcing in tests without executing the entrypoint.
246
+ if ($MyInvocation.InvocationName -eq '.') {
247
+ return
248
+ }
249
+
250
+ try {
251
+ $decision = Invoke-ParallelAbandonGateDecision -ToolInputRaw (Get-ParallelAbandonGateToolInput)
252
+ } catch {
253
+ Write-Error $_
254
+ exit 1
255
+ }
256
+
257
+ $decision | ConvertTo-Json -Compress -Depth 5 | Write-Output
258
+
259
+ exit 0