@danmoisan/drm-copilot-mcp 1.1.22 → 1.1.24
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 +18758 -12030
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -0
- package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
- package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +101 -43
- package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +107 -43
- package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +60 -6
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/pr-author.md +48 -7
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +117 -42
- package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +103 -43
- package/resources/claude-customizations/.claude/hooks/discovery-capability-probe.ps1 +102 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +69 -194
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-planning-gate.ps1 +87 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +29 -7
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
- package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +51 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +168 -48
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +51 -4
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +72 -11
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +4 -2
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/record-discovery-agent-start.ps1 +132 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +56 -212
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-rejection.ps1 +172 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +34 -4
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +9 -3
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusAggregate.psm1 +154 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusCombination.psm1 +228 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +1 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +4 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +63 -16
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +56 -1
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +4 -1
- package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +5 -1
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +25 -2
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +188 -341
- package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
- package/resources/claude-customizations/.claude/lib/worktree-resolution/HookTargetWorktree.psm1 +391 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
- package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +29 -5
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +152 -20
- package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
- package/resources/claude-customizations/.claude/rules/shell.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +36 -3
- package/resources/claude-customizations/.claude/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/claude-customizations/.claude/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
- package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +28 -47
- package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +32 -48
- package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +28 -45
- package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +28 -62
- package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +28 -45
- package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +28 -61
- package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +55 -139
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +25 -10
- package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
- package/resources/claude-customizations/.claude/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/claude-customizations/.claude/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +15 -7
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +25 -2
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +124 -14
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +72 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +56 -9
- package/resources/claude-customizations/.claude/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/claude-customizations/.claude/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
- package/resources/claude-customizations/config/blast-radius.json +6 -5
- package/resources/claude-customizations/config/orchestration-routing.json +61 -1
- package/resources/claude-customizations/pack-manifests/core.json +40 -1
- package/resources/codex-and-agents-customizations/.agents/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +7 -0
- package/resources/codex-and-agents-customizations/.agents/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-coverage-ledger/SKILL.md +50 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-parity-matrix/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-repo-inventory/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-runtime-characterization/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-validate-artifacts/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-workflow/SKILL.md +62 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +25 -10
- package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
- package/resources/codex-and-agents-customizations/.agents/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/codex-and-agents-customizations/.agents/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/codex-and-agents-customizations/.agents/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/discovery-capability-sentinel.toml +51 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c1.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c2.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3-elevated.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c4.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c1.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c2.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3-elevated.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c4.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c1.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c2.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3-elevated.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c4.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c1.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c2.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3-elevated.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c4.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +39 -3
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +22 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/discovery-capability-probe.ps1 +97 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1 +171 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +4 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1 +187 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1 +149 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +239 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +54 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +54 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-target-worktree.ps1 +369 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +8 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +22 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1 +178 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +11 -1
- package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +65 -1
- package/resources/config/orchestration-routing.json +61 -1
- package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
- package/resources/customizations/.github/agents/discovery-capability-sentinel.agent.md +34 -0
- package/resources/customizations/.github/agents/legacy-parity-analyst.agent.md +122 -0
- package/resources/customizations/.github/agents/migration-coverage-reviewer.agent.md +128 -0
- package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
- package/resources/customizations/.github/agents/requirements-reconciler.agent.md +138 -0
- package/resources/customizations/.github/agents/runtime-characterization-analyst.agent.md +124 -0
- package/resources/customizations/.github/hooks/discovery-agent-start.ps1 +139 -0
- package/resources/customizations/.github/hooks/discovery-agent-stop.ps1 +123 -0
- package/resources/customizations/.github/hooks/discovery-capability-probe.ps1 +98 -0
- package/resources/customizations/.github/hooks/discovery-planning.ps1 +91 -0
- package/resources/customizations/.github/hooks/discovery-pre-tool.ps1 +123 -0
- package/resources/customizations/.github/hooks/discovery.json +35 -0
- package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
- package/resources/customizations/.github/instructions/mermaid.instructions.md +85 -0
- package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
- package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
- package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
- package/resources/customizations/.github/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/customizations/.github/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/customizations/.github/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-coverage-ledger/SKILL.md +50 -0
- package/resources/customizations/.github/skills/discovery-parity-matrix/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-repo-inventory/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-runtime-characterization/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-validate-artifacts/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-workflow/SKILL.md +62 -0
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +25 -10
- package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
- package/resources/customizations/.github/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/customizations/.github/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/customizations/.github/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/customizations/.github/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/customizations/.github/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/customizations/.github/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/lib/codex-routing/CodexDeployment.psm1 +5 -1
- package/resources/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
- package/resources/lib/codex-routing/CodexTopology.psm1 +25 -2
- package/resources/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
- package/resources/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
- package/resources/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
- package/resources/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
- package/resources/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
- package/resources/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
- package/resources/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
- package/resources/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
- package/resources/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
- package/resources/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
- package/resources/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
- package/resources/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
- package/resources/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
- package/resources/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
- package/resources/powershell/PoshQC/PoshQC.Parallel.psm1 +452 -0
- package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +106 -8
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -0
- package/resources/powershell/PoshQC/PoshQC.psd1 +6 -1
- package/resources/powershell/PoshQC/PoshQC.psm1 +7 -1
- package/resources/powershell/PoshQC/README.md +20 -1
- package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1
CHANGED
|
@@ -46,6 +46,8 @@ try { Import-Module (Join-Path $PSScriptRoot '../lib/cleanup-manifest/CleanupWor
|
|
|
46
46
|
try { . (Join-Path $PSScriptRoot 'hook-command-scanner.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-scanner.ps1' -ErrorRecord $_ }
|
|
47
47
|
try { . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-invocation.ps1' -ErrorRecord $_ }
|
|
48
48
|
|
|
49
|
+
# Shared recorded-path matcher and main-checkout-root seam (issue #995).
|
|
50
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunRecordPath.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeRunRecordPath.psm1' -ErrorRecord $_ }
|
|
49
51
|
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunResolution.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeRunResolution.psm1' -ErrorRecord $_ }
|
|
50
52
|
|
|
51
53
|
$script:AllowedMergeStatuses = @('merged', 'worktree_removed')
|
|
@@ -170,7 +172,10 @@ function Find-ParallelWorktreeItemRecord {
|
|
|
170
172
|
Name of the record array to scan. Defaults to 'items', the parallel
|
|
171
173
|
checkpoint's array, so every existing caller is unchanged; the epic branch
|
|
172
174
|
added for issue #688 passes 'features'. Parameterized rather than duplicated
|
|
173
|
-
so both topologies share one path-
|
|
175
|
+
so both topologies share one path-comparison implementation.
|
|
176
|
+
.PARAMETER BaseRoot
|
|
177
|
+
Optional. The roots a relative recorded worktree_path is joined to (issue #995).
|
|
178
|
+
With none, a relative record matches nothing.
|
|
174
179
|
.OUTPUTS
|
|
175
180
|
System.Object or $null
|
|
176
181
|
#>
|
|
@@ -183,7 +188,11 @@ function Find-ParallelWorktreeItemRecord {
|
|
|
183
188
|
[string] $WorktreePath,
|
|
184
189
|
|
|
185
190
|
[ValidateNotNullOrEmpty()]
|
|
186
|
-
[string] $RecordArrayName = 'items'
|
|
191
|
+
[string] $RecordArrayName = 'items',
|
|
192
|
+
|
|
193
|
+
[AllowNull()]
|
|
194
|
+
[AllowEmptyCollection()]
|
|
195
|
+
[string[]] $BaseRoot = @()
|
|
187
196
|
)
|
|
188
197
|
|
|
189
198
|
if ($null -eq $Checkpoint -or [string]::IsNullOrWhiteSpace($WorktreePath)) {
|
|
@@ -194,17 +203,14 @@ function Find-ParallelWorktreeItemRecord {
|
|
|
194
203
|
return $null
|
|
195
204
|
}
|
|
196
205
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
# Scan every recorded item for a worktree_path that matches the removal target;
|
|
200
|
-
# path separators are normalized so Windows- and POSIX-style paths compare equal.
|
|
206
|
+
# Scan every recorded item for a worktree_path that names the removal target through
|
|
207
|
+
# the shared matcher (separator style, trailing slash, case rule, relative join).
|
|
201
208
|
foreach ($item in @($Checkpoint.$RecordArrayName)) {
|
|
202
209
|
$itemProps = @($item.PSObject.Properties.Name)
|
|
203
210
|
if ($itemProps -notcontains 'worktree_path') {
|
|
204
211
|
continue
|
|
205
212
|
}
|
|
206
|
-
|
|
207
|
-
if ($normalizedItemPath -eq $normalizedTarget) {
|
|
213
|
+
if (Test-WorktreeRunRecordedPathMatchesTarget -RecordedPath ([string]$item.worktree_path) -TargetPath $WorktreePath -BaseRoot $BaseRoot) {
|
|
208
214
|
return $item
|
|
209
215
|
}
|
|
210
216
|
}
|
|
@@ -353,8 +359,13 @@ function Get-ParallelWorktreeRemovalTargetDenial {
|
|
|
353
359
|
}
|
|
354
360
|
}
|
|
355
361
|
$checkpoint = $parallelRead.Checkpoint
|
|
362
|
+
# A relative record is joined to the main checkout root and to the root holding the
|
|
363
|
+
# checkpoint read (issue #995); the main root is derived once per target.
|
|
364
|
+
$mainRoot = Get-WorktreeRunMainCheckoutRoot -SessionRoot (Get-Location).Path
|
|
365
|
+
$parallelBaseRoot = Get-WorktreeRunRecordBaseRoot -MainRoot $mainRoot -Read $parallelRead
|
|
366
|
+
$epicBaseRoot = Get-WorktreeRunRecordBaseRoot -MainRoot $mainRoot -Read $epicRead
|
|
356
367
|
|
|
357
|
-
$itemRecord = Find-ParallelWorktreeItemRecord -Checkpoint $checkpoint -WorktreePath $worktreePath
|
|
368
|
+
$itemRecord = Find-ParallelWorktreeItemRecord -Checkpoint $checkpoint -WorktreePath $worktreePath -BaseRoot $parallelBaseRoot
|
|
358
369
|
if (Test-ParallelWorktreeRemovalAllowed -ItemRecord $itemRecord) {
|
|
359
370
|
return $null
|
|
360
371
|
}
|
|
@@ -371,7 +382,7 @@ function Get-ParallelWorktreeRemovalTargetDenial {
|
|
|
371
382
|
# $null, which yields no record, which is not allowed.
|
|
372
383
|
$epicCheckpoint = $epicRead.Checkpoint
|
|
373
384
|
|
|
374
|
-
$featureRecord = Find-ParallelWorktreeItemRecord -Checkpoint $epicCheckpoint -WorktreePath $worktreePath -RecordArrayName 'features'
|
|
385
|
+
$featureRecord = Find-ParallelWorktreeItemRecord -Checkpoint $epicCheckpoint -WorktreePath $worktreePath -RecordArrayName 'features' -BaseRoot $epicBaseRoot
|
|
375
386
|
if (Test-ParallelWorktreeRemovalAllowed -ItemRecord $featureRecord) {
|
|
376
387
|
return $null
|
|
377
388
|
}
|
|
@@ -386,7 +397,7 @@ function Get-ParallelWorktreeRemovalTargetDenial {
|
|
|
386
397
|
# reaches the unchanged deny below. This gate defines only the parallel checkpoint
|
|
387
398
|
# seam and has no epic-checkpoint seam, so its exclusion covers the items array
|
|
388
399
|
# only; the epic gate covers the features array with its own exclusion.
|
|
389
|
-
if (-not (Test-CleanupManifestCheckpointCoversPath -Checkpoint $checkpoint -RecordArrayName 'items' -WorktreePath $worktreePath) -and
|
|
400
|
+
if (-not (Test-CleanupManifestCheckpointCoversPath -Checkpoint $checkpoint -RecordArrayName 'items' -WorktreePath $worktreePath -BaseRoot $parallelBaseRoot) -and
|
|
390
401
|
(Test-CleanupWorktreeManifestAuthorizesRemoval -WorktreePath $worktreePath)) {
|
|
391
402
|
return $null
|
|
392
403
|
}
|
|
@@ -7,14 +7,28 @@
|
|
|
7
7
|
operation. When the target file is a PowerShell source file (.ps1, .psm1, .psd1),
|
|
8
8
|
it decides whether the change may proceed in direct mode.
|
|
9
9
|
|
|
10
|
-
Direct mode counts distinct production PowerShell paths per Claude Code session
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The
|
|
17
|
-
|
|
10
|
+
Direct mode counts distinct production PowerShell paths per Claude Code session and
|
|
11
|
+
per resolved target worktree, and repeated edits to the same file are counted once.
|
|
12
|
+
The 4th distinct production path in one worktree is denied with a
|
|
13
|
+
POWERSHELL_LARGE_PATH_REQUIRED reason that instructs the caller to route the change
|
|
14
|
+
through /orchestrate.
|
|
15
|
+
|
|
16
|
+
The edited file is placed with Resolve-HookTargetWorktree from
|
|
17
|
+
.claude/lib/worktree-resolution/HookTargetWorktree.psm1. An absolute path resolves to
|
|
18
|
+
its nearest enclosing registered git worktree; a relative path, a path inside no
|
|
19
|
+
registered worktree, and an ambiguous result use the session root (the checkout that
|
|
20
|
+
holds this hook). The route is read from
|
|
21
|
+
artifacts/orchestration/orchestrator-state.json in the resolved target worktree.
|
|
22
|
+
The running set is kept under the session root, in
|
|
23
|
+
.claude/state/powershell-batch-budget.<session_id>.json when the resolved target worktree
|
|
24
|
+
is the session root and in
|
|
25
|
+
.claude/state/powershell-batch-budget.<session_id>.<worktree key>.json otherwise,
|
|
26
|
+
where the key comes from Get-HookTargetWorktreeKey; no state is written under another
|
|
27
|
+
worktree. A path under the root-level artifacts/ directory of the resolved target worktree
|
|
28
|
+
is gitignored scratch: it is allowed, consumes no slot, and writes no state. A
|
|
29
|
+
nested directory named artifacts elsewhere in the tree still counts.
|
|
30
|
+
|
|
31
|
+
The selected route is the
|
|
18
32
|
route_id value when that key is present, otherwise the path_selected value, and it
|
|
19
33
|
is usable only as a non-blank string. When the selected route is large,
|
|
20
34
|
remediation, or preparation and the checkpoint is not terminal (next_step is not
|
|
@@ -38,9 +52,9 @@
|
|
|
38
52
|
is composed into a file name, so a hostile id cannot escape the state
|
|
39
53
|
directory. Resolving the id never creates the state directory.
|
|
40
54
|
|
|
41
|
-
Candidate paths are contained to the resolved root. A candidate
|
|
42
|
-
outside it is discarded: the decision is 'allow', no slot is consumed,
|
|
43
|
-
state is written. Persisted entries that fail the same containment test are
|
|
55
|
+
Candidate paths are contained to the resolved target worktree root. A candidate
|
|
56
|
+
that resolves outside it is discarded: the decision is 'allow', no slot is consumed,
|
|
57
|
+
and no state is written. Persisted entries that fail the same containment test are
|
|
44
58
|
dropped when state is rehydrated, so a state file carried between worktrees
|
|
45
59
|
cannot spend this worktree's budget.
|
|
46
60
|
|
|
@@ -48,9 +62,12 @@
|
|
|
48
62
|
hookSpecificOutput.permissionDecision = 'deny' and exits 0. Files already counted
|
|
49
63
|
are always allowed through.
|
|
50
64
|
|
|
51
|
-
Known
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
Known limitations: an 8.3 short-name path, or a path reached through a junction,
|
|
66
|
+
that differs textually from the long path git reports matches no registered
|
|
67
|
+
worktree and falls back to the session root. A stale non-terminal large-path
|
|
68
|
+
checkpoint in a worktree exempts a later direct-mode session editing that worktree;
|
|
69
|
+
orchestrator checkpoint hygiene (issue #673) moves foreign checkpoints aside before
|
|
70
|
+
a new run.
|
|
54
71
|
|
|
55
72
|
.NOTES
|
|
56
73
|
Compatible with PowerShell 7+.
|
|
@@ -61,6 +78,7 @@ $script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot
|
|
|
61
78
|
|
|
62
79
|
|
|
63
80
|
try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
|
|
81
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/HookTargetWorktree.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookTargetWorktree.psm1' -ErrorRecord $_ }
|
|
64
82
|
$script:PowerShellBatchBudgetRouteImportFailure = $null; try { . (Join-Path $PSScriptRoot 'enforce-batch-budget-route.ps1') } catch { $script:PowerShellBatchBudgetRouteImportFailure = 'enforce-batch-budget-route.ps1' }
|
|
65
83
|
|
|
66
84
|
function Test-PowerShellBatchBudgetPathInRoot {
|
|
@@ -351,7 +369,8 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
351
369
|
[scriptblock] $WriteState = {
|
|
352
370
|
param([string] $Path, [System.Collections.IDictionary] $State)
|
|
353
371
|
$State | ConvertTo-Json -Depth 5 | Set-Content -Path $Path -Encoding UTF8
|
|
354
|
-
}
|
|
372
|
+
},
|
|
373
|
+
[scriptblock] $WorktreeListInvoker
|
|
355
374
|
)
|
|
356
375
|
|
|
357
376
|
$payload = Resolve-ClaudeHookToolInput -Raw $ToolInputRaw
|
|
@@ -373,6 +392,25 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
373
392
|
}
|
|
374
393
|
if ($script:PowerShellBatchBudgetRouteImportFailure) { return Get-PowerShellBatchBudgetBlockDecision -Reason "POWERSHELL_LARGE_PATH_REQUIRED: the route helper '$($script:PowerShellBatchBudgetRouteImportFailure)' failed to load, so the batch budget for '$normalized' cannot be evaluated; the gate fails closed." }
|
|
375
394
|
|
|
395
|
+
# The file is evaluated against the registered worktree that holds it. The session root
|
|
396
|
+
# stays the fallback for a relative path, a path in no registered worktree, and an
|
|
397
|
+
# ambiguous result, which keeps today's checkpoint, containment, and state-file name.
|
|
398
|
+
$resolverArguments = @{ SessionRoot = $Root; FilePath = @($filePath) }
|
|
399
|
+
if ($PSBoundParameters.ContainsKey('WorktreeListInvoker')) { $resolverArguments['WorktreeListInvoker'] = $WorktreeListInvoker }
|
|
400
|
+
$resolution = Resolve-HookTargetWorktree @resolverArguments
|
|
401
|
+
$targetRoot = $Root
|
|
402
|
+
$isSessionRoot = $true
|
|
403
|
+
if (-not $resolution.Ambiguous -and $null -ne $resolution.WorktreeRoot -and -not [string]::Equals($resolution.WorktreeRoot, (ConvertTo-HookTargetWorktreeNormalizedPath -Path $Root), [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
404
|
+
$targetRoot = $resolution.WorktreeRoot
|
|
405
|
+
$isSessionRoot = $false
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
# The root-level artifacts/ directory is gitignored scratch, never a production file.
|
|
409
|
+
$relativePath = if ($normalized -match '^(/|[A-Za-z]:/)') { Get-HookTargetWorktreeRelativePath -Path $normalized -WorktreeRoot $targetRoot } else { $normalized }
|
|
410
|
+
if ($null -ne $relativePath -and $relativePath.StartsWith('artifacts/', [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
411
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
412
|
+
}
|
|
413
|
+
|
|
376
414
|
$stateDir = Join-Path -Path $Root -ChildPath '.claude/state'
|
|
377
415
|
|
|
378
416
|
# Resolved before the directory is ensured, because reading the session-id
|
|
@@ -383,11 +421,12 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
383
421
|
-SessionIdFilePath (Join-Path -Path $stateDir -ChildPath 'current-session-id') `
|
|
384
422
|
-ReadSessionIdFile $ReadSessionIdFile
|
|
385
423
|
|
|
386
|
-
$
|
|
424
|
+
$stateLeaf = if ($isSessionRoot) { "powershell-batch-budget.$resolvedSessionId.json" } else { "powershell-batch-budget.$resolvedSessionId.$(Get-HookTargetWorktreeKey -WorktreeRoot $targetRoot).json" }
|
|
425
|
+
$stateFile = Join-Path -Path $stateDir -ChildPath $stateLeaf
|
|
387
426
|
|
|
388
427
|
# The checkpoint is read before any state operation, so the large path neither
|
|
389
428
|
# creates the state directory nor reads or writes the state file.
|
|
390
|
-
$checkpointPath = Join-Path -Path $
|
|
429
|
+
$checkpointPath = Join-Path -Path $targetRoot -ChildPath 'artifacts/orchestration/orchestrator-state.json'
|
|
391
430
|
$checkpointText = ''
|
|
392
431
|
try {
|
|
393
432
|
$checkpointText = [string](& $ReadCheckpoint $checkpointPath)
|
|
@@ -399,7 +438,7 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
399
438
|
$isLargePath = Test-BatchBudgetLargePathRoute -CheckpointText $checkpointText
|
|
400
439
|
$observedRoute = Get-BatchBudgetSelectedRoute -CheckpointText $checkpointText
|
|
401
440
|
if ($isLargePath) {
|
|
402
|
-
return Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State (Get-PowerShellBatchBudgetState -ProdCap $ProdCap) -StateFile $stateFile -Root $
|
|
441
|
+
return Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State (Get-PowerShellBatchBudgetState -ProdCap $ProdCap) -StateFile $stateFile -Root $targetRoot -LargePathRoute
|
|
403
442
|
}
|
|
404
443
|
|
|
405
444
|
if (-not (& $TestPathExists $stateDir)) {
|
|
@@ -411,13 +450,13 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
411
450
|
if (& $TestPathExists $stateFile) {
|
|
412
451
|
try {
|
|
413
452
|
$loaded = & $ReadState $stateFile | ConvertFrom-Json -ErrorAction Stop
|
|
414
|
-
$state = ConvertTo-PowerShellBatchBudgetState -InputObject $loaded -ProdCap $ProdCap -Root $
|
|
453
|
+
$state = ConvertTo-PowerShellBatchBudgetState -InputObject $loaded -ProdCap $ProdCap -Root $targetRoot
|
|
415
454
|
} catch {
|
|
416
455
|
Write-Verbose "Ignoring unreadable PowerShell batch-budget state file '$stateFile': $($_.Exception.Message)"
|
|
417
456
|
}
|
|
418
457
|
}
|
|
419
458
|
|
|
420
|
-
$decision = Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State $state -StateFile $stateFile -Root $
|
|
459
|
+
$decision = Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State $state -StateFile $stateFile -Root $targetRoot -ObservedRoute $observedRoute
|
|
421
460
|
if ($decision.shouldWriteState) {
|
|
422
461
|
try {
|
|
423
462
|
& $WriteState $stateFile $decision.state
|
package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1
CHANGED
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
in one of these forms, matched by token position:
|
|
11
11
|
|
|
12
12
|
- git log ... and git rev-parse ... (no git global option)
|
|
13
|
+
- git worktree list --porcelain (exactly these four tokens, issue #1011)
|
|
13
14
|
- gh pr create ... and gh pr edit ... (no gh global option)
|
|
15
|
+
- gh pr view <N> --json closingIssuesReferences,body (exactly these six tokens, issue #989)
|
|
14
16
|
- sha256sum artifacts/pr_body_<N>.md (only as the whole command)
|
|
17
|
+
- sha256sum <item worktree>/artifacts/pr_body_<N>.md (only as the whole command; an absolute
|
|
18
|
+
forward-slash path, issue #1011)
|
|
15
19
|
- date -u [+<format>] (only as the whole command)
|
|
16
20
|
|
|
17
21
|
Segments may be joined only by ';', '&&', '||', '|', or a newline. A record that is
|
|
@@ -41,7 +45,38 @@ $script:PrAuthorAllowlistWrapperWords = @(
|
|
|
41
45
|
'sh', 'bash', 'zsh', 'dash', 'ksh', 'pwsh', 'powershell', 'eval', 'xargs',
|
|
42
46
|
'env', 'timeout', 'time', 'command', 'nohup'
|
|
43
47
|
)
|
|
44
|
-
$script:PrAuthorAllowlistFormText = 'git log, git rev-parse, gh pr create, gh pr edit, sha256sum artifacts/pr_body_<N>.md, date -u [+<format>]'
|
|
48
|
+
$script:PrAuthorAllowlistFormText = 'git log, git rev-parse, git worktree list --porcelain, gh pr create, gh pr edit, gh pr view <N> --json closingIssuesReferences,body, sha256sum artifacts/pr_body_<N>.md, sha256sum <item worktree>/artifacts/pr_body_<N>.md, date -u [+<format>]'
|
|
49
|
+
|
|
50
|
+
function Test-PrAuthorAbsoluteBodyPathToken {
|
|
51
|
+
<#
|
|
52
|
+
.SYNOPSIS
|
|
53
|
+
Report whether a token is an absolute canonical body path beneath an item worktree (issue #1011).
|
|
54
|
+
.DESCRIPTION
|
|
55
|
+
The token must be rooted at '/' or at a drive letter followed by ':/', use forward slashes
|
|
56
|
+
only, hold at least one segment before 'artifacts', hold no empty, '.', or '..' segment,
|
|
57
|
+
and end in '/artifacts/pr_body_<digits>.md' with the exact case of the relative form.
|
|
58
|
+
Pure string logic: no process, file read, or module import.
|
|
59
|
+
.PARAMETER Value
|
|
60
|
+
The sha256sum argument token, quotes already stripped.
|
|
61
|
+
.OUTPUTS
|
|
62
|
+
System.Boolean
|
|
63
|
+
#>
|
|
64
|
+
[CmdletBinding()]
|
|
65
|
+
[OutputType([bool])]
|
|
66
|
+
param(
|
|
67
|
+
[Parameter(Mandatory)][AllowEmptyString()][string] $Value
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if ($Value.Contains('\') -or $Value -cnotmatch '^(/|[A-Za-z]:/)(?<rest>.+)/artifacts/pr_body_\d+\.md$') {
|
|
71
|
+
return $false
|
|
72
|
+
}
|
|
73
|
+
foreach ($segment in $Matches['rest'].Split('/')) {
|
|
74
|
+
if ($segment -eq '' -or $segment -eq '.' -or $segment -eq '..') {
|
|
75
|
+
return $false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return $true
|
|
79
|
+
}
|
|
45
80
|
|
|
46
81
|
function Test-PrAuthorAllowlistForm {
|
|
47
82
|
<#
|
|
@@ -66,13 +101,25 @@ function Test-PrAuthorAllowlistForm {
|
|
|
66
101
|
}
|
|
67
102
|
switch -CaseSensitive ($Token[0]) {
|
|
68
103
|
'git' {
|
|
69
|
-
|
|
104
|
+
if ($Token.Count -ge 2 -and @('log', 'rev-parse') -ccontains $Token[1]) {
|
|
105
|
+
return $true
|
|
106
|
+
}
|
|
107
|
+
# The read-only worktree discovery form, matched exactly (issue #1011).
|
|
108
|
+
return ($Token.Count -eq 4 -and $Token[1] -ceq 'worktree' -and $Token[2] -ceq 'list' -and $Token[3] -ceq '--porcelain')
|
|
70
109
|
}
|
|
71
110
|
'gh' {
|
|
72
|
-
|
|
111
|
+
if ($Token.Count -ge 3 -and $Token[1] -ceq 'pr' -and @('create', 'edit') -ccontains $Token[2]) {
|
|
112
|
+
return $true
|
|
113
|
+
}
|
|
114
|
+
# The read-only closing-reference verification form, matched exactly (issue #989).
|
|
115
|
+
return ($Token.Count -eq 6 -and $Token[1] -ceq 'pr' -and $Token[2] -ceq 'view' -and $Token[3] -cmatch '^\d+$' -and
|
|
116
|
+
$Token[4] -ceq '--json' -and $Token[5] -ceq 'closingIssuesReferences,body')
|
|
73
117
|
}
|
|
74
118
|
'sha256sum' {
|
|
75
|
-
|
|
119
|
+
if (-not $IsWholeCommand -or $Token.Count -ne 2) {
|
|
120
|
+
return $false
|
|
121
|
+
}
|
|
122
|
+
return ($Token[1] -cmatch '^artifacts/pr_body_\d+\.md$' -or (Test-PrAuthorAbsoluteBodyPathToken -Value $Token[1]))
|
|
76
123
|
}
|
|
77
124
|
'date' {
|
|
78
125
|
if (-not $IsWholeCommand -or $Token.Count -lt 2 -or $Token[1] -cne '-u') {
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
|
|
28
28
|
.NOTES
|
|
29
29
|
Compatible with PowerShell 7+. Dependencies are in-repository only: the command parsers
|
|
30
|
-
and worktree-resolution modules loaded below, and the artifact-root
|
|
31
|
-
No PowerShell Gallery module is required.
|
|
32
|
-
The docs-only sibling runs the git executable at call time (issue #901)
|
|
30
|
+
and worktree-resolution modules loaded below, and the artifact-root, docs-only, and
|
|
31
|
+
current-branch siblings. No PowerShell Gallery module is required.
|
|
32
|
+
The docs-only sibling runs the git executable at call time (issue #901), and so does the
|
|
33
|
+
current-branch sibling when a call carries no target signal (issue #989).
|
|
33
34
|
#>
|
|
34
35
|
[CmdletBinding()]
|
|
35
36
|
param()
|
|
@@ -49,6 +50,8 @@ Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeTarge
|
|
|
49
50
|
# feature folder exists in every checkout branched from main, so it places a call in many at
|
|
50
51
|
# once. The item is identified by its canonical issue number and its branch instead.
|
|
51
52
|
Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeItemResolution.psm1') -Force -ErrorAction Stop
|
|
53
|
+
# Shared target-worktree resolver (issues #1009, #1011): resolves the branch a --head names.
|
|
54
|
+
Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/HookTargetWorktree.psm1') -Force -ErrorAction Stop
|
|
52
55
|
# Epic scope (issue #663): the epic integration pull request is gated against the epic checkpoint.
|
|
53
56
|
Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/EpicScopeResolution.psm1') -Force -ErrorAction Stop
|
|
54
57
|
Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/EpicScopeReadiness.psm1') -Force -ErrorAction Stop
|
|
@@ -56,6 +59,8 @@ Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/EpicScopeRead
|
|
|
56
59
|
. (Join-Path $PSScriptRoot 'enforce-pr-author-skill.artifact-root.ps1')
|
|
57
60
|
# Docs-only exemption from the orchestrator-state preflight (issue #901).
|
|
58
61
|
. (Join-Path $PSScriptRoot 'enforce-pr-author-skill.docs-only.ps1')
|
|
62
|
+
# Current-branch target derivation and the no-target guidance text (issue #989).
|
|
63
|
+
. (Join-Path $PSScriptRoot 'enforce-pr-author-skill.current-branch.ps1')
|
|
59
64
|
|
|
60
65
|
function Resolve-PrAuthorWorktreeTarget {
|
|
61
66
|
<#
|
|
@@ -67,9 +72,15 @@ function Resolve-PrAuthorWorktreeTarget {
|
|
|
67
72
|
directly would depend on the machine's live worktrees and would pass or fail
|
|
68
73
|
according to what other sessions happen to have checked out, which the repository's
|
|
69
74
|
determinism policy forbids. Mocking here lets a test state the resolution outcome it
|
|
70
|
-
is exercising and nothing else.
|
|
75
|
+
is exercising and nothing else. A branch the command names (--head, --branch, or
|
|
76
|
+
branch:) is resolved by the shared resolver Resolve-HookTargetWorktree, given only the
|
|
77
|
+
session root and that branch (issue #1011), unless the command also carries a canonical
|
|
78
|
+
issue number line, which Resolve-WorktreeItemTarget decides so the branch/issue agreement
|
|
79
|
+
check applies. Without a selection, Resolve-WorktreeItemTarget runs, and a NoTarget result
|
|
80
|
+
for a command with no signal passes through Resolve-PrAuthorCurrentBranchTarget, which
|
|
81
|
+
re-resolves the current branch (#989).
|
|
71
82
|
.OUTPUTS
|
|
72
|
-
|
|
83
|
+
A target result object built by New-WorktreeResolutionTargetResult.
|
|
73
84
|
#>
|
|
74
85
|
[CmdletBinding()]
|
|
75
86
|
param(
|
|
@@ -77,7 +88,57 @@ function Resolve-PrAuthorWorktreeTarget {
|
|
|
77
88
|
[string] $CommandText
|
|
78
89
|
)
|
|
79
90
|
|
|
80
|
-
|
|
91
|
+
$sessionRoot = (Get-Location).Path
|
|
92
|
+
$branch = Find-WorktreeResolutionBranchSignal -Text $CommandText
|
|
93
|
+
$issueSignal = Find-WorktreeItemIssueSignal -Text $CommandText
|
|
94
|
+
if ($null -ne $branch -and @($issueSignal).Count -eq 0) {
|
|
95
|
+
$shared = Resolve-HookTargetWorktree -SessionRoot $sessionRoot -CommandBranch $branch
|
|
96
|
+
$mapped = ConvertFrom-PrAuthorHookTargetResult -Result $shared -CommandText $CommandText -SessionRoot $sessionRoot
|
|
97
|
+
if ($null -ne $mapped) { return $mapped }
|
|
98
|
+
}
|
|
99
|
+
$target = Resolve-WorktreeItemTarget -Text $CommandText -SessionRoot $sessionRoot
|
|
100
|
+
return (Resolve-PrAuthorCurrentBranchTarget -CommandText $CommandText -Target $target)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function ConvertFrom-PrAuthorHookTargetResult {
|
|
104
|
+
<#
|
|
105
|
+
.SYNOPSIS
|
|
106
|
+
Map a Resolve-HookTargetWorktree result onto a pr-author target result, or $null (issue #1011).
|
|
107
|
+
.DESCRIPTION
|
|
108
|
+
Returns $null (no selection) when Result is null, when CommandText carries no branch
|
|
109
|
+
signal, when Result.Source is not CommandOperand, when Result names no root, or when that
|
|
110
|
+
root fails Test-WorktreeResolutionRootMarker (a registration whose directory is gone).
|
|
111
|
+
Only a CommandOperand result selects, being branch-derived; a FilePath, SessionRoot, or
|
|
112
|
+
DelegationIdentity result never selects the worktree (issue #673). An ambiguous result
|
|
113
|
+
maps to Ambiguous. Labelling is delegated to ConvertTo-WorktreeItemResolvedResult, which
|
|
114
|
+
maps a root equal to SessionRoot, or to the worktree enclosing it, to SessionRoot and any
|
|
115
|
+
other root to OtherWorktree.
|
|
116
|
+
.PARAMETER Result
|
|
117
|
+
The Resolve-HookTargetWorktree result.
|
|
118
|
+
.PARAMETER CommandText
|
|
119
|
+
The Bash command text under evaluation.
|
|
120
|
+
.PARAMETER SessionRoot
|
|
121
|
+
The session root the result is compared with.
|
|
122
|
+
.OUTPUTS
|
|
123
|
+
System.Management.Automation.PSCustomObject or $null
|
|
124
|
+
#>
|
|
125
|
+
[CmdletBinding()]
|
|
126
|
+
[OutputType([pscustomobject])]
|
|
127
|
+
param(
|
|
128
|
+
[AllowNull()][object] $Result,
|
|
129
|
+
[Parameter(Mandatory)][AllowEmptyString()][string] $CommandText,
|
|
130
|
+
[Parameter(Mandatory)][string] $SessionRoot
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
$branch = Find-WorktreeResolutionBranchSignal -Text $CommandText
|
|
134
|
+
if ($null -eq $Result -or $null -eq $branch -or $Result.Source -cne 'CommandOperand') { return $null }
|
|
135
|
+
$detail = if ([string]::IsNullOrWhiteSpace([string]$Result.Detail)) { "branch '$branch' resolved by the shared resolver" } else { [string]$Result.Detail }
|
|
136
|
+
if ($Result.Ambiguous) {
|
|
137
|
+
return (New-WorktreeResolutionTargetResult -Status Ambiguous -SessionRoot $SessionRoot -Signal Branch -SignalValue $branch -Candidate @($Result.Candidates) -Detail $detail)
|
|
138
|
+
}
|
|
139
|
+
if ([string]::IsNullOrEmpty([string]$Result.WorktreeRoot)) { return $null }
|
|
140
|
+
if (-not (Test-WorktreeResolutionRootMarker -Path $Result.WorktreeRoot)) { return $null }
|
|
141
|
+
return (ConvertTo-WorktreeItemResolvedResult -WorktreeRoot $Result.WorktreeRoot -SessionRoot $SessionRoot -Branch $branch -Detail $detail)
|
|
81
142
|
}
|
|
82
143
|
|
|
83
144
|
function Get-PrAuthorTargetCheckpointResolution {
|
|
@@ -91,10 +152,10 @@ function Get-PrAuthorTargetCheckpointResolution {
|
|
|
91
152
|
SessionRoot -> that worktree's own checkpoint, composed absolutely.
|
|
92
153
|
OtherWorktree -> that worktree's own checkpoint, composed the same way.
|
|
93
154
|
NoTarget -> deny, carrying the code Get-WorktreeResolutionNoTargetReasonCode
|
|
94
|
-
returns.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
session root.
|
|
155
|
+
returns. The call named no target and no branch could be derived
|
|
156
|
+
from the current checkout; the remedy text from
|
|
157
|
+
Get-PrAuthorTargetGuidanceText names the accepted forms, and the
|
|
158
|
+
gate never falls back to the session root's checkpoint.
|
|
98
159
|
Ambiguous -> deny, carrying the code
|
|
99
160
|
Get-WorktreeResolutionAmbiguityReasonCode returns.
|
|
100
161
|
|
|
@@ -125,7 +186,7 @@ function Get-PrAuthorTargetCheckpointResolution {
|
|
|
125
186
|
return [ordered]@{ CheckpointPath = (Get-WorktreeItemCheckpointPath -WorktreeRoot $target.WorktreeRoot); Reason = $null; WorktreeRoot = $target.WorktreeRoot; Status = $target.Status }
|
|
126
187
|
}
|
|
127
188
|
default {
|
|
128
|
-
$reason = "$($target.ReasonCode): $($target.Detail) The pr-author gate will not validate this call against the session root's checkpoint, because that checkpoint may belong to a different item.
|
|
189
|
+
$reason = "$($target.ReasonCode): $($target.Detail) The pr-author gate will not validate this call against the session root's checkpoint, because that checkpoint may belong to a different item. $(Get-PrAuthorTargetGuidanceText)"
|
|
129
190
|
return [ordered]@{ CheckpointPath = $null; Reason = $reason; WorktreeRoot = $null; Status = $target.Status }
|
|
130
191
|
}
|
|
131
192
|
}
|
package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Current-branch target derivation for enforce-pr-author-skill.ps1 (issue #989).
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Dot-sourced by enforce-pr-author-skill-helpers.ps1. Resolve-PrAuthorWorktreeTarget passes its
|
|
7
|
+
command-text resolution through Resolve-PrAuthorCurrentBranchTarget, which applies one
|
|
8
|
+
fallback: when the command carries no branch signal (--head, --branch, or branch:) and no
|
|
9
|
+
canonical issue line, and resolution returned NoTarget, the branch checked out in the hook
|
|
10
|
+
process's working directory is read and re-resolved through the existing resolver as a
|
|
11
|
+
'branch: <name>' signal. gh pr edit has no --head flag, so this is how an edit run from the
|
|
12
|
+
item worktree names its own target.
|
|
13
|
+
|
|
14
|
+
Derivation order: explicit signal in the command, else the current branch, else the
|
|
15
|
+
original NoTarget result. A signal that matches no live worktree does not trigger the
|
|
16
|
+
fallback. A detached HEAD (git prints the literal HEAD), a non-zero git exit, or empty
|
|
17
|
+
output keeps the original NoTarget result and its reason code.
|
|
18
|
+
|
|
19
|
+
Get-PrAuthorTargetGuidanceText supplies the remedy sentence that follows the reason code and
|
|
20
|
+
detail in the TARGET_WORKTREE_NOT_DERIVABLE denial.
|
|
21
|
+
|
|
22
|
+
.NOTES
|
|
23
|
+
PowerShell 7+. Depends, at call time, on Find-WorktreeResolutionBranchSignal,
|
|
24
|
+
Find-WorktreeItemIssueSignal, and Resolve-WorktreeItemTarget from the worktree-resolution
|
|
25
|
+
modules the helpers file imports. It reads no file content. The git executable runs only
|
|
26
|
+
through Invoke-PrAuthorCurrentBranchGitExe, the single executable seam, which never throws.
|
|
27
|
+
Mirrored byte-identically under extensions/drm-copilot/resources/claude-customizations/.
|
|
28
|
+
#>
|
|
29
|
+
[CmdletBinding()]
|
|
30
|
+
param()
|
|
31
|
+
|
|
32
|
+
function Invoke-PrAuthorCurrentBranchGitExe {
|
|
33
|
+
<#
|
|
34
|
+
.SYNOPSIS
|
|
35
|
+
Run git with the given arguments in the current directory. The single executable seam.
|
|
36
|
+
.DESCRIPTION
|
|
37
|
+
Never throws: an uncaught error ends the hook with exit 1, which PreToolUse treats as
|
|
38
|
+
non-blocking, so a throw here would allow the call. A git that cannot start returns
|
|
39
|
+
ExitCode -1. Standard error is discarded so that it is never read as a branch name.
|
|
40
|
+
.PARAMETER GitArgs
|
|
41
|
+
The git arguments.
|
|
42
|
+
.PARAMETER GitInvoker
|
|
43
|
+
The scriptblock that runs git; a unit test passes a test-local stand-in so that this
|
|
44
|
+
body runs without starting a process.
|
|
45
|
+
.OUTPUTS
|
|
46
|
+
System.Management.Automation.PSCustomObject with ExitCode and Output (trimmed).
|
|
47
|
+
#>
|
|
48
|
+
[CmdletBinding()]
|
|
49
|
+
[OutputType([pscustomobject])]
|
|
50
|
+
param(
|
|
51
|
+
[Parameter(Mandatory)][string[]] $GitArgs,
|
|
52
|
+
[ValidateNotNull()][scriptblock] $GitInvoker = { git @args 2>$null }
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
$lines = @(& $GitInvoker @GitArgs 2>$null)
|
|
57
|
+
$code = $LASTEXITCODE
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return [pscustomobject]@{ ExitCode = -1; Output = '' }
|
|
61
|
+
}
|
|
62
|
+
return [pscustomobject]@{ ExitCode = [int]$code; Output = ($lines -join "`n").Trim() }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function Get-PrAuthorCurrentBranch {
|
|
66
|
+
<#
|
|
67
|
+
.SYNOPSIS
|
|
68
|
+
Return the branch checked out in the current directory, or $null.
|
|
69
|
+
.DESCRIPTION
|
|
70
|
+
Runs git rev-parse --abbrev-ref HEAD through Invoke-PrAuthorCurrentBranchGitExe. Returns
|
|
71
|
+
$null for a non-zero exit, for empty output, for output containing whitespace, and for
|
|
72
|
+
the literal HEAD that git prints on a detached checkout.
|
|
73
|
+
.PARAMETER GitInvoker
|
|
74
|
+
Optional. Forwarded to the git seam; omitted, the seam's default invoker runs git.
|
|
75
|
+
.OUTPUTS
|
|
76
|
+
System.String or $null
|
|
77
|
+
#>
|
|
78
|
+
[CmdletBinding()]
|
|
79
|
+
[OutputType([string])]
|
|
80
|
+
param(
|
|
81
|
+
[scriptblock] $GitInvoker
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
$seamArgs = @{ GitArgs = @('rev-parse', '--abbrev-ref', 'HEAD') }
|
|
85
|
+
if ($null -ne $GitInvoker) { $seamArgs['GitInvoker'] = $GitInvoker }
|
|
86
|
+
$result = Invoke-PrAuthorCurrentBranchGitExe @seamArgs
|
|
87
|
+
$name = [string]$result.Output
|
|
88
|
+
if ($result.ExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($name) -or $name -match '\s' -or $name -ceq 'HEAD') {
|
|
89
|
+
return $null
|
|
90
|
+
}
|
|
91
|
+
return $name
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function Resolve-PrAuthorCurrentBranchTarget {
|
|
95
|
+
<#
|
|
96
|
+
.SYNOPSIS
|
|
97
|
+
Apply the current-branch fallback to a command-text resolution result.
|
|
98
|
+
.DESCRIPTION
|
|
99
|
+
Returns Target unchanged unless its Status is NoTarget and the command text carries
|
|
100
|
+
neither a branch signal nor a canonical issue line. In that case the current branch is
|
|
101
|
+
read; a $null branch returns Target unchanged, and any other branch is re-resolved with
|
|
102
|
+
Resolve-WorktreeItemTarget as the text 'branch: <name>', so ambiguity handling and the
|
|
103
|
+
SessionRoot or OtherWorktree labelling stay with the existing resolver.
|
|
104
|
+
.PARAMETER CommandText
|
|
105
|
+
The Bash command text under evaluation.
|
|
106
|
+
.PARAMETER Target
|
|
107
|
+
The result Resolve-WorktreeItemTarget returned for the command text.
|
|
108
|
+
.OUTPUTS
|
|
109
|
+
The target result object from Resolve-WorktreeItemTarget.
|
|
110
|
+
#>
|
|
111
|
+
[CmdletBinding()]
|
|
112
|
+
[OutputType([pscustomobject])]
|
|
113
|
+
param(
|
|
114
|
+
[Parameter(Mandatory)][AllowEmptyString()][string] $CommandText,
|
|
115
|
+
[Parameter(Mandatory)][AllowNull()][object] $Target
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if ($null -eq $Target -or $Target.Status -ne 'NoTarget') {
|
|
119
|
+
return $Target
|
|
120
|
+
}
|
|
121
|
+
# Find-WorktreeItemIssueSignal emits its array as one object, so it is assigned before counting.
|
|
122
|
+
$issueSignal = Find-WorktreeItemIssueSignal -Text $CommandText
|
|
123
|
+
if ($null -ne (Find-WorktreeResolutionBranchSignal -Text $CommandText) -or $issueSignal.Count -gt 0) {
|
|
124
|
+
return $Target
|
|
125
|
+
}
|
|
126
|
+
$branch = Get-PrAuthorCurrentBranch
|
|
127
|
+
if ($null -eq $branch) {
|
|
128
|
+
return $Target
|
|
129
|
+
}
|
|
130
|
+
return (Resolve-WorktreeItemTarget -Text "branch: $branch" -SessionRoot (Get-Location).Path)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function Get-PrAuthorTargetGuidanceText {
|
|
134
|
+
<#
|
|
135
|
+
.SYNOPSIS
|
|
136
|
+
Return the remedy sentence of the TARGET_WORKTREE_NOT_DERIVABLE denial.
|
|
137
|
+
.DESCRIPTION
|
|
138
|
+
Names the accepted target forms: --head <branch> on gh pr create, and for gh pr edit
|
|
139
|
+
either running the command from the item worktree (the branch is derived) or appending
|
|
140
|
+
the shell comment # branch: <branch>. States that --head is not valid for gh pr edit.
|
|
141
|
+
.OUTPUTS
|
|
142
|
+
System.String
|
|
143
|
+
#>
|
|
144
|
+
[CmdletBinding()]
|
|
145
|
+
[OutputType([string])]
|
|
146
|
+
param()
|
|
147
|
+
|
|
148
|
+
return 'Name the target: for gh pr create, pass --head <branch> (gh pr create --head <branch> ...). For gh pr edit, run the command from the item worktree so the gate derives the branch from its checkout, or append the shell comment # branch: <branch> to the command; --head is not valid for gh pr edit.'
|
|
149
|
+
}
|
package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1
CHANGED
|
@@ -59,7 +59,9 @@ function Test-EpicBaseBranchOverride {
|
|
|
59
59
|
with reason EPIC_BASE_BRANCH_MISMATCH. When epic_mode is absent or false, when the
|
|
60
60
|
checkpoint is unreadable, or when the command is not gh pr create (the base branch is
|
|
61
61
|
set at create time, not edit time), this check is a no-op and standalone behavior is
|
|
62
|
-
unchanged.
|
|
62
|
+
unchanged. Only the JSON boolean true counts as epic mode: a string or number such as
|
|
63
|
+
"false", "true", or 1 is not epic mode, so the --base requirement does not apply
|
|
64
|
+
(issue #1001).
|
|
63
65
|
.PARAMETER CommandText
|
|
64
66
|
The Bash command text under evaluation.
|
|
65
67
|
.PARAMETER CheckpointPath
|
|
@@ -116,7 +118,7 @@ function Test-EpicBaseBranchOverride {
|
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
$checkpointProps = @($checkpoint.PSObject.Properties.Name)
|
|
119
|
-
if ($checkpointProps -notcontains 'epic_mode' -or -not [bool]$checkpoint.epic_mode) {
|
|
121
|
+
if ($checkpointProps -notcontains 'epic_mode' -or -not (($checkpoint.epic_mode -is [bool]) -and $checkpoint.epic_mode)) {
|
|
120
122
|
return $null
|
|
121
123
|
}
|
|
122
124
|
|