@danmoisan/drm-copilot-mcp 1.1.23 → 1.1.25
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 +13347 -7926
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -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/parallel-orchestrator.md +14 -0
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
- package/resources/claude-customizations/.claude/agents/pr-author.md +17 -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.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +6 -3
- 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-powershell-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +44 -3
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +60 -4
- 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-rejection.ps1 +172 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +9 -1
- 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/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/worktree-resolution/HookTargetWorktree.psm1 +391 -0
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +1 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +150 -18
- package/resources/claude-customizations/.claude/settings.json +32 -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/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 +24 -9
- package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -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 +5 -4
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +21 -1
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +34 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +69 -6
- 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 +21 -4
- 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/config/blast-radius.json +6 -5
- package/resources/claude-customizations/config/orchestration-routing.json +61 -1
- package/resources/claude-customizations/pack-manifests/core.json +33 -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 +24 -9
- package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
- 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/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/discovery-capability-sentinel.toml +51 -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/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 +33 -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-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/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/pack-manifests/core.json +63 -1
- package/resources/config/orchestration-routing.json +61 -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/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/mermaid.instructions.md +85 -0
- package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
- 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 +24 -9
- package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -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/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Codex PreToolUse hook that gates planner and orchestrator launches on current configured discovery authority.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Invoked by the Codex PreToolUse hook. The hook reads the Codex envelope from
|
|
7
|
+
stdin, recognizes an atomic-planner or orchestrator launch, and takes its
|
|
8
|
+
decision from the shared DiscoveryPlanning module (published under
|
|
9
|
+
.codex/lib/discovery-validation, or read from .claude/lib when this repository
|
|
10
|
+
hosts itself):
|
|
11
|
+
|
|
12
|
+
- a call that is not a planner or orchestrator launch, and a workspace without
|
|
13
|
+
a protected discovery activation, allow silently (no stdout) so the existing
|
|
14
|
+
Codex gates keep their behavior;
|
|
15
|
+
- an active workspace must still hold the activated locator and domain profile
|
|
16
|
+
and the protected session must hold a current, passing, gateway-written
|
|
17
|
+
planning-mode receipt for this host and session; otherwise the launch is
|
|
18
|
+
denied with a PreToolUse deny decision at exit 0.
|
|
19
|
+
|
|
20
|
+
An envelope the hook cannot read is a hard failure: the reason goes to stderr
|
|
21
|
+
and the hook exits 2. Dependency failures deny with the
|
|
22
|
+
DISCOVERY_PLANNING_GATE_BLOCKED: prefix. The hook never runs Python (issue #980).
|
|
23
|
+
|
|
24
|
+
.NOTES
|
|
25
|
+
Requires PowerShell 7+. Invokes NO external process.
|
|
26
|
+
#>
|
|
27
|
+
[CmdletBinding()]
|
|
28
|
+
param()
|
|
29
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
30
|
+
|
|
31
|
+
function Get-DiscoveryPlanningHelperModulePath {
|
|
32
|
+
<#
|
|
33
|
+
.SYNOPSIS
|
|
34
|
+
Returns the published (.codex/lib) or self-hosting (.claude/lib) path of one helper module.
|
|
35
|
+
#>
|
|
36
|
+
[CmdletBinding()]
|
|
37
|
+
[OutputType([string])]
|
|
38
|
+
param(
|
|
39
|
+
[Parameter(Mandatory = $true)][string]$ModuleName,
|
|
40
|
+
[Parameter(Mandatory = $false)][string]$ScriptRoot = $PSScriptRoot
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
$published = Join-Path $ScriptRoot "../lib/discovery-validation/$ModuleName"
|
|
44
|
+
$selfHosted = Join-Path $ScriptRoot "../../.claude/lib/discovery-validation/$ModuleName"
|
|
45
|
+
foreach ($candidate in @($published, $selfHosted)) {
|
|
46
|
+
if (Test-Path -LiteralPath $candidate -PathType Leaf) { return $candidate }
|
|
47
|
+
}
|
|
48
|
+
return $published
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function Import-DiscoveryPlanningSelfHostedModule {
|
|
52
|
+
<#
|
|
53
|
+
.SYNOPSIS
|
|
54
|
+
Imports the shared helpers from this repository's .claude/lib layout when no published .codex/lib exists (exemption D4).
|
|
55
|
+
#>
|
|
56
|
+
[CmdletBinding()]
|
|
57
|
+
param()
|
|
58
|
+
|
|
59
|
+
$ScriptRoot = $PSScriptRoot
|
|
60
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
61
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
62
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryManifest.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryManifest.psm1' -ErrorRecord $_ }
|
|
63
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
|
|
64
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryToolRouting.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryToolRouting.psm1' -ErrorRecord $_ }
|
|
65
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryAuthorization.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthorization.psm1' -ErrorRecord $_ }
|
|
66
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
67
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryPlanning.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPlanning.psm1' -ErrorRecord $_ }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# The published destination keeps the helpers beside .codex/hooks; this repository hosts them under .claude/lib.
|
|
71
|
+
if (Test-Path -LiteralPath (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -PathType Leaf) {
|
|
72
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
73
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
74
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryManifest.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryManifest.psm1' -ErrorRecord $_ }
|
|
75
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
|
|
76
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryToolRouting.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryToolRouting.psm1' -ErrorRecord $_ }
|
|
77
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthorization.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthorization.psm1' -ErrorRecord $_ }
|
|
78
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
79
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryPlanning.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPlanning.psm1' -ErrorRecord $_ }
|
|
80
|
+
} else {
|
|
81
|
+
Import-DiscoveryPlanningSelfHostedModule
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
$script:DiscoveryPlanningReasonPrefix = 'DISCOVERY_PLANNING_GATE_BLOCKED:'
|
|
85
|
+
|
|
86
|
+
function Invoke-DiscoveryPlanningGateDecision {
|
|
87
|
+
<#
|
|
88
|
+
.SYNOPSIS
|
|
89
|
+
Parses the Codex PreToolUse envelope and returns the planning outcome.
|
|
90
|
+
.DESCRIPTION
|
|
91
|
+
Returns the shared outcome object (Decision, Code, Reason, Receipt,
|
|
92
|
+
Prerequisite). Every seam defaults to the real host and is injectable. A
|
|
93
|
+
recorded dependency failure returns a deny outcome before the envelope is read.
|
|
94
|
+
#>
|
|
95
|
+
[CmdletBinding()]
|
|
96
|
+
[OutputType([pscustomobject])]
|
|
97
|
+
param(
|
|
98
|
+
[Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$ToolInputRaw,
|
|
99
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
|
|
100
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
|
|
101
|
+
[Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadBytes = $null
|
|
102
|
+
)
|
|
103
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix $script:DiscoveryPlanningReasonPrefix
|
|
104
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
105
|
+
|
|
106
|
+
if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
|
|
107
|
+
if ($null -eq $Store) { $Store = Get-DiscoveryStartStore }
|
|
108
|
+
|
|
109
|
+
$normalized = ConvertFrom-DiscoveryHostPayloadText -HostName 'codex' -Text $ToolInputRaw
|
|
110
|
+
$parameters = @{ Normalized = $normalized; HostEnvironment = $HostEnvironment; Store = $Store }
|
|
111
|
+
if ($null -ne $ReadBytes) { $parameters['ReadBytes'] = $ReadBytes }
|
|
112
|
+
return Get-DiscoveryPlanningDecision @parameters
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function Invoke-DiscoveryPlanningGateEntryPoint {
|
|
116
|
+
<#
|
|
117
|
+
.SYNOPSIS
|
|
118
|
+
Reads one Codex PreToolUse payload, writes the decision and returns the process exit code.
|
|
119
|
+
.DESCRIPTION
|
|
120
|
+
An unreadable envelope writes its reason to stderr and returns 2. A deny
|
|
121
|
+
writes the PreToolUse decision JSON to stdout and returns 0. An allow writes
|
|
122
|
+
nothing and returns 0, as the Codex gates do.
|
|
123
|
+
#>
|
|
124
|
+
[CmdletBinding()]
|
|
125
|
+
[OutputType([int])]
|
|
126
|
+
param([Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw)
|
|
127
|
+
|
|
128
|
+
$outcome = Invoke-DiscoveryPlanningGateDecision -ToolInputRaw $PayloadRaw
|
|
129
|
+
# A dependency failure is already the PreToolUse deny decision.
|
|
130
|
+
if ($outcome -is [System.Collections.IDictionary]) { [Console]::Out.WriteLine(($outcome | ConvertTo-Json -Compress -Depth 5)); return 0 }
|
|
131
|
+
if ($outcome.Decision -eq 'allow') { return 0 }
|
|
132
|
+
if ($outcome.Code -eq 'ENVELOPE') {
|
|
133
|
+
[Console]::Error.WriteLine("$($script:DiscoveryPlanningReasonPrefix) $($outcome.Reason)")
|
|
134
|
+
return 2
|
|
135
|
+
}
|
|
136
|
+
$decision = ConvertTo-DiscoveryPlanningHookOutput -Outcome $outcome -ReasonPrefix $script:DiscoveryPlanningReasonPrefix
|
|
137
|
+
[Console]::Out.WriteLine(($decision | ConvertTo-Json -Compress -Depth 5))
|
|
138
|
+
return 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Guard allows dot-sourcing in tests without executing the entrypoint.
|
|
142
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('DISCOVERY_PLANNING_GATE_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
146
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'DISCOVERY_PLANNING_GATE_BLOCKED:'
|
|
147
|
+
if ($null -ne $dependencyDecision) { $dependencyDecision | ConvertTo-Json -Compress -Depth 5 | Write-Output; exit 0 }
|
|
148
|
+
|
|
149
|
+
exit (Invoke-DiscoveryPlanningGateEntryPoint -PayloadRaw ([Console]::In.ReadToEnd()))
|
|
@@ -4,12 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
.DESCRIPTION
|
|
6
6
|
Dot-sourced by enforce-orchestration-preimplementation-gate.ps1. The Codex counterpart
|
|
7
|
-
of the issue #663 Claude sibling, holding
|
|
7
|
+
of the issue #663 Claude sibling, holding three groups of functions:
|
|
8
8
|
|
|
9
9
|
- The two per-mode read seams of issue #554 (Get-EpicCheckpointContent and
|
|
10
10
|
Get-ParallelCheckpointContent), relocated verbatim from the gate file so the gate
|
|
11
11
|
stays inside the 500-line cap. Their names and behaviour are unchanged, so tests
|
|
12
12
|
that mock or shadow them by name are unaffected.
|
|
13
|
+
- The target-resolution building blocks of issue #1010, byte-identical to the Claude
|
|
14
|
+
sibling: the worktree-list wrapper Get-OrchestrationGateWorktreeList (the only
|
|
15
|
+
listing seam), the recording invoker Invoke-OrchestrationGateWorktreeList, and the
|
|
16
|
+
command-operand parser Get-OrchestrationGateCommandOperandPath, plus the reason-code
|
|
17
|
+
pair restated from WorktreeResolution.psm1. They feed Resolve-OrchestrationGateTarget
|
|
18
|
+
and Read-OrchestrationGateCheckpoint, which read the single-feature checkpoint through
|
|
19
|
+
the Get-CheckpointContent seam (mandatory absolute Path, moved here from the gate)
|
|
20
|
+
beneath the worktree the file path, apply_patch markers, or command operands name.
|
|
13
21
|
- The epic-scope decision for the command, apply_patch, and path legs. A call is epic
|
|
14
22
|
scope when the effective worktree's HEAD (the -C selector worktree when present,
|
|
15
23
|
otherwise the session root) equals the integration_branch of
|
|
@@ -29,13 +37,23 @@
|
|
|
29
37
|
from the resolution sibling dot-sourced below. The per-segment target resolver comes
|
|
30
38
|
from the targets file dot-sourced below (issue #738), which calls
|
|
31
39
|
Read-CommandLineSegment, Get-CommandLineGlobalOption, and Get-CommandLineInvocation,
|
|
32
|
-
loaded by the gate's dot-source of hook-command-invocation.ps1.
|
|
40
|
+
loaded by the gate's dot-source of hook-command-invocation.ps1. Resolve-HookTargetWorktree
|
|
41
|
+
and ConvertFrom-HookTargetWorktreePorcelain come from the guarded dot-source of the
|
|
42
|
+
resolver twin hook-target-worktree.ps1 (issue #1009).
|
|
33
43
|
Mirrored byte-identically under extensions/drm-copilot/resources/codex-and-agents-customizations/.
|
|
34
44
|
AUTHORITY: PowerShell-authoritative. The epic readiness predicate has no reference implementation in another language, and this hook starts no interpreter process (issue #707, D15).
|
|
35
45
|
#>
|
|
36
46
|
|
|
37
47
|
. (Join-Path $PSScriptRoot 'enforce-orchestration-preimplementation-gate-epic-resolution.ps1')
|
|
38
48
|
. (Join-Path $PSScriptRoot 'enforce-orchestration-preimplementation-gate-targets.ps1')
|
|
49
|
+
try { . (Join-Path $PSScriptRoot 'hook-target-worktree.ps1') } catch { Add-HookDependencyFailure -Name 'hook-target-worktree.ps1' -ErrorRecord $_ }
|
|
50
|
+
|
|
51
|
+
# The target-resolution reason codes (issue #1010). Their source is
|
|
52
|
+
# Get-WorktreeResolutionAmbiguityReasonCode and Get-WorktreeResolutionNoTargetReasonCode
|
|
53
|
+
# in .claude/lib/worktree-resolution/WorktreeResolution.psm1; Codex hooks cannot import
|
|
54
|
+
# .claude/lib, so the two literals are restated once here and pinned equal by a test.
|
|
55
|
+
$script:OrchestrationGateAmbiguousReasonCode = 'TARGET_WORKTREE_AMBIGUOUS'
|
|
56
|
+
$script:OrchestrationGateNotDerivableReasonCode = 'TARGET_WORKTREE_NOT_DERIVABLE'
|
|
39
57
|
|
|
40
58
|
# An epic manifest lives under the epics tree; the pattern is tested after backslash
|
|
41
59
|
# normalisation so either separator spelling is accepted.
|
|
@@ -68,6 +86,225 @@ function Get-ParallelCheckpointContent {
|
|
|
68
86
|
return Get-Content -Raw -LiteralPath $path
|
|
69
87
|
}
|
|
70
88
|
|
|
89
|
+
# The single-feature read seam (issue #1010, moved from the gate file). It takes the
|
|
90
|
+
# absolute path composed beneath the resolved worktree root, so no read binds to the
|
|
91
|
+
# calling process's directory; an absent file returns an empty string.
|
|
92
|
+
function Get-CheckpointContent {
|
|
93
|
+
[CmdletBinding()]
|
|
94
|
+
[OutputType([string])]
|
|
95
|
+
param([Parameter(Mandatory)][ValidatePattern('^([A-Za-z]:[\\/]|/)')][string] $Path)
|
|
96
|
+
|
|
97
|
+
if (-not (Test-Path -LiteralPath $Path)) {
|
|
98
|
+
return ''
|
|
99
|
+
}
|
|
100
|
+
return Get-Content -Raw -LiteralPath $Path
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function Get-OrchestrationGateWorktreeList {
|
|
104
|
+
<#
|
|
105
|
+
.SYNOPSIS
|
|
106
|
+
Returns the porcelain worktree listing for the session root (issue #1010 seam).
|
|
107
|
+
.DESCRIPTION
|
|
108
|
+
Runs the listing exactly as the default WorktreeListInvoker of
|
|
109
|
+
Resolve-HookTargetWorktree does and returns an empty string on a non-zero exit. It
|
|
110
|
+
is the only test seam for the listing.
|
|
111
|
+
.OUTPUTS
|
|
112
|
+
System.String
|
|
113
|
+
#>
|
|
114
|
+
[CmdletBinding()]
|
|
115
|
+
[OutputType([string])]
|
|
116
|
+
param([Parameter(Mandatory)][string] $SessionRoot)
|
|
117
|
+
|
|
118
|
+
$porcelain = & git -C $SessionRoot worktree list --porcelain 2>$null
|
|
119
|
+
if ($LASTEXITCODE -ne 0) { return '' }
|
|
120
|
+
return ($porcelain -join "`n")
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function Invoke-OrchestrationGateWorktreeList {
|
|
124
|
+
<#
|
|
125
|
+
.SYNOPSIS
|
|
126
|
+
Recording WorktreeListInvoker: returns the listing and records a listing failure.
|
|
127
|
+
.DESCRIPTION
|
|
128
|
+
Sets $script:OrchestrationGateWorktreeListFailed when the wrapper throws (and then
|
|
129
|
+
rethrows) or when its text holds no worktree entry, so the gate denies instead of
|
|
130
|
+
accepting the resolver's session-root fallback (issue #1010, spec E1).
|
|
131
|
+
.OUTPUTS
|
|
132
|
+
System.String
|
|
133
|
+
#>
|
|
134
|
+
[CmdletBinding()]
|
|
135
|
+
[OutputType([string])]
|
|
136
|
+
param([Parameter(Mandatory)][string] $SessionRoot)
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
$text = [string](Get-OrchestrationGateWorktreeList -SessionRoot $SessionRoot)
|
|
140
|
+
} catch {
|
|
141
|
+
$script:OrchestrationGateWorktreeListFailed = $true
|
|
142
|
+
throw
|
|
143
|
+
}
|
|
144
|
+
if (@(ConvertFrom-HookTargetWorktreePorcelain -Text $text).Count -eq 0) {
|
|
145
|
+
$script:OrchestrationGateWorktreeListFailed = $true
|
|
146
|
+
}
|
|
147
|
+
return $text
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function Get-OrchestrationGateCommandOperandPath {
|
|
151
|
+
<#
|
|
152
|
+
.SYNOPSIS
|
|
153
|
+
Returns the worktree-selecting paths of every git add and git commit invocation.
|
|
154
|
+
.DESCRIPTION
|
|
155
|
+
Scans every Structural match of git add and git commit (every command segment and
|
|
156
|
+
wrapper payload). Each -C value in any git global-option position and each absolute
|
|
157
|
+
operand is returned, distinct and in first-seen order. Relative operands, a -C on a
|
|
158
|
+
git segment invoking neither add nor commit, and Indeterminate matches are ignored.
|
|
159
|
+
For a match whose record is not argument-injected, a subcommand-aware walk (issue
|
|
160
|
+
#1010, F2) also reads the tokens after the subcommand with a per-subcommand option
|
|
161
|
+
model, compared case-sensitively: a value option consumes the next token unless its
|
|
162
|
+
value is inline (--name=value) or attached (-mvalue); a standalone flag consumes
|
|
163
|
+
itself; '--' makes every later token an operand; a redirection and its target are
|
|
164
|
+
skipped; any other dash token, such as the cluster -am, stops the walk. Its literal
|
|
165
|
+
absolute tokens are returned, and a token the walk reads as an option value is not
|
|
166
|
+
returned as an operand.
|
|
167
|
+
.PARAMETER Command
|
|
168
|
+
The full command line.
|
|
169
|
+
.OUTPUTS
|
|
170
|
+
System.String[]
|
|
171
|
+
#>
|
|
172
|
+
[CmdletBinding()]
|
|
173
|
+
[OutputType([string[]])]
|
|
174
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $Command)
|
|
175
|
+
|
|
176
|
+
$valueOptions = @{
|
|
177
|
+
commit = @('-m', '--message', '-F', '--file', '--author', '--date', '-C', '--reuse-message', '-c', '--reedit-message', '-t', '--template', '--fixup', '--squash', '--trailer', '--pathspec-from-file')
|
|
178
|
+
add = @('--pathspec-from-file', '--chmod')
|
|
179
|
+
}
|
|
180
|
+
$flagOptions = @{
|
|
181
|
+
commit = @('-a', '--all', '--amend', '--no-edit', '--no-verify', '-n', '-s', '--signoff', '-q', '--quiet', '-v', '--verbose', '--allow-empty', '-o', '--only', '-i', '--include', '--pathspec-file-nul')
|
|
182
|
+
add = @('-A', '--all', '-u', '--update', '-f', '--force', '-N', '--intent-to-add', '-n', '--dry-run', '-v', '--verbose', '--pathspec-file-nul')
|
|
183
|
+
}
|
|
184
|
+
$absolutePattern = '^([A-Za-z]:[\\/]|/)'
|
|
185
|
+
$paths = [System.Collections.Generic.List[string]]::new()
|
|
186
|
+
foreach ($subcommand in @('add', 'commit')) {
|
|
187
|
+
foreach ($match in @(Get-CommandLineInvocation -CommandText $Command -CommandWord 'git' -SubcommandPath @($subcommand))) {
|
|
188
|
+
if ($match.Status -ne 'Structural') { continue }
|
|
189
|
+
$walked = [System.Collections.Generic.List[string]]::new()
|
|
190
|
+
$optionValues = [System.Collections.Generic.List[string]]::new()
|
|
191
|
+
$tokens = if ($match.Segment.ArgumentInjected) { [string[]]@() } else { [string[]]@($match.Segment.Tokens) }
|
|
192
|
+
$afterSeparator = $false
|
|
193
|
+
for ($index = [int]$match.OperandIndex; $index -lt $tokens.Count; $index++) {
|
|
194
|
+
$token = $tokens[$index]
|
|
195
|
+
if (-not $afterSeparator -and $token -match '^(<|>|\d*>|&>)') {
|
|
196
|
+
if ($token -match '^(\d*[<>]{1,2}&?|&>{1,2})$') { $index++ }
|
|
197
|
+
continue
|
|
198
|
+
}
|
|
199
|
+
if ($afterSeparator -or -not $token.StartsWith('-')) { $walked.Add($token); continue }
|
|
200
|
+
if ($token -ceq '--') { $afterSeparator = $true; continue }
|
|
201
|
+
$name = if ($token.IndexOf('=') -gt 0) { $token.Substring(0, $token.IndexOf('=')) } else { $token }
|
|
202
|
+
if ($valueOptions[$subcommand] -ccontains $name) {
|
|
203
|
+
if ($name -ceq $token -and $index + 1 -lt $tokens.Count) { $index++; $optionValues.Add($tokens[$index]) }
|
|
204
|
+
continue
|
|
205
|
+
}
|
|
206
|
+
if ($token -match '^-[^-].' -and $valueOptions[$subcommand] -ccontains $token.Substring(0, 2)) { continue }
|
|
207
|
+
if ($flagOptions[$subcommand] -ccontains $token) { continue }
|
|
208
|
+
break
|
|
209
|
+
}
|
|
210
|
+
$candidates = @(@($match.GlobalOptions) | Where-Object { $_.Name -ceq '-C' -and $_.Value } | ForEach-Object { [string]$_.Value })
|
|
211
|
+
$candidates += @(@($match.Operands) | Where-Object { $_ -match $absolutePattern -and $optionValues -cnotcontains $_ })
|
|
212
|
+
$candidates += @($walked | Where-Object { $_ -match $absolutePattern -and (Test-CommandLineTokenLiteral -Token $_) })
|
|
213
|
+
foreach ($candidate in $candidates) {
|
|
214
|
+
if ($paths -notcontains $candidate) { $paths.Add($candidate) }
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return [string[]]$paths.ToArray()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function Resolve-OrchestrationGateTarget {
|
|
222
|
+
<#
|
|
223
|
+
.SYNOPSIS
|
|
224
|
+
Resolves the worktree whose checkpoint governs a single-feature path or command leg (issue #1010).
|
|
225
|
+
.DESCRIPTION
|
|
226
|
+
Calls Resolve-HookTargetWorktree with the recording invoker: a file path is passed as
|
|
227
|
+
-FilePath, the marker paths of an apply_patch body as -FilePath (markers in two
|
|
228
|
+
worktrees resolve as ambiguous), and any other command's
|
|
229
|
+
Get-OrchestrationGateCommandOperandPath result as -CommandOperandPath. A failed or
|
|
230
|
+
empty listing gives NoTarget instead of the session-root fallback; Ambiguous gives
|
|
231
|
+
Ambiguous; a null root gives NoTarget; otherwise SessionRoot or OtherWorktree.
|
|
232
|
+
.OUTPUTS
|
|
233
|
+
System.Management.Automation.PSCustomObject with Status, WorktreeRoot, ReasonCode, and Detail.
|
|
234
|
+
#>
|
|
235
|
+
[CmdletBinding()]
|
|
236
|
+
[OutputType([pscustomobject])]
|
|
237
|
+
param(
|
|
238
|
+
[AllowNull()][AllowEmptyString()][string] $FilePath = '',
|
|
239
|
+
[AllowNull()][AllowEmptyString()][string] $Command = ''
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
$sessionRoot = (Get-Location).Path
|
|
243
|
+
$script:OrchestrationGateWorktreeListFailed = $false
|
|
244
|
+
$invoker = { param($SessionRoot) Invoke-OrchestrationGateWorktreeList -SessionRoot $SessionRoot }
|
|
245
|
+
$markerPaths = if ($FilePath) { @() } else { @(Get-OrchestrationPatchMarkerPath -PatchText ([string]$Command)) }
|
|
246
|
+
$resolved = if ($FilePath) {
|
|
247
|
+
Resolve-HookTargetWorktree -SessionRoot $sessionRoot -FilePath @($FilePath) -WorktreeListInvoker $invoker
|
|
248
|
+
} elseif ($markerPaths.Count -gt 0) {
|
|
249
|
+
Resolve-HookTargetWorktree -SessionRoot $sessionRoot -FilePath $markerPaths -WorktreeListInvoker $invoker
|
|
250
|
+
} else {
|
|
251
|
+
Resolve-HookTargetWorktree -SessionRoot $sessionRoot -CommandOperandPath @(Get-OrchestrationGateCommandOperandPath -Command ([string]$Command)) -WorktreeListInvoker $invoker
|
|
252
|
+
}
|
|
253
|
+
$detail = "resolver source $($resolved.Source): $($resolved.Detail)"
|
|
254
|
+
if ($script:OrchestrationGateWorktreeListFailed) {
|
|
255
|
+
return [pscustomobject]@{ Status = 'NoTarget'; WorktreeRoot = $null; ReasonCode = $script:OrchestrationGateNotDerivableReasonCode; Detail = "the worktree listing failed or named no worktree; $detail" }
|
|
256
|
+
}
|
|
257
|
+
if ($resolved.Ambiguous) {
|
|
258
|
+
return [pscustomobject]@{ Status = 'Ambiguous'; WorktreeRoot = $null; ReasonCode = $script:OrchestrationGateAmbiguousReasonCode; Detail = $detail }
|
|
259
|
+
}
|
|
260
|
+
if ([string]::IsNullOrEmpty([string]$resolved.WorktreeRoot)) {
|
|
261
|
+
return [pscustomobject]@{ Status = 'NoTarget'; WorktreeRoot = $null; ReasonCode = $script:OrchestrationGateNotDerivableReasonCode; Detail = $detail }
|
|
262
|
+
}
|
|
263
|
+
$isSession = [string]::Equals([string]$resolved.WorktreeRoot, (ConvertTo-HookTargetWorktreeNormalizedPath -Path $sessionRoot), [System.StringComparison]::OrdinalIgnoreCase)
|
|
264
|
+
$status = if ($isSession) { 'SessionRoot' } else { 'OtherWorktree' }
|
|
265
|
+
return [pscustomobject]@{ Status = $status; WorktreeRoot = [string]$resolved.WorktreeRoot; ReasonCode = $null; Detail = $detail }
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function Read-OrchestrationGateCheckpoint {
|
|
269
|
+
<#
|
|
270
|
+
.SYNOPSIS
|
|
271
|
+
Reads the checkpoint beneath the resolved target worktree, or returns the deny reason.
|
|
272
|
+
.DESCRIPTION
|
|
273
|
+
Resolved is $false, with DenyReason set, when the target is NoTarget or Ambiguous.
|
|
274
|
+
Otherwise Raw holds the checkpoint text (empty when absent) and Path its absolute
|
|
275
|
+
path, composed beneath the resolved root with a forward slash.
|
|
276
|
+
.OUTPUTS
|
|
277
|
+
System.Management.Automation.PSCustomObject
|
|
278
|
+
#>
|
|
279
|
+
[CmdletBinding()]
|
|
280
|
+
[OutputType([pscustomobject])]
|
|
281
|
+
param(
|
|
282
|
+
[Parameter(Mandatory)][string] $Mode,
|
|
283
|
+
[AllowNull()][AllowEmptyString()][string] $FilePath = '',
|
|
284
|
+
[AllowNull()][AllowEmptyString()][string] $Command = ''
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
$target = Resolve-OrchestrationGateTarget -FilePath $FilePath -Command $Command
|
|
288
|
+
if ($target.Status -eq 'NoTarget' -or $target.Status -eq 'Ambiguous') {
|
|
289
|
+
return [pscustomobject]@{
|
|
290
|
+
Resolved = $false
|
|
291
|
+
Raw = ''
|
|
292
|
+
Path = $null
|
|
293
|
+
DenyReason = ("PREIMPLEMENTATION_GATE_BLOCKED: $($target.ReasonCode): the target worktree of this $Mode call " +
|
|
294
|
+
"could not be resolved: $($target.Detail). Implementation operations require an identifiable target " +
|
|
295
|
+
'worktree whose checkpoint is ready.')
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
$path = ([string]$target.WorktreeRoot).TrimEnd('/') + '/artifacts/orchestration/orchestrator-state.json'
|
|
300
|
+
return [pscustomobject]@{
|
|
301
|
+
Resolved = $true
|
|
302
|
+
Raw = [string](Get-CheckpointContent -Path $path)
|
|
303
|
+
Path = $path
|
|
304
|
+
DenyReason = $null
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
71
308
|
function Get-OrchestrationEpicScopeSelector {
|
|
72
309
|
<#
|
|
73
310
|
.SYNOPSIS
|
|
@@ -33,8 +33,6 @@ try { . (Join-Path $PSScriptRoot 'enforce-orchestration-preimplementation-gate-e
|
|
|
33
33
|
# Shared command-line parser (issue #545): per-segment scan text and structural matching.
|
|
34
34
|
try { . (Join-Path $PSScriptRoot 'hook-command-scanner.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-scanner.ps1' -ErrorRecord $_ }
|
|
35
35
|
try { . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-invocation.ps1' -ErrorRecord $_ }
|
|
36
|
-
# The readiness checkpoint this gate reads and names in its block message.
|
|
37
|
-
$script:CheckpointPath = 'artifacts/orchestration/orchestrator-state.json'
|
|
38
36
|
|
|
39
37
|
# Every orchestration checkpoint a planner or orchestrator surface writes. Writing one
|
|
40
38
|
# of these is orchestration bookkeeping, not implementation, so the gate must not
|
|
@@ -270,7 +268,7 @@ function Test-OrchestrationReady {
|
|
|
270
268
|
}
|
|
271
269
|
$lifecycleReady = $false
|
|
272
270
|
if ($Payload.PSObject.Properties.Name -contains 'lifecycle_ready') {
|
|
273
|
-
$lifecycleReady = [bool]$Payload.lifecycle_ready
|
|
271
|
+
$lifecycleReady = ($Payload.lifecycle_ready -is [bool]) -and $Payload.lifecycle_ready
|
|
274
272
|
}
|
|
275
273
|
|
|
276
274
|
if (-not $issueNum -or -not $featureFolder -or -not $routeId -or -not $lifecycleReady) {
|
|
@@ -284,17 +282,6 @@ function Test-OrchestrationReady {
|
|
|
284
282
|
)
|
|
285
283
|
}
|
|
286
284
|
|
|
287
|
-
function Get-CheckpointContent {
|
|
288
|
-
[CmdletBinding()]
|
|
289
|
-
[OutputType([string])]
|
|
290
|
-
param()
|
|
291
|
-
|
|
292
|
-
if (-not (Test-Path -LiteralPath $script:CheckpointPath)) {
|
|
293
|
-
return ''
|
|
294
|
-
}
|
|
295
|
-
return Get-Content -Raw -LiteralPath $script:CheckpointPath
|
|
296
|
-
}
|
|
297
|
-
|
|
298
285
|
function Get-OrchestrationPreimplementationGateAllowDecision {
|
|
299
286
|
[CmdletBinding()]
|
|
300
287
|
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
@@ -445,8 +432,12 @@ function Invoke-OrchestrationPreimplementationGateDecision {
|
|
|
445
432
|
Get-OrchestrationModeDenyReason -Mode $mode -Failure $failure)
|
|
446
433
|
}
|
|
447
434
|
|
|
435
|
+
# Truthiness fall-through is kept: an empty -CheckpointRaw resolves like an unbound one.
|
|
436
|
+
# The checkpoint is read beneath the worktree the call targets (issue #1010).
|
|
448
437
|
if (-not $CheckpointRaw) {
|
|
449
|
-
$
|
|
438
|
+
$read = Read-OrchestrationGateCheckpoint -Mode 'single-feature' -FilePath $filePath -Command $command
|
|
439
|
+
if (-not $read.Resolved) { return Get-OrchestrationPreimplementationGateBlockDecision -Reason $read.DenyReason }
|
|
440
|
+
$CheckpointRaw = $read.Raw
|
|
450
441
|
}
|
|
451
442
|
try {
|
|
452
443
|
$checkpoint = ConvertFrom-CheckpointJson -Json $CheckpointRaw
|
package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1
CHANGED
|
@@ -8,14 +8,26 @@
|
|
|
8
8
|
operation. When the target file is a PowerShell source file (.ps1, .psm1, .psd1),
|
|
9
9
|
it decides whether the change may proceed in direct mode.
|
|
10
10
|
|
|
11
|
-
Direct mode counts distinct production PowerShell paths per Codex session
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
Direct mode counts distinct production PowerShell paths per Codex session and per
|
|
12
|
+
resolved target worktree, and repeated edits to the same file are counted once. The
|
|
13
|
+
4th distinct production path in one worktree is denied with a
|
|
14
|
+
POWERSHELL_LARGE_PATH_REQUIRED reason that instructs the caller to route the change
|
|
15
|
+
through .codex/prompts/orchestrate-work.md.
|
|
16
|
+
|
|
17
|
+
Each evaluated path is placed with Resolve-HookTargetWorktree from the dot-sourced
|
|
18
|
+
hook-target-worktree.ps1. An absolute path resolves to its nearest enclosing
|
|
19
|
+
registered git worktree; a relative path, a path inside no registered worktree, and
|
|
20
|
+
an ambiguous result use the session root. 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
|
+
.codex/state/powershell-batch-budget.<session_id>.json when the resolved target worktree
|
|
24
|
+
is the session root and in .codex/state/powershell-batch-budget.<session_id>.<worktree key>.json
|
|
25
|
+
otherwise; no state is written under another worktree. A path under the root-level
|
|
26
|
+
artifacts/ directory of the resolved target worktree is never counted and writes no
|
|
27
|
+
state. No containment filter applies: a path outside every registered worktree is
|
|
28
|
+
counted against the session root, as before.
|
|
29
|
+
|
|
30
|
+
The selected route is the
|
|
19
31
|
route_id value when that key is present, otherwise the path_selected value, and it
|
|
20
32
|
is usable only as a non-blank string. When the selected route is large,
|
|
21
33
|
remediation, or preparation and the checkpoint is not terminal (next_step is not
|
|
@@ -36,9 +48,12 @@
|
|
|
36
48
|
hookSpecificOutput.permissionDecision = 'deny' and exits 0. Files already counted
|
|
37
49
|
are always allowed through.
|
|
38
50
|
|
|
39
|
-
Known
|
|
40
|
-
|
|
41
|
-
|
|
51
|
+
Known limitations: an 8.3 short-name path, or a path reached through a junction,
|
|
52
|
+
that differs textually from the long path git reports matches no registered
|
|
53
|
+
worktree and falls back to the session root. A stale non-terminal large-path
|
|
54
|
+
checkpoint in a worktree exempts a later direct-mode session editing that worktree;
|
|
55
|
+
orchestrator checkpoint hygiene (issue #673) moves foreign checkpoints aside before
|
|
56
|
+
a new run.
|
|
42
57
|
|
|
43
58
|
.NOTES
|
|
44
59
|
Compatible with PowerShell 7+.
|
|
@@ -51,6 +66,9 @@ $script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot
|
|
|
51
66
|
# mapping for every tool name the ^(apply_patch|Edit|Write)$ matcher admits.
|
|
52
67
|
try { . (Join-Path $PSScriptRoot 'codex-pretooluse-file-mapping.ps1') } catch { Add-HookDependencyFailure -Name 'codex-pretooluse-file-mapping.ps1' -ErrorRecord $_ }
|
|
53
68
|
|
|
69
|
+
# Shared target-worktree resolver; the Codex twin of HookTargetWorktree.psm1.
|
|
70
|
+
try { . (Join-Path $PSScriptRoot 'hook-target-worktree.ps1') } catch { Add-HookDependencyFailure -Name 'hook-target-worktree.ps1' -ErrorRecord $_ }
|
|
71
|
+
|
|
54
72
|
# Shared route helpers; this file is byte-identical to the Claude runtime copy.
|
|
55
73
|
$script:PowerShellBatchBudgetRouteImportFailure = $null; try { . (Join-Path $PSScriptRoot 'enforce-batch-budget-route.ps1') } catch { $script:PowerShellBatchBudgetRouteImportFailure = 'enforce-batch-budget-route.ps1' }
|
|
56
74
|
|
|
@@ -194,7 +212,8 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
194
212
|
[scriptblock] $WriteState = {
|
|
195
213
|
param([string] $Path, [System.Collections.IDictionary] $State)
|
|
196
214
|
$State | ConvertTo-Json -Depth 5 | Set-Content -Path $Path -Encoding UTF8
|
|
197
|
-
}
|
|
215
|
+
},
|
|
216
|
+
[scriptblock] $WorktreeListInvoker
|
|
198
217
|
)
|
|
199
218
|
|
|
200
219
|
if (-not $ToolInputRaw) {
|
|
@@ -218,12 +237,31 @@ function Invoke-PowerShellBatchBudgetHook {
|
|
|
218
237
|
}
|
|
219
238
|
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." }
|
|
220
239
|
|
|
240
|
+
# The path is evaluated against the registered worktree that holds it; the session root
|
|
241
|
+
# is the fallback for a relative path, a path in no registered worktree, and an ambiguous result.
|
|
242
|
+
$resolverArguments = @{ SessionRoot = $Root; FilePath = @($filePath) }
|
|
243
|
+
if ($PSBoundParameters.ContainsKey('WorktreeListInvoker')) { $resolverArguments['WorktreeListInvoker'] = $WorktreeListInvoker }
|
|
244
|
+
$resolution = Resolve-HookTargetWorktree @resolverArguments
|
|
245
|
+
$targetRoot = $Root
|
|
246
|
+
$isSessionRoot = $true
|
|
247
|
+
if (-not $resolution.Ambiguous -and $null -ne $resolution.WorktreeRoot -and -not [string]::Equals($resolution.WorktreeRoot, (ConvertTo-HookTargetWorktreeNormalizedPath -Path $Root), [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
248
|
+
$targetRoot = $resolution.WorktreeRoot
|
|
249
|
+
$isSessionRoot = $false
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
# The root-level artifacts/ directory is gitignored scratch, never a production file.
|
|
253
|
+
$relativePath = if ($normalized -match '^(/|[A-Za-z]:/)') { Get-HookTargetWorktreeRelativePath -Path $normalized -WorktreeRoot $targetRoot } else { $normalized }
|
|
254
|
+
if ($null -ne $relativePath -and $relativePath.StartsWith('artifacts/', [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
255
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
256
|
+
}
|
|
257
|
+
|
|
221
258
|
$stateDir = Join-Path -Path $Root -ChildPath '.codex/state'
|
|
222
|
-
$
|
|
259
|
+
$stateLeaf = if ($isSessionRoot) { "powershell-batch-budget.$SessionId.json" } else { "powershell-batch-budget.$SessionId.$(Get-HookTargetWorktreeKey -WorktreeRoot $targetRoot).json" }
|
|
260
|
+
$stateFile = Join-Path -Path $stateDir -ChildPath $stateLeaf
|
|
223
261
|
|
|
224
262
|
# The checkpoint is read before any state operation, so the large path neither
|
|
225
263
|
# creates the state directory nor reads or writes the state file.
|
|
226
|
-
$checkpointPath = Join-Path -Path $
|
|
264
|
+
$checkpointPath = Join-Path -Path $targetRoot -ChildPath 'artifacts/orchestration/orchestrator-state.json'
|
|
227
265
|
$checkpointText = ''
|
|
228
266
|
try {
|
|
229
267
|
$checkpointText = [string](& $ReadCheckpoint $checkpointPath)
|
|
@@ -279,7 +317,8 @@ function Invoke-PowerShellBatchBudgetCodexEntryPoint {
|
|
|
279
317
|
.PARAMETER PayloadRaw
|
|
280
318
|
Raw PreToolUse payload text.
|
|
281
319
|
.PARAMETER RepositoryRoot
|
|
282
|
-
|
|
320
|
+
Session root: it locates the Codex state directory and is the fallback root. The
|
|
321
|
+
orchestrator checkpoint comes from the resolved target worktree of each path.
|
|
283
322
|
.PARAMETER HookSeams
|
|
284
323
|
Optional seam overrides splatted into Invoke-PowerShellBatchBudgetHook.
|
|
285
324
|
#>
|