@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
@@ -7,12 +7,17 @@
7
7
  plan state satisfy the executor's mechanical contract.
8
8
 
9
9
  Enforced checks:
10
- - hook payload is valid JSON and contains non-empty output,
10
+ - the SubagentStop envelope read from stdin carries a non-empty last_assistant_message,
11
11
  - output advertises `plan-path: <path>` (or supported equivalent forms),
12
12
  - the advertised plan exists on disk,
13
- - preflight-only runs return an exact preflight signal and may not claim
14
- non-canonical blocked text,
15
- - non-preflight runs may not stop in a blocked state,
13
+ - a run is classified as preflight from the delegation prompt in the subagent
14
+ transcript (Test-IsPreflightRun), falling back to the plan file or one output signal,
15
+ - preflight runs return exactly one preflight signal consistent with their
16
+ PREFLIGHT-DEFECT lines, name an existing fix record for any PREFLIGHT-FIX line,
17
+ and may not claim non-canonical blocked text,
18
+ - non-preflight runs may not stop in a blocked state, except a canonical preflight
19
+ block with a plan delta and no checked task (combined proportionate run); only the
20
+ uppercase BLOCKED token counts as a blocked claim, and lowercase prose does not,
16
21
  - non-preflight plans contain checkboxes and all are checked,
17
22
  - non-preflight output includes `AC Status Summary`,
18
23
  - non-preflight output includes command/status reporting,
@@ -20,48 +25,44 @@
20
25
  output includes a PASS or FAIL status line for that language.
21
26
 
22
27
  .NOTES
23
- Reads the hook payload from CLAUDE_HOOK_INPUT as JSON. Exits 0 to allow
24
- termination; exits 1 with an error message to block. Plan file contents are
25
- read through Get-PlanFileContent so tests can mock the filesystem boundary
26
- without writing temporary files.
28
+ Reads the SubagentStop envelope from stdin through Read-SubagentStopEnvelope
29
+ (subagentstop-envelope.ps1); the assistant text comes from the helper's
30
+ AssistantText. A non-repairable condition blocks once: when StopHookActive is
31
+ set, the re-entered stop is allowed. Exits 0 to allow termination; a block is
32
+ written to stderr with exit 2 through Exit-SubagentStopBlock. The dependency
33
+ guard and the E1 helper are guarded loads: a failure blocks with exit 2,
34
+ naming the file. Plan file contents are read through Get-PlanFileContent so
35
+ tests can mock the filesystem boundary without writing temporary files.
36
+ An unhandled error during validation blocks with exit 2 and a reason (issue #928).
27
37
  #>
28
38
 
29
39
  [CmdletBinding()]
30
40
  param()
41
+ $script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
31
42
 
32
43
  Set-StrictMode -Version Latest
44
+ try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
33
45
  $ErrorActionPreference = 'Stop'
46
+ $script:SubagentStopReportAndHaltLine = 'This condition is not repairable by the subagent. Report it to the operator and halt.'
34
47
 
35
48
  function Get-PlanFileContent {
36
49
  [CmdletBinding()]
37
50
  [OutputType([hashtable])]
38
- param(
39
- [Parameter(Mandatory = $true)]
40
- [string] $Path
41
- )
51
+ param([Parameter(Mandatory = $true)] [string] $Path)
42
52
 
43
53
  if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
44
54
  return @{ Exists = $false; Lines = @() }
45
55
  }
46
56
 
47
- $lines = Get-Content -LiteralPath $Path -ErrorAction Stop
48
- if ($null -eq $lines) {
49
- $lines = @()
50
- }
51
- elseif ($lines -isnot [array]) {
52
- $lines = @($lines)
53
- }
54
-
57
+ # @() yields an array for any line count; the filter drops a $null emitted at the read boundary.
58
+ $lines = @(Get-Content -LiteralPath $Path -ErrorAction Stop | Where-Object { $null -ne $_ })
55
59
  return @{ Exists = $true; Lines = $lines }
56
60
  }
57
61
 
