claude-dev-env 4.2.0 → 7.0.0

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 (350) hide show
  1. package/.agents/agents/pr-description-writer.md +2 -2
  2. package/.agents/agents/test_agent_frontmatter.py +2 -2
  3. package/.agents/agents/test_pr_description_writer_style.py +1 -3
  4. package/.agents/skills/e-code-review/SKILL.md +12 -12
  5. package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
  6. package/.agents/skills/e-code-review/reference/fix.md +15 -17
  7. package/.agents/skills/e-code-review/reference/loop.md +35 -39
  8. package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
  9. package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
  10. package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
  11. package/.agents/skills/issue-tracker/SKILL.md +7 -0
  12. package/.agents/skills/pull-request/SKILL.md +216 -0
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +18 -0
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/__init__.py +1 -0
  15. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/__init__.py +1 -0
  16. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +69 -0
  17. package/.agents/skills/pull-request/scripts/pull_request.py +265 -0
  18. package/.agents/skills/pull-request/scripts/recover_legacy_author.py +251 -0
  19. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +58 -0
  20. package/.agents/skills/pull-request/scripts/test_pull_request.py +396 -0
  21. package/.agents/skills/pull-request/scripts/test_recover_legacy_author.py +221 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/test-runner/SKILL.md +69 -0
  24. package/.agents/skills/test-runner/scripts/preflight_checks.py +365 -0
  25. package/.agents/skills/test-runner/scripts/run_tests.py +316 -0
  26. package/.agents/skills/test-runner/scripts/test_preflight_checks.py +185 -0
  27. package/.agents/skills/test-runner/scripts/test_run_tests.py +281 -0
  28. package/.agents/skills/test-runner/scripts/test_runner_constants/__init__.py +1 -0
  29. package/.agents/skills/test-runner/scripts/test_runner_constants/config/__init__.py +1 -0
  30. package/.agents/skills/test-runner/scripts/test_runner_constants/config/constants.py +96 -0
  31. package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
  32. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  33. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  34. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  35. package/bin/ever-shipped-skills.mjs +2 -0
  36. package/bin/ever-shipped-skills.test.mjs +8 -0
  37. package/bin/install.agents-home.test.mjs +15 -13
  38. package/bin/install.mjs +37 -1
  39. package/bin/install.policy-lint.test.mjs +78 -0
  40. package/bin/install.prune.test.mjs +149 -20
  41. package/bin/install.pstack-plugin.test.mjs +114 -0
  42. package/bin/install.test.mjs +61 -7
  43. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  44. package/hooks/advisory/pr_done_reminder.py +342 -0
  45. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  46. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  47. package/hooks/blocking/code_rules_paired_test.py +22 -15
  48. package/hooks/blocking/pii_prevention_blocker.py +32 -51
  49. package/hooks/blocking/test_bash_post_call_dispatcher.py +55 -17
  50. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +1 -4
  51. package/hooks/blocking/test_code_rules_command_dispatch.py +2 -2
  52. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  53. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  54. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  55. package/hooks/blocking/test_pii_prevention_blocker.py +37 -89
  56. package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
  57. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  58. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
  59. package/hooks/gh_post_body_texts.py +195 -0
  60. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  61. package/hooks/git-hooks/pre_commit.py +52 -11
  62. package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
  63. package/hooks/git-hooks/test_native_policy_commit.py +87 -0
  64. package/hooks/git-hooks/test_pre_commit.py +246 -0
  65. package/hooks/hooks.json +1 -16
  66. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -2
  67. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -8
  68. package/hooks/hooks_constants/gh_post_body_texts_constants.py +12 -0
  69. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  70. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
  71. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +17 -7
  72. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -7
  73. package/hooks/hooks_constants/test_failure_recorder_constants.py +3 -3
  74. package/hooks/hooks_constants/test_gh_post_body_texts_constants.py +19 -0
  75. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  76. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
  77. package/hooks/observability/test_failure_recorder.py +1 -1
  78. package/hooks/pyproject.toml +1 -1
  79. package/hooks/test_gh_post_body_texts.py +79 -0
  80. package/package.json +2 -2
  81. package/rules/durable-post-artifacts.md +32 -20
  82. package/rules/gh-cli-conventions.md +23 -13
  83. package/rules/git-workflow.md +21 -8
  84. package/scripts/check.ps1 +0 -1
  85. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  86. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  87. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  88. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  89. package/scripts/durable_post_lint.py +206 -0
  90. package/scripts/durable_post_lint_config/config/constants.py +96 -0
  91. package/scripts/durable_post_lint_config/config/test_constants.py +25 -0
  92. package/scripts/policy_lint/adapter_configuration.py +53 -12
  93. package/scripts/policy_lint/adapter_detectors.py +13 -6
  94. package/scripts/policy_lint/adapters.py +7 -4
  95. package/scripts/policy_lint/config/constants.py +5 -0
  96. package/scripts/policy_lint/engine.py +48 -4
  97. package/scripts/policy_lint/model.py +1 -0
  98. package/scripts/policy_lint/registry.py +1 -1
  99. package/scripts/policy_lint/selection.py +2 -1
  100. package/scripts/policy_lint/selection_git.py +2 -0
  101. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  102. package/scripts/repository_checks/config/constants.py +0 -5
  103. package/scripts/shared_tree_paths.py +32 -3
  104. package/scripts/test_durable_post_lint.py +332 -0
  105. package/scripts/test_shared_tree_paths.py +33 -0
  106. package/scripts/tests/test_adapter_configuration.py +54 -0
  107. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  108. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  109. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  110. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  111. package/scripts/tests/test_policy_lint_selection.py +25 -2
  112. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  113. package/scripts/tests/test_rules.py +3 -7
  114. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  115. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
  116. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  117. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  118. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  119. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  120. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  121. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  122. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  123. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  124. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  125. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  126. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  127. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  128. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  129. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  130. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  131. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  132. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  133. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  134. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  135. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  136. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  137. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  138. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  139. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  140. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  141. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  142. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  143. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  144. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  145. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  146. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  147. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  148. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  149. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  150. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  151. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  152. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  153. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  154. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  155. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  156. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  157. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  158. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  159. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  160. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  161. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  162. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  163. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  164. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  165. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  166. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  167. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  168. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  169. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  170. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  171. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  172. package/.agents/skills/autoconverge/SKILL.md +0 -431
  173. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  174. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  175. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  176. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  177. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  178. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  179. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  180. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  181. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  182. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  183. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  184. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  185. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  186. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  187. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  188. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  189. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  190. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  191. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  192. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  193. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  194. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  195. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  196. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  197. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  198. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  199. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  200. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  201. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  202. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  203. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  204. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  205. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  206. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  207. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  208. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  209. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  210. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  211. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  212. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  213. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  214. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  215. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  216. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  217. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  218. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  219. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  220. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  221. package/.agents/skills/hitl/SKILL.md +0 -45
  222. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  223. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  224. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  225. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  226. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  227. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  228. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  229. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  230. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  231. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  232. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  233. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  234. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  235. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  236. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  237. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  238. package/.agents/skills/prototype/SKILL.md +0 -85
  239. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  240. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  241. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  242. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  243. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  244. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  245. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  246. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  247. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  248. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  249. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  250. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  251. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  252. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  253. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  254. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  255. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  256. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  257. package/.agents/skills/rebase/AGENTS.md +0 -1
  258. package/.agents/skills/rebase/SKILL.md +0 -178
  259. package/.agents/skills/review-router/SKILL.md +0 -51
  260. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  261. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  262. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  263. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  264. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  265. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  266. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  267. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  268. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  269. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  270. package/.agents/skills/review-tier/SKILL.md +0 -56
  271. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  272. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  273. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  274. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  275. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  276. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  277. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  278. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  279. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  280. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  281. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/session-log/AGENTS.md +0 -1
  283. package/.agents/skills/session-log/SKILL.md +0 -170
  284. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  285. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  286. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  287. package/.agents/skills/session-tidy/SKILL.md +0 -191
  288. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  289. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  290. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  291. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  292. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  293. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  294. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  295. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  296. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  297. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  298. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  299. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  300. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  301. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  302. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  303. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  304. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  305. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  306. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  307. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  308. package/.agents/skills/update/AGENTS.md +0 -1
  309. package/.agents/skills/update/SKILL.md +0 -190
  310. package/_shared/pr-loop/AGENTS.md +0 -1
  311. package/_shared/pr-loop/CLAUDE.md +0 -1
  312. package/_shared/pr-loop/audit-contract.md +0 -183
  313. package/_shared/pr-loop/audit-reply-template.md +0 -151
  314. package/_shared/pr-loop/code-rules-gate.md +0 -65
  315. package/_shared/pr-loop/fix-protocol.md +0 -60
  316. package/_shared/pr-loop/gh-payloads.md +0 -75
  317. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  318. package/_shared/pr-loop/precatch-rubric.md +0 -66
  319. package/_shared/pr-loop/preflight-proposal.md +0 -56
  320. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  321. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  322. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  323. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  324. package/_shared/pr-loop/state-schema.md +0 -45
  325. package/_shared/pr-loop/worker-spawn.md +0 -189
  326. package/hooks/_gh_pr_author_swap_utils.py +0 -1225
  327. package/hooks/blocking/conventional_pr_title_gate.py +0 -443
  328. package/hooks/blocking/gh_body_arg_blocker.py +0 -176
  329. package/hooks/blocking/gh_pr_author_enforcer.py +0 -487
  330. package/hooks/blocking/gh_pr_author_restore.py +0 -105
  331. package/hooks/blocking/pr_description_writer_gate.py +0 -256
  332. package/hooks/blocking/test_conventional_pr_title_gate.py +0 -640
  333. package/hooks/blocking/test_gh_body_arg_blocker.py +0 -441
  334. package/hooks/blocking/test_gh_pr_author_enforcer.py +0 -1166
  335. package/hooks/blocking/test_gh_pr_author_restore.py +0 -513
  336. package/hooks/blocking/test_gh_pr_author_swap_utils.py +0 -910
  337. package/hooks/blocking/test_pr_description_writer_gate.py +0 -234
  338. package/hooks/blocking/test_preflight_check.py +0 -343
  339. package/hooks/blocking/test_test_preflight_check.py +0 -80
  340. package/hooks/blocking/test_volatile_path_in_post_blocker.py +0 -322
  341. package/hooks/blocking/volatile_path_in_post_blocker.py +0 -461
  342. package/hooks/hooks_constants/conventional_pr_title_gate_constants.py +0 -58
  343. package/hooks/hooks_constants/gh_pr_author_swap_constants.py +0 -76
  344. package/hooks/hooks_constants/pr_description_writer_gate_constants.py +0 -73
  345. package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +0 -55
  346. package/hooks/observability/pr_description_writer_spawn_tracker.py +0 -113
  347. package/hooks/observability/test_pr_description_writer_spawn_tracker.py +0 -150
  348. package/hooks/session/gh_pr_author_session_cleanup.py +0 -175
  349. package/hooks/session/test_gh_pr_author_session_cleanup.py +0 -576
  350. package/hooks/test__gh_pr_author_swap_utils.py +0 -333
