@danmoisan/drm-copilot-mcp 0.0.1 → 0.0.5

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 (156) hide show
  1. package/out/mcp-server.js +5 -1
  2. package/package.json +21 -5
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +15 -3
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_branch_base_check_unmerged_pr_deps.md +16 -0
  5. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_every_change_through_lifecycle.md +15 -0
  6. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_policy_compliance_not_optional.md +18 -0
  7. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_potential_to_issue_creates_github_issue.md +13 -0
  8. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_remediation_plan_em_dash_required.md +13 -0
  9. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_small_bug_uses_minor_audit.md +13 -0
  10. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +13 -0
  11. package/resources/claude-customizations/.claude/agents/atomic-executor.md +7 -7
  12. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +4 -5
  13. package/resources/claude-customizations/.claude/agents/feature-review.md +7 -3
  14. package/resources/claude-customizations/.claude/agents/orchestrator.md +16 -1
  15. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +245 -0
  17. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +273 -0
  18. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +148 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +190 -0
  20. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +216 -0
  21. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +84 -15
  22. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +1 -1
  23. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +75 -5
  24. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +93 -0
  25. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +68 -0
  26. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +46 -0
  27. package/resources/claude-customizations/.claude/rules/benchmark-baselines.md +35 -0
  28. package/resources/claude-customizations/.claude/rules/ci-workflows.md +36 -0
  29. package/resources/claude-customizations/.claude/rules/csharp.md +62 -16
  30. package/resources/claude-customizations/.claude/rules/general-code-change.md +12 -3
  31. package/resources/claude-customizations/.claude/rules/general-unit-test.md +47 -2
  32. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +39 -0
  33. package/resources/claude-customizations/.claude/rules/powershell.md +5 -5
  34. package/resources/claude-customizations/.claude/rules/python.md +4 -3
  35. package/resources/claude-customizations/.claude/rules/quality-tiers.md +51 -0
  36. package/resources/claude-customizations/.claude/rules/typescript.md +37 -8
  37. package/resources/claude-customizations/.claude/settings.json +37 -12
  38. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -2
  39. package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +25 -10
  40. package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +6 -6
  41. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +8 -8
  42. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +17 -6
  43. package/resources/claude-customizations/.claude/skills/human-exception-runbook/SKILL.md +52 -0
  44. package/resources/claude-customizations/.claude/skills/human-exception-runbook/example.runbook.md +36 -0
  45. package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -4
  46. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +96 -3
  47. package/resources/claude-customizations/.claude/skills/policy-audit-template-usage/SKILL.md +3 -3
  48. package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +4 -4
  49. package/resources/claude-customizations/.claude/skills/pr-base-branch-merge-base/SKILL.md +3 -3
  50. package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +1 -1
  51. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +90 -17
  52. package/resources/claude-dir-customizations/.mcp.json +3 -3
  53. package/resources/codex-and-agents-customizations/.agents/README.md +1 -1
  54. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +0 -5
  55. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +52 -0
  56. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +16 -8
  57. package/resources/codex-and-agents-customizations/.agents/skills/benchmark-baselines/SKILL.md +44 -0
  58. package/resources/codex-and-agents-customizations/.agents/skills/ci-workflows/SKILL.md +45 -0
  59. package/resources/codex-and-agents-customizations/.agents/skills/commit-message/SKILL.md +3 -11
  60. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +1 -5
  61. package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -6
  62. package/resources/codex-and-agents-customizations/.agents/skills/csharp-orchestration-state-machine/SKILL.md +0 -5
  63. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +0 -5
  64. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +0 -5
  65. package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +8 -17
  66. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +13 -14
  67. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +1 -6
  68. package/resources/codex-and-agents-customizations/.agents/skills/fill-feature-docs/SKILL.md +0 -5
  69. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +86 -0
  70. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +111 -0
  71. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/SKILL.md +57 -0
  72. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/example.runbook.md +36 -0
  73. package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +0 -9
  74. package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -9
  75. package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +0 -9
  76. package/resources/codex-and-agents-customizations/.agents/skills/make-skill-template/SKILL.md +0 -5
  77. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +93 -8
  78. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +48 -0
  79. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +61 -2
  80. package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +3 -8
  81. package/resources/codex-and-agents-customizations/.agents/skills/policy-compliance-order/SKILL.md +0 -10
  82. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +4 -8
  83. package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -6
  84. package/resources/codex-and-agents-customizations/.agents/skills/powershell-orchestration-state-machine/SKILL.md +0 -5
  85. package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +3 -9
  86. package/resources/codex-and-agents-customizations/.agents/skills/pr-author/SKILL.md +1 -9
  87. package/resources/codex-and-agents-customizations/.agents/skills/pr-base-branch-merge-base/SKILL.md +4 -9
  88. package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +0 -5
  89. package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +1 -5
  90. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -6
  91. package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +0 -5
  92. package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +2 -6
  93. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +57 -0
  94. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +0 -5
  95. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +91 -72
  96. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/agents/openai.yaml +1 -1
  97. package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +0 -10
  98. package/resources/codex-and-agents-customizations/.agents/skills/review-epic/SKILL.md +0 -5
  99. package/resources/codex-and-agents-customizations/.agents/skills/review-feature/SKILL.md +0 -5
  100. package/resources/codex-and-agents-customizations/.agents/skills/review-staged/SKILL.md +0 -5
  101. package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +2 -6
  102. package/resources/codex-and-agents-customizations/.agents/skills/skill-canonical-location-audit/SKILL.md +0 -5
  103. package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +86 -0
  104. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +297 -0
  105. package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +0 -22
  106. package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +1 -5
  107. package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +2 -6
  108. package/resources/codex-and-agents-customizations/.agents/skills/update-status/SKILL.md +0 -5
  109. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +5 -5
  110. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +91 -63
  111. package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +1 -1
  112. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  113. package/resources/codex-and-agents-customizations/.codex/config.toml +51 -136
  114. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +1 -1
  115. package/resources/codex-and-agents-customizations/.codex/prompts/orchestrate-work.md +4 -3
  116. package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +5 -0
  117. package/resources/codex-and-agents-customizations/.github/workflows/_validate-orchestrator-state.yml +68 -0
  118. package/resources/codex-and-agents-customizations/.github/workflows/validate-orchestrator-state.yml +15 -0
  119. package/resources/config/orchestration-routing.json +84 -0
  120. package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +1 -1
  121. package/resources/customizations/.github/agents/atomic_executor.agent.md +1 -1
  122. package/resources/customizations/.github/agents/atomic_planning.agent.md +10 -10
  123. package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +6 -2
  124. package/resources/customizations/.github/agents/feature-review.agent.md +2 -2
  125. package/resources/customizations/.github/agents/orchestrator.agent.md +6 -2
  126. package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +4 -4
  127. package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +10 -10
  128. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -2
  129. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +2 -2
  130. package/resources/customizations/.github/agents/python-orchestrator.agent.md +6 -2
  131. package/resources/customizations/.github/agents/staged-review.agent.md +1 -1
  132. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +6 -6
  133. package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +1 -1
  134. package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +5 -3
  135. package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +5 -3
  136. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +14 -1
  137. package/resources/customizations/.github/skills/feature-promotion-lifecycle/SKILL.md +11 -7
  138. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +10 -1
  139. package/resources/customizations/.github/skills/pr-base-branch-merge-base/SKILL.md +2 -2
  140. package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +5 -0
  141. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +7 -0
  142. package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +127 -0
  143. package/resources/scripts/dev_tools/_orchestrator_state_routing.py +216 -0
  144. package/resources/scripts/dev_tools/push_down_claude_customizations.py +191 -5
  145. package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +103 -411
  146. package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +107 -0
  147. package/resources/scripts/dev_tools/validate_orchestrator_state.py +428 -0
  148. package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +448 -0
  149. package/resources/templates/push_down_claude_customizations.py +227 -6
  150. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_repo_root_is_source_of_truth.md +0 -11
  151. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_vsce_verify_package_location.md +0 -19
  152. package/resources/claude-customizations/.claude/agent-memory/orchestrator/project_extension_location.md +0 -11
  153. package/resources/claude-customizations/.claude/agent-memory/prd-feature/MEMORY.md +0 -1
  154. package/resources/claude-customizations/.claude/agent-memory/prd-feature/project_push_down_pattern.md +0 -13
  155. package/resources/claude-customizations/.claude/agent-memory/task-researcher/MEMORY.md +0 -3
  156. package/resources/claude-customizations/.claude/agent-memory/task-researcher/project_push_down_claude_dir.md +0 -11
