claude-dev-env 2.12.0 → 2.14.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 (399) hide show
  1. package/AGENTS.md +61 -0
  2. package/CLAUDE.md +1 -57
  3. package/_shared/AGENTS.md +15 -0
  4. package/_shared/CLAUDE.md +1 -15
  5. package/_shared/advisor/AGENTS.md +22 -0
  6. package/_shared/advisor/CLAUDE.md +1 -22
  7. package/_shared/pr-loop/AGENTS.md +27 -0
  8. package/_shared/pr-loop/CLAUDE.md +1 -27
  9. package/_shared/pr-loop/scripts/AGENTS.md +35 -0
  10. package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
  11. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
  13. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
  14. package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
  15. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
  16. package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
  17. package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
  18. package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
  19. package/_shared/process-tree/AGENTS.md +41 -0
  20. package/_shared/process-tree/CLAUDE.md +1 -41
  21. package/agents/AGENTS.md +31 -0
  22. package/agents/CLAUDE.md +1 -32
  23. package/agents/clean-coder.md +6 -6
  24. package/agents/pr-description-writer.md +11 -81
  25. package/agents/test_agent_frontmatter.py +4 -4
  26. package/audit-rubrics/AGENTS.md +43 -0
  27. package/audit-rubrics/CLAUDE.md +1 -43
  28. package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
  29. package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
  30. package/audit-rubrics/prompts/AGENTS.md +37 -0
  31. package/audit-rubrics/prompts/CLAUDE.md +1 -37
  32. package/bin/AGENTS.md +112 -0
  33. package/bin/CLAUDE.md +1 -112
  34. package/bin/ever-shipped-skills.mjs +1 -0
  35. package/bin/install-constants.mjs +6 -7
  36. package/bin/install.mjs +71 -13
  37. package/bin/install.prune.test.mjs +26 -0
  38. package/bin/install.settings-defaults.test.mjs +60 -33
  39. package/bin/install.test.mjs +36 -4
  40. package/commands/AGENTS.md +23 -0
  41. package/commands/CLAUDE.md +1 -23
  42. package/commands/hook-log-extract.md +3 -3
  43. package/commands/sr-loop.md +9 -5
  44. package/docs/AGENTS.md +32 -0
  45. package/docs/CLAUDE.md +1 -33
  46. package/docs/CODE_RULES.md +1 -1
  47. package/docs/imagegen.md +22 -0
  48. package/docs/references/AGENTS.md +17 -0
  49. package/docs/references/CLAUDE.md +1 -18
  50. package/hooks/AGENTS.md +31 -0
  51. package/hooks/CLAUDE.md +1 -31
  52. package/hooks/_gh_pr_author_swap_utils.py +14 -0
  53. package/hooks/advisory/AGENTS.md +16 -0
  54. package/hooks/advisory/CLAUDE.md +1 -16
  55. package/hooks/blocking/AGENTS.md +123 -0
  56. package/hooks/blocking/CLAUDE.md +1 -148
  57. package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
  58. package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
  59. package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
  60. package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
  61. package/hooks/blocking/code_rules_probe_chains.py +6 -2
  62. package/hooks/blocking/config/AGENTS.md +10 -0
  63. package/hooks/blocking/config/CLAUDE.md +1 -22
  64. package/hooks/blocking/conventional_pr_title_gate.py +1 -2
  65. package/hooks/blocking/gh_pr_author_restore.py +7 -2
  66. package/hooks/blocking/intent_only_ending_blocker.py +11 -16
  67. package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
  68. package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
  69. package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
  70. package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
  71. package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
  72. package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
  73. package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
  74. package/hooks/blocking/stop_dispatcher.py +4 -4
  75. package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
  76. package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
  77. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
  78. package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
  79. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
  80. package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
  81. package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
  82. package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
  83. package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
  84. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
  85. package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
  86. package/hooks/diagnostic/AGENTS.md +43 -0
  87. package/hooks/diagnostic/CLAUDE.md +1 -43
  88. package/hooks/diagnostic/hook_log_extractor.py +4 -38
  89. package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
  90. package/hooks/diagnostic/migrations/AGENTS.md +16 -0
  91. package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
  92. package/hooks/diagnostic/queries/AGENTS.md +19 -0
  93. package/hooks/diagnostic/queries/CLAUDE.md +1 -19
  94. package/hooks/diagnostic/test_hook_log_extractor.py +10 -23
  95. package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
  96. package/hooks/git-hooks/AGENTS.md +31 -0
  97. package/hooks/git-hooks/CLAUDE.md +1 -31
  98. package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
  99. package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
  100. package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -12
  101. package/hooks/git-hooks/pre_push.py +49 -118
  102. package/hooks/git-hooks/test_pre_push.py +111 -137
  103. package/hooks/hooks.json +0 -35
  104. package/hooks/hooks_constants/AGENTS.md +104 -0
  105. package/hooks/hooks_constants/CLAUDE.md +1 -113
  106. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
  107. package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
  108. package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
  109. package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
  110. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
  111. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
  112. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
  113. package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
  114. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
  115. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
  116. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
  117. package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
  118. package/hooks/lifecycle/AGENTS.md +18 -0
  119. package/hooks/lifecycle/CLAUDE.md +1 -20
  120. package/hooks/observability/AGENTS.md +20 -0
  121. package/hooks/observability/CLAUDE.md +1 -20
  122. package/hooks/session/AGENTS.md +33 -0
  123. package/hooks/session/CLAUDE.md +1 -33
  124. package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
  125. package/hooks/session/task_list_loop_starter.py +3 -3
  126. package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
  127. package/hooks/session/test_task_list_loop_starter.py +10 -2
  128. package/hooks/session/test_working_style_prompt.py +9 -4
  129. package/hooks/validation/AGENTS.md +20 -0
  130. package/hooks/validation/CLAUDE.md +1 -20
  131. package/hooks/validators/AGENTS.md +51 -0
  132. package/hooks/validators/CLAUDE.md +1 -51
  133. package/hooks/validators/health_check.py +52 -19
  134. package/hooks/validators/python_style_checks.py +1 -1
  135. package/hooks/validators/test_health_check.py +112 -27
  136. package/hooks/workflow/AGENTS.md +16 -0
  137. package/hooks/workflow/CLAUDE.md +1 -16
  138. package/installable-surfaces.manifest.json +1 -0
  139. package/output-styles/AGENTS.md +15 -0
  140. package/output-styles/CLAUDE.md +1 -15
  141. package/package.json +2 -1
  142. package/rules/AGENTS.md +61 -0
  143. package/rules/CLAUDE.md +1 -63
  144. package/rules/code-standards.md +5 -9
  145. package/rules/doc-prose-cuts.md +1 -1
  146. package/rules/gh-cli-conventions.md +0 -1
  147. package/rules/git-workflow.md +1 -3
  148. package/scripts/AGENTS.md +62 -0
  149. package/scripts/CLAUDE.md +1 -63
  150. package/scripts/_code_review_test_support.py +0 -95
  151. package/scripts/codex_compat_materializer.py +4 -0
  152. package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
  153. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
  154. package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
  155. package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
  156. package/scripts/invoke_code_review.py +8 -451
  157. package/scripts/sync_to_cursor/AGENTS.md +23 -0
  158. package/scripts/sync_to_cursor/CLAUDE.md +1 -23
  159. package/scripts/test_invoke_code_review.py +5 -61
  160. package/scripts/test_invoke_code_review_cli.py +1 -45
  161. package/scripts/test_invoke_code_review_contract.py +1 -118
  162. package/scripts/test_validate_instruction_pairs.py +90 -0
  163. package/scripts/test_verify_installable_package.py +5 -1
  164. package/scripts/tests/AGENTS.md +33 -0
  165. package/scripts/tests/CLAUDE.md +1 -33
  166. package/scripts/tests/test_codex_compat_materializer.py +36 -1
  167. package/scripts/validate_instruction_pairs.py +183 -0
  168. package/settings.json +1 -10
  169. package/skills/AGENTS.md +72 -0
  170. package/skills/CLAUDE.md +1 -64
  171. package/skills/_shared/AGENTS.md +44 -0
  172. package/skills/_shared/CLAUDE.md +1 -44
  173. package/skills/_shared/advisor/AGENTS.md +9 -0
  174. package/skills/_shared/advisor/CLAUDE.md +1 -9
  175. package/skills/_shared/pr-loop/AGENTS.md +50 -0
  176. package/skills/_shared/pr-loop/CLAUDE.md +1 -50
  177. package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
  178. package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
  179. package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
  180. package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
  181. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
  182. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
  183. package/skills/anthropic-plan/AGENTS.md +34 -0
  184. package/skills/anthropic-plan/CLAUDE.md +1 -34
  185. package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
  186. package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
  187. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
  188. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
  189. package/skills/anthropic-plan/templates/AGENTS.md +13 -0
  190. package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
  191. package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
  192. package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
  193. package/skills/auditing-claude-config/AGENTS.md +21 -0
  194. package/skills/auditing-claude-config/CLAUDE.md +1 -21
  195. package/skills/autoconverge/AGENTS.md +36 -0
  196. package/skills/autoconverge/CLAUDE.md +1 -36
  197. package/skills/autoconverge/reference/AGENTS.md +16 -0
  198. package/skills/autoconverge/reference/CLAUDE.md +1 -16
  199. package/skills/autoconverge/reference/convergence.md +7 -7
  200. package/skills/autoconverge/reference/gotchas.md +3 -10
  201. package/skills/autoconverge/workflow/AGENTS.md +26 -0
  202. package/skills/autoconverge/workflow/CLAUDE.md +1 -26
  203. package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
  204. package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
  205. package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
  206. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
  207. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
  208. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
  209. package/skills/autoconverge/workflow/converge.mjs +201 -238
  210. package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
  211. package/skills/bugteam/AGENTS.md +30 -0
  212. package/skills/bugteam/CLAUDE.md +1 -30
  213. package/skills/bugteam/CONSTRAINTS.md +1 -1
  214. package/skills/bugteam/SKILL.md +9 -0
  215. package/skills/bugteam/reference/AGENTS.md +20 -0
  216. package/skills/bugteam/reference/CLAUDE.md +1 -20
  217. package/skills/bugteam/reference/audit-and-teammates.md +10 -6
  218. package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
  219. package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
  220. package/skills/bugteam/scripts/AGENTS.md +30 -0
  221. package/skills/bugteam/scripts/CLAUDE.md +1 -30
  222. package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
  223. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
  224. package/skills/bugteam/test_skill_additions.py +9 -0
  225. package/skills/closeout/reference/handoff-prompt-template.md +1 -1
  226. package/skills/codex-review/AGENTS.md +46 -0
  227. package/skills/codex-review/CLAUDE.md +1 -46
  228. package/skills/codex-review/reference/AGENTS.md +15 -0
  229. package/skills/codex-review/reference/CLAUDE.md +1 -15
  230. package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
  231. package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
  232. package/skills/codex-review/test_skill_scaffold.py +3 -3
  233. package/skills/comments/SKILL.md +65 -0
  234. package/skills/copilot-review/AGENTS.md +18 -0
  235. package/skills/copilot-review/CLAUDE.md +1 -18
  236. package/skills/descriptions/SKILL.md +51 -0
  237. package/skills/emergencies/SKILL.md +42 -0
  238. package/skills/everything-search/AGENTS.md +17 -0
  239. package/skills/everything-search/CLAUDE.md +1 -17
  240. package/skills/fresh-branch/AGENTS.md +14 -0
  241. package/skills/fresh-branch/CLAUDE.md +1 -14
  242. package/skills/grok-spawn/AGENTS.md +28 -0
  243. package/skills/grok-spawn/CLAUDE.md +1 -28
  244. package/skills/orchestrator/SKILL.md +2 -4
  245. package/skills/plan-to-pr/SKILL.md +6 -7
  246. package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
  247. package/skills/plan-to-pr/reference/process-inventory.md +2 -2
  248. package/skills/plan-to-pr/reference/review-loop.md +2 -2
  249. package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
  250. package/skills/plan-to-pr/reference/task-seeds.md +1 -1
  251. package/skills/plan-to-pr/reference/task-ticket.md +3 -4
  252. package/skills/plan-to-pr/scripts/config/constants.py +1 -2
  253. package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
  254. package/skills/plan-to-pr/test_skill_contract.py +2 -2
  255. package/skills/pr-converge/AGENTS.md +32 -0
  256. package/skills/pr-converge/CLAUDE.md +1 -32
  257. package/skills/pr-converge/SKILL.md +13 -16
  258. package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
  259. package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
  260. package/skills/pr-converge/reference/AGENTS.md +28 -0
  261. package/skills/pr-converge/reference/CLAUDE.md +1 -28
  262. package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
  263. package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
  264. package/skills/pr-converge/reference/progress-checklist.md +6 -5
  265. package/skills/pr-converge/reference/state-schema.md +1 -27
  266. package/skills/pr-converge/scripts/AGENTS.md +46 -0
  267. package/skills/pr-converge/scripts/CLAUDE.md +1 -46
  268. package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
  269. package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
  270. package/skills/pr-converge/workflows/AGENTS.md +16 -0
  271. package/skills/pr-converge/workflows/CLAUDE.md +1 -16
  272. package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
  273. package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
  274. package/skills/pr-loop-lifecycle/SKILL.md +1 -1
  275. package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
  276. package/skills/prototype/SKILL.md +4 -4
  277. package/skills/prototype/reference/honest-limitations.md +5 -5
  278. package/skills/prototype/reference/promotion-tasks.md +2 -2
  279. package/skills/prototype/workflows/promotion.md +4 -6
  280. package/skills/rebase/AGENTS.md +32 -0
  281. package/skills/rebase/CLAUDE.md +1 -32
  282. package/skills/recall/AGENTS.md +30 -0
  283. package/skills/recall/CLAUDE.md +1 -30
  284. package/skills/remember/AGENTS.md +31 -0
  285. package/skills/remember/CLAUDE.md +1 -31
  286. package/skills/reviews/SKILL.md +85 -0
  287. package/skills/session-log/AGENTS.md +32 -0
  288. package/skills/session-log/CLAUDE.md +1 -32
  289. package/skills/session-tidy/AGENTS.md +36 -0
  290. package/skills/session-tidy/CLAUDE.md +1 -36
  291. package/skills/skill-builder/AGENTS.md +49 -0
  292. package/skills/skill-builder/CLAUDE.md +1 -49
  293. package/skills/skill-builder/references/AGENTS.md +25 -0
  294. package/skills/skill-builder/references/CLAUDE.md +1 -25
  295. package/skills/skill-builder/references/deterministic-elements.md +1 -1
  296. package/skills/skill-builder/templates/AGENTS.md +14 -0
  297. package/skills/skill-builder/templates/CLAUDE.md +1 -14
  298. package/skills/skill-builder/workflows/AGENTS.md +19 -0
  299. package/skills/skill-builder/workflows/CLAUDE.md +1 -19
  300. package/skills/small-cl/SKILL.md +52 -0
  301. package/skills/task-build/AGENTS.md +29 -0
  302. package/skills/task-build/CLAUDE.md +1 -29
  303. package/skills/update/AGENTS.md +38 -0
  304. package/skills/update/CLAUDE.md +1 -38
  305. package/system-prompts/AGENTS.md +17 -0
  306. package/system-prompts/CLAUDE.md +1 -17
  307. package/system-prompts/software-engineer.xml +3 -3
  308. package/agents/code-verifier.md +0 -74
  309. package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
  310. package/docs/references/code-review-enforcement.md +0 -132
  311. package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
  312. package/hooks/blocking/code_review_gate_deny.py +0 -74
  313. package/hooks/blocking/code_review_pr_create_gate.py +0 -198
  314. package/hooks/blocking/code_review_push_gate.py +0 -145
  315. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
  316. package/hooks/blocking/code_review_stamp_store.py +0 -233
  317. package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
  318. package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
  319. package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
  320. package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
  321. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
  322. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
  323. package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
  324. package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
  325. package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
  326. package/hooks/blocking/config/verified_commit_constants.py +0 -160
  327. package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
  328. package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
  329. package/hooks/blocking/conftest.py +0 -123
  330. package/hooks/blocking/convergence_gate_blocker.py +0 -310
  331. package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
  332. package/hooks/blocking/pr_description_body_audit.py +0 -148
  333. package/hooks/blocking/pr_description_command_parser.py +0 -237
  334. package/hooks/blocking/pr_description_enforcer.py +0 -227
  335. package/hooks/blocking/pr_description_pr_number.py +0 -155
  336. package/hooks/blocking/pr_description_proof_of_work.py +0 -385
  337. package/hooks/blocking/pr_description_readability.py +0 -364
  338. package/hooks/blocking/reviewer_spawn_gate.py +0 -182
  339. package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
  340. package/hooks/blocking/test_code_review_gate_deny.py +0 -54
  341. package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
  342. package/hooks/blocking/test_code_review_push_gate.py +0 -205
  343. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
  344. package/hooks/blocking/test_code_review_stamp_store.py +0 -205
  345. package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
  346. package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
  347. package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
  348. package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
  349. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
  350. package/hooks/blocking/test_pr_description_enforcer.py +0 -221
  351. package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
  352. package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
  353. package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
  354. package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
  355. package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
  356. package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
  357. package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
  358. package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
  359. package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
  360. package/hooks/blocking/test_verification_verdict_store.py +0 -974
  361. package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
  362. package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
  363. package/hooks/blocking/test_verified_commit_gate.py +0 -581
  364. package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
  365. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
  366. package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
  367. package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
  368. package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
  369. package/hooks/blocking/verification_verdict_store.py +0 -1039
  370. package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
  371. package/hooks/blocking/verified_commit_gate.py +0 -113
  372. package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
  373. package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
  374. package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
  375. package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
  376. package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
  377. package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
  378. package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
  379. package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
  380. package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
  381. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
  382. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
  383. package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
  384. package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
  385. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
  386. package/hooks/blocking/verifier_verdict_minter.py +0 -280
  387. package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
  388. package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
  389. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
  390. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
  391. package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
  392. package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
  393. package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
  394. package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
  395. package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
  396. package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
  397. package/rules/proof-of-work-pr-comments.md +0 -22
  398. package/rules/verified-commit-gate-skip.md +0 -4
  399. package/scripts/Show-Asset.ps1 +0 -106