@@ -215,12 +215,27 @@ def _collect_referenced_identifiers(source: str) -> set[str]:
215
215
  return all_referenced_identifiers
216
216
 
217
217
 
218
+ def _sibling_test_paths(stem_test_path: Path) -> list[Path]:
219
+ """Return the capped, sorted test files beside the stem test, stem excluded."""
220
+ suite_directory = stem_test_path.parent
221
+ stem_path_key = os.path.normcase(str(stem_test_path.resolve()))
222
+ all_sibling_paths: list[Path] = []
223
+ for each_glob in ALL_TEST_FILENAME_GLOBS:
224
+ all_sibling_paths.extend(
225
+ each_path
226
+ for each_path in sorted(suite_directory.glob(each_glob))
227
+ if os.path.normcase(str(each_path.resolve())) != stem_path_key
228
+ )
229
+ return all_sibling_paths[:MAX_TEST_FILES_SCANNED]
230
+
231
+
218
232
  def _suite_referenced_identifiers(stem_test_path: Path) -> set[str]:
219
233
  """Return identifiers referenced across every test file beside the stem test.
220
234
 
221
- Scans every ``test_*.py`` and ``*_test.py`` file in the directory holding the
222
- stem-matched test file, bounded by the scan cap, and unions the identifiers
223
- each one references.
235
+ Reads the stem-matched test file first, then scans every other ``test_*.py``
236
+ and ``*_test.py`` file in its directory, bounded by the scan cap, and unions
237
+ the identifiers each one references. The stem test always counts, so a
238
+ directory with more test files than the cap cannot hide it.
224
239
 
225
240
  Args:
226
241
  stem_test_path: The stem-matched test file whose directory is scanned.
@@ -228,12 +243,9 @@ def _suite_referenced_identifiers(stem_test_path: Path) -> set[str]:
228
243
  Returns:
229
244
  The union of referenced identifiers across the scanned test files.
230
245
  """
