@danmoisan/drm-copilot-mcp 1.1.18 → 1.1.20
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 +1149 -661
- package/package.json +3 -2
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +28 -6
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +20 -2
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +17 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +6 -4
- package/resources/claude-customizations/.claude/agents/orchestrator.md +9 -5
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +35 -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/agents/task-researcher.md +8 -0
- 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-command.ps1 +190 -0
- 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 +78 -77
- 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 +497 -0
- package/resources/claude-customizations/.claude/hooks/premortem-section.ps1 +149 -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 +267 -113
- 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 +77 -33
- 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 +52 -36
- 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-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/ci-gate/Invoke-MergeConfirmationParser.ps1 +203 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +24 -3
- 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 +37 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +85 -10
- 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 +1 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +52 -16
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +7 -3
- 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 +2 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +2 -0
- package/resources/claude-customizations/.claude/skills/csharp-change-budget-router/SKILL.md +2 -2
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -9
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +5 -3
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +134 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -3
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +36 -15
- 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 +108 -21
- 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/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +1 -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 +16 -8
- package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +6 -0
- package/resources/claude-customizations/pack-manifests/core.json +27 -0
- package/resources/codex-and-agents-customizations/.agents/skills/README.md +1 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +1 -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 +19 -7
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +43 -4
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +18 -6
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/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 +16 -1
- 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 +10 -1
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +134 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +13 -5
- 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 +27 -8
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -1
- 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 +7 -3
- package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +6 -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 +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +4 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c1.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c2.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3-elevated.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c4.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher.toml +6 -0
- 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-command.ps1 +190 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +54 -43
- 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 +497 -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/.codex/prompts/feature-review-remediate.md +6 -4
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +11 -0
- package/resources/customizations/.github/agents/atomic_executor.agent.md +21 -11
- package/resources/customizations/.github/agents/atomic_planning.agent.md +8 -3
- package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +13 -9
- package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +2 -2
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +5 -5
- package/resources/customizations/.github/agents/orchestrator.agent.md +8 -5
- package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +13 -9
- package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +2 -2
- package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +3 -3
- package/resources/customizations/.github/agents/python-atomic-executor.agent.md +13 -9
- package/resources/customizations/.github/agents/python-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +2 -2
- package/resources/customizations/.github/agents/task-researcher.agent.md +6 -0
- 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/prompts/generate-atomic-plan.prompt.md +16 -10
- package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +2 -2
- package/resources/customizations/.github/prompts/orchestrate-powershell-work.prompt.md +1 -1
- package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +1 -1
- package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +43 -4
- package/resources/customizations/.github/skills/csharp-change-budget-router/SKILL.md +1 -1
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +134 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/customizations/.github/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +10 -0
- package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +11 -0
- package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +11 -0
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.CoverageMerge.psm1 +163 -0
- package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +296 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +48 -32
- package/resources/powershell/PoshQC/PoshQC.psd1 +7 -1
- package/resources/powershell/PoshQC/PoshQC.psm1 +18 -5
- package/resources/powershell/PoshQC/README.md +21 -3
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +5 -319
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
structure requirements.
|
|
10
10
|
|
|
11
11
|
Enforced checks:
|
|
12
|
-
-
|
|
12
|
+
- the SubagentStop envelope read from stdin carries a non-empty last_assistant_message,
|
|
13
13
|
- output advertises `plan-path: <path>` (or supported equivalent forms),
|
|
14
14
|
- output contains `PREFLIGHT: ALL CLEAR` or
|
|
15
15
|
`PREFLIGHT: REVISIONS REQUIRED`,
|
|
@@ -19,20 +19,31 @@
|
|
|
19
19
|
- each task uses `- [ ] [P#-T#]` (or checked equivalent),
|
|
20
20
|
- task numbering is sequential within each phase,
|
|
21
21
|
- every task includes at least one explicit path token,
|
|
22
|
-
- the final phase contains QA-oriented work
|
|
22
|
+
- the final phase contains QA-oriented work,
|
|
23
|
+
- the plan carries a complete `## Pre-Mortem` section (Test-PreMortemSection, issue #964),
|
|
24
|
+
- no internal-review `CITATION:` locator is a line reference (issue #964).
|
|
23
25
|
|
|
24
26
|
.NOTES
|
|
25
|
-
Reads the
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
Reads the SubagentStop envelope from stdin through Read-SubagentStopEnvelope
|
|
28
|
+
(subagentstop-envelope.ps1); the assistant text comes from the helper's
|
|
29
|
+
AssistantText. A non-repairable condition blocks once: when StopHookActive is
|
|
30
|
+
set, the re-entered stop is allowed. Exits 0 to allow termination; a block is
|
|
31
|
+
written to stderr with exit 2 through Exit-SubagentStopBlock. The dependency
|
|
32
|
+
guard and the E1 helper are guarded loads: a failure blocks with exit 2,
|
|
33
|
+
naming the file. Filesystem reads go through Get-PlanFileContent so tests can
|
|
34
|
+
mock the boundary without writing temporary files.
|
|
35
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
29
36
|
#>
|
|
30
37
|
|
|
31
38
|
[CmdletBinding()]
|
|
32
39
|
param()
|
|
40
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
33
41
|
|
|
34
42
|
Set-StrictMode -Version Latest
|
|
43
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
44
|
+
try { . (Join-Path $PSScriptRoot 'premortem-section.ps1') } catch { Add-HookDependencyFailure -Name 'premortem-section.ps1' -ErrorRecord $_ }
|
|
35
45
|
$ErrorActionPreference = 'Stop'
|
|
46
|
+
$script:SubagentStopReportAndHaltLine = 'This condition is not repairable by the subagent. Report it to the operator and halt.'
|
|
36
47
|
|
|
37
48
|
function Get-PlanFileContent {
|
|
38
49
|
[CmdletBinding()]
|
|
@@ -178,6 +189,10 @@ function Get-PlannerInternalReviewValidation {
|
|
|
178
189
|
if (-not $citation.Success -or $citation.Groups['Path'].Value -notmatch '^(?![A-Za-z]:)(?!/)(?!\\)(?:\.?[^/\\|\s]+)(?:/[^/\\|\s]+)+$') {
|
|
179
190
|
return @{ Ok = $false; Message = 'planner internal review citations require a repository-relative path and nonblank locator.' }
|
|
180
191
|
}
|
|
192
|
+
# Issue #964: a line reference goes stale when main moves (consistent with validator rule G11).
|
|
193
|
+
if ($citation.Groups['Locator'].Value.Trim() -match '(?i)^(?:\d+(?:\s*-\s*\d+)?|#?L\d+(?:-L?\d+)?|lines?\s+\d+.*|[^\s:|]+:\d+(?:-\d+)?)$') {
|
|
194
|
+
return @{ Ok = $false; Message = "planner internal review citation locator ``$($citation.Groups['Locator'].Value.Trim())`` is a line reference; cite a symbol, heading, or test name instead." }
|
|
195
|
+
}
|
|
181
196
|
}
|
|
182
197
|
|
|
183
198
|
$inventoryLines = @($recordLines | Where-Object { $_ -match '^\s*AC-INVENTORY\s*:' })
|
|
@@ -232,7 +247,7 @@ function Get-PlanStructureValidationReport {
|
|
|
232
247
|
[OutputType([string[]])]
|
|
233
248
|
param(
|
|
234
249
|
[Parameter(Mandatory = $true)]
|
|
235
|
-
[string[]] $Lines
|
|
250
|
+
[AllowEmptyString()] [string[]] $Lines
|
|
236
251
|
)
|
|
237
252
|
|
|
238
253
|
$phasePattern = '^### Phase (?<Phase>\d+)\s+—\s+(?<Title>.+)$'
|
|
@@ -243,12 +258,14 @@ function Get-PlanStructureValidationReport {
|
|
|
243
258
|
$currentPhase = $null
|
|
244
259
|
$expectedPhase = 0
|
|
245
260
|
$foundTask = $false
|
|
261
|
+
$insidePhaseSection = $false
|
|
246
262
|
|
|
247
263
|
for ($i = 0; $i -lt $Lines.Count; $i++) {
|
|
248
264
|
$lineNumber = $i + 1
|
|
249
265
|
$line = $Lines[$i]
|
|
250
266
|
|
|
251
267
|
if ($line -match '^### Phase ') {
|
|
268
|
+
$insidePhaseSection = $true
|
|
252
269
|
$phaseMatch = [regex]::Match($line, $phasePattern)
|
|
253
270
|
if (-not $phaseMatch.Success) {
|
|
254
271
|
$errors.Add("Line ${lineNumber}: phase heading must match `### Phase N — <Title>`.")
|
|
@@ -269,10 +286,12 @@ function Get-PlanStructureValidationReport {
|
|
|
269
286
|
continue
|
|
270
287
|
}
|
|
271
288
|
|
|
289
|
+
if ($line -match '^#{1,2} ') { $insidePhaseSection = $false; continue }
|
|
272
290
|
if ($line -notmatch '^- \[') {
|
|
273
291
|
continue
|
|
274
292
|
}
|
|
275
293
|
|
|
294
|
+
if (-not $insidePhaseSection -and $line -notmatch $taskPattern) { continue }
|
|
276
295
|
$foundTask = $true
|
|
277
296
|
$taskMatch = [regex]::Match($line, $taskPattern)
|
|
278
297
|
if (-not $taskMatch.Success) {
|
|
@@ -344,54 +363,79 @@ function Get-PlanStructureValidationReport {
|
|
|
344
363
|
}
|
|
345
364
|
|
|
346
365
|
function Invoke-PlannerOutputValidation {
|
|
366
|
+
<#
|
|
367
|
+
.SYNOPSIS
|
|
368
|
+
Reads the SubagentStop envelope, validates the assistant text, and applies the re-entry policy.
|
|
369
|
+
#>
|
|
347
370
|
[CmdletBinding()]
|
|
348
371
|
[OutputType([hashtable])]
|
|
349
372
|
param(
|
|
350
|
-
[string] $
|
|
373
|
+
[AllowNull()] [AllowEmptyString()] [string] $InputText
|
|
351
374
|
)
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
$
|
|
375
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-planner-output:'
|
|
376
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
377
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
378
|
+
if (-not $envelope.IsValid) { $decision = @{ Ok = $false; Repairable = $false; Message = ('{0} payload anomaly - {1}' -f 'atomic-planner hook:', (Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)) } }
|
|
379
|
+
else {
|
|
380
|
+
$agentOutput = $envelope.AssistantText
|
|
381
|
+
$decision = Get-PlannerOutputBlockDecision -AgentOutput ([string]$agentOutput)
|
|
359
382
|
}
|
|
360
|
-
|
|
361
|
-
|
|
383
|
+
if ($decision.Ok) { return @{ Ok = $true; Message = $null } }
|
|
384
|
+
if (-not $decision.Repairable) {
|
|
385
|
+
if ($envelope.StopHookActive) { return @{ Ok = $true; Message = $null } }
|
|
386
|
+
if (-not $decision.Message.Contains('to the operator and halt.')) { $decision.Message = $decision.Message + "`n" + $script:SubagentStopReportAndHaltLine }
|
|
362
387
|
}
|
|
388
|
+
return @{ Ok = $false; Message = $decision.Message }
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function Get-PlannerOutputBlockDecision {
|
|
392
|
+
<#
|
|
393
|
+
.SYNOPSIS
|
|
394
|
+
Applies the planner completion checks to the assistant text and returns the block decision.
|
|
395
|
+
.DESCRIPTION
|
|
396
|
+
Returns @{ Ok = $true; Message = $null } to allow, or a hashtable with Ok = $false, a
|
|
397
|
+
Repairable boolean, and Message. Every planner content check is repairable by the subagent.
|
|
398
|
+
#>
|
|
399
|
+
[CmdletBinding()]
|
|
400
|
+
[OutputType([hashtable])]
|
|
401
|
+
param(
|
|
402
|
+
[Parameter(Mandatory = $true)]
|
|
403
|
+
[AllowEmptyString()]
|
|
404
|
+
[string] $AgentOutput
|
|
405
|
+
)
|
|
363
406
|
|
|
364
|
-
$agentOutput = $null
|
|
365
|
-
if ($null -ne $payload.PSObject.Properties['output']) {
|
|
366
|
-
$agentOutput = $payload.output
|
|
367
|
-
}
|
|
368
407
|
if ([string]::IsNullOrWhiteSpace($agentOutput)) {
|
|
369
|
-
return @{ Ok = $false; Message = 'atomic-planner hook: agent output is empty; planner must return plan-path and final preflight signal.' }
|
|
408
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-planner hook: agent output is empty (last_assistant_message carries no text); planner must return plan-path and final preflight signal.' }
|
|
370
409
|
}
|
|
371
410
|
|
|
372
411
|
if (-not (Test-HasPreflightSignal -AgentOutput $agentOutput)) {
|
|
373
|
-
return @{ Ok = $false; Message = 'atomic-planner hook: agent output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
|
|
412
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-planner hook: agent output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
|
|
374
413
|
}
|
|
375
414
|
|
|
376
415
|
$planPath = Get-PlanPathFromOutput -AgentOutput $agentOutput
|
|
377
416
|
if ($null -eq $planPath) {
|
|
378
|
-
return @{ Ok = $false; Message = 'atomic-planner hook: agent output does not advertise a plan-path. Planner must report `plan-path: <path>` per atomic-plan-contract.' }
|
|
417
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-planner hook: agent output does not advertise a plan-path. Planner must report `plan-path: <path>` per atomic-plan-contract.' }
|
|
379
418
|
}
|
|
380
419
|
|
|
381
420
|
$file = Get-PlanFileContent -Path $planPath
|
|
382
421
|
if (-not $file.Exists) {
|
|
383
|
-
return @{ Ok = $false; Message = "atomic-planner hook: planner advertised plan-path '$planPath' but no file exists at that location." }
|
|
422
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-planner hook: planner advertised plan-path '$planPath' but no file exists at that location." }
|
|
384
423
|
}
|
|
385
424
|
|
|
386
425
|
$errors = @(Get-PlanStructureValidationReport -Lines $file.Lines)
|
|
387
426
|
if ($errors.Count -gt 0) {
|
|
388
427
|
$message = "atomic-planner hook: plan '$planPath' violates the atomic plan contract:`n - " + ($errors -join "`n - ")
|
|
389
|
-
return @{ Ok = $false; Message = $message }
|
|
428
|
+
return @{ Ok = $false; Repairable = $true; Message = $message }
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
$preMortem = Test-PreMortemSection -Content ($file.Lines -join "`n")
|
|
432
|
+
if (-not $preMortem.Ok) {
|
|
433
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-planner hook: plan '$planPath' $($preMortem.Message) See ``## Design-Level Plan Contract (Mandatory)`` in atomic-plan-contract." }
|
|
390
434
|
}
|
|
391
435
|
|
|
392
436
|
$review = Get-PlannerInternalReviewValidation -AgentOutput $agentOutput
|
|
393
437
|
if (-not $review.Ok) {
|
|
394
|
-
return @{ Ok = $false; Message = "atomic-planner hook: $($review.Message)" }
|
|
438
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-planner hook: $($review.Message)" }
|
|
395
439
|
}
|
|
396
440
|
|
|
397
441
|
return @{ Ok = $true; Message = $null }
|
|
@@ -400,11 +444,11 @@ function Invoke-PlannerOutputValidation {
|
|
|
400
444
|
if ($MyInvocation.InvocationName -eq '.') {
|
|
401
445
|
return
|
|
402
446
|
}
|
|
447
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('validate-planner-output: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
448
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-planner-output:'
|
|
449
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
403
450
|
|
|
404
|
-
$result = Invoke-PlannerOutputValidation
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
exit 1
|
|
408
|
-
}
|
|
409
|
-
|
|
451
|
+
try { $result = Invoke-PlannerOutputValidation }
|
|
452
|
+
catch { Exit-SubagentStopBlock -Message ('validate-planner-output: validator error: ' + ([string]$_.Exception.Message -split "`r?`n")[0] + '; the gate fails closed.' + "`n" + $script:SubagentStopReportAndHaltLine) }
|
|
453
|
+
if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
|
|
410
454
|
exit 0
|
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
SubagentStop hook that verifies the pr-author agent reported a created or updated PR.
|
|
4
4
|
|
|
5
5
|
.DESCRIPTION
|
|
6
|
-
Invoked by the Claude Code SubagentStop hook for the pr-author matcher. Reads the
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
(exit 0) when
|
|
6
|
+
Invoked by the Claude Code SubagentStop hook for the pr-author matcher. Reads the SubagentStop
|
|
7
|
+
envelope JSON from stdin through the shared envelope helper (subagentstop-envelope.ps1) and
|
|
8
|
+
validates its last_assistant_message field, the pr-author agent's last assistant message. The
|
|
9
|
+
hook allows (exit 0) when that message contains:
|
|
10
10
|
- a GitHub PR URL (github.com/<owner>/<repo>/pull/<n>), or
|
|
11
11
|
- a PR reference of the form "PR #<n>", or
|
|
12
12
|
- a "gh pr create"/"gh pr edit" confirmation that includes a PR number.
|
|
13
|
-
The hook blocks
|
|
14
|
-
|
|
15
|
-
- the
|
|
16
|
-
|
|
17
|
-
- the
|
|
13
|
+
The hook blocks, writing the reason to stderr and exiting 2 through the shared envelope
|
|
14
|
+
helper, when:
|
|
15
|
+
- the envelope is empty, is not valid JSON, is not a JSON object, or carries no string
|
|
16
|
+
last_assistant_message (reason prefix "PR_AUTHOR_OUTPUT_MALFORMED: payload anomaly"),
|
|
17
|
+
- the last assistant message is blank (PR_AUTHOR_OUTPUT_EMPTY), or
|
|
18
|
+
- the last assistant message contains no PR URL or PR number (PR_AUTHOR_OUTPUT_NO_PR).
|
|
19
|
+
A hook dependency that fails to load blocks with exit 2 and the PR_AUTHOR_OUTPUT_MISSING:
|
|
20
|
+
prefix.
|
|
18
21
|
|
|
19
22
|
.NOTES
|
|
20
23
|
Compatible with PowerShell 7+. No external module dependencies.
|
|
@@ -24,9 +27,12 @@
|
|
|
24
27
|
that the referenced PR actually exists on GitHub, and the output text is forgeable by any actor
|
|
25
28
|
that controls the agent transcript. It MUST NOT be described as tamper-proof or as a security
|
|
26
29
|
boundary.
|
|
30
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
27
31
|
#>
|
|
28
32
|
[CmdletBinding()]
|
|
29
33
|
param()
|
|
34
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
35
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
30
36
|
|
|
31
37
|
function Test-PrAuthorOutputReportsPr {
|
|
32
38
|
<#
|
|
@@ -36,7 +42,7 @@ function Test-PrAuthorOutputReportsPr {
|
|
|
36
42
|
Detection helper (injectable boundary for tests). Matches a GitHub PR URL, a "PR #<n>"
|
|
37
43
|
reference, or a "gh pr create"/"gh pr edit" confirmation that contains a PR number.
|
|
38
44
|
.PARAMETER OutputText
|
|
39
|
-
The pr-author agent's
|
|
45
|
+
The pr-author agent's last assistant message text.
|
|
40
46
|
.OUTPUTS
|
|
41
47
|
System.Boolean
|
|
42
48
|
#>
|
|
@@ -71,53 +77,43 @@ function Test-PrAuthorOutputReportsPr {
|
|
|
71
77
|
function Get-PrAuthorOutputDecision {
|
|
72
78
|
<#
|
|
73
79
|
.SYNOPSIS
|
|
74
|
-
|
|
80
|
+
Read the SubagentStop envelope and return an allow-or-block decision.
|
|
75
81
|
.DESCRIPTION
|
|
76
82
|
Returns an ordered dictionary with 'allowed' (bool) and 'reason' (string). Allowed is $true
|
|
77
|
-
only when the
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
only when the envelope's last assistant message reports a PR per
|
|
84
|
+
Test-PrAuthorOutputReportsPr. An invalid envelope (payload anomaly), a blank last assistant
|
|
85
|
+
message, and a message without a PR reference all yield allowed = $false.
|
|
86
|
+
.PARAMETER InputText
|
|
87
|
+
The SubagentStop envelope JSON. When the parameter is not bound, Read-SubagentStopEnvelope
|
|
88
|
+
reads the envelope from stdin.
|
|
81
89
|
.OUTPUTS
|
|
82
90
|
System.Collections.Specialized.OrderedDictionary
|
|
83
91
|
#>
|
|
84
92
|
[CmdletBinding()]
|
|
85
93
|
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
86
94
|
param(
|
|
87
|
-
[string] $
|
|
95
|
+
[AllowNull()] [AllowEmptyString()] [string] $InputText
|
|
88
96
|
)
|
|
97
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'PR_AUTHOR_OUTPUT_MISSING:'
|
|
98
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
99
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
100
|
+
if (-not $envelope.IsValid) { return [ordered]@{ allowed = $false; reason = "PR_AUTHOR_OUTPUT_MALFORMED: payload anomaly - $(Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)" } }
|
|
101
|
+
$assistantMessage = [string]$envelope.AssistantText
|
|
89
102
|
|
|
90
|
-
if ([string]::IsNullOrWhiteSpace($
|
|
103
|
+
if ([string]::IsNullOrWhiteSpace($assistantMessage)) {
|
|
91
104
|
return [ordered]@{
|
|
92
105
|
allowed = $false
|
|
93
|
-
reason = '
|
|
106
|
+
reason = 'PR_AUTHOR_OUTPUT_EMPTY: the pr-author last assistant message is empty; it must report the created or updated PR URL or number.'
|
|
94
107
|
}
|
|
95
108
|
}
|
|
96
109
|
|
|
97
|
-
|
|
98
|
-
$parsed = $HookInputRaw | ConvertFrom-Json -ErrorAction Stop
|
|
99
|
-
} catch {
|
|
100
|
-
return [ordered]@{
|
|
101
|
-
allowed = $false
|
|
102
|
-
reason = 'PR_AUTHOR_OUTPUT_MALFORMED: CLAUDE_HOOK_INPUT is not valid JSON.'
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
$outputText = [string]$parsed.output
|
|
107
|
-
if ([string]::IsNullOrWhiteSpace($outputText)) {
|
|
108
|
-
return [ordered]@{
|
|
109
|
-
allowed = $false
|
|
110
|
-
reason = 'PR_AUTHOR_OUTPUT_EMPTY: the pr-author agent output is empty; it must report the created or updated PR URL or number.'
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (Test-PrAuthorOutputReportsPr -OutputText $outputText) {
|
|
110
|
+
if (Test-PrAuthorOutputReportsPr -OutputText $assistantMessage) {
|
|
115
111
|
return [ordered]@{ allowed = $true }
|
|
116
112
|
}
|
|
117
113
|
|
|
118
114
|
return [ordered]@{
|
|
119
115
|
allowed = $false
|
|
120
|
-
reason = 'PR_AUTHOR_OUTPUT_NO_PR: the pr-author
|
|
116
|
+
reason = 'PR_AUTHOR_OUTPUT_NO_PR: the pr-author last assistant message does not reference a PR URL or PR number; it must report the created or updated pull request.'
|
|
121
117
|
}
|
|
122
118
|
}
|
|
123
119
|
|
|
@@ -125,12 +121,11 @@ function Get-PrAuthorOutputDecision {
|
|
|
125
121
|
if ($MyInvocation.InvocationName -eq '.') {
|
|
126
122
|
return
|
|
127
123
|
}
|
|
124
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('PR_AUTHOR_OUTPUT_MISSING: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
125
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'PR_AUTHOR_OUTPUT_MISSING:'
|
|
126
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
128
127
|
|
|
129
|
-
$decision = Get-PrAuthorOutputDecision
|
|
130
|
-
|
|
131
|
-
if (-not $decision['allowed']) {
|
|
132
|
-
Write-Error $decision['reason']
|
|
133
|
-
exit 1
|
|
134
|
-
}
|
|
135
|
-
|
|
128
|
+
try { $decision = Get-PrAuthorOutputDecision }
|
|
129
|
+
catch { Exit-SubagentStopBlock -Message ('PR_AUTHOR_OUTPUT_MISSING: 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.') }
|
|
130
|
+
if (-not $decision['allowed']) { Exit-SubagentStopBlock -Message $decision['reason'] }
|
|
136
131
|
exit 0
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
3
|
Validates numeric acceptance criteria produced by the prd-feature worker.
|
|
4
|
+
|
|
5
|
+
.NOTES
|
|
6
|
+
Reads the SubagentStop envelope JSON from stdin through the shared envelope helper
|
|
7
|
+
(subagentstop-envelope.ps1) and validates its last_assistant_message field, the prd-feature
|
|
8
|
+
worker's last assistant message. Exits 0 to allow. A block writes the reason to stderr and
|
|
9
|
+
exits 2 through the shared envelope helper; an invalid envelope blocks with a payload anomaly
|
|
10
|
+
reason. A hook dependency that fails to load blocks with exit 2 and the
|
|
11
|
+
validate-prd-feature-output: prefix.
|
|
12
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
4
13
|
#>
|
|
5
14
|
|
|
6
15
|
[CmdletBinding()]
|
|
7
16
|
param()
|
|
17
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
18
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
8
19
|
|
|
9
20
|
Set-StrictMode -Version Latest
|
|
10
21
|
$ErrorActionPreference = 'Stop'
|
|
@@ -38,7 +49,7 @@ function Test-NumericDerivationEvidence {
|
|
|
38
49
|
if (-not $match.Success) { return @{ Ok = $false; Message = "prd-feature hook: numeric derivation evidence is missing $label." } }
|
|
39
50
|
$values[$label] = $match.Groups['value'].Value.Trim()
|
|
40
51
|
}
|
|
41
|
-
if ($values['Exhaustive Search Scope'] -notmatch '(?i)\b(entire|all|complete)\b.*\b(repository|repo|source tree|tree)\b') { return @{ Ok = $false; Message = 'prd-feature hook: numeric derivation evidence does not declare an exhaustive repository search scope.' } }
|
|
52
|
+
if ($values['Exhaustive Search Scope'] -notmatch '(?i)\b(entire|whole|all|complete)\b.*\b(repository|repo|worktree|source tree|tree)\b') { return @{ Ok = $false; Message = 'prd-feature hook: numeric derivation evidence does not declare an exhaustive repository search scope.' } }
|
|
42
53
|
$primaryStrategy = $values['Primary Search Strategy or Query Expression']
|
|
43
54
|
$crossCheckStrategy = $values['Cross-check Search Strategy or Query Expression']
|
|
44
55
|
if ($primaryStrategy -match '(?i)\b(single|narrow|named[- ]?pattern)\b' -or $crossCheckStrategy -match '(?i)\b(single|narrow|named[- ]?pattern)\b') { return @{ Ok = $false; Message = 'prd-feature hook: numeric derivation evidence uses a narrow named-pattern search.' } }
|
|
@@ -64,28 +75,46 @@ function Test-SpecNumericCriterion {
|
|
|
64
75
|
param([Parameter(Mandatory = $true)][AllowEmptyString()][string] $SpecContent)
|
|
65
76
|
|
|
66
77
|
$section = [regex]::Match($SpecContent, '(?ims)^##\s+Acceptance\s+Criteria\s*$.*?(?=^##\s|\z)')
|
|
67
|
-
|
|
78
|
+
if (-not $section.Success) { return $false }
|
|
79
|
+
# Rule R2 (issue #905): a criterion is numeric only when it states a determiner-led cardinal count of a
|
|
80
|
+
# plural noun and cites no policy file.
|
|
81
|
+
$derivedCountPattern = '\b(?:all|exactly|the|these|those)\s+(?:[1-9]\d*|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)\s+(?:(?!(?:seconds|minutes|hours|days|weeks|milliseconds|lines|bytes|characters|percent|is|as|us|has|was|does|this|its|thus|plus|less|unless|across|always|yes)\b)[\w`./-]+\s+){0,3}?(?!(?:seconds|minutes|hours|days|weeks|milliseconds|lines|bytes|characters|percent|is|as|us|has|was|does|this|its|thus|plus|less|unless|across|always|yes)\b)[a-z][\w-]*s\b'
|
|
82
|
+
$policyMarkers = @('.claude/rules/', '.github/instructions/', '.github/copilot-instructions.md')
|
|
83
|
+
foreach ($line in ($section.Value -split "`r?`n")) {
|
|
84
|
+
if ($line -notmatch '^\s*[-*]\s*\[.\]') { continue }
|
|
85
|
+
if (-not [regex]::IsMatch($line, $derivedCountPattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)) { continue }
|
|
86
|
+
$normalized = $line -replace '\\', '/'
|
|
87
|
+
if (@($policyMarkers | Where-Object { $normalized.Contains($_) }).Count -gt 0) { continue }
|
|
88
|
+
return $true
|
|
89
|
+
}
|
|
90
|
+
return $false
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
function Invoke-PrdFeatureOutputValidation {
|
|
71
94
|
[CmdletBinding()]
|
|
72
95
|
[OutputType([hashtable])]
|
|
73
|
-
param([string] $
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
$
|
|
96
|
+
param([AllowNull()] [AllowEmptyString()] [string] $InputText)
|
|
97
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-prd-feature-output:'
|
|
98
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
99
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
100
|
+
if (-not $envelope.IsValid) { return @{ Ok = $false; Message = "prd-feature hook: payload anomaly - $(Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)" } }
|
|
101
|
+
$assistantMessage = [string]$envelope.AssistantText
|
|
102
|
+
if ([string]::IsNullOrWhiteSpace($assistantMessage)) { return @{ Ok = $false; Message = 'prd-feature hook: last assistant message is empty.' } }
|
|
103
|
+
$specPath = Get-ArtifactPathFromOutput -Output $assistantMessage -Label 'spec-path'
|
|
80
104
|
if ([string]::IsNullOrWhiteSpace($specPath) -or -not (Test-Path -LiteralPath $specPath -PathType Leaf)) { return @{ Ok = $false; Message = 'prd-feature hook: spec-path is required and must exist.' } }
|
|
81
|
-
$specContent = Get-Content -LiteralPath $specPath -Raw -ErrorAction Stop
|
|
105
|
+
try { $specContent = Get-Content -LiteralPath $specPath -Raw -ErrorAction Stop } catch { return @{ Ok = $false; Message = "prd-feature hook: failed to read spec-path '$specPath': $($_.Exception.Message)" } }
|
|
82
106
|
if (-not (Test-SpecNumericCriterion -SpecContent $specContent)) { return @{ Ok = $true; Message = $null } }
|
|
83
|
-
$researchPath = Get-ArtifactPathFromOutput -Output $
|
|
107
|
+
$researchPath = Get-ArtifactPathFromOutput -Output $assistantMessage -Label 'research-path'
|
|
84
108
|
if ([string]::IsNullOrWhiteSpace($researchPath) -or -not (Test-Path -LiteralPath $researchPath -PathType Leaf)) { return @{ Ok = $false; Message = 'prd-feature hook: numeric acceptance criterion requires an existing research-path.' } }
|
|
85
|
-
|
|
109
|
+
try { $researchContent = Get-Content -LiteralPath $researchPath -Raw -ErrorAction Stop } catch { return @{ Ok = $false; Message = "prd-feature hook: failed to read research-path '$researchPath': $($_.Exception.Message)" } }
|
|
110
|
+
return Test-NumericDerivationEvidence -Content $researchContent
|
|
86
111
|
}
|
|
87
112
|
|
|
88
113
|
if ($MyInvocation.InvocationName -eq '.') { return }
|
|
89
|
-
$
|
|
90
|
-
|
|
114
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('validate-prd-feature-output: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
115
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-prd-feature-output:'
|
|
116
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
117
|
+
try { $result = Invoke-PrdFeatureOutputValidation }
|
|
118
|
+
catch { Exit-SubagentStopBlock -Message ('validate-prd-feature-output: 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.') }
|
|
119
|
+
if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
|
|
91
120
|
exit 0
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
Generic SubagentStop hook for agents that must advertise exact artifact paths.
|
|
4
4
|
|
|
5
5
|
.DESCRIPTION
|
|
6
|
-
Validates that the
|
|
7
|
-
|
|
8
|
-
advertised path matches the configured contract regex, and the file
|
|
9
|
-
on disk.
|
|
6
|
+
Validates that the SubagentStop envelope read from stdin carries a non-empty
|
|
7
|
+
last_assistant_message, each required artifact token is advertised in that
|
|
8
|
+
text, the advertised path matches the configured contract regex, and the file
|
|
9
|
+
exists on disk.
|
|
10
10
|
|
|
11
11
|
Each required artifact spec must use:
|
|
12
12
|
token|regex|description
|
|
@@ -15,10 +15,17 @@
|
|
|
15
15
|
spec-path|^docs/features/active/.+/spec\.md$|spec artifact
|
|
16
16
|
|
|
17
17
|
.NOTES
|
|
18
|
-
Reads the
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
Reads the SubagentStop envelope from stdin through Read-SubagentStopEnvelope
|
|
19
|
+
(subagentstop-envelope.ps1); the assistant text comes from the helper's
|
|
20
|
+
AssistantText. A non-repairable condition blocks once: when StopHookActive is
|
|
21
|
+
set, the re-entered stop is allowed. Exits 0 to allow termination; a block is
|
|
22
|
+
written to stderr with exit 2 through Exit-SubagentStopBlock. A missing
|
|
23
|
+
AgentName or RequiredArtifact argument exits 2 inline and blocks once. The
|
|
24
|
+
dependency guard and the E1 helper are guarded loads: a failure blocks with
|
|
25
|
+
exit 2, naming the file. Filesystem existence checks go through
|
|
26
|
+
Test-ArtifactFile so tests can mock the boundary without writing temporary
|
|
27
|
+
files.
|
|
28
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
22
29
|
#>
|
|
23
30
|
|
|
24
31
|
[CmdletBinding()]
|
|
@@ -27,9 +34,12 @@ param(
|
|
|
27
34
|
|
|
28
35
|
[string[]] $RequiredArtifact
|
|
29
36
|
)
|
|
37
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
30
38
|
|
|
31
39
|
Set-StrictMode -Version Latest
|
|
40
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
32
41
|
$ErrorActionPreference = 'Stop'
|
|
42
|
+
$script:SubagentStopReportAndHaltLine = 'This condition is not repairable by the subagent. Report it to the operator and halt.'
|
|
33
43
|
|
|
34
44
|
function Test-ArtifactFile {
|
|
35
45
|
[CmdletBinding()]
|
|
@@ -90,31 +100,53 @@ function Get-ArtifactPathFromOutput {
|
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
function Invoke-RequiredArtifactOutputValidation {
|
|
103
|
+
<#
|
|
104
|
+
.SYNOPSIS
|
|
105
|
+
Reads the SubagentStop envelope, validates the assistant text, and applies the re-entry policy.
|
|
106
|
+
#>
|
|
93
107
|
[CmdletBinding()]
|
|
94
108
|
[OutputType([hashtable])]
|
|
95
109
|
param(
|
|
96
|
-
[string] $
|
|
110
|
+
[AllowNull()] [AllowEmptyString()] [string] $InputText,
|
|
97
111
|
[string] $AgentName,
|
|
98
112
|
[string[]] $RequiredArtifact
|
|
99
113
|
)
|
|
100
114
|
|
|
101
|
-
if (
|
|
102
|
-
|
|
115
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
116
|
+
if (-not $envelope.IsValid) { $decision = @{ Ok = $false; Repairable = $false; Message = ('{0} payload anomaly - {1}' -f ("$AgentName hook:"), (Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)) } }
|
|
117
|
+
else {
|
|
118
|
+
$agentOutput = $envelope.AssistantText
|
|
119
|
+
$decision = Get-RequiredArtifactOutputBlockDecision -AgentOutput ([string]$agentOutput) -AgentName $AgentName -RequiredArtifact $RequiredArtifact
|
|
103
120
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
$
|
|
107
|
-
|
|
108
|
-
catch {
|
|
109
|
-
return @{ Ok = $false; Message = "$AgentName hook: failed to parse CLAUDE_HOOK_INPUT as JSON: $($_.Exception.Message)" }
|
|
121
|
+
if ($decision.Ok) { return @{ Ok = $true; Message = $null } }
|
|
122
|
+
if (-not $decision.Repairable) {
|
|
123
|
+
if ($envelope.StopHookActive) { return @{ Ok = $true; Message = $null } }
|
|
124
|
+
if (-not $decision.Message.Contains('to the operator and halt.')) { $decision.Message = $decision.Message + "`n" + $script:SubagentStopReportAndHaltLine }
|
|
110
125
|
}
|
|
126
|
+
return @{ Ok = $false; Message = $decision.Message }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function Get-RequiredArtifactOutputBlockDecision {
|
|
130
|
+
<#
|
|
131
|
+
.SYNOPSIS
|
|
132
|
+
Applies the required-artifact checks to the assistant text and returns the block decision.
|
|
133
|
+
.DESCRIPTION
|
|
134
|
+
Returns @{ Ok = $true; Message = $null } to allow, or a hashtable with Ok = $false, a
|
|
135
|
+
Repairable boolean, and Message. A malformed RequiredArtifact spec is a registration
|
|
136
|
+
defect the subagent cannot clear, so it is not repairable; the other blocks are.
|
|
137
|
+
#>
|
|
138
|
+
[CmdletBinding()]
|
|
139
|
+
[OutputType([hashtable])]
|
|
140
|
+
param(
|
|
141
|
+
[Parameter(Mandatory = $true)]
|
|
142
|
+
[AllowEmptyString()]
|
|
143
|
+
[string] $AgentOutput,
|
|
144
|
+
[string] $AgentName,
|
|
145
|
+
[string[]] $RequiredArtifact
|
|
146
|
+
)
|
|
111
147
|
|
|
112
|
-
$agentOutput = $null
|
|
113
|
-
if ($payload.PSObject.Properties.Name -contains 'output') {
|
|
114
|
-
$agentOutput = $payload.output
|
|
115
|
-
}
|
|
116
148
|
if ([string]::IsNullOrWhiteSpace($agentOutput)) {
|
|
117
|
-
return @{ Ok = $false; Message = "$AgentName hook: agent output is empty; artifact paths must be reported before termination." }
|
|
149
|
+
return @{ Ok = $false; Repairable = $true; Message = "$AgentName hook: agent output is empty (last_assistant_message carries no text); artifact paths must be reported before termination." }
|
|
118
150
|
}
|
|
119
151
|
|
|
120
152
|
$errors = [System.Collections.Generic.List[string]]::new()
|
|
@@ -123,7 +155,7 @@ function Invoke-RequiredArtifactOutputValidation {
|
|
|
123
155
|
$spec = ConvertTo-ArtifactSpec -Spec $specText
|
|
124
156
|
}
|
|
125
157
|
catch {
|
|
126
|
-
return @{ Ok = $false; Message = "$AgentName hook: $($_.Exception.Message)" }
|
|
158
|
+
return @{ Ok = $false; Repairable = $false; Message = "$AgentName hook: $($_.Exception.Message)" }
|
|
127
159
|
}
|
|
128
160
|
|
|
129
161
|
$path = Get-ArtifactPathFromOutput -AgentOutput $agentOutput -Token $spec.Token
|
|
@@ -144,7 +176,7 @@ function Invoke-RequiredArtifactOutputValidation {
|
|
|
144
176
|
|
|
145
177
|
if ($errors.Count -gt 0) {
|
|
146
178
|
$message = "$AgentName hook: required artifact validation failed:`n - " + ($errors -join "`n - ")
|
|
147
|
-
return @{ Ok = $false; Message = $message }
|
|
179
|
+
return @{ Ok = $false; Repairable = $true; Message = $message }
|
|
148
180
|
}
|
|
149
181
|
|
|
150
182
|
return @{ Ok = $true; Message = $null }
|
|
@@ -154,18 +186,16 @@ if ($MyInvocation.InvocationName -eq '.') {
|
|
|
154
186
|
return
|
|
155
187
|
}
|
|
156
188
|
|
|
189
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('validate-required-artifact-output: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
190
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-required-artifact-output:'
|
|
191
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
157
192
|
if ([string]::IsNullOrWhiteSpace($AgentName) -or $null -eq $RequiredArtifact -or $RequiredArtifact.Count -eq 0) {
|
|
158
|
-
|
|
159
|
-
exit
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
$result = Invoke-RequiredArtifactOutputValidation `
|
|
163
|
-
-RawPayload $env:CLAUDE_HOOK_INPUT `
|
|
164
|
-
-AgentName $AgentName `
|
|
165
|
-
-RequiredArtifact $RequiredArtifact
|
|
166
|
-
if (-not $result.Ok) {
|
|
167
|
-
Write-Error $result.Message
|
|
168
|
-
exit 1
|
|
193
|
+
$argumentEnvelope = Read-SubagentStopEnvelope
|
|
194
|
+
if ($argumentEnvelope.StopHookActive) { exit 0 }
|
|
195
|
+
[Console]::Error.WriteLine("validate-required-artifact-output hook: AgentName and at least one RequiredArtifact spec are required.`n$($script:SubagentStopReportAndHaltLine)")
|
|
196
|
+
exit 2
|
|
169
197
|
}
|
|
170
|
-
|
|
198
|
+
try { $result = Invoke-RequiredArtifactOutputValidation -AgentName $AgentName -RequiredArtifact $RequiredArtifact }
|
|
199
|
+
catch { Exit-SubagentStopBlock -Message ('validate-required-artifact-output: validator error: ' + ([string]$_.Exception.Message -split "`r?`n")[0] + '; the gate fails closed.' + "`n" + $script:SubagentStopReportAndHaltLine) }
|
|
200
|
+
if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
|
|
171
201
|
exit 0
|