@@ -1,4 +1,8 @@
1
- """Attribute-chain and os.environ alias-resolution primitives for the test-isolation check."""
1
+ """Attribute-chain and os.environ alias-resolution primitives.
2
+
3
+ Serves the test-isolation check, and lends ``_dotted_attribute_chain`` to the
4
+ dead-module-constant check's widened attribute-read scan.
5
+ """
2
6
 
3
7
  import ast
4
8
  import sys
@@ -143,7 +147,7 @@ def _attribute_chain_resolves_to_os_environ(
143
147
  return canonical_chain == OS_ENVIRON_DOTTED_NAME
144
148
 
145
149
 
146
- def _dotted_attribute_chain(attribute_node: ast.Attribute) -> str | None:
150
+ def _dotted_attribute_chain(attribute_node: ast.expr) -> str | None:
147
151
  chain_parts: list[str] = []
148
152
  walker: ast.expr = attribute_node
149
153
  while isinstance(walker, ast.Attribute):
@@ -0,0 +1,10 @@
1
+ # hooks/blocking/config
2
+
3
+ A Python package that holds shared constants for blocking hooks. Opinionated prose-style gates import from here.
4
+
5
+ ## Key files
6
+
7
+ | File | Contents |
8
+ |---|---|
9
+ | `__init__.py` | Declares this as a regular package (not a namespace package) so it resolves first on `sys.path` |
10
+ | `prose_style_enforcement_constants.py` | `CLAUDE_PROSE_STYLE_ENFORCEMENT` opt-in (default off) for opinionated prose gates |
@@ -1,22 +1 @@
1
- # hooks/blocking/config
2
-
3
- A Python package that holds shared constants for blocking hooks. Verified-commit gate modules and opinionated prose-style gates import from here.
4
-
5
- ## Key files
6
-
7
- | File | Contents |
8
- |---|---|
9
- | `__init__.py` | Declares this as a regular package (not a namespace package) so it resolves first on `sys.path` |
10
- | `code_review_enforcement_constants.py` | Stamp and effort tunables for the code-review enforcement gates |
11
- | `prose_style_enforcement_constants.py` | `CLAUDE_PROSE_STYLE_ENFORCEMENT` opt-in (default off) for opinionated prose gates |
12
- | `verified_commit_constants.py` | All tunables for the gate: directory names, regex patterns for detecting verdict paths and obfuscation attempts, timeout values, git subcommand sets, bypass marker, and corrective messages |
13
- | `verified_commit_context_constants.py` | `VERIFY_SKIP_ADDITIONAL_CONTEXT`, the ``# verify-skip`` usage rule the gate attaches to a deny payload's `additionalContext` |
14
- | `verified_commit_gate_output_constants.py` | `PRE_TOOL_USE_HOOK_EVENT_NAME` and `DENY_PERMISSION_DECISION` (the deny payload's event name and decision string), `GATE_HOOK_MODULE_NAME` (the gate's own module name for block logging), and `REGEX_ALTERNATION_SEPARATOR` (the `\|` join for the directory-change verb alternation in `gated_invocations.py`) |
15
-
16
- ## Key constants in `verified_commit_constants.py`
17
-
18
- - `VERIFICATION_BYPASS_MARKER` — the `# verify-skip` comment that exempts a single commit/push from the gate
19
- - `MINTING_AGENT_TYPE` — `"code-verifier"`, the agent type whose SubagentStop hook mints verdicts
20
- - `VERDICT_DIRECTORY_NAME` — `"verification"`, the directory under `~/.claude/` that holds verdict JSON files
21
- - `DOCS_ONLY_EXTENSIONS` — extensions (`.md`, `.txt`, images) whose changes are mechanically exempt from the gate
22
- - `CORRECTIVE_MESSAGE` / `VERDICT_DIRECTORY_GUARD_MESSAGE` — user-facing block messages
1
+ @AGENTS.md
@@ -36,8 +36,6 @@ _hooks_dir = str(Path(__file__).resolve().parent.parent)
36
36
  if _hooks_dir not in sys.path:
37
37
  sys.path.insert(0, _hooks_dir)
38
38
 
39
- from verification_verdict_store import resolve_repo_root # noqa: E402
40
-
41
39
  from blocking._gh_body_arg_utils import ( # noqa: E402
42
40
  all_value_flags,
43
41
  count_extra_tokens_to_skip_for_split_quoted_value,
@@ -68,6 +66,7 @@ from hooks_constants.conventional_pr_title_gate_constants import ( # noqa: E402
68
66
  YAML_LIST_ITEM_PREFIX,
69
67
  )
70
68
  from hooks_constants.hook_block_logger import log_hook_block # noqa: E402
69
+ from hooks_constants.project_paths_reader import find_git_root as resolve_repo_root # noqa: E402
71
70
 
72
71
 
73
72
  def _matches_gh_pr_title_subcommand(command: str) -> bool:
@@ -36,6 +36,7 @@ if hooks_parent_directory not in sys.path:
36
36
  sys.path.insert(0, hooks_parent_directory)
37
37
 
38
38
  from _gh_pr_author_swap_utils import ( # noqa: E402
39
+ _build_restore_failure_message,
39
40
  _command_invokes_gh_pr_create_in_stripped,
40
41
  _delete_state_file,
41
42
  _preprocess_command_for_matching,
@@ -89,8 +90,12 @@ def main() -> None:
89
90
  _delete_state_file(state_file)
90
91
  else:
91
92
  _write_line(
92
- f"[gh-pr-author-restore] failed to restore active gh account to {original_account!r}; "
93
- f"state file {state_file} left in place so the SessionStart cleanup hook can retry",
93
+ _build_restore_failure_message(
94
+ "gh-pr-author-restore",
95
+ original_account,
96
+ state_file,
97
+ "state file",
98
+ ),
94
99
  sys.stderr,
95
100
  )
96
101
  sys.exit(0)
@@ -1,12 +1,10 @@
1
1
  #!/usr/bin/env python3
2
- """
3
- Stop hook that blocks Claude responses ending on a promise about undone work.
2
+ """Stop hook that blocks a turn ending with a promise of future work.
4
3
 
5
- When a turn ends on a forward-looking statement of intent ("I'll now run the
6
- tests", "Let me implement the fix") instead of actually doing the work, the
7
- agent is forced to do the work now with tool calls, or - when genuinely blocked
8
- on input only the user can supply - route through AskUserQuestion and end
9
- cleanly. The rule name is long-horizon-autonomy.
4
+ When a turn ends with a forward-looking statement of intent ("I'll now run the
5
+ tests", "Let me implement the fix"), complete the work with tool calls during
6
+ the turn. Route work requiring user-only input through AskUserQuestion. The
7
+ rule name is long-horizon-autonomy.
10
8
  """
11
9
 
12
10
  import json
@@ -104,7 +102,7 @@ def find_intent_only_ending(text: str) -> bool:
104
102
 
105
103
 
106
104
  def main() -> None:
107
- """Read the stop-hook payload and block turns that end on a promise of undone work."""
105
+ """Read the stop-hook payload and block turns that promise future work."""
108
106
  try:
109
107
  hook_input = json.load(sys.stdin)
110
108
  except json.JSONDecodeError:
@@ -125,14 +123,11 @@ def main() -> None:
125
123
  sys.exit(0)
126
124
 
127
125
  block_reason = (
128
- "LONG-HORIZON-AUTONOMY GUARDRAIL: Your turn ends on a promise about work "
129
- "that is not yet done, rather than doing it. Do the work NOW with tool calls "
130
- "instead of describing what you are about to do.\n\n"
131
- "If the work is genuinely blocked on input only the user can give, route the "
132
- "ask through an AskUserQuestion tool call and end the turn cleanly. Otherwise, "
133
- "carry out the stated action this turn.\n\n"
134
- "You MUST re-output the complete response with the work actually performed, "
135
- "per the long-horizon-autonomy rule."
126
+ "LONG-HORIZON-AUTONOMY GUARDRAIL: This turn ends with a promise of future "
127
+ "work. Complete that work with tool calls during this turn. Route questions "
128
+ "requiring user-only input through AskUserQuestion, then end the turn cleanly.\n\n"
129
+ "Re-output the complete response with the work performed, per the "
130
+ "long-horizon-autonomy rule."
136
131
  )
137
132
  block_response = {
138
133
  "decision": "block",
@@ -0,0 +1,26 @@
1
+ # inventory_intent_records
2
+
3
+ The shared pending-intent store that lets `package_inventory_stale_blocker.py`
4
+ and `claude_md_orphan_file_blocker.py` add a new file and its inventory row in
5
+ one change, in either order. When one blocker denies, it records a note; the
6
+ sibling blocker reads that note to allow the matching second write.
7
+
8
+ ## Modules
9
+
10
+ | File | Purpose |
11
+ |---|---|
12
+ | `records.py` | Read, record, peek, and consume the per-session file and row intents; a missing or corrupt store reads as no notes |
13
+ | `__init__.py` | Package marker |
14
+
15
+ ## Subdirectories
16
+
17
+ | Entry | Description |
18
+ |---|---|
19
+ | `config/` | The records-file name shape, the freshness window, the list keys, and the note field names (`intent_records_constants.py`) |
20
+ | `tests/` | pytest suite for the records store |
21
+
22
+ ## Running tests
23
+
24
+ ```bash
25
+ python -m pytest packages/claude-dev-env/hooks/blocking/inventory_intent_records/tests/
26
+ ```
@@ -1,26 +1 @@
1
- # inventory_intent_records
2
-
3
- The shared pending-intent store that lets `package_inventory_stale_blocker.py`
4
- and `claude_md_orphan_file_blocker.py` add a new file and its inventory row in
5
- one change, in either order. When one blocker denies, it records a note; the
6
- sibling blocker reads that note to allow the matching second write.
7
-
8
- ## Modules
9
-
10
- | File | Purpose |
11
- |---|---|
12
- | `records.py` | Read, record, peek, and consume the per-session file and row intents; a missing or corrupt store reads as no notes |
13
- | `__init__.py` | Package marker |
14
-
15
- ## Subdirectories
16
-
17
- | Entry | Description |
18
- |---|---|
19
- | `config/` | The records-file name shape, the freshness window, the list keys, and the note field names (`intent_records_constants.py`) |
20
- | `tests/` | pytest suite for the records store |
21
-
22
- ## Running tests
23
-
24
- ```bash
25
- python -m pytest packages/claude-dev-env/hooks/blocking/inventory_intent_records/tests/
26
- ```
1
+ @AGENTS.md
@@ -0,0 +1,26 @@
1
+ # package_inventory_stale_blocker_parts
2
+
3
+ The concern modules `package_inventory_stale_blocker.py` wires together to block a
4
+ new production file its package inventory omits. The entry hook imports them and
5
+ re-exports their surface for the test suite.
6
+
7
+ ## Modules
8
+
9
+ | File | Purpose |
10
+ |---|---|
11
+ | `inventory_detection.py` | Surveys a directory's `README.md`/`CLAUDE.md`/`SKILL.md`, collects the filenames they name, and reports whether a maintained inventory omits the file being written |
12
+ | `decision.py` | Builds the deny payload naming the omitted file and closing with the retry hint, and emits the decision JSON |
13
+ | `__init__.py` | Package marker |
14
+
15
+ ## Subdirectories
16
+
17
+ | Entry | Description |
18
+ |---|---|
19
+ | `config/` | The retry hint the deny reason closes with and the inventory-name join separator (`inventory_blocker_constants.py`) |
20
+ | `tests/` | pytest suite with one test module per module above |
21
+
22
+ ## Running tests
23
+
24
+ ```bash
25
+ python -m pytest packages/claude-dev-env/hooks/blocking/package_inventory_stale_blocker_parts/tests/
26
+ ```
@@ -1,26 +1 @@
1
- # package_inventory_stale_blocker_parts
2
-
3
- The concern modules `package_inventory_stale_blocker.py` wires together to block a
4
- new production file its package inventory omits. The entry hook imports them and
5
- re-exports their surface for the test suite.
6
-
7
- ## Modules
8
-
9
- | File | Purpose |
10
- |---|---|
11
- | `inventory_detection.py` | Surveys a directory's `README.md`/`CLAUDE.md`/`SKILL.md`, collects the filenames they name, and reports whether a maintained inventory omits the file being written |
12
- | `decision.py` | Builds the deny payload naming the omitted file and closing with the retry hint, and emits the decision JSON |
13
- | `__init__.py` | Package marker |
14
-
15
- ## Subdirectories
16
-
17
- | Entry | Description |
18
- |---|---|
19
- | `config/` | The retry hint the deny reason closes with and the inventory-name join separator (`inventory_blocker_constants.py`) |
20
- | `tests/` | pytest suite with one test module per module above |
21
-
22
- ## Running tests
23
-
24
- ```bash
25
- python -m pytest packages/claude-dev-env/hooks/blocking/package_inventory_stale_blocker_parts/tests/
26
- ```
1
+ @AGENTS.md
@@ -0,0 +1,24 @@
1
+ # pii_prevention_blocker_parts
2
+
3
+ The concern modules `pii_prevention_blocker.py` wires together. The entry hook
4
+ imports them and re-exports their surface for the test suite.
5
+
6
+ ## Modules
7
+
8
+ | File | Purpose |
9
+ |---|---|
10
+ | `repository_exemption.py` | Resolves a commit's origin owner/repo slug, decides whether the repository skips the staged PII scan, and resolves the exact values that repository allows past the scan |
11
+ | `repository_resolution.py` | Reads the repository a commit command targets — composing multiple `-C` values and a leading `cd`/`pushd` — and builds the deny reason naming the path when the repository root does not resolve |
12
+ | `__init__.py` | Package marker |
13
+
14
+ ## Subdirectories
15
+
16
+ | Entry | Description |
17
+ |---|---|
18
+ | `config/` | The repository-resolution deny-message template and the session-cwd label (`repository_resolution_constants.py`) |
19
+
20
+ ## Running tests
21
+
22
+ ```bash
23
+ python -m pytest packages/claude-dev-env/hooks/blocking/tests/
24
+ ```
@@ -1,24 +1 @@
1
- # pii_prevention_blocker_parts
2
-
3
- The concern modules `pii_prevention_blocker.py` wires together. The entry hook
4
- imports them and re-exports their surface for the test suite.
5
-
6
- ## Modules
7
-
8
- | File | Purpose |
9
- |---|---|
10
- | `repository_exemption.py` | Resolves a commit's origin owner/repo slug, decides whether the repository skips the staged PII scan, and resolves the exact values that repository allows past the scan |
11
- | `repository_resolution.py` | Reads the repository a commit command targets — composing multiple `-C` values and a leading `cd`/`pushd` — and builds the deny reason naming the path when the repository root does not resolve |
12
- | `__init__.py` | Package marker |
13
-
14
- ## Subdirectories
15
-
16
- | Entry | Description |
17
- |---|---|
18
- | `config/` | The repository-resolution deny-message template and the session-cwd label (`repository_resolution_constants.py`) |
19
-
20
- ## Running tests
21
-
22
- ```bash
23
- python -m pytest packages/claude-dev-env/hooks/blocking/tests/
24
- ```
1
+ @AGENTS.md
@@ -3,7 +3,7 @@
3
3
 
4
4
  SendUserFile attaches a file to the session. While the user is at the terminal
5
5
  (status "normal" or unset) an attach does not let them see the file — it must
6
- open on screen in its own viewer via Show-Asset.ps1. The one attach allowed
6
+ open on screen in its native Windows app. The one attach allowed
7
7
  through is an away-from-desk phone push (status "proactive").
8
8
  """
9
9
 
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env python3
2
- """Stop-hook dispatcher that hosts the six Stop-chain hooks in one process.
2
+ """Stop-hook dispatcher that hosts the Stop-chain blockers in one process.
3
3
 
4
4
  Reads the Stop payload from stdin once, runs each hosted hook in registration
5
5
  order via the shared hosted-hook runner, and emits the first block decision the
6
- chain produced. Later hooks still run so side-effect hooks (the log extractor
7
- wrapper) fire even when an earlier hook blocked. A single hosted hook crash
8
- fails open and does not suppress the remaining hooks.
6
+ chain produced. Later hooks still run after an earlier block so every hosted
7
+ hook gets a chance to run. A single hosted hook crash fails open and does not
8
+ suppress the remaining hooks.
9
9
  """
10
10
 
11
11
  from __future__ import annotations
@@ -0,0 +1,30 @@
1
+ # tdd_enforcer_parts
2
+
3
+ The concern modules `tdd_enforcer.py` wires together to run the TDD gate. Each
4
+ module owns one concern; the entry hook imports them and re-exports their
5
+ surface for the test suite.
6
+
7
+ ## Modules
8
+
9
+ | File | Purpose |
10
+ |---|---|
11
+ | `path_classification.py` | Classifies a write target (docs, tests, `.claude` trees) the gate skips, and extracts the written text from a Write, Edit, or MultiEdit payload |
12
+ | `content_analysis.py` | Decides whether a payload is constants-only, and whether an Edit or MultiEdit merely removes or reorders imports |
13
+ | `candidate_paths.py` | Resolves the candidate test files whose freshness can satisfy the gate for a production file |
14
+ | `freshness.py` | Checks whether a candidate test was modified within the window and holds a real test function |
15
+ | `git_tracking.py` | Detects a write that restores a git-tracked file absent on disk, so a remove-then-Write rewrite is exempt from the gate |
16
+ | `decisions.py` | Builds the deny reason and writes the allow or deny decision JSON to stdout |
17
+ | `__init__.py` | Package marker |
18
+
19
+ ## Subdirectories
20
+
21
+ | Entry | Description |
22
+ |---|---|
23
+ | `config/` | The freshness window, the ancestor-walk limit, the git-tracking command tokens, the source-file extension sets, and the join separator (`tdd_enforcer_constants.py`) |
24
+ | `tests/` | pytest suite with one test module per module above |
25
+
26
+ ## Running tests
27
+
28
+ ```bash
29
+ python -m pytest packages/claude-dev-env/hooks/blocking/tdd_enforcer_parts/tests/
30
+ ```
@@ -1,30 +1 @@
1
- # tdd_enforcer_parts
2
-
3
- The concern modules `tdd_enforcer.py` wires together to run the TDD gate. Each
4
- module owns one concern; the entry hook imports them and re-exports their
5
- surface for the test suite.
6
-
7
- ## Modules
8
-
9
- | File | Purpose |
10
- |---|---|
11
- | `path_classification.py` | Classifies a write target (docs, tests, `.claude` trees) the gate skips, and extracts the written text from a Write, Edit, or MultiEdit payload |
12
- | `content_analysis.py` | Decides whether a payload is constants-only, and whether an Edit or MultiEdit merely removes or reorders imports |
13
- | `candidate_paths.py` | Resolves the candidate test files whose freshness can satisfy the gate for a production file |
14
- | `freshness.py` | Checks whether a candidate test was modified within the window and holds a real test function |
15
- | `git_tracking.py` | Detects a write that restores a git-tracked file absent on disk, so a remove-then-Write rewrite is exempt from the gate |
16
- | `decisions.py` | Builds the deny reason and writes the allow or deny decision JSON to stdout |
17
- | `__init__.py` | Package marker |
18
-
19
- ## Subdirectories
20
-
21
- | Entry | Description |
22
- |---|---|
23
- | `config/` | The freshness window, the ancestor-walk limit, the git-tracking command tokens, the source-file extension sets, and the join separator (`tdd_enforcer_constants.py`) |
24
- | `tests/` | pytest suite with one test module per module above |
25
-
26
- ## Running tests
27
-
28
- ```bash
29
- python -m pytest packages/claude-dev-env/hooks/blocking/tdd_enforcer_parts/tests/
30
- ```
1
+ @AGENTS.md
@@ -221,9 +221,6 @@ def test_powershell_selects_the_shared_hooks_in_registration_order() -> None:
221
221
  assert powershell_paths == [
222
222
  "blocking/unscoped_search_blocker.py",
223
223
  "blocking/pii_prevention_blocker.py",
224
- "blocking/code_review_push_gate.py",
225
- "blocking/code_review_pr_create_gate.py",
226
- "blocking/code_review_stamp_directory_write_blocker.py",
227
224
  ]
228
225
 
229
226
 
@@ -1,6 +1,6 @@
1
1
  """Tests for check_banned_prefixes — flags function names with generic prefixes.
2
2
 
3
- CODE_RULES.md §5 / AGENTS.md "Naming → Function names use specific verbs:
3
+ CODE_RULES.md §5 "Naming → Function names use specific verbs:
4
4
  parse_invoice, dispatch_event, migrate_schema. Generic prefixes to replace:
5
5
  handle_, process_, manage_, do_."
6
6
 
@@ -506,3 +506,174 @@ def test_dead_constant_stays_denied_on_every_attempt(neutral_root: Path) -> None
506
506
  "re-issue this write" in each_issue for each_issue in each_attempt
507
507
  ), f"A dead constant stays denied with the retry escape, got: {each_attempt}"
508
508
 
509
+
510
+ ALIAS_CONSTANTS_BODY = 'BASE_PROMPTS_DIRECTORY_NAME = "prompts"\nSTYLE_SHEET_FILENAME = "style.css"\n'
511
+
512
+ ALIASED_IMPORT_CONSUMER_BODY = (
513
+ "from style_guide_gen_constants.config import constants as sg\n"
514
+ "\n"
515
+ "def prompts_directory() -> str:\n"
516
+ " return sg.BASE_PROMPTS_DIRECTORY_NAME\n"
517
+ "\n"
518
+ "def style_sheet() -> str:\n"
519
+ " return sg.STYLE_SHEET_FILENAME\n"
520
+ )
521
+
522
+
523
+ def _build_alias_repository(
524
+ package_parent: Path,
525
+ consumer_directory: Path,
526
+ consumer_body: str,
527
+ ) -> Path:
528
+ package_directory = package_parent / "style_guide_gen_constants"
529
+ config_directory = package_directory / "config"
530
+ config_directory.mkdir(parents=True)
531
+ (package_directory / "__init__.py").write_text("", encoding="utf-8")
532
+ (config_directory / "__init__.py").write_text("", encoding="utf-8")
533
+ constants_path = config_directory / "constants.py"
534
+ constants_path.write_text(ALIAS_CONSTANTS_BODY, encoding="utf-8")
535
+ consumer_directory.mkdir(parents=True, exist_ok=True)
536
+ (consumer_directory / "style_guide_gen.py").write_text(consumer_body, encoding="utf-8")
537
+ return constants_path
538
+
539
+
540
+ def test_does_not_flag_constant_read_through_an_aliased_module_import(
541
+ neutral_root: Path,
542
+ ) -> None:
543
+ constants_path = _build_alias_repository(
544
+ neutral_root,
545
+ neutral_root / "style_guide_gen_constants",
546
+ ALIASED_IMPORT_CONSUMER_BODY,
547
+ )
548
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
549
+ assert issues == [], (
550
+ f"A constant read as an attribute on an aliased module import stays live, got: {issues}"
551
+ )
552
+
553
+
554
+ def test_does_not_flag_constant_read_through_an_alias_outside_the_package_tree(
555
+ neutral_root: Path,
556
+ ) -> None:
557
+ constants_path = _build_alias_repository(
558
+ neutral_root / "scripts",
559
+ neutral_root / "scripts",
560
+ ALIASED_IMPORT_CONSUMER_BODY,
561
+ )
562
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
563
+ assert issues == [], (
564
+ "A constant an aliased module import reads from outside the package tree "
565
+ f"stays live through the widened scan, got: {issues}"
566
+ )
567
+
568
+
569
+ def test_does_not_flag_constant_read_through_an_unaliased_module_import_outside_the_tree(
570
+ neutral_root: Path,
571
+ ) -> None:
572
+ consumer_body = (
573
+ "from style_guide_gen_constants.config import constants\n"
574
+ "\n"
575
+ "def prompts_directory() -> str:\n"
576
+ " return constants.BASE_PROMPTS_DIRECTORY_NAME\n"
577
+ "\n"
578
+ "def style_sheet() -> str:\n"
579
+ " return constants.STYLE_SHEET_FILENAME\n"
580
+ )
581
+ constants_path = _build_alias_repository(
582
+ neutral_root / "scripts",
583
+ neutral_root / "scripts",
584
+ consumer_body,
585
+ )
586
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
587
+ assert issues == [], (
588
+ f"A constant read on an unaliased imported module object stays live, got: {issues}"
589
+ )
590
+
591
+
592
+ def test_does_not_flag_constant_read_through_a_dotted_module_path_outside_the_tree(
593
+ neutral_root: Path,
594
+ ) -> None:
595
+ consumer_body = (
596
+ "import style_guide_gen_constants.config.constants\n"
597
+ "\n"
598
+ "def prompts_directory() -> str:\n"
599
+ " return style_guide_gen_constants.config.constants.BASE_PROMPTS_DIRECTORY_NAME\n"
600
+ "\n"
601
+ "def style_sheet() -> str:\n"
602
+ " return style_guide_gen_constants.config.constants.STYLE_SHEET_FILENAME\n"
603
+ )
604
+ constants_path = _build_alias_repository(
605
+ neutral_root / "scripts",
606
+ neutral_root / "scripts",
607
+ consumer_body,
608
+ )
609
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
610
+ assert issues == [], (
611
+ f"A constant read through the full dotted module path stays live, got: {issues}"
612
+ )
613
+
614
+
615
+ def test_does_not_flag_constant_read_through_an_alias_in_a_sibling_tree(
616
+ neutral_root: Path,
617
+ ) -> None:
618
+ constants_body = 'CROSS_TREE_CONSTANT = "cross"\nLOCALLY_DEAD_CONSTANT = "dead"\n'
619
+ sibling_consumer_body = (
620
+ "from shared.theme_db.config import constants as theme_constants\n"
621
+ "\n"
622
+ "def tally() -> str:\n"
623
+ " return theme_constants.CROSS_TREE_CONSTANT\n"
624
+ )
625
+ constants_path = _build_cross_tree_repository(
626
+ neutral_root, constants_body, sibling_consumer_body
627
+ )
628
+ issues = _check(constants_body, str(constants_path))
629
+ assert not any("CROSS_TREE_CONSTANT" in each_issue for each_issue in issues), (
630
+ "A constant a sibling tree reads as an attribute on an aliased module import "
631
+ f"must not be flagged, got: {issues}"
632
+ )
633
+ assert any("LOCALLY_DEAD_CONSTANT" in each_issue for each_issue in issues), (
634
+ f"A constant referenced nowhere in the repository stays flagged, got: {issues}"
635
+ )
636
+
637
+
638
+ def _build_alias_collision_repository(
639
+ repository_root: Path,
640
+ promoter_constants_body: str,
641
+ harness_constants_body: str,
642
+ harness_consumer_body: str,
643
+ ) -> Path:
644
+ promoter_config = repository_root / "promoter" / "config"
645
+ promoter_config.mkdir(parents=True)
646
+ promoter_constants_path = promoter_config / "constants.py"
647
+ promoter_constants_path.write_text(promoter_constants_body, encoding="utf-8")
648
+ harness_config = repository_root / "harness" / "config"
649
+ harness_config.mkdir(parents=True)
650
+ (harness_config / "other_constants.py").write_text(harness_constants_body, encoding="utf-8")
651
+ (repository_root / "harness" / "lockfile.py").write_text(
652
+ harness_consumer_body, encoding="utf-8"
653
+ )
654
+ return promoter_constants_path
655
+
656
+
657
+ def test_alias_attribute_read_on_an_unrelated_module_does_not_mask_a_dead_constant(
658
+ neutral_root: Path,
659
+ ) -> None:
660
+ promoter_constants_body = 'NEVER_READ_CONSTANT = "dead"\n'
661
+ harness_constants_body = 'NEVER_READ_CONSTANT = "twin"\n'
662
+ harness_consumer_body = (
663
+ "from harness.config import other_constants as oc\n"
664
+ "\n"
665
+ "def acquire() -> str:\n"
666
+ " return oc.NEVER_READ_CONSTANT\n"
667
+ )
668
+ promoter_constants_path = _build_alias_collision_repository(
669
+ neutral_root,
670
+ promoter_constants_body,
671
+ harness_constants_body,
672
+ harness_consumer_body,
673
+ )
674
+ issues = _check(promoter_constants_body, str(promoter_constants_path))
675
+ assert any("NEVER_READ_CONSTANT" in each_issue for each_issue in issues), (
676
+ "A constant whose only same-named twin is read as an attribute on an "
677
+ f"unrelated aliased module must still be flagged dead, got: {issues}"
678
+ )
679
+
@@ -1,6 +1,6 @@
1
1
  """Tests for magic-value allowlist alignment with CODE_RULES §HOOK-ENFORCED.
2
2
 
3
- CODE_RULES.md and AGENTS.md both state that only
3
+ CODE_RULES.md states that only
4
4
  0, 1, and -1 (plus their float forms 0.0, 1.0) are exempt from the
5
5
  magic-value check. Prior to this change, the hook silently allowed 2
6
6
  and 100 as well, making the hook more permissive than the written rule.
@@ -422,7 +422,8 @@ def test_main_logs_high_level_failure_when_restore_switch_fails(
422
422
 
423
423
  assert exit_code == 0
424
424
  assert state_file.exists()
425
- assert "[gh-pr-author-restore] failed to restore" in captured_streams.err
425
+ assert "[gh-pr-author-restore] Restore the gh account" in captured_streams.err
426
+ assert "gh account switch requires attention" in captured_streams.err
426
427
  assert "'jl-cmd'" in captured_streams.err
427
428
  assert str(state_file) in captured_streams.err
428
429
 
@@ -111,6 +111,10 @@ def test_intent_ending_message_emits_block_with_short_user_notice():
111
111
  assert parsed_response["systemMessage"] == USER_FACING_INTENT_ENDING_NOTICE
112
112
  assert parsed_response["suppressOutput"] is True
113
113
  assert "long-horizon-autonomy" in parsed_response["reason"]
114
+ assert "This turn ends with a promise of future work." in parsed_response["reason"]
115
+ assert "Complete that work with tool calls during this turn." in parsed_response[
116
+ "reason"
117
+ ]
114
118
 
115
119
 
116
120
  def test_next_steps_lead_in_emits_block():