231
- suite_directory = stem_test_path.parent
232
- all_test_file_paths: list[Path] = []
233
- for each_glob in ALL_TEST_FILENAME_GLOBS:
234
- all_test_file_paths.extend(sorted(suite_directory.glob(each_glob)))
246
+ all_test_file_paths = [stem_test_path, *_sibling_test_paths(stem_test_path)]
235
247
  all_referenced_identifiers: set[str] = set()
236
- for each_test_file_path in all_test_file_paths[:MAX_TEST_FILES_SCANNED]:
248
+ for each_test_file_path in all_test_file_paths:
237
249
  try:
238
250
  test_source = each_test_file_path.read_text(encoding="utf-8")
239
251
  except (OSError, UnicodeDecodeError):
@@ -364,16 +376,12 @@ def _production_stem_from_test_filename(test_filename: str) -> str | None:
364
376
  if test_filename.startswith(STEM_TEST_FILENAME_PREFIX) and test_filename.endswith(
365
377
  PYTHON_SOURCE_SUFFIX
366
378
  ):
367
- production_stem = test_filename[
368
- len(STEM_TEST_FILENAME_PREFIX) : -len(PYTHON_SOURCE_SUFFIX)
369
- ]
379
+ production_stem = test_filename[len(STEM_TEST_FILENAME_PREFIX) : -len(PYTHON_SOURCE_SUFFIX)]
370
380
  return production_stem or None
371
381
  return None
372
382
 
373
383
 
374
- def _paired_production_module_path(
375
- test_path: Path, production_stem: str
376
- ) -> Path | None:
384
+ def _paired_production_module_path(test_path: Path, production_stem: str) -> Path | None:
377
385
  """Return the production module a stem-matched test file pairs with, or None.
378
386
 
379
387
  Mirrors ``_stem_matched_test_path`` in reverse for the two common layouts: a
@@ -515,4 +523,3 @@ def check_test_file_omits_module_public_function(
515
523
  if len(all_omission_violations) >= MAX_PAIRED_TEST_COVERAGE_ISSUES:
516
524
  break
517
525
  return all_omission_violations
518
-
@@ -1,23 +1,18 @@
1
1
  #!/usr/bin/env python3
2
2
  """PreToolUse hook: block writes, durable posts, and commits that carry PII.
3
3
 
