@danmoisan/drm-copilot-mcp 1.1.17 → 1.1.19
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 +1405 -684
- package/package.json +6 -4
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +11 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -0
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +12 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +16 -5
- package/resources/claude-customizations/.claude/agents/orchestrator.md +21 -7
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +37 -13
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +55 -23
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +66 -38
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +64 -32
- package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
- package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +31 -34
- package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
- package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
- package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +396 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
- package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
- package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +153 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
- package/resources/claude-customizations/.claude/rules/shell.md +10 -8
- package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +3 -4
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +7 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +171 -5
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +6 -15
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -11
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +7 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -16
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +97 -19
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/claude-customizations/pack-manifests/core.json +25 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +13 -3
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +16 -6
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +43 -11
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +19 -4
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
- package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
- package/resources/powershell/PoshQC/README.md +8 -2
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -315
|
@@ -37,13 +37,14 @@ param(
|
|
|
37
37
|
[Parameter(Position = 0, Mandatory = $false)]
|
|
38
38
|
[string]$CommandInput
|
|
39
39
|
)
|
|
40
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
40
41
|
|
|
41
|
-
Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force
|
|
42
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
|
|
42
43
|
# Shared command-line parser (issue #545). Both detectors below run against the segment
|
|
43
44
|
# list rather than against the unsegmented command string, so a dangerous phrase quoted
|
|
44
45
|
# inside a message body is no longer a match and a relocating spelling no longer escapes.
|
|
45
|
-
. (Join-Path $PSScriptRoot 'hook-command-scanner.ps1')
|
|
46
|
-
. (Join-Path $PSScriptRoot 'hook-command-invocation.ps1')
|
|
46
|
+
try { . (Join-Path $PSScriptRoot 'hook-command-scanner.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-scanner.ps1' -ErrorRecord $_ }
|
|
47
|
+
try { . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-invocation.ps1' -ErrorRecord $_ }
|
|
47
48
|
|
|
48
49
|
function Get-BlockedBashPattern {
|
|
49
50
|
[CmdletBinding()]
|
|
@@ -417,6 +418,8 @@ function Invoke-ValidateBashDecision {
|
|
|
417
418
|
[AllowNull()]
|
|
418
419
|
[string] $PositionalInput
|
|
419
420
|
)
|
|
421
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'HOOK_DEPENDENCY_LOAD_FAILED:'
|
|
422
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
420
423
|
|
|
421
424
|
$commandToCheck = Get-BashCommandToCheck -ToolInputRaw $ToolInputRaw -PositionalInput $PositionalInput
|
|
422
425
|
|
|
@@ -431,6 +434,9 @@ function Invoke-ValidateBashDecision {
|
|
|
431
434
|
if ($MyInvocation.InvocationName -eq '.') {
|
|
432
435
|
return
|
|
433
436
|
}
|
|
437
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('HOOK_DEPENDENCY_LOAD_FAILED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
438
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'HOOK_DEPENDENCY_LOAD_FAILED:'
|
|
439
|
+
if ($null -ne $dependencyDecision) { $dependencyDecision | ConvertTo-Json -Compress -Depth 5 | Write-Output; exit 0 }
|
|
434
440
|
|
|
435
441
|
$toolInputRaw = Read-ClaudeHookRawPayload
|
|
436
442
|
|
|
@@ -5,19 +5,24 @@
|
|
|
5
5
|
|
|
6
6
|
.DESCRIPTION
|
|
7
7
|
Invoked by the Claude Code SubagentStop hook under the existing broad
|
|
8
|
-
generic-agent matcher group. The hook reads
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
generic-agent matcher group. The hook reads the SubagentStop envelope JSON
|
|
9
|
+
from stdin through the shared envelope helper (subagentstop-envelope.ps1),
|
|
10
|
+
takes its last_assistant_message field (the terminating subagent's last
|
|
11
|
+
assistant message), scans that text for discovery-artifact path references
|
|
12
|
+
via Get-DiscoveryArtifactType, and for each recognized reference (when a
|
|
13
|
+
required-artifact declaration is present) invokes the discovery validator
|
|
14
|
+
via Invoke-DiscoveryValidatorExe.
|
|
14
15
|
|
|
15
16
|
Any referenced artifact that fails validation blocks the subagent's
|
|
16
|
-
termination: the hook writes
|
|
17
|
-
DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix and exits
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
termination: the hook writes the reason with a
|
|
18
|
+
DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix to stderr and exits 2 through the
|
|
19
|
+
shared envelope helper. An invalid envelope (empty, not valid JSON, not a
|
|
20
|
+
JSON object, or without a string last_assistant_message) also blocks, with
|
|
21
|
+
a "DISCOVERY_ARTIFACT_GATE_BLOCKED: payload anomaly" reason. The hook
|
|
22
|
+
allows termination when the last assistant message is blank, when it
|
|
23
|
+
references no discovery-artifact path, when the required-artifact
|
|
24
|
+
declaration is absent (fail-open), or when every referenced artifact
|
|
25
|
+
passes validation.
|
|
21
26
|
|
|
22
27
|
This hook provides the authoritative, defense-in-depth check of final
|
|
23
28
|
workspace state, regardless of which tool produced the artifact,
|
|
@@ -32,9 +37,13 @@
|
|
|
32
37
|
`Test-Json -SchemaFile` Draft 2020-12 support). Read-only validation gate that
|
|
33
38
|
invokes NO external process: validation runs in-process through
|
|
34
39
|
`.claude/lib/discovery-validation/DiscoveryValidation.psm1` (issue #475).
|
|
40
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
35
41
|
#>
|
|
36
42
|
[CmdletBinding()]
|
|
37
43
|
param()
|
|
44
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
45
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
46
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryValidation.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryValidation.psm1' -ErrorRecord $_ }
|
|
38
47
|
|
|
39
48
|
function Invoke-DiscoveryValidatorExe {
|
|
40
49
|
<#
|
|
@@ -179,7 +188,7 @@ function Find-DiscoveryArtifactReference {
|
|
|
179
188
|
$foundReferences = New-Object System.Collections.Generic.List[string]
|
|
180
189
|
foreach ($token in $tokens) {
|
|
181
190
|
$trimmed = $token.Trim('`', '"', "'", ',', ';', '(', ')', '[', ']')
|
|
182
|
-
if (Get-DiscoveryArtifactType -Path $trimmed) {
|
|
191
|
+
if ($trimmed -and (Get-DiscoveryArtifactType -Path $trimmed)) {
|
|
183
192
|
if (-not $foundReferences.Contains($trimmed)) {
|
|
184
193
|
$foundReferences.Add($trimmed)
|
|
185
194
|
}
|
|
@@ -192,35 +201,24 @@ function Find-DiscoveryArtifactReference {
|
|
|
192
201
|
function Invoke-DiscoveryArtifactGateValidation {
|
|
193
202
|
<#
|
|
194
203
|
.SYNOPSIS
|
|
195
|
-
|
|
196
|
-
for a discovery-artifact completion gate.
|
|
204
|
+
Reads the SubagentStop envelope and returns an Ok/Message validation
|
|
205
|
+
result for a discovery-artifact completion gate.
|
|
197
206
|
#>
|
|
198
207
|
[CmdletBinding()]
|
|
199
208
|
[OutputType([hashtable])]
|
|
200
209
|
param(
|
|
201
|
-
[string] $
|
|
210
|
+
[AllowNull()] [AllowEmptyString()] [string] $InputText,
|
|
202
211
|
|
|
203
212
|
[Parameter(Mandatory = $false)]
|
|
204
213
|
[scriptblock] $RequiredArtifactReader = { Get-RequiredDiscoveryArtifactDeclaration }
|
|
205
214
|
)
|
|
215
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
216
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
217
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
218
|
+
if (-not $envelope.IsValid) { return @{ Ok = $false; Message = "DISCOVERY_ARTIFACT_GATE_BLOCKED: payload anomaly - $(Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)" } }
|
|
219
|
+
$assistantMessage = [string]$envelope.AssistantText
|
|
206
220
|
|
|
207
|
-
|
|
208
|
-
return @{ Ok = $false; Message = 'discovery artifact gate hook: CLAUDE_HOOK_INPUT is empty' }
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
$payload = $RawPayload | ConvertFrom-Json -ErrorAction Stop
|
|
213
|
-
}
|
|
214
|
-
catch {
|
|
215
|
-
return @{ Ok = $false; Message = "discovery artifact gate hook: CLAUDE_HOOK_INPUT is not valid JSON: $_" }
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
$outputText = ''
|
|
219
|
-
if ($null -ne $payload -and ($payload.PSObject.Properties.Name -contains 'output')) {
|
|
220
|
-
$outputText = [string]$payload.output
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
$references = Find-DiscoveryArtifactReference -OutputText $outputText
|
|
221
|
+
$references = Find-DiscoveryArtifactReference -OutputText $assistantMessage
|
|
224
222
|
if ($references.Count -eq 0) {
|
|
225
223
|
return @{ Ok = $true; Message = $null }
|
|
226
224
|
}
|
|
@@ -233,10 +231,10 @@ function Invoke-DiscoveryArtifactGateValidation {
|
|
|
233
231
|
|
|
234
232
|
foreach ($reference in $references) {
|
|
235
233
|
$artifactType = Get-DiscoveryArtifactType -Path $reference
|
|
236
|
-
$
|
|
237
|
-
$hasErrorOutput = -not [string]::IsNullOrWhiteSpace($
|
|
238
|
-
if ($
|
|
239
|
-
return @{ Ok = $false; Message = "DISCOVERY_ARTIFACT_GATE_BLOCKED: $($
|
|
234
|
+
$validatorResult = Invoke-DiscoveryValidatorExe -ValidatorArgs @($artifactType, $reference)
|
|
235
|
+
$hasErrorOutput = -not [string]::IsNullOrWhiteSpace($validatorResult['Output'])
|
|
236
|
+
if ($validatorResult['ExitCode'] -ne 0 -or $hasErrorOutput) {
|
|
237
|
+
return @{ Ok = $false; Message = "DISCOVERY_ARTIFACT_GATE_BLOCKED: $($validatorResult['Output'])" }
|
|
240
238
|
}
|
|
241
239
|
}
|
|
242
240
|
|
|
@@ -247,11 +245,11 @@ function Invoke-DiscoveryArtifactGateValidation {
|
|
|
247
245
|
if ($MyInvocation.InvocationName -eq '.') {
|
|
248
246
|
return
|
|
249
247
|
}
|
|
248
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('DISCOVERY_ARTIFACT_GATE_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
249
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
250
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
250
251
|
|
|
251
|
-
$result = Invoke-DiscoveryArtifactGateValidation
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
exit 1
|
|
255
|
-
}
|
|
256
|
-
|
|
252
|
+
try { $result = Invoke-DiscoveryArtifactGateValidation }
|
|
253
|
+
catch { Exit-SubagentStopBlock -Message ('DISCOVERY_ARTIFACT_GATE_BLOCKED: validator error: ' + ([string]$_.Exception.Message -split "`r?`n")[0] + '; the gate fails closed.' + "`n" + 'This condition is not repairable by the subagent. Report it to the operator and halt.') }
|
|
254
|
+
if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
|
|
257
255
|
exit 0
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
plan state satisfy the executor's mechanical contract.
|
|
8
8
|
|
|
9
9
|
Enforced checks:
|
|
10
|
-
-
|
|
10
|
+
- the SubagentStop envelope read from stdin carries a non-empty last_assistant_message,
|
|
11
11
|
- output advertises `plan-path: <path>` (or supported equivalent forms),
|
|
12
12
|
- the advertised plan exists on disk,
|
|
13
13
|
- preflight-only runs return an exact preflight signal and may not claim
|
|
@@ -20,17 +20,25 @@
|
|
|
20
20
|
output includes a PASS or FAIL status line for that language.
|
|
21
21
|
|
|
22
22
|
.NOTES
|
|
23
|
-
Reads the
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
Reads the SubagentStop envelope from stdin through Read-SubagentStopEnvelope
|
|
24
|
+
(subagentstop-envelope.ps1); the assistant text comes from the helper's
|
|
25
|
+
AssistantText. A non-repairable condition blocks once: when StopHookActive is
|
|
26
|
+
set, the re-entered stop is allowed. Exits 0 to allow termination; a block is
|
|
27
|
+
written to stderr with exit 2 through Exit-SubagentStopBlock. The dependency
|
|
28
|
+
guard and the E1 helper are guarded loads: a failure blocks with exit 2,
|
|
29
|
+
naming the file. Plan file contents are read through Get-PlanFileContent so
|
|
30
|
+
tests can mock the filesystem boundary without writing temporary files.
|
|
31
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
27
32
|
#>
|
|
28
33
|
|
|
29
34
|
[CmdletBinding()]
|
|
30
35
|
param()
|
|
36
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
31
37
|
|
|
32
38
|
Set-StrictMode -Version Latest
|
|
39
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
33
40
|
$ErrorActionPreference = 'Stop'
|
|
41
|
+
$script:SubagentStopReportAndHaltLine = 'This condition is not repairable by the subagent. Report it to the operator and halt.'
|
|
34
42
|
|
|
35
43
|
function Get-PlanFileContent {
|
|
36
44
|
[CmdletBinding()]
|
|
@@ -83,7 +91,7 @@ function Test-IsPreflightPlan {
|
|
|
83
91
|
[OutputType([bool])]
|
|
84
92
|
param(
|
|
85
93
|
[Parameter(Mandatory = $true)]
|
|
86
|
-
[string[]] $Lines
|
|
94
|
+
[AllowEmptyString()] [string[]] $Lines
|
|
87
95
|
)
|
|
88
96
|
|
|
89
97
|
return @($Lines | Where-Object { $_ -match '(?i)^\s*DIRECTIVE:\s*PREFLIGHT VALIDATION ONLY\s*$' }).Count -gt 0
|
|
@@ -94,7 +102,7 @@ function Get-TouchedLanguagesFromPlan {
|
|
|
94
102
|
[OutputType([string[]])]
|
|
95
103
|
param(
|
|
96
104
|
[Parameter(Mandatory = $true)]
|
|
97
|
-
[string[]] $Lines
|
|
105
|
+
[AllowEmptyString()] [string[]] $Lines
|
|
98
106
|
)
|
|
99
107
|
|
|
100
108
|
$languages = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
|
|
@@ -176,54 +184,74 @@ function Test-HasCanonicalBlockedText {
|
|
|
176
184
|
}
|
|
177
185
|
|
|
178
186
|
function Invoke-ExecutorOutputValidation {
|
|
187
|
+
<#
|
|
188
|
+
.SYNOPSIS
|
|
189
|
+
Reads the SubagentStop envelope, validates the assistant text, and applies the re-entry policy.
|
|
190
|
+
#>
|
|
179
191
|
[CmdletBinding()]
|
|
180
192
|
[OutputType([hashtable])]
|
|
181
193
|
param(
|
|
182
|
-
[string] $
|
|
194
|
+
[AllowNull()] [AllowEmptyString()] [string] $InputText
|
|
183
195
|
)
|
|
184
196
|
|
|
185
|
-
if (
|
|
186
|
-
|
|
197
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
198
|
+
if (-not $envelope.IsValid) { $decision = @{ Ok = $false; Repairable = $false; Message = ('{0} payload anomaly - {1}' -f 'atomic-executor hook:', (Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)) } }
|
|
199
|
+
else {
|
|
200
|
+
$agentOutput = $envelope.AssistantText
|
|
201
|
+
$decision = Get-ExecutorOutputBlockDecision -AgentOutput ([string]$agentOutput)
|
|
187
202
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
$
|
|
191
|
-
|
|
192
|
-
catch {
|
|
193
|
-
return @{ Ok = $false; Message = "atomic-executor hook: failed to parse CLAUDE_HOOK_INPUT as JSON: $($_.Exception.Message)" }
|
|
203
|
+
if ($decision.Ok) { return @{ Ok = $true; Message = $null } }
|
|
204
|
+
if (-not $decision.Repairable) {
|
|
205
|
+
if ($envelope.StopHookActive) { return @{ Ok = $true; Message = $null } }
|
|
206
|
+
if (-not $decision.Message.Contains('to the operator and halt.')) { $decision.Message = $decision.Message + "`n" + $script:SubagentStopReportAndHaltLine }
|
|
194
207
|
}
|
|
208
|
+
return @{ Ok = $false; Message = $decision.Message }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function Get-ExecutorOutputBlockDecision {
|
|
212
|
+
<#
|
|
213
|
+
.SYNOPSIS
|
|
214
|
+
Applies the executor completion checks to the assistant text and returns the block decision.
|
|
215
|
+
.DESCRIPTION
|
|
216
|
+
Returns @{ Ok = $true; Message = $null } to allow, or a hashtable with Ok = $false, a
|
|
217
|
+
Repairable boolean, and Message. Repairable is $false for a non-preflight BLOCKED claim
|
|
218
|
+
and for a plan with no task checkboxes; every other block is repairable by the subagent.
|
|
219
|
+
#>
|
|
220
|
+
[CmdletBinding()]
|
|
221
|
+
[OutputType([hashtable])]
|
|
222
|
+
param(
|
|
223
|
+
[Parameter(Mandatory = $true)]
|
|
224
|
+
[AllowEmptyString()]
|
|
225
|
+
[string] $AgentOutput
|
|
226
|
+
)
|
|
195
227
|
|
|
196
|
-
$agentOutput = $null
|
|
197
|
-
if ($payload.PSObject.Properties.Name -contains 'output') {
|
|
198
|
-
$agentOutput = $payload.output
|
|
199
|
-
}
|
|
200
228
|
if ([string]::IsNullOrWhiteSpace($agentOutput)) {
|
|
201
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: agent output is empty; executor must return plan-path and final completion summary.' }
|
|
229
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: agent output is empty (last_assistant_message carries no text); executor must return plan-path and final completion summary.' }
|
|
202
230
|
}
|
|
203
231
|
|
|
204
232
|
$planPath = Get-PlanPathFromOutput -AgentOutput $agentOutput
|
|
205
233
|
if ($null -eq $planPath) {
|
|
206
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: agent output does not advertise a plan-path. Executor must report `plan-path: <path>` per atomic-plan-contract.' }
|
|
234
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: agent output does not advertise a plan-path. Executor must report `plan-path: <path>` per atomic-plan-contract.' }
|
|
207
235
|
}
|
|
208
236
|
|
|
209
237
|
$file = Get-PlanFileContent -Path $planPath
|
|
210
238
|
if (-not $file.Exists) {
|
|
211
|
-
return @{ Ok = $false; Message = "atomic-executor hook: executor advertised plan-path '$planPath' but no file exists at that location." }
|
|
239
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: executor advertised plan-path '$planPath' but no file exists at that location." }
|
|
212
240
|
}
|
|
213
241
|
|
|
214
242
|
$isPreflight = Test-IsPreflightPlan -Lines $file.Lines
|
|
215
243
|
if ($isPreflight) {
|
|
216
244
|
if (-not (Test-HasCanonicalBlockedText -AgentOutput $agentOutput)) {
|
|
217
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: blocked preflight output must include the exact text `BLOCKED at preflight (before [P0-T1])` plus a concrete plan delta.' }
|
|
245
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: blocked preflight output must include the exact text `BLOCKED at preflight (before [P0-T1])` plus a concrete plan delta.' }
|
|
218
246
|
}
|
|
219
247
|
if ($agentOutput -notmatch 'BLOCKED' -and -not (Test-HasPreflightSignal -AgentOutput $agentOutput)) {
|
|
220
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: preflight output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
|
|
248
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: preflight output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
|
|
221
249
|
}
|
|
222
250
|
return @{ Ok = $true; Message = $null }
|
|
223
251
|
}
|
|
224
252
|
|
|
225
253
|
if ($agentOutput -match 'BLOCKED') {
|
|
226
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: blocking is permitted only during preflight validation (before [P0-T1]).' }
|
|
254
|
+
return @{ Ok = $false; Repairable = $false; Message = 'atomic-executor hook: blocking is permitted only during preflight validation (before [P0-T1]).' }
|
|
227
255
|
}
|
|
228
256
|
|
|
229
257
|
$checkboxLineCount = 0
|
|
@@ -243,7 +271,7 @@ function Invoke-ExecutorOutputValidation {
|
|
|
243
271
|
}
|
|
244
272
|
|
|
245
273
|
if ($checkboxLineCount -eq 0) {
|
|
246
|
-
return @{ Ok = $false; Message = "atomic-executor hook: plan file '$planPath' contains no task checkboxes; executor cannot complete against an empty plan." }
|
|
274
|
+
return @{ Ok = $false; Repairable = $false; Message = "atomic-executor hook: plan file '$planPath' contains no task checkboxes; executor cannot complete against an empty plan." }
|
|
247
275
|
}
|
|
248
276
|
|
|
249
277
|
if ($uncheckedLineNumbers.Count -gt 0) {
|
|
@@ -255,17 +283,17 @@ function Invoke-ExecutorOutputValidation {
|
|
|
255
283
|
}
|
|
256
284
|
$lineList = ($reported -join ', ')
|
|
257
285
|
$message = "atomic-executor hook: plan file '$planPath' has $($uncheckedLineNumbers.Count) unchecked task(s) at line(s) ${lineList}${suffix}. All `- [ ]` items must be ticked to `- [x]` before termination."
|
|
258
|
-
return @{ Ok = $false; Message = $message }
|
|
286
|
+
return @{ Ok = $false; Repairable = $true; Message = $message }
|
|
259
287
|
}
|
|
260
288
|
|
|
261
289
|
if ($agentOutput -notmatch '(?i)\bAC Status Summary\b') {
|
|
262
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: completion output must include an `AC Status Summary` section.' }
|
|
290
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: completion output must include an `AC Status Summary` section.' }
|
|
263
291
|
}
|
|
264
292
|
|
|
265
|
-
$hasCommandEvidence = $agentOutput -match '(?i)(Commands Run|Command[s]?:|poetry run |npx |pwsh |git |mcp__drm-copilot__)'
|
|
293
|
+
$hasCommandEvidence = $agentOutput -match '(?i)(Commands Run|Command[s]?:|poetry[ ]run |npx |pwsh |git |mcp__drm-copilot__)'
|
|
266
294
|
$hasStatusEvidence = $agentOutput -match '(?i)\b(PASS|FAIL)\b'
|
|
267
295
|
if (-not $hasCommandEvidence -or -not $hasStatusEvidence) {
|
|
268
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: completion output must report commands run and pass/fail status results.' }
|
|
296
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: completion output must report commands run and pass/fail status results.' }
|
|
269
297
|
}
|
|
270
298
|
|
|
271
299
|
$missingLanguageStatuses = [System.Collections.Generic.List[string]]::new()
|
|
@@ -277,7 +305,7 @@ function Invoke-ExecutorOutputValidation {
|
|
|
277
305
|
|
|
278
306
|
if ($missingLanguageStatuses.Count -gt 0) {
|
|
279
307
|
$missingList = $missingLanguageStatuses -join ', '
|
|
280
|
-
return @{ Ok = $false; Message = "atomic-executor hook: completion output is missing explicit PASS/FAIL toolchain status lines for: $missingList." }
|
|
308
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: completion output is missing explicit PASS/FAIL toolchain status lines for: $missingList." }
|
|
281
309
|
}
|
|
282
310
|
|
|
283
311
|
return @{ Ok = $true; Message = $null }
|
|
@@ -287,10 +315,10 @@ if ($MyInvocation.InvocationName -eq '.') {
|
|
|
287
315
|
return
|
|
288
316
|
}
|
|
289
317
|
|
|
290
|
-
$
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
318
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('validate-executor-output: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
319
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-executor-output:'
|
|
320
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
321
|
+
try { $result = Invoke-ExecutorOutputValidation }
|
|
322
|
+
catch { Exit-SubagentStopBlock -Message ('validate-executor-output: validator error: ' + ([string]$_.Exception.Message -split "`r?`n")[0] + '; the gate fails closed.' + "`n" + $script:SubagentStopReportAndHaltLine) }
|
|
323
|
+
if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
|
|
296
324
|
exit 0
|
package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Artifact reader and coverage-report parsers for the feature-review coverage hook.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Dot-sourced by validate-feature-review-coverage.ps1. Defines the review-artifact file reader
|
|
7
|
+
(Get-ArtifactFileContent), the LCOV and JaCoCo line and branch coverage parsers, and the
|
|
8
|
+
per-language dispatchers that select a coverage report for a changed language.
|
|
9
|
+
|
|
10
|
+
The file has no param() block, writes nothing to the output stream, and runs no top-level
|
|
11
|
+
statement other than function definitions.
|
|
12
|
+
|
|
13
|
+
.NOTES
|
|
14
|
+
Requires PowerShell 7+.
|
|
15
|
+
#>
|
|
16
|
+
|
|
17
|
+
function Get-ArtifactFileContent {
|
|
18
|
+
[CmdletBinding()]
|
|
19
|
+
[OutputType([hashtable])]
|
|
20
|
+
param(
|
|
21
|
+
[Parameter(Mandatory = $true)]
|
|
22
|
+
[string] $Path
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
|
|
26
|
+
return @{ Exists = $false; Text = $null; Lines = @() }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$text = Get-Content -LiteralPath $Path -Raw -ErrorAction Stop
|
|
30
|
+
$lines = Get-Content -LiteralPath $Path -ErrorAction Stop
|
|
31
|
+
if ($null -eq $lines) {
|
|
32
|
+
$lines = @()
|
|
33
|
+
}
|
|
34
|
+
elseif ($lines -isnot [array]) {
|
|
35
|
+
$lines = @($lines)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return @{ Exists = $true; Text = $text; Lines = $lines }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function Get-FeatureReviewClaudeMdText {
|
|
42
|
+
<#
|
|
43
|
+
.SYNOPSIS
|
|
44
|
+
Reads the repository's root CLAUDE.md for the coverage-floor lookup (CR-4).
|
|
45
|
+
.DESCRIPTION
|
|
46
|
+
Returns a hashtable with Text and ReadError. An absent file yields Text = $null and
|
|
47
|
+
ReadError = $null, so the caller applies the default floors. A file that exists but
|
|
48
|
+
cannot be read yields Text = $null and ReadError set to the first line of the
|
|
49
|
+
exception message, so the caller fails closed. The function never throws.
|
|
50
|
+
#>
|
|
51
|
+
[CmdletBinding()]
|
|
52
|
+
[OutputType([hashtable])]
|
|
53
|
+
param()
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
$file = Get-ArtifactFileContent -Path 'CLAUDE.md'
|
|
57
|
+
return @{ Text = $file.Text; ReadError = $null }
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return @{ Text = $null; ReadError = ([string]$_.Exception.Message -split "`r?`n")[0] }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Get-LcovRepoCoverage {
|
|
65
|
+
[OutputType([Nullable[double]])]
|
|
66
|
+
param([string]$Path)
|
|
67
|
+
|
|
68
|
+
$file = Get-ArtifactFileContent -Path $Path
|
|
69
|
+
if (-not $file.Exists) { return $null }
|
|
70
|
+
|
|
71
|
+
$totalFound = 0
|
|
72
|
+
$totalHit = 0
|
|
73
|
+
foreach ($line in $file.Lines) {
|
|
74
|
+
if ($line.StartsWith('LF:')) {
|
|
75
|
+
$totalFound += [int]($line.Substring(3))
|
|
76
|
+
}
|
|
77
|
+
elseif ($line.StartsWith('LH:')) {
|
|
78
|
+
$totalHit += [int]($line.Substring(3))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if ($totalFound -le 0) { return $null }
|
|
82
|
+
return [math]::Round(($totalHit * 100.0) / $totalFound, 2)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function Get-LcovBranchCoverage {
|
|
86
|
+
# Parses LCOV branch counters (BRF: branches found, BRH: branches hit) and returns a percent.
|
|
87
|
+
# LCOV emits one BRF/BRH line per source file in the report; we sum across the file to compute
|
|
88
|
+
# repo-wide branch coverage. Returns $null when the artifact is absent or when no branch
|
|
89
|
+
# information is recorded (BRF total = 0).
|
|
90
|
+
[OutputType([Nullable[double]])]
|
|
91
|
+
param([string]$Path)
|
|
92
|
+
|
|
93
|
+
$file = Get-ArtifactFileContent -Path $Path
|
|
94
|
+
if (-not $file.Exists) { return $null }
|
|
95
|
+
|
|
96
|
+
$totalFound = 0
|
|
97
|
+
$totalHit = 0
|
|
98
|
+
foreach ($line in $file.Lines) {
|
|
99
|
+
if ($line.StartsWith('BRF:')) {
|
|
100
|
+
$totalFound += [int]($line.Substring(4))
|
|
101
|
+
}
|
|
102
|
+
elseif ($line.StartsWith('BRH:')) {
|
|
103
|
+
$totalHit += [int]($line.Substring(4))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if ($totalFound -le 0) { return $null }
|
|
107
|
+
return [math]::Round(($totalHit * 100.0) / $totalFound, 2)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function Get-JacocoBranchCoverage {
|
|
111
|
+
[OutputType([Nullable[double]])]
|
|
112
|
+
param([string]$Path)
|
|
113
|
+
|
|
114
|
+
$file = Get-ArtifactFileContent -Path $Path
|
|
115
|
+
if (-not $file.Exists) { return $null }
|
|
116
|
+
|
|
117
|
+
[xml]$doc = $file.Text
|
|
118
|
+
$counters = $doc.SelectNodes('//counter[@type="BRANCH"]')
|
|
119
|
+
if (-not $counters -or $counters.Count -eq 0) { return $null }
|
|
120
|
+
|
|
121
|
+
$missed = 0
|
|
122
|
+
$covered = 0
|
|
123
|
+
foreach ($counter in $counters) {
|
|
124
|
+
$missed += [int]$counter.missed
|
|
125
|
+
$covered += [int]$counter.covered
|
|
126
|
+
}
|
|
127
|
+
$total = $missed + $covered
|
|
128
|
+
if ($total -le 0) { return $null }
|
|
129
|
+
return [math]::Round(($covered * 100.0) / $total, 2)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function Get-LanguageBranchCoverage {
|
|
133
|
+
[OutputType([Nullable[double]])]
|
|
134
|
+
param([string]$Language)
|
|
135
|
+
|
|
136
|
+
switch ($Language) {
|
|
137
|
+
'TypeScript' { return Get-LcovBranchCoverage -Path 'coverage/lcov.info' }
|
|
138
|
+
'Python' { return Get-LcovBranchCoverage -Path 'artifacts/python/lcov.info' }
|
|
139
|
+
'PowerShell' { return Get-JacocoBranchCoverage -Path 'artifacts/pester/powershell-coverage.xml' }
|
|
140
|
+
'CSharp' { return Get-JacocoBranchCoverage -Path 'artifacts/csharp/coverage.xml' }
|
|
141
|
+
}
|
|
142
|
+
return $null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function Get-JacocoRepoCoverage {
|
|
146
|
+
[OutputType([Nullable[double]])]
|
|
147
|
+
param([string]$Path)
|
|
148
|
+
|
|
149
|
+
$file = Get-ArtifactFileContent -Path $Path
|
|
150
|
+
if (-not $file.Exists) { return $null }
|
|
151
|
+
|
|
152
|
+
[xml]$doc = $file.Text
|
|
153
|
+
$counters = $doc.SelectNodes('//counter[@type="LINE"]')
|
|
154
|
+
if (-not $counters -or $counters.Count -eq 0) { return $null }
|
|
155
|
+
|
|
156
|
+
$missed = 0
|
|
157
|
+
$covered = 0
|
|
158
|
+
foreach ($counter in $counters) {
|
|
159
|
+
$missed += [int]$counter.missed
|
|
160
|
+
$covered += [int]$counter.covered
|
|
161
|
+
}
|
|
162
|
+
$total = $missed + $covered
|
|
163
|
+
if ($total -le 0) { return $null }
|
|
164
|
+
return [math]::Round(($covered * 100.0) / $total, 2)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function Get-LanguageRepoCoverage {
|
|
168
|
+
[OutputType([Nullable[double]])]
|
|
169
|
+
param(
|
|
170
|
+
[string]$Language
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
switch ($Language) {
|
|
174
|
+
'TypeScript' { return Get-LcovRepoCoverage -Path 'coverage/lcov.info' }
|
|
175
|
+
'Python' { return Get-LcovRepoCoverage -Path 'artifacts/python/lcov.info' }
|
|
176
|
+
'PowerShell' { return Get-JacocoRepoCoverage -Path 'artifacts/pester/powershell-coverage.xml' }
|
|
177
|
+
'CSharp' { return Get-JacocoRepoCoverage -Path 'artifacts/csharp/coverage.xml' }
|
|
178
|
+
}
|
|
179
|
+
return $null
|
|
180
|
+
}
|