@danmoisan/drm-copilot-mcp 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/mcp-server.js +335 -24
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +163 -18
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +477 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +120 -12
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +11 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +1 -0
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +131 -2
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +37 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +136 -4
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +18 -9
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +8 -1
- package/resources/claude-customizations/.claude/skills/pr-context-artifacts/SKILL.md +22 -0
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +10 -0
- package/resources/claude-customizations/config/orchestration-routing.json +1 -0
- package/resources/claude-customizations/pack-manifests/core.json +1 -0
- package/resources/codex-and-agents-customizations/.agents/skills/codex-model-routing/SKILL.md +10 -0
- package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +22 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c1.toml +22 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c2.toml +22 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c3-elevated.toml +22 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c3.toml +22 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward-c4.toml +22 -0
- package/resources/codex-and-agents-customizations/.codex/agents/commit-steward.toml +2 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +7 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +7 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +7 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +7 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +7 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +7 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +477 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +125 -12
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +8 -1
- package/resources/config/orchestration-routing.json +1 -0
- package/resources/customizations/.github/skills/pr-context-artifacts/SKILL.md +22 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +10 -2
package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1
CHANGED
|
@@ -4,14 +4,51 @@
|
|
|
4
4
|
|
|
5
5
|
.DESCRIPTION
|
|
6
6
|
Invoked by the Claude Code PreToolUse hook on the "Bash" matcher before any Bash
|
|
7
|
-
command runs. Regex-matches git worktree remove against the envelope's
|
|
8
|
-
extracts the target worktree path argument,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
command runs. Regex-matches git worktree remove against the envelope's
|
|
8
|
+
tool_input.command, extracts the target worktree path argument, and allows the
|
|
9
|
+
removal only when one of two checkpoint-only conditions holds. The branches are
|
|
10
|
+
evaluated in this order and are ORed, not ANDed: the first that authorizes wins and
|
|
11
|
+
the second is not consulted.
|
|
12
|
+
|
|
13
|
+
1. Epic path: artifacts/orchestration/epic-orchestrator-state.json carries a
|
|
14
|
+
features[] record whose worktree_path matches the removal target and whose
|
|
15
|
+
merge_status is merged or worktree_removed.
|
|
16
|
+
2. Parallel path: artifacts/orchestration/parallel-orchestrator-state.json has
|
|
17
|
+
route_id == "parallel" and carries an items[] entry whose worktree_path matches
|
|
18
|
+
the removal target and whose merge_status is merged or worktree_removed.
|
|
19
|
+
|
|
20
|
+
Otherwise the command is denied with reason EPIC_WORKTREE_REMOVAL_BLOCKED. The gate
|
|
21
|
+
is fail-closed in every failure mode: neither checkpoint present, either checkpoint
|
|
22
|
+
unparseable, route_id absent or not "parallel", no matching worktree_path, a matched
|
|
23
|
+
record whose merge_status is not in the allowed set, or a matched record carrying no
|
|
24
|
+
merge_status key. The cascade is a disjunction of two positive predicates; no
|
|
25
|
+
negative path returns an allow. An envelope-level anomaly is checked first and denies
|
|
26
|
+
before either checkpoint is read.
|
|
27
|
+
|
|
28
|
+
Both branches key on the worktree PATH because the command names a path, and both
|
|
29
|
+
normalize separators and trim a trailing slash on each side of the comparison, so
|
|
30
|
+
Windows- and POSIX-style paths compare equal. Path is also why the two branches are
|
|
31
|
+
mutually exclusive in practice: an epic run and a parallel run allocate worktrees
|
|
32
|
+
under distinct per-run, per-item paths, so a path recorded in one checkpoint is not a
|
|
33
|
+
path recorded in the other, and adding branch 2 cannot widen what branch 1 authorizes.
|
|
34
|
+
The authorization is a property of the path rather than of the caller, and the safety
|
|
35
|
+
property this gate protects - do not destroy unmerged work - is likewise a property of
|
|
36
|
+
the path's recorded merge state.
|
|
37
|
+
|
|
38
|
+
Accepted residual: artifacts/ is gitignored, so the parallel checkpoint persists after
|
|
39
|
+
a run ends and a stale document remains readable here. For a stale document to
|
|
40
|
+
authorize a removal it should not, a worktree would have to exist at a path
|
|
41
|
+
byte-identical, after normalization, to one it records with merge_status merged or
|
|
42
|
+
worktree_removed. Worktree paths carry a session or timestamp component, so a
|
|
43
|
+
collision is implausible, and where the recorded status is worktree_removed the path
|
|
44
|
+
was already deleted. This is a documented accepted trade, not an unexamined gap; the
|
|
45
|
+
route_id check does not reduce it, because a stale parallel checkpoint legitimately
|
|
46
|
+
declares that route.
|
|
47
|
+
|
|
48
|
+
The sibling gate enforce-parallel-worktree-removal-gate.ps1 fires on the same command
|
|
49
|
+
and owns its own reason prefix. PreToolUse denials are conjunctive, so both gates must
|
|
50
|
+
allow for a removal to proceed; this gate keeps the EPIC_WORKTREE_REMOVAL_BLOCKED
|
|
51
|
+
prefix for both of its branches so transcript attribution stays unambiguous.
|
|
15
52
|
|
|
16
53
|
.NOTES
|
|
17
54
|
Compatible with PowerShell 7+. No external module dependencies. Filesystem reads go
|
|
@@ -24,6 +61,7 @@ param()
|
|
|
24
61
|
|
|
25
62
|
Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force
|
|
26
63
|
$script:EpicCheckpointPath = 'artifacts/orchestration/epic-orchestrator-state.json'
|
|
64
|
+
$script:ParallelCheckpointPath = 'artifacts/orchestration/parallel-orchestrator-state.json'
|
|
27
65
|
$script:AllowedMergeStatuses = @('merged', 'worktree_removed')
|
|
28
66
|
|
|
29
67
|
function Get-EpicWorktreeGateCheckpointContent {
|
|
@@ -44,6 +82,52 @@ function Get-EpicWorktreeGateCheckpointContent {
|
|
|
44
82
|
return (Get-Content -LiteralPath $script:EpicCheckpointPath -Raw)
|
|
45
83
|
}
|
|
46
84
|
|
|
85
|
+
function Get-EpicWorktreeGateParallelCheckpointContent {
|
|
86
|
+
<#
|
|
87
|
+
.SYNOPSIS
|
|
88
|
+
Read the raw JSON text of the parallel-orchestrator checkpoint. Tests mock
|
|
89
|
+
this function (read seam).
|
|
90
|
+
.OUTPUTS
|
|
91
|
+
System.String or $null
|
|
92
|
+
#>
|
|
93
|
+
[CmdletBinding()]
|
|
94
|
+
[OutputType([string])]
|
|
95
|
+
param()
|
|
96
|
+
|
|
97
|
+
if (-not (Test-Path -LiteralPath $script:ParallelCheckpointPath -PathType Leaf)) {
|
|
98
|
+
return $null
|
|
99
|
+
}
|
|
100
|
+
return (Get-Content -LiteralPath $script:ParallelCheckpointPath -Raw)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function ConvertFrom-EpicWorktreeGateJson {
|
|
104
|
+
<#
|
|
105
|
+
.SYNOPSIS
|
|
106
|
+
Parse checkpoint JSON text, returning $null on unreadable/invalid content.
|
|
107
|
+
.DESCRIPTION
|
|
108
|
+
Shared by both authorization branches so the two checkpoints are parsed by
|
|
109
|
+
one implementation rather than by duplicated inline logic.
|
|
110
|
+
.PARAMETER Raw
|
|
111
|
+
Raw checkpoint text, or $null when the file does not exist.
|
|
112
|
+
.OUTPUTS
|
|
113
|
+
System.Object or $null
|
|
114
|
+
#>
|
|
115
|
+
[CmdletBinding()]
|
|
116
|
+
param(
|
|
117
|
+
[AllowNull()]
|
|
118
|
+
[string] $Raw
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if ([string]::IsNullOrWhiteSpace($Raw)) {
|
|
122
|
+
return $null
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
return ($Raw | ConvertFrom-Json -ErrorAction Stop)
|
|
126
|
+
} catch {
|
|
127
|
+
return $null
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
47
131
|
function Get-EpicWorktreeRemovalCommandPath {
|
|
48
132
|
<#
|
|
49
133
|
.SYNOPSIS
|
|
@@ -138,6 +222,70 @@ function Test-EpicWorktreeRemovalAllowed {
|
|
|
138
222
|
return $script:AllowedMergeStatuses -contains ([string]$FeatureRecord.merge_status)
|
|
139
223
|
}
|
|
140
224
|
|
|
225
|
+
function Test-ParallelCheckpointAllowsWorktreeRemoval {
|
|
226
|
+
<#
|
|
227
|
+
.SYNOPSIS
|
|
228
|
+
Decision logic for the parallel-orchestrator checkpoint path (branch 2).
|
|
229
|
+
.DESCRIPTION
|
|
230
|
+
Allows only when the checkpoint declares the parallel route identity and
|
|
231
|
+
carries an items[] entry whose worktree_path matches the removal target and
|
|
232
|
+
whose merge_status is in the allowed set. Every other shape returns $false,
|
|
233
|
+
so the branch is a positive predicate with no negative path to an allow.
|
|
234
|
+
.PARAMETER Checkpoint
|
|
235
|
+
Parsed parallel-orchestrator checkpoint, or $null when absent/unreadable.
|
|
236
|
+
.PARAMETER WorktreePath
|
|
237
|
+
The target worktree path extracted from the command text.
|
|
238
|
+
.OUTPUTS
|
|
239
|
+
System.Boolean
|
|
240
|
+
#>
|
|
241
|
+
[CmdletBinding()]
|
|
242
|
+
[OutputType([bool])]
|
|
243
|
+
param(
|
|
244
|
+
[AllowNull()]
|
|
245
|
+
$Checkpoint,
|
|
246
|
+
|
|
247
|
+
[AllowNull()]
|
|
248
|
+
[string] $WorktreePath
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if ($null -eq $Checkpoint -or [string]::IsNullOrWhiteSpace($WorktreePath)) {
|
|
252
|
+
return $false
|
|
253
|
+
}
|
|
254
|
+
$props = @($Checkpoint.PSObject.Properties.Name)
|
|
255
|
+
# Route identity is orchestrator invariant 2, so a document at the parallel path
|
|
256
|
+
# that does not declare it is malformed by the rule's own definition and inert here.
|
|
257
|
+
if ($props -notcontains 'route_id' -or ([string]$Checkpoint.route_id) -ne 'parallel') {
|
|
258
|
+
return $false
|
|
259
|
+
}
|
|
260
|
+
if ($props -notcontains 'items' -or $null -eq $Checkpoint.items) {
|
|
261
|
+
return $false
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
$normalizedTarget = ($WorktreePath -replace '\\', '/').TrimEnd('/')
|
|
265
|
+
|
|
266
|
+
# Scan every recorded item for a worktree_path that matches the removal target;
|
|
267
|
+
# path separators are normalized exactly as the epic branch normalizes them.
|
|
268
|
+
foreach ($item in @($Checkpoint.items)) {
|
|
269
|
+
if ($null -eq $item) {
|
|
270
|
+
continue
|
|
271
|
+
}
|
|
272
|
+
$itemProps = @($item.PSObject.Properties.Name)
|
|
273
|
+
if ($itemProps -notcontains 'worktree_path') {
|
|
274
|
+
continue
|
|
275
|
+
}
|
|
276
|
+
$normalizedItemPath = (([string]$item.worktree_path) -replace '\\', '/').TrimEnd('/')
|
|
277
|
+
if ($normalizedItemPath -ne $normalizedTarget) {
|
|
278
|
+
continue
|
|
279
|
+
}
|
|
280
|
+
if ($itemProps -notcontains 'merge_status') {
|
|
281
|
+
return $false
|
|
282
|
+
}
|
|
283
|
+
return $script:AllowedMergeStatuses -contains ([string]$item.merge_status)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return $false
|
|
287
|
+
}
|
|
288
|
+
|
|
141
289
|
function Get-EpicWorktreeGateAllowDecision {
|
|
142
290
|
[CmdletBinding()]
|
|
143
291
|
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
@@ -202,22 +350,19 @@ function Invoke-EpicWorktreeRemovalGateDecision {
|
|
|
202
350
|
|
|
203
351
|
$worktreePath = Get-EpicWorktreeRemovalCommandPath -CommandText $commandText
|
|
204
352
|
|
|
205
|
-
$
|
|
206
|
-
$checkpoint = $null
|
|
207
|
-
if (-not [string]::IsNullOrWhiteSpace($checkpointRaw)) {
|
|
208
|
-
try {
|
|
209
|
-
$checkpoint = $checkpointRaw | ConvertFrom-Json -ErrorAction Stop
|
|
210
|
-
} catch {
|
|
211
|
-
$checkpoint = $null
|
|
212
|
-
}
|
|
213
|
-
}
|
|
353
|
+
$checkpoint = ConvertFrom-EpicWorktreeGateJson -Raw (Get-EpicWorktreeGateCheckpointContent)
|
|
214
354
|
|
|
215
355
|
$featureRecord = Find-EpicWorktreeFeatureRecord -Checkpoint $checkpoint -WorktreePath $worktreePath
|
|
216
356
|
if (Test-EpicWorktreeRemovalAllowed -FeatureRecord $featureRecord) {
|
|
217
357
|
return Get-EpicWorktreeGateAllowDecision
|
|
218
358
|
}
|
|
219
359
|
|
|
220
|
-
|
|
360
|
+
$parallelCheckpoint = ConvertFrom-EpicWorktreeGateJson -Raw (Get-EpicWorktreeGateParallelCheckpointContent)
|
|
361
|
+
if (Test-ParallelCheckpointAllowsWorktreeRemoval -Checkpoint $parallelCheckpoint -WorktreePath $worktreePath) {
|
|
362
|
+
return Get-EpicWorktreeGateAllowDecision
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return Get-EpicWorktreeGateBlockDecision -Reason "EPIC_WORKTREE_REMOVAL_BLOCKED: git worktree remove for '$worktreePath' requires either an epic checkpoint features[] record with merge_status in {merged, worktree_removed}, or a parallel-orchestrator checkpoint with route_id == ""parallel"" whose matching items[] record (matched by worktree_path) has merge_status in {merged, worktree_removed}. No checkpoint authorized this removal."
|
|
221
366
|
}
|
|
222
367
|
|
|
223
368
|
function Invoke-EpicWorktreeRemovalGateEntryPoint {
|