@danmoisan/drm-copilot-mcp 1.1.18 → 1.1.20
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 +1149 -661
- package/package.json +3 -2
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +28 -6
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +20 -2
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +17 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +6 -4
- package/resources/claude-customizations/.claude/agents/orchestrator.md +9 -5
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +35 -13
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
- package/resources/claude-customizations/.claude/agents/task-researcher.md +8 -0
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-command.ps1 +190 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +78 -77
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +497 -0
- package/resources/claude-customizations/.claude/hooks/premortem-section.ps1 +149 -0
- package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +267 -113
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +77 -33
- package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
- package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +52 -36
- package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
- package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-MergeConfirmationParser.ps1 +203 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +24 -3
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
- package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
- package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +37 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +85 -10
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
- package/resources/claude-customizations/.claude/rules/shell.md +10 -8
- package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +3 -4
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +52 -16
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +7 -3
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +2 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +2 -0
- package/resources/claude-customizations/.claude/skills/csharp-change-budget-router/SKILL.md +2 -2
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +45 -9
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +5 -3
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +134 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -3
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +36 -15
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +108 -21
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
- package/resources/claude-customizations/.claude/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/python-change-budget-router/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +16 -8
- package/resources/claude-customizations/.claude/skills/research-issue/SKILL.md +6 -0
- package/resources/claude-customizations/pack-manifests/core.json +27 -0
- package/resources/codex-and-agents-customizations/.agents/skills/README.md +1 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +19 -7
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +43 -4
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +18 -6
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +16 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +134 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +13 -5
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +27 -8
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +6 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +21 -6
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +15 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +4 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +7 -4
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-atomic-planning.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c1.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c2.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3-elevated.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c3.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher-c4.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/agents/task-researcher.toml +6 -0
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate-command.ps1 +190 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +54 -43
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +497 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
- package/resources/codex-and-agents-customizations/.codex/prompts/feature-review-remediate.md +6 -4
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +11 -0
- package/resources/customizations/.github/agents/atomic_executor.agent.md +21 -11
- package/resources/customizations/.github/agents/atomic_planning.agent.md +8 -3
- package/resources/customizations/.github/agents/csharp-atomic-executor.agent.md +13 -9
- package/resources/customizations/.github/agents/csharp-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +2 -2
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +5 -5
- package/resources/customizations/.github/agents/orchestrator.agent.md +8 -5
- package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +13 -9
- package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +2 -2
- package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +3 -3
- package/resources/customizations/.github/agents/python-atomic-executor.agent.md +13 -9
- package/resources/customizations/.github/agents/python-atomic-planning.agent.md +2 -2
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +2 -2
- package/resources/customizations/.github/agents/task-researcher.agent.md +6 -0
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
- package/resources/customizations/.github/prompts/generate-atomic-plan.prompt.md +16 -10
- package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +2 -2
- package/resources/customizations/.github/prompts/orchestrate-powershell-work.prompt.md +1 -1
- package/resources/customizations/.github/prompts/orchestrate-python-work.prompt.md +1 -1
- package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +43 -4
- package/resources/customizations/.github/skills/csharp-change-budget-router/SKILL.md +1 -1
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +134 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/customizations/.github/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +7 -3
- package/resources/feature-templates/bug/plan.yyyy-MM-ddTHH-mm.md +10 -0
- package/resources/feature-templates/feature/plan.yyyy-MM-ddTHH-mm.md +11 -0
- package/resources/feature-templates/refactor/plan.yyyy-MM-ddTHH-mm.md +11 -0
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.CoverageMerge.psm1 +163 -0
- package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +296 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +48 -32
- package/resources/powershell/PoshQC/PoshQC.psd1 +7 -1
- package/resources/powershell/PoshQC/PoshQC.psm1 +18 -5
- package/resources/powershell/PoshQC/README.md +21 -3
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +5 -319
|
@@ -3,18 +3,25 @@
|
|
|
3
3
|
Structural command-invocation matcher shared by the Claude and Codex enforcement hooks.
|
|
4
4
|
.DESCRIPTION
|
|
5
5
|
Realizes Piece 3 of the D2 behavior contract and the retrieval surface of D12 in
|
|
6
|
-
docs/features/active/2026-08-25-enforcement-hook-trigger-matches-whole-command-text-545/spec.md
|
|
6
|
+
docs/features/active/2026-08-25-enforcement-hook-trigger-matches-whole-command-text-545/spec.md,
|
|
7
|
+
as revised by issue #824.
|
|
7
8
|
|
|
8
|
-
Answers
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Answers whether a command line INVOKES a named command word with a named subcommand
|
|
10
|
+
path, rather than merely containing those words. Every record produced by
|
|
11
|
+
Read-CommandLineInvocationSegment (top-level segments, wrapper payloads, substitution
|
|
12
|
+
bodies, and xargs-injected commands) is classified Structural, Indeterminate, or not a
|
|
13
|
+
match. An Indeterminate match is fail-closed for every consumer: it means the command may
|
|
14
|
+
invoke the governed command and its target cannot be read. Classification never rests on
|
|
15
|
+
substring containment; every presence test is whole-token (Test-CommandLineWordPresent).
|
|
12
16
|
|
|
13
17
|
Pure string logic only: no disk, process, network, clock, or environment access. It is
|
|
14
18
|
dot-sourced as: . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1')
|
|
15
19
|
#>
|
|
16
20
|
|
|
17
21
|
. (Join-Path $PSScriptRoot 'hook-command-scanner.ps1')
|
|
22
|
+
. (Join-Path $PSScriptRoot 'hook-command-payload.ps1')
|
|
23
|
+
. (Join-Path $PSScriptRoot 'hook-command-payload-powershell.ps1')
|
|
24
|
+
. (Join-Path $PSScriptRoot 'hook-command-invocation-operands.ps1')
|
|
18
25
|
|
|
19
26
|
# The transparent-wrapper set of D2 Piece 3 step 2. These prefix a command without changing
|
|
20
27
|
# which command runs, so the structural matcher skips them. All five are also members of the
|
|
@@ -22,25 +29,30 @@
|
|
|
22
29
|
# both mechanisms. Pinned by test through Get-CommandLineTransparentWrapperName (rule R6).
|
|
23
30
|
$script:CommandLineTransparentWrapperNames = @('command', 'env', 'nohup', 'time', 'timeout')
|
|
24
31
|
|
|
25
|
-
# The modeled global-option tables of D2 Piece 3
|
|
26
|
-
# in WithArgument consumes the following token as its
|
|
27
|
-
# the '--name=value' form; an option in Standalone
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
32
|
+
# The modeled global-option tables of D2 Piece 3 step 3, the D6/D10 gh surface, and the
|
|
33
|
+
# issue #824 Terminal lists. An option in WithArgument consumes the following token as its
|
|
34
|
+
# value, or carries the value inline in the '--name=value' form; an option in Standalone
|
|
35
|
+
# consumes only itself ('--exec-path=<value>' is one token, so it is Standalone); a bare
|
|
36
|
+
# option in Terminal makes the command print and exit, so the segment is a resolved
|
|
37
|
+
# non-match. A dash-leading token in none of the lists is UNMODELED: its arity is unknown, so
|
|
38
|
+
# an unmodeled token between the command word and the subcommand classifies the segment
|
|
39
|
+
# Indeterminate, which every consumer treats fail-closed. Pinned by test through
|
|
31
40
|
# Get-CommandLineGlobalOption (rule R6).
|
|
32
41
|
$script:CommandLineGlobalOptions = @{
|
|
33
42
|
git = [pscustomobject]@{
|
|
34
|
-
WithArgument = @('-C', '-c', '--git-dir', '--work-tree', '--namespace'
|
|
35
|
-
Standalone = @('-p', '--paginate', '--no-pager', '--literal-pathspecs', '--no-optional-locks', '--bare')
|
|
43
|
+
WithArgument = @('-C', '-c', '--git-dir', '--work-tree', '--namespace')
|
|
44
|
+
Standalone = @('-p', '--paginate', '--no-pager', '--literal-pathspecs', '--no-optional-locks', '--bare', '--exec-path')
|
|
45
|
+
Terminal = @('--version', '-v', '--help', '-h', '--html-path', '--man-path', '--info-path', '--exec-path')
|
|
36
46
|
}
|
|
37
47
|
gh = [pscustomobject]@{
|
|
38
48
|
WithArgument = @('-R', '--repo')
|
|
39
49
|
Standalone = @()
|
|
50
|
+
Terminal = @('--version', '--help')
|
|
40
51
|
}
|
|
41
52
|
npx = [pscustomobject]@{
|
|
42
53
|
WithArgument = @('-p', '--package', '-c', '--call', '--node-arg', '--userconfig')
|
|
43
54
|
Standalone = @('-y', '--yes', '--no-install', '--ignore-existing', '-q', '--quiet')
|
|
55
|
+
Terminal = @()
|
|
44
56
|
}
|
|
45
57
|
}
|
|
46
58
|
|
|
@@ -69,11 +81,10 @@ function Get-CommandLineGlobalOption {
|
|
|
69
81
|
.SYNOPSIS
|
|
70
82
|
Return the modeled global-option table for one command word.
|
|
71
83
|
.DESCRIPTION
|
|
72
|
-
Returns a record carrying
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
classifies - the fail-closed direction.
|
|
84
|
+
Returns a record carrying three string arrays: WithArgument, Standalone, and Terminal.
|
|
85
|
+
An unrecognized command word yields three empty arrays, so every dash-leading token
|
|
86
|
+
for that command word is unmodeled and classifies Indeterminate - the fail-closed
|
|
87
|
+
direction.
|
|
77
88
|
.OUTPUTS
|
|
78
89
|
System.Management.Automation.PSCustomObject
|
|
79
90
|
#>
|
|
@@ -86,32 +97,40 @@ function Get-CommandLineGlobalOption {
|
|
|
86
97
|
return $script:CommandLineGlobalOptions[$key]
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
return [pscustomobject]@{ WithArgument = @(); Standalone = @() }
|
|
100
|
+
return [pscustomobject]@{ WithArgument = @(); Standalone = @(); Terminal = @() }
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
function Test-
|
|
103
|
+
function Test-CommandLineTokenLiteral {
|
|
93
104
|
<#
|
|
94
105
|
.SYNOPSIS
|
|
95
|
-
Report whether a
|
|
96
|
-
.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
Report whether a token is literal: no '$' or backtick, and not led by '(', '@', or '{'.
|
|
107
|
+
.OUTPUTS
|
|
108
|
+
System.Boolean
|
|
109
|
+
#>
|
|
110
|
+
[CmdletBinding()]
|
|
111
|
+
[OutputType([bool])]
|
|
112
|
+
param([Parameter(Mandatory)][AllowEmptyString()][string] $Token)
|
|
113
|
+
|
|
114
|
+
if ($Token.Contains('$') -or $Token.Contains('`')) { return $false }
|
|
115
|
+
return -not ($Token.StartsWith('(') -or $Token.StartsWith('@') -or $Token.StartsWith('{'))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function Test-CommandLineAllWordPresent {
|
|
119
|
+
<#
|
|
120
|
+
.SYNOPSIS
|
|
121
|
+
Report whether every word passes Test-CommandLineWordPresent on one text.
|
|
100
122
|
.OUTPUTS
|
|
101
123
|
System.Boolean
|
|
102
124
|
#>
|
|
103
125
|
[CmdletBinding()]
|
|
104
126
|
[OutputType([bool])]
|
|
105
127
|
param(
|
|
106
|
-
[Parameter(Mandatory)][AllowEmptyString()][string] $
|
|
107
|
-
[Parameter(Mandatory)][string] $
|
|
108
|
-
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
128
|
+
[Parameter(Mandatory)][AllowEmptyString()][AllowNull()][string] $Text,
|
|
129
|
+
[Parameter(Mandatory)][string[]] $Word
|
|
109
130
|
)
|
|
110
131
|
|
|
111
|
-
$
|
|
112
|
-
|
|
113
|
-
foreach ($element in $SubcommandPath) {
|
|
114
|
-
if ($RawText.IndexOf($element, $comparison) -lt 0) { return $false }
|
|
132
|
+
foreach ($current in $Word) {
|
|
133
|
+
if (-not (Test-CommandLineWordPresent -RawText $Text -Word $current)) { return $false }
|
|
115
134
|
}
|
|
116
135
|
return $true
|
|
117
136
|
}
|
|
@@ -121,9 +140,10 @@ function Skip-CommandLineOption {
|
|
|
121
140
|
.SYNOPSIS
|
|
122
141
|
Absorb modeled options from a token list and report where they end.
|
|
123
142
|
.DESCRIPTION
|
|
124
|
-
Returns Index, the position of the first token that is not a modeled option,
|
|
125
|
-
|
|
126
|
-
|
|
143
|
+
Returns Index, the position of the first token that is not a modeled option; Terminal,
|
|
144
|
+
set when a bare token (no '=') is in the Terminal list, which is tested before any
|
|
145
|
+
other list; Unmodeled, set when a dash-leading token appears in no list; and Options,
|
|
146
|
+
the ordered {Name, Value} pairs absorbed. A bare '-' and a bare '--' stop absorption.
|
|
127
147
|
.OUTPUTS
|
|
128
148
|
System.Management.Automation.PSCustomObject
|
|
129
149
|
#>
|
|
@@ -136,300 +156,290 @@ function Skip-CommandLineOption {
|
|
|
136
156
|
)
|
|
137
157
|
|
|
138
158
|
$index = $StartIndex
|
|
159
|
+
$options = [System.Collections.Generic.List[pscustomobject]]::new()
|
|
139
160
|
while ($index -lt $Token.Count) {
|
|
140
161
|
$current = $Token[$index]
|
|
141
162
|
if (-not $current.StartsWith('-') -or $current -eq '-' -or $current -eq '--') { break }
|
|
142
163
|
|
|
143
164
|
$name = $current
|
|
144
|
-
$
|
|
165
|
+
$value = $null
|
|
145
166
|
$split = $current.IndexOf('=')
|
|
146
167
|
if ($split -gt 0) {
|
|
147
168
|
$name = $current.Substring(0, $split)
|
|
148
|
-
$
|
|
169
|
+
$value = $current.Substring($split + 1)
|
|
170
|
+
} elseif (@($Option.Terminal) -contains $current) {
|
|
171
|
+
return [pscustomobject]@{ Index = $index; Unmodeled = $false; Terminal = $true; Options = $options.ToArray() }
|
|
149
172
|
}
|
|
150
173
|
|
|
151
174
|
if ($Option.WithArgument -contains $name) {
|
|
152
|
-
|
|
175
|
+
if ($null -eq $value) {
|
|
176
|
+
$value = if ($index + 1 -lt $Token.Count) { $Token[$index + 1] } else { $null }
|
|
177
|
+
$index++
|
|
178
|
+
}
|
|
179
|
+
$options.Add([pscustomobject]@{ Name = $name; Value = $value })
|
|
180
|
+
$index++
|
|
153
181
|
continue
|
|
154
182
|
}
|
|
155
183
|
if ($Option.Standalone -contains $name) {
|
|
184
|
+
$options.Add([pscustomobject]@{ Name = $name; Value = $value })
|
|
156
185
|
$index++
|
|
157
186
|
continue
|
|
158
187
|
}
|
|
159
188
|
|
|
160
|
-
return [pscustomobject]@{ Index = $index; Unmodeled = $true }
|
|
189
|
+
return [pscustomobject]@{ Index = $index; Unmodeled = $true; Terminal = $false; Options = $options.ToArray() }
|
|
161
190
|
}
|
|
162
191
|
|
|
163
|
-
return [pscustomobject]@{ Index = $index; Unmodeled = $false }
|
|
192
|
+
return [pscustomobject]@{ Index = $index; Unmodeled = $false; Terminal = $false; Options = $options.ToArray() }
|
|
164
193
|
}
|
|
165
194
|
|
|
166
|
-
function
|
|
195
|
+
function Get-CommandLineStructuralWalk {
|
|
167
196
|
<#
|
|
168
197
|
.SYNOPSIS
|
|
169
|
-
|
|
198
|
+
Walk one record's tokens for a command word and subcommand path (DC-10 rule 3).
|
|
170
199
|
.DESCRIPTION
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
command
|
|
175
|
-
|
|
176
|
-
non-dash token that is not the next expected subcommand element terminates that
|
|
177
|
-
segment's scan without a match, so 'git log --grep add' does not classify.
|
|
178
|
-
|
|
179
|
-
Returns $null when no segment matched. Otherwise returns Segment, the matched record,
|
|
180
|
-
and OperandIndex, the token position just past the subcommand path - or -1 when the
|
|
181
|
-
match was reached by a non-structural rule, in which case there is no operand
|
|
182
|
-
position to report.
|
|
200
|
+
Skips VAR=value prefixes and transparent wrappers, leaf-compares the command word, and
|
|
201
|
+
absorbs modeled options before each subcommand element. Outcome is 'Match' (with
|
|
202
|
+
OperandIndex and GlobalOptions), 'Terminal', 'Unmodeled', or 'NoMatch'. A NoMatch
|
|
203
|
+
reports whether the command-word token or the subcommand-position token where the walk
|
|
204
|
+
stopped was non-literal, and whether a transparent wrapper was skipped.
|
|
183
205
|
.OUTPUTS
|
|
184
206
|
System.Management.Automation.PSCustomObject
|
|
185
207
|
#>
|
|
186
208
|
[CmdletBinding()]
|
|
187
209
|
[OutputType([pscustomobject])]
|
|
188
210
|
param(
|
|
189
|
-
[Parameter(Mandatory)][
|
|
211
|
+
[Parameter(Mandatory)][AllowEmptyCollection()][AllowEmptyString()][string[]] $Token,
|
|
190
212
|
[Parameter(Mandatory)][string] $CommandWord,
|
|
191
|
-
[Parameter(Mandatory)][
|
|
213
|
+
[Parameter(Mandatory)][string[]] $SubcommandPath,
|
|
214
|
+
[Parameter(Mandatory)][pscustomobject] $Option
|
|
192
215
|
)
|
|
193
216
|
|
|
194
|
-
$
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
$result = [pscustomobject]@{
|
|
218
|
+
Outcome = 'NoMatch'; OperandIndex = -1; GlobalOptions = [pscustomobject[]]@()
|
|
219
|
+
SkippedWrapper = $false; CommandWordNonLiteral = $false; SubcommandNonLiteral = $false
|
|
220
|
+
}
|
|
221
|
+
$skip = Skip-CommandLineTransparentWrapper -Token $Token -Except $CommandWord
|
|
222
|
+
$result.SkippedWrapper = $skip.SkippedWrapper
|
|
223
|
+
$index = $skip.Index
|
|
224
|
+
if ($index -ge $Token.Count) { return $result }
|
|
225
|
+
if (-not (Test-CommandLineTokenLiteral -Token $Token[$index])) { $result.CommandWordNonLiteral = $true; return $result }
|
|
226
|
+
if ((ConvertTo-CommandLineLeafWord -Word $Token[$index]) -ne $CommandWord) { return $result }
|
|
227
|
+
$index++
|
|
228
|
+
|
|
229
|
+
$globalOptions = [System.Collections.Generic.List[pscustomobject]]::new()
|
|
230
|
+
foreach ($element in $SubcommandPath) {
|
|
231
|
+
$skipOption = Skip-CommandLineOption -Token $Token -StartIndex $index -Option $Option
|
|
232
|
+
foreach ($absorbed in @($skipOption.Options)) { $globalOptions.Add($absorbed) }
|
|
233
|
+
if ($skipOption.Terminal) { $result.Outcome = 'Terminal'; return $result }
|
|
234
|
+
if ($skipOption.Unmodeled) { $result.Outcome = 'Unmodeled'; return $result }
|
|
235
|
+
$index = $skipOption.Index
|
|
236
|
+
if ($index -ge $Token.Count) { return $result }
|
|
237
|
+
if (-not (Test-CommandLineTokenLiteral -Token $Token[$index])) { $result.SubcommandNonLiteral = $true; return $result }
|
|
238
|
+
if ($Token[$index] -ne $element) { return $result }
|
|
239
|
+
$index++
|
|
240
|
+
}
|
|
206
241
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
$index++
|
|
213
|
-
}
|
|
242
|
+
$result.Outcome = 'Match'
|
|
243
|
+
$result.OperandIndex = $index
|
|
244
|
+
$result.GlobalOptions = $globalOptions.ToArray()
|
|
245
|
+
return $result
|
|
246
|
+
}
|
|
214
247
|
|
|
215
|
-
|
|
216
|
-
|
|
248
|
+
function Get-CommandLineInvocationOperand {
|
|
249
|
+
<#
|
|
250
|
+
.SYNOPSIS
|
|
251
|
+
Collect the operands after a structural match and report whether they are complete (DC-12).
|
|
252
|
+
.DESCRIPTION
|
|
253
|
+
OperandsComplete is $false for an argument-injected record, for any non-literal operand,
|
|
254
|
+
for a redirection after the subcommand (a bare operator also consumes its target), and
|
|
255
|
+
for an unmodeled dash token followed by another token.
|
|
256
|
+
.OUTPUTS
|
|
257
|
+
System.Management.Automation.PSCustomObject with Operands and Complete.
|
|
258
|
+
#>
|
|
259
|
+
[CmdletBinding()]
|
|
260
|
+
[OutputType([pscustomobject])]
|
|
261
|
+
param(
|
|
262
|
+
[Parameter(Mandatory)][AllowEmptyCollection()][AllowEmptyString()][string[]] $Token,
|
|
263
|
+
[Parameter(Mandatory)][int] $StartIndex,
|
|
264
|
+
[Parameter(Mandatory)][pscustomobject] $Option,
|
|
265
|
+
[Parameter(Mandatory)][bool] $ArgumentInjected
|
|
266
|
+
)
|
|
217
267
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
$index++
|
|
268
|
+
$operands = [System.Collections.Generic.List[string]]::new()
|
|
269
|
+
$complete = -not $ArgumentInjected
|
|
270
|
+
$afterSeparator = $false
|
|
271
|
+
$index = $StartIndex
|
|
272
|
+
while ($index -lt $Token.Count) {
|
|
273
|
+
$current = $Token[$index]
|
|
274
|
+
if (-not $afterSeparator -and $current -match '^(<|>|\d*>|&>)') {
|
|
275
|
+
$complete = $false
|
|
276
|
+
$index += if ($current -match '^(\d*[<>]{1,2}&?|&>{1,2})$') { 2 } else { 1 }
|
|
277
|
+
continue
|
|
230
278
|
}
|
|
231
|
-
|
|
232
|
-
if ($
|
|
233
|
-
|
|
279
|
+
if ($afterSeparator) { $operands.Add($current); $index++; continue }
|
|
280
|
+
if ($current -eq '--') { $afterSeparator = $true; $index++; continue }
|
|
281
|
+
if ($current.StartsWith('-') -and $current.Length -gt 1) {
|
|
282
|
+
$name = $current
|
|
283
|
+
$hasInlineValue = $false
|
|
284
|
+
$split = $current.IndexOf('=')
|
|
285
|
+
if ($split -gt 0) { $name = $current.Substring(0, $split); $hasInlineValue = $true }
|
|
286
|
+
if ($Option.WithArgument -contains $name) { $index += if ($hasInlineValue) { 1 } else { 2 }; continue }
|
|
287
|
+
if ($Option.Standalone -contains $name -or $script:CommandLineStandaloneFlagNames -contains $name) { $index++; continue }
|
|
288
|
+
if ($index + 1 -lt $Token.Count) { $complete = $false }
|
|
289
|
+
break
|
|
234
290
|
}
|
|
291
|
+
$operands.Add($current)
|
|
292
|
+
$index++
|
|
235
293
|
}
|
|
236
|
-
|
|
237
|
-
|
|
294
|
+
foreach ($operand in $operands) {
|
|
295
|
+
if (-not (Test-CommandLineTokenLiteral -Token $operand)) { $complete = $false }
|
|
296
|
+
}
|
|
297
|
+
return [pscustomobject]@{ Operands = [string[]]$operands.ToArray(); Complete = $complete }
|
|
238
298
|
}
|
|
239
299
|
|
|
240
|
-
function
|
|
300
|
+
function ConvertTo-CommandLineIndeterminateMatch {
|
|
241
301
|
<#
|
|
242
302
|
.SYNOPSIS
|
|
243
|
-
|
|
244
|
-
subcommand path, structurally rather than by raw-text adjacency.
|
|
245
|
-
.DESCRIPTION
|
|
246
|
-
Scans every segment produced by Read-CommandLineSegment and applies the four
|
|
247
|
-
mandatory fail-closed rules of D12, which are stated in full on
|
|
248
|
-
Resolve-CommandLineInvocation. This predicate is the replacement for every
|
|
249
|
-
raw-text trigger regex that asked whether a governed command runs.
|
|
250
|
-
.PARAMETER CommandText
|
|
251
|
-
The raw Bash command text.
|
|
252
|
-
.PARAMETER CommandWord
|
|
253
|
-
The command name, e.g. 'git' or 'gh'. Compared case-insensitively.
|
|
254
|
-
.PARAMETER SubcommandPath
|
|
255
|
-
One or more ordered subcommand tokens, e.g. @('worktree','remove'), @('pr','merge'),
|
|
256
|
-
@('issue','create'), @('add'). Compared case-insensitively.
|
|
303
|
+
Build an Indeterminate match record: no operand position, no operands, incomplete.
|
|
257
304
|
.OUTPUTS
|
|
258
|
-
System.
|
|
305
|
+
System.Management.Automation.PSCustomObject
|
|
259
306
|
#>
|
|
260
307
|
[CmdletBinding()]
|
|
261
|
-
[OutputType([
|
|
308
|
+
[OutputType([pscustomobject])]
|
|
262
309
|
param(
|
|
263
|
-
[Parameter(Mandatory)][
|
|
264
|
-
[Parameter(Mandatory)][string] $
|
|
265
|
-
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
310
|
+
[Parameter(Mandatory)][pscustomobject] $Record,
|
|
311
|
+
[Parameter(Mandatory)][string] $Reason
|
|
266
312
|
)
|
|
267
313
|
|
|
268
|
-
return
|
|
314
|
+
return [pscustomobject]@{
|
|
315
|
+
Status = 'Indeterminate'; Reason = $Reason; Segment = $Record; OperandIndex = -1
|
|
316
|
+
GlobalOptions = [pscustomobject[]]@(); Operands = [string[]]@(); OperandsComplete = $false
|
|
317
|
+
}
|
|
269
318
|
}
|
|
270
319
|
|
|
271
|
-
function Get-
|
|
320
|
+
function Get-CommandLineInvocation {
|
|
272
321
|
<#
|
|
273
322
|
.SYNOPSIS
|
|
274
|
-
Return
|
|
323
|
+
Return every match of a command word and subcommand path, in source order.
|
|
275
324
|
.DESCRIPTION
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
match reached by a non-structural fail-closed rule reports no operand position, and
|
|
287
|
-
yields no operands.
|
|
288
|
-
|
|
289
|
-
Callers receive the result through the @(...) array form used at every call site, so
|
|
290
|
-
the no-operand case arrives as an empty array rather than as $null.
|
|
291
|
-
.PARAMETER CommandText
|
|
292
|
-
The raw Bash command text.
|
|
293
|
-
.PARAMETER CommandWord
|
|
294
|
-
The command name.
|
|
295
|
-
.PARAMETER SubcommandPath
|
|
296
|
-
The ordered subcommand tokens.
|
|
325
|
+
For each iterator record the first applicable rule wins (DC-10): Unbalanced, decode
|
|
326
|
+
failure, and depth limit are Indeterminate; a structural walk that reaches a Terminal
|
|
327
|
+
option is no match, one that meets an unmodeled option is Indeterminate (Opaque), and
|
|
328
|
+
one that matches the full path is Structural. Otherwise a wrapper with no payload or a
|
|
329
|
+
transparent-wrapper-led record whose own RawText carries every word as a whole token
|
|
330
|
+
is Indeterminate (Opaque); a non-literal command word or subcommand token is
|
|
331
|
+
Indeterminate (DynamicPosition) when the whole command text carries every word; and a
|
|
332
|
+
payload, substitution, or injected record is Indeterminate (NotProvenInert) when its
|
|
333
|
+
PresenceText carries every word and its root's payload is not proven inert, at most
|
|
334
|
+
once per root.
|
|
297
335
|
.OUTPUTS
|
|
298
|
-
System.
|
|
336
|
+
System.Management.Automation.PSCustomObject[] - each carries Status ('Structural' or
|
|
337
|
+
'Indeterminate'), Reason ('', 'Unbalanced', 'Opaque', 'DynamicPosition',
|
|
338
|
+
'NotProvenInert', 'DepthLimit'), Segment (the iterator record), OperandIndex (-1 when
|
|
339
|
+
Indeterminate), GlobalOptions, Operands, and OperandsComplete.
|
|
299
340
|
#>
|
|
300
341
|
[CmdletBinding()]
|
|
301
|
-
[OutputType([
|
|
342
|
+
[OutputType([pscustomobject[]])]
|
|
302
343
|
param(
|
|
303
344
|
[Parameter(Mandatory)][AllowEmptyString()][AllowNull()][string] $CommandText,
|
|
304
345
|
[Parameter(Mandatory)][string] $CommandWord,
|
|
305
346
|
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
306
347
|
)
|
|
307
348
|
|
|
308
|
-
$
|
|
309
|
-
$
|
|
310
|
-
if ($
|
|
311
|
-
return [string[]]$operands.ToArray()
|
|
312
|
-
}
|
|
313
|
-
|
|
349
|
+
$matchList = [System.Collections.Generic.List[pscustomobject]]::new()
|
|
350
|
+
$records = @(Read-CommandLineInvocationSegment -CommandText $CommandText)
|
|
351
|
+
if ($records.Count -eq 0) { return [pscustomobject[]]$matchList.ToArray() }
|
|
314
352
|
$option = Get-CommandLineGlobalOption -CommandWord $CommandWord
|
|
315
|
-
$
|
|
316
|
-
$
|
|
317
|
-
$
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
353
|
+
$words = [string[]](@($CommandWord) + $SubcommandPath)
|
|
354
|
+
$normalized = ConvertTo-CommandLineNormalizedText -CommandText $CommandText
|
|
355
|
+
$inertByRoot = @{}
|
|
356
|
+
$presenceRoots = [System.Collections.Generic.HashSet[int]]::new()
|
|
357
|
+
|
|
358
|
+
foreach ($record in $records) {
|
|
359
|
+
if ($record.Unbalanced) { $matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'Unbalanced')); continue }
|
|
360
|
+
if ($record.Opaque -and $record.OpaqueReason -eq 'DecodeFailure') { $matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'Opaque')); continue }
|
|
361
|
+
if ($record.Opaque -and $record.OpaqueReason -eq 'DepthLimit') { $matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'DepthLimit')); continue }
|
|
362
|
+
|
|
363
|
+
$tokens = [string[]]@($record.Tokens)
|
|
364
|
+
$walk = Get-CommandLineStructuralWalk -Token $tokens -CommandWord $CommandWord -SubcommandPath $SubcommandPath -Option $option
|
|
365
|
+
if ($walk.Outcome -eq 'Terminal') { continue }
|
|
366
|
+
if ($walk.Outcome -eq 'Unmodeled') { $matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'Opaque')); continue }
|
|
367
|
+
if ($walk.Outcome -eq 'Match') {
|
|
368
|
+
$collected = Get-CommandLineInvocationOperand -Token $tokens -StartIndex $walk.OperandIndex -Option $option -ArgumentInjected ([bool]$record.ArgumentInjected)
|
|
369
|
+
$matchList.Add([pscustomobject]@{
|
|
370
|
+
Status = 'Structural'; Reason = ''; Segment = $record; OperandIndex = $walk.OperandIndex
|
|
371
|
+
GlobalOptions = $walk.GlobalOptions; Operands = $collected.Operands; OperandsComplete = $collected.Complete
|
|
372
|
+
})
|
|
373
|
+
continue
|
|
374
|
+
}
|
|
321
375
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
376
|
+
# A transparent-wrapper-led record that expanded a payload is judged by its payload records.
|
|
377
|
+
$hasChild = $record.Index + 1 -lt $records.Count -and $records[$record.Index + 1].Depth -gt $record.Depth
|
|
378
|
+
$opaqueLed = ($record.Opaque -and $record.OpaqueReason -eq 'NoPayload') -or ($walk.SkippedWrapper -and -not $hasChild)
|
|
379
|
+
if ($opaqueLed -and (Test-CommandLineAllWordPresent -Text $record.RawText -Word $words)) {
|
|
380
|
+
$matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'Opaque'))
|
|
325
381
|
continue
|
|
326
382
|
}
|
|
327
|
-
if ($
|
|
328
|
-
$
|
|
329
|
-
$index++
|
|
383
|
+
if (($walk.CommandWordNonLiteral -or $walk.SubcommandNonLiteral) -and (Test-CommandLineAllWordPresent -Text $normalized -Word $words)) {
|
|
384
|
+
$matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'DynamicPosition'))
|
|
330
385
|
continue
|
|
331
386
|
}
|
|
332
|
-
|
|
333
|
-
if (
|
|
334
|
-
|
|
335
|
-
$
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if ($option.WithArgument -contains $name) {
|
|
343
|
-
$index += if ($hasInlineValue) { 1 } else { 2 }
|
|
344
|
-
continue
|
|
345
|
-
}
|
|
346
|
-
if ($option.Standalone -contains $name -or $script:CommandLineStandaloneFlagNames -contains $name) {
|
|
347
|
-
$index++
|
|
348
|
-
continue
|
|
349
|
-
}
|
|
350
|
-
break
|
|
387
|
+
if ($record.Origin -eq 'TopLevel' -or $presenceRoots.Contains([int]$record.RootIndex)) { continue }
|
|
388
|
+
if (-not (Test-CommandLineAllWordPresent -Text $record.PresenceText -Word $words)) { continue }
|
|
389
|
+
if (-not $inertByRoot.ContainsKey($record.RootIndex)) {
|
|
390
|
+
$inertByRoot[$record.RootIndex] = Test-CommandLinePayloadInert -Record $records -RootIndex $record.RootIndex
|
|
391
|
+
}
|
|
392
|
+
if (-not $inertByRoot[$record.RootIndex]) {
|
|
393
|
+
[void]$presenceRoots.Add([int]$record.RootIndex)
|
|
394
|
+
$matchList.Add((ConvertTo-CommandLineIndeterminateMatch -Record $record -Reason 'NotProvenInert'))
|
|
351
395
|
}
|
|
352
|
-
|
|
353
|
-
$operands.Add($current)
|
|
354
|
-
$index++
|
|
355
396
|
}
|
|
356
397
|
|
|
357
|
-
return [
|
|
398
|
+
return [pscustomobject[]]$matchList.ToArray()
|
|
358
399
|
}
|
|
359
400
|
|
|
360
|
-
function
|
|
401
|
+
function Resolve-CommandLineInvocation {
|
|
361
402
|
<#
|
|
362
403
|
.SYNOPSIS
|
|
363
|
-
Return the
|
|
404
|
+
Return the first match of a command word and subcommand path, or $null.
|
|
364
405
|
.DESCRIPTION
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
The $null-on-missing-value contract is mandatory and is pinned by issue #591's first
|
|
372
|
-
constraint: downstream logic treats a missing explicit pull-request number as a
|
|
373
|
-
fail-closed condition, so a bare 'gh pr merge --merge' must yield $null, never 0 and
|
|
374
|
-
never ''.
|
|
375
|
-
.PARAMETER CommandText
|
|
376
|
-
The raw Bash command text.
|
|
377
|
-
.PARAMETER CommandWord
|
|
378
|
-
The command name.
|
|
379
|
-
.PARAMETER SubcommandPath
|
|
380
|
-
The ordered subcommand tokens.
|
|
381
|
-
.PARAMETER FlagName
|
|
382
|
-
The flag as written, including leading dashes, e.g. '--merge' or '--body-file'.
|
|
383
|
-
Compared case-insensitively.
|
|
406
|
+
Returns Segment (the matched iterator record), OperandIndex (the token position just
|
|
407
|
+
past the subcommand path, or -1 when Status is 'Indeterminate'), and Status
|
|
408
|
+
('Structural' or 'Indeterminate') for the first record Get-CommandLineInvocation
|
|
409
|
+
matched. An Indeterminate match means the record may invoke the command and its
|
|
410
|
+
structure could not be resolved; every consumer treats it fail-closed.
|
|
384
411
|
.OUTPUTS
|
|
385
|
-
System.
|
|
386
|
-
the result themselves after a $null check.
|
|
412
|
+
System.Management.Automation.PSCustomObject
|
|
387
413
|
#>
|
|
388
414
|
[CmdletBinding()]
|
|
389
|
-
[OutputType([
|
|
415
|
+
[OutputType([pscustomobject])]
|
|
390
416
|
param(
|
|
391
417
|
[Parameter(Mandatory)][AllowEmptyString()][AllowNull()][string] $CommandText,
|
|
392
418
|
[Parameter(Mandatory)][string] $CommandWord,
|
|
393
|
-
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
394
|
-
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $FlagName
|
|
419
|
+
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
395
420
|
)
|
|
396
421
|
|
|
397
|
-
$
|
|
398
|
-
if ($null -eq $
|
|
399
|
-
|
|
400
|
-
$tokens = @($resolved.Segment.Tokens)
|
|
401
|
-
$prefix = $FlagName + '='
|
|
402
|
-
for ($index = 0; $index -lt $tokens.Count; $index++) {
|
|
403
|
-
$current = $tokens[$index]
|
|
404
|
-
|
|
405
|
-
if ($current -eq $FlagName) {
|
|
406
|
-
if ($index + 1 -ge $tokens.Count) { return $null }
|
|
407
|
-
$value = $tokens[$index + 1]
|
|
408
|
-
if ($value.StartsWith('-') -and $value.Length -gt 1) { return $null }
|
|
409
|
-
return $value
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if ($current.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
413
|
-
$value = $current.Substring($prefix.Length)
|
|
414
|
-
if ([string]::IsNullOrEmpty($value)) { return $null }
|
|
415
|
-
return $value
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
return $null
|
|
422
|
+
$first = @(Get-CommandLineInvocation -CommandText $CommandText -CommandWord $CommandWord -SubcommandPath $SubcommandPath) | Select-Object -First 1
|
|
423
|
+
if ($null -eq $first) { return $null }
|
|
424
|
+
return [pscustomobject]@{ Segment = $first.Segment; OperandIndex = $first.OperandIndex; Status = $first.Status }
|
|
420
425
|
}
|
|
421
426
|
|
|
422
|
-
function Test-
|
|
427
|
+
function Test-CommandLineInvocation {
|
|
423
428
|
<#
|
|
424
429
|
.SYNOPSIS
|
|
425
|
-
Report whether a
|
|
426
|
-
|
|
430
|
+
Report whether a command line invokes a named command word with a named
|
|
431
|
+
subcommand path, structurally rather than by raw-text adjacency.
|
|
427
432
|
.DESCRIPTION
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
+
True for any match, Structural or Indeterminate, as Get-CommandLineInvocation
|
|
434
|
+
defines them. This predicate is the replacement for every raw-text trigger regex
|
|
435
|
+
that asked whether a governed command runs.
|
|
436
|
+
.PARAMETER CommandText
|
|
437
|
+
The raw Bash command text.
|
|
438
|
+
.PARAMETER CommandWord
|
|
439
|
+
The command name, e.g. 'git' or 'gh'. Compared case-insensitively.
|
|
440
|
+
.PARAMETER SubcommandPath
|
|
441
|
+
One or more ordered subcommand tokens, e.g. @('worktree','remove'), @('pr','merge'),
|
|
442
|
+
@('issue','create'), @('add'). Compared case-insensitively.
|
|
433
443
|
.OUTPUTS
|
|
434
444
|
System.Boolean
|
|
435
445
|
#>
|
|
@@ -438,20 +448,10 @@ function Test-CommandLineFlag {
|
|
|
438
448
|
param(
|
|
439
449
|
[Parameter(Mandatory)][AllowEmptyString()][AllowNull()][string] $CommandText,
|
|
440
450
|
[Parameter(Mandatory)][string] $CommandWord,
|
|
441
|
-
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
442
|
-
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $FlagName
|
|
451
|
+
[Parameter(Mandatory)][ValidateNotNullOrEmpty()][string[]] $SubcommandPath
|
|
443
452
|
)
|
|
444
453
|
|
|
445
|
-
|
|
446
|
-
if ($null -eq $resolved) { return $false }
|
|
447
|
-
|
|
448
|
-
$prefix = $FlagName + '='
|
|
449
|
-
foreach ($current in @($resolved.Segment.Tokens)) {
|
|
450
|
-
if ($current -eq $FlagName) { return $true }
|
|
451
|
-
if ($current.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) { return $true }
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
return $false
|
|
454
|
+
return @(Get-CommandLineInvocation -CommandText $CommandText -CommandWord $CommandWord -SubcommandPath $SubcommandPath).Count -gt 0
|
|
455
455
|
}
|
|
456
456
|
|
|
457
457
|
function Test-CommandLineMention {
|
|
@@ -460,10 +460,9 @@ function Test-CommandLineMention {
|
|
|
460
460
|
Report whether a command line merely MENTIONS a command word and subcommand path
|
|
461
461
|
without invoking it.
|
|
462
462
|
.DESCRIPTION
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
decision from this predicate.
|
|
463
|
+
True when Test-CommandLineInvocation returns false and every word occurs in the
|
|
464
|
+
command text as a whole token (Test-CommandLineWordPresent). Purely informational;
|
|
465
|
+
no hook makes a deny decision from this predicate.
|
|
467
466
|
.OUTPUTS
|
|
468
467
|
System.Boolean
|
|
469
468
|
#>
|
|
@@ -479,5 +478,5 @@ function Test-CommandLineMention {
|
|
|
479
478
|
return $false
|
|
480
479
|
}
|
|
481
480
|
|
|
482
|
-
return (Test-
|
|
481
|
+
return (Test-CommandLineAllWordPresent -Text ([string]$CommandText) -Word ([string[]](@($CommandWord) + $SubcommandPath)))
|
|
483
482
|
}
|