@danmoisan/drm-copilot-mcp 1.1.23 → 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 +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
|
@@ -2,7 +2,7 @@ default_permissions = ":danger-full-access"
|
|
|
2
2
|
|
|
3
3
|
[mcp_servers.drm-copilot]
|
|
4
4
|
command = "npx"
|
|
5
|
-
args = ["-y", "@danmoisan/drm-copilot-mcp@1.1.
|
|
5
|
+
args = ["-y", "@danmoisan/drm-copilot-mcp@1.1.24"]
|
|
6
6
|
required = true
|
|
7
7
|
enabled_tools = [
|
|
8
8
|
"collect_commit_context",
|
|
@@ -107,7 +107,7 @@ timeout = 15
|
|
|
107
107
|
statusMessage = "Authorizing root epic entry"
|
|
108
108
|
|
|
109
109
|
[[hooks.SubagentStart]]
|
|
110
|
-
matcher = "epic-planner|epic-orchestrator|orchestrator|atomic-planner|atomic-executor|feature-review|feature-reviewer|task-researcher|prd-feature|pr-author|typed-engineer|-c"
|
|
110
|
+
matcher = "epic-planner|epic-orchestrator|orchestrator|atomic-planner|atomic-executor|feature-review|feature-reviewer|task-researcher|prd-feature|pr-author|typed-engineer|-c|legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer"
|
|
111
111
|
|
|
112
112
|
[[hooks.SubagentStart.hooks]]
|
|
113
113
|
type = "command"
|
|
@@ -152,6 +152,12 @@ timeout = 30
|
|
|
152
152
|
[[hooks.PreToolUse]]
|
|
153
153
|
matcher = "^(Bash|shell_command|apply_patch|Edit|Write|mcp__.*)$"
|
|
154
154
|
|
|
155
|
+
[[hooks.PreToolUse.hooks]]
|
|
156
|
+
type = "command"
|
|
157
|
+
command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-discovery-artifact-gate.ps1"'
|
|
158
|
+
command_windows = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-discovery-artifact-gate.ps1"'
|
|
159
|
+
timeout = 30
|
|
160
|
+
|
|
155
161
|
[[hooks.PreToolUse.hooks]]
|
|
156
162
|
type = "command"
|
|
157
163
|
command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-epic-root-invocation.ps1"'
|
|
@@ -239,8 +245,23 @@ command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/
|
|
|
239
245
|
command_windows = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-completion-consistency.ps1"'
|
|
240
246
|
timeout = 30
|
|
241
247
|
|
|
248
|
+
[[hooks.PreToolUse]]
|
|
249
|
+
matcher = "^(Agent|Task|spawn_agent|run_subagent|delegate)$"
|
|
250
|
+
|
|
251
|
+
[[hooks.PreToolUse.hooks]]
|
|
252
|
+
type = "command"
|
|
253
|
+
command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-discovery-artifact-gate.ps1"'
|
|
254
|
+
command_windows = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-discovery-artifact-gate.ps1"'
|
|
255
|
+
timeout = 30
|
|
256
|
+
|
|
257
|
+
[[hooks.PreToolUse.hooks]]
|
|
258
|
+
type = "command"
|
|
259
|
+
command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-discovery-planning-gate.ps1"'
|
|
260
|
+
command_windows = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/enforce-discovery-planning-gate.ps1"'
|
|
261
|
+
timeout = 30
|
|
262
|
+
|
|
242
263
|
[[hooks.SubagentStop]]
|
|
243
|
-
matcher = "epic-planner|epic-orchestrator|orchestrator|atomic-planner|atomic-executor|feature-review|feature-reviewer|task-researcher|prd-feature|pr-author|typed-engineer|-c"
|
|
264
|
+
matcher = "epic-planner|epic-orchestrator|orchestrator|atomic-planner|atomic-executor|feature-review|feature-reviewer|task-researcher|prd-feature|pr-author|typed-engineer|-c|legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer"
|
|
244
265
|
|
|
245
266
|
[[hooks.SubagentStop.hooks]]
|
|
246
267
|
type = "command"
|
|
@@ -248,6 +269,15 @@ command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/
|
|
|
248
269
|
command_windows = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/validate-codex-subagent-routing.ps1"'
|
|
249
270
|
timeout = 30
|
|
250
271
|
|
|
272
|
+
[[hooks.SubagentStop]]
|
|
273
|
+
matcher = "legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer"
|
|
274
|
+
|
|
275
|
+
[[hooks.SubagentStop.hooks]]
|
|
276
|
+
type = "command"
|
|
277
|
+
command = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/validate-discovery-agent-output.ps1"'
|
|
278
|
+
command_windows = 'pwsh -NoProfile -File "$(git rev-parse --show-toplevel)/.codex/hooks/validate-discovery-agent-output.ps1"'
|
|
279
|
+
timeout = 30
|
|
280
|
+
|
|
251
281
|
[[hooks.SubagentStop]]
|
|
252
282
|
matcher = "feature-review|feature-reviewer"
|
|
253
283
|
|
package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1
CHANGED
|
@@ -119,6 +119,28 @@ function Test-CodexAgentProfileBinding {
|
|
|
119
119
|
return $true
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
function ConvertTo-CodexSharedAgentProfile {
|
|
123
|
+
<#
|
|
124
|
+
.SYNOPSIS
|
|
125
|
+
Projects a Codex profile attestation into the shared discovery agent-profile shape.
|
|
126
|
+
.DESCRIPTION
|
|
127
|
+
The shared DiscoveryStart decision compares ProfileName, ProfileSha256,
|
|
128
|
+
ProfileModel and ProfileReasoningEffort against the protected invocation;
|
|
129
|
+
this projection keeps the Codex TOML reader as the single source of those values.
|
|
130
|
+
#>
|
|
131
|
+
[CmdletBinding()]
|
|
132
|
+
[OutputType([pscustomobject])]
|
|
133
|
+
param([Parameter(Mandatory)] $AgentProfile)
|
|
134
|
+
|
|
135
|
+
return [pscustomobject]@{
|
|
136
|
+
ProfilePath = [string]$AgentProfile.profile_path
|
|
137
|
+
ProfileSha256 = [string]$AgentProfile.profile_sha256
|
|
138
|
+
ProfileName = [string]$AgentProfile.profile_name
|
|
139
|
+
ProfileModel = [string]$AgentProfile.profile_model
|
|
140
|
+
ProfileReasoningEffort = [string]$AgentProfile.profile_reasoning_effort
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
122
144
|
function Test-CodexRoutedAgentType {
|
|
123
145
|
[CmdletBinding()]
|
|
124
146
|
[OutputType([bool])]
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Codex capability probe for discovery agents: observes registration, handler hashes and the recorded sentinel observations.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Not an event hook. The gateway doctor and the operator script
|
|
7
|
+
scripts/dev-tools/Test-DiscoveryHostCapability.ps1 run this probe to observe
|
|
8
|
+
whether this workspace's Codex host provides the required discovery controls:
|
|
9
|
+
the SubagentStart, PreToolUse and SubagentStop handlers registered in
|
|
10
|
+
.codex/config.toml for the four discovery agents and the controlled tools, their
|
|
11
|
+
current hashes, and the host observations the PreToolUse gate recorded while the
|
|
12
|
+
discovery-capability-sentinel agent ran in session SessionId. The result is a
|
|
13
|
+
capability-attestation-shaped JSON document on stdout; exit 0 when supported, 1
|
|
14
|
+
when unsupported. A session without observations, or whose sentinel observation
|
|
15
|
+
carries no agent_id, is unsupported.
|
|
16
|
+
|
|
17
|
+
.NOTES
|
|
18
|
+
Issue #980. Requires PowerShell 7+. Invokes NO external process and makes no
|
|
19
|
+
in-process sentinel decision.
|
|
20
|
+
#>
|
|
21
|
+
[CmdletBinding()]
|
|
22
|
+
param(
|
|
23
|
+
[Parameter(Mandatory = $false)][string]$WorkspaceRoot = (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent),
|
|
24
|
+
[Parameter(Mandatory = $false)][string]$SessionId = 'capability-probe',
|
|
25
|
+
[Parameter(Mandatory = $false)][AllowNull()][string]$Nonce = $null,
|
|
26
|
+
[Parameter(Mandatory = $false)][bool]$WorkspaceTrusted = $true,
|
|
27
|
+
[Parameter(Mandatory = $false)][AllowNull()][string]$RuntimeJson = $null
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
. (Join-Path $PSScriptRoot 'enforce-discovery-artifact-gate.ps1')
|
|
31
|
+
Import-Module (Get-DiscoveryHelperModulePath -ModuleName 'DiscoveryCapability.psm1') -Force -Global -ErrorAction Stop
|
|
32
|
+
|
|
33
|
+
function Get-DiscoveryProbeRuntime {
|
|
34
|
+
<#
|
|
35
|
+
.SYNOPSIS
|
|
36
|
+
Returns the runtime identity the probe records: the caller's JSON, or the local configuration digest.
|
|
37
|
+
#>
|
|
38
|
+
[CmdletBinding()]
|
|
39
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
40
|
+
param([Parameter(Mandatory = $false)][AllowNull()][string]$RuntimeJson, [Parameter(Mandatory = $true)][string]$WorkspaceRoot)
|
|
41
|
+
|
|
42
|
+
if (-not [string]::IsNullOrWhiteSpace($RuntimeJson)) {
|
|
43
|
+
$parsed = ConvertFrom-Json -InputObject $RuntimeJson -Depth 4
|
|
44
|
+
$runtime = [ordered]@{}
|
|
45
|
+
foreach ($key in @('build_sha256', 'package_version', 'policy_sha256', 'policy_version', 'schema_version')) {
|
|
46
|
+
# The runtime identity contract types policy_version as an integer; the hosts compare it canonically.
|
|
47
|
+
$runtime[$key] = $(if ($key -eq 'policy_version') { [int]$parsed.$key } else { [string]$parsed.$key })
|
|
48
|
+
}
|
|
49
|
+
return $runtime
|
|
50
|
+
}
|
|
51
|
+
# The workspace root is a host-modelled path string; Join-Path would require its drive to exist locally.
|
|
52
|
+
$configuration = "$($WorkspaceRoot.TrimEnd('/', '\'))/.codex/config.toml"
|
|
53
|
+
$digest = $(if (Test-Path -LiteralPath $configuration -PathType Leaf) { Get-DiscoveryBytesSha256Hex -Bytes ([System.IO.File]::ReadAllBytes($configuration)) } else { '0' * 64 })
|
|
54
|
+
return [ordered]@{ build_sha256 = $digest; package_version = '2.0.0'; policy_sha256 = $digest; policy_version = 2; schema_version = '2.0.0' }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function Invoke-DiscoveryCapabilityProbe {
|
|
58
|
+
<#
|
|
59
|
+
.SYNOPSIS
|
|
60
|
+
Runs the Codex capability observation and returns the attestation-shaped document.
|
|
61
|
+
#>
|
|
62
|
+
[CmdletBinding()]
|
|
63
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
64
|
+
param(
|
|
65
|
+
[Parameter(Mandatory = $true)][string]$WorkspaceRoot,
|
|
66
|
+
[Parameter(Mandatory = $true)][string]$SessionId,
|
|
67
|
+
[Parameter(Mandatory = $false)][AllowNull()][string]$Nonce = $null,
|
|
68
|
+
[Parameter(Mandatory = $false)][bool]$WorkspaceTrusted = $true,
|
|
69
|
+
[Parameter(Mandatory = $false)][AllowNull()][string]$RuntimeJson = $null,
|
|
70
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
|
|
71
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
|
|
72
|
+
[Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadBytes = $null,
|
|
73
|
+
[Parameter(Mandatory = $false)][AllowNull()][nullable[datetime]]$Now = $null
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if ([string]::IsNullOrEmpty($Nonce)) { $Nonce = Get-DiscoveryAuthorizationNonce }
|
|
77
|
+
if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
|
|
78
|
+
if ($null -eq $Store) { $Store = Get-DiscoveryDefaultStore }
|
|
79
|
+
if ($null -eq $Now) { $Now = [datetime]::UtcNow }
|
|
80
|
+
$parameters = @{
|
|
81
|
+
HostName = 'codex'; WorkspaceRoot = $WorkspaceRoot; SessionId = $SessionId; Nonce = $Nonce; WorkspaceTrusted = $WorkspaceTrusted; Now = $Now
|
|
82
|
+
Runtime = (Get-DiscoveryProbeRuntime -RuntimeJson $RuntimeJson -WorkspaceRoot $WorkspaceRoot)
|
|
83
|
+
HostEnvironment = $HostEnvironment; Store = $Store
|
|
84
|
+
}
|
|
85
|
+
if ($null -ne $ReadBytes) { $parameters['ReadBytes'] = $ReadBytes }
|
|
86
|
+
$observation = Get-DiscoveryCapabilityObservation @parameters
|
|
87
|
+
# The doctor, the agent preparation and the start attestation read only the protected session copy.
|
|
88
|
+
[void](Write-DiscoveryCapabilityAttestation -Observation $observation -WorkspaceRoot $WorkspaceRoot -HostEnvironment $HostEnvironment -Store $Store)
|
|
89
|
+
return $observation
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
$observation = Invoke-DiscoveryCapabilityProbe -WorkspaceRoot $WorkspaceRoot -SessionId $SessionId -Nonce $Nonce -WorkspaceTrusted $WorkspaceTrusted -RuntimeJson $RuntimeJson
|
|
96
|
+
$observation | ConvertTo-Json -Depth 8 | Write-Output
|
|
97
|
+
exit $(if ($observation['status'] -eq 'supported') { 0 } else { 1 })
|
package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Codex SubagentStart attestation for discovery specialists through the protected discovery store.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Dot-sourced by record-subagent-routing-attestation.ps1. A Codex start whose agent
|
|
7
|
+
type names a discovery specialist is attested against the explicit
|
|
8
|
+
`discovery-invocation` receipt the root prepared in the protected store, through
|
|
9
|
+
the shared DiscoveryStart module (published under .codex/lib/discovery-validation,
|
|
10
|
+
or read from .claude/lib when this repository hosts itself). The result is
|
|
11
|
+
projected into the schema-2 routing attestation the Codex PreToolUse gates
|
|
12
|
+
already consume, with receipt_kind `discovery-invocation`, so an unattested or
|
|
13
|
+
drifted specialist is denied before its first tool use. No orchestrator
|
|
14
|
+
checkpoint, repository HEAD or epic receipt is read for a discovery start.
|
|
15
|
+
#>
|
|
16
|
+
[CmdletBinding()]
|
|
17
|
+
param()
|
|
18
|
+
|
|
19
|
+
$script:CodexDiscoveryAgentTypePattern = '^(legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer)(-c(1|2|3|4|3-elevated))?$'
|
|
20
|
+
$script:CodexDiscoveryStartPrefix = 'DISCOVERY_START_ATTESTATION_BLOCKED:'
|
|
21
|
+
$script:CodexDiscoveryStartModules = @('DiscoveryEncoding.psm1', 'DiscoveryAuthority.psm1', 'DiscoveryPayload.psm1', 'DiscoveryStartRecord.psm1', 'DiscoveryStart.psm1')
|
|
22
|
+
|
|
23
|
+
function Test-CodexDiscoveryAgentType {
|
|
24
|
+
[CmdletBinding()]
|
|
25
|
+
[OutputType([bool])]
|
|
26
|
+
param([AllowNull()][AllowEmptyString()][string] $AgentType)
|
|
27
|
+
|
|
28
|
+
return -not [string]::IsNullOrWhiteSpace($AgentType) -and $AgentType -cmatch $script:CodexDiscoveryAgentTypePattern
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Get-CodexDiscoveryStartModulePath {
|
|
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)][string] $ModuleName,
|
|
40
|
+
[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-CodexDiscoveryStartModule {
|
|
52
|
+
<#
|
|
53
|
+
.SYNOPSIS
|
|
54
|
+
Loads the shared discovery modules a discovery start needs; ordinary starts never load them.
|
|
55
|
+
#>
|
|
56
|
+
[CmdletBinding()]
|
|
57
|
+
param([string] $ScriptRoot = $PSScriptRoot)
|
|
58
|
+
|
|
59
|
+
foreach ($moduleName in $script:CodexDiscoveryStartModules) {
|
|
60
|
+
Import-Module (Get-CodexDiscoveryStartModulePath -ModuleName $moduleName -ScriptRoot $ScriptRoot) -Force -Global -ErrorAction Stop
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Get-CodexDiscoveryStartAttestation {
|
|
65
|
+
<#
|
|
66
|
+
.SYNOPSIS
|
|
67
|
+
Builds the schema-2 attestation of a Codex discovery start from the protected invocation.
|
|
68
|
+
.DESCRIPTION
|
|
69
|
+
The actual model comes from the SubagentStart payload and the actual effort and
|
|
70
|
+
profile hash from the generated Codex profile; both must equal the deployment
|
|
71
|
+
the root prepared. routing_valid is true only when the shared decision
|
|
72
|
+
attested the start; discovery_code and discovery_reason carry the decision.
|
|
73
|
+
#>
|
|
74
|
+
[CmdletBinding()]
|
|
75
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
76
|
+
param(
|
|
77
|
+
[Parameter(Mandatory)] $Payload,
|
|
78
|
+
[Parameter(Mandatory)][string] $RepositoryRoot,
|
|
79
|
+
[Parameter(Mandatory)][datetimeoffset] $Now,
|
|
80
|
+
[AllowNull()][hashtable] $HostEnvironment = $null,
|
|
81
|
+
[AllowNull()][hashtable] $Store = $null,
|
|
82
|
+
[AllowNull()][string] $Nonce = $null,
|
|
83
|
+
[AllowNull()] $AgentProfile = $null,
|
|
84
|
+
[string] $HandlerPath = (Join-Path $PSScriptRoot 'record-subagent-routing-attestation.ps1')
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
$agentId = [string]$Payload.agent_id
|
|
88
|
+
$agentType = [string]$Payload.agent_type
|
|
89
|
+
$model = [string]$Payload.model
|
|
90
|
+
if (-not $agentId -or -not $agentType -or -not $model) {
|
|
91
|
+
throw "$($script:CodexDiscoveryStartPrefix) SubagentStart requires agent_id, agent_type, and model."
|
|
92
|
+
}
|
|
93
|
+
Import-CodexDiscoveryStartModule
|
|
94
|
+
$profileValidationError = $null
|
|
95
|
+
if ($null -eq $AgentProfile) {
|
|
96
|
+
try { $AgentProfile = Get-CodexAgentProfileAttestation -RepositoryRoot $RepositoryRoot -AgentType $agentType } catch { $profileValidationError = [string]$_ }
|
|
97
|
+
}
|
|
98
|
+
$sharedProfile = $(if ($null -ne $AgentProfile) { ConvertTo-CodexSharedAgentProfile -AgentProfile $AgentProfile } else { $null })
|
|
99
|
+
# The principal comes from the payload alone: Codex supplies no parent identifier, so the parent is the literal root.
|
|
100
|
+
$normalized = [pscustomobject]@{
|
|
101
|
+
HostName = 'codex'; Event = 'SubagentStart'; SessionId = [string]$Payload.session_id; AgentId = $agentId; AgentType = $agentType; ParentAgentId = $null
|
|
102
|
+
ToolName = $null; ToolInput = $null; Cwd = $RepositoryRoot; ToolUseId = $null; Anomaly = $null
|
|
103
|
+
}
|
|
104
|
+
if ([string]::IsNullOrWhiteSpace($normalized.SessionId)) { $normalized.Anomaly = 'MissingSessionId' }
|
|
105
|
+
$handlerSha256 = $(if (Test-Path -LiteralPath $HandlerPath -PathType Leaf) { Get-DiscoveryBytesSha256Hex -Bytes ([System.IO.File]::ReadAllBytes($HandlerPath)) } else { '0' * 64 })
|
|
106
|
+
$parameters = @{ Normalized = $normalized; HandlerSha256 = $handlerSha256; Now = $Now.UtcDateTime; ActualModel = $model }
|
|
107
|
+
$parameters['HostEnvironment'] = $(if ($null -ne $HostEnvironment) { $HostEnvironment } else { Get-DiscoveryTrustedHostEnvironment })
|
|
108
|
+
if ($null -ne $Store) { $parameters['Store'] = $Store }
|
|
109
|
+
if (-not [string]::IsNullOrEmpty($Nonce)) { $parameters['Nonce'] = $Nonce }
|
|
110
|
+
if ($null -ne $sharedProfile) { $parameters['AgentProfile'] = $sharedProfile; $parameters['ActualReasoningEffort'] = $sharedProfile.ProfileReasoningEffort }
|
|
111
|
+
$outcome = $(if ($null -eq $sharedProfile) {
|
|
112
|
+
[pscustomobject]@{ Decision = 'deny'; Code = 'PROFILE'; Reason = "the agent profile could not be read: $profileValidationError"; Attestation = $null; AttestationPath = $null; Invocation = $null }
|
|
113
|
+
} else { Get-DiscoveryStartDecision @parameters })
|
|
114
|
+
$record = $outcome.Invocation
|
|
115
|
+
$attested = ($outcome.Decision -eq 'attest')
|
|
116
|
+
return [ordered]@{
|
|
117
|
+
schema_version = 2
|
|
118
|
+
receipt_kind = 'discovery-invocation'
|
|
119
|
+
session_id = [string]$Payload.session_id
|
|
120
|
+
turn_id = [string]$Payload.turn_id
|
|
121
|
+
agent_id = $agentId
|
|
122
|
+
agent_type = $agentType
|
|
123
|
+
transcript_path = [string]$Payload.transcript_path
|
|
124
|
+
attestation_key = Get-SubagentAttestationKey -TranscriptPath ([string]$Payload.transcript_path) -AgentId $agentId
|
|
125
|
+
actual_model = $model
|
|
126
|
+
expected_model = $(if ($null -ne $record) { [string]$record.deployment.model } else { '' })
|
|
127
|
+
actual_reasoning_effort = $(if ($null -ne $AgentProfile) { [string]$AgentProfile.profile_reasoning_effort } else { $null })
|
|
128
|
+
expected_reasoning_effort = $(if ($null -ne $record) { [string]$record.deployment.reasoning_effort } else { '' })
|
|
129
|
+
profile_name = $(if ($null -ne $AgentProfile) { [string]$AgentProfile.profile_name } else { $null })
|
|
130
|
+
profile_model = $(if ($null -ne $AgentProfile) { [string]$AgentProfile.profile_model } else { $null })
|
|
131
|
+
profile_path = $(if ($null -ne $AgentProfile) { [string]$AgentProfile.profile_path } else { $null })
|
|
132
|
+
profile_sha256 = $(if ($null -ne $AgentProfile) { [string]$AgentProfile.profile_sha256 } else { $null })
|
|
133
|
+
profile_validation_error = $profileValidationError
|
|
134
|
+
routing_valid = $attested
|
|
135
|
+
launch_authority_valid = $attested
|
|
136
|
+
root_authorized = $null
|
|
137
|
+
root_entry_kind = $null
|
|
138
|
+
root_epic_reference = $null
|
|
139
|
+
root_kickoff_path = $null
|
|
140
|
+
authority_repository_sha256 = Get-CodexAuthorityRepositoryKey -RepositoryRoot $RepositoryRoot
|
|
141
|
+
provenance_valid = $true
|
|
142
|
+
enforcement_marker = $(if ($attested) { $null } else { 'DISCOVERY_START_ATTESTATION_BLOCKED' })
|
|
143
|
+
invocation_id = $(if ($null -ne $record) { [string]$record.invocation_id } else { $null })
|
|
144
|
+
start_attestation_ref = $(if ($attested) { [string]$outcome.Attestation['start_attestation_ref'] } else { $null })
|
|
145
|
+
discovery_code = $outcome.Code
|
|
146
|
+
discovery_reason = $outcome.Reason
|
|
147
|
+
recorded_at = $Now.ToUniversalTime().ToString('o')
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function Get-CodexDiscoveryStartCommandOutput {
|
|
152
|
+
<#
|
|
153
|
+
.SYNOPSIS
|
|
154
|
+
Returns the SubagentStart stdout for a discovery attestation, or $null when the start was attested.
|
|
155
|
+
#>
|
|
156
|
+
[CmdletBinding()]
|
|
157
|
+
[OutputType([string])]
|
|
158
|
+
param(
|
|
159
|
+
[Parameter(Mandatory)][System.Collections.IDictionary] $Attestation,
|
|
160
|
+
[Parameter(Mandatory)][string] $AttestationPath
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if ([bool]$Attestation.routing_valid) { return $null }
|
|
164
|
+
return [ordered]@{
|
|
165
|
+
systemMessage = "$($script:CodexDiscoveryStartPrefix) $($Attestation.discovery_reason) Attestation: $AttestationPath"
|
|
166
|
+
hookSpecificOutput = [ordered]@{
|
|
167
|
+
hookEventName = 'SubagentStart'
|
|
168
|
+
additionalContext = "$($script:CodexDiscoveryStartPrefix) no discovery tool grant is active for this agent. Do not read or mutate state; report the blocked start and stop."
|
|
169
|
+
}
|
|
170
|
+
} | ConvertTo-Json -Compress -Depth 5
|
|
171
|
+
}
|
package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1
CHANGED
|
@@ -127,7 +127,10 @@ function Test-CodexModelGateAgentType {
|
|
|
127
127
|
[OutputType([bool])]
|
|
128
128
|
param([Parameter(Mandatory)][string] $AgentType)
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
# Discovery specialists are gated by their SubagentStart attestation of the
|
|
131
|
+
# protected invocation (issue #980); a start without one denies the first tool use.
|
|
132
|
+
return $AgentType -match '-c(?:1|2|3|4|3-elevated)$' -or
|
|
133
|
+
$AgentType -cmatch '^(legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer)$' -or @(
|
|
131
134
|
'orchestrator', 'atomic-planner', 'atomic-executor', 'feature-review',
|
|
132
135
|
'feature-reviewer', 'task-researcher', 'prd-feature', 'pr-author',
|
|
133
136
|
'python-typed-engineer', 'powershell-typed-engineer',
|
package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Native PreToolUse authorization adapter for Codex discovery agents.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Invoked by the Codex PreToolUse hook. The hook reads the Codex envelope from
|
|
7
|
+
stdin, derives the trusted principal from the payload alone (session, the
|
|
8
|
+
host-assigned agent_id and agent_type when the payload carries them, and the
|
|
9
|
+
literal parent root), and takes its decision from the shared
|
|
10
|
+
DiscoveryAuthorization module (published under .codex/lib/discovery-validation,
|
|
11
|
+
or read from .claude/lib when this repository hosts itself):
|
|
12
|
+
|
|
13
|
+
- a root call (no agent_id) of prepare_discovery_agent, run_discovery_doctor or
|
|
14
|
+
a controlled discovery tool is allowed with a one-use root grant the MCP
|
|
15
|
+
server consumes; every other root call and every call of an agent that is
|
|
16
|
+
not a discovery specialist allows silently (no stdout), so ordinary
|
|
17
|
+
sessions keep the behavior of their other gates;
|
|
18
|
+
- a sentinel envelope is observed for the capability probe and never granted;
|
|
19
|
+
- a discovery specialist may use read-only native tools and the controlled
|
|
20
|
+
discovery MCP tools only; shell, exec and evaluation tools, generic
|
|
21
|
+
apply_patch/Write/Edit mutations, nested agents, foreign MCP servers,
|
|
22
|
+
root-only discovery operations and caller-supplied identity fields are denied
|
|
23
|
+
before execution with a PreToolUse deny decision at exit 0;
|
|
24
|
+
- every controlled call must name the specialist's started invocation through
|
|
25
|
+
invocation_ref and is recorded as one short-lived, one-use tool-authorization;
|
|
26
|
+
the Codex SubagentStart attestation binds the prepared invocation, and the
|
|
27
|
+
gate's first-call binding reports PROFILE when no start attested the agent.
|
|
28
|
+
|
|
29
|
+
An envelope the hook cannot read is a hard failure: the reason goes to stderr
|
|
30
|
+
and the hook exits 2. Dependency failures deny with the
|
|
31
|
+
DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix (issue #980).
|
|
32
|
+
|
|
33
|
+
.NOTES
|
|
34
|
+
Requires PowerShell 7+. Invokes NO external process and never reads a profile,
|
|
35
|
+
locator or request field to decide identity or authority.
|
|
36
|
+
#>
|
|
37
|
+
[CmdletBinding()]
|
|
38
|
+
param()
|
|
39
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
40
|
+
|
|
41
|
+
function Get-DiscoveryHelperModulePath {
|
|
42
|
+
<#
|
|
43
|
+
.SYNOPSIS
|
|
44
|
+
Returns the published (.codex/lib) or self-hosting (.claude/lib) path of one helper module.
|
|
45
|
+
.DESCRIPTION
|
|
46
|
+
The published destination holds the helpers beside .codex/hooks under
|
|
47
|
+
.codex/lib/discovery-validation; this repository holds them under
|
|
48
|
+
.claude/lib/discovery-validation. The first existing candidate wins; when
|
|
49
|
+
neither exists the published path is returned so the import failure names it.
|
|
50
|
+
#>
|
|
51
|
+
[CmdletBinding()]
|
|
52
|
+
[OutputType([string])]
|
|
53
|
+
param(
|
|
54
|
+
[Parameter(Mandatory = $true)][string]$ModuleName,
|
|
55
|
+
[Parameter(Mandatory = $false)][string]$ScriptRoot = $PSScriptRoot
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
$published = Join-Path $ScriptRoot "../lib/discovery-validation/$ModuleName"
|
|
59
|
+
$selfHosted = Join-Path $ScriptRoot "../../.claude/lib/discovery-validation/$ModuleName"
|
|
60
|
+
# Resolution order: the destination layout first, then the repository layout.
|
|
61
|
+
foreach ($candidate in @($published, $selfHosted)) {
|
|
62
|
+
if (Test-Path -LiteralPath $candidate -PathType Leaf) { return $candidate }
|
|
63
|
+
}
|
|
64
|
+
return $published
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function Import-DiscoveryGateSelfHostedModule {
|
|
68
|
+
<#
|
|
69
|
+
.SYNOPSIS
|
|
70
|
+
Imports the shared helpers from this repository's .claude/lib layout when no published .codex/lib exists (exemption D4).
|
|
71
|
+
#>
|
|
72
|
+
[CmdletBinding()]
|
|
73
|
+
param()
|
|
74
|
+
|
|
75
|
+
$ScriptRoot = $PSScriptRoot
|
|
76
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
77
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
78
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
|
|
79
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryToolRouting.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryToolRouting.psm1' -ErrorRecord $_ }
|
|
80
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
81
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryRootGrant.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryRootGrant.psm1' -ErrorRecord $_ }
|
|
82
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryObservation.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryObservation.psm1' -ErrorRecord $_ }
|
|
83
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryStart.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStart.psm1' -ErrorRecord $_ }
|
|
84
|
+
try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryAuthorization.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthorization.psm1' -ErrorRecord $_ }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# The published destination keeps the helpers beside .codex/hooks; this repository hosts them under .claude/lib.
|
|
88
|
+
if (Test-Path -LiteralPath (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -PathType Leaf) {
|
|
89
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
90
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
91
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
|
|
92
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryToolRouting.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryToolRouting.psm1' -ErrorRecord $_ }
|
|
93
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
94
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryRootGrant.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryRootGrant.psm1' -ErrorRecord $_ }
|
|
95
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryObservation.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryObservation.psm1' -ErrorRecord $_ }
|
|
96
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStart.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStart.psm1' -ErrorRecord $_ }
|
|
97
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthorization.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthorization.psm1' -ErrorRecord $_ }
|
|
98
|
+
} else {
|
|
99
|
+
Import-DiscoveryGateSelfHostedModule
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
$script:DiscoveryGateReasonPrefix = 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
103
|
+
$script:DiscoveryGateHandlerPath = $PSCommandPath
|
|
104
|
+
|
|
105
|
+
function Get-DiscoveryGateHandlerSha256 {
|
|
106
|
+
<#
|
|
107
|
+
.SYNOPSIS
|
|
108
|
+
Returns the SHA-256 of this handler's own bytes for the authorization writer record.
|
|
109
|
+
#>
|
|
110
|
+
[CmdletBinding()]
|
|
111
|
+
[OutputType([string])]
|
|
112
|
+
param([Parameter(Mandatory = $false)][AllowNull()][string]$HandlerPath = $script:DiscoveryGateHandlerPath)
|
|
113
|
+
|
|
114
|
+
if ([string]::IsNullOrEmpty($HandlerPath) -or -not (Test-Path -LiteralPath $HandlerPath -PathType Leaf)) {
|
|
115
|
+
return ('0' * 64)
|
|
116
|
+
}
|
|
117
|
+
return Get-DiscoveryBytesSha256Hex -Bytes ([System.IO.File]::ReadAllBytes($HandlerPath))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function Invoke-DiscoveryArtifactGateDecision {
|
|
121
|
+
<#
|
|
122
|
+
.SYNOPSIS
|
|
123
|
+
Parses the Codex PreToolUse envelope and returns the decision outcome.
|
|
124
|
+
.DESCRIPTION
|
|
125
|
+
Returns the shared outcome object (Decision, Code, Reason, Record,
|
|
126
|
+
RecordPath). Every seam defaults to the real host and is injectable. A
|
|
127
|
+
recorded dependency failure returns a deny outcome before the envelope is read.
|
|
128
|
+
#>
|
|
129
|
+
[CmdletBinding()]
|
|
130
|
+
[OutputType([pscustomobject])]
|
|
131
|
+
param(
|
|
132
|
+
[Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$ToolInputRaw,
|
|
133
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
|
|
134
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
|
|
135
|
+
[Parameter(Mandatory = $false)][AllowNull()][nullable[datetime]]$Now = $null,
|
|
136
|
+
[Parameter(Mandatory = $false)][AllowNull()][string]$Nonce = $null
|
|
137
|
+
)
|
|
138
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix $script:DiscoveryGateReasonPrefix
|
|
139
|
+
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
140
|
+
|
|
141
|
+
# Seams resolve only after the dependency check so a missing module denies
|
|
142
|
+
# instead of raising while a default is evaluated.
|
|
143
|
+
if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
|
|
144
|
+
if ($null -eq $Store) { $Store = Get-DiscoveryDefaultStore }
|
|
145
|
+
if ($null -eq $Now) { $Now = [datetime]::UtcNow }
|
|
146
|
+
if ([string]::IsNullOrEmpty($Nonce)) { $Nonce = Get-DiscoveryAuthorizationNonce }
|
|
147
|
+
|
|
148
|
+
$normalized = ConvertFrom-DiscoveryHostPayloadText -HostName 'codex' -Text $ToolInputRaw
|
|
149
|
+
return Get-DiscoveryPreToolDecision -Normalized $normalized -HostEnvironment $HostEnvironment `
|
|
150
|
+
-HandlerSha256 (Get-DiscoveryGateHandlerSha256) -Store $Store -Now $Now -Nonce $Nonce
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function Invoke-DiscoveryArtifactGateEntryPoint {
|
|
154
|
+
<#
|
|
155
|
+
.SYNOPSIS
|
|
156
|
+
Reads one Codex PreToolUse payload, writes the decision and returns the process exit code.
|
|
157
|
+
.DESCRIPTION
|
|
158
|
+
An unreadable envelope writes its reason to stderr and returns 2. A deny
|
|
159
|
+
writes the PreToolUse decision JSON to stdout and returns 0. An allow writes
|
|
160
|
+
nothing and returns 0, as the Codex gates do.
|
|
161
|
+
#>
|
|
162
|
+
[CmdletBinding()]
|
|
163
|
+
[OutputType([int])]
|
|
164
|
+
param([Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw)
|
|
165
|
+
|
|
166
|
+
$outcome = Invoke-DiscoveryArtifactGateDecision -ToolInputRaw $PayloadRaw
|
|
167
|
+
# A dependency failure is already the PreToolUse deny decision.
|
|
168
|
+
if ($outcome -is [System.Collections.IDictionary]) { [Console]::Out.WriteLine(($outcome | ConvertTo-Json -Compress -Depth 5)); return 0 }
|
|
169
|
+
if ($outcome.Decision -eq 'allow') { return 0 }
|
|
170
|
+
if ($outcome.Code -eq 'ENVELOPE') {
|
|
171
|
+
[Console]::Error.WriteLine("$($script:DiscoveryGateReasonPrefix) $($outcome.Reason)")
|
|
172
|
+
return 2
|
|
173
|
+
}
|
|
174
|
+
$decision = ConvertTo-DiscoveryPreToolHookOutput -Outcome $outcome -ReasonPrefix $script:DiscoveryGateReasonPrefix
|
|
175
|
+
[Console]::Out.WriteLine(($decision | ConvertTo-Json -Compress -Depth 5))
|
|
176
|
+
return 0
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Guard allows dot-sourcing in tests without executing the entrypoint.
|
|
180
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('DISCOVERY_ARTIFACT_GATE_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
184
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent PreToolUse -ReasonPrefix 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
185
|
+
if ($null -ne $dependencyDecision) { $dependencyDecision | ConvertTo-Json -Compress -Depth 5 | Write-Output; exit 0 }
|
|
186
|
+
|
|
187
|
+
exit (Invoke-DiscoveryArtifactGateEntryPoint -PayloadRaw ([Console]::In.ReadToEnd()))
|