4
- Surfaces guarded:
5
-
6
- - Write / Edit / MultiEdit — new content about to land on disk
7
- - Bash / PowerShell ``gh`` post subcommands and GitHub MCP post tools — durable
8
- bodies
9
- - Bash / PowerShell ``git commit`` (including ``git.exe`` and flag forms) —
10
- staged file contents about to become history. Commit message bodies are out
11
- of scope; only staged blob text is scanned.
12
-
13
- Payload and post-body scanning live in ``pii_payload_scan``; git-commit command
14
- detection lives in ``pii_commit_command``; both re-export through this entry
15
- module so the hooks.json wiring and every importer resolve unchanged.
16
-
17
- A repository named in ``CLAUDE_PII_EXEMPT_REPOS`` or the ``pii_exempt_repositories``
18
- list in ``~/.claude/local-identity.json`` skips the staged-commit scan; a
19
- repository without a readable origin remote is never exempt. Exact values listed
20
- under ``pii_allowlisted_values`` for a repository's origin slug may pass the
4
+ ::
5
+
6
+ Write/Edit/MultiEdit -> scan new disk content
7
+ gh post / GitHub MCP -> scan durable bodies
8
+ git commit -> scan staged blob text, not the commit message
9
+
10
+ ``pii_payload_scan`` and ``pii_commit_command`` re-export through this
11
+ entry module so hooks.json wiring and importers stay unchanged.
12
+ ``CLAUDE_PII_EXEMPT_REPOS`` or ``pii_exempt_repositories`` in
13
+ ``~/.claude/local-identity.json`` skip the staged-commit scan. A repo
14
+ without a readable origin remote is never exempt.
15
+ ``pii_allowlisted_values`` for a repository origin slug may pass
21
16
  Write/Edit and staged-commit scans in that repository only.
22
17
  """
23
18
 
@@ -56,7 +51,7 @@ try:
56
51
  )
57
52
  from pii_scanner import is_path_exempt_from_pii_scan, scan_text_for_pii
58
53
  from precommit_code_rules_gate import resolve_repository_root
59
- from volatile_path_in_post_blocker import (
54
+ from gh_post_body_texts import (
60
55
  extract_gh_post_body_texts_for_privacy_gate,
61
56
  extract_mcp_body_texts,
62
57
  )
@@ -124,7 +119,8 @@ def list_staged_file_paths(
124
119
  try:
125
120
  completed_process = subprocess.run(
126
121
  list(ALL_STAGED_FILES_COMMAND),
127
- check=False, capture_output=True,
122
+ check=False,
123
+ capture_output=True,
128
124
  text=True,
129
125
  timeout=GIT_COMMAND_TIMEOUT_SECONDS,
130
126
  cwd=str(repository_root),
@@ -148,7 +144,8 @@ def _git_show_staged_blob(
148
144
  try:
149
145
  completed_process = subprocess.run(
150
146
  list(ALL_STAGED_BLOB_SHOW_COMMAND_PREFIX) + [staged_blob_reference],
151
- check=False, capture_output=True,
147
+ check=False,
148
+ capture_output=True,
152
149
  timeout=GIT_COMMAND_TIMEOUT_SECONDS,
153
150
  cwd=str(repository_root),
154
151
  )
@@ -197,9 +194,7 @@ def _scan_staged_path(
197
194
  repository_root: Path, relative_path: str, all_allowlisted_values: frozenset[str]
198
195
  ) -> str | None:
199
196
  """Return a deny reason for one staged path, or None when it is clean."""
200
- staged_text, unscannable_reason = read_staged_file_text(
201
- repository_root, relative_path
202
- )
197
+ staged_text, unscannable_reason = read_staged_file_text(repository_root, relative_path)
203
198
  if unscannable_reason is not None:
204
199
  return unscannable_reason
205
200
  if staged_text is None:
@@ -217,9 +212,9 @@ def _scan_staged_path(
217
212
  def evaluate_staged_commit(repository_root: Path) -> str | None:
218
213
  """Return a deny reason when staged content carries PII or is unscannable.
219
214
 
220
- Fail-closed: git list/show failures and unscannable blobs deny the commit
221
- rather than treating unread content as clean. A value in the repository's
222
- PII allowlist is dropped from the findings, so its commits may carry it.
215
+ Git list or show failures and unscannable blobs deny the commit. A value
216
+ in the repository's PII allowlist is dropped from the findings, so its
217
+ commits may carry it.
223
218
 
224
219
  Args:
225
220
  repository_root: Repository whose index is about to be committed.
@@ -234,22 +229,18 @@ def evaluate_staged_commit(repository_root: Path) -> str | None:
234
229
  for each_relative_path in all_relative_paths:
235
230
  if is_path_exempt_from_pii_scan(each_relative_path):
236
231
  continue
237
- deny_reason = _scan_staged_path(
238
- repository_root, each_relative_path, all_allowlisted_values
239
- )
232
+ deny_reason = _scan_staged_path(repository_root, each_relative_path, all_allowlisted_values)
240
233
  if deny_reason is not None:
241
234
  return deny_reason
242
235
  return None
243
236
 
244
237
 
245
- def _evaluate_commit_staged_content(
246
- bash_command: str, working_directory: str | None
247
- ) -> str | None:
238
+ def _evaluate_commit_staged_content(bash_command: str, working_directory: str | None) -> str | None:
248
239
  """Scan the staged content of the repository the commit command targets.
249
240
 
250
- Resolves the repository from the command's ``-C``/``cd`` path, falling back
251
- to the session working directory only when the command names none, so a
252
- removed cwd never blocks a commit that targets a valid repo.
241
+ Resolves the repository from the command's ``-C`` or ``cd`` path. Falls
242
+ back to the session working directory only when the command names none. A
243
+ removed cwd does not block a commit that targets a valid repo.
253
244
 
254
245
  Args:
255
246
  bash_command: The Bash or PowerShell tool command string.
@@ -259,9 +250,7 @@ def _evaluate_commit_staged_content(
259
250
  Deny reason text, or None when the staged content is clean or exempt.
260
251
  """
261
252
  command_directory = compose_command_working_directory(bash_command)
262
- attempted_directory = (
263
- command_directory if command_directory is not None else working_directory
264
- )
253
+ attempted_directory = command_directory if command_directory is not None else working_directory
265
254
  expanded_directory = expand_user_directory(attempted_directory)
