@danmoisan/drm-copilot-mcp 0.0.1 → 0.0.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.
Files changed (183) hide show
  1. package/out/mcp-server.js +98 -21
  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 +22 -3
  15. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/agents/pr-author.md +78 -0
  17. package/resources/claude-customizations/.claude/agents/task-researcher.md +10 -6
  18. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +303 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +300 -0
  20. package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +40 -14
  21. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +148 -0
  22. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +210 -0
  23. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +333 -0
  24. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +216 -0
  25. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +84 -15
  26. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +1 -1
  27. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +75 -5
  28. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +93 -0
  29. package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +136 -0
  30. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +90 -6
  31. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +46 -0
  32. package/resources/claude-customizations/.claude/rules/benchmark-baselines.md +35 -0
  33. package/resources/claude-customizations/.claude/rules/ci-workflows.md +36 -0
  34. package/resources/claude-customizations/.claude/rules/csharp.md +62 -16
  35. package/resources/claude-customizations/.claude/rules/general-code-change.md +12 -3
  36. package/resources/claude-customizations/.claude/rules/general-unit-test.md +47 -2
  37. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +39 -0
  38. package/resources/claude-customizations/.claude/rules/powershell.md +5 -5
  39. package/resources/claude-customizations/.claude/rules/python.md +4 -3
  40. package/resources/claude-customizations/.claude/rules/quality-tiers.md +51 -0
  41. package/resources/claude-customizations/.claude/rules/typescript.md +37 -8
  42. package/resources/claude-customizations/.claude/settings.json +59 -12
  43. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -2
  44. package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +25 -10
  45. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +0 -1
  46. package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +6 -6
  47. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +8 -8
  48. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +17 -6
  49. package/resources/claude-customizations/.claude/skills/human-exception-runbook/SKILL.md +52 -0
  50. package/resources/claude-customizations/.claude/skills/human-exception-runbook/example.runbook.md +36 -0
  51. package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -4
  52. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +172 -5
  53. package/resources/claude-customizations/.claude/skills/policy-audit-template-usage/SKILL.md +3 -3
  54. package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +4 -4
  55. package/resources/claude-customizations/.claude/skills/pr-base-branch-merge-base/SKILL.md +3 -3
  56. package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +1 -1
  57. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +90 -17
  58. package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +5 -3
  59. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +69 -0
  60. package/resources/claude-customizations/.claude-variants/csharp-legacy/rules/csharp.md +96 -0
  61. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +77 -0
  62. package/resources/claude-customizations/.claude-variants/csharp-legacy/skills/invoke-csharp-engineer/SKILL.md +64 -0
  63. package/resources/claude-customizations/pack-manifests/core.json +65 -0
  64. package/resources/claude-customizations/pack-manifests/csharp-legacy.json +11 -0
  65. package/resources/claude-customizations/pack-manifests/csharp-modern.json +12 -0
  66. package/resources/claude-customizations/pack-manifests/powershell.json +14 -0
  67. package/resources/claude-customizations/pack-manifests/python.json +14 -0
  68. package/resources/claude-customizations/pack-manifests/typescript.json +9 -0
  69. package/resources/claude-dir-customizations/.mcp.json +3 -3
  70. package/resources/codex-and-agents-customizations/.agents/README.md +1 -1
  71. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +0 -5
  72. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +52 -0
  73. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +16 -8
  74. package/resources/codex-and-agents-customizations/.agents/skills/benchmark-baselines/SKILL.md +44 -0
  75. package/resources/codex-and-agents-customizations/.agents/skills/ci-workflows/SKILL.md +45 -0
  76. package/resources/codex-and-agents-customizations/.agents/skills/commit-message/SKILL.md +3 -11
  77. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +1 -5
  78. package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -6
  79. package/resources/codex-and-agents-customizations/.agents/skills/csharp-orchestration-state-machine/SKILL.md +0 -5
  80. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +0 -5
  81. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +0 -5
  82. package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +8 -17
  83. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +41 -25
  84. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +1 -6
  85. package/resources/codex-and-agents-customizations/.agents/skills/fill-feature-docs/SKILL.md +0 -5
  86. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +86 -0
  87. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +111 -0
  88. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/SKILL.md +57 -0
  89. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/example.runbook.md +36 -0
  90. package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +0 -9
  91. package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -9
  92. package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +0 -9
  93. package/resources/codex-and-agents-customizations/.agents/skills/make-skill-template/SKILL.md +0 -5
  94. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +206 -18
  95. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +48 -0
  96. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +94 -10
  97. package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +3 -8
  98. package/resources/codex-and-agents-customizations/.agents/skills/policy-compliance-order/SKILL.md +0 -10
  99. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +4 -8
  100. package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -6
  101. package/resources/codex-and-agents-customizations/.agents/skills/powershell-orchestration-state-machine/SKILL.md +0 -5
  102. package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +3 -9
  103. package/resources/codex-and-agents-customizations/.agents/skills/pr-author/SKILL.md +1 -9
  104. package/resources/codex-and-agents-customizations/.agents/skills/pr-base-branch-merge-base/SKILL.md +4 -9
  105. package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +0 -5
  106. package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +1 -5
  107. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -6
  108. package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +0 -5
  109. package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +2 -6
  110. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +57 -0
  111. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +0 -5
  112. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +96 -72
  113. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/agents/openai.yaml +1 -1
  114. package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +0 -10
  115. package/resources/codex-and-agents-customizations/.agents/skills/review-epic/SKILL.md +0 -5
  116. package/resources/codex-and-agents-customizations/.agents/skills/review-feature/SKILL.md +0 -5
  117. package/resources/codex-and-agents-customizations/.agents/skills/review-staged/SKILL.md +0 -5
  118. package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +2 -6
  119. package/resources/codex-and-agents-customizations/.agents/skills/skill-canonical-location-audit/SKILL.md +0 -5
  120. package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +86 -0
  121. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +297 -0
  122. package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +0 -22
  123. package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +1 -5
  124. package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +2 -6
  125. package/resources/codex-and-agents-customizations/.agents/skills/update-status/SKILL.md +0 -5
  126. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +5 -5
  127. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +91 -63
  128. package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +1 -1
  129. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  130. package/resources/codex-and-agents-customizations/.codex/config.toml +111 -137
  131. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +303 -0
  132. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +300 -0
  133. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +148 -0
  134. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-pr-author-skill.ps1 +336 -0
  135. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +84 -18
  136. package/resources/codex-and-agents-customizations/.codex/prompts/orchestrate-work.md +4 -3
  137. package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +5 -0
  138. package/resources/codex-and-agents-customizations/.github/workflows/_validate-orchestrator-state.yml +68 -0
  139. package/resources/codex-and-agents-customizations/.github/workflows/validate-orchestrator-state.yml +15 -0
  140. package/resources/config/orchestration-routing.json +76 -0
  141. package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +1 -1
  142. package/resources/customizations/.github/agents/atomic_executor.agent.md +1 -1
  143. package/resources/customizations/.github/agents/atomic_planning.agent.md +10 -10
  144. package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +6 -2
  145. package/resources/customizations/.github/agents/feature-review.agent.md +2 -2
  146. package/resources/customizations/.github/agents/orchestrator.agent.md +6 -2
  147. package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +4 -4
  148. package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +10 -10
  149. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -2
  150. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +2 -2
  151. package/resources/customizations/.github/agents/pr-author.agent.md +25 -0
  152. package/resources/customizations/.github/agents/python-orchestrator.agent.md +6 -2
  153. package/resources/customizations/.github/agents/staged-review.agent.md +1 -1
  154. package/resources/customizations/.github/agents/task-researcher.agent.md +4 -4
  155. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +6 -6
  156. package/resources/customizations/.github/prompts/fillout-prd-feature.prompt.md +1 -1
  157. package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +1 -1
  158. package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +5 -3
  159. package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +5 -3
  160. package/resources/customizations/.github/prompts/research-issue.prompt.md +4 -3
  161. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +14 -1
  162. package/resources/customizations/.github/skills/feature-promotion-lifecycle/SKILL.md +11 -7
  163. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +10 -1
  164. package/resources/customizations/.github/skills/pr-base-branch-merge-base/SKILL.md +2 -2
  165. package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +5 -0
  166. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +7 -0
  167. package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +127 -0
  168. package/resources/scripts/dev_tools/_orchestrator_state_routing.py +216 -0
  169. package/resources/scripts/dev_tools/push_down_claude_customizations.py +276 -61
  170. package/resources/scripts/dev_tools/push_down_claude_filesystem.py +472 -0
  171. package/resources/scripts/dev_tools/push_down_claude_pack_selection.py +401 -0
  172. package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +103 -411
  173. package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +107 -0
  174. package/resources/scripts/dev_tools/validate_orchestrator_state.py +505 -0
  175. package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +472 -0
  176. package/resources/templates/push_down_claude_customizations.py +162 -117
  177. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_repo_root_is_source_of_truth.md +0 -11
  178. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_vsce_verify_package_location.md +0 -19
  179. package/resources/claude-customizations/.claude/agent-memory/orchestrator/project_extension_location.md +0 -11
  180. package/resources/claude-customizations/.claude/agent-memory/prd-feature/MEMORY.md +0 -1
  181. package/resources/claude-customizations/.claude/agent-memory/prd-feature/project_push_down_pattern.md +0 -13
  182. package/resources/claude-customizations/.claude/agent-memory/task-researcher/MEMORY.md +0 -3
  183. package/resources/claude-customizations/.claude/agent-memory/task-researcher/project_push_down_claude_dir.md +0 -11