58
62
  function Get-PlanPathFromOutput {
59
63
  [CmdletBinding()]
60
64
  [OutputType([string])]
61
- param(
62
- [Parameter(Mandatory = $true)]
63
- [string] $AgentOutput
64
- )
65
+ param([Parameter(Mandatory = $true)] [string] $AgentOutput)
65
66
 
66
67
  $pattern = 'plan-path\s*[:=]\s*["'']?([^\s"''\)`]+)|\[plan-path\]\(([^)]+)\)'
67
68
  $match = [regex]::Match($AgentOutput, $pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
@@ -81,22 +82,180 @@ function Get-PlanPathFromOutput {
81
82
  function Test-IsPreflightPlan {
82
83
  [CmdletBinding()]
83
84
  [OutputType([bool])]
84
- param(
85
- [Parameter(Mandatory = $true)]
86
- [string[]] $Lines
87
- )
85
+ param([Parameter(Mandatory = $true)] [AllowEmptyCollection()] [AllowEmptyString()] [string[]] $Lines)
88
86
 
89
87
  return @($Lines | Where-Object { $_ -match '(?i)^\s*DIRECTIVE:\s*PREFLIGHT VALIDATION ONLY\s*$' }).Count -gt 0
90
88
  }
91
89
 
92
- function Get-TouchedLanguagesFromPlan {
90
+ function Get-JsonPropertyValue {
91
+ # Returns a named property of a parsed JSON object, or $null; safe under StrictMode.
92
+ [CmdletBinding()]
93
+ [OutputType([object])]
94
+ param([AllowNull()] [object] $Object, [Parameter(Mandatory = $true)] [string] $Name)
95
+
96
+ if ($null -eq $Object -or -not ($Object -is [System.Management.Automation.PSCustomObject])) {
97
+ return $null
98
+ }
99
+ $property = @($Object.PSObject.Properties | Where-Object { $_.Name -ceq $Name })
100
+ if ($property.Count -eq 0) {
101
+ return $null
102
+ }
103
+ return $property[0].Value
104
+ }
105
+
106
+ function Get-TranscriptPathFromEnvelope {
107
+ # Returns agent_transcript_path from the SubagentStop envelope with a leading ~ expanded, or $null.
108
+ [CmdletBinding()]
109
+ [OutputType([string])]
110
+ param([AllowNull()] [object] $Envelope)
111
+
112
+ $path = Get-JsonPropertyValue -Object $Envelope -Name 'agent_transcript_path'
113
+ if (-not ($path -is [string]) -or [string]::IsNullOrWhiteSpace($path)) {
114
+ return $null
115
+ }
116
+ if ($path.StartsWith('~')) {
117
+ $path = $HOME + $path.Substring(1)
118
+ }
119
+ return $path
120
+ }
121
+
122
+ function Get-TranscriptFirstUserText {
123
+ # Returns the text of the first `user` entry of transcript JSONL lines, or $null when none parses.
124
+ [CmdletBinding()]
125
+ [OutputType([string])]
126
+ param([AllowEmptyString()] [string[]] $Lines = @())
127
+
128
+ foreach ($line in $Lines) {
129
+ if ([string]::IsNullOrWhiteSpace($line)) {
130
+ continue
131
+ }
132
+ try {
133
+ $entry = ConvertFrom-Json -InputObject $line -ErrorAction Stop
134
+ }
135
+ catch {
136
+ continue
137
+ }
138
+ if ((Get-JsonPropertyValue -Object $entry -Name 'type') -ne 'user') {
139
+ continue
140
+ }
141
+ $container = Get-JsonPropertyValue -Object $entry -Name 'message'
142
+ if ($null -eq $container) {
143
+ $container = $entry
144
+ }
145
+ $content = Get-JsonPropertyValue -Object $container -Name 'content'
146
+ if ($content -is [string]) {
147
+ return $content
148
+ }
149
+ $textBlocks = @(@($content) | Where-Object { (Get-JsonPropertyValue -Object $_ -Name 'type') -eq 'text' })
150
+ $texts = @($textBlocks | ForEach-Object { [string](Get-JsonPropertyValue -Object $_ -Name 'text') })
151
+ if ($texts.Count -gt 0) {
152
+ return ($texts -join "`n")
153
+ }
154
+ }
155
+ return $null
156
+ }
157
+
158
+ function Read-TranscriptHead {
159
+ # File seam: returns the first 50 lines of the transcript at Path, or $null when no file exists.
93
160
  [CmdletBinding()]
94
161
  [OutputType([string[]])]
162
+ param([Parameter(Mandatory = $true)] [string] $Path)
163
+
164
+ if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
165
+ return $null
166
+ }
167
+ return [string[]]@(Get-Content -LiteralPath $Path -TotalCount 50 -ErrorAction Stop)
168
+ }
169
+
170
+ function Test-IsPreflightRun {
171
+ <#
172
+ .SYNOPSIS
173
+ Classifies an executor run as preflight or execution (issue #964).
174
+ .DESCRIPTION
175
+ A readable transcript is authoritative: its first `user` entry (the delegation prompt) decides, even
176
+ against a stale plan-file directive. Otherwise the plan-file directive, then exactly one output
177
+ `PREFLIGHT:` signal, decide (self-declared). ReadTranscriptHead returns JSONL lines or $null.
178
+ #>
179
+ [CmdletBinding()]
180
+ [OutputType([bool])]
95
181
  param(
96
- [Parameter(Mandatory = $true)]
97
- [string[]] $Lines
182
+ [Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $AgentOutput,
183
+ [Parameter(Mandatory = $true)] [AllowEmptyCollection()] [AllowEmptyString()] [string[]] $PlanLines,
184
+ [AllowNull()] [AllowEmptyString()] [string] $TranscriptPath,
185
+ [scriptblock] $ReadTranscriptHead = ${function:Read-TranscriptHead}
98
186
  )
99
187
 
188
+ if (-not [string]::IsNullOrWhiteSpace($TranscriptPath)) {
189
+ $head = $null
190
+ try {
191
+ $head = & $ReadTranscriptHead $TranscriptPath
192
+ }
193
+ catch {
194
+ $head = $null
195
+ }
196
+ if ($null -ne $head) {
197
+ $prompt = Get-TranscriptFirstUserText -Lines ([string[]]@($head))
198
+ if ($null -ne $prompt) {
199
+ return [regex]::IsMatch($prompt, '(?im)^\s*DIRECTIVE:\s*PREFLIGHT VALIDATION ONLY\s*$')
200
+ }
201
+ }
202
+ }
203
+ if (Test-IsPreflightPlan -Lines $PlanLines) {
204
+ return $true
205
+ }
206
+ return [regex]::Matches($AgentOutput, '(?m)^\s*PREFLIGHT:\s*(ALL CLEAR|REVISIONS REQUIRED)\s*$').Count -eq 1
207
+ }
208
+
209
+ function Test-PreflightFixRecord {
210
+ # File seam for the preflight-fix-record path.
211
+ [CmdletBinding()]
212
+ [OutputType([bool])]
213
+ param([Parameter(Mandatory = $true)] [string] $Path)
214
+ return [bool](Test-Path -LiteralPath $Path -PathType Leaf)
215
+ }
216
+
217
+ function Get-PreflightRunBlockDecision {
218
+ <#
219
+ .SYNOPSIS
220
+ Applies the single-pass preflight output rules (issue #964); every block is repairable.
221
+ #>
222
+ [CmdletBinding()]
223
+ [OutputType([hashtable])]
224
+ param([Parameter(Mandatory = $true)] [string] $AgentOutput)
225
+
226
+ if (-not (Test-HasCanonicalBlockedText -AgentOutput $AgentOutput)) {
227
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: blocked preflight output must include the exact text `BLOCKED at preflight (before [P0-T1])` plus a concrete plan delta.' }
228
+ }
229
+ if ($AgentOutput -cmatch 'BLOCKED') {
230
+ return @{ Ok = $true; Message = $null }
231
+ }
232
+
233
+ $signals = @([regex]::Matches($AgentOutput, '(?m)^\s*PREFLIGHT:\s*(?<Signal>ALL CLEAR|REVISIONS REQUIRED)\s*$'))
234
+ if ($signals.Count -ne 1) {
235
+ return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: preflight output must carry exactly one ``PREFLIGHT: ALL CLEAR`` or ``PREFLIGHT: REVISIONS REQUIRED`` signal line; found $($signals.Count)." }
236
+ }
237
+ $defectCount = [regex]::Matches($AgentOutput, '(?m)^\s*PREFLIGHT-DEFECT:\s*\S').Count
238
+ if ($signals[0].Groups['Signal'].Value -eq 'ALL CLEAR' -and $defectCount -gt 0) {
239
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: `PREFLIGHT: ALL CLEAR` must not carry a `PREFLIGHT-DEFECT:` line; fix trivial defects in place or return `PREFLIGHT: REVISIONS REQUIRED`.' }
240
+ }
241
+ if ($signals[0].Groups['Signal'].Value -eq 'REVISIONS REQUIRED' -and $defectCount -eq 0) {
242
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: `PREFLIGHT: REVISIONS REQUIRED` must list every substantive defect as a `PREFLIGHT-DEFECT:` line.' }
243
+ }
244
+ if ([regex]::IsMatch($AgentOutput, '(?m)^\s*PREFLIGHT-FIX:\s*\S')) {
245
+ $record = [regex]::Match($AgentOutput, '(?im)^\s*preflight-fix-record:\s*`?(?<Path>[^\s`]+)`?\s*$')
246
+ $recordPath = if ($record.Success) { ($record.Groups['Path'].Value -replace '\\', '/') -replace '^\./', '' } else { '' }
247
+ if (-not $recordPath.StartsWith('docs/features/', [System.StringComparison]::OrdinalIgnoreCase) -or -not (Test-PreflightFixRecord -Path $recordPath)) {
248
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: a `PREFLIGHT-FIX:` line requires a `preflight-fix-record: <path>` line naming an existing record under docs/features/.' }
249
+ }
250
+ }
251
+ return @{ Ok = $true; Message = $null }
252
+ }
253
+
254
+ function Get-TouchedLanguagesFromPlan {
255
+ [CmdletBinding()]
256
+ [OutputType([string[]])]
257
+ param([Parameter(Mandatory = $true)] [AllowEmptyString()] [string[]] $Lines)
258
+
100
259
  $languages = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
101
260
  $pathPattern = '(?i)(?:[.\w*?-]+[\\/])+[.\w*?-]+'
102
261
 
@@ -118,13 +277,7 @@ function Get-TouchedLanguagesFromPlan {
118
277
  function Test-OutputHasLanguageStatus {
119
278
  [CmdletBinding()]
120
279
  [OutputType([bool])]
121
- param(
122
- [Parameter(Mandatory = $true)]
123
- [string] $AgentOutput,
124
-
125
- [Parameter(Mandatory = $true)]
126
- [string] $Language
127
- )
280
+ param([Parameter(Mandatory = $true)] [string] $AgentOutput, [Parameter(Mandatory = $true)] [string] $Language)
128
281
 
129
282
  $labelMap = @{
130
283
  'TypeScript' = @('TypeScript', 'typescript')
@@ -141,34 +294,28 @@ function Test-OutputHasLanguageStatus {
141
294
  function Test-HasPreflightSignal {
142
295
  [CmdletBinding()]
143
296
  [OutputType([bool])]
144
- param(
145
- [Parameter(Mandatory = $true)]
146
- [string] $AgentOutput
147
- )
297
+ param([Parameter(Mandatory = $true)] [string] $AgentOutput)
148
298
 
149
- return [regex]::IsMatch(
150
- $AgentOutput,
151
- '(?m)^\s*PREFLIGHT:\s*(ALL CLEAR|REVISIONS REQUIRED)\s*$'
152
- )
299
+ return [regex]::IsMatch($AgentOutput, '(?m)^\s*PREFLIGHT:\s*(ALL CLEAR|REVISIONS REQUIRED)\s*$')
153
300
  }
154
301
 
155
302
  function Test-HasCanonicalBlockedText {
156
303
  [CmdletBinding()]
157
304
  [OutputType([bool])]
158
- param(
159
- [Parameter(Mandatory = $true)]
160
- [string] $AgentOutput
161
- )
305
+ param([Parameter(Mandatory = $true)] [string] $AgentOutput)
162
306
 
163
- if ($AgentOutput -notmatch 'BLOCKED') {
307
+ # Case-sensitive: lowercase prose such as `blocked_reason` is not a BLOCKED claim (issue #964).
308
+ if ($AgentOutput -cnotmatch 'BLOCKED') {
164
309
  return $true
165
310
  }
166
311
 
167
- if ($AgentOutput -notmatch 'BLOCKED at preflight \(before \[P0-T1\]\)') {
312
+ if ($AgentOutput -cnotmatch 'BLOCKED at preflight \(before \[P0-T1\]\)') {
168
313
  return $false
169
314
  }
170
315
 
171
- if ($AgentOutput -notmatch '(?i)plan delta' -and $AgentOutput -notmatch '\[P\d+-T\d+\]') {
316
+ # The canonical phrase itself carries [P0-T1], so it is removed before looking for a plan delta.
317
+ $remainder = $AgentOutput -creplace 'BLOCKED at preflight \(before \[P0-T1\]\)', ''
318
+ if ($remainder -notmatch '(?i)plan delta' -and $remainder -notmatch '\[P\d+-T\d+\]') {
172
319
  return $false
173
320
  }
174
321
 
@@ -176,74 +323,89 @@ function Test-HasCanonicalBlockedText {
176
323
  }
177
324
 
178
325
  function Invoke-ExecutorOutputValidation {
326
+ <#
327
+ .SYNOPSIS
328
+ Reads the SubagentStop envelope, validates the assistant text, and applies the re-entry policy.
329
+ #>
179
330
  [CmdletBinding()]
180
331
  [OutputType([hashtable])]
181
- param(
182
- [string] $RawPayload
183
- )
184
-
185
- if ([string]::IsNullOrWhiteSpace($RawPayload)) {
186
- return @{ Ok = $false; Message = 'atomic-executor hook: CLAUDE_HOOK_INPUT is empty; cannot validate executor output.' }
187
- }
332
+ param([AllowNull()] [AllowEmptyString()] [string] $InputText)
188
333
 
189
- try {
190
- $payload = $RawPayload | ConvertFrom-Json -ErrorAction Stop
334
+ $envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
335
+ if (-not $envelope.IsValid) { $decision = @{ Ok = $false; Repairable = $false; Message = ('{0} payload anomaly - {1}' -f 'atomic-executor hook:', (Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)) } }
336
+ else {
337
+ $agentOutput = $envelope.AssistantText
338
+ $decision = Get-ExecutorOutputBlockDecision -AgentOutput ([string]$agentOutput) -TranscriptPath (Get-TranscriptPathFromEnvelope -Envelope $envelope.Envelope)
191
339
  }
192
- catch {
193
- return @{ Ok = $false; Message = "atomic-executor hook: failed to parse CLAUDE_HOOK_INPUT as JSON: $($_.Exception.Message)" }
340
+ if ($decision.Ok) { return @{ Ok = $true; Message = $null } }
341
+ if (-not $decision.Repairable) {
342
+ if ($envelope.StopHookActive) { return @{ Ok = $true; Message = $null } }
343
+ if (-not $decision.Message.Contains('to the operator and halt.')) { $decision.Message = $decision.Message + "`n" + $script:SubagentStopReportAndHaltLine }
194
344
  }
345
+ return @{ Ok = $false; Message = $decision.Message }
346
+ }
347
+
348
+ function Get-ExecutorOutputBlockDecision {
349
+ <#
350
+ .SYNOPSIS
351
+ Applies the executor completion checks to the assistant text and returns the block decision.
352
+ .DESCRIPTION
353
+ Returns @{ Ok = $true; Message = $null } to allow, or a hashtable with Ok = $false, a
354
+ Repairable boolean, and Message. Repairable is $false for a non-preflight BLOCKED claim
355
+ and for a plan with no task checkboxes; every other block is repairable by the subagent.
356
+ TranscriptPath and ReadTranscriptHead feed Test-IsPreflightRun. An execution run that
357
+ stops with the canonical preflight BLOCKED text, a plan delta, and no checked task is a
358
+ preflight block inside a combined proportionate run and is allowed.
359
+ #>
360
+ [CmdletBinding()]
361
+ [OutputType([hashtable])]
362
+ param(
363
+ [Parameter(Mandatory = $true)] [AllowEmptyString()] [string] $AgentOutput,
364
+ [AllowNull()] [AllowEmptyString()] [string] $TranscriptPath,
365
+ [scriptblock] $ReadTranscriptHead
366
+ )
195
367
 
196
- $agentOutput = $null
197
- if ($payload.PSObject.Properties.Name -contains 'output') {
198
- $agentOutput = $payload.output
199
- }
200
368
  if ([string]::IsNullOrWhiteSpace($agentOutput)) {
201
- return @{ Ok = $false; Message = 'atomic-executor hook: agent output is empty; executor must return plan-path and final completion summary.' }
369
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: agent output is empty (last_assistant_message carries no text); executor must return plan-path and final completion summary.' }
202
370
  }
203
371
 
204
372
  $planPath = Get-PlanPathFromOutput -AgentOutput $agentOutput
205
373
  if ($null -eq $planPath) {
206
- return @{ Ok = $false; Message = 'atomic-executor hook: agent output does not advertise a plan-path. Executor must report `plan-path: <path>` per atomic-plan-contract.' }
374
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: agent output does not advertise a plan-path. Executor must report `plan-path: <path>` per atomic-plan-contract.' }
207
375
  }
208
376
 
209
377
  $file = Get-PlanFileContent -Path $planPath
210
378
  if (-not $file.Exists) {
211
- return @{ Ok = $false; Message = "atomic-executor hook: executor advertised plan-path '$planPath' but no file exists at that location." }
379
+ return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: executor advertised plan-path '$planPath' but no file exists at that location." }
212
380
  }
213
381
 
214
- $isPreflight = Test-IsPreflightPlan -Lines $file.Lines
215
- if ($isPreflight) {
216
- if (-not (Test-HasCanonicalBlockedText -AgentOutput $agentOutput)) {
217
- return @{ Ok = $false; Message = 'atomic-executor hook: blocked preflight output must include the exact text `BLOCKED at preflight (before [P0-T1])` plus a concrete plan delta.' }
218
- }
219
- if ($agentOutput -notmatch 'BLOCKED' -and -not (Test-HasPreflightSignal -AgentOutput $agentOutput)) {
220
- return @{ Ok = $false; Message = 'atomic-executor hook: preflight output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
382
+ $runArguments = @{ AgentOutput = $agentOutput; PlanLines = [string[]]@($file.Lines); TranscriptPath = $TranscriptPath }
383
+ if ($null -ne $ReadTranscriptHead) { $runArguments['ReadTranscriptHead'] = $ReadTranscriptHead }
384
+ if (Test-IsPreflightRun @runArguments) {
385
+ if ($agentOutput -cnotmatch 'BLOCKED' -and -not (Test-HasPreflightSignal -AgentOutput $agentOutput)) {
386
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: preflight output must include `PREFLIGHT: ALL CLEAR` or `PREFLIGHT: REVISIONS REQUIRED`.' }
221
387
  }
222
- return @{ Ok = $true; Message = $null }
388
+ return Get-PreflightRunBlockDecision -AgentOutput $agentOutput
223
389
  }
224
390
 
225
- if ($agentOutput -match 'BLOCKED') {
226
- return @{ Ok = $false; Message = 'atomic-executor hook: blocking is permitted only during preflight validation (before [P0-T1]).' }
391
+ if ($agentOutput -cmatch 'BLOCKED') {
392
+ $hasCheckedTask = @($file.Lines | Where-Object { $_ -match '^\s*-\s\[[xX]\]\s\[P\d+-T\d+\]' }).Count -gt 0
393
+ if ($agentOutput -cmatch 'BLOCKED at preflight \(before \[P0-T1\]\)' -and (Test-HasCanonicalBlockedText -AgentOutput $agentOutput) -and -not $hasCheckedTask) {
394
+ return @{ Ok = $true; Message = $null }
395
+ }
396
+ return @{ Ok = $false; Repairable = $false; Message = 'atomic-executor hook: blocking is permitted only during preflight validation (before [P0-T1]).' }
227
397
  }
228
398
 
229
- $checkboxLineCount = 0
399
+ $checkboxLineCount = @($file.Lines | Where-Object { $_ -match '^\s*-\s\[(?:\s|[xX])\]\s' }).Count
230
400
  $uncheckedLineNumbers = [System.Collections.Generic.List[int]]::new()
231
- $uncheckedPattern = '^\s*-\s\[\s\]\s'
232
- $checkedPattern = '^\s*-\s\[[xX]\]\s'
233
-
234
401
  for ($i = 0; $i -lt $file.Lines.Count; $i++) {
235
- $line = $file.Lines[$i]
236
- if ($line -match $uncheckedPattern) {
237
- $checkboxLineCount++
402
+ if ($file.Lines[$i] -match '^\s*-\s\[\s\]\s') {
238
403
  $uncheckedLineNumbers.Add($i + 1)
239
404
  }
240
- elseif ($line -match $checkedPattern) {
241
- $checkboxLineCount++
242
- }
243
405
  }
244
406
 
245
407
  if ($checkboxLineCount -eq 0) {
246
- return @{ Ok = $false; Message = "atomic-executor hook: plan file '$planPath' contains no task checkboxes; executor cannot complete against an empty plan." }
408
+ return @{ Ok = $false; Repairable = $false; Message = "atomic-executor hook: plan file '$planPath' contains no task checkboxes; executor cannot complete against an empty plan." }
247
409
  }
248
410
 
249
411
  if ($uncheckedLineNumbers.Count -gt 0) {
@@ -253,31 +415,23 @@ function Invoke-ExecutorOutputValidation {
253
415
  $reported = $uncheckedLineNumbers.GetRange(0, 5)
254
416
  $suffix = ' (showing first 5)'
255
417
  }
256
- $lineList = ($reported -join ', ')
257
- $message = "atomic-executor hook: plan file '$planPath' has $($uncheckedLineNumbers.Count) unchecked task(s) at line(s) ${lineList}${suffix}. All `- [ ]` items must be ticked to `- [x]` before termination."
258
- return @{ Ok = $false; Message = $message }
418
+ $message = "atomic-executor hook: plan file '$planPath' has $($uncheckedLineNumbers.Count) unchecked task(s) at line(s) $($reported -join ', ')${suffix}. All `- [ ]` items must be ticked to `- [x]` before termination."
419
+ return @{ Ok = $false; Repairable = $true; Message = $message }
259
420
  }
260
421
 
261
422
  if ($agentOutput -notmatch '(?i)\bAC Status Summary\b') {
262
- return @{ Ok = $false; Message = 'atomic-executor hook: completion output must include an `AC Status Summary` section.' }
423
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: completion output must include an `AC Status Summary` section.' }
263
424
  }
264
425
 
265
- $hasCommandEvidence = $agentOutput -match '(?i)(Commands Run|Command[s]?:|poetry run |npx |pwsh |git |mcp__drm-copilot__)'
426
+ $hasCommandEvidence = $agentOutput -match '(?i)(Commands Run|Command[s]?:|poetry[ ]run |npx |pwsh |git |mcp__drm-copilot__)'
266
427
  $hasStatusEvidence = $agentOutput -match '(?i)\b(PASS|FAIL)\b'
267
428
  if (-not $hasCommandEvidence -or -not $hasStatusEvidence) {
268
- return @{ Ok = $false; Message = 'atomic-executor hook: completion output must report commands run and pass/fail status results.' }
269
- }
270
-
271
- $missingLanguageStatuses = [System.Collections.Generic.List[string]]::new()
272
- foreach ($language in Get-TouchedLanguagesFromPlan -Lines $file.Lines) {
273
- if (-not (Test-OutputHasLanguageStatus -AgentOutput $agentOutput -Language $language)) {
274
- $missingLanguageStatuses.Add($language)
275
- }
429
+ return @{ Ok = $false; Repairable = $true; Message = 'atomic-executor hook: completion output must report commands run and pass/fail status results.' }
276
430
  }
277
431
 
432
+ $missingLanguageStatuses = @(Get-TouchedLanguagesFromPlan -Lines $file.Lines | Where-Object { -not (Test-OutputHasLanguageStatus -AgentOutput $agentOutput -Language $_) })
278
433
  if ($missingLanguageStatuses.Count -gt 0) {
279
- $missingList = $missingLanguageStatuses -join ', '
280
- return @{ Ok = $false; Message = "atomic-executor hook: completion output is missing explicit PASS/FAIL toolchain status lines for: $missingList." }
434
+ return @{ Ok = $false; Repairable = $true; Message = "atomic-executor hook: completion output is missing explicit PASS/FAIL toolchain status lines for: $($missingLanguageStatuses -join ', ')." }
281
435
  }
282
436
 
283
437
  return @{ Ok = $true; Message = $null }
@@ -287,10 +441,10 @@ if ($MyInvocation.InvocationName -eq '.') {
287
441
  return
288
442
  }
289
443
 
290
- $result = Invoke-ExecutorOutputValidation -RawPayload $env:CLAUDE_HOOK_INPUT
291
- if (-not $result.Ok) {
292
- Write-Error $result.Message
293
- exit 1
294
- }
295
-
444
+ if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('validate-executor-output: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
445
+ $dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'validate-executor-output:'
446
+ if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
447
+ try { $result = Invoke-ExecutorOutputValidation }
448
+ catch { Exit-SubagentStopBlock -Message ('validate-executor-output: validator error: ' + ([string]$_.Exception.Message -split "`r?`n")[0] + '; the gate fails closed.' + "`n" + $script:SubagentStopReportAndHaltLine) }
449
+ if (-not $result.Ok) { Exit-SubagentStopBlock -Message $result.Message }
296
450
  exit 0