@danmoisan/drm-copilot-mcp 1.1.17 → 1.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/mcp-server.js +1405 -684
- package/package.json +6 -4
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +11 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -0
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +12 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +16 -5
- package/resources/claude-customizations/.claude/agents/orchestrator.md +21 -7
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +37 -13
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +55 -23
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +66 -38
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +64 -32
- package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
- package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +31 -34
- package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
- package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
- package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +396 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
- package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
- package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +153 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
- package/resources/claude-customizations/.claude/rules/shell.md +10 -8
- package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +3 -4
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +7 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +171 -5
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +6 -15
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -11
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +7 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +42 -16
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +97 -19
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/claude-customizations/pack-manifests/core.json +25 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +13 -3
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +16 -6
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +43 -11
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +19 -4
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +3 -3
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +9 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
- package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
- package/resources/powershell/PoshQC/README.md +8 -2
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -315
|
@@ -17,16 +17,30 @@
|
|
|
17
17
|
|
|
18
18
|
PURITY. This file is pure string and object logic, with no filesystem,
|
|
19
19
|
process, network, or environment access: it opens no file, probes no path,
|
|
20
|
-
issues no web request, launches no executable, and imports no module.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
issues no web request, launches no executable, and imports no module. It
|
|
21
|
+
dot-sources one pure sibling, feature-folder-resolution.ps1 (issue #565),
|
|
22
|
+
inside a guard: a failure sets a modes-local flag, and the target finder and
|
|
23
|
+
the readiness predicates then fail closed. Every readiness predicate accepts
|
|
24
|
+
an ALREADY-PARSED checkpoint object, or $null; the per-mode read seams live
|
|
25
|
+
in the main gate hook. It is a new sibling rather than an addition to the
|
|
26
|
+
issue #539 helpers file, whose header declares a different normative
|
|
27
|
+
contract and which lacks headroom under the 500-line cap; leaving that file
|
|
28
|
+
byte-untouched is the proof the #539 exemption is unchanged.
|
|
26
29
|
#>
|
|
27
30
|
[CmdletBinding()]
|
|
28
31
|
param()
|
|
29
32
|
|
|
33
|
+
# Shared pure feature-folder resolution (issue #565). Guarded: a failed dot-source
|
|
34
|
+
# sets the modes-local flag, so the target finder returns nothing and the readiness
|
|
35
|
+
# predicates name feature-folder-resolution-import instead of failing open.
|
|
36
|
+
$script:OrchestrationFeatureFolderResolutionImportFailure = $null
|
|
37
|
+
try {
|
|
38
|
+
. (Join-Path $PSScriptRoot 'feature-folder-resolution.ps1')
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
$script:OrchestrationFeatureFolderResolutionImportFailure = 'feature-folder-resolution.ps1'
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
# --- Constant table 1: the fixed mode table --------------------------------------
|
|
31
45
|
# Markers are reused verbatim from shipped contracts and hooks; do not invent them.
|
|
32
46
|
# The trailing-period asymmetry is deliberate: preparation markers are matched WITH
|
|
@@ -215,39 +229,18 @@ function Test-OrchestrationImplementationAgent {
|
|
|
215
229
|
function Find-OrchestrationDelegationTargetFolder {
|
|
216
230
|
<#
|
|
217
231
|
.SYNOPSIS
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
Returns the distinct feature-folder basenames cited in a delegation prompt,
|
|
233
|
+
in first-occurrence order, through the shared Find-FeatureFolderCandidate
|
|
234
|
+
(issue #565). A nested research/ or evidence/ citation names its own folder.
|
|
235
|
+
No output when no folder is cited or the shared resolver failed to load; the
|
|
236
|
+
readiness predicates select among several candidates.
|
|
223
237
|
#>
|
|
224
238
|
[CmdletBinding()]
|
|
225
|
-
[OutputType([string])]
|
|
239
|
+
[OutputType([string[]])]
|
|
226
240
|
param([AllowNull()][AllowEmptyString()][string] $Prompt)
|
|
227
241
|
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
$pattern = 'docs[\\/]+features[\\/]+active[\\/]+[^\s"''`]+'
|
|
231
|
-
$matchList = [regex]::Matches($Prompt, $pattern)
|
|
232
|
-
if ($matchList.Count -eq 0) { return $null }
|
|
233
|
-
|
|
234
|
-
$unique = [ordered]@{}
|
|
235
|
-
foreach ($item in $matchList) { $unique[$item.Value] = $true }
|
|
236
|
-
$candidates = @(@($unique.Keys) | Sort-Object -Property Length -Descending)
|
|
237
|
-
$best = [string]$candidates[0]
|
|
238
|
-
|
|
239
|
-
# Sentence punctuation trails a bare path token in every shipped kickoff
|
|
240
|
-
# contract. A trailing period is stripped only when it does not form the
|
|
241
|
-
# Markdown extension the next branch depends on.
|
|
242
|
-
$best = $best.TrimEnd(',', ';', ':')
|
|
243
|
-
while ($best.EndsWith('.') -and -not $best.EndsWith('.md')) {
|
|
244
|
-
$best = $best.Substring(0, $best.Length - 1)
|
|
245
|
-
}
|
|
246
|
-
if ($best -match '\.md$') { $best = $best -replace '[\\/][^\\/]+\.md$', '' }
|
|
247
|
-
|
|
248
|
-
$basename = Get-OrchestrationModeFolderBasename -Path $best
|
|
249
|
-
if (-not $basename) { return $null }
|
|
250
|
-
return $basename
|
|
242
|
+
if ($script:OrchestrationFeatureFolderResolutionImportFailure) { return }
|
|
243
|
+
return [string[]]@(Find-FeatureFolderCandidate -Text $Prompt)
|
|
251
244
|
}
|
|
252
245
|
|
|
253
246
|
function Find-OrchestrationDelegationIssueNumber {
|
|
@@ -259,16 +252,19 @@ function Find-OrchestrationDelegationIssueNumber {
|
|
|
259
252
|
form; $null when neither resolves. Accepted widening: a bare hash form such
|
|
260
253
|
as a pull-request reference can supply a number that is not the target's,
|
|
261
254
|
which widens the SEARCH only - an unmatched number yields no record and
|
|
262
|
-
denies, so deny-by-default is preserved.
|
|
255
|
+
denies, so deny-by-default is preserved. -KeyedOnly returns the keyed form
|
|
256
|
+
or $null and never the bare hash form: the readiness tie-break among cited
|
|
257
|
+
candidates consumes only that value (issue #565, spec R4 and R6).
|
|
263
258
|
#>
|
|
264
259
|
[CmdletBinding()]
|
|
265
260
|
[OutputType([string])]
|
|
266
|
-
param([AllowNull()][AllowEmptyString()][string] $Prompt)
|
|
261
|
+
param([AllowNull()][AllowEmptyString()][string] $Prompt, [switch] $KeyedOnly)
|
|
267
262
|
|
|
268
263
|
if (-not $Prompt) { return $null }
|
|
269
264
|
|
|
270
265
|
$keyed = [regex]::Match($Prompt, 'issue[_-]?num(?:ber)?\s*[:=]\s*#?(\d+)', 'IgnoreCase')
|
|
271
266
|
if ($keyed.Success) { return $keyed.Groups[1].Value }
|
|
267
|
+
if ($KeyedOnly) { return $null }
|
|
272
268
|
$hashForm = [regex]::Match($Prompt, '(?:^|\s)#(\d+)\b')
|
|
273
269
|
if ($hashForm.Success) { return $hashForm.Groups[1].Value }
|
|
274
270
|
return $null
|
|
@@ -371,14 +367,18 @@ function Get-EpicOrchestrationReadinessFailure {
|
|
|
371
367
|
merged nor worktree_removed. The epic_manifest_path conjunct deliberately
|
|
372
368
|
tightens relative to validate_epic_orchestrator_state.py, whose
|
|
373
369
|
required-key set omits it, but is not stricter than the producing skill's
|
|
374
|
-
contract, which mandates it; a false deny names the failed conjunct.
|
|
370
|
+
contract, which mandates it; a false deny names the failed conjunct. The
|
|
371
|
+
target is selected among the cited folders with dependency pruning (issue
|
|
372
|
+
#565); an unresolved tie fails as target-ambiguous.
|
|
373
|
+
Only the keyed -IssueNumber breaks a tie; -FallbackIssueNumber feeds D3 only.
|
|
375
374
|
#>
|
|
376
375
|
[CmdletBinding()]
|
|
377
376
|
[OutputType([string])]
|
|
378
377
|
param(
|
|
379
378
|
[Parameter(Mandatory)][AllowNull()] $Checkpoint,
|
|
380
|
-
[AllowNull()][AllowEmptyString()][string] $TargetFolder,
|
|
381
|
-
[AllowNull()][AllowEmptyString()][string] $IssueNumber
|
|
379
|
+
[AllowNull()][AllowEmptyCollection()][AllowEmptyString()][string[]] $TargetFolder,
|
|
380
|
+
[AllowNull()][AllowEmptyString()][string] $IssueNumber,
|
|
381
|
+
[AllowNull()][AllowEmptyString()][string] $FallbackIssueNumber
|
|
382
382
|
)
|
|
383
383
|
|
|
384
384
|
if ($null -eq $Checkpoint) { return 'checkpoint-absent' }
|
|
@@ -397,7 +397,13 @@ function Get-EpicOrchestrationReadinessFailure {
|
|
|
397
397
|
}
|
|
398
398
|
$features = Get-OrchestrationModeCollection -Value $Checkpoint -Name 'features'
|
|
399
399
|
if ($features.Count -eq 0) { return 'features' }
|
|
400
|
-
$
|
|
400
|
+
if ($script:OrchestrationFeatureFolderResolutionImportFailure) { return 'feature-folder-resolution-import' }
|
|
401
|
+
$selectionArguments = @{ Records = $features; Candidate = @($TargetFolder | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }); DependencyAware = $true }
|
|
402
|
+
$declared = 0
|
|
403
|
+
if ($IssueNumber -match '^\d+$' -and [int]::TryParse($IssueNumber, [ref]$declared)) { $selectionArguments['DeclaredIssueNumber'] = $declared }
|
|
404
|
+
$selection = Select-FeatureFolderTarget @selectionArguments
|
|
405
|
+
if ($selection.Status -eq 'Ambiguous') { return 'target-ambiguous: ' + ($selection.Remaining -join ', ') }
|
|
406
|
+
$record = Find-OrchestrationModeRecord -Records $features -TargetFolder $selection.Basename -IssueNumber $(if ($IssueNumber -or @($selection.Remaining).Count -gt 0) { $IssueNumber } else { $FallbackIssueNumber })
|
|
401
407
|
if ($null -eq $record) { return 'target-record' }
|
|
402
408
|
if (Test-OrchestrationModeTerminalMergeStatus -Record $record) { return 'merge_status' }
|
|
403
409
|
return ''
|
|
@@ -412,7 +418,7 @@ function Test-EpicOrchestrationReady {
|
|
|
412
418
|
[OutputType([bool])]
|
|
413
419
|
param(
|
|
414
420
|
[Parameter(Mandatory)][AllowNull()] $Checkpoint,
|
|
415
|
-
[AllowNull()][AllowEmptyString()][string] $TargetFolder,
|
|
421
|
+
[AllowNull()][AllowEmptyCollection()][AllowEmptyString()][string[]] $TargetFolder,
|
|
416
422
|
[AllowNull()][AllowEmptyString()][string] $IssueNumber
|
|
417
423
|
)
|
|
418
424
|
|
|
@@ -430,14 +436,18 @@ function Get-ParallelOrchestrationReadinessFailure {
|
|
|
430
436
|
parallel_manifest_path; present and non-empty items; the resolved target
|
|
431
437
|
present as a record in items; and that record's merge_status neither merged
|
|
432
438
|
nor worktree_removed. It consumes the parallel item-state and merge-status
|
|
433
|
-
member sets and adds no member to either.
|
|
439
|
+
member sets and adds no member to either. The target is selected among the
|
|
440
|
+
cited folders, with the issue number as a tie-break (issue #565); an
|
|
441
|
+
unresolved tie fails as target-ambiguous.
|
|
442
|
+
Only the keyed -IssueNumber breaks a tie; -FallbackIssueNumber feeds D3 only.
|
|
434
443
|
#>
|
|
435
444
|
[CmdletBinding()]
|
|
436
445
|
[OutputType([string])]
|
|
437
446
|
param(
|
|
438
447
|
[Parameter(Mandatory)][AllowNull()] $Checkpoint,
|
|
439
|
-
[AllowNull()][AllowEmptyString()][string] $TargetFolder,
|
|
440
|
-
[AllowNull()][AllowEmptyString()][string] $IssueNumber
|
|
448
|
+
[AllowNull()][AllowEmptyCollection()][AllowEmptyString()][string[]] $TargetFolder,
|
|
449
|
+
[AllowNull()][AllowEmptyString()][string] $IssueNumber,
|
|
450
|
+
[AllowNull()][AllowEmptyString()][string] $FallbackIssueNumber
|
|
441
451
|
)
|
|
442
452
|
|
|
443
453
|
if ($null -eq $Checkpoint) { return 'checkpoint-absent' }
|
|
@@ -452,7 +462,13 @@ function Get-ParallelOrchestrationReadinessFailure {
|
|
|
452
462
|
}
|
|
453
463
|
$items = Get-OrchestrationModeCollection -Value $Checkpoint -Name 'items'
|
|
454
464
|
if ($items.Count -eq 0) { return 'items' }
|
|
455
|
-
$
|
|
465
|
+
if ($script:OrchestrationFeatureFolderResolutionImportFailure) { return 'feature-folder-resolution-import' }
|
|
466
|
+
$selectionArguments = @{ Records = $items; Candidate = @($TargetFolder | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) }
|
|
467
|
+
$declared = 0
|
|
468
|
+
if ($IssueNumber -match '^\d+$' -and [int]::TryParse($IssueNumber, [ref]$declared)) { $selectionArguments['DeclaredIssueNumber'] = $declared }
|
|
469
|
+
$selection = Select-FeatureFolderTarget @selectionArguments
|
|
470
|
+
if ($selection.Status -eq 'Ambiguous') { return 'target-ambiguous: ' + ($selection.Remaining -join ', ') }
|
|
471
|
+
$record = Find-OrchestrationModeRecord -Records $items -TargetFolder $selection.Basename -IssueNumber $(if ($IssueNumber -or @($selection.Remaining).Count -gt 0) { $IssueNumber } else { $FallbackIssueNumber })
|
|
456
472
|
if ($null -eq $record) { return 'target-record' }
|
|
457
473
|
if (Test-OrchestrationModeTerminalMergeStatus -Record $record) { return 'merge_status' }
|
|
458
474
|
return ''
|
|
@@ -467,7 +483,7 @@ function Test-ParallelOrchestrationReady {
|
|
|
467
483
|
[OutputType([bool])]
|
|
468
484
|
param(
|
|
469
485
|
[Parameter(Mandatory)][AllowNull()] $Checkpoint,
|
|
470
|
-
[AllowNull()][AllowEmptyString()][string] $TargetFolder,
|
|
486
|
+
[AllowNull()][AllowEmptyCollection()][AllowEmptyString()][string[]] $TargetFolder,
|
|
471
487
|
[AllowNull()][AllowEmptyString()][string] $IssueNumber
|
|
472
488
|
)
|
|
473
489
|
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Per-segment target resolution for the epic-scope decision of the preimplementation gate (issue #738).
|
|
4
|
+
.DESCRIPTION
|
|
5
|
+
Pure string logic only: no disk, process, network, clock, or environment access, and no
|
|
6
|
+
dot-source of its own. Every command segment and every path of a gated call is resolved to
|
|
7
|
+
the absolute worktree target it operates on, or the call is reported unresolvable with one
|
|
8
|
+
rule token, so the epic-scope decision can evaluate every target instead of the first
|
|
9
|
+
segment only. Resolution rules R0 to R7 and verdict rules V1 to V7 are defined in the
|
|
10
|
+
issue #732 feature folder plan, section 4.
|
|
11
|
+
|
|
12
|
+
Dot-sourced by enforce-orchestration-preimplementation-gate-epic-scope.ps1 on both the
|
|
13
|
+
Claude and the Codex surface; the four copies are byte-identical.
|
|
14
|
+
.NOTES
|
|
15
|
+
PowerShell 7+. Call-time dependencies, loaded by each gate's existing dot-source of
|
|
16
|
+
hook-command-invocation.ps1 (which itself dot-sources hook-command-scanner.ps1 and
|
|
17
|
+
hook-command-payload.ps1): Read-CommandLineSegment (segment records with IsWrapperLed and
|
|
18
|
+
HasLiveSubstitution), Get-CommandLineGlobalOption (the git global-option table), and
|
|
19
|
+
Get-CommandLineInvocation (the token-aware git add and git commit matcher, read for its
|
|
20
|
+
match count only). Never calls the command-line splitter or the command-line tokenizer
|
|
21
|
+
of the sibling helpers file.
|
|
22
|
+
#>
|
|
23
|
+
|
|
24
|
+
# Command words that change the working directory of later segments (rule R3).
|
|
25
|
+
$script:OrchestrationTargetDirectoryChangeWords = @(
|
|
26
|
+
'cd', 'pushd', 'popd', 'chdir', 'Set-Location', 'sl', 'Push-Location', 'Pop-Location'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Environment names that relocate the git directory or work tree (rule R5).
|
|
30
|
+
$script:OrchestrationTargetRelocationNames = @('GIT_DIR', 'GIT_WORK_TREE', 'GIT_COMMON_DIR', 'GIT_INDEX_FILE')
|
|
31
|
+
# A relocation name not embedded in a longer identifier (issue #903, #732 CR-2).
|
|
32
|
+
$script:OrchestrationTargetRelocationPattern = '(?i)(?<![A-Za-z0-9_])(?:' +
|
|
33
|
+
($script:OrchestrationTargetRelocationNames -join '|') + ')(?![A-Za-z0-9_])'
|
|
34
|
+
|
|
35
|
+
# An absolute target: a drive-lettered or a rooted, non-UNC path after separator normalization.
|
|
36
|
+
$script:OrchestrationTargetAbsolutePattern = '^([A-Za-z]:/|/(?!/))'
|
|
37
|
+
|
|
38
|
+
# A non-local path-leg spelling, tested before normalization (issue #937): UNC, extended-length,
|
|
39
|
+
# device, or NT-object prefixes in either separator style, a drive-relative drive letter, a
|
|
40
|
+
# current-drive-rooted single backslash, a URI scheme, a ~-prefixed home path, or surrounding whitespace.
|
|
41
|
+
$script:OrchestrationTargetNonLocalPattern = '^(?:\s|[\\/]{2}|[\\/]\?\?[\\/]|\\(?![\\/])|[A-Za-z]:(?![\\/])' +
|
|
42
|
+
'|[A-Za-z][A-Za-z0-9+.-]+:|~)|\s$'
|
|
43
|
+
|
|
44
|
+
# The apply_patch markers whose path names a file the patch writes (Codex path leg).
|
|
45
|
+
$script:OrchestrationPatchMarkers = @('*** Add File:', '*** Update File:', '*** Delete File:', '*** Move to:')
|
|
46
|
+
|
|
47
|
+
function ConvertTo-OrchestrationTargetPath {
|
|
48
|
+
<#
|
|
49
|
+
.SYNOPSIS
|
|
50
|
+
Normalizes a session root or a path-leg input to forward slashes.
|
|
51
|
+
.DESCRIPTION
|
|
52
|
+
Replaces every backslash with a forward slash and removes one trailing slash, except
|
|
53
|
+
from a bare root. Never applied to a -C selector value, which is judged as written.
|
|
54
|
+
.OUTPUTS
|
|
55
|
+
System.String
|
|
56
|
+
#>
|
|
57
|
+
[CmdletBinding()]
|
|
58
|
+
[OutputType([string])]
|
|
59
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $Path)
|
|
60
|
+
|
|
61
|
+
$normalized = $Path.Replace('\', '/')
|
|
62
|
+
if ($normalized.Length -gt 1 -and $normalized.EndsWith('/') -and $normalized -notmatch '^[A-Za-z]:/$') {
|
|
63
|
+
$normalized = $normalized.Substring(0, $normalized.Length - 1)
|
|
64
|
+
}
|
|
65
|
+
return $normalized
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function Get-OrchestrationPatchMarkerPath {
|
|
69
|
+
<#
|
|
70
|
+
.SYNOPSIS
|
|
71
|
+
Returns the file paths an apply_patch text names, or an empty array.
|
|
72
|
+
.DESCRIPTION
|
|
73
|
+
Recognized only when the first non-empty line is `*** Begin Patch`. Each Add File,
|
|
74
|
+
Update File, Delete File, and Move to marker contributes its trimmed path.
|
|
75
|
+
.OUTPUTS
|
|
76
|
+
System.String[]
|
|
77
|
+
#>
|
|
78
|
+
[CmdletBinding()]
|
|
79
|
+
[OutputType([string[]])]
|
|
80
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $PatchText)
|
|
81
|
+
|
|
82
|
+
$lines = @($PatchText -split "`r?`n")
|
|
83
|
+
$first = @($lines | Where-Object { $_.Trim() }) | Select-Object -First 1
|
|
84
|
+
if ($null -eq $first -or $first.Trim() -cne '*** Begin Patch') {
|
|
85
|
+
return [string[]]@()
|
|
86
|
+
}
|
|
87
|
+
$paths = [System.Collections.Generic.List[string]]::new()
|
|
88
|
+
foreach ($line in $lines) {
|
|
89
|
+
foreach ($marker in $script:OrchestrationPatchMarkers) {
|
|
90
|
+
if ($line.StartsWith($marker, [System.StringComparison]::Ordinal)) {
|
|
91
|
+
$paths.Add($line.Substring($marker.Length).Trim())
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return [string[]]$paths.ToArray()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function Test-OrchestrationTargetDotSegment {
|
|
99
|
+
# True when a forward-slash path carries a '.' or '..' segment.
|
|
100
|
+
[CmdletBinding()]
|
|
101
|
+
[OutputType([bool])]
|
|
102
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $Path)
|
|
103
|
+
|
|
104
|
+
$segments = @($Path -split '/')
|
|
105
|
+
return ($segments -contains '.' -or $segments -contains '..')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function New-OrchestrationTargetResult {
|
|
109
|
+
# Builds the FR-3 result object; an unresolved result carries no targets.
|
|
110
|
+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
|
|
111
|
+
'PSUseShouldProcessForStateChangingFunctions', '',
|
|
112
|
+
Justification = 'Pure in-memory factory that changes no system state.')]
|
|
113
|
+
[CmdletBinding()]
|
|
114
|
+
[OutputType([pscustomobject])]
|
|
115
|
+
param(
|
|
116
|
+
[AllowEmptyCollection()][string[]] $Targets = @(),
|
|
117
|
+
[AllowEmptyString()][string] $Rule = '',
|
|
118
|
+
[AllowEmptyString()][string] $Value = ''
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if ($Rule) {
|
|
122
|
+
Write-Debug "PREIMPL_TARGET_UNRESOLVABLE: ${Rule}: $Value"
|
|
123
|
+
return [pscustomobject]@{
|
|
124
|
+
Resolved = $false; Targets = [string[]]@(); ReasonCode = 'target-unresolvable'; Detail = "${Rule}: $Value"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return [pscustomobject]@{ Resolved = $true; Targets = [string[]]$Targets; ReasonCode = ''; Detail = '' }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function Get-OrchestrationGitSelectorTarget {
|
|
131
|
+
<#
|
|
132
|
+
.SYNOPSIS
|
|
133
|
+
Walks the git global options of one segment record and returns its -C targets or a failure.
|
|
134
|
+
.DESCRIPTION
|
|
135
|
+
Rules R5 (option form) and R6. Returns an object with Rule and Value set on failure, and
|
|
136
|
+
Selectors holding every -C value otherwise (empty when the segment has no -C).
|
|
137
|
+
.OUTPUTS
|
|
138
|
+
System.Management.Automation.PSCustomObject
|
|
139
|
+
#>
|
|
140
|
+
[CmdletBinding()]
|
|
141
|
+
[OutputType([pscustomobject])]
|
|
142
|
+
param([Parameter(Mandatory)][AllowEmptyCollection()][AllowEmptyString()][string[]] $Token)
|
|
143
|
+
|
|
144
|
+
$table = Get-CommandLineGlobalOption -CommandWord 'git'
|
|
145
|
+
$gitIndex = [array]::IndexOf($Token, 'git')
|
|
146
|
+
if ($gitIndex -lt 0) {
|
|
147
|
+
return [pscustomobject]@{ Rule = 'git-command-word-missing'; Value = ''; Selectors = [string[]]@() }
|
|
148
|
+
}
|
|
149
|
+
$start = $gitIndex + 1
|
|
150
|
+
$selectors = [System.Collections.Generic.List[string]]::new()
|
|
151
|
+
$relocation = ''
|
|
152
|
+
$unmodeled = ''
|
|
153
|
+
$missing = $false
|
|
154
|
+
$index = $start
|
|
155
|
+
while ($index -lt $Token.Count -and $Token[$index].StartsWith('-')) {
|
|
156
|
+
$name = $Token[$index]
|
|
157
|
+
$value = $null
|
|
158
|
+
$equals = $name.IndexOf('=')
|
|
159
|
+
if ($name.StartsWith('--') -and $equals -gt 0) {
|
|
160
|
+
$value = $name.Substring($equals + 1)
|
|
161
|
+
$name = $name.Substring(0, $equals)
|
|
162
|
+
}
|
|
163
|
+
if ($table.WithArgument -ccontains $name) {
|
|
164
|
+
if ($null -eq $value) {
|
|
165
|
+
$index++
|
|
166
|
+
if ($index -lt $Token.Count) {
|
|
167
|
+
$value = $Token[$index]
|
|
168
|
+
}
|
|
169
|
+
elseif ($name -ceq '-C') {
|
|
170
|
+
$missing = $true
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
$value = ''
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
} elseif ($table.Standalone -notcontains $name -and $table.Terminal -notcontains $name) {
|
|
177
|
+
$unmodeled = $name
|
|
178
|
+
break
|
|
179
|
+
}
|
|
180
|
+
$isWorktreeConfig = $name -ceq '-c' -and $null -ne $value -and
|
|
181
|
+
$value.StartsWith('core.worktree', [System.StringComparison]::OrdinalIgnoreCase)
|
|
182
|
+
if ($name -ceq '--git-dir' -or $name -ceq '--work-tree' -or $isWorktreeConfig) {
|
|
183
|
+
if (-not $relocation) { $relocation = "$name $value".Trim() }
|
|
184
|
+
}
|
|
185
|
+
if ($name -ceq '-C' -and -not $missing) { $selectors.Add($value) }
|
|
186
|
+
$index++
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
$rule = ''; $value = ''
|
|
190
|
+
if ($relocation) { $rule = 'git-relocation'; $value = $relocation }
|
|
191
|
+
elseif ($unmodeled) { $rule = 'git-option-unmodeled'; $value = $unmodeled }
|
|
192
|
+
elseif ($missing) { $rule = 'selector-missing-value'; $value = '-C' }
|
|
193
|
+
foreach ($selector in $selectors) {
|
|
194
|
+
if ($rule) { break }
|
|
195
|
+
if ($selector.Contains('\')) { $rule = 'selector-backslash' }
|
|
196
|
+
elseif ($selector -notmatch $script:OrchestrationTargetAbsolutePattern) { $rule = 'selector-not-absolute' }
|
|
197
|
+
elseif (Test-OrchestrationTargetDotSegment -Path $selector) { $rule = 'selector-dot-segment' }
|
|
198
|
+
$value = $selector
|
|
199
|
+
}
|
|
200
|
+
if ($rule) { return [pscustomobject]@{ Rule = $rule; Value = $value; Selectors = [string[]]@() } }
|
|
201
|
+
return [pscustomobject]@{ Rule = ''; Value = ''; Selectors = [string[]]$selectors.ToArray() }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function Get-OrchestrationCommandTarget {
|
|
205
|
+
<#
|
|
206
|
+
.SYNOPSIS
|
|
207
|
+
Resolves every command segment and path of a gated call to its absolute target worktree.
|
|
208
|
+
.DESCRIPTION
|
|
209
|
+
Rules R0 to R7 (first failing rule decides). Returns Resolved, Targets (ordinal
|
|
210
|
+
case-insensitive distinct, first-seen order), ReasonCode ('' or target-unresolvable),
|
|
211
|
+
and Detail (a rule token, ': ', and the offending text or value).
|
|
212
|
+
.OUTPUTS
|
|
213
|
+
System.Management.Automation.PSCustomObject
|
|
214
|
+
#>
|
|
215
|
+
[CmdletBinding()]
|
|
216
|
+
[OutputType([pscustomobject])]
|
|
217
|
+
param(
|
|
218
|
+
[AllowNull()][AllowEmptyString()][string] $Command = '',
|
|
219
|
+
[AllowNull()][AllowEmptyCollection()][string[]] $FilePath = @(),
|
|
220
|
+
[Parameter(Mandatory)][AllowEmptyString()][string] $SessionRoot
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
$root = ConvertTo-OrchestrationTargetPath -Path $SessionRoot
|
|
224
|
+
if ($root -notmatch $script:OrchestrationTargetAbsolutePattern) {
|
|
225
|
+
return (New-OrchestrationTargetResult -Rule 'session-root-not-absolute' -Value $SessionRoot)
|
|
226
|
+
}
|
|
227
|
+
$targets = [System.Collections.Generic.List[string]]::new()
|
|
228
|
+
|
|
229
|
+
foreach ($rawPath in @($FilePath | Where-Object { $_ })) {
|
|
230
|
+
if ($rawPath -match $script:OrchestrationTargetNonLocalPattern) {
|
|
231
|
+
return (New-OrchestrationTargetResult -Rule 'path-not-local' -Value $rawPath)
|
|
232
|
+
}
|
|
233
|
+
$path = ConvertTo-OrchestrationTargetPath -Path $rawPath
|
|
234
|
+
if ($path -notmatch $script:OrchestrationTargetAbsolutePattern) { $targets.Add($root); continue }
|
|
235
|
+
if (Test-OrchestrationTargetDotSegment -Path $path) {
|
|
236
|
+
return (New-OrchestrationTargetResult -Rule 'path-dot-segment' -Value $rawPath)
|
|
237
|
+
}
|
|
238
|
+
$targets.Add($path)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if ($Command) {
|
|
242
|
+
$records = @(Read-CommandLineSegment -CommandText $Command)
|
|
243
|
+
if ($records.Count -eq 0) { $targets.Add($root) }
|
|
244
|
+
foreach ($record in $records) {
|
|
245
|
+
$text = ([string]$record.RawText).Trim()
|
|
246
|
+
if ($record.Unbalanced) { return (New-OrchestrationTargetResult -Rule 'segment-unbalanced' -Value $text) }
|
|
247
|
+
if ($script:OrchestrationTargetDirectoryChangeWords -contains [string]$record.CommandWord) {
|
|
248
|
+
return (New-OrchestrationTargetResult -Rule 'directory-change' -Value $text)
|
|
249
|
+
}
|
|
250
|
+
$wrapped = [bool]$record.IsWrapperLed -or [bool]$record.HasLiveSubstitution
|
|
251
|
+
if ($wrapped) {
|
|
252
|
+
$matchCount = 0
|
|
253
|
+
foreach ($sub in @('add', 'commit')) {
|
|
254
|
+
$invocationArguments = @{
|
|
255
|
+
CommandText = $record.RawText; CommandWord = 'git'; SubcommandPath = @($sub)
|
|
256
|
+
}
|
|
257
|
+
$matchCount += @(Get-CommandLineInvocation @invocationArguments).Count
|
|
258
|
+
}
|
|
259
|
+
if ($matchCount -gt 0) { return (New-OrchestrationTargetResult -Rule 'wrapper-git' -Value $text) }
|
|
260
|
+
}
|
|
261
|
+
if ($text -match $script:OrchestrationTargetRelocationPattern) {
|
|
262
|
+
return (New-OrchestrationTargetResult -Rule 'git-relocation' -Value $text)
|
|
263
|
+
}
|
|
264
|
+
if ($wrapped -or [string]$record.CommandWord -cne 'git') { $targets.Add($root); continue }
|
|
265
|
+
$git = Get-OrchestrationGitSelectorTarget -Token ([string[]]@($record.Tokens))
|
|
266
|
+
if ($git.Rule) { return (New-OrchestrationTargetResult -Rule $git.Rule -Value $git.Value) }
|
|
267
|
+
if ($git.Selectors.Count -eq 0) {
|
|
268
|
+
$targets.Add($root)
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
foreach ($selector in $git.Selectors) { $targets.Add($selector) }
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
$distinct = [System.Collections.Generic.List[string]]::new()
|
|
277
|
+
foreach ($target in $targets) {
|
|
278
|
+
$seen = $distinct | Where-Object { [string]::Equals($_, $target, [System.StringComparison]::OrdinalIgnoreCase) }
|
|
279
|
+
if (-not $seen) { $distinct.Add($target) }
|
|
280
|
+
}
|
|
281
|
+
return (New-OrchestrationTargetResult -Targets $distinct.ToArray())
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function Resolve-OrchestrationEpicTargetVerdict {
|
|
285
|
+
<#
|
|
286
|
+
.SYNOPSIS
|
|
287
|
+
Decides the epic-scope verdict for a resolved or unresolved target result.
|
|
288
|
+
.DESCRIPTION
|
|
289
|
+
Verdict rules V1 to V7. Resolves the session-root scope with an empty selector and each
|
|
290
|
+
target scope with the target as selector, each distinct key (ordinal
|
|
291
|
+
case-insensitive) at most once; a target equal to the session root reuses its scope.
|
|
292
|
+
Returns Verdict ('none', 'deny', or 'evaluate'), ReasonCode, Detail, and Evaluations
|
|
293
|
+
(one Target, IsSessionRoot, Scope entry per target when the verdict is evaluate).
|
|
294
|
+
.OUTPUTS
|
|
295
|
+
System.Management.Automation.PSCustomObject
|
|
296
|
+
#>
|
|
297
|
+
[CmdletBinding()]
|
|
298
|
+
[OutputType([pscustomobject])]
|
|
299
|
+
param(
|
|
300
|
+
[Parameter(Mandatory)][AllowEmptyString()][string] $SessionRoot,
|
|
301
|
+
[Parameter(Mandatory)][pscustomobject] $TargetResult,
|
|
302
|
+
[Parameter(Mandatory)][scriptblock] $ScopeResolver
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
$root = ConvertTo-OrchestrationTargetPath -Path $SessionRoot
|
|
306
|
+
$cache = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::OrdinalIgnoreCase)
|
|
307
|
+
$cache[$root] = & $ScopeResolver ''
|
|
308
|
+
$evaluations = [System.Collections.Generic.List[pscustomobject]]::new()
|
|
309
|
+
if ($TargetResult.Resolved) {
|
|
310
|
+
foreach ($target in @($TargetResult.Targets)) {
|
|
311
|
+
if (-not $cache.ContainsKey($target)) { $cache[$target] = & $ScopeResolver $target }
|
|
312
|
+
$isSessionRoot = [string]::Equals($target, $root, [System.StringComparison]::OrdinalIgnoreCase)
|
|
313
|
+
$evaluations.Add([pscustomobject]@{
|
|
314
|
+
Target = $target; IsSessionRoot = $isSessionRoot; Scope = $cache[$target]
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
$relevant = @($cache.Values | Where-Object { $_.IsEpicScope -or $_.Reason -eq 'target-worktree-ambiguous' })
|
|
320
|
+
$code = ''; $detail = ''
|
|
321
|
+
if ($relevant.Count -eq 0) {
|
|
322
|
+
return [pscustomobject]@{ Verdict = 'none'; ReasonCode = ''; Detail = ''; Evaluations = @() }
|
|
323
|
+
}
|
|
324
|
+
if (-not $TargetResult.Resolved) {
|
|
325
|
+
$code = 'target-unresolvable'; $detail = [string]$TargetResult.Detail
|
|
326
|
+
}
|
|
327
|
+
$ambiguous = @($evaluations | Where-Object { $_.Scope.Reason -eq 'target-worktree-ambiguous' })
|
|
328
|
+
$unresolved = @($evaluations | Where-Object { $_.Scope.Reason -eq 'selector-unresolved' })
|
|
329
|
+
$mixed = @($evaluations | Where-Object { -not $_.Scope.IsEpicScope })
|
|
330
|
+
if (-not $code -and $ambiguous.Count -gt 0) { $code = 'target-ambiguous'; $detail = $ambiguous[0].Target }
|
|
331
|
+
if (-not $code -and $unresolved.Count -gt 0) {
|
|
332
|
+
$code = 'target-unresolvable'; $detail = "selector-unresolved: $($unresolved[0].Target)"
|
|
333
|
+
}
|
|
334
|
+
if (-not $code -and $mixed.Count -gt 0) { $code = 'target-mixed'; $detail = $mixed[0].Target }
|
|
335
|
+
if ($code) {
|
|
336
|
+
return [pscustomobject]@{ Verdict = 'deny'; ReasonCode = $code; Detail = $detail; Evaluations = @() }
|
|
337
|
+
}
|
|
338
|
+
return [pscustomobject]@{ Verdict = 'evaluate'; ReasonCode = ''; Detail = ''; Evaluations = $evaluations.ToArray() }
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function Get-OrchestrationEpicTargetDenyReason {
|
|
342
|
+
<#
|
|
343
|
+
.SYNOPSIS
|
|
344
|
+
Builds the deny reason of an epic-scope target verdict or a not-ready target.
|
|
345
|
+
.DESCRIPTION
|
|
346
|
+
One string per code, behind the unchanged PREIMPLEMENTATION_GATE_BLOCKED prefix:
|
|
347
|
+
target-unresolvable (Detail is the rule detail), target-ambiguous and target-mixed
|
|
348
|
+
(Detail is the target), and target-not-ready (Detail is the target, with the
|
|
349
|
+
consulted checkpoint path and the failed readiness predicate).
|
|
350
|
+
.OUTPUTS
|
|
351
|
+
System.String
|
|
352
|
+
#>
|
|
353
|
+
[CmdletBinding()]
|
|
354
|
+
[OutputType([string])]
|
|
355
|
+
param(
|
|
356
|
+
[Parameter(Mandatory)][string] $ReasonCode,
|
|
357
|
+
[AllowEmptyString()][string] $Detail = '',
|
|
358
|
+
[AllowEmptyString()][string] $CheckpointPath = '',
|
|
359
|
+
[AllowEmptyString()][string] $Failure = ''
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
$prefix = "PREIMPLEMENTATION_GATE_BLOCKED: ${ReasonCode}: "
|
|
363
|
+
switch ($ReasonCode) {
|
|
364
|
+
'target-ambiguous' {
|
|
365
|
+
return $prefix + "more than one worktree claims the epic integration branch for target $Detail. " +
|
|
366
|
+
'Implementation operations in epic scope require an unambiguous target worktree.'
|
|
367
|
+
}
|
|
368
|
+
'target-mixed' {
|
|
369
|
+
return $prefix + "target $Detail is not in the epic scope that governs this operation. " +
|
|
370
|
+
'Implementation operations in epic scope may not also target a worktree outside it.'
|
|
371
|
+
}
|
|
372
|
+
'target-not-ready' {
|
|
373
|
+
return $prefix + "the epic-scope target $Detail was evaluated against $CheckpointPath, " +
|
|
374
|
+
"and the failed readiness predicate is '$Failure'. " +
|
|
375
|
+
'Implementation operations in epic scope require that checkpoint to satisfy every ' +
|
|
376
|
+
'readiness predicate, and a production path may be staged or edited only while a merge is in progress.'
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return $prefix + "the target worktree of this epic-scope operation cannot be resolved ($Detail). " +
|
|
380
|
+
'Implementation operations in epic scope require every command segment and path to name ' +
|
|
381
|
+
'an absolute, resolvable target.'
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function Resolve-OrchestrationEpicTargetOutcome {
|
|
385
|
+
<#
|
|
386
|
+
.SYNOPSIS
|
|
387
|
+
Decides the shared epic-scope outcome of a target verdict (issue #903, #732 CR-3).
|
|
388
|
+
.DESCRIPTION
|
|
389
|
+
Pure decision logic shared by the Claude and the Codex epic-scope gates; reads no file,
|
|
390
|
+
process, or environment value. Returns Outcome 'none' (not epic scope), 'deny' (with
|
|
391
|
+
the deny Reason), or 'allow' (empty Reason). The caller supplies the readiness predicate,
|
|
392
|
+
invoked as & $ReadinessFailure $evaluation.Scope; the first evaluation with a non-empty
|
|
393
|
+
failure denies, and the session-root wording is unchanged.
|
|
394
|
+
.OUTPUTS
|
|
395
|
+
System.Management.Automation.PSCustomObject
|
|
396
|
+
#>
|
|
397
|
+
[CmdletBinding()]
|
|
398
|
+
[OutputType([pscustomobject])]
|
|
399
|
+
param(
|
|
400
|
+
[Parameter(Mandatory)][pscustomobject] $Verdict,
|
|
401
|
+
[Parameter(Mandatory)][scriptblock] $ReadinessFailure
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
if ($Verdict.Verdict -eq 'none') {
|
|
405
|
+
return [pscustomobject]@{ Outcome = 'none'; Reason = '' }
|
|
406
|
+
}
|
|
407
|
+
if ($Verdict.Verdict -eq 'deny') {
|
|
408
|
+
$reason = Get-OrchestrationEpicTargetDenyReason -ReasonCode $Verdict.ReasonCode -Detail $Verdict.Detail
|
|
409
|
+
return [pscustomobject]@{ Outcome = 'deny'; Reason = $reason }
|
|
410
|
+
}
|
|
411
|
+
foreach ($evaluation in $Verdict.Evaluations) {
|
|
412
|
+
$scope = $evaluation.Scope
|
|
413
|
+
$failure = & $ReadinessFailure $evaluation.Scope
|
|
414
|
+
if (-not $failure) {
|
|
415
|
+
continue
|
|
416
|
+
}
|
|
417
|
+
if ($evaluation.IsSessionRoot) {
|
|
418
|
+
$reason = 'PREIMPLEMENTATION_GATE_BLOCKED: this epic-scope operation was evaluated against ' +
|
|
419
|
+
"$($scope.CheckpointPath), and the failed readiness predicate is '$failure'. " +
|
|
420
|
+
'Implementation operations in epic scope require that checkpoint to satisfy every ' +
|
|
421
|
+
'readiness predicate, and a production path may be staged or edited only while a merge is in progress.'
|
|
422
|
+
return [pscustomobject]@{ Outcome = 'deny'; Reason = $reason }
|
|
423
|
+
}
|
|
424
|
+
$reasonArguments = @{
|
|
425
|
+
ReasonCode = 'target-not-ready'
|
|
426
|
+
Detail = $evaluation.Target
|
|
427
|
+
CheckpointPath = $scope.CheckpointPath
|
|
428
|
+
Failure = $failure
|
|
429
|
+
}
|
|
430
|
+
return [pscustomobject]@{ Outcome = 'deny'; Reason = (Get-OrchestrationEpicTargetDenyReason @reasonArguments) }
|
|
431
|
+
}
|
|
432
|
+
return [pscustomobject]@{ Outcome = 'allow'; Reason = '' }
|
|
433
|
+
}
|