@danmoisan/drm-copilot-mcp 1.1.22 → 1.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/out/mcp-server.js +18758 -12030
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
  5. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
  6. package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -0
  7. package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
  8. package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +101 -43
  9. package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +107 -43
  10. package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
  11. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +60 -6
  12. package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
  13. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  14. package/resources/claude-customizations/.claude/agents/pr-author.md +48 -7
  15. package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +117 -42
  17. package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +103 -43
  18. package/resources/claude-customizations/.claude/hooks/discovery-capability-probe.ps1 +102 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +69 -194
  20. package/resources/claude-customizations/.claude/hooks/enforce-discovery-planning-gate.ps1 +87 -0
  21. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
  22. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +29 -7
  23. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
  24. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
  25. package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
  26. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +51 -0
  27. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +168 -48
  28. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +1 -1
  29. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
  30. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +59 -20
  31. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +51 -4
  32. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +72 -11
  33. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
  34. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +4 -2
  35. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +59 -20
  36. package/resources/claude-customizations/.claude/hooks/record-discovery-agent-start.ps1 +132 -0
  37. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +56 -212
  38. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
  39. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-rejection.ps1 +172 -0
  40. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +34 -4
  41. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +9 -3
  42. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusAggregate.psm1 +154 -0
  43. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusCombination.psm1 +228 -0
  44. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +1 -0
  45. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +4 -2
  46. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +63 -16
  47. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +56 -1
  48. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +4 -1
  49. package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
  50. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +5 -1
  51. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
  52. package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +25 -2
  53. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
  54. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
  55. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
  56. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
  57. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
  58. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
  59. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
  60. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
  61. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
  62. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
  63. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
  64. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
  65. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
  66. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
  67. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +188 -341
  68. package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
  69. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
  70. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
  71. package/resources/claude-customizations/.claude/lib/worktree-resolution/HookTargetWorktree.psm1 +391 -0
  72. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
  73. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
  74. package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
  75. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +29 -5
  76. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +152 -20
  77. package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
  78. package/resources/claude-customizations/.claude/rules/shell.md +1 -1
  79. package/resources/claude-customizations/.claude/settings.json +36 -3
  80. package/resources/claude-customizations/.claude/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  81. package/resources/claude-customizations/.claude/skills/characterize-runtime-behavior/SKILL.md +134 -0
  82. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
  83. package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +28 -47
  84. package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +32 -48
  85. package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +28 -45
  86. package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +28 -62
  87. package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +28 -45
  88. package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +28 -61
  89. package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +55 -139
  90. package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +25 -10
  91. package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -0
  92. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
  93. package/resources/claude-customizations/.claude/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  94. package/resources/claude-customizations/.claude/skills/initialize-discovery-workspace/SKILL.md +131 -0
  95. package/resources/claude-customizations/.claude/skills/inventory-legacy-system/SKILL.md +131 -0
  96. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +15 -7
  97. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +25 -2
  98. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
  99. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +124 -14
  100. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +72 -7
  101. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +15 -0
  102. package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +6 -0
  103. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +56 -9
  104. package/resources/claude-customizations/.claude/skills/reconcile-parity-matrix/SKILL.md +131 -0
  105. package/resources/claude-customizations/.claude/skills/review-discovery-coverage/SKILL.md +129 -0
  106. package/resources/claude-customizations/.claude/skills/validate-discovery-artifacts/SKILL.md +127 -0
  107. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
  108. package/resources/claude-customizations/config/blast-radius.json +6 -5
  109. package/resources/claude-customizations/config/orchestration-routing.json +61 -1
  110. package/resources/claude-customizations/pack-manifests/core.json +40 -1
  111. package/resources/codex-and-agents-customizations/.agents/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  112. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +7 -0
  113. package/resources/codex-and-agents-customizations/.agents/skills/characterize-runtime-behavior/SKILL.md +134 -0
  114. package/resources/codex-and-agents-customizations/.agents/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
  115. package/resources/codex-and-agents-customizations/.agents/skills/discovery-coverage-ledger/SKILL.md +50 -0
  116. package/resources/codex-and-agents-customizations/.agents/skills/discovery-parity-matrix/SKILL.md +46 -0
  117. package/resources/codex-and-agents-customizations/.agents/skills/discovery-repo-inventory/SKILL.md +46 -0
  118. package/resources/codex-and-agents-customizations/.agents/skills/discovery-runtime-characterization/SKILL.md +46 -0
  119. package/resources/codex-and-agents-customizations/.agents/skills/discovery-validate-artifacts/SKILL.md +46 -0
  120. package/resources/codex-and-agents-customizations/.agents/skills/discovery-workflow/SKILL.md +62 -0
  121. package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +25 -10
  122. package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
  123. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  124. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
  125. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
  126. package/resources/codex-and-agents-customizations/.agents/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  127. package/resources/codex-and-agents-customizations/.agents/skills/initialize-discovery-workspace/SKILL.md +131 -0
  128. package/resources/codex-and-agents-customizations/.agents/skills/inventory-legacy-system/SKILL.md +131 -0
  129. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +8 -0
  130. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
  131. package/resources/codex-and-agents-customizations/.agents/skills/reconcile-parity-matrix/SKILL.md +131 -0
  132. package/resources/codex-and-agents-customizations/.agents/skills/review-discovery-coverage/SKILL.md +129 -0
  133. package/resources/codex-and-agents-customizations/.agents/skills/validate-discovery-artifacts/SKILL.md +127 -0
  134. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
  135. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
  136. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
  137. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
  138. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
  139. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
  140. package/resources/codex-and-agents-customizations/.codex/agents/discovery-capability-sentinel.toml +51 -0
  141. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
  142. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c1.toml +148 -0
  143. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c2.toml +148 -0
  144. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3-elevated.toml +148 -0
  145. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3.toml +148 -0
  146. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c4.toml +148 -0
  147. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst.toml +148 -0
  148. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c1.toml +154 -0
  149. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c2.toml +154 -0
  150. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3-elevated.toml +154 -0
  151. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3.toml +154 -0
  152. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c4.toml +154 -0
  153. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer.toml +154 -0
  154. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
  155. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
  156. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
  157. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
  158. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
  159. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  160. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
  161. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
  162. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
  163. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
  164. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
  165. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
  166. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c1.toml +164 -0
  167. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c2.toml +164 -0
  168. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3-elevated.toml +164 -0
  169. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3.toml +164 -0
  170. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c4.toml +164 -0
  171. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler.toml +164 -0
  172. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c1.toml +150 -0
  173. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c2.toml +150 -0
  174. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3-elevated.toml +150 -0
  175. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3.toml +150 -0
  176. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c4.toml +150 -0
  177. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst.toml +150 -0
  178. package/resources/codex-and-agents-customizations/.codex/config.toml +39 -3
  179. package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +22 -0
  180. package/resources/codex-and-agents-customizations/.codex/hooks/discovery-capability-probe.ps1 +97 -0
  181. package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1 +171 -0
  182. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +4 -1
  183. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1 +187 -0
  184. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1 +149 -0
  185. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
  186. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +239 -2
  187. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -15
  188. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +54 -15
  189. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +54 -15
  190. package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
  191. package/resources/codex-and-agents-customizations/.codex/hooks/hook-target-worktree.ps1 +369 -0
  192. package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +8 -0
  193. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +22 -1
  194. package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1 +178 -0
  195. package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +11 -1
  196. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
  197. package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
  198. package/resources/codex-and-agents-customizations/pack-manifests/core.json +65 -1
  199. package/resources/config/orchestration-routing.json +61 -1
  200. package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
  201. package/resources/customizations/.github/agents/discovery-capability-sentinel.agent.md +34 -0
  202. package/resources/customizations/.github/agents/legacy-parity-analyst.agent.md +122 -0
  203. package/resources/customizations/.github/agents/migration-coverage-reviewer.agent.md +128 -0
  204. package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
  205. package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
  206. package/resources/customizations/.github/agents/requirements-reconciler.agent.md +138 -0
  207. package/resources/customizations/.github/agents/runtime-characterization-analyst.agent.md +124 -0
  208. package/resources/customizations/.github/hooks/discovery-agent-start.ps1 +139 -0
  209. package/resources/customizations/.github/hooks/discovery-agent-stop.ps1 +123 -0
  210. package/resources/customizations/.github/hooks/discovery-capability-probe.ps1 +98 -0
  211. package/resources/customizations/.github/hooks/discovery-planning.ps1 +91 -0
  212. package/resources/customizations/.github/hooks/discovery-pre-tool.ps1 +123 -0
  213. package/resources/customizations/.github/hooks/discovery.json +35 -0
  214. package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
  215. package/resources/customizations/.github/instructions/mermaid.instructions.md +85 -0
  216. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
  217. package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
  218. package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
  219. package/resources/customizations/.github/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  220. package/resources/customizations/.github/skills/characterize-runtime-behavior/SKILL.md +134 -0
  221. package/resources/customizations/.github/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
  222. package/resources/customizations/.github/skills/discovery-coverage-ledger/SKILL.md +50 -0
  223. package/resources/customizations/.github/skills/discovery-parity-matrix/SKILL.md +46 -0
  224. package/resources/customizations/.github/skills/discovery-repo-inventory/SKILL.md +46 -0
  225. package/resources/customizations/.github/skills/discovery-runtime-characterization/SKILL.md +46 -0
  226. package/resources/customizations/.github/skills/discovery-validate-artifacts/SKILL.md +46 -0
  227. package/resources/customizations/.github/skills/discovery-workflow/SKILL.md +62 -0
  228. package/resources/customizations/.github/skills/execution-environment/SKILL.md +25 -10
  229. package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -0
  230. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
  231. package/resources/customizations/.github/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  232. package/resources/customizations/.github/skills/initialize-discovery-workspace/SKILL.md +131 -0
  233. package/resources/customizations/.github/skills/inventory-legacy-system/SKILL.md +131 -0
  234. package/resources/customizations/.github/skills/reconcile-parity-matrix/SKILL.md +131 -0
  235. package/resources/customizations/.github/skills/review-discovery-coverage/SKILL.md +129 -0
  236. package/resources/customizations/.github/skills/validate-discovery-artifacts/SKILL.md +127 -0
  237. package/resources/lib/codex-routing/CodexDeployment.psm1 +5 -1
  238. package/resources/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
  239. package/resources/lib/codex-routing/CodexTopology.psm1 +25 -2
  240. package/resources/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
  241. package/resources/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
  242. package/resources/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
  243. package/resources/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
  244. package/resources/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
  245. package/resources/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
  246. package/resources/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
  247. package/resources/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
  248. package/resources/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
  249. package/resources/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
  250. package/resources/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
  251. package/resources/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
  252. package/resources/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
  253. package/resources/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
  254. package/resources/powershell/PoshQC/PoshQC.Parallel.psm1 +452 -0
  255. package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +106 -8
  256. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -0
  257. package/resources/powershell/PoshQC/PoshQC.psd1 +6 -1
  258. package/resources/powershell/PoshQC/PoshQC.psm1 +7 -1
  259. package/resources/powershell/PoshQC/README.md +20 -1
  260. package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
  261. package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
