@danmoisan/drm-copilot-mcp 1.1.22 → 1.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/mcp-server.js +18758 -12030
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -0
- package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
- package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +101 -43
- package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +107 -43
- package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +60 -6
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/pr-author.md +48 -7
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +117 -42
- package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +103 -43
- package/resources/claude-customizations/.claude/hooks/discovery-capability-probe.ps1 +102 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +69 -194
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-planning-gate.ps1 +87 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +29 -7
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
- package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +51 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +168 -48
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +51 -4
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +72 -11
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +4 -2
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/record-discovery-agent-start.ps1 +132 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +56 -212
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-rejection.ps1 +172 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +34 -4
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +9 -3
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusAggregate.psm1 +154 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusCombination.psm1 +228 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +1 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +4 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +63 -16
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +56 -1
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +4 -1
- package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +5 -1
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +25 -2
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +188 -341
- package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
- package/resources/claude-customizations/.claude/lib/worktree-resolution/HookTargetWorktree.psm1 +391 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
- package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +29 -5
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +152 -20
- package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
- package/resources/claude-customizations/.claude/rules/shell.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +36 -3
- package/resources/claude-customizations/.claude/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/claude-customizations/.claude/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
- package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +28 -47
- package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +32 -48
- package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +28 -45
- package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +28 -62
- package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +28 -45
- package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +28 -61
- package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +55 -139
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +25 -10
- package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
- package/resources/claude-customizations/.claude/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/claude-customizations/.claude/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +15 -7
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +25 -2
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +124 -14
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +72 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +56 -9
- package/resources/claude-customizations/.claude/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/claude-customizations/.claude/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
- package/resources/claude-customizations/config/blast-radius.json +6 -5
- package/resources/claude-customizations/config/orchestration-routing.json +61 -1
- package/resources/claude-customizations/pack-manifests/core.json +40 -1
- package/resources/codex-and-agents-customizations/.agents/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +7 -0
- package/resources/codex-and-agents-customizations/.agents/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-coverage-ledger/SKILL.md +50 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-parity-matrix/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-repo-inventory/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-runtime-characterization/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-validate-artifacts/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-workflow/SKILL.md +62 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +25 -10
- package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
- package/resources/codex-and-agents-customizations/.agents/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/codex-and-agents-customizations/.agents/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/codex-and-agents-customizations/.agents/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/discovery-capability-sentinel.toml +51 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c1.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c2.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3-elevated.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c4.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c1.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c2.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3-elevated.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c4.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c1.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c2.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3-elevated.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c4.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c1.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c2.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3-elevated.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c4.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +39 -3
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +22 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/discovery-capability-probe.ps1 +97 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1 +171 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +4 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1 +187 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1 +149 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +239 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +54 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +54 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-target-worktree.ps1 +369 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +8 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +22 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1 +178 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +11 -1
- package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +65 -1
- package/resources/config/orchestration-routing.json +61 -1
- package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
- package/resources/customizations/.github/agents/discovery-capability-sentinel.agent.md +34 -0
- package/resources/customizations/.github/agents/legacy-parity-analyst.agent.md +122 -0
- package/resources/customizations/.github/agents/migration-coverage-reviewer.agent.md +128 -0
- package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
- package/resources/customizations/.github/agents/requirements-reconciler.agent.md +138 -0
- package/resources/customizations/.github/agents/runtime-characterization-analyst.agent.md +124 -0
- package/resources/customizations/.github/hooks/discovery-agent-start.ps1 +139 -0
- package/resources/customizations/.github/hooks/discovery-agent-stop.ps1 +123 -0
- package/resources/customizations/.github/hooks/discovery-capability-probe.ps1 +98 -0
- package/resources/customizations/.github/hooks/discovery-planning.ps1 +91 -0
- package/resources/customizations/.github/hooks/discovery-pre-tool.ps1 +123 -0
- package/resources/customizations/.github/hooks/discovery.json +35 -0
- package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
- package/resources/customizations/.github/instructions/mermaid.instructions.md +85 -0
- package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
- package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
- package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
- package/resources/customizations/.github/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/customizations/.github/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/customizations/.github/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-coverage-ledger/SKILL.md +50 -0
- package/resources/customizations/.github/skills/discovery-parity-matrix/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-repo-inventory/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-runtime-characterization/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-validate-artifacts/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-workflow/SKILL.md +62 -0
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +25 -10
- package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
- package/resources/customizations/.github/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/customizations/.github/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/customizations/.github/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/customizations/.github/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/customizations/.github/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/customizations/.github/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/lib/codex-routing/CodexDeployment.psm1 +5 -1
- package/resources/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
- package/resources/lib/codex-routing/CodexTopology.psm1 +25 -2
- package/resources/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
- package/resources/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
- package/resources/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
- package/resources/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
- package/resources/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
- package/resources/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
- package/resources/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
- package/resources/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
- package/resources/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
- package/resources/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
- package/resources/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
- package/resources/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
- package/resources/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
- package/resources/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
- package/resources/powershell/PoshQC/PoshQC.Parallel.psm1 +452 -0
- package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +106 -8
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -0
- package/resources/powershell/PoshQC/PoshQC.psd1 +6 -1
- package/resources/powershell/PoshQC/PoshQC.psm1 +7 -1
- package/resources/powershell/PoshQC/README.md +20 -1
- package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Codex twin of the HookTargetWorktree target-worktree resolver functions (issue #1009).
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Source: .claude/lib/worktree-resolution/HookTargetWorktree.psm1. This file carries the
|
|
7
|
+
six functions of that module with byte-identical function text, because Codex hooks
|
|
8
|
+
cannot import .claude/lib in a consumer repository: a consumer receives the .codex
|
|
9
|
+
runtime without the Claude library. tests/scripts/codex-hooks/hook-target-worktree.Tests.ps1
|
|
10
|
+
holds the function names and each function's text equal to the module and runs the
|
|
11
|
+
shared resolver behavior rows against this file.
|
|
12
|
+
|
|
13
|
+
Functions-only: the file has no entry point and no statement outside the function
|
|
14
|
+
definitions. It is dot-sourced by .codex/hooks/enforce-python-batch-budget.ps1 and
|
|
15
|
+
.codex/hooks/enforce-powershell-batch-budget.ps1. Edit the module first, then copy the
|
|
16
|
+
changed function text here.
|
|
17
|
+
|
|
18
|
+
.NOTES
|
|
19
|
+
Compatible with PowerShell 7+. Mirrored byte-identically under
|
|
20
|
+
extensions/drm-copilot/resources/codex-and-agents-customizations/.
|
|
21
|
+
#>
|
|
22
|
+
|
|
23
|
+
function ConvertTo-HookTargetWorktreeNormalizedPath {
|
|
24
|
+
<#
|
|
25
|
+
.SYNOPSIS
|
|
26
|
+
Normalize a path to forward slashes with repeated and trailing slashes removed.
|
|
27
|
+
.DESCRIPTION
|
|
28
|
+
Backslashes become forward slashes, runs of slashes collapse to one, and a trailing
|
|
29
|
+
slash is trimmed except from a bare root ('/' or a drive root such as 'C:/'). Blank
|
|
30
|
+
input returns an empty string. Case is preserved; callers compare with
|
|
31
|
+
OrdinalIgnoreCase.
|
|
32
|
+
.PARAMETER Path
|
|
33
|
+
The path to normalize.
|
|
34
|
+
#>
|
|
35
|
+
[CmdletBinding()]
|
|
36
|
+
[OutputType([string])]
|
|
37
|
+
param(
|
|
38
|
+
[AllowNull()] [AllowEmptyString()] [string] $Path
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if ([string]::IsNullOrWhiteSpace($Path)) { return '' }
|
|
42
|
+
$normalized = ($Path.Trim() -replace '\\', '/') -replace '/{2,}', '/'
|
|
43
|
+
if ($normalized.Length -gt 1 -and $normalized.EndsWith('/') -and $normalized -notmatch '^[A-Za-z]:/$') {
|
|
44
|
+
$normalized = $normalized.Substring(0, $normalized.Length - 1)
|
|
45
|
+
}
|
|
46
|
+
return $normalized
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function Get-HookTargetWorktreeRelativePath {
|
|
50
|
+
<#
|
|
51
|
+
.SYNOPSIS
|
|
52
|
+
Return a path relative to a worktree root, or $null when it lies outside the root.
|
|
53
|
+
.DESCRIPTION
|
|
54
|
+
Both values are normalized first. A path equal to the root returns an empty string;
|
|
55
|
+
a path under the root returns its forward-slash remainder; any other path, or a
|
|
56
|
+
blank value, returns $null.
|
|
57
|
+
.PARAMETER Path
|
|
58
|
+
The path to express relative to the root.
|
|
59
|
+
.PARAMETER WorktreeRoot
|
|
60
|
+
The worktree root.
|
|
61
|
+
#>
|
|
62
|
+
[CmdletBinding()]
|
|
63
|
+
[OutputType([string])]
|
|
64
|
+
param(
|
|
65
|
+
[AllowNull()] [AllowEmptyString()] [string] $Path,
|
|
66
|
+
[AllowNull()] [AllowEmptyString()] [string] $WorktreeRoot
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
$normalizedPath = ConvertTo-HookTargetWorktreeNormalizedPath -Path $Path
|
|
70
|
+
$normalizedRoot = ConvertTo-HookTargetWorktreeNormalizedPath -Path $WorktreeRoot
|
|
71
|
+
if ([string]::IsNullOrEmpty($normalizedPath) -or [string]::IsNullOrEmpty($normalizedRoot)) { return $null }
|
|
72
|
+
if ([string]::Equals($normalizedPath, $normalizedRoot, [System.StringComparison]::OrdinalIgnoreCase)) { return '' }
|
|
73
|
+
$prefix = if ($normalizedRoot.EndsWith('/')) { $normalizedRoot } else { $normalizedRoot + '/' }
|
|
74
|
+
if ($normalizedPath.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
75
|
+
return $normalizedPath.Substring($prefix.Length)
|
|
76
|
+
}
|
|
77
|
+
return $null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function Get-HookTargetWorktreeEnclosingRoot {
|
|
81
|
+
<#
|
|
82
|
+
.SYNOPSIS
|
|
83
|
+
Return the nearest root that encloses a path, or $null when none does.
|
|
84
|
+
.DESCRIPTION
|
|
85
|
+
A root encloses a path when the normalized path equals the normalized root or
|
|
86
|
+
starts with the root followed by a slash. When several roots enclose the path, the
|
|
87
|
+
longest one wins, so a worktree nested inside another wins for paths under it.
|
|
88
|
+
.PARAMETER Path
|
|
89
|
+
The path to place.
|
|
90
|
+
.PARAMETER Roots
|
|
91
|
+
The candidate worktree roots.
|
|
92
|
+
#>
|
|
93
|
+
[CmdletBinding()]
|
|
94
|
+
[OutputType([string])]
|
|
95
|
+
param(
|
|
96
|
+
[AllowNull()] [AllowEmptyString()] [string] $Path,
|
|
97
|
+
[AllowNull()] [AllowEmptyCollection()] [string[]] $Roots
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
$best = $null
|
|
101
|
+
foreach ($root in @($Roots)) {
|
|
102
|
+
$normalizedRoot = ConvertTo-HookTargetWorktreeNormalizedPath -Path $root
|
|
103
|
+
if ([string]::IsNullOrEmpty($normalizedRoot)) { continue }
|
|
104
|
+
$relative = Get-HookTargetWorktreeRelativePath -Path $Path -WorktreeRoot $normalizedRoot
|
|
105
|
+
if ($null -ne $relative -and ($null -eq $best -or $normalizedRoot.Length -gt $best.Length)) { $best = $normalizedRoot }
|
|
106
|
+
}
|
|
107
|
+
return $best
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function Get-HookTargetWorktreeKey {
|
|
111
|
+
<#
|
|
112
|
+
.SYNOPSIS
|
|
113
|
+
Return the stable key '<sanitized leaf>-<8 hex>' that names a worktree root.
|
|
114
|
+
.DESCRIPTION
|
|
115
|
+
The hex part is the first four bytes of the SHA-256 of the normalized root with no
|
|
116
|
+
trailing slash, and the leaf is reduced to file-name-safe characters. The algorithm
|
|
117
|
+
equals the worktree-derived batch-budget session id, which prefixes 'worktree-'.
|
|
118
|
+
.PARAMETER WorktreeRoot
|
|
119
|
+
The worktree root to key.
|
|
120
|
+
#>
|
|
121
|
+
[CmdletBinding()]
|
|
122
|
+
[OutputType([string])]
|
|
123
|
+
param(
|
|
124
|
+
[Parameter(Mandatory)] [string] $WorktreeRoot
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
$normalizedRoot = (ConvertTo-HookTargetWorktreeNormalizedPath -Path $WorktreeRoot).TrimEnd('/')
|
|
128
|
+
$leaf = $normalizedRoot.Substring($normalizedRoot.LastIndexOf('/') + 1) -replace '[^A-Za-z0-9._-]', '_'
|
|
129
|
+
$hashBytes = [System.Security.Cryptography.SHA256]::HashData([System.Text.Encoding]::UTF8.GetBytes($normalizedRoot))
|
|
130
|
+
$shortHash = -join (@($hashBytes[0..3]) | ForEach-Object { $_.ToString('x2') })
|
|
131
|
+
return "$leaf-$shortHash"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function ConvertFrom-HookTargetWorktreePorcelain {
|
|
135
|
+
<#
|
|
136
|
+
.SYNOPSIS
|
|
137
|
+
Parse `git worktree list --porcelain` text into worktree records.
|
|
138
|
+
.DESCRIPTION
|
|
139
|
+
Emits one record per non-bare stanza with Root (normalized), Branch (the short
|
|
140
|
+
branch name, or $null when detached), Bare, and Prunable. A bare stanza is skipped.
|
|
141
|
+
Blank lines separate stanzas, and CRLF line endings are tolerated.
|
|
142
|
+
.PARAMETER Text
|
|
143
|
+
The porcelain text.
|
|
144
|
+
#>
|
|
145
|
+
[CmdletBinding()]
|
|
146
|
+
[OutputType([pscustomobject])]
|
|
147
|
+
param(
|
|
148
|
+
[AllowNull()] [AllowEmptyString()] [string] $Text
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
$records = [System.Collections.Generic.List[object]]::new()
|
|
152
|
+
$stanza = $null
|
|
153
|
+
foreach ($rawLine in @(([string] $Text -split "`r?`n") + '')) {
|
|
154
|
+
$line = $rawLine.Trim()
|
|
155
|
+
if ($line -eq '' -or $line.StartsWith('worktree ')) {
|
|
156
|
+
if ($null -ne $stanza -and -not $stanza.Bare) {
|
|
157
|
+
$records.Add([pscustomobject]@{ Root = $stanza.Root; Branch = $stanza.Branch; Bare = $false; Prunable = $stanza.Prunable })
|
|
158
|
+
}
|
|
159
|
+
$stanza = $null
|
|
160
|
+
if ($line -ne '') {
|
|
161
|
+
$stanza = @{ Root = (ConvertTo-HookTargetWorktreeNormalizedPath -Path $line.Substring(9)); Branch = $null; Bare = $false; Prunable = $false }
|
|
162
|
+
}
|
|
163
|
+
continue
|
|
164
|
+
}
|
|
165
|
+
if ($null -eq $stanza) { continue }
|
|
166
|
+
if ($line -eq 'bare') {
|
|
167
|
+
$stanza.Bare = $true
|
|
168
|
+
} elseif ($line.StartsWith('branch ')) {
|
|
169
|
+
$reference = $line.Substring(7).Trim()
|
|
170
|
+
$stanza.Branch = if ($reference.StartsWith('refs/heads/')) { $reference.Substring(11) } else { $reference }
|
|
171
|
+
} elseif ($line -eq 'detached') {
|
|
172
|
+
$stanza.Branch = $null
|
|
173
|
+
} elseif ($line -eq 'prunable' -or $line.StartsWith('prunable ')) {
|
|
174
|
+
$stanza.Prunable = $true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return $records.ToArray()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function Resolve-HookTargetWorktree {
|
|
181
|
+
<#
|
|
182
|
+
.SYNOPSIS
|
|
183
|
+
Resolve the registered worktree that a hook call acts on.
|
|
184
|
+
.DESCRIPTION
|
|
185
|
+
The first present source decides, in the order FilePath, CommandOperand (paths
|
|
186
|
+
and/or branch), DelegationIdentity, SessionRoot; a later source is never consulted.
|
|
187
|
+
Relative paths map to the session root without enumerating worktrees. An absolute
|
|
188
|
+
path maps to its nearest enclosing registered worktree, and a path inside none, or
|
|
189
|
+
an invoker that throws or returns no worktree, falls back to the session root.
|
|
190
|
+
Disagreeing components yield TARGET_WORKTREE_AMBIGUOUS; a present branch or
|
|
191
|
+
identity that names no worktree yields TARGET_WORKTREE_NOT_DERIVABLE and never the
|
|
192
|
+
session root. The result carries WorktreeRoot, Source, Ambiguous, ReasonCode,
|
|
193
|
+
Detail, and Candidates. The invoker runs at most once.
|
|
194
|
+
.PARAMETER SessionRoot
|
|
195
|
+
The absolute session root (the hook's root); the fallback root.
|
|
196
|
+
.PARAMETER FilePath
|
|
197
|
+
File-tool target paths.
|
|
198
|
+
.PARAMETER CommandOperandPath
|
|
199
|
+
Command operand paths parsed by the caller.
|
|
200
|
+
.PARAMETER CommandBranch
|
|
201
|
+
A command branch operand parsed by the caller.
|
|
202
|
+
.PARAMETER DelegationPrompt
|
|
203
|
+
Agent delegation prompt text; its 'branch:' label and canonical issue line are read.
|
|
204
|
+
.PARAMETER CheckpointIssueReader
|
|
205
|
+
Optional { param($WorktreeRoot) <issue number or $null> } used only for an issue identity.
|
|
206
|
+
.PARAMETER WorktreeListInvoker
|
|
207
|
+
{ param($SessionRoot) <porcelain text> }; the default runs git worktree list --porcelain.
|
|
208
|
+
#>
|
|
209
|
+
[CmdletBinding()]
|
|
210
|
+
[OutputType([pscustomobject])]
|
|
211
|
+
param(
|
|
212
|
+
[Parameter(Mandatory)] [string] $SessionRoot,
|
|
213
|
+
[AllowNull()] [AllowEmptyCollection()] [string[]] $FilePath,
|
|
214
|
+
[AllowNull()] [AllowEmptyCollection()] [string[]] $CommandOperandPath,
|
|
215
|
+
[AllowNull()] [AllowEmptyString()] [string] $CommandBranch,
|
|
216
|
+
[AllowNull()] [AllowEmptyString()] [string] $DelegationPrompt,
|
|
217
|
+
[scriptblock] $CheckpointIssueReader,
|
|
218
|
+
[scriptblock] $WorktreeListInvoker = { param($SessionRoot) $porcelain = & git -C $SessionRoot worktree list --porcelain 2>$null; if ($LASTEXITCODE -ne 0) { return '' }; return ($porcelain -join "`n") }
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
$ambiguousCode = 'TARGET_WORKTREE_AMBIGUOUS'
|
|
222
|
+
$notDerivableCode = 'TARGET_WORKTREE_NOT_DERIVABLE'
|
|
223
|
+
$ignoreCase = [System.StringComparison]::OrdinalIgnoreCase
|
|
224
|
+
$absolutePattern = '^(/|[A-Za-z]:/)'
|
|
225
|
+
$session = ConvertTo-HookTargetWorktreeNormalizedPath -Path $SessionRoot
|
|
226
|
+
|
|
227
|
+
# Nested helpers are called by constant name and read this function's variables.
|
|
228
|
+
function Get-HookTargetResult {
|
|
229
|
+
param($Root, [string] $Source, $Code, [string] $Detail = '', [string[]] $Candidates = @())
|
|
230
|
+
[pscustomobject]@{
|
|
231
|
+
WorktreeRoot = $Root
|
|
232
|
+
Source = $Source
|
|
233
|
+
Ambiguous = ($Code -eq $ambiguousCode)
|
|
234
|
+
ReasonCode = $Code
|
|
235
|
+
Detail = $Detail
|
|
236
|
+
Candidates = [string[]] @($Candidates)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function Add-HookTargetDistinctValue {
|
|
240
|
+
param([System.Collections.Generic.List[string]] $List, [string] $Value)
|
|
241
|
+
foreach ($existing in $List) { if ([string]::Equals($existing, $Value, $ignoreCase)) { return } }
|
|
242
|
+
$List.Add($Value)
|
|
243
|
+
}
|
|
244
|
+
function Get-HookTargetRecordedIssue {
|
|
245
|
+
param([string] $Root)
|
|
246
|
+
try { $value = ([string] (& $CheckpointIssueReader $Root)).Trim().TrimStart('#') } catch { return $null }
|
|
247
|
+
if ($value -notmatch '^\d+$') { return $null }
|
|
248
|
+
$digits = $value.TrimStart('0')
|
|
249
|
+
return $(if ($digits -eq '') { '0' } else { $digits })
|
|
250
|
+
}
|
|
251
|
+
function Resolve-HookTargetPathSource {
|
|
252
|
+
param([string[]] $Paths, [string] $Source)
|
|
253
|
+
$resolved = [System.Collections.Generic.List[string]]::new()
|
|
254
|
+
$details = [System.Collections.Generic.List[string]]::new()
|
|
255
|
+
$fellBack = $false
|
|
256
|
+
foreach ($candidate in $Paths) {
|
|
257
|
+
$normalized = ConvertTo-HookTargetWorktreeNormalizedPath -Path $candidate
|
|
258
|
+
$root = $session
|
|
259
|
+
if ($normalized -notmatch $absolutePattern) {
|
|
260
|
+
$fellBack = $true
|
|
261
|
+
$details.Add("relative path '$normalized' maps to the session root")
|
|
262
|
+
} else {
|
|
263
|
+
$enclosing = Get-HookTargetWorktreeEnclosingRoot -Path $normalized -Roots $roots
|
|
264
|
+
if ($null -eq $enclosing) {
|
|
265
|
+
$fellBack = $true
|
|
266
|
+
$details.Add($(if ($listDetail) { $listDetail } else { "path '$normalized' is inside no registered worktree" }))
|
|
267
|
+
} else {
|
|
268
|
+
$root = $enclosing
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
Add-HookTargetDistinctValue -List $resolved -Value $root
|
|
272
|
+
}
|
|
273
|
+
if ($resolved.Count -gt 1) {
|
|
274
|
+
return (Get-HookTargetResult -Root $null -Source $Source -Code $ambiguousCode -Detail ('the paths resolve to {0} different worktrees' -f $resolved.Count) -Candidates $resolved.ToArray())
|
|
275
|
+
}
|
|
276
|
+
$decidedBy = if ($fellBack) { 'SessionRoot' } else { $Source }
|
|
277
|
+
return (Get-HookTargetResult -Root $resolved[0] -Source $decidedBy -Code $null -Detail ($details -join '; '))
|
|
278
|
+
}
|
|
279
|
+
function Resolve-HookTargetBranchSource {
|
|
280
|
+
param([string] $Branch, [string] $Source)
|
|
281
|
+
$matched = @($records | Where-Object { $null -ne $_.Branch -and [string]::Equals($_.Branch, $Branch, $ignoreCase) } | ForEach-Object { $_.Root })
|
|
282
|
+
if ($matched.Count -eq 0) { return (Get-HookTargetResult -Root $null -Source $Source -Code $notDerivableCode -Detail "branch '$Branch' is checked out in no registered worktree") }
|
|
283
|
+
if ($matched.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $Source -Code $ambiguousCode -Detail "branch '$Branch' is checked out in $($matched.Count) registered worktrees" -Candidates $matched) }
|
|
284
|
+
return (Get-HookTargetResult -Root $matched[0] -Source $Source -Code $null)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# Select the deciding source: the first present one in precedence order.
|
|
288
|
+
$filePaths = @($FilePath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
289
|
+
$operandPaths = @($CommandOperandPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
290
|
+
$branchOperand = if ([string]::IsNullOrWhiteSpace($CommandBranch)) { '' } else { $CommandBranch.Trim() }
|
|
291
|
+
$branches = [System.Collections.Generic.List[string]]::new()
|
|
292
|
+
$issues = [System.Collections.Generic.List[string]]::new()
|
|
293
|
+
if ($filePaths.Count -gt 0) {
|
|
294
|
+
$source = 'FilePath'
|
|
295
|
+
} elseif ($operandPaths.Count -gt 0 -or $branchOperand) {
|
|
296
|
+
$source = 'CommandOperand'
|
|
297
|
+
} elseif (-not [string]::IsNullOrWhiteSpace($DelegationPrompt)) {
|
|
298
|
+
$source = 'DelegationIdentity'
|
|
299
|
+
foreach ($match in [regex]::Matches($DelegationPrompt, '(?i)\bbranch:\s*(?<name>[A-Za-z0-9][A-Za-z0-9._/-]*)')) {
|
|
300
|
+
Add-HookTargetDistinctValue -List $branches -Value $match.Groups['name'].Value.TrimEnd('.', '/')
|
|
301
|
+
}
|
|
302
|
+
foreach ($match in [regex]::Matches($DelegationPrompt, 'Canonical issue number for this feature is #?(?<number>\d+)')) {
|
|
303
|
+
$digits = $match.Groups['number'].Value.TrimStart('0')
|
|
304
|
+
Add-HookTargetDistinctValue -List $issues -Value $(if ($digits -eq '') { '0' } else { $digits })
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
return (Get-HookTargetResult -Root $session -Source 'SessionRoot' -Code $null -Detail 'no target source is present; the session root applies')
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Enumerate registered worktrees at most once, and only when the deciding source needs them.
|
|
311
|
+
$needsList = switch ($source) {
|
|
312
|
+
'FilePath' { @($filePaths | Where-Object { (ConvertTo-HookTargetWorktreeNormalizedPath -Path $_) -match $absolutePattern }).Count -gt 0 }
|
|
313
|
+
'CommandOperand' { [bool] $branchOperand -or @($operandPaths | Where-Object { (ConvertTo-HookTargetWorktreeNormalizedPath -Path $_) -match $absolutePattern }).Count -gt 0 }
|
|
314
|
+
default { ($branches.Count -eq 1 -and $issues.Count -le 1) -or ($branches.Count -eq 0 -and $issues.Count -eq 1 -and $null -ne $CheckpointIssueReader) }
|
|
315
|
+
}
|
|
316
|
+
$records = @()
|
|
317
|
+
$listDetail = ''
|
|
318
|
+
if ($needsList) {
|
|
319
|
+
try {
|
|
320
|
+
$records = @(ConvertFrom-HookTargetWorktreePorcelain -Text (@(& $WorktreeListInvoker $SessionRoot) -join "`n"))
|
|
321
|
+
if ($records.Count -eq 0) { $listDetail = 'the worktree list returned no registered worktree' }
|
|
322
|
+
} catch {
|
|
323
|
+
$records = @()
|
|
324
|
+
$listDetail = "the worktree list failed: $($_.Exception.Message)"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
$roots = @($records | ForEach-Object { $_.Root })
|
|
328
|
+
|
|
329
|
+
if ($source -eq 'FilePath') { return (Resolve-HookTargetPathSource -Paths $filePaths -Source 'FilePath') }
|
|
330
|
+
|
|
331
|
+
if ($source -eq 'CommandOperand') {
|
|
332
|
+
$pathResult = if ($operandPaths.Count -gt 0) { Resolve-HookTargetPathSource -Paths $operandPaths -Source 'CommandOperand' } else { $null }
|
|
333
|
+
if (-not $branchOperand) { return $pathResult }
|
|
334
|
+
$branchResult = Resolve-HookTargetBranchSource -Branch $branchOperand -Source 'CommandOperand'
|
|
335
|
+
if ($null -eq $pathResult) { return $branchResult }
|
|
336
|
+
if ($pathResult.Ambiguous) { return $pathResult }
|
|
337
|
+
if ($null -ne $branchResult.ReasonCode) { return $branchResult }
|
|
338
|
+
if (-not [string]::Equals($pathResult.WorktreeRoot, $branchResult.WorktreeRoot, $ignoreCase)) {
|
|
339
|
+
return (Get-HookTargetResult -Root $null -Source 'CommandOperand' -Code $ambiguousCode -Detail "the operand paths and branch '$branchOperand' resolve to different worktrees" -Candidates @($pathResult.WorktreeRoot, $branchResult.WorktreeRoot))
|
|
340
|
+
}
|
|
341
|
+
return $branchResult
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if ($branches.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail ('the prompt names {0} different branches: {1}' -f $branches.Count, ($branches -join ', '))) }
|
|
345
|
+
if ($issues.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail ('the prompt names {0} different issue numbers: {1}' -f $issues.Count, ($issues -join ', '))) }
|
|
346
|
+
if ($branches.Count -eq 1) {
|
|
347
|
+
$branchResult = Resolve-HookTargetBranchSource -Branch $branches[0] -Source $source
|
|
348
|
+
if ($null -ne $branchResult.ReasonCode -or $issues.Count -eq 0 -or $null -eq $CheckpointIssueReader) { return $branchResult }
|
|
349
|
+
$target = $branchResult.WorktreeRoot
|
|
350
|
+
$recorded = Get-HookTargetRecordedIssue -Root $target
|
|
351
|
+
if ($null -ne $recorded) {
|
|
352
|
+
if ($recorded -eq $issues[0]) { return $branchResult }
|
|
353
|
+
return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail "branch '$($branches[0])' places the call in a worktree whose checkpoint records issue $recorded, not issue $($issues[0])" -Candidates @($target))
|
|
354
|
+
}
|
|
355
|
+
$elsewhere = @($records | Where-Object { -not [string]::Equals($_.Root, $target, $ignoreCase) -and (Get-HookTargetRecordedIssue -Root $_.Root) -eq $issues[0] } | ForEach-Object { $_.Root })
|
|
356
|
+
if ($elsewhere.Count -gt 0) {
|
|
357
|
+
return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail "branch '$($branches[0])' and issue $($issues[0]) place the call in different worktrees" -Candidates (@($target) + $elsewhere))
|
|
358
|
+
}
|
|
359
|
+
return $branchResult
|
|
360
|
+
}
|
|
361
|
+
if ($issues.Count -eq 1) {
|
|
362
|
+
if ($null -eq $CheckpointIssueReader) { return (Get-HookTargetResult -Root $null -Source $source -Code $notDerivableCode -Detail "issue $($issues[0]) cannot be placed without a checkpoint issue reader") }
|
|
363
|
+
$matched = @($records | Where-Object { (Get-HookTargetRecordedIssue -Root $_.Root) -eq $issues[0] } | ForEach-Object { $_.Root })
|
|
364
|
+
if ($matched.Count -eq 0) { return (Get-HookTargetResult -Root $null -Source $source -Code $notDerivableCode -Detail "issue $($issues[0]) is recorded by no registered worktree") }
|
|
365
|
+
if ($matched.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail "issue $($issues[0]) is recorded by $($matched.Count) registered worktrees" -Candidates $matched) }
|
|
366
|
+
return (Get-HookTargetResult -Root $matched[0] -Source $source -Code $null)
|
|
367
|
+
}
|
|
368
|
+
return (Get-HookTargetResult -Root $null -Source $source -Code $notDerivableCode -Detail 'the prompt carries no branch: label and no canonical issue line')
|
|
369
|
+
}
|
|
@@ -13,6 +13,7 @@ param()
|
|
|
13
13
|
. (Join-Path $PSScriptRoot 'codex-authority-store.ps1')
|
|
14
14
|
. (Join-Path $PSScriptRoot 'codex-agent-profile-attestation.ps1')
|
|
15
15
|
. (Join-Path $PSScriptRoot 'codex-epic-child-launch-attestation.ps1')
|
|
16
|
+
. (Join-Path $PSScriptRoot 'discovery-start-attestation.ps1')
|
|
16
17
|
$script:EpicPersonas = @('epic-planner', 'epic-orchestrator')
|
|
17
18
|
|
|
18
19
|
function ConvertFrom-SubagentAttestationJson {
|
|
@@ -365,6 +366,13 @@ function Invoke-CodexSubagentAttestationCommand {
|
|
|
365
366
|
)
|
|
366
367
|
try {
|
|
367
368
|
$payload = ConvertFrom-SubagentAttestationJson -Raw (& $ReadInput) -Name 'SubagentStart input'
|
|
369
|
+
if (Test-CodexDiscoveryAgentType -AgentType ([string]$payload.agent_type)) {
|
|
370
|
+
# A discovery specialist is attested against its protected invocation only;
|
|
371
|
+
# no checkpoint, HEAD or epic receipt is consulted (issue #980).
|
|
372
|
+
$attestation = Get-CodexDiscoveryStartAttestation -Payload $payload -RepositoryRoot $repositoryRoot -Now (& $GetNow)
|
|
373
|
+
$attestationPath = Write-CodexSubagentAttestation -RepositoryRoot $repositoryRoot -Attestation $attestation
|
|
374
|
+
return [ordered]@{ exit_code = 0; stdout = (Get-CodexDiscoveryStartCommandOutput -Attestation $attestation -AttestationPath $attestationPath); stderr = $null }
|
|
375
|
+
}
|
|
368
376
|
$stateRoot = Join-Path $repositoryRoot 'artifacts/orchestration'
|
|
369
377
|
$receiptPath = Get-CodexAuthorityReceiptPath `
|
|
370
378
|
-RepositoryRoot $repositoryRoot `
|
package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1
CHANGED
|
@@ -31,7 +31,7 @@ function Test-CodexStopGatedAgent {
|
|
|
31
31
|
[OutputType([bool])]
|
|
32
32
|
param([Parameter(Mandatory)][string] $AgentType)
|
|
33
33
|
|
|
34
|
-
if ($AgentType -match '-c(?:1|2|3|4|3-elevated)$') {
|
|
34
|
+
if ($AgentType -match '-c(?:1|2|3|4|3-elevated)$' -or (Test-CodexStopDiscoveryAgent -AgentType $AgentType)) {
|
|
35
35
|
return $true
|
|
36
36
|
}
|
|
37
37
|
return @(
|
|
@@ -42,6 +42,19 @@ function Test-CodexStopGatedAgent {
|
|
|
42
42
|
) -contains $AgentType
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
function Test-CodexStopDiscoveryAgent {
|
|
46
|
+
<#
|
|
47
|
+
.SYNOPSIS
|
|
48
|
+
True for a discovery specialist, whose stop requires the discovery-invocation start attestation (issue #980).
|
|
49
|
+
#>
|
|
50
|
+
[CmdletBinding()]
|
|
51
|
+
[OutputType([bool])]
|
|
52
|
+
param([AllowNull()][AllowEmptyString()][string] $AgentType)
|
|
53
|
+
|
|
54
|
+
return -not [string]::IsNullOrWhiteSpace($AgentType) -and
|
|
55
|
+
$AgentType -cmatch '^(legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer)(-c(1|2|3|4|3-elevated))?$'
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
function Get-CodexStopContinuation {
|
|
46
59
|
[CmdletBinding()]
|
|
47
60
|
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
@@ -98,6 +111,14 @@ function Invoke-CodexSubagentStopDecision {
|
|
|
98
111
|
return Get-CodexStopContinuation -Reason "EPIC_INVOCATION_ORIGIN_BLOCKED: '$agentType' lacks valid root provenance." -AlreadyContinued $alreadyContinued
|
|
99
112
|
}
|
|
100
113
|
}
|
|
114
|
+
if (Test-CodexStopDiscoveryAgent -AgentType $agentType) {
|
|
115
|
+
# A specialist's attestation must be the protected discovery-invocation receipt kind;
|
|
116
|
+
# the output authority itself is validated by validate-discovery-agent-output.ps1.
|
|
117
|
+
$attestationNames = @($attestation.PSObject.Properties.Name)
|
|
118
|
+
if ($attestationNames -notcontains 'receipt_kind' -or [string]$attestation.receipt_kind -cne 'discovery-invocation') {
|
|
119
|
+
return Get-CodexStopContinuation -Reason "DISCOVERY_START_ATTESTATION_BLOCKED: '$agentType' was not attested against a protected discovery invocation." -AlreadyContinued $alreadyContinued
|
|
120
|
+
}
|
|
121
|
+
}
|
|
101
122
|
if ($attestation.routing_valid -isnot [bool] -or -not [bool]$attestation.routing_valid) {
|
|
102
123
|
return Get-CodexStopContinuation -Reason "MODEL_ROUTING_ATTESTATION_BLOCKED: '$agentType' did not run under its recorded deployment model." -AlreadyContinued $alreadyContinued
|
|
103
124
|
}
|
package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Native SubagentStop output validation adapter for Codex discovery agents.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Invoked by the Codex SubagentStop hook. The hook reads the Codex stop envelope
|
|
7
|
+
from stdin, derives the stopping principal from the payload alone (session, the
|
|
8
|
+
host-assigned agent_id and agent_type, and the literal parent root), and
|
|
9
|
+
takes its decision from the shared DiscoveryStop module (published under
|
|
10
|
+
.codex/lib/discovery-validation, or read from .claude/lib when this repository
|
|
11
|
+
hosts itself):
|
|
12
|
+
|
|
13
|
+
- a stop whose agent type is not a discovery specialist writes nothing, so the
|
|
14
|
+
routing validator and the other Codex stop gates keep their behavior;
|
|
15
|
+
- a discovery specialist may stop only when its protected invocation was
|
|
16
|
+
finalized through the gateway with a current, gateway-written completion
|
|
17
|
+
receipt whose required outputs are present and whose inputs are unchanged;
|
|
18
|
+
- a stop that cannot be validated requests one continuation (decision=block at
|
|
19
|
+
exit 0) and, when stop_hook_active is already true, ends the stop with the
|
|
20
|
+
reason instead of looping.
|
|
21
|
+
|
|
22
|
+
An envelope the hook cannot read writes the reason to stderr at exit 2.
|
|
23
|
+
Dependency failures block with the DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix
|
|
24
|
+
(issue #980). No orchestrator checkpoint is read or written.
|
|
25
|
+
|
|
26
|
+
.NOTES
|
|
27
|
+
Requires PowerShell 7+. Invokes NO external process.
|
|
28
|
+
#>
|
|
29
|
+
[CmdletBinding()]
|
|
30
|
+
param()
|
|
31
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
32
|
+
|
|
33
|
+
function Get-DiscoveryStopHelperModulePath {
|
|
34
|
+
<#
|
|
35
|
+
.SYNOPSIS
|
|
36
|
+
Returns the published (.codex/lib) or self-hosting (.claude/lib) path of one helper module.
|
|
37
|
+
#>
|
|
38
|
+
[CmdletBinding()]
|
|
39
|
+
[OutputType([string])]
|
|
40
|
+
param(
|
|
41
|
+
[Parameter(Mandatory = $true)][string]$ModuleName,
|
|
42
|
+
[Parameter(Mandatory = $false)][string]$ScriptRoot = $PSScriptRoot
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
$published = Join-Path $ScriptRoot "../lib/discovery-validation/$ModuleName"
|
|
46
|
+
$selfHosted = Join-Path $ScriptRoot "../../.claude/lib/discovery-validation/$ModuleName"
|
|
47
|
+
foreach ($candidate in @($published, $selfHosted)) {
|
|
48
|
+
if (Test-Path -LiteralPath $candidate -PathType Leaf) { return $candidate }
|
|
49
|
+
}
|
|
50
|
+
return $published
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function Import-DiscoveryOutputSelfHostedModule {
|
|
54
|
+
<#
|
|
55
|
+
.SYNOPSIS
|
|
56
|
+
Imports the shared helpers from this repository's .claude/lib layout when no published .codex/lib exists (exemption D4).
|
|
57
|
+
#>
|
|
58
|
+
[CmdletBinding()]
|
|
59
|
+
param()
|
|
60
|
+
|
|
61
|
+
$ScriptRoot = $PSScriptRoot
|
|
62
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
63
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
64
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryManifest.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryManifest.psm1' -ErrorRecord $_ }
|
|
65
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.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/DiscoveryStop.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStop.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/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
77
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStop.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStop.psm1' -ErrorRecord $_ }
|
|
78
|
+
} else {
|
|
79
|
+
Import-DiscoveryOutputSelfHostedModule
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
$script:DiscoveryGateReasonPrefix = 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
83
|
+
|
|
84
|
+
function Invoke-DiscoveryAgentOutputDecision {
|
|
85
|
+
<#
|
|
86
|
+
.SYNOPSIS
|
|
87
|
+
Parses the Codex SubagentStop envelope and returns the shared stop outcome.
|
|
88
|
+
.DESCRIPTION
|
|
89
|
+
Returns the outcome object (Decision skip, allow or block; Code; Reason;
|
|
90
|
+
Receipt; Invocation). Every seam defaults to the real host and is injectable.
|
|
91
|
+
A recorded dependency failure blocks before the envelope is read.
|
|
92
|
+
#>
|
|
93
|
+
[CmdletBinding()]
|
|
94
|
+
[OutputType([pscustomobject])]
|
|
95
|
+
param(
|
|
96
|
+
[Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw,
|
|
97
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
|
|
98
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
|
|
99
|
+
[Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadBytes = $null
|
|
100
|
+
)
|
|
101
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix $script:DiscoveryGateReasonPrefix
|
|
102
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
103
|
+
|
|
104
|
+
if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
|
|
105
|
+
if ($null -eq $Store) { $Store = Get-DiscoveryStartStore }
|
|
106
|
+
|
|
107
|
+
$normalized = ConvertFrom-DiscoveryHostPayloadText -HostName 'codex' -Text $PayloadRaw
|
|
108
|
+
$assistantText = ''
|
|
109
|
+
$stopHookActive = $false
|
|
110
|
+
if ($null -eq $normalized.Anomaly) {
|
|
111
|
+
$payload = ConvertFrom-Json -InputObject $PayloadRaw -Depth 16
|
|
112
|
+
$names = @($payload.PSObject.Properties.Name)
|
|
113
|
+
if ($names -contains 'last_assistant_message' -and $payload.last_assistant_message -is [string]) { $assistantText = [string]$payload.last_assistant_message }
|
|
114
|
+
if ($names -contains 'stop_hook_active' -and $payload.stop_hook_active -is [bool]) { $stopHookActive = [bool]$payload.stop_hook_active }
|
|
115
|
+
}
|
|
116
|
+
$parameters = @{
|
|
117
|
+
Normalized = $normalized; HostEnvironment = $HostEnvironment
|
|
118
|
+
AssistantText = $assistantText; StopHookActive = $stopHookActive; Store = $Store
|
|
119
|
+
}
|
|
120
|
+
if ($null -ne $ReadBytes) { $parameters['ReadBytes'] = $ReadBytes }
|
|
121
|
+
return Get-DiscoveryStopDecision @parameters
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function Get-DiscoveryAgentOutputContinuation {
|
|
125
|
+
<#
|
|
126
|
+
.SYNOPSIS
|
|
127
|
+
Renders a blocked stop as the Codex continuation (decision=block) or, when already continued, the stop reason.
|
|
128
|
+
#>
|
|
129
|
+
[CmdletBinding()]
|
|
130
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
131
|
+
param(
|
|
132
|
+
[Parameter(Mandatory = $true)][string]$Reason,
|
|
133
|
+
[Parameter(Mandatory = $true)][bool]$AlreadyContinued
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if ($AlreadyContinued) {
|
|
137
|
+
return [ordered]@{ continue = $false; stopReason = $Reason; systemMessage = $Reason }
|
|
138
|
+
}
|
|
139
|
+
return [ordered]@{ decision = 'block'; reason = $Reason }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function Invoke-DiscoveryAgentOutputEntryPoint {
|
|
143
|
+
<#
|
|
144
|
+
.SYNOPSIS
|
|
145
|
+
Reads one Codex SubagentStop payload, writes the decision and returns the process exit code.
|
|
146
|
+
.DESCRIPTION
|
|
147
|
+
An unreadable envelope or a dependency failure writes its reason to stderr and
|
|
148
|
+
returns 2. A blocked stop writes the continuation JSON and returns 0; a
|
|
149
|
+
CONTINUED allow writes the stop reason JSON and returns 0. A skipped or
|
|
150
|
+
validated stop writes nothing and returns 0.
|
|
151
|
+
#>
|
|
152
|
+
[CmdletBinding()]
|
|
153
|
+
[OutputType([int])]
|
|
154
|
+
param([Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw)
|
|
155
|
+
|
|
156
|
+
$outcome = Invoke-DiscoveryAgentOutputDecision -PayloadRaw $PayloadRaw
|
|
157
|
+
# A dependency failure is already the SubagentStop block result (ExitCode, Reason).
|
|
158
|
+
if ($null -ne $outcome.PSObject.Properties['ExitCode']) { [Console]::Error.WriteLine([string]$outcome.Reason); return [int]$outcome.ExitCode }
|
|
159
|
+
if ($outcome.Code -eq 'ENVELOPE') {
|
|
160
|
+
[Console]::Error.WriteLine("$($script:DiscoveryGateReasonPrefix) $($outcome.Reason)")
|
|
161
|
+
return 2
|
|
162
|
+
}
|
|
163
|
+
if ($outcome.Decision -eq 'block' -or $outcome.Code -eq 'CONTINUED') {
|
|
164
|
+
$continuation = Get-DiscoveryAgentOutputContinuation -Reason "$($script:DiscoveryGateReasonPrefix) $($outcome.Reason)" -AlreadyContinued ($outcome.Code -eq 'CONTINUED')
|
|
165
|
+
[Console]::Out.WriteLine(($continuation | ConvertTo-Json -Compress -Depth 5))
|
|
166
|
+
}
|
|
167
|
+
return 0
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# Guard allows dot-sourcing in tests without executing the entrypoint.
|
|
171
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('DISCOVERY_ARTIFACT_GATE_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
175
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
176
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
177
|
+
|
|
178
|
+
exit (Invoke-DiscoveryAgentOutputEntryPoint -PayloadRaw ([Console]::In.ReadToEnd()))
|
|
@@ -49,6 +49,14 @@ function Invoke-CodexTopologyCli {
|
|
|
49
49
|
Default = $null
|
|
50
50
|
}
|
|
51
51
|
'--cross-cutting' = @{ Key = 'cross_cutting'; Kind = 'switch'; Required = $false; Default = $false }
|
|
52
|
+
'--invocation-kind' = @{
|
|
53
|
+
Key = 'invocation_kind'
|
|
54
|
+
Kind = 'value'
|
|
55
|
+
Required = $false
|
|
56
|
+
Choices = @('ordinary', 'discovery')
|
|
57
|
+
Default = 'ordinary'
|
|
58
|
+
}
|
|
59
|
+
'--skill-id' = @{ Key = 'skill_id'; Kind = 'value'; Required = $false; Default = $null }
|
|
52
60
|
'--root-persona' = @{
|
|
53
61
|
Key = 'root_persona'
|
|
54
62
|
Kind = 'value'
|
|
@@ -79,7 +87,9 @@ function Invoke-CodexTopologyCli {
|
|
|
79
87
|
-TestFileCount $values['test_file_count'] `
|
|
80
88
|
-ExecutionContext $values['execution_context'] `
|
|
81
89
|
-CrossCutting ([bool]$values['cross_cutting']) `
|
|
82
|
-
-RootPersona $values['root_persona']
|
|
90
|
+
-RootPersona $values['root_persona'] `
|
|
91
|
+
-InvocationKind $values['invocation_kind'] `
|
|
92
|
+
-SkillId $values['skill_id']
|
|
83
93
|
} catch [System.ArgumentException] {
|
|
84
94
|
return New-CodexRoutingCliResult -ExitCode 1 -Stderr "$($_.Exception.Message)`n"
|
|
85
95
|
}
|
|
@@ -83,7 +83,7 @@ If the marker is missing or malformed, fail closed to `full-feature`.
|
|
|
83
83
|
Stop implementation and return to the user when:
|
|
84
84
|
|
|
85
85
|
- the scope estimate or an in-flight batch would exceed the 3-production-file cap in direct mode,
|
|
86
|
-
- a file is
|
|
86
|
+
- a file is above or would exceed the 800-line hard limit of the tiered file-size policy (split it before proceeding; at 500 lines look for a logical split, and at 700 lines split more aggressively),
|
|
87
87
|
- any QA gate delta is non-zero after self-correction,
|
|
88
88
|
- the toolchain cannot be executed in the current environment (mark the change **unverified**),
|
|
89
89
|
- orchestrator handoff mode is requested but the required context package is incomplete,
|