@@ -0,0 +1,273 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Pre-tool-use hook that blocks Write operations on the orchestrator checkpoint
4
+ file when the checkpoint asserts completion without verifiable completion
5
+ evidence.
6
+
7
+ .DESCRIPTION
8
+ Invoked by the Claude Code PreToolUse hook on Write or Edit operations. The
9
+ hook activates only when the target file_path normalizes to
10
+ artifacts/orchestration/orchestrator-state.json.
11
+
12
+ A written checkpoint asserts completion when any of the following hold:
13
+
14
+ next_step == "complete"
15
+ completed_steps contains "S12_complete"
16
+ step8_status, step9_status, or step10_status == "completed"
17
+
18
+ When completion is asserted, the write is blocked unless ALL of the following
19
+ completion evidence is present:
20
+
21
+ - a non-empty issue-num (top-level, falling back to variables.issue-num);
22
+ - a non-empty feature-folder (top-level, falling back to
23
+ variables.feature-folder);
24
+ - a ci_gate object with conclusion == "success" and a non-empty head_sha.
25
+
26
+ The block reason names the specific missing evidence so the caller can
27
+ remediate. When completion is not asserted, the write is allowed
28
+ (backward compatibility).
29
+
30
+ Edit tool calls supply only old_string/new_string (a partial patch) and
31
+ cannot be reliably validated without the full target file content, so they
32
+ are allowed by this hook, matching enforce-checkpoint-monotonic.ps1. For
33
+ Write calls whose content is not valid JSON, the hook allows the operation
34
+ and defers to downstream tools to surface the error.
35
+
36
+ .NOTES
37
+ Compatible with PowerShell 7+. Read-only validation gate.
38
+ #>
39
+ [CmdletBinding()]
40
+ param()
41
+
42
+ function ConvertFrom-CheckpointJson {
43
+ <#
44
+ .SYNOPSIS
45
+ Wrapper around ConvertFrom-Json for the checkpoint content. Mockable.
46
+ #>
47
+ [CmdletBinding()]
48
+ param(
49
+ [Parameter(Mandatory)]
50
+ [string] $Json
51
+ )
52
+
53
+ return $Json | ConvertFrom-Json -ErrorAction Stop
54
+ }
55
+
56
+ function Test-IsCheckpointPath {
57
+ [CmdletBinding()]
58
+ [OutputType([bool])]
59
+ param(
60
+ [Parameter(Mandatory)]
61
+ [string] $NormalizedPath
62
+ )
63
+
64
+ return $NormalizedPath -match '(^|/)artifacts/orchestration/orchestrator-state\.json$'
65
+ }
66
+
67
+ function Get-CheckpointStringValue {
68
+ <#
69
+ .SYNOPSIS
70
+ Returns a trimmed string for a payload property, or an empty string when
71
+ the property is absent or its value is not a non-empty string.
72
+ #>
73
+ [CmdletBinding()]
74
+ [OutputType([string])]
75
+ param(
76
+ [Parameter(Mandatory)]
77
+ [AllowNull()]
78
+ $Payload,
79
+
80
+ [Parameter(Mandatory)]
81
+ [string] $Name
82
+ )
83
+
84
+ if ($null -eq $Payload) {
85
+ return ''
86
+ }
87
+ if (-not ($Payload.PSObject.Properties.Name -contains $Name)) {
88
+ return ''
89
+ }
90
+
91
+ $value = $Payload.$Name
92
+ if ($null -eq $value) {
93
+ return ''
94
+ }
95
+
96
+ return ([string]$value).Trim()
97
+ }
98
+
99
+ function Test-CompletionAsserted {
100
+ <#
101
+ .SYNOPSIS
102
+ Returns $true when the checkpoint payload asserts completion via
103
+ next_step, completed_steps, or step8/9/10 status fields.
104
+ #>
105
+ [CmdletBinding()]
106
+ [OutputType([bool])]
107
+ param(
108
+ [Parameter(Mandatory)]
109
+ [AllowNull()]
110
+ $Payload
111
+ )
112
+
113
+ if ($null -eq $Payload) {
114
+ return $false
115
+ }
116
+
117
+ $nextStep = Get-CheckpointStringValue -Payload $Payload -Name 'next_step'
118
+ if ($nextStep -eq 'complete') {
119
+ return $true
120
+ }
121
+
122
+ if ($Payload.PSObject.Properties.Name -contains 'completed_steps' -and $Payload.completed_steps) {
123
+ foreach ($step in $Payload.completed_steps) {
124
+ if (([string]$step) -eq 'S12_complete') {
125
+ return $true
126
+ }
127
+ }
128
+ }
129
+
130
+ foreach ($statusField in @('step8_status', 'step9_status', 'step10_status')) {
131
+ $status = Get-CheckpointStringValue -Payload $Payload -Name $statusField
132
+ if ($status -eq 'completed') {
133
+ return $true
134
+ }
135
+ }
136
+
137
+ return $false
138
+ }
139
+
140
+ function Get-MissingCompletionEvidence {
141
+ <#
142
+ .SYNOPSIS
143
+ Returns the list of missing completion-evidence descriptions for a
144
+ completion-asserting checkpoint. An empty list means all evidence is
145
+ present.
146
+ #>
147
+ [CmdletBinding()]
148
+ [OutputType([string[]])]
149
+ param(
150
+ [Parameter(Mandatory)]
151
+ [AllowNull()]
152
+ $Payload
153
+ )
154
+
155
+ $missing = @()
156
+
157
+ $issueNum = Get-CheckpointStringValue -Payload $Payload -Name 'issue-num'
158
+ if (-not $issueNum -and $null -ne $Payload -and ($Payload.PSObject.Properties.Name -contains 'variables')) {
159
+ $issueNum = Get-CheckpointStringValue -Payload $Payload.variables -Name 'issue-num'
160
+ }
161
+ if (-not $issueNum) {
162
+ $missing += 'issue-num'
163
+ }
164
+
165
+ $featureFolder = Get-CheckpointStringValue -Payload $Payload -Name 'feature-folder'
166
+ if (-not $featureFolder -and $null -ne $Payload -and ($Payload.PSObject.Properties.Name -contains 'variables')) {
167
+ $featureFolder = Get-CheckpointStringValue -Payload $Payload.variables -Name 'feature-folder'
168
+ }
169
+ if (-not $featureFolder) {
170
+ $missing += 'feature-folder'
171
+ }
172
+
173
+ $ciGate = $null
174
+ if ($null -ne $Payload -and ($Payload.PSObject.Properties.Name -contains 'ci_gate')) {
175
+ $ciGate = $Payload.ci_gate
176
+ }
177
+ if ($null -eq $ciGate -or $ciGate -isnot [System.Management.Automation.PSCustomObject]) {
178
+ $missing += 'ci_gate (object with conclusion == "success" and non-empty head_sha)'
179
+ }
180
+ else {
181
+ $conclusion = Get-CheckpointStringValue -Payload $ciGate -Name 'conclusion'
182
+ if ($conclusion -ne 'success') {
183
+ $missing += 'ci_gate.conclusion == "success"'
184
+ }
185
+ $headSha = Get-CheckpointStringValue -Payload $ciGate -Name 'head_sha'
186
+ if (-not $headSha) {
187
+ $missing += 'ci_gate.head_sha'
188
+ }
189
+ }
190
+
191
+ return [string[]]$missing
192
+ }
193
+
194
+ function Invoke-CompletionConsistencyDecision {
195
+ <#
196
+ .SYNOPSIS
197
+ Parses CLAUDE_TOOL_INPUT and returns an allow-or-block decision based on
198
+ completion-evidence consistency.
199
+ #>
200
+ [CmdletBinding()]
201
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
202
+ param(
203
+ [string] $ToolInputRaw
204
+ )
205
+
206
+ if (-not $ToolInputRaw) {
207
+ return [ordered]@{ decision = 'allow' }
208
+ }
209
+
210
+ try {
211
+ $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
212
+ }
213
+ catch {
214
+ throw "enforce-completion-consistency hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
215
+ }
216
+
217
+ $filePath = $toolInput.file_path
218
+ if (-not $filePath) {
219
+ return [ordered]@{ decision = 'allow' }
220
+ }
221
+
222
+ $normalized = $filePath -replace '\\', '/'
223
+ if (-not (Test-IsCheckpointPath -NormalizedPath $normalized)) {
224
+ return [ordered]@{ decision = 'allow' }
225
+ }
226
+
227
+ # Write tool: validate the content payload. Edit tool: partial new_string is
228
+ # not reliable without the full target file content, so allow.
229
+ $content = $toolInput.content
230
+ if (-not $content) {
231
+ return [ordered]@{ decision = 'allow' }
232
+ }
233
+
234
+ try {
235
+ $payload = ConvertFrom-CheckpointJson -Json $content
236
+ }
237
+ catch {
238
+ # The content itself is not valid JSON. Let downstream tools surface the
239
+ # error rather than blocking with a misleading reason here.
240
+ return [ordered]@{ decision = 'allow' }
241
+ }
242
+
243
+ if (-not (Test-CompletionAsserted -Payload $payload)) {
244
+ return [ordered]@{ decision = 'allow' }
245
+ }
246
+
247
+ $missing = Get-MissingCompletionEvidence -Payload $payload
248
+ if ($missing.Count -eq 0) {
249
+ return [ordered]@{ decision = 'allow' }
250
+ }
251
+
252
+ return [ordered]@{
253
+ decision = 'block'
254
+ reason = "COMPLETION_CONSISTENCY_BLOCKED: the checkpoint asserts completion but is missing required completion evidence: $($missing -join ', '). A completion-asserting checkpoint must include a non-empty issue-num, a non-empty feature-folder, and a ci_gate object with conclusion == 'success' and a non-empty head_sha. Supply the missing evidence or remove the completion assertion."
255
+ }
256
+ }
257
+
258
+ # Guard allows dot-sourcing in tests without executing the entrypoint.
259
+ if ($MyInvocation.InvocationName -eq '.') {
260
+ return
261
+ }
262
+
263
+ try {
264
+ $decision = Invoke-CompletionConsistencyDecision -ToolInputRaw $env:CLAUDE_TOOL_INPUT
265
+ }
266
+ catch {
267
+ Write-Error $_
268
+ exit 1
269
+ }
270
+
271
+ $decision | ConvertTo-Json -Compress | Write-Output
272
+
273
+ exit 0
@@ -0,0 +1,148 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Pre-tool-use hook that blocks writes to a feature folder's plan.md when issue.md,
4
+ spec.md, or user-story.md are not yet present in that same folder.
5
+
6
+ .DESCRIPTION
7
+ Invoked by the Claude Code PreToolUse hook on Write or Edit operations. Reads
8
+ tool input JSON from the CLAUDE_TOOL_INPUT environment variable. When the
9
+ target file_path matches a feature-folder plan.md path under
10
+ docs/features/(active|archive)/<folder>/plan.md, the script verifies that
11
+ each of issue.md, spec.md, and user-story.md exists in the same folder.
12
+
13
+ If any of the three sibling files is missing, the script emits a JSON
14
+ response with decision='block' and exits 0 so Claude Code surfaces the
15
+ reason. All other paths pass through with decision='allow'.
16
+
17
+ Filesystem reads go through Get-FeatureFolderFileExistence so tests can
18
+ inject a fake without touching disk.
19
+
20
+ .NOTES
21
+ Compatible with PowerShell 7+. Read-only validation gate; no state mutation.
22
+ #>
23
+ [CmdletBinding()]
24
+ param()
25
+
26
+ function Get-FeatureFolderFileExistence {
27
+ <#
28
+ .SYNOPSIS
29
+ Wrapper around Test-Path for sibling-file existence checks. Tests mock this.
30
+ .PARAMETER Path
31
+ Absolute or workspace-relative file path to check.
32
+ #>
33
+ [CmdletBinding()]
34
+ [OutputType([bool])]
35
+ param(
36
+ [Parameter(Mandatory)]
37
+ [string] $Path
38
+ )
39
+
40
+ return [bool](Test-Path -LiteralPath $Path -PathType Leaf)
41
+ }
42
+
43
+ function Get-FeatureFolderMissingFile {
44
+ <#
45
+ .SYNOPSIS
46
+ Returns the list of required sibling files missing alongside plan.md.
47
+ .PARAMETER PlanFilePath
48
+ Normalized (forward-slash) path to the plan.md target.
49
+ #>
50
+ [CmdletBinding()]
51
+ [OutputType([string[]])]
52
+ param(
53
+ [Parameter(Mandatory)]
54
+ [string] $PlanFilePath
55
+ )
56
+
57
+ $folder = $PlanFilePath -replace '/plan\.md$', ''
58
+ $required = @('issue.md', 'spec.md', 'user-story.md')
59
+ [System.Collections.Generic.List[string]] $missing = [System.Collections.Generic.List[string]]::new()
60
+
61
+ foreach ($name in $required) {
62
+ $siblingPath = "$folder/$name"
63
+ if (-not (Get-FeatureFolderFileExistence -Path $siblingPath)) {
64
+ $missing.Add($name)
65
+ }
66
+ }
67
+
68
+ return [string[]] $missing.ToArray()
69
+ }
70
+
71
+ function Test-IsFeaturePlanPath {
72
+ <#
73
+ .SYNOPSIS
74
+ Returns $true if the normalized path targets a feature-folder plan.md.
75
+ #>
76
+ [CmdletBinding()]
77
+ [OutputType([bool])]
78
+ param(
79
+ [Parameter(Mandatory)]
80
+ [string] $NormalizedPath
81
+ )
82
+
83
+ return $NormalizedPath -match '(^|/)docs/features/(active|archive)/[^/]+/plan\.md$'
84
+ }
85
+
86
+ function Invoke-FeatureFolderOrderDecision {
87
+ <#
88
+ .SYNOPSIS
89
+ Parses CLAUDE_TOOL_INPUT and produces an allow-or-block decision.
90
+ .PARAMETER ToolInputRaw
91
+ Raw JSON string. Empty/null returns allow.
92
+ #>
93
+ [CmdletBinding()]
94
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
95
+ param(
96
+ [string] $ToolInputRaw
97
+ )
98
+
99
+ if (-not $ToolInputRaw) {
100
+ return [ordered]@{ decision = 'allow' }
101
+ }
102
+
103
+ try {
104
+ $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
105
+ }
106
+ catch {
107
+ throw "enforce-feature-folder-order hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
108
+ }
109
+
110
+ $filePath = $toolInput.file_path
111
+ if (-not $filePath) {
112
+ return [ordered]@{ decision = 'allow' }
113
+ }
114
+
115
+ $normalized = $filePath -replace '\\', '/'
116
+
117
+ if (-not (Test-IsFeaturePlanPath -NormalizedPath $normalized)) {
118
+ return [ordered]@{ decision = 'allow' }
119
+ }
120
+
121
+ $missing = Get-FeatureFolderMissingFile -PlanFilePath $normalized
122
+ if ($missing.Count -eq 0) {
123
+ return [ordered]@{ decision = 'allow' }
124
+ }
125
+
126
+ $list = ($missing -join ', ')
127
+ return [ordered]@{
128
+ decision = 'block'
129
+ reason = "FEATURE_FOLDER_ORDER_BLOCKED: cannot write plan.md before producing prerequisite documents. Missing in feature folder: $list. Invoke the prd-feature subagent to generate the missing file(s) before authoring plan.md."
130
+ }
131
+ }
132
+
133
+ # Guard allows dot-sourcing in tests without executing the entrypoint.
134
+ if ($MyInvocation.InvocationName -eq '.') {
135
+ return
136
+ }
137
+
138
+ try {
139
+ $decision = Invoke-FeatureFolderOrderDecision -ToolInputRaw $env:CLAUDE_TOOL_INPUT
140
+ }
141
+ catch {
142
+ Write-Error $_
143
+ exit 1
144
+ }
145
+
146
+ $decision | ConvertTo-Json -Compress | Write-Output
147
+
148
+ exit 0
@@ -0,0 +1,190 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Pre-tool-use hook that enforces the pr-author skill is used before gh pr create or gh pr edit.
4
+
5
+ .DESCRIPTION
6
+ Invoked by the Claude Code PreToolUse hook before any Bash command runs. Reads
7
+ tool input JSON from the CLAUDE_TOOL_INPUT environment variable, inspects the
8
+ attempted command, and blocks gh pr create / gh pr edit commands that bypass the
9
+ pr-author skill workflow.
10
+
11
+ Required sequence:
12
+ 1. mcp__drm-copilot__collect_pr_context writes artifacts/pr_context.summary.txt
13
+ 2. pr-author skill reads that file and writes artifacts/pr_body_<N>.md
14
+ 3. gh pr create --body-file artifacts/pr_body_<N>.md
15
+ (or gh pr edit --body-file ...)
16
+
17
+ Three block cases:
18
+ Case A - gh pr create with --body (inline, no --body-file): blocked.
19
+ Case B - gh pr create with neither --body nor --body-file: blocked.
20
+ Case C - gh pr create or gh pr edit with --body-file but context artifact absent: blocked.
21
+
22
+ .NOTES
23
+ Compatible with PowerShell 7+. No external module dependencies.
24
+ #>
25
+ [CmdletBinding()]
26
+ param()
27
+
28
+ $script:PrContextArtifactPath = 'artifacts/pr_context.summary.txt'
29
+
30
+ function Get-PrContextArtifactExistence {
31
+ <#
32
+ .SYNOPSIS
33
+ Wrapper around Test-Path for the PR context artifact. Tests mock this function.
34
+ .OUTPUTS
35
+ System.Boolean
36
+ #>
37
+ [CmdletBinding()]
38
+ [OutputType([bool])]
39
+ param()
40
+
41
+ return [bool](Test-Path -LiteralPath $script:PrContextArtifactPath)
42
+ }
43
+
44
+ function Get-PrAuthorBypassReason {
45
+ <#
46
+ .SYNOPSIS
47
+ Inspect the command text and return a block reason string, or $null when the command is allowed.
48
+ .DESCRIPTION
49
+ Returns PR_AUTHOR_SKILL_BLOCKED when gh pr create is run with --body (inline) or with no body
50
+ flag at all. Returns PR_CONTEXT_MISSING when --body-file is present but the context artifact
51
+ does not exist on disk. Returns $null for all allowed patterns.
52
+ .PARAMETER CommandText
53
+ The Bash command text extracted from CLAUDE_TOOL_INPUT.
54
+ .PARAMETER ContextExists
55
+ Whether artifacts/pr_context.summary.txt currently exists on disk.
56
+ .OUTPUTS
57
+ System.String or $null
58
+ #>
59
+ [CmdletBinding()]
60
+ [OutputType([string])]
61
+ param(
62
+ [Parameter(Mandatory)]
63
+ [string] $CommandText,
64
+
65
+ [Parameter(Mandatory)]
66
+ [bool] $ContextExists
67
+ )
68
+
69
+ # Only act on gh pr create or gh pr edit subcommands.
70
+ $isPrCreate = $CommandText -match '(?i)\bgh\s+pr\s+create\b'
71
+ $isPrEdit = $CommandText -match '(?i)\bgh\s+pr\s+edit\b'
72
+
73
+ if (-not $isPrCreate -and -not $isPrEdit) {
74
+ return $null
75
+ }
76
+
77
+ $hasBodyFile = $CommandText -match '(?i)--body-file\b'
78
+ $hasInlineBody = $CommandText -match '(?i)--body(?!-file)\b'
79
+
80
+ if ($isPrCreate) {
81
+ # Case A: gh pr create with inline --body (not --body-file).
82
+ if ($hasInlineBody -and -not $hasBodyFile) {
83
+ return "PR_AUTHOR_SKILL_BLOCKED: ``gh pr create`` must use ``--body-file`` with a file produced by the pr-author skill from ``$script:PrContextArtifactPath``. Run ``mcp__drm-copilot__collect_pr_context`` to generate the context file, apply the pr-author skill to produce ``artifacts/pr_body_<N>.md``, then pass that file via ``--body-file``."
84
+ }
85
+
86
+ # Case B: gh pr create with no body flag at all.
87
+ if (-not $hasInlineBody -and -not $hasBodyFile) {
88
+ return "PR_AUTHOR_SKILL_BLOCKED: New PRs require ``--body-file``. Run ``mcp__drm-copilot__collect_pr_context`` to generate ``$script:PrContextArtifactPath``, apply the pr-author skill to produce ``artifacts/pr_body_<N>.md``, then pass that file via ``--body-file``."
89
+ }
90
+ }
91
+
92
+ if ($isPrEdit) {
93
+ # gh pr edit with no --body or --body-file (e.g., --title, --add-label, --reviewer) is allowed.
94
+ if (-not $hasInlineBody -and -not $hasBodyFile) {
95
+ return $null
96
+ }
97
+ }
98
+
99
+ # Case C: --body-file present but context artifact is absent.
100
+ if ($hasBodyFile -and -not $ContextExists) {
101
+ return "PR_CONTEXT_MISSING: ``$script:PrContextArtifactPath`` is absent. Run ``mcp__drm-copilot__collect_pr_context`` before creating or editing the PR body."
102
+ }
103
+
104
+ return $null
105
+ }
106
+
107
+ function Invoke-PrAuthorSkillDecision {
108
+ <#
109
+ .SYNOPSIS
110
+ Parse CLAUDE_TOOL_INPUT and return an allow-or-block decision.
111
+ .PARAMETER ToolInputRaw
112
+ The raw JSON tool payload supplied by Claude Code.
113
+ .OUTPUTS
114
+ System.Collections.Specialized.OrderedDictionary
115
+ .NOTES
116
+ Missing tool input or missing command text is treated as allow.
117
+ #>
118
+ [CmdletBinding()]
119
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
120
+ param(
121
+ [string] $ToolInputRaw
122
+ )
123
+
124
+ if (-not $ToolInputRaw) {
125
+ return [ordered]@{ decision = 'allow' }
126
+ }
127
+
128
+ try {
129
+ $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
130
+ } catch {
131
+ throw "enforce-pr-author-skill hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
132
+ }
133
+
134
+ $commandText = $toolInput.command
135
+ if (-not $commandText) {
136
+ return [ordered]@{ decision = 'allow' }
137
+ }
138
+
139
+ $contextExists = Get-PrContextArtifactExistence
140
+ $reason = Get-PrAuthorBypassReason -CommandText $commandText -ContextExists $contextExists
141
+
142
+ if ($reason) {
143
+ return [ordered]@{
144
+ decision = 'block'
145
+ reason = $reason
146
+ }
147
+ }
148
+
149
+ return [ordered]@{ decision = 'allow' }
150
+ }
151
+
152
+ function Test-PrAuthorBypassRequired {
153
+ <#
154
+ .SYNOPSIS
155
+ Return $true when a Bash command requires the pr-author skill to run first.
156
+ .PARAMETER CommandText
157
+ The Bash command text extracted from CLAUDE_TOOL_INPUT.
158
+ .PARAMETER ContextExists
159
+ Whether artifacts/pr_context.summary.txt currently exists on disk.
160
+ .OUTPUTS
161
+ System.Boolean
162
+ #>
163
+ [CmdletBinding()]
164
+ [OutputType([bool])]
165
+ param(
166
+ [Parameter(Mandatory)]
167
+ [string] $CommandText,
168
+
169
+ [Parameter(Mandatory)]
170
+ [bool] $ContextExists
171
+ )
172
+
173
+ return ($null -ne (Get-PrAuthorBypassReason -CommandText $CommandText -ContextExists $ContextExists))
174
+ }
175
+
176
+ # Allow dot-sourcing in tests without executing the entrypoint.
177
+ if ($MyInvocation.InvocationName -eq '.') {
178
+ return
179
+ }
180
+
181
+ try {
182
+ $decision = Invoke-PrAuthorSkillDecision -ToolInputRaw $env:CLAUDE_TOOL_INPUT
183
+ } catch {
184
+ Write-Error $_
185
+ exit 1
186
+ }
187
+
188
+ $decision | ConvertTo-Json -Compress | Write-Output
189
+
190
+ exit 0