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