@@ -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,210 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Blocks implementation operations before orchestration readiness exists.
4
+ #>
5
+ [CmdletBinding()]
6
+ param()
7
+
8
+ $script:CheckpointPath = 'artifacts/orchestration/orchestrator-state.json'
9
+ $script:Issue232FeatureFolder = 'docs/features/active/2026-06-24-harden-orchestrate-skill-232'
10
+
11
+ function ConvertFrom-CheckpointJson {
12
+ [CmdletBinding()]
13
+ param([Parameter(Mandatory)][string] $Json)
14
+
15
+ return $Json | ConvertFrom-Json -ErrorAction Stop
16
+ }
17
+
18
+ function Get-StringProperty {
19
+ [CmdletBinding()]
20
+ [OutputType([string])]
21
+ param(
22
+ [Parameter(Mandatory)][AllowNull()] $Value,
23
+ [Parameter(Mandatory)][string] $Name
24
+ )
25
+
26
+ if ($null -eq $Value -or -not ($Value.PSObject.Properties.Name -contains $Name)) {
27
+ return ''
28
+ }
29
+ return ([string]$Value.$Name).Trim()
30
+ }
31
+
32
+ function Test-FeatureDocumentationOrEvidencePath {
33
+ [CmdletBinding()]
34
+ [OutputType([bool])]
35
+ param([Parameter(Mandatory)][string] $NormalizedPath)
36
+
37
+ return $NormalizedPath.StartsWith('docs/features/active/')
38
+ }
39
+
40
+ function Test-ImplementationPath {
41
+ [CmdletBinding()]
42
+ [OutputType([bool])]
43
+ param([Parameter(Mandatory)][string] $NormalizedPath)
44
+
45
+ if (Test-FeatureDocumentationOrEvidencePath -NormalizedPath $NormalizedPath) {
46
+ return $false
47
+ }
48
+ if ($NormalizedPath -eq $script:CheckpointPath) {
49
+ return $false
50
+ }
51
+ return $NormalizedPath -match '\.(py|ps1|psm1|ts|tsx|js|jsx|cs|json|yml|yaml)$'
52
+ }
53
+
54
+ function Test-ImplementationCommand {
55
+ [CmdletBinding()]
56
+ [OutputType([bool])]
57
+ param([Parameter(Mandatory)][string] $Command)
58
+
59
+ $normalizedCommand = $Command.Trim()
60
+ if (-not $normalizedCommand) {
61
+ return $false
62
+ }
63
+
64
+ $implementationCommandPatterns = @(
65
+ '(^|\s)git\s+(add|commit)\b',
66
+ '(^|\s)(poetry\s+run\s+)?(black|ruff|pyright|pytest)\b',
67
+ '(^|\s)npm\s+.*\s+(prettier|lint|typecheck|test:unit)\b',
68
+ '(^|\s)npx\s+(prettier|eslint|tsc|jest)\b',
69
+ '(^|\s)pwsh\s+.*(Invoke-Pester|tests/scripts/)'
70
+ )
71
+
72
+ foreach ($pattern in $implementationCommandPatterns) {
73
+ if ($normalizedCommand -match $pattern) {
74
+ return $true
75
+ }
76
+ }
77
+ return $false
78
+ }
79
+
80
+ function Test-ImplementationDelegation {
81
+ [CmdletBinding()]
82
+ [OutputType([bool])]
83
+ param([Parameter(Mandatory)][AllowNull()] $ToolInput)
84
+
85
+ if ($null -eq $ToolInput) {
86
+ return $false
87
+ }
88
+
89
+ $payloadText = ($ToolInput | ConvertTo-Json -Depth 20 -Compress)
90
+ return $payloadText -match '(python-typed-engineer|powershell-typed-engineer|typescript-engineer|csharp-typed-engineer|atomic-executor|implementation|execute)'
91
+ }
92
+
93
+ function Test-OrchestrationReady {
94
+ [CmdletBinding()]
95
+ [OutputType([bool])]
96
+ param([Parameter(Mandatory)][AllowNull()] $Payload)
97
+
98
+ if ($null -eq $Payload) {
99
+ return $false
100
+ }
101
+ $issueNum = Get-StringProperty -Value $Payload -Name 'issue-num'
102
+ $featureFolder = Get-StringProperty -Value $Payload -Name 'feature-folder'
103
+ $routeId = Get-StringProperty -Value $Payload -Name 'route_id'
104
+ if (-not $routeId) {
105
+ $routeId = Get-StringProperty -Value $Payload -Name 'path_selected'
106
+ }
107
+ $lifecycleReady = $false
108
+ if ($Payload.PSObject.Properties.Name -contains 'lifecycle_ready') {
109
+ $lifecycleReady = [bool]$Payload.lifecycle_ready
110
+ }
111
+
112
+ if (-not $issueNum -or -not $featureFolder -or -not $routeId -or -not $lifecycleReady) {
113
+ return $false
114
+ }
115
+
116
+ if ($issueNum -eq '232' -and $featureFolder -ne $script:Issue232FeatureFolder) {
117
+ return $false
118
+ }
119
+
120
+ return (
121
+ $featureFolder.StartsWith('docs/features/active/') -and
122
+ $routeId -and
123
+ $lifecycleReady
124
+ )
125
+ }
126
+
127
+ function Get-CheckpointContent {
128
+ [CmdletBinding()]
129
+ [OutputType([string])]
130
+ param()
131
+
132
+ if (-not (Test-Path -LiteralPath $script:CheckpointPath)) {
133
+ return ''
134
+ }
135
+ return Get-Content -Raw -LiteralPath $script:CheckpointPath
136
+ }
137
+
138
+ function Invoke-OrchestrationPreimplementationGateDecision {
139
+ [CmdletBinding()]
140
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
141
+ param(
142
+ [string] $ToolInputRaw,
143
+ [string] $CheckpointRaw
144
+ )
145
+
146
+ if (-not $ToolInputRaw) {
147
+ return [ordered]@{ decision = 'allow' }
148
+ }
149
+ try {
150
+ $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
151
+ } catch {
152
+ throw "enforce-orchestration-preimplementation-gate hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
153
+ }
154
+
155
+ $requiresReadyCheckpoint = $false
156
+ $filePath = Get-StringProperty -Value $toolInput -Name 'file_path'
157
+ if ($filePath) {
158
+ $normalized = ([string]$filePath) -replace '\\', '/'
159
+ $requiresReadyCheckpoint = Test-ImplementationPath -NormalizedPath $normalized
160
+ } else {
161
+ $command = Get-StringProperty -Value $toolInput -Name 'command'
162
+ if ($command) {
163
+ $requiresReadyCheckpoint = Test-ImplementationCommand -Command $command
164
+ } else {
165
+ $requiresReadyCheckpoint = Test-ImplementationDelegation -ToolInput $toolInput
166
+ }
167
+ }
168
+
169
+ if (-not $requiresReadyCheckpoint) {
170
+ return [ordered]@{ decision = 'allow' }
171
+ }
172
+
173
+ if (-not $CheckpointRaw) {
174
+ $CheckpointRaw = Get-CheckpointContent
175
+ }
176
+ try {
177
+ $checkpoint = ConvertFrom-CheckpointJson -Json $CheckpointRaw
178
+ } catch {
179
+ $checkpoint = $null
180
+ }
181
+
182
+ if (Test-OrchestrationReady -Payload $checkpoint) {
183
+ return [ordered]@{ decision = 'allow' }
184
+ }
185
+ $issueNum = Get-StringProperty -Value $checkpoint -Name 'issue-num'
186
+ if ($issueNum -eq '232') {
187
+ return [ordered]@{
188
+ decision = 'block'
189
+ reason = 'PREIMPLEMENTATION_GATE_BLOCKED: Issue #232 implementation operations require artifacts/orchestration/orchestrator-state.json to contain route metadata, lifecycle readiness, and checkpoint state before implementation begins.'
190
+ }
191
+ }
192
+ return [ordered]@{
193
+ decision = 'block'
194
+ 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.'
195
+ }
196
+ }
197
+
198
+ if ($MyInvocation.InvocationName -eq '.') {
199
+ return
200
+ }
201
+
202
+ try {
203
+ $decision = Invoke-OrchestrationPreimplementationGateDecision -ToolInputRaw $env:CLAUDE_TOOL_INPUT
204
+ } catch {
205
+ Write-Error $_
206
+ exit 1
207
+ }
208
+
209
+ $decision | ConvertTo-Json -Compress | Write-Output
210
+ exit 0
@@ -0,0 +1,333 @@
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
+ Block cases:
18
+ Case A - gh pr create or gh pr edit 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
+ Case D - --body-file present, context artifact present, but the authorization sentinel
22
+ artifacts/pr_author_authorization.json is absent or empty: blocked
23
+ (PR_AGENT_AUTHORIZATION_MISSING).
24
+ Malformed - sentinel present but not valid JSON, or issued_at missing/unparseable: blocked
25
+ (PR_AGENT_AUTHORIZATION_MALFORMED).
26
+ Case E - sentinel valid JSON but issued_by != "pr-author": blocked
27
+ (PR_AGENT_AUTHORIZATION_INVALID).
28
+ Case F - sentinel issued_by == "pr-author" but elapsed time since issued_at exceeds
29
+ ttl_seconds: blocked (PR_AGENT_AUTHORIZATION_EXPIRED).
30
+
31
+ Authorization sentinel decision order on the --body-file-with-context path:
32
+ missing -> malformed -> invalid issuer -> expired -> allow.
33
+
34
+ .NOTES
35
+ Compatible with PowerShell 7+. No external module dependencies.
36
+
37
+ Enforcement strength: the authorization sentinel is a policy guardrail, not a cryptographic
38
+ or security control. Any actor with Write access to artifacts/ can forge
39
+ artifacts/pr_author_authorization.json, because all agents share the same filesystem and the
40
+ runtime exposes no native agent-identity signal at Bash PreToolUse time. The mechanism prevents
41
+ accidental bypass and requires a deliberate, documented act to circumvent. It MUST NOT be
42
+ described as tamper-proof or as a security boundary.
43
+ #>
44
+ [CmdletBinding()]
45
+ param()
46
+
47
+ $script:PrContextArtifactPath = 'artifacts/pr_context.summary.txt'
48
+ $script:PrAuthorAuthorizationPath = 'artifacts/pr_author_authorization.json'
49
+ $script:PrAuthorAuthorizationTtlSeconds = 120
50
+
51
+ function Get-PrContextArtifactExistence {
52
+ <#
53
+ .SYNOPSIS
54
+ Wrapper around Test-Path for the PR context artifact. Tests mock this function.
55
+ .OUTPUTS
56
+ System.Boolean
57
+ #>
58
+ [CmdletBinding()]
59
+ [OutputType([bool])]
60
+ param()
61
+
62
+ return [bool](Test-Path -LiteralPath $script:PrContextArtifactPath)
63
+ }
64
+
65
+ function Get-PrAuthorAuthorizationContent {
66
+ <#
67
+ .SYNOPSIS
68
+ Read the raw text of the authorization sentinel. Tests mock this function (read seam).
69
+ .DESCRIPTION
70
+ Returns the raw text content of artifacts/pr_author_authorization.json, or $null when the
71
+ sentinel file is absent. This is the injectable boundary for sentinel content in tests; no
72
+ test writes the sentinel file to disk.
73
+ .OUTPUTS
74
+ System.String or $null
75
+ #>
76
+ [CmdletBinding()]
77
+ [OutputType([string])]
78
+ param()
79
+
80
+ if (-not (Test-Path -LiteralPath $script:PrAuthorAuthorizationPath)) {
81
+ return $null
82
+ }
83
+
84
+ return (Get-Content -LiteralPath $script:PrAuthorAuthorizationPath -Raw)
85
+ }
86
+
87
+ function Get-CurrentDateTimeUtc {
88
+ <#
89
+ .SYNOPSIS
90
+ Return the current UTC time. Tests mock this function (clock seam) for time-travel scenarios.
91
+ .OUTPUTS
92
+ System.DateTime
93
+ #>
94
+ [CmdletBinding()]
95
+ [OutputType([datetime])]
96
+ param()
97
+
98
+ return [DateTime]::UtcNow
99
+ }
100
+
101
+ function Test-PrAuthorAuthorization {
102
+ <#
103
+ .SYNOPSIS
104
+ Validate the authorization sentinel and return a block-reason string, or $null when authorized.
105
+ .DESCRIPTION
106
+ Reads the sentinel via Get-PrAuthorAuthorizationContent and computes elapsed time via
107
+ Get-CurrentDateTimeUtc. Applies the decision order missing -> malformed -> invalid issuer ->
108
+ expired -> allow (spec FR-2 step 3):
109
+ - $null/empty contents -> PR_AGENT_AUTHORIZATION_MISSING
110
+ - not valid JSON, or issued_at
111
+ missing/unparseable -> PR_AGENT_AUTHORIZATION_MALFORMED
112
+ - issued_by != "pr-author" -> PR_AGENT_AUTHORIZATION_INVALID
113
+ - elapsed seconds > ttl_seconds -> PR_AGENT_AUTHORIZATION_EXPIRED
114
+ - all checks pass -> $null (allow)
115
+ The ttl_seconds value defaults to the named constant when absent from the sentinel.
116
+ This is a policy guardrail, not a cryptographic control; the sentinel is forgeable by any
117
+ actor with Write access to artifacts/.
118
+ .OUTPUTS
119
+ System.String or $null
120
+ #>
121
+ [CmdletBinding()]
122
+ [OutputType([string])]
123
+ param()
124
+
125
+ $contents = Get-PrAuthorAuthorizationContent
126
+
127
+ if ([string]::IsNullOrWhiteSpace($contents)) {
128
+ return "PR_AGENT_AUTHORIZATION_MISSING: ``$script:PrAuthorAuthorizationPath`` is absent or empty. The pr-author agent must write the authorization sentinel immediately before issuing ``gh pr create``/``gh pr edit --body*``."
129
+ }
130
+
131
+ try {
132
+ $sentinel = $contents | ConvertFrom-Json -ErrorAction Stop
133
+ } catch {
134
+ return "PR_AGENT_AUTHORIZATION_MALFORMED: ``$script:PrAuthorAuthorizationPath`` is not valid JSON. The pr-author agent must write a well-formed sentinel with ``issued_by``, ``issued_at``, and ``ttl_seconds``."
135
+ }
136
+
137
+ $issuedAtRaw = $sentinel.issued_at
138
+ if ([string]::IsNullOrWhiteSpace([string]$issuedAtRaw)) {
139
+ return "PR_AGENT_AUTHORIZATION_MALFORMED: ``$script:PrAuthorAuthorizationPath`` is missing ``issued_at``. The pr-author agent must record a UTC ISO-8601 ``issued_at`` timestamp."
140
+ }
141
+
142
+ $issuedAt = [DateTime]::MinValue
143
+ $parsed = [DateTime]::TryParse(
144
+ [string]$issuedAtRaw,
145
+ [System.Globalization.CultureInfo]::InvariantCulture,
146
+ [System.Globalization.DateTimeStyles]::AdjustToUniversal -bor [System.Globalization.DateTimeStyles]::AssumeUniversal,
147
+ [ref] $issuedAt)
148
+ if (-not $parsed) {
149
+ return "PR_AGENT_AUTHORIZATION_MALFORMED: ``$script:PrAuthorAuthorizationPath`` has an unparseable ``issued_at``. The pr-author agent must record a UTC ISO-8601 ``issued_at`` timestamp."
150
+ }
151
+
152
+ if ($sentinel.issued_by -ne 'pr-author') {
153
+ return "PR_AGENT_AUTHORIZATION_INVALID: ``$script:PrAuthorAuthorizationPath`` ``issued_by`` is not ``pr-author``. Only the pr-author agent may authorize PR creation or body edits."
154
+ }
155
+
156
+ $ttlSeconds = $script:PrAuthorAuthorizationTtlSeconds
157
+ if ($null -ne $sentinel.ttl_seconds) {
158
+ $candidateTtl = 0
159
+ if ([int]::TryParse([string]$sentinel.ttl_seconds, [ref] $candidateTtl)) {
160
+ $ttlSeconds = $candidateTtl
161
+ }
162
+ }
163
+
164
+ $elapsedSeconds = ((Get-CurrentDateTimeUtc) - $issuedAt).TotalSeconds
165
+ if ($elapsedSeconds -gt $ttlSeconds) {
166
+ return "PR_AGENT_AUTHORIZATION_EXPIRED: ``$script:PrAuthorAuthorizationPath`` issued $([math]::Round($elapsedSeconds)) s ago, exceeding the ${ttlSeconds}s TTL. The pr-author agent must write a fresh sentinel immediately before the ``gh`` command."
167
+ }
168
+
169
+ return $null
170
+ }
171
+
172
+ function Get-PrAuthorBypassReason {
173
+ <#
174
+ .SYNOPSIS
175
+ Inspect the command text and return a block reason string, or $null when the command is allowed.
176
+ .DESCRIPTION
177
+ Returns PR_AUTHOR_SKILL_BLOCKED when gh pr create or gh pr edit is run with --body (inline,
178
+ no --body-file), or when gh pr create is run with no body flag at all. Returns
179
+ PR_CONTEXT_MISSING when --body-file is present but the context artifact
180
+ does not exist on disk. When --body-file is present and the context artifact exists, evaluates
181
+ the authorization sentinel via Test-PrAuthorAuthorization and returns its block reason
182
+ (PR_AGENT_AUTHORIZATION_*) when authorization fails. Returns $null for all allowed patterns.
183
+ Cases A, B, and C are evaluated first and unchanged; the sentinel check only extends the
184
+ previously-allowed --body-file-with-context path.
185
+ .PARAMETER CommandText
186
+ The Bash command text extracted from CLAUDE_TOOL_INPUT.
187
+ .PARAMETER ContextExists
188
+ Whether artifacts/pr_context.summary.txt currently exists on disk.
189
+ .OUTPUTS
190
+ System.String or $null
191
+ #>
192
+ [CmdletBinding()]
193
+ [OutputType([string])]
194
+ param(
195
+ [Parameter(Mandatory)]
196
+ [string] $CommandText,
197
+
198
+ [Parameter(Mandatory)]
199
+ [bool] $ContextExists
200
+ )
201
+
202
+ # Only act on gh pr create or gh pr edit subcommands.
203
+ $isPrCreate = $CommandText -match '(?i)\bgh\s+pr\s+create\b'
204
+ $isPrEdit = $CommandText -match '(?i)\bgh\s+pr\s+edit\b'
205
+
206
+ if (-not $isPrCreate -and -not $isPrEdit) {
207
+ return $null
208
+ }
209
+
210
+ $hasBodyFile = $CommandText -match '(?i)--body-file\b'
211
+ $hasInlineBody = $CommandText -match '(?i)--body(?!-file)\b'
212
+
213
+ # Case A: gh pr create OR gh pr edit with inline --body (not --body-file). Evaluated before the
214
+ # gh pr edit no-body allow short-circuit so inline-body edits are blocked, not allowed.
215
+ if (($isPrCreate -or $isPrEdit) -and $hasInlineBody -and -not $hasBodyFile) {
216
+ return "PR_AUTHOR_SKILL_BLOCKED: ``gh pr create`` and ``gh pr edit`` 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``."
217
+ }
218
+
219
+ if ($isPrCreate) {
220
+ # Case B: gh pr create with no body flag at all.
221
+ if (-not $hasInlineBody -and -not $hasBodyFile) {
222
+ 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``."
223
+ }
224
+ }
225
+
226
+ if ($isPrEdit) {
227
+ # gh pr edit with no --body or --body-file (e.g., --title, --add-label, --reviewer) is allowed.
228
+ if (-not $hasInlineBody -and -not $hasBodyFile) {
229
+ return $null
230
+ }
231
+ }
232
+
233
+ # Case C: --body-file present but context artifact is absent.
234
+ if ($hasBodyFile -and -not $ContextExists) {
235
+ return "PR_CONTEXT_MISSING: ``$script:PrContextArtifactPath`` is absent. Run ``mcp__drm-copilot__collect_pr_context`` before creating or editing the PR body."
236
+ }
237
+
238
+ # Cases D/E/F and malformed: --body-file present and context artifact exists; verify the
239
+ # authorization sentinel. This extends, and does not replace, the previously-allowed path.
240
+ if ($hasBodyFile -and $ContextExists) {
241
+ $authorizationReason = Test-PrAuthorAuthorization
242
+ if ($authorizationReason) {
243
+ return $authorizationReason
244
+ }
245
+ }
246
+
247
+ return $null
248
+ }
249
+
250
+ function Invoke-PrAuthorSkillDecision {
251
+ <#
252
+ .SYNOPSIS
253
+ Parse CLAUDE_TOOL_INPUT and return an allow-or-block decision.
254
+ .PARAMETER ToolInputRaw
255
+ The raw JSON tool payload supplied by Claude Code.
256
+ .OUTPUTS
257
+ System.Collections.Specialized.OrderedDictionary
258
+ .NOTES
259
+ Missing tool input or missing command text is treated as allow.
260
+ #>
261
+ [CmdletBinding()]
262
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
263
+ param(
264
+ [string] $ToolInputRaw
265
+ )
266
+
267
+ if (-not $ToolInputRaw) {
268
+ return [ordered]@{ decision = 'allow' }
269
+ }
270
+
271
+ try {
272
+ $toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
273
+ } catch {
274
+ throw "enforce-pr-author-skill hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
275
+ }
276
+
277
+ $commandText = $toolInput.command
278
+ if (-not $commandText) {
279
+ return [ordered]@{ decision = 'allow' }
280
+ }
281
+
282
+ $contextExists = Get-PrContextArtifactExistence
283
+ $reason = Get-PrAuthorBypassReason -CommandText $commandText -ContextExists $contextExists
284
+
285
+ if ($reason) {
286
+ return [ordered]@{
287
+ decision = 'block'
288
+ reason = $reason
289
+ }
290
+ }
291
+
292
+ return [ordered]@{ decision = 'allow' }
293
+ }
294
+
295
+ function Test-PrAuthorBypassRequired {
296
+ <#
297
+ .SYNOPSIS
298
+ Return $true when a Bash command requires the pr-author skill to run first.
299
+ .PARAMETER CommandText
300
+ The Bash command text extracted from CLAUDE_TOOL_INPUT.
301
+ .PARAMETER ContextExists
302
+ Whether artifacts/pr_context.summary.txt currently exists on disk.
303
+ .OUTPUTS
304
+ System.Boolean
305
+ #>
306
+ [CmdletBinding()]
307
+ [OutputType([bool])]
308
+ param(
309
+ [Parameter(Mandatory)]
310
+ [string] $CommandText,
311
+
312
+ [Parameter(Mandatory)]
313
+ [bool] $ContextExists
314
+ )
315
+
316
+ return ($null -ne (Get-PrAuthorBypassReason -CommandText $CommandText -ContextExists $ContextExists))
317
+ }
318
+
319
+ # Allow dot-sourcing in tests without executing the entrypoint.
320
+ if ($MyInvocation.InvocationName -eq '.') {
321
+ return
322
+ }
323
+
324
+ try {
325
+ $decision = Invoke-PrAuthorSkillDecision -ToolInputRaw $env:CLAUDE_TOOL_INPUT
326
+ } catch {
327
+ Write-Error $_
328
+ exit 1
329
+ }
330
+
331
+ $decision | ConvertTo-Json -Compress | Write-Output
332
+
333
+ exit 0