@@ -46,6 +46,8 @@ try { Import-Module (Join-Path $PSScriptRoot '../lib/cleanup-manifest/CleanupWor
46
46
  try { . (Join-Path $PSScriptRoot 'hook-command-scanner.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-scanner.ps1' -ErrorRecord $_ }
47
47
  try { . (Join-Path $PSScriptRoot 'hook-command-invocation.ps1') } catch { Add-HookDependencyFailure -Name 'hook-command-invocation.ps1' -ErrorRecord $_ }
48
48
 
49
+ # Shared recorded-path matcher and main-checkout-root seam (issue #995).
50
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunRecordPath.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeRunRecordPath.psm1' -ErrorRecord $_ }
49
51
  try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeRunResolution.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'WorktreeRunResolution.psm1' -ErrorRecord $_ }
50
52
 
51
53
  $script:AllowedMergeStatuses = @('merged', 'worktree_removed')
@@ -170,7 +172,10 @@ function Find-ParallelWorktreeItemRecord {
170
172
  Name of the record array to scan. Defaults to 'items', the parallel
171
173
  checkpoint's array, so every existing caller is unchanged; the epic branch
172
174
  added for issue #688 passes 'features'. Parameterized rather than duplicated
173
- so both topologies share one path-normalization implementation.
175
+ so both topologies share one path-comparison implementation.
176
+ .PARAMETER BaseRoot
177
+ Optional. The roots a relative recorded worktree_path is joined to (issue #995).
178
+ With none, a relative record matches nothing.
174
179
  .OUTPUTS
175
180
  System.Object or $null
176
181
  #>
@@ -183,7 +188,11 @@ function Find-ParallelWorktreeItemRecord {
183
188
  [string] $WorktreePath,
184
189
 
185
190
  [ValidateNotNullOrEmpty()]
186
- [string] $RecordArrayName = 'items'
191
+ [string] $RecordArrayName = 'items',
192
+
193
+ [AllowNull()]
194
+ [AllowEmptyCollection()]
195
+ [string[]] $BaseRoot = @()
187
196
  )
188
197
 
189
198
  if ($null -eq $Checkpoint -or [string]::IsNullOrWhiteSpace($WorktreePath)) {
@@ -194,17 +203,14 @@ function Find-ParallelWorktreeItemRecord {
194
203
  return $null
195
204
  }
196
205
 
197
- $normalizedTarget = ($WorktreePath -replace '\\', '/').TrimEnd('/')
198
-
199
- # Scan every recorded item for a worktree_path that matches the removal target;
200
- # path separators are normalized so Windows- and POSIX-style paths compare equal.
206
+ # Scan every recorded item for a worktree_path that names the removal target through
207
+ # the shared matcher (separator style, trailing slash, case rule, relative join).
201
208
  foreach ($item in @($Checkpoint.$RecordArrayName)) {
202
209
  $itemProps = @($item.PSObject.Properties.Name)
203
210
  if ($itemProps -notcontains 'worktree_path') {
204
211
  continue
205
212
  }
206
- $normalizedItemPath = (([string]$item.worktree_path) -replace '\\', '/').TrimEnd('/')
207
- if ($normalizedItemPath -eq $normalizedTarget) {
213
+ if (Test-WorktreeRunRecordedPathMatchesTarget -RecordedPath ([string]$item.worktree_path) -TargetPath $WorktreePath -BaseRoot $BaseRoot) {
208
214
  return $item
209
215
  }
210
216
  }
@@ -353,8 +359,13 @@ function Get-ParallelWorktreeRemovalTargetDenial {
353
359
  }
354
360
  }
355
361
  $checkpoint = $parallelRead.Checkpoint
362
+ # A relative record is joined to the main checkout root and to the root holding the
363
+ # checkpoint read (issue #995); the main root is derived once per target.
364
+ $mainRoot = Get-WorktreeRunMainCheckoutRoot -SessionRoot (Get-Location).Path
365
+ $parallelBaseRoot = Get-WorktreeRunRecordBaseRoot -MainRoot $mainRoot -Read $parallelRead
366
+ $epicBaseRoot = Get-WorktreeRunRecordBaseRoot -MainRoot $mainRoot -Read $epicRead
356
367
 
357
- $itemRecord = Find-ParallelWorktreeItemRecord -Checkpoint $checkpoint -WorktreePath $worktreePath
368
+ $itemRecord = Find-ParallelWorktreeItemRecord -Checkpoint $checkpoint -WorktreePath $worktreePath -BaseRoot $parallelBaseRoot
358
369
  if (Test-ParallelWorktreeRemovalAllowed -ItemRecord $itemRecord) {
359
370
  return $null
360
371
  }
@@ -371,7 +382,7 @@ function Get-ParallelWorktreeRemovalTargetDenial {
371
382
  # $null, which yields no record, which is not allowed.
372
383
  $epicCheckpoint = $epicRead.Checkpoint
373
384
 
374
- $featureRecord = Find-ParallelWorktreeItemRecord -Checkpoint $epicCheckpoint -WorktreePath $worktreePath -RecordArrayName 'features'
385
+ $featureRecord = Find-ParallelWorktreeItemRecord -Checkpoint $epicCheckpoint -WorktreePath $worktreePath -RecordArrayName 'features' -BaseRoot $epicBaseRoot
375
386
  if (Test-ParallelWorktreeRemovalAllowed -ItemRecord $featureRecord) {
376
387
  return $null
377
388
  }
@@ -386,7 +397,7 @@ function Get-ParallelWorktreeRemovalTargetDenial {
386
397
  # reaches the unchanged deny below. This gate defines only the parallel checkpoint
387
398
  # seam and has no epic-checkpoint seam, so its exclusion covers the items array
388
399
  # only; the epic gate covers the features array with its own exclusion.
389
- if (-not (Test-CleanupManifestCheckpointCoversPath -Checkpoint $checkpoint -RecordArrayName 'items' -WorktreePath $worktreePath) -and
400
+ if (-not (Test-CleanupManifestCheckpointCoversPath -Checkpoint $checkpoint -RecordArrayName 'items' -WorktreePath $worktreePath -BaseRoot $parallelBaseRoot) -and
390
401
  (Test-CleanupWorktreeManifestAuthorizesRemoval -WorktreePath $worktreePath)) {
391
402
  return $null
392
403
  }
@@ -7,14 +7,28 @@
7
7
  operation. When the target file is a PowerShell source file (.ps1, .psm1, .psd1),
8
8
  it decides whether the change may proceed in direct mode.
9
9
 
10
- Direct mode counts distinct production PowerShell paths per Claude Code session.
11
- The running set is persisted under .claude/state/powershell-batch-budget.<session_id>.json,
12
- and repeated edits to the same file are counted once. The 4th distinct production
13
- path is denied with a POWERSHELL_LARGE_PATH_REQUIRED reason that instructs the
14
- caller to route the change through /orchestrate.
15
-
16
- The orchestrated large path is detected from
17
- <root>/artifacts/orchestration/orchestrator-state.json. The selected route is the
10
+ Direct mode counts distinct production PowerShell paths per Claude Code session and
11
+ per resolved target worktree, and repeated edits to the same file are counted once.
12
+ The 4th distinct production path in one worktree is denied with a
13
+ POWERSHELL_LARGE_PATH_REQUIRED reason that instructs the caller to route the change
14
+ through /orchestrate.
15
+
16
+ The edited file is placed with Resolve-HookTargetWorktree from
17
+ .claude/lib/worktree-resolution/HookTargetWorktree.psm1. An absolute path resolves to
18
+ its nearest enclosing registered git worktree; a relative path, a path inside no
19
+ registered worktree, and an ambiguous result use the session root (the checkout that
20
+ holds this hook). The route is read from
21
+ artifacts/orchestration/orchestrator-state.json in the resolved target worktree.
22
+ The running set is kept under the session root, in
23
+ .claude/state/powershell-batch-budget.<session_id>.json when the resolved target worktree
24
+ is the session root and in
25
+ .claude/state/powershell-batch-budget.<session_id>.<worktree key>.json otherwise,
26
+ where the key comes from Get-HookTargetWorktreeKey; no state is written under another
27
+ worktree. A path under the root-level artifacts/ directory of the resolved target worktree
28
+ is gitignored scratch: it is allowed, consumes no slot, and writes no state. A
29
+ nested directory named artifacts elsewhere in the tree still counts.
30
+
31
+ The selected route is the
18
32
  route_id value when that key is present, otherwise the path_selected value, and it
19
33
  is usable only as a non-blank string. When the selected route is large,
20
34
  remediation, or preparation and the checkpoint is not terminal (next_step is not
@@ -38,9 +52,9 @@
38
52
  is composed into a file name, so a hostile id cannot escape the state
39
53
  directory. Resolving the id never creates the state directory.
40
54
 
41
- Candidate paths are contained to the resolved root. A candidate that resolves
42
- outside it is discarded: the decision is 'allow', no slot is consumed, and no
43
- state is written. Persisted entries that fail the same containment test are
55
+ Candidate paths are contained to the resolved target worktree root. A candidate
56
+ that resolves outside it is discarded: the decision is 'allow', no slot is consumed,
57
+ and no state is written. Persisted entries that fail the same containment test are
44
58
  dropped when state is rehydrated, so a state file carried between worktrees
45
59
  cannot spend this worktree's budget.
46
60
 
@@ -48,9 +62,12 @@
48
62
  hookSpecificOutput.permissionDecision = 'deny' and exits 0. Files already counted
49
63
  are always allowed through.
50
64
 
51
- Known limitation: a stale non-terminal large-path checkpoint left at the root
52
- exempts a later direct-mode session at that root. Orchestrator checkpoint hygiene
53
- (issue #673) moves foreign checkpoints aside before a new run.
65
+ Known limitations: an 8.3 short-name path, or a path reached through a junction,
66
+ that differs textually from the long path git reports matches no registered
67
+ worktree and falls back to the session root. A stale non-terminal large-path
68
+ checkpoint in a worktree exempts a later direct-mode session editing that worktree;
69
+ orchestrator checkpoint hygiene (issue #673) moves foreign checkpoints aside before
70
+ a new run.
54
71
 
55
72
  .NOTES
56
73
  Compatible with PowerShell 7+.
@@ -61,6 +78,7 @@ $script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot
61
78
 
62
79
 
63
80
  try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
81
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/HookTargetWorktree.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookTargetWorktree.psm1' -ErrorRecord $_ }
64
82
  $script:PowerShellBatchBudgetRouteImportFailure = $null; try { . (Join-Path $PSScriptRoot 'enforce-batch-budget-route.ps1') } catch { $script:PowerShellBatchBudgetRouteImportFailure = 'enforce-batch-budget-route.ps1' }
65
83
 
66
84
  function Test-PowerShellBatchBudgetPathInRoot {
@@ -351,7 +369,8 @@ function Invoke-PowerShellBatchBudgetHook {
351
369
  [scriptblock] $WriteState = {
352
370
  param([string] $Path, [System.Collections.IDictionary] $State)
353
371
  $State | ConvertTo-Json -Depth 5 | Set-Content -Path $Path -Encoding UTF8
354
- }
372
+ },
373
+ [scriptblock] $WorktreeListInvoker
355
374
  )
356
375
 
357
376
  $payload = Resolve-ClaudeHookToolInput -Raw $ToolInputRaw
@@ -373,6 +392,25 @@ function Invoke-PowerShellBatchBudgetHook {
373
392
  }
374
393
  if ($script:PowerShellBatchBudgetRouteImportFailure) { return Get-PowerShellBatchBudgetBlockDecision -Reason "POWERSHELL_LARGE_PATH_REQUIRED: the route helper '$($script:PowerShellBatchBudgetRouteImportFailure)' failed to load, so the batch budget for '$normalized' cannot be evaluated; the gate fails closed." }
375
394
 
395
+ # The file is evaluated against the registered worktree that holds it. The session root
396
+ # stays the fallback for a relative path, a path in no registered worktree, and an
397
+ # ambiguous result, which keeps today's checkpoint, containment, and state-file name.
398
+ $resolverArguments = @{ SessionRoot = $Root; FilePath = @($filePath) }
399
+ if ($PSBoundParameters.ContainsKey('WorktreeListInvoker')) { $resolverArguments['WorktreeListInvoker'] = $WorktreeListInvoker }
400
+ $resolution = Resolve-HookTargetWorktree @resolverArguments
401
+ $targetRoot = $Root
402
+ $isSessionRoot = $true
403
+ if (-not $resolution.Ambiguous -and $null -ne $resolution.WorktreeRoot -and -not [string]::Equals($resolution.WorktreeRoot, (ConvertTo-HookTargetWorktreeNormalizedPath -Path $Root), [System.StringComparison]::OrdinalIgnoreCase)) {
404
+ $targetRoot = $resolution.WorktreeRoot
405
+ $isSessionRoot = $false
406
+ }
407
+
408
+ # The root-level artifacts/ directory is gitignored scratch, never a production file.
409
+ $relativePath = if ($normalized -match '^(/|[A-Za-z]:/)') { Get-HookTargetWorktreeRelativePath -Path $normalized -WorktreeRoot $targetRoot } else { $normalized }
410
+ if ($null -ne $relativePath -and $relativePath.StartsWith('artifacts/', [System.StringComparison]::OrdinalIgnoreCase)) {
411
+ return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
412
+ }
413
+
376
414
  $stateDir = Join-Path -Path $Root -ChildPath '.claude/state'
377
415
 
378
416
  # Resolved before the directory is ensured, because reading the session-id
@@ -383,11 +421,12 @@ function Invoke-PowerShellBatchBudgetHook {
383
421
  -SessionIdFilePath (Join-Path -Path $stateDir -ChildPath 'current-session-id') `
384
422
  -ReadSessionIdFile $ReadSessionIdFile
385
423
 
386
- $stateFile = Join-Path -Path $stateDir -ChildPath ("powershell-batch-budget.$resolvedSessionId.json")
424
+ $stateLeaf = if ($isSessionRoot) { "powershell-batch-budget.$resolvedSessionId.json" } else { "powershell-batch-budget.$resolvedSessionId.$(Get-HookTargetWorktreeKey -WorktreeRoot $targetRoot).json" }
425
+ $stateFile = Join-Path -Path $stateDir -ChildPath $stateLeaf
387
426
 
388
427
  # The checkpoint is read before any state operation, so the large path neither
389
428
  # creates the state directory nor reads or writes the state file.
390
- $checkpointPath = Join-Path -Path $Root -ChildPath 'artifacts/orchestration/orchestrator-state.json'
429
+ $checkpointPath = Join-Path -Path $targetRoot -ChildPath 'artifacts/orchestration/orchestrator-state.json'
391
430
  $checkpointText = ''
392
431
  try {
393
432
  $checkpointText = [string](& $ReadCheckpoint $checkpointPath)
@@ -399,7 +438,7 @@ function Invoke-PowerShellBatchBudgetHook {
399
438
  $isLargePath = Test-BatchBudgetLargePathRoute -CheckpointText $checkpointText
400
439
  $observedRoute = Get-BatchBudgetSelectedRoute -CheckpointText $checkpointText
401
440
  if ($isLargePath) {
402
- return Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State (Get-PowerShellBatchBudgetState -ProdCap $ProdCap) -StateFile $stateFile -Root $Root -LargePathRoute
441
+ return Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State (Get-PowerShellBatchBudgetState -ProdCap $ProdCap) -StateFile $stateFile -Root $targetRoot -LargePathRoute
403
442
  }
404
443
 
405
444
  if (-not (& $TestPathExists $stateDir)) {
@@ -411,13 +450,13 @@ function Invoke-PowerShellBatchBudgetHook {
411
450
  if (& $TestPathExists $stateFile) {
412
451
  try {
413
452
  $loaded = & $ReadState $stateFile | ConvertFrom-Json -ErrorAction Stop
414
- $state = ConvertTo-PowerShellBatchBudgetState -InputObject $loaded -ProdCap $ProdCap -Root $Root
453
+ $state = ConvertTo-PowerShellBatchBudgetState -InputObject $loaded -ProdCap $ProdCap -Root $targetRoot
415
454
  } catch {
416
455
  Write-Verbose "Ignoring unreadable PowerShell batch-budget state file '$stateFile': $($_.Exception.Message)"
417
456
  }
418
457
  }
419
458
 
420
- $decision = Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State $state -StateFile $stateFile -Root $Root -ObservedRoute $observedRoute
459
+ $decision = Invoke-PowerShellBatchBudgetDecision -FilePath $filePath -State $state -StateFile $stateFile -Root $targetRoot -ObservedRoute $observedRoute
421
460
  if ($decision.shouldWriteState) {
422
461
  try {
423
462
  & $WriteState $stateFile $decision.state
@@ -10,8 +10,12 @@
10
10
  in one of these forms, matched by token position:
11
11
 
12
12
  - git log ... and git rev-parse ... (no git global option)
13
+ - git worktree list --porcelain (exactly these four tokens, issue #1011)
13
14
  - gh pr create ... and gh pr edit ... (no gh global option)
15
+ - gh pr view <N> --json closingIssuesReferences,body (exactly these six tokens, issue #989)
14
16
  - sha256sum artifacts/pr_body_<N>.md (only as the whole command)
17
+ - sha256sum <item worktree>/artifacts/pr_body_<N>.md (only as the whole command; an absolute
18
+ forward-slash path, issue #1011)
15
19
  - date -u [+<format>] (only as the whole command)
16
20
 
17
21
  Segments may be joined only by ';', '&&', '||', '|', or a newline. A record that is
@@ -41,7 +45,38 @@ $script:PrAuthorAllowlistWrapperWords = @(
41
45
  'sh', 'bash', 'zsh', 'dash', 'ksh', 'pwsh', 'powershell', 'eval', 'xargs',
42
46
  'env', 'timeout', 'time', 'command', 'nohup'
43
47
  )
44
- $script:PrAuthorAllowlistFormText = 'git log, git rev-parse, gh pr create, gh pr edit, sha256sum artifacts/pr_body_<N>.md, date -u [+<format>]'
48
+ $script:PrAuthorAllowlistFormText = 'git log, git rev-parse, git worktree list --porcelain, gh pr create, gh pr edit, gh pr view <N> --json closingIssuesReferences,body, sha256sum artifacts/pr_body_<N>.md, sha256sum <item worktree>/artifacts/pr_body_<N>.md, date -u [+<format>]'
49
+
50
+ function Test-PrAuthorAbsoluteBodyPathToken {
51
+ <#
52
+ .SYNOPSIS
53
+ Report whether a token is an absolute canonical body path beneath an item worktree (issue #1011).
54
+ .DESCRIPTION
55
+ The token must be rooted at '/' or at a drive letter followed by ':/', use forward slashes
56
+ only, hold at least one segment before 'artifacts', hold no empty, '.', or '..' segment,
57
+ and end in '/artifacts/pr_body_<digits>.md' with the exact case of the relative form.
58
+ Pure string logic: no process, file read, or module import.
59
+ .PARAMETER Value
60
+ The sha256sum argument token, quotes already stripped.
61
+ .OUTPUTS
62
+ System.Boolean
63
+ #>
64
+ [CmdletBinding()]
65
+ [OutputType([bool])]
66
+ param(
67
+ [Parameter(Mandatory)][AllowEmptyString()][string] $Value
68
+ )
69
+
70
+ if ($Value.Contains('\') -or $Value -cnotmatch '^(/|[A-Za-z]:/)(?<rest>.+)/artifacts/pr_body_\d+\.md$') {
71
+ return $false
72
+ }
73
+ foreach ($segment in $Matches['rest'].Split('/')) {
74
+ if ($segment -eq '' -or $segment -eq '.' -or $segment -eq '..') {
75
+ return $false
76
+ }
77
+ }
78
+ return $true
79
+ }
45
80
 
46
81
  function Test-PrAuthorAllowlistForm {
47
82
  <#
@@ -66,13 +101,25 @@ function Test-PrAuthorAllowlistForm {
66
101
  }
67
102
  switch -CaseSensitive ($Token[0]) {
68
103
  'git' {
69
- return ($Token.Count -ge 2 -and @('log', 'rev-parse') -ccontains $Token[1])
104
+ if ($Token.Count -ge 2 -and @('log', 'rev-parse') -ccontains $Token[1]) {
105
+ return $true
106
+ }
107
+ # The read-only worktree discovery form, matched exactly (issue #1011).
108
+ return ($Token.Count -eq 4 -and $Token[1] -ceq 'worktree' -and $Token[2] -ceq 'list' -and $Token[3] -ceq '--porcelain')
70
109
  }
71
110
  'gh' {
72
- return ($Token.Count -ge 3 -and $Token[1] -ceq 'pr' -and @('create', 'edit') -ccontains $Token[2])
111
+ if ($Token.Count -ge 3 -and $Token[1] -ceq 'pr' -and @('create', 'edit') -ccontains $Token[2]) {
112
+ return $true
113
+ }
114
+ # The read-only closing-reference verification form, matched exactly (issue #989).
115
+ return ($Token.Count -eq 6 -and $Token[1] -ceq 'pr' -and $Token[2] -ceq 'view' -and $Token[3] -cmatch '^\d+$' -and
116
+ $Token[4] -ceq '--json' -and $Token[5] -ceq 'closingIssuesReferences,body')
73
117
  }
74
118
  'sha256sum' {
75
- return ($IsWholeCommand -and $Token.Count -eq 2 -and $Token[1] -cmatch '^artifacts/pr_body_\d+\.md$')
119
+ if (-not $IsWholeCommand -or $Token.Count -ne 2) {
120
+ return $false
121
+ }
122
+ return ($Token[1] -cmatch '^artifacts/pr_body_\d+\.md$' -or (Test-PrAuthorAbsoluteBodyPathToken -Value $Token[1]))
76
123
  }
77
124
  'date' {
78
125
  if (-not $IsWholeCommand -or $Token.Count -lt 2 -or $Token[1] -cne '-u') {
@@ -27,9 +27,10 @@
27
27
 
28
28
  .NOTES
29
29
  Compatible with PowerShell 7+. Dependencies are in-repository only: the command parsers
30
- and worktree-resolution modules loaded below, and the artifact-root and docs-only siblings.
31
- No PowerShell Gallery module is required.
32
- The docs-only sibling runs the git executable at call time (issue #901).
30
+ and worktree-resolution modules loaded below, and the artifact-root, docs-only, and
31
+ current-branch siblings. No PowerShell Gallery module is required.
32
+ The docs-only sibling runs the git executable at call time (issue #901), and so does the
33
+ current-branch sibling when a call carries no target signal (issue #989).
33
34
  #>
34
35
  [CmdletBinding()]
35
36
  param()
@@ -49,6 +50,8 @@ Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeTarge
49
50
  # feature folder exists in every checkout branched from main, so it places a call in many at
50
51
  # once. The item is identified by its canonical issue number and its branch instead.
51
52
  Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/WorktreeItemResolution.psm1') -Force -ErrorAction Stop
53
+ # Shared target-worktree resolver (issues #1009, #1011): resolves the branch a --head names.
54
+ Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/HookTargetWorktree.psm1') -Force -ErrorAction Stop
52
55
  # Epic scope (issue #663): the epic integration pull request is gated against the epic checkpoint.
53
56
  Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/EpicScopeResolution.psm1') -Force -ErrorAction Stop
54
57
  Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/EpicScopeReadiness.psm1') -Force -ErrorAction Stop
@@ -56,6 +59,8 @@ Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/EpicScopeRead
56
59
  . (Join-Path $PSScriptRoot 'enforce-pr-author-skill.artifact-root.ps1')
57
60
  # Docs-only exemption from the orchestrator-state preflight (issue #901).
58
61
  . (Join-Path $PSScriptRoot 'enforce-pr-author-skill.docs-only.ps1')
62
+ # Current-branch target derivation and the no-target guidance text (issue #989).
63
+ . (Join-Path $PSScriptRoot 'enforce-pr-author-skill.current-branch.ps1')
59
64
 
60
65
  function Resolve-PrAuthorWorktreeTarget {
61
66
  <#
@@ -67,9 +72,15 @@ function Resolve-PrAuthorWorktreeTarget {
67
72
  directly would depend on the machine's live worktrees and would pass or fail
68
73
  according to what other sessions happen to have checked out, which the repository's
69
74
  determinism policy forbids. Mocking here lets a test state the resolution outcome it
70
- is exercising and nothing else.
75
+ is exercising and nothing else. A branch the command names (--head, --branch, or
76
+ branch:) is resolved by the shared resolver Resolve-HookTargetWorktree, given only the
77
+ session root and that branch (issue #1011), unless the command also carries a canonical
78
+ issue number line, which Resolve-WorktreeItemTarget decides so the branch/issue agreement
79
+ check applies. Without a selection, Resolve-WorktreeItemTarget runs, and a NoTarget result
80
+ for a command with no signal passes through Resolve-PrAuthorCurrentBranchTarget, which
81
+ re-resolves the current branch (#989).
71
82
  .OUTPUTS
72
- The target result object from Resolve-WorktreeItemTarget.
83
+ A target result object built by New-WorktreeResolutionTargetResult.
73
84
  #>
74
85
  [CmdletBinding()]
75
86
  param(
@@ -77,7 +88,57 @@ function Resolve-PrAuthorWorktreeTarget {
77
88
  [string] $CommandText
78
89
  )
79
90
 
80
- return (Resolve-WorktreeItemTarget -Text $CommandText -SessionRoot (Get-Location).Path)
91
+ $sessionRoot = (Get-Location).Path
92
+ $branch = Find-WorktreeResolutionBranchSignal -Text $CommandText
93
+ $issueSignal = Find-WorktreeItemIssueSignal -Text $CommandText
94
+ if ($null -ne $branch -and @($issueSignal).Count -eq 0) {
95
+ $shared = Resolve-HookTargetWorktree -SessionRoot $sessionRoot -CommandBranch $branch
96
+ $mapped = ConvertFrom-PrAuthorHookTargetResult -Result $shared -CommandText $CommandText -SessionRoot $sessionRoot
97
+ if ($null -ne $mapped) { return $mapped }
98
+ }
99
+ $target = Resolve-WorktreeItemTarget -Text $CommandText -SessionRoot $sessionRoot
100
+ return (Resolve-PrAuthorCurrentBranchTarget -CommandText $CommandText -Target $target)
101
+ }
102
+
103
+ function ConvertFrom-PrAuthorHookTargetResult {
104
+ <#
105
+ .SYNOPSIS
106
+ Map a Resolve-HookTargetWorktree result onto a pr-author target result, or $null (issue #1011).
107
+ .DESCRIPTION
108
+ Returns $null (no selection) when Result is null, when CommandText carries no branch
109
+ signal, when Result.Source is not CommandOperand, when Result names no root, or when that
110
+ root fails Test-WorktreeResolutionRootMarker (a registration whose directory is gone).
111
+ Only a CommandOperand result selects, being branch-derived; a FilePath, SessionRoot, or
112
+ DelegationIdentity result never selects the worktree (issue #673). An ambiguous result
113
+ maps to Ambiguous. Labelling is delegated to ConvertTo-WorktreeItemResolvedResult, which
114
+ maps a root equal to SessionRoot, or to the worktree enclosing it, to SessionRoot and any
115
+ other root to OtherWorktree.
116
+ .PARAMETER Result
117
+ The Resolve-HookTargetWorktree result.
118
+ .PARAMETER CommandText
119
+ The Bash command text under evaluation.
120
+ .PARAMETER SessionRoot
121
+ The session root the result is compared with.
122
+ .OUTPUTS
123
+ System.Management.Automation.PSCustomObject or $null
124
+ #>
125
+ [CmdletBinding()]
126
+ [OutputType([pscustomobject])]
127
+ param(
128
+ [AllowNull()][object] $Result,
129
+ [Parameter(Mandatory)][AllowEmptyString()][string] $CommandText,
130
+ [Parameter(Mandatory)][string] $SessionRoot
131
+ )
132
+
133
+ $branch = Find-WorktreeResolutionBranchSignal -Text $CommandText
134
+ if ($null -eq $Result -or $null -eq $branch -or $Result.Source -cne 'CommandOperand') { return $null }
135
+ $detail = if ([string]::IsNullOrWhiteSpace([string]$Result.Detail)) { "branch '$branch' resolved by the shared resolver" } else { [string]$Result.Detail }
136
+ if ($Result.Ambiguous) {
137
+ return (New-WorktreeResolutionTargetResult -Status Ambiguous -SessionRoot $SessionRoot -Signal Branch -SignalValue $branch -Candidate @($Result.Candidates) -Detail $detail)
138
+ }
139
+ if ([string]::IsNullOrEmpty([string]$Result.WorktreeRoot)) { return $null }
140
+ if (-not (Test-WorktreeResolutionRootMarker -Path $Result.WorktreeRoot)) { return $null }
141
+ return (ConvertTo-WorktreeItemResolvedResult -WorktreeRoot $Result.WorktreeRoot -SessionRoot $SessionRoot -Branch $branch -Detail $detail)
81
142
  }
82
143
 
83
144
  function Get-PrAuthorTargetCheckpointResolution {
@@ -91,10 +152,10 @@ function Get-PrAuthorTargetCheckpointResolution {
91
152
  SessionRoot -> that worktree's own checkpoint, composed absolutely.
92
153
  OtherWorktree -> that worktree's own checkpoint, composed the same way.
93
154
  NoTarget -> deny, carrying the code Get-WorktreeResolutionNoTargetReasonCode
94
- returns. pr-author passes --head on every gh pr create, so a call
95
- reaching here omitted the explicit target; the remedy is to supply
96
- it, never to fall back to whichever checkpoint occupies the
97
- session root.
155
+ returns. The call named no target and no branch could be derived
156
+ from the current checkout; the remedy text from
157
+ Get-PrAuthorTargetGuidanceText names the accepted forms, and the
158
+ gate never falls back to the session root's checkpoint.
98
159
  Ambiguous -> deny, carrying the code
99
160
  Get-WorktreeResolutionAmbiguityReasonCode returns.
100
161
 
@@ -125,7 +186,7 @@ function Get-PrAuthorTargetCheckpointResolution {
125
186
  return [ordered]@{ CheckpointPath = (Get-WorktreeItemCheckpointPath -WorktreeRoot $target.WorktreeRoot); Reason = $null; WorktreeRoot = $target.WorktreeRoot; Status = $target.Status }
126
187
  }
127
188
  default {
128
- $reason = "$($target.ReasonCode): $($target.Detail) The pr-author gate will not validate this call against the session root's checkpoint, because that checkpoint may belong to a different item. Pass --head <branch> on the gh pr create command so the call names its own target."
189
+ $reason = "$($target.ReasonCode): $($target.Detail) The pr-author gate will not validate this call against the session root's checkpoint, because that checkpoint may belong to a different item. $(Get-PrAuthorTargetGuidanceText)"
129
190
  return [ordered]@{ CheckpointPath = $null; Reason = $reason; WorktreeRoot = $null; Status = $target.Status }
130
191
  }
131
192
  }
@@ -0,0 +1,149 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Current-branch target derivation for enforce-pr-author-skill.ps1 (issue #989).
4
+
5
+ .DESCRIPTION
6
+ Dot-sourced by enforce-pr-author-skill-helpers.ps1. Resolve-PrAuthorWorktreeTarget passes its
7
+ command-text resolution through Resolve-PrAuthorCurrentBranchTarget, which applies one
8
+ fallback: when the command carries no branch signal (--head, --branch, or branch:) and no
9
+ canonical issue line, and resolution returned NoTarget, the branch checked out in the hook
10
+ process's working directory is read and re-resolved through the existing resolver as a
11
+ 'branch: <name>' signal. gh pr edit has no --head flag, so this is how an edit run from the
12
+ item worktree names its own target.
13
+
14
+ Derivation order: explicit signal in the command, else the current branch, else the
15
+ original NoTarget result. A signal that matches no live worktree does not trigger the
16
+ fallback. A detached HEAD (git prints the literal HEAD), a non-zero git exit, or empty
17
+ output keeps the original NoTarget result and its reason code.
18
+
19
+ Get-PrAuthorTargetGuidanceText supplies the remedy sentence that follows the reason code and
20
+ detail in the TARGET_WORKTREE_NOT_DERIVABLE denial.
21
+
22
+ .NOTES
23
+ PowerShell 7+. Depends, at call time, on Find-WorktreeResolutionBranchSignal,
24
+ Find-WorktreeItemIssueSignal, and Resolve-WorktreeItemTarget from the worktree-resolution
25
+ modules the helpers file imports. It reads no file content. The git executable runs only
26
+ through Invoke-PrAuthorCurrentBranchGitExe, the single executable seam, which never throws.
27
+ Mirrored byte-identically under extensions/drm-copilot/resources/claude-customizations/.
28
+ #>
29
+ [CmdletBinding()]
30
+ param()
31
+
32
+ function Invoke-PrAuthorCurrentBranchGitExe {
33
+ <#
34
+ .SYNOPSIS
35
+ Run git with the given arguments in the current directory. The single executable seam.
36
+ .DESCRIPTION
37
+ Never throws: an uncaught error ends the hook with exit 1, which PreToolUse treats as
38
+ non-blocking, so a throw here would allow the call. A git that cannot start returns
39
+ ExitCode -1. Standard error is discarded so that it is never read as a branch name.
40
+ .PARAMETER GitArgs
41
+ The git arguments.
42
+ .PARAMETER GitInvoker
43
+ The scriptblock that runs git; a unit test passes a test-local stand-in so that this
44
+ body runs without starting a process.
45
+ .OUTPUTS
46
+ System.Management.Automation.PSCustomObject with ExitCode and Output (trimmed).
47
+ #>
48
+ [CmdletBinding()]
49
+ [OutputType([pscustomobject])]
50
+ param(
51
+ [Parameter(Mandatory)][string[]] $GitArgs,
52
+ [ValidateNotNull()][scriptblock] $GitInvoker = { git @args 2>$null }
53
+ )
54
+
55
+ try {
56
+ $lines = @(& $GitInvoker @GitArgs 2>$null)
57
+ $code = $LASTEXITCODE
58
+ }
59
+ catch {
60
+ return [pscustomobject]@{ ExitCode = -1; Output = '' }
61
+ }
62
+ return [pscustomobject]@{ ExitCode = [int]$code; Output = ($lines -join "`n").Trim() }
63
+ }
64
+
65
+ function Get-PrAuthorCurrentBranch {
66
+ <#
67
+ .SYNOPSIS
68
+ Return the branch checked out in the current directory, or $null.
69
+ .DESCRIPTION
70
+ Runs git rev-parse --abbrev-ref HEAD through Invoke-PrAuthorCurrentBranchGitExe. Returns
71
+ $null for a non-zero exit, for empty output, for output containing whitespace, and for
72
+ the literal HEAD that git prints on a detached checkout.
73
+ .PARAMETER GitInvoker
74
+ Optional. Forwarded to the git seam; omitted, the seam's default invoker runs git.
75
+ .OUTPUTS
76
+ System.String or $null
77
+ #>
78
+ [CmdletBinding()]
79
+ [OutputType([string])]
80
+ param(
81
+ [scriptblock] $GitInvoker
82
+ )
83
+
84
+ $seamArgs = @{ GitArgs = @('rev-parse', '--abbrev-ref', 'HEAD') }
85
+ if ($null -ne $GitInvoker) { $seamArgs['GitInvoker'] = $GitInvoker }
86
+ $result = Invoke-PrAuthorCurrentBranchGitExe @seamArgs
87
+ $name = [string]$result.Output
88
+ if ($result.ExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($name) -or $name -match '\s' -or $name -ceq 'HEAD') {
89
+ return $null
90
+ }
91
+ return $name
92
+ }
93
+
94
+ function Resolve-PrAuthorCurrentBranchTarget {
95
+ <#
96
+ .SYNOPSIS
97
+ Apply the current-branch fallback to a command-text resolution result.
98
+ .DESCRIPTION
99
+ Returns Target unchanged unless its Status is NoTarget and the command text carries
100
+ neither a branch signal nor a canonical issue line. In that case the current branch is
101
+ read; a $null branch returns Target unchanged, and any other branch is re-resolved with
102
+ Resolve-WorktreeItemTarget as the text 'branch: <name>', so ambiguity handling and the
103
+ SessionRoot or OtherWorktree labelling stay with the existing resolver.
104
+ .PARAMETER CommandText
105
+ The Bash command text under evaluation.
106
+ .PARAMETER Target
107
+ The result Resolve-WorktreeItemTarget returned for the command text.
108
+ .OUTPUTS
109
+ The target result object from Resolve-WorktreeItemTarget.
110
+ #>
111
+ [CmdletBinding()]
112
+ [OutputType([pscustomobject])]
113
+ param(
114
+ [Parameter(Mandatory)][AllowEmptyString()][string] $CommandText,
115
+ [Parameter(Mandatory)][AllowNull()][object] $Target
116
+ )
117
+
118
+ if ($null -eq $Target -or $Target.Status -ne 'NoTarget') {
119
+ return $Target
120
+ }
121
+ # Find-WorktreeItemIssueSignal emits its array as one object, so it is assigned before counting.
122
+ $issueSignal = Find-WorktreeItemIssueSignal -Text $CommandText
123
+ if ($null -ne (Find-WorktreeResolutionBranchSignal -Text $CommandText) -or $issueSignal.Count -gt 0) {
124
+ return $Target
125
+ }
126
+ $branch = Get-PrAuthorCurrentBranch
127
+ if ($null -eq $branch) {
128
+ return $Target
129
+ }
130
+ return (Resolve-WorktreeItemTarget -Text "branch: $branch" -SessionRoot (Get-Location).Path)
131
+ }
132
+
133
+ function Get-PrAuthorTargetGuidanceText {
134
+ <#
135
+ .SYNOPSIS
136
+ Return the remedy sentence of the TARGET_WORKTREE_NOT_DERIVABLE denial.
137
+ .DESCRIPTION
138
+ Names the accepted target forms: --head <branch> on gh pr create, and for gh pr edit
139
+ either running the command from the item worktree (the branch is derived) or appending
140
+ the shell comment # branch: <branch>. States that --head is not valid for gh pr edit.
141
+ .OUTPUTS
142
+ System.String
143
+ #>
144
+ [CmdletBinding()]
145
+ [OutputType([string])]
146
+ param()
147
+
148
+ return 'Name the target: for gh pr create, pass --head <branch> (gh pr create --head <branch> ...). For gh pr edit, run the command from the item worktree so the gate derives the branch from its checkout, or append the shell comment # branch: <branch> to the command; --head is not valid for gh pr edit.'
149
+ }
@@ -59,7 +59,9 @@ function Test-EpicBaseBranchOverride {
59
59
  with reason EPIC_BASE_BRANCH_MISMATCH. When epic_mode is absent or false, when the
60
60
  checkpoint is unreadable, or when the command is not gh pr create (the base branch is
61
61
  set at create time, not edit time), this check is a no-op and standalone behavior is
62
- unchanged.
62
+ unchanged. Only the JSON boolean true counts as epic mode: a string or number such as
63
+ "false", "true", or 1 is not epic mode, so the --base requirement does not apply
64
+ (issue #1001).
63
65
  .PARAMETER CommandText
64
66
  The Bash command text under evaluation.
65
67
  .PARAMETER CheckpointPath
@@ -116,7 +118,7 @@ function Test-EpicBaseBranchOverride {
116
118
  }
117
119
 
118
120
  $checkpointProps = @($checkpoint.PSObject.Properties.Name)
119
- if ($checkpointProps -notcontains 'epic_mode' -or -not [bool]$checkpoint.epic_mode) {
121
+ if ($checkpointProps -notcontains 'epic_mode' -or -not (($checkpoint.epic_mode -is [bool]) -and $checkpoint.epic_mode)) {
120
122
  return $null
121
123
  }
122
124