@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
|
@@ -7,12 +7,17 @@
|
|
|
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
|
-
-
|
|
14
|
-
|
|
15
|
-
-
|
|
13
|
+
- a run is classified as preflight from the delegation prompt in the subagent
|
|
14
|
+
transcript (Test-IsPreflightRun), falling back to the plan file or one output signal,
|
|
15
|
+
- preflight runs return exactly one preflight signal consistent with their
|
|
16
|
+
PREFLIGHT-DEFECT lines, name an existing fix record for any PREFLIGHT-FIX line,
|
|
17
|
+
and may not claim non-canonical blocked text,
|
|
18
|
+
- non-preflight runs may not stop in a blocked state, except a canonical preflight
|
|
19
|
+
block with a plan delta and no checked task (combined proportionate run); only the
|
|
20
|
+
uppercase BLOCKED token counts as a blocked claim, and lowercase prose does not,
|
|
16
21
|
- non-preflight plans contain checkboxes and all are checked,
|
|
17
22
|
- non-preflight output includes `AC Status Summary`,
|
|
18
23
|
- non-preflight output includes command/status reporting,
|
|
@@ -20,48 +25,44 @@
|
|
|
20
25
|
output includes a PASS or FAIL status line for that language.
|
|
21
26
|
|
|
22
27
|
.NOTES
|
|
23
|
-
Reads the
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
Reads the SubagentStop envelope from stdin through Read-SubagentStopEnvelope
|
|
29
|
+
(subagentstop-envelope.ps1); the assistant text comes from the helper's
|
|
30
|
+
AssistantText. A non-repairable condition blocks once: when StopHookActive is
|
|
31
|
+
set, the re-entered stop is allowed. Exits 0 to allow termination; a block is
|
|
32
|
+
written to stderr with exit 2 through Exit-SubagentStopBlock. The dependency
|
|
33
|
+
guard and the E1 helper are guarded loads: a failure blocks with exit 2,
|
|
34
|
+
naming the file. Plan file contents are read through Get-PlanFileContent so
|
|
35
|
+
tests can mock the filesystem boundary without writing temporary files.
|
|
36
|
+
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
27
37
|
#>
|
|
28
38
|
|
|
29
39
|
[CmdletBinding()]
|
|
30
40
|
param()
|
|
41
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
31
42
|
|
|
32
43
|
Set-StrictMode -Version Latest
|
|
44
|
+
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
33
45
|
$ErrorActionPreference = 'Stop'
|
|
46
|
+
$script:SubagentStopReportAndHaltLine = 'This condition is not repairable by the subagent. Report it to the operator and halt.'
|
|
34
47
|
|
|
35
48
|
function Get-PlanFileContent {
|
|
36
49
|
[CmdletBinding()]
|
|
37
50
|
[OutputType([hashtable])]
|
|
38
|
-
param(
|
|
39
|
-
[Parameter(Mandatory = $true)]
|
|
40
|
-
[string] $Path
|
|
41
|
-
)
|
|
51
|
+
param([Parameter(Mandatory = $true)] [string] $Path)
|
|
42
52
|
|
|
43
53
|
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
|
|
44
54
|
return @{ Exists = $false; Lines = @() }
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
$lines = @()
|
|
50
|
-
}
|
|
51
|
-
elseif ($lines -isnot [array]) {
|
|
52
|
-
$lines = @($lines)
|
|
53
|
-
}
|
|
54
|
-
|
|
57
|
+
# @() yields an array for any line count; the filter drops a $null emitted at the read boundary.
|
|
58
|
+
$lines = @(Get-Content -LiteralPath $Path -ErrorAction Stop | Where-Object { $null -ne $_ })
|
|
55
59
|
return @{ Exists = $true; Lines = $lines }
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
function Get-PlanPathFromOutput {
|
|
59
63
|
[CmdletBinding()]
|
|
60
64
|
[OutputType([string])]
|
|
61
|
-
param(
|
|
62
|
-
[Parameter(Mandatory = $true)]
|
|
63
|
-
[string] $AgentOutput
|
|
64
|
-
)
|
|
65
|
+
param([Parameter(Mandatory = $true)] [string] $AgentOutput)
|
|
65
66
|
|
|
66
67
|
$pattern = 'plan-path\s*[:=]\s*["'']?([^\s"''\)`]+)|\[plan-path\]\(([^)]+)\)'
|
|
67
68
|
$match = [regex]::Match($AgentOutput, $pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
|
|
@@ -81,22 +82,180 @@ function Get-PlanPathFromOutput {
|
|
|
81
82
|
function Test-IsPreflightPlan {
|
|
82
83
|
[CmdletBinding()]
|
|
83
84
|
[OutputType([bool])]
|
|
84
|
-
param(
|
|
85
|
-
[Parameter(Mandatory = $true)]
|
|
86
|
-
[string[]] $Lines
|
|
87
|
-
)
|
|
85
|
+
param([Parameter(Mandatory = $true)] [AllowEmptyCollection()] [AllowEmptyString()] [string[]] $Lines)
|
|
88
86
|
|
|
89
87
|
return @($Lines | Where-Object { $_ -match '(?i)^\s*DIRECTIVE:\s*PREFLIGHT VALIDATION ONLY\s*$' }).Count -gt 0
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
function Get-
|
|
90
|
+
function Get-JsonPropertyValue {
|
|
91
|
+
# Returns a named property of a parsed JSON object, or $null; safe under StrictMode.
|
|
92
|
+
[CmdletBinding()]
|
|
93
|
+
[OutputType([object])]
|
|
94
|
+
param([AllowNull()] [object] $Object, [Parameter(Mandatory = $true)] [string] $Name)
|
|
95
|
+
|
|
96
|
+
if ($null -eq $Object -or -not ($Object -is [System.Management.Automation.PSCustomObject])) {
|
|
97
|
+
return $null
|
|
98
|
+
}
|
|
99
|
+
$property = @($Object.PSObject.Properties | Where-Object { $_.Name -ceq $Name })
|
|
100
|
+
if ($property.Count -eq 0) {
|
|
101
|
+
return $null
|
|
102
|
+
}
|
|
103
|
+
return $property[0].Value
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function Get-TranscriptPathFromEnvelope {
|
|
107
|
+
# Returns agent_transcript_path from the SubagentStop envelope with a leading ~ expanded, or $null.
|
|
108
|
+
[CmdletBinding()]
|
|
109
|
+
[OutputType([string])]
|
|
110
|
+
param([AllowNull()] [object] $Envelope)
|
|
111
|
+
|
|
112
|
+
$path = Get-JsonPropertyValue -Object $Envelope -Name 'agent_transcript_path'
|
|
113
|
+
if (-not ($path -is [string]) -or [string]::IsNullOrWhiteSpace($path)) {
|
|
114
|
+
return $null
|
|
115
|
+
}
|
|
116
|
+
if ($path.StartsWith('~')) {
|
|
117
|
+
$path = $HOME + $path.Substring(1)
|
|
118
|
+
}
|
|
119
|
+
return $path
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function Get-TranscriptFirstUserText {
|
|
123
|
+
# Returns the text of the first `user` entry of transcript JSONL lines, or $null when none parses.
|
|
124
|
+
[CmdletBinding()]
|
|
125
|
+
[OutputType([string])]
|
|
126
|
+
param([AllowEmptyString()] [string[]] $Lines = @())
|
|
127
|
+
|
|
128
|
+
foreach ($line in $Lines) {
|
|
129
|
+
if ([string]::IsNullOrWhiteSpace($line)) {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
$entry = ConvertFrom-Json -InputObject $line -ErrorAction Stop
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
continue
|
|
137
|
+
}
|
|
138
|
+
if ((Get-JsonPropertyValue -Object $entry -Name 'type') -ne 'user') {
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
$container = Get-JsonPropertyValue -Object $entry -Name 'message'
|
|
142
|
+
if ($null -eq $container) {
|
|
143
|
+
$container = $entry
|
|
144
|
+
}
|
|
145
|
+
$content = Get-JsonPropertyValue -Object $container -Name 'content'
|
|
146
|
+
if ($content -is [string]) {
|
|
147
|
+
return $content
|
|
148
|
+
}
|
|
149
|
+
$textBlocks = @(@($content) | Where-Object { (Get-JsonPropertyValue -Object $_ -Name 'type') -eq 'text' })
|
|
150
|
+
$texts = @($textBlocks | ForEach-Object { [string](Get-JsonPropertyValue -Object $_ -Name 'text') })
|
|
151
|
+
if ($texts.Count -gt 0) {
|
|
152
|
+
return ($texts -join "`n")
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return $null
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function Read-TranscriptHead {
|
|
159
|
+
# File seam: returns the first 50 lines of the transcript at Path, or $null when no file exists.
|
|
93
160
|
[CmdletBinding()]
|
|
94
161
|
[OutputType([string[]])]
|
|
162
|
+
param([Parameter(Mandatory = $true)] [string] $Path)
|
|
163
|
+
|
|
164
|
+
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
|
|
165
|
+
return $null
|
|
166
|
+
}
|
|
167
|
+
return [string[]]@(Get-Content -LiteralPath $Path -TotalCount 50 -ErrorAction Stop)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function Test-IsPreflightRun {
|
|
171
|
+
<#
|
|
172
|
+
.SYNOPSIS
|
|
173
|
+
Classifies an executor run as preflight or execution (issue #964).
|
|
174
|
+
.DESCRIPTION
|
|
175
|
+
A readable transcript is authoritative: its first `user` entry (the delegation prompt) decides, even
|
|
176
|
+
against a stale plan-file directive. Otherwise the plan-file directive, then exactly one output
|
|
177
|
+
`PREFLIGHT:` signal, decide (self-declared). ReadTranscriptHead returns JSONL lines or $null.
|
|
178
|
+
#>
|
|
179
|
+
[CmdletBinding()]
|
|
180
|
+
[OutputType([bool])]
|
|
95
181
|
param(
|
|
96
|
-
[Parameter(Mandatory = $true)]
|
|
97
|
-
[string[]] $
|
|
182
|
+
[Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $AgentOutput,
|
|
183
|
+
[Parameter(Mandatory = $true)] [AllowEmptyCollection()] [AllowEmptyString()] [string[]] $PlanLines,
|
|
184
|
+
[AllowNull()] [AllowEmptyString()] [string] $TranscriptPath,
|
|
185
|
+
[scriptblock] $ReadTranscriptHead = ${function:Read-TranscriptHead}
|
|
98
186
|
)
|
|
99
187
|
|
|
188
|
+
if (-not [string]::IsNullOrWhiteSpace($TranscriptPath)) {
|
|
189
|
+
$head = $null
|
|
190
|
+
try {
|
|
191
|
+
$head = & $ReadTranscriptHead $TranscriptPath
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
$head = $null
|
|
195
|
+
}
|
|
196
|
+
if ($null -ne $head) {
|
|
197
|
+
$prompt = Get-TranscriptFirstUserText -Lines ([string[]]@($head))
|
|
198
|
+
if ($null -ne $prompt) {
|
|
199
|
+
return [regex]::IsMatch($prompt, '(?im)^\s*DIRECTIVE:\s*PREFLIGHT VALIDATION ONLY\s*$')
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (Test-IsPreflightPlan -Lines $PlanLines) {
|
|
204
|
+
return $true
|
|
205
|
+
}
|
|
206
|
+
return [regex]::Matches($AgentOutput, '(?m)^\s*PREFLIGHT:\s*(ALL CLEAR|REVISIONS REQUIRED)\s*$').Count -eq 1
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function Test-PreflightFixRecord {
|
|
210
|
+
# File seam for the preflight-fix-record path.
|
|
211
|
+
[CmdletBinding()]
|
|
212
|
+
[OutputType([bool])]
|
|
213
|
+
param([Parameter(Mandatory = $true)] [string] $Path)
|
|
214
|
+
return [bool](Test-Path -LiteralPath $Path -PathType Leaf)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function Get-PreflightRunBlockDecision {
|
|
218
|
+
<#
|
|
219
|
+
.SYNOPSIS
|
|
220
|
+
Applies the single-pass preflight output rules (issue #964); every block is repairable.
|
|
221
|
+
#>
|
|
222
|
+
[CmdletBinding()]
|
|
223
|
+
[OutputType([hashtable])]
|
|
224
|
+
param([Parameter(Mandatory = $true)] [string] $AgentOutput)
|
|
225
|
+
|
|
226
|
+
if (-not (Test-HasCanonicalBlockedText -AgentOutput $AgentOutput)) {
|
|
227
|
+
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.' }
|
|
228
|
+
}
|
|
229
|
+
if ($AgentOutput -cmatch 'BLOCKED') {
|
|
230
|
+
return @{ Ok = $true; Message = $null }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
$signals = @([regex]::Matches($AgentOutput, '(?m)^\s*PREFLIGHT:\s*(?<Signal>ALL CLEAR|REVISIONS REQUIRED)\s*$'))
|
|
234
|
+
if ($signals.Count -ne 1) {
|
|
235
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: preflight output must carry exactly one ``PREFLIGHT: ALL CLEAR`` or ``PREFLIGHT: REVISIONS REQUIRED`` signal line; found $($signals.Count)." }
|
|
236
|
+
}
|
|
237
|
+
$defectCount = [regex]::Matches($AgentOutput, '(?m)^\s*PREFLIGHT-DEFECT:\s*\S').Count
|
|
238
|
+
if ($signals[0].Groups['Signal'].Value -eq 'ALL CLEAR' -and $defectCount -gt 0) {
|
|
239
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: `PREFLIGHT: ALL CLEAR` must not carry a `PREFLIGHT-DEFECT:` line; fix trivial defects in place or return `PREFLIGHT: REVISIONS REQUIRED`.' }
|
|
240
|
+
}
|
|
241
|
+
if ($signals[0].Groups['Signal'].Value -eq 'REVISIONS REQUIRED' -and $defectCount -eq 0) {
|
|
242
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: `PREFLIGHT: REVISIONS REQUIRED` must list every substantive defect as a `PREFLIGHT-DEFECT:` line.' }
|
|
243
|
+
}
|
|
244
|
+
if ([regex]::IsMatch($AgentOutput, '(?m)^\s*PREFLIGHT-FIX:\s*\S')) {
|
|
245
|
+
$record = [regex]::Match($AgentOutput, '(?im)^\s*preflight-fix-record:\s*`?(?<Path>[^\s`]+)`?\s*$')
|
|
246
|
+
$recordPath = if ($record.Success) { ($record.Groups['Path'].Value -replace '\\', '/') -replace '^\./', '' } else { '' }
|
|
247
|
+
if (-not $recordPath.StartsWith('docs/features/', [System.StringComparison]::OrdinalIgnoreCase) -or -not (Test-PreflightFixRecord -Path $recordPath)) {
|
|
248
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: a `PREFLIGHT-FIX:` line requires a `preflight-fix-record: <path>` line naming an existing record under docs/features/.' }
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return @{ Ok = $true; Message = $null }
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function Get-TouchedLanguagesFromPlan {
|
|
255
|
+
[CmdletBinding()]
|
|
256
|
+
[OutputType([string[]])]
|
|
257
|
+
param([Parameter(Mandatory = $true)] [AllowEmptyString()] [string[]] $Lines)
|
|
258
|
+
|
|
100
259
|
$languages = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
|
|
101
260
|
$pathPattern = '(?i)(?:[.\w*?-]+[\\/])+[.\w*?-]+'
|
|
102
261
|
|
|
@@ -118,13 +277,7 @@ function Get-TouchedLanguagesFromPlan {
|
|
|
118
277
|
function Test-OutputHasLanguageStatus {
|
|
119
278
|
[CmdletBinding()]
|
|
120
279
|
[OutputType([bool])]
|
|
121
|
-
param(
|
|
122
|
-
[Parameter(Mandatory = $true)]
|
|
123
|
-
[string] $AgentOutput,
|
|
124
|
-
|
|
125
|
-
[Parameter(Mandatory = $true)]
|
|
126
|
-
[string] $Language
|
|
127
|
-
)
|
|
280
|
+
param([Parameter(Mandatory = $true)] [string] $AgentOutput, [Parameter(Mandatory = $true)] [string] $Language)
|
|
128
281
|
|
|
129
282
|
$labelMap = @{
|
|
130
283
|
'TypeScript' = @('TypeScript', 'typescript')
|
|
@@ -141,34 +294,28 @@ function Test-OutputHasLanguageStatus {
|
|
|
141
294
|
function Test-HasPreflightSignal {
|
|
142
295
|
[CmdletBinding()]
|
|
143
296
|
[OutputType([bool])]
|
|
144
|
-
param(
|
|
145
|
-
[Parameter(Mandatory = $true)]
|
|
146
|
-
[string] $AgentOutput
|
|
147
|
-
)
|
|
297
|
+
param([Parameter(Mandatory = $true)] [string] $AgentOutput)
|
|
148
298
|
|
|
149
|
-
return [regex]::IsMatch(
|
|
150
|
-
$AgentOutput,
|
|
151
|
-
'(?m)^\s*PREFLIGHT:\s*(ALL CLEAR|REVISIONS REQUIRED)\s*$'
|
|
152
|
-
)
|
|
299
|
+
return [regex]::IsMatch($AgentOutput, '(?m)^\s*PREFLIGHT:\s*(ALL CLEAR|REVISIONS REQUIRED)\s*$')
|
|
153
300
|
}
|
|
154
301
|
|
|
155
302
|
function Test-HasCanonicalBlockedText {
|
|
156
303
|
[CmdletBinding()]
|
|
157
304
|
[OutputType([bool])]
|
|
158
|
-
param(
|
|
159
|
-
[Parameter(Mandatory = $true)]
|
|
160
|
-
[string] $AgentOutput
|
|
161
|
-
)
|
|
305
|
+
param([Parameter(Mandatory = $true)] [string] $AgentOutput)
|
|
162
306
|
|
|
163
|
-
|
|
307
|
+
# Case-sensitive: lowercase prose such as `blocked_reason` is not a BLOCKED claim (issue #964).
|
|
308
|
+
if ($AgentOutput -cnotmatch 'BLOCKED') {
|
|
164
309
|
return $true
|
|
165
310
|
}
|
|
166
311
|
|
|
167
|
-
if ($AgentOutput -
|
|
312
|
+
if ($AgentOutput -cnotmatch 'BLOCKED at preflight \(before \[P0-T1\]\)') {
|
|
168
313
|
return $false
|
|
169
314
|
}
|
|
170
315
|
|
|
171
|
-
|
|
316
|
+
# The canonical phrase itself carries [P0-T1], so it is removed before looking for a plan delta.
|
|
317
|
+
$remainder = $AgentOutput -creplace 'BLOCKED at preflight \(before \[P0-T1\]\)', ''
|
|
318
|
+
if ($remainder -notmatch '(?i)plan delta' -and $remainder -notmatch '\[P\d+-T\d+\]') {
|
|
172
319
|
return $false
|
|
173
320
|
}
|
|
174
321
|
|
|
@@ -176,74 +323,89 @@ function Test-HasCanonicalBlockedText {
|
|
|
176
323
|
}
|
|
177
324
|
|
|
178
325
|
function Invoke-ExecutorOutputValidation {
|
|
326
|
+
<#
|
|
327
|
+
.SYNOPSIS
|
|
328
|
+
Reads the SubagentStop envelope, validates the assistant text, and applies the re-entry policy.
|
|
329
|
+
#>
|
|
179
330
|
[CmdletBinding()]
|
|
180
331
|
[OutputType([hashtable])]
|
|
181
|
-
param(
|
|
182
|
-
[string] $RawPayload
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
if ([string]::IsNullOrWhiteSpace($RawPayload)) {
|
|
186
|
-
return @{ Ok = $false; Message = 'atomic-executor hook: CLAUDE_HOOK_INPUT is empty; cannot validate executor output.' }
|
|
187
|
-
}
|
|
332
|
+
param([AllowNull()] [AllowEmptyString()] [string] $InputText)
|
|
188
333
|
|
|
189
|
-
|
|
190
|
-
|
|
334
|
+
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
335
|
+
if (-not $envelope.IsValid) { $decision = @{ Ok = $false; Repairable = $false; Message = ('{0} payload anomaly - {1}' -f 'atomic-executor hook:', (Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)) } }
|
|
336
|
+
else {
|
|
337
|
+
$agentOutput = $envelope.AssistantText
|
|
338
|
+
$decision = Get-ExecutorOutputBlockDecision -AgentOutput ([string]$agentOutput) -TranscriptPath (Get-TranscriptPathFromEnvelope -Envelope $envelope.Envelope)
|
|
191
339
|
}
|
|
192
|
-
|
|
193
|
-
|
|
340
|
+
if ($decision.Ok) { return @{ Ok = $true; Message = $null } }
|
|
341
|
+
if (-not $decision.Repairable) {
|
|
342
|
+
if ($envelope.StopHookActive) { return @{ Ok = $true; Message = $null } }
|
|
343
|
+
if (-not $decision.Message.Contains('to the operator and halt.')) { $decision.Message = $decision.Message + "`n" + $script:SubagentStopReportAndHaltLine }
|
|
194
344
|
}
|
|
345
|
+
return @{ Ok = $false; Message = $decision.Message }
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function Get-ExecutorOutputBlockDecision {
|
|
349
|
+
<#
|
|
350
|
+
.SYNOPSIS
|
|
351
|
+
Applies the executor completion checks to the assistant text and returns the block decision.
|
|
352
|
+
.DESCRIPTION
|
|
353
|
+
Returns @{ Ok = $true; Message = $null } to allow, or a hashtable with Ok = $false, a
|
|
354
|
+
Repairable boolean, and Message. Repairable is $false for a non-preflight BLOCKED claim
|
|
355
|
+
and for a plan with no task checkboxes; every other block is repairable by the subagent.
|
|
356
|
+
TranscriptPath and ReadTranscriptHead feed Test-IsPreflightRun. An execution run that
|
|
357
|
+
stops with the canonical preflight BLOCKED text, a plan delta, and no checked task is a
|
|
358
|
+
preflight block inside a combined proportionate run and is allowed.
|
|
359
|
+
#>
|
|
360
|
+
[CmdletBinding()]
|
|
361
|
+
[OutputType([hashtable])]
|
|
362
|
+
param(
|
|
363
|
+
[Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $AgentOutput,
|
|
364
|
+
[AllowNull()] [AllowEmptyString()] [string] $TranscriptPath,
|
|
365
|
+
[scriptblock] $ReadTranscriptHead
|
|
366
|
+
)
|
|
195
367
|
|
|
196
|
-
$agentOutput = $null
|
|
197
|
-
if ($payload.PSObject.Properties.Name -contains 'output') {
|
|
198
|
-
$agentOutput = $payload.output
|
|
199
|
-
}
|
|
200
368
|
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.' }
|
|
369
|
+
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
370
|
}
|
|
203
371
|
|
|
204
372
|
$planPath = Get-PlanPathFromOutput -AgentOutput $agentOutput
|
|
205
373
|
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.' }
|
|
374
|
+
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
375
|
}
|
|
208
376
|
|
|
209
377
|
$file = Get-PlanFileContent -Path $planPath
|
|
210
378
|
if (-not $file.Exists) {
|
|
211
|
-
return @{ Ok = $false; Message = "atomic-executor hook: executor advertised plan-path '$planPath' but no file exists at that location." }
|
|
379
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: executor advertised plan-path '$planPath' but no file exists at that location." }
|
|
212
380
|
}
|
|
213
381
|
|
|
214
|
-
$
|
|
215
|
-
if ($
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
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`.' }
|
|
382
|
+
$runArguments = @{ AgentOutput = $agentOutput; PlanLines = [string[]]@($file.Lines); TranscriptPath = $TranscriptPath }
|
|
383
|
+
if ($null -ne $ReadTranscriptHead) { $runArguments['ReadTranscriptHead'] = $ReadTranscriptHead }
|
|
384
|
+
if (Test-IsPreflightRun @runArguments) {
|
|
385
|
+
if ($agentOutput -cnotmatch 'BLOCKED' -and -not (Test-HasPreflightSignal -AgentOutput $agentOutput)) {
|
|
386
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: preflight output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
|
|
221
387
|
}
|
|
222
|
-
return
|
|
388
|
+
return Get-PreflightRunBlockDecision -AgentOutput $agentOutput
|
|
223
389
|
}
|
|
224
390
|
|
|
225
|
-
if ($agentOutput -
|
|
226
|
-
|
|
391
|
+
if ($agentOutput -cmatch 'BLOCKED') {
|
|
392
|
+
$hasCheckedTask = @($file.Lines | Where-Object { $_ -match '^\s*-\s\[[xX]\]\s\[P\d+-T\d+\]' }).Count -gt 0
|
|
393
|
+
if ($agentOutput -cmatch 'BLOCKED at preflight \(before \[P0-T1\]\)' -and (Test-HasCanonicalBlockedText -AgentOutput $agentOutput) -and -not $hasCheckedTask) {
|
|
394
|
+
return @{ Ok = $true; Message = $null }
|
|
395
|
+
}
|
|
396
|
+
return @{ Ok = $false; Repairable = $false; Message = 'atomic-executor hook: blocking is permitted only during preflight validation (before [P0-T1]).' }
|
|
227
397
|
}
|
|
228
398
|
|
|
229
|
-
$checkboxLineCount =
|
|
399
|
+
$checkboxLineCount = @($file.Lines | Where-Object { $_ -match '^\s*-\s\[(?:\s|[xX])\]\s' }).Count
|
|
230
400
|
$uncheckedLineNumbers = [System.Collections.Generic.List[int]]::new()
|
|
231
|
-
$uncheckedPattern = '^\s*-\s\[\s\]\s'
|
|
232
|
-
$checkedPattern = '^\s*-\s\[[xX]\]\s'
|
|
233
|
-
|
|
234
401
|
for ($i = 0; $i -lt $file.Lines.Count; $i++) {
|
|
235
|
-
|
|
236
|
-
if ($line -match $uncheckedPattern) {
|
|
237
|
-
$checkboxLineCount++
|
|
402
|
+
if ($file.Lines[$i] -match '^\s*-\s\[\s\]\s') {
|
|
238
403
|
$uncheckedLineNumbers.Add($i + 1)
|
|
239
404
|
}
|
|
240
|
-
elseif ($line -match $checkedPattern) {
|
|
241
|
-
$checkboxLineCount++
|
|
242
|
-
}
|
|
243
405
|
}
|
|
244
406
|
|
|
245
407
|
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." }
|
|
408
|
+
return @{ Ok = $false; Repairable = $false; Message = "atomic-executor hook: plan file '$planPath' contains no task checkboxes; executor cannot complete against an empty plan." }
|
|
247
409
|
}
|
|
248
410
|
|
|
249
411
|
if ($uncheckedLineNumbers.Count -gt 0) {
|
|
@@ -253,31 +415,23 @@ function Invoke-ExecutorOutputValidation {
|
|
|
253
415
|
$reported = $uncheckedLineNumbers.GetRange(0, 5)
|
|
254
416
|
$suffix = ' (showing first 5)'
|
|
255
417
|
}
|
|
256
|
-
$
|
|
257
|
-
|
|
258
|
-
return @{ Ok = $false; Message = $message }
|
|
418
|
+
$message = "atomic-executor hook: plan file '$planPath' has $($uncheckedLineNumbers.Count) unchecked task(s) at line(s) $($reported -join ', ')${suffix}. All `- [ ]` items must be ticked to `- [x]` before termination."
|
|
419
|
+
return @{ Ok = $false; Repairable = $true; Message = $message }
|
|
259
420
|
}
|
|
260
421
|
|
|
261
422
|
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.' }
|
|
423
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: completion output must include an `AC Status Summary` section.' }
|
|
263
424
|
}
|
|
264
425
|
|
|
265
|
-
$hasCommandEvidence = $agentOutput -match '(?i)(Commands Run|Command[s]?:|poetry run |npx |pwsh |git |mcp__drm-copilot__)'
|
|
426
|
+
$hasCommandEvidence = $agentOutput -match '(?i)(Commands Run|Command[s]?:|poetry[ ]run |npx |pwsh |git |mcp__drm-copilot__)'
|
|
266
427
|
$hasStatusEvidence = $agentOutput -match '(?i)\b(PASS|FAIL)\b'
|
|
267
428
|
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.' }
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
$missingLanguageStatuses = [System.Collections.Generic.List[string]]::new()
|
|
272
|
-
foreach ($language in Get-TouchedLanguagesFromPlan -Lines $file.Lines) {
|
|
273
|
-
if (-not (Test-OutputHasLanguageStatus -AgentOutput $agentOutput -Language $language)) {
|
|
274
|
-
$missingLanguageStatuses.Add($language)
|
|
275
|
-
}
|
|
429
|
+
return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: completion output must report commands run and pass/fail status results.' }
|
|
276
430
|
}
|
|
277
431
|
|
|
432
|
+
$missingLanguageStatuses = @(Get-TouchedLanguagesFromPlan -Lines $file.Lines | Where-Object { -not (Test-OutputHasLanguageStatus -AgentOutput $agentOutput -Language $_) })
|
|
278
433
|
if ($missingLanguageStatuses.Count -gt 0) {
|
|
279
|
-
$
|
|
280
|
-
return @{ Ok = $false; Message = "atomic-executor hook: completion output is missing explicit PASS/FAIL toolchain status lines for: $missingList." }
|
|
434
|
+
return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: completion output is missing explicit PASS/FAIL toolchain status lines for: $($missingLanguageStatuses -join ', ')." }
|
|
281
435
|
}
|
|
282
436
|
|
|
283
437
|
return @{ Ok = $true; Message = $null }
|
|
@@ -287,10 +441,10 @@ if ($MyInvocation.InvocationName -eq '.') {
|
|
|
287
441
|
return
|
|
288
442
|
}
|
|
289
443
|
|
|
290
|
-
$
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
444
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('validate-executor-output: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
445
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-executor-output:'
|
|
446
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
447
|
+
try { $result = Invoke-ExecutorOutputValidation }
|
|
448
|
+
catch { Exit-SubagentStopBlock -Message ('validate-executor-output: validator error: ' + ([string]$_.Exception.Message -split "`r?`n")[0] + '; the gate fails closed.' + "`n" + $script:SubagentStopReportAndHaltLine) }
|
|
449
|
+
if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
|
|
296
450
|
exit 0
|