266
255
  repository_root = resolve_repository_root(expanded_directory)
267
256
  if repository_root is None:
@@ -271,9 +260,7 @@ def _evaluate_commit_staged_content(
271
260
  return evaluate_staged_commit(repository_root)
272
261
 
273
262
 
274
- def evaluate_bash_command(
275
- bash_command: str, working_directory: str | None
276
- ) -> str | None:
263
+ def evaluate_bash_command(bash_command: str, working_directory: str | None) -> str | None:
277
264
  """Return a deny reason for a shell gh post or git commit with PII.
278
265
 
279
266
  Args:
@@ -284,10 +271,8 @@ def evaluate_bash_command(
284
271
  Returns:
285
272
  Deny reason text, or None when the command is clean or out of scope.
286
273
  """
287
- all_post_bodies, body_file_failure_reason = (
288
- extract_gh_post_body_texts_for_privacy_gate(
289
- bash_command, working_directory=working_directory
290
- )
274
+ all_post_bodies, body_file_failure_reason = extract_gh_post_body_texts_for_privacy_gate(
275
+ bash_command, working_directory=working_directory
291
276
  )
292
277
  if body_file_failure_reason is not None:
293
278
  return body_file_failure_reason
@@ -308,9 +293,7 @@ def _evaluate_shell_tool(
308
293
  return None
309
294
  working_directory_value = all_tool_input.get("working_directory")
310
295
  working_directory = (
311
- working_directory_value
312
- if isinstance(working_directory_value, str)
313
- else None
296
+ working_directory_value if isinstance(working_directory_value, str) else None
314
297
  )
315
298
  if working_directory is None:
316
299
  cwd_value = payload_by_key.get("cwd")
@@ -332,9 +315,7 @@ def evaluate(payload_by_key: dict[str, object]) -> str | None:
332
315
  raw_tool_input = payload_by_key.get("tool_input", {})
333
316
  all_tool_input = raw_tool_input if isinstance(raw_tool_input, dict) else {}
334
317
  if tool_name in ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES:
335
- return evaluate_write_edit_payload(
336
- tool_name, all_tool_input, hook_payload=payload_by_key
337
- )
318
+ return evaluate_write_edit_payload(tool_name, all_tool_input, hook_payload=payload_by_key)
338
319
  if tool_name == APPLY_PATCH_TOOL_NAME:
339
320
  return evaluate_apply_patch_payload(all_tool_input, hook_payload=payload_by_key)
340
321
  if tool_name in ALL_SHELL_TOOL_NAMES:
@@ -1,7 +1,7 @@
1
1
  """Behavior tests for the Bash PostToolUse dispatcher.
2
2
 
3
3
  One interpreter start runs every hosted PostToolUse hook a Bash call fires.
4
- The unit tests pin selection, call order, and crash isolation with a fake
4
+ The unit tests pin selection and call order with a fake
5
5
  runner; the end-to-end test drives the real hosted hooks through a real
6
6
  payload and confirms the recorder's own real side effect lands.
7
7
  ``hooks/conftest.py`` already puts the hooks and blocking directories on
@@ -15,19 +15,26 @@ from pathlib import Path
15
15
 
16
16
  import pytest
17
17
 
18
- from bash_post_call_dispatcher import dispatch, main, select_applicable_entries
18
+ from bash_post_call_dispatcher import (
19
+ additional_context_from_hook_output,
20
+ dispatch,
21
+ main,
22
+ select_applicable_entries,
23
+ )
19
24
  from hooks_constants.bash_pre_tool_use_dispatcher_constants import BASH_TOOL_NAME
20
25
  from hooks_constants.hosted_hook_runner import HostedHookRun
21
26
  from tdd_enforcer_parts import content_hash_store
22
27
 
28
+ _ALL_EXPECTED_ROSTER_PATHS = [
29
+ "observability/test_failure_recorder.py",
30
+ "advisory/pr_done_reminder.py",
31
+ ]
23
32
 
24
- def test_select_applicable_entries_returns_both_hosted_hooks_for_bash() -> None:
33
+
34
+ def test_select_applicable_entries_returns_the_hosted_hooks_for_bash() -> None:
25
35
  all_entries = select_applicable_entries(BASH_TOOL_NAME)
26
36
  all_script_paths = [each_entry.script_relative_path for each_entry in all_entries]
27
- assert all_script_paths == [
28
- "blocking/gh_pr_author_restore.py",
29
- "observability/test_failure_recorder.py",
30
- ]
37
+ assert all_script_paths == _ALL_EXPECTED_ROSTER_PATHS
31
38
 
32
39
 
33
40
  def test_select_applicable_entries_returns_none_for_a_write_tool() -> None:
@@ -48,27 +55,58 @@ def test_dispatch_runs_every_hosted_hook_in_roster_order(
48
55
 
49
56
  dispatch('{"tool_name": "Bash"}', BASH_TOOL_NAME)
50
57
 
51
- assert all_call_paths == ["gh_pr_author_restore.py", "test_failure_recorder.py"]
58
+ assert all_call_paths == [Path(each_path).name for each_path in _ALL_EXPECTED_ROSTER_PATHS]
52
59
 
53
60
 
54
- def test_dispatch_runs_the_later_hook_after_an_earlier_one_crashes(
55
- monkeypatch: pytest.MonkeyPatch,
61
+ def test_dispatch_forwards_hosted_hook_additional_context_as_one_payload(
62
+ monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
56
63
  ) -> None:
57
- all_call_paths: list[str] = []
64
+ context_by_hook = {
65
+ "test_failure_recorder.py": "",
66
+ "pr_done_reminder.py": json.dumps(
67
+ {"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "PR #42"}}
68
+ ),
69
+ }
58
70
 
59
71
  def _fake_run_hook(script_path: str, payload_text: str) -> HostedHookRun:
60
72
  del payload_text
61
- script_name = Path(script_path).name
62
- all_call_paths.append(script_name)
63
- if script_name == "gh_pr_author_restore.py":
64
- return HostedHookRun(captured_stdout="", did_crash=True)
73
+ return HostedHookRun(
74
+ captured_stdout=context_by_hook[Path(script_path).name], did_crash=False
75
+ )
76
+
77
+ monkeypatch.setattr("bash_post_call_dispatcher.run_hook_capturing_output", _fake_run_hook)
78
+
79
+ dispatch('{"tool_name": "Bash"}', BASH_TOOL_NAME)
80
+
81
+ emitted = json.loads(capsys.readouterr().out)
82
+ assert emitted == {
83
+ "hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "PR #42"}
84
+ }
85
+ assert "decision" not in emitted
86
+
87
+
88
+ def test_dispatch_writes_nothing_when_no_hosted_hook_printed_context(
89
+ monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
90
+ ) -> None:
91
+ def _fake_run_hook(script_path: str, payload_text: str) -> HostedHookRun:
92
+ del script_path, payload_text
65
93
  return HostedHookRun(captured_stdout="", did_crash=False)
66
94
 
67
95
  monkeypatch.setattr("bash_post_call_dispatcher.run_hook_capturing_output", _fake_run_hook)
68
96
 
69
97
  dispatch('{"tool_name": "Bash"}', BASH_TOOL_NAME)
70
98
 
71
- assert all_call_paths == ["gh_pr_author_restore.py", "test_failure_recorder.py"]
99
+ assert capsys.readouterr().out == ""
100
+
101
+
102
+ @pytest.mark.parametrize(
103
+ "captured_stdout",
104
+ ["", " ", "not json", "[]", '{"decision": "block"}', '{"hookSpecificOutput": {}}'],
105
+ )
106
+ def test_additional_context_from_hook_output_ignores_non_context_output(
107
+ captured_stdout: str,
108
+ ) -> None:
109
+ assert additional_context_from_hook_output(captured_stdout) is None
72
110
 
73
111
 
74
112
  def test_main_exits_zero_and_writes_nothing_to_stdout(
@@ -85,7 +123,7 @@ def test_main_exits_zero_and_writes_nothing_to_stdout(
85
123
 
86
124
 
87
125
  def test_end_to_end_real_hosted_hooks_record_a_real_pytest_failure(tmp_path: Path) -> None:
88
- """Drives the real, unfaked roster: both scripts run in one process."""
126
+ """Drive the real recorder through the dispatcher."""
89
127
  test_file = tmp_path / "test_orders.py"
90
128
  test_file.write_text("def test_fulfill(): assert False\n")
91
129
  session_id = "post-dispatcher-session"
@@ -222,7 +222,6 @@ def test_powershell_selects_the_shared_hooks_in_registration_order() -> None:
222
222
  "blocking/cursor_cli_python_misfire_blocker.py",
223
223
  "blocking/unscoped_search_blocker.py",
224
224
  "blocking/pii_prevention_blocker.py",
225
- "blocking/pr_description_writer_gate.py",
226
225
  ]
227
226
 
228
227
 
@@ -270,9 +269,7 @@ def test_dispatcher_denies_subshell_disguised_as_arithmetic_expansion() -> None:
270
269
  the live Bash tool path.
271
270
  """
272
271
  payload_text = _bash_payload("echo $((cd /tmp) && pwd)")
273
- decision, _reason = _decision_from_stdout(
274
- _run_process(_DISPATCHER_SCRIPT, payload_text).stdout
275
- )
272
+ decision, _reason = _decision_from_stdout(_run_process(_DISPATCHER_SCRIPT, payload_text).stdout)
276
273
  assert decision == "deny"
277
274
 
278
275
 
@@ -11,7 +11,7 @@ from code_rules_command_dispatch import ( # noqa: E402
11
11
  check_unanchored_command_dispatch,
12
12
  )
13
13
 
14
- GATE_PATH = "packages/claude-dev-env/hooks/blocking/conventional_pr_title_gate.py"
14
+ GATE_PATH = "packages/claude-dev-env/hooks/blocking/block_main_commit.py"
15
15
 
16
16
  UNANCHORED_SOURCE = (
17
17
  "import re\n"
@@ -84,7 +84,7 @@ def test_ignores_file_outside_hooks_blocking() -> None:
84
84
 
85
85
 
86
86
  def test_ignores_test_file() -> None:
87
- test_path = "packages/claude-dev-env/hooks/blocking/test_conventional_pr_title_gate.py"
87
+ test_path = "packages/claude-dev-env/hooks/blocking/test_block_main_commit.py"
88
88
  assert check_unanchored_command_dispatch(UNANCHORED_SOURCE, test_path) == []
89
89
 
90
90
 
@@ -19,6 +19,10 @@ _BLOCKING_DIRECTORY = Path(__file__).resolve().parent
19
19
  if str(_BLOCKING_DIRECTORY) not in sys.path:
20
20
  sys.path.insert(0, str(_BLOCKING_DIRECTORY))
21
21
 
22
+ from hooks_constants.paired_test_coverage_constants import ( # noqa: E402
23
+ MAX_TEST_FILES_SCANNED,
24
+ )
25
+
22
26
  from code_rules_paired_test import ( # noqa: E402
23
27
  check_public_function_missing_paired_test,
24
28
  check_test_file_omits_module_public_function,
@@ -26,9 +30,7 @@ from code_rules_paired_test import ( # noqa: E402
26
30
 
27
31
  _TWO_PUBLIC_FUNCTIONS = "def alpha():\n return 1\n\n\ndef beta():\n return 2\n"
28
32
  _THREE_PUBLIC_FUNCTIONS = (
29
- "def alpha():\n return 1\n\n\n"
30
- "def beta():\n return 2\n\n\n"
31
- "def gamma():\n return 3\n"
33
+ "def alpha():\n return 1\n\n\ndef beta():\n return 2\n\n\ndef gamma():\n return 3\n"
32
34
  )
33
35
 
34
36
 
@@ -145,6 +147,28 @@ def test_counts_coverage_across_sibling_test_files(
145
147
  assert all_issues == []
146
148
 
147
149
 
150
+ def test_reads_the_stem_test_when_the_suite_exceeds_the_scan_cap(
151
+ neutral_package_directory: Path,
152
+ ) -> None:
153
+ filler_body = "def test_nothing():\n assert True\n"
154
+ _write_test_file(
155
+ neutral_package_directory,
156
+ "test_a0000.py",
157
+ "from pkg.mod import alpha\n\ndef test_alpha():\n assert alpha() == 1\n",
158
+ )
159
+ for each_index in range(1, MAX_TEST_FILES_SCANNED + 1):
160
+ _write_test_file(neutral_package_directory, f"test_a{each_index:04d}.py", filler_body)
161
+ _write_test_file(
162
+ neutral_package_directory,
163
+ "test_mod.py",
164
+ "from pkg.mod import beta\n\ndef test_beta():\n assert beta() == 2\n",
165
+ )
166
+ all_issues = check_public_function_missing_paired_test(
167
+ _TWO_PUBLIC_FUNCTIONS, str(neutral_package_directory / "mod.py")
168
+ )
169
+ assert all_issues == []
170
+
171
+
148
172
  def test_main_and_private_functions_are_never_required(
149
173
  neutral_package_directory: Path,
150
174
  ) -> None:
@@ -183,8 +207,7 @@ def _write_module(package_directory: Path, body: str) -> None:
183
207
 
184
208
 
185
209
  _SUITE_COVERS_ALPHA_BETA = (
186
- "from pkg.mod import alpha, beta\n\n"
187
- "def test_pair():\n assert alpha() == 1 and beta() == 2\n"
210
+ "from pkg.mod import alpha, beta\n\ndef test_pair():\n assert alpha() == 1 and beta() == 2\n"
188
211
  )
189
212
 
190
213
 
@@ -193,9 +216,7 @@ def test_flags_module_public_function_when_test_suite_omits_it(
193
216
  ) -> None:
194
217
  _write_module(neutral_package_directory, _THREE_PUBLIC_FUNCTIONS)
195
218
  test_path = str(neutral_package_directory / "tests" / "test_mod.py")
196
- all_issues = check_test_file_omits_module_public_function(
197
- _SUITE_COVERS_ALPHA_BETA, test_path
198
- )
219
+ all_issues = check_test_file_omits_module_public_function(_SUITE_COVERS_ALPHA_BETA, test_path)
199
220
  assert len(all_issues) == 1
200
221
  assert "gamma" in all_issues[0]
201
222
  assert "mod.py" in all_issues[0]
@@ -231,9 +252,7 @@ def test_skips_test_file_with_no_paired_production_module(
231
252
  neutral_package_directory: Path,
232
253
  ) -> None:
233
254
  test_path = str(neutral_package_directory / "tests" / "test_mod.py")
234
- all_issues = check_test_file_omits_module_public_function(
235
- _SUITE_COVERS_ALPHA_BETA, test_path
236
- )
255
+ all_issues = check_test_file_omits_module_public_function(_SUITE_COVERS_ALPHA_BETA, test_path)
237
256
  assert all_issues == []
238
257
 
239
258
 
@@ -242,9 +261,7 @@ def test_ignores_a_non_stem_matched_written_file(
242
261
  ) -> None:
243
262
  _write_module(neutral_package_directory, _THREE_PUBLIC_FUNCTIONS)
244
263
  helper_path = str(neutral_package_directory / "helper.py")
245
- all_issues = check_test_file_omits_module_public_function(
246
- _SUITE_COVERS_ALPHA_BETA, helper_path
247
- )
264
+ all_issues = check_test_file_omits_module_public_function(_SUITE_COVERS_ALPHA_BETA, helper_path)
248
265
  assert all_issues == []
249
266
 
250
267
 
@@ -274,9 +291,7 @@ def test_judges_post_edit_content_over_stale_on_disk_test(
274
291
  "from pkg.mod import alpha, beta, gamma\n\n"
275
292
  "def test_all():\n assert alpha() and beta() and gamma()\n"
276
293
  )
277
- all_issues = check_test_file_omits_module_public_function(
278
- post_edit_covers_all, test_path
279
- )
294
+ all_issues = check_test_file_omits_module_public_function(post_edit_covers_all, test_path)
280
295
  assert all_issues == []
281
296
 
282
297
 
@@ -290,9 +305,7 @@ def test_counts_coverage_across_sibling_test_files_on_test_write(
290
305
  "from pkg.mod import gamma\n\ndef test_gamma():\n assert gamma() == 3\n",
291
306
  )
292
307
  test_path = str(neutral_package_directory / "tests" / "test_mod.py")
293
- all_issues = check_test_file_omits_module_public_function(
294
- _SUITE_COVERS_ALPHA_BETA, test_path
295
- )
308
+ all_issues = check_test_file_omits_module_public_function(_SUITE_COVERS_ALPHA_BETA, test_path)
296
309
  assert all_issues == []
297
310
 
298
311
 
@@ -301,9 +314,7 @@ def test_test_side_message_names_module_and_function_without_line_prefix(
301
314
  ) -> None:
302
315
  _write_module(neutral_package_directory, _THREE_PUBLIC_FUNCTIONS)
303
316
  test_path = str(neutral_package_directory / "tests" / "test_mod.py")
304
- all_issues = check_test_file_omits_module_public_function(
305
- _SUITE_COVERS_ALPHA_BETA, test_path
306
- )
317
+ all_issues = check_test_file_omits_module_public_function(_SUITE_COVERS_ALPHA_BETA, test_path)
307
318
  assert len(all_issues) == 1
308
319
  assert not all_issues[0].startswith("Line ")
309
320
  assert "mod.py" in all_issues[0]
@@ -315,9 +326,7 @@ def test_test_side_omission_blocks_on_any_test_file_edit(
315
326
  ) -> None:
316
327
  _write_module(neutral_package_directory, _THREE_PUBLIC_FUNCTIONS)
317
328
  test_path = str(neutral_package_directory / "tests" / "test_mod.py")
318
- all_issues = check_test_file_omits_module_public_function(
319
- _SUITE_COVERS_ALPHA_BETA, test_path
320
- )
329
+ all_issues = check_test_file_omits_module_public_function(_SUITE_COVERS_ALPHA_BETA, test_path)
321
330
  assert len(all_issues) == 1
322
331
  assert "gamma" in all_issues[0]
323
332
 
@@ -333,7 +342,5 @@ def test_skips_when_paired_production_module_is_exempt(
333
342
  "from pkg import alpha, beta, gamma\n\n"
334
343
  "def test_all():\n assert alpha() and beta() and gamma()\n"
335
344
  )
336
- all_issues = check_test_file_omits_module_public_function(
337
- suite_covers_all, beside_test_path
338
- )
345
+ all_issues = check_test_file_omits_module_public_function(suite_covers_all, beside_test_path)
339
346
  assert all_issues == []
@@ -17,8 +17,8 @@ import pathlib
17
17
  import sys
18
18
 
19
19
  _PACKAGE_ROOT = pathlib.Path(__file__).resolve().parents[2]
20
- _SHIPPED_CONVERGE_MJS = (
21
- _PACKAGE_ROOT / ".agents" / "skills" / "autoconverge" / "workflow" / "converge.mjs"
20
+ _ARCHIVED_CONVERGE_MJS = (
21
+ _PACKAGE_ROOT.parents[1] / "skill-archive" / "autoconverge" / "workflow" / "converge.mjs"
22
22
  )
23
23
 
24
24
  _HOOK_DIRECTORY = pathlib.Path(__file__).parent
@@ -750,8 +750,8 @@ def should_still_flag_real_dispatch_alongside_task_substring_identifier() -> Non
750
750
  assert "spawnVerifierAgent" in issues[0]
751
751
 
752
752
 
753
- def should_not_flag_shipped_converge_workflow() -> None:
754
- converge_source = _SHIPPED_CONVERGE_MJS.read_text(encoding="utf-8")
753
+ def should_not_flag_archived_converge_regression_fixture() -> None:
754
+ converge_source = _ARCHIVED_CONVERGE_MJS.read_text(encoding="utf-8")
755
755
  issues = check_js_resume_task_enumeration_coverage(
756
756
  converge_source, "skills/autoconverge/workflow/converge.mjs"
757
757
  )
@@ -34,8 +34,8 @@ check_js_returns_object_schemaless_branch = (
34
34
 
35
35
  _MJS_PATH = "skills/autoconverge/workflow/converge.mjs"
36
36
 
37
- _SHIPPED_CONVERGE_MJS = (
38
- _HOOK_DIRECTORY.parents[1] / ".agents" / "skills" / "autoconverge" / "workflow" / "converge.mjs"
37
+ _ARCHIVED_CONVERGE_MJS = (
38
+ _HOOK_DIRECTORY.parents[3] / "skill-archive" / "autoconverge" / "workflow" / "converge.mjs"
39
39
  )
40
40
 
41
41
 
@@ -161,7 +161,7 @@ def test_skips_python_files() -> None:
161
161
  assert issues == []
162
162
 
163
163
 
164
- def test_shipped_converge_mjs_passes_its_own_check() -> None:
165
- shipped_source = _SHIPPED_CONVERGE_MJS.read_text(encoding="utf-8")
166
- issues = check_js_returns_object_schemaless_branch(shipped_source, _MJS_PATH)
164
+ def test_archived_converge_regression_fixture_passes_the_check() -> None:
165
+ archived_source = _ARCHIVED_CONVERGE_MJS.read_text(encoding="utf-8")
166
+ issues = check_js_returns_object_schemaless_branch(archived_source, _MJS_PATH)
167
167
  assert issues == []