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
@@ -45,9 +45,17 @@ class TestSessionDirective:
45
45
  emitted = json.loads(_run_main())
46
46
  assert "/loop 10m" in emitted["additionalContext"]
47
47
 
48
- def test_directive_is_idempotent_about_an_existing_loop(self) -> None:
48
+ def test_directive_runs_the_instruction_immediately(self) -> None:
49
49
  emitted = json.loads(_run_main())
50
- assert "not already running" in emitted["additionalContext"]
50
+ assert "Run that instruction once immediately when starting the loop, then" in emitted[
51
+ "additionalContext"
52
+ ]
53
+
54
+ def test_directive_reuses_an_existing_loop(self) -> None:
55
+ emitted = json.loads(_run_main())
56
+ assert "Reuse the active task-list maintenance loop when available." in emitted[
57
+ "additionalContext"
58
+ ]
51
59
 
52
60
  def test_build_session_directive_returns_the_shared_constant(self) -> None:
53
61
  assert starter.build_session_directive() == TASK_LIST_LOOP_DIRECTIVE
@@ -36,12 +36,17 @@ class TestWorkingStylePrompt:
36
36
  emitted = json.loads(_run_main())
37
37
  assert emitted["additionalContext"] == WORKING_STYLE_PROMPT
38
38
 
39
- def test_emitted_prompt_carries_ledger_and_scope_lines(self) -> None:
39
+ def test_emitted_prompt_preserves_existing_guidance_and_adds_policy(self) -> None:
40
40
  emitted = json.loads(_run_main())
41
41
  prompt_text = emitted["additionalContext"]
42
- assert "scratch txt file you'll keep running as you go; ledger, if you will." in prompt_text
43
- assert "Deliver what was asked, at the scope intended." in prompt_text
44
- assert 'answer "what happened" or "what did you find,"' in prompt_text
42
+ assert "Document each task in a location that remains easy to find later." in prompt_text
43
+ assert "Deliver the requested work at its intended scope." in prompt_text
44
+ assert "Use positive prose throughout every generated text surface" in prompt_text
45
+ assert "Write each point as one direct affirmative statement" in prompt_text
46
+ assert "Use plain language, full terms, and simple descriptive names" in prompt_text
47
+ assert "When a request has multiple reasonable interpretations" in prompt_text
48
+ assert "Ask one focused clarification question" in prompt_text
49
+ assert "Pause for the user's choice before making a high-impact decision." in prompt_text
45
50
 
46
51
  def test_build_session_directive_returns_the_shared_constant(self) -> None:
47
52
  assert starter.build_session_directive() == WORKING_STYLE_PROMPT
@@ -0,0 +1,20 @@
1
+ # hooks/validation
2
+
3
+ PostToolUse hooks that validate code quality after Claude writes or edits a file. Unlike the blocking hooks (which fire PreToolUse and can deny the write), these hooks run after the write and report errors that need a follow-up fix.
4
+
5
+ ## Key files
6
+
7
+ | File | Event | What it does |
8
+ |---|---|---|
9
+ | `mypy_validator.py` | PostToolUse (Write/Edit on `.py` files) | Runs mypy on the written file and blocks (via PostToolUse block decision) when type errors are found — catches missing attributes, wrong signatures, type mismatches, and import errors |
10
+ | `hook_format_validator.py` | PostToolUse | Validates that a hook script's output JSON matches the expected Claude Code hook-output schema |
11
+ | `test_mypy_validator.py` | — | Tests for `mypy_validator.py` |
12
+ | `test_hook_format_validator.py` | — | Tests for `hook_format_validator.py` |
13
+
14
+ ## Conventions
15
+
16
+ - `mypy_validator.py` resolves the project root via `CLAUDE_PROJECT_ROOT` or `git rev-parse --show-toplevel`.
17
+ - It works on both WSL and Windows.
18
+ - Constants (timeouts, max displayed errors) are inline in `mypy_validator.py`; longer tunables go in `hooks_constants/`.
19
+ - The `eval_*.txt` files in this directory are evaluation exports used during development — not runtime artifacts.
20
+ - Tests run with `python -m pytest validation/test_<name>.py`.
@@ -1,20 +1 @@
1
- # hooks/validation
2
-
3
- PostToolUse hooks that validate code quality after Claude writes or edits a file. Unlike the blocking hooks (which fire PreToolUse and can deny the write), these hooks run after the write and report errors that need a follow-up fix.
4
-
5
- ## Key files
6
-
7
- | File | Event | What it does |
8
- |---|---|---|
9
- | `mypy_validator.py` | PostToolUse (Write/Edit on `.py` files) | Runs mypy on the written file and blocks (via PostToolUse block decision) when type errors are found — catches missing attributes, wrong signatures, type mismatches, and import errors |
10
- | `hook_format_validator.py` | PostToolUse | Validates that a hook script's output JSON matches the expected Claude Code hook-output schema |
11
- | `test_mypy_validator.py` | — | Tests for `mypy_validator.py` |
12
- | `test_hook_format_validator.py` | — | Tests for `hook_format_validator.py` |
13
-
14
- ## Conventions
15
-
16
- - `mypy_validator.py` resolves the project root via `CLAUDE_PROJECT_ROOT` or `git rev-parse --show-toplevel`.
17
- - It works on both WSL and Windows.
18
- - Constants (timeouts, max displayed errors) are inline in `mypy_validator.py`; longer tunables go in `hooks_constants/`.
19
- - The `eval_*.txt` files in this directory are evaluation exports used during development — not runtime artifacts.
20
- - Tests run with `python -m pytest validation/test_<name>.py`.
1
+ @AGENTS.md
@@ -0,0 +1,51 @@
1
+ # hooks/validators
2
+
3
+ A library of check modules used by the validation hooks. Each module focuses on one concern; `run_all_validators.py` runs them all and collects results. These modules do not hook into Claude Code directly — they are imported by the validation hooks.
4
+
5
+ ## Core infrastructure
6
+
7
+ | File | Role |
8
+ |---|---|
9
+ | `validator_base.py` | Defines the `Violation` dataclass (`file`, `line`, `message`) used by every check module |
10
+ | `validator_defaults.py` | Default configuration values shared across check modules |
11
+ | `exempt_paths.py` | Path exemption logic — paths that checks skip (e.g. vendored code) |
12
+ | `output_formatter.py` | Formats `Violation` lists into human-readable output |
13
+ | `run_all_validators.py` | Entry point — runs every check module and aggregates results |
14
+ | `health_check.py` | Verifies that all validator dependencies (ruff, mypy) are reachable |
15
+ | `pyproject_config_discovery.py` | Shared walk-up primitive that resolves a tool's pyproject.toml config from an original target path, matching the `[tool.<name>]` table the tool owns |
16
+ | `python_style_helpers.py` | Shared source-line splitting and function-discovery helpers imported by `python_style_checks.py` |
17
+
18
+ ## Check modules
19
+
20
+ | Module | What it checks |
21
+ |---|---|
22
+ | `abbreviation_checks.py` | Abbreviated names in Python code |
23
+ | `code_quality_checks.py` | General code quality concerns (dead code, stub bodies, etc.) |
24
+ | `comment_checks.py` | Inline comment presence and content |
25
+ | `file_structure_checks.py` | File-level structural rules (line count, module layout) |
26
+ | `git_checks.py` | Git-state checks (untracked files, merge conflicts) |
27
+ | `magic_value_checks.py` | Magic numbers and strings |
28
+ | `mypy_integration.py` | Runs mypy and converts its output to `Violation` objects |
29
+ | `pr_reference_checks.py` | PR references in commit messages and changelogs |
30
+ | `python_antipattern_checks.py` | Python-specific anti-patterns (bare `except`, `Any`, etc.) |
31
+ | `python_style_checks.py` | Python style rules (naming, imports, type hints) |
32
+ | `react_checks.py` | React/TSX-specific checks (class component patterns, PureComponent usage) |
33
+ | `ruff_integration.py` | Runs ruff and converts its output to `Violation` objects |
34
+ | `security_checks.py` | Security anti-patterns (hardcoded secrets, unsafe calls) |
35
+ | `todo_checks.py` | TODO/FIXME markers without an associated issue reference |
36
+ | `type_safety_checks.py` | Type-safety rules (no `Any`, no `cast`, no `# type: ignore`) |
37
+ | `useless_test_checks.py` | Tests that check only existence or constant values |
38
+
39
+ ## Subdirectory
40
+
41
+ | Directory | Role |
42
+ |---|---|
43
+ | `config/` | Constants module (`directory_exemption_constants.py`) holding the exemption directory-segment names that `validate_proposed_file` staging keeps |
44
+ | `test_files/` | Fixture files used by the validator tests — not checked-in test code |
45
+
46
+ ## Conventions
47
+
48
+ - Every check module exposes one or more functions that take file content or an AST and return a list of `Violation` objects.
49
+ - Test files live beside the modules they test: `test_<module>.py`. Run with `python -m pytest validators/test_<name>.py`.
50
+ - `conftest.py` provides shared test fixtures (sample files, fixture paths).
51
+ - `README.md` in this directory documents the validator design and how to add a new check.
@@ -1,51 +1 @@
1
- # hooks/validators
2
-
3
- A library of check modules used by the validation hooks. Each module focuses on one concern; `run_all_validators.py` runs them all and collects results. These modules do not hook into Claude Code directly — they are imported by the validation hooks.
4
-
5
- ## Core infrastructure
6
-
7
- | File | Role |
8
- |---|---|
9
- | `validator_base.py` | Defines the `Violation` dataclass (`file`, `line`, `message`) used by every check module |
10
- | `validator_defaults.py` | Default configuration values shared across check modules |
11
- | `exempt_paths.py` | Path exemption logic — paths that checks skip (e.g. vendored code) |
12
- | `output_formatter.py` | Formats `Violation` lists into human-readable output |
13
- | `run_all_validators.py` | Entry point — runs every check module and aggregates results |
14
- | `health_check.py` | Verifies that all validator dependencies (ruff, mypy) are reachable |
15
- | `pyproject_config_discovery.py` | Shared walk-up primitive that resolves a tool's pyproject.toml config from an original target path, matching the `[tool.<name>]` table the tool owns |
16
- | `python_style_helpers.py` | Shared source-line splitting and function-discovery helpers imported by `python_style_checks.py` |
17
-
18
- ## Check modules
19
-
20
- | Module | What it checks |
21
- |---|---|
22
- | `abbreviation_checks.py` | Abbreviated names in Python code |
23
- | `code_quality_checks.py` | General code quality concerns (dead code, stub bodies, etc.) |
24
- | `comment_checks.py` | Inline comment presence and content |
25
- | `file_structure_checks.py` | File-level structural rules (line count, module layout) |
26
- | `git_checks.py` | Git-state checks (untracked files, merge conflicts) |
27
- | `magic_value_checks.py` | Magic numbers and strings |
28
- | `mypy_integration.py` | Runs mypy and converts its output to `Violation` objects |
29
- | `pr_reference_checks.py` | PR references in commit messages and changelogs |
30
- | `python_antipattern_checks.py` | Python-specific anti-patterns (bare `except`, `Any`, etc.) |
31
- | `python_style_checks.py` | Python style rules (naming, imports, type hints) |
32
- | `react_checks.py` | React/TSX-specific checks (class component patterns, PureComponent usage) |
33
- | `ruff_integration.py` | Runs ruff and converts its output to `Violation` objects |
34
- | `security_checks.py` | Security anti-patterns (hardcoded secrets, unsafe calls) |
35
- | `todo_checks.py` | TODO/FIXME markers without an associated issue reference |
36
- | `type_safety_checks.py` | Type-safety rules (no `Any`, no `cast`, no `# type: ignore`) |
37
- | `useless_test_checks.py` | Tests that check only existence or constant values |
38
-
39
- ## Subdirectory
40
-
41
- | Directory | Role |
42
- |---|---|
43
- | `config/` | Constants module (`directory_exemption_constants.py`) holding the exemption directory-segment names that `validate_proposed_file` staging keeps |
44
- | `test_files/` | Fixture files used by the validator tests — not checked-in test code |
45
-
46
- ## Conventions
47
-
48
- - Every check module exposes one or more functions that take file content or an AST and return a list of `Violation` objects.
49
- - Test files live beside the modules they test: `test_<module>.py`. Run with `python -m pytest validators/test_<name>.py`.
50
- - `conftest.py` provides shared test fixtures (sample files, fixture paths).
51
- - `README.md` in this directory documents the validator design and how to add a new check.
1
+ @AGENTS.md
@@ -7,14 +7,15 @@ Provides:
7
7
  """
8
8
 
9
9
  import hashlib
10
+ import stat
10
11
  import subprocess
11
12
  import sys
12
13
  from dataclasses import dataclass
13
- from datetime import datetime
14
+ from datetime import datetime, timezone
15
+ from enum import StrEnum
14
16
  from pathlib import Path
15
17
  from typing import Dict, Optional
16
18
 
17
-
18
19
  VALIDATOR_FILES = [
19
20
  "python_style_checks.py",
20
21
  "test_safety_checks.py",
@@ -25,15 +26,38 @@ VALIDATOR_FILES = [
25
26
  ]
26
27
 
27
28
 
29
+ class ValidatorStatus(StrEnum):
30
+ """Displayed state for one required validator."""
31
+
32
+ READY = "[READY]"
33
+ FILE_REQUIRED = "[FILE REQUIRED]"
34
+ ACCESS_REQUIRED = "[ACCESS REQUIRED]"
35
+
36
+
28
37
  @dataclass(frozen=True)
29
38
  class ValidatorHealth:
30
39
  """Health status of a single validator."""
31
40
 
32
41
  name: str
33
- healthy: bool
42
+ status: ValidatorStatus
34
43
  error: Optional[str] = None
35
44
  last_modified: Optional[datetime] = None
36
45
 
46
+ @property
47
+ def is_healthy(self) -> bool:
48
+ """Return whether the validator is ready for use."""
49
+ return self.status is ValidatorStatus.READY
50
+
51
+ @property
52
+ def healthy(self) -> bool:
53
+ """Return the readiness state for compatibility readers."""
54
+ return self.is_healthy
55
+
56
+ @property
57
+ def is_present(self) -> bool:
58
+ """Return whether the validator file is present on disk."""
59
+ return self.status is not ValidatorStatus.FILE_REQUIRED
60
+
37
61
 
38
62
  @dataclass(frozen=True)
39
63
  class SystemHealth:
@@ -56,26 +80,33 @@ def check_validator_exists(validator_path: Path) -> ValidatorHealth:
56
80
  """
57
81
  name = validator_path.stem
58
82
 
59
- if not validator_path.exists():
83
+ try:
84
+ validator_stat = validator_path.stat()
85
+ if not stat.S_ISREG(validator_stat.st_mode):
86
+ return ValidatorHealth(
87
+ name=name,
88
+ status=ValidatorStatus.FILE_REQUIRED,
89
+ error=f"Validator file required: {validator_path}",
90
+ )
91
+ validator_path.read_text(encoding="utf-8")
60
92
  return ValidatorHealth(
61
93
  name=name,
62
- healthy=False,
63
- error=f"Validator not found: {validator_path}",
94
+ status=ValidatorStatus.READY,
95
+ last_modified=datetime.fromtimestamp(
96
+ validator_stat.st_mtime, tz=timezone.utc
97
+ ),
64
98
  )
65
-
66
- try:
67
- validator_path.read_text(encoding="utf-8")
68
- mtime = datetime.fromtimestamp(validator_path.stat().st_mtime)
99
+ except FileNotFoundError:
69
100
  return ValidatorHealth(
70
101
  name=name,
71
- healthy=True,
72
- last_modified=mtime,
102
+ status=ValidatorStatus.FILE_REQUIRED,
103
+ error=f"Validator file required: {validator_path}",
73
104
  )
74
105
  except (IOError, OSError, PermissionError) as error:
75
106
  return ValidatorHealth(
76
107
  name=name,
77
- healthy=False,
78
- error=f"Cannot read validator: {error}",
108
+ status=ValidatorStatus.ACCESS_REQUIRED,
109
+ error=f"Validator read access requires attention: {error}",
79
110
  )
80
111
 
81
112
 
@@ -135,7 +166,10 @@ def get_validator_version(validators_dir: Optional[Path] = None) -> str:
135
166
  for validator_file in sorted(VALIDATOR_FILES):
136
167
  validator_path = validators_dir / validator_file
137
168
  if validator_path.exists():
138
- content = validator_path.read_bytes()
169
+ try:
170
+ content = validator_path.read_bytes()
171
+ except (FileNotFoundError, OSError):
172
+ continue
139
173
  hasher.update(content)
140
174
 
141
175
  return hasher.hexdigest()[:8]
@@ -154,7 +188,7 @@ def get_system_health(validators_dir: Optional[Path] = None) -> SystemHealth:
154
188
  validators_dir = Path(__file__).parent
155
189
 
156
190
  validators = check_all_validators(validators_dir)
157
- all_healthy = all(v.healthy for v in validators.values())
191
+ all_healthy = all(v.is_healthy for v in validators.values())
158
192
 
159
193
  optional_tools = {
160
194
  "ruff": check_optional_tool("ruff"),
@@ -187,15 +221,14 @@ def print_health_report(health: SystemHealth) -> None:
187
221
 
188
222
  print("Required Validators:")
189
223
  for name, validator in sorted(health.validators.items()):
190
- status = "[OK]" if validator.healthy else "[MISSING]"
191
- print(f" {status} {name}")
224
+ print(f" {validator.status.value} {name}")
192
225
  if validator.error:
193
226
  print(f" Error: {validator.error}")
194
227
  print()
195
228
 
196
229
  print("Optional Tools:")
197
230
  for tool, available in sorted(health.optional_tools.items()):
198
- status = "[OK]" if available else "[NOT INSTALLED]"
231
+ status = ValidatorStatus.READY.value if available else "[OPTIONAL]"
199
232
  print(f" {status} {tool}")
200
233
  print()
201
234
 
@@ -169,7 +169,7 @@ def _decorator_gap_violation(
169
169
  return Violation(
170
170
  filename,
171
171
  last_decorator_line,
172
- "No empty line allowed between decorator and function",
172
+ "Place the decorator directly above the function",
173
173
  )
174
174
 
175
175
 
@@ -1,35 +1,92 @@
1
1
  """Tests for validator health checks."""
2
2
 
3
- import tempfile
4
3
  from pathlib import Path
5
4
 
6
5
  import pytest
7
6
 
8
7
  from .health_check import (
8
+ SystemHealth,
9
9
  ValidatorHealth,
10
+ ValidatorStatus,
10
11
  check_validator_exists,
11
12
  check_all_validators,
12
13
  get_validator_version,
14
+ print_health_report,
13
15
  )
14
16
 
15
17
 
16
18
  class TestValidatorExists:
17
- def test_existing_validator_healthy(self) -> None:
18
- with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as temp_file:
19
- temp_file.write(b"print('hello')")
20
- temp_path = Path(temp_file.name)
21
-
22
- try:
23
- result = check_validator_exists(temp_path)
24
- assert result.healthy is True
25
- assert result.error is None
26
- finally:
27
- temp_path.unlink()
28
-
29
- def test_missing_validator_unhealthy(self) -> None:
19
+ def test_existing_validator_is_ready(self, tmp_path: Path) -> None:
20
+ validator_path = tmp_path / "validator.py"
21
+ validator_path.write_text("print('hello')", encoding="utf-8")
22
+
23
+ result = check_validator_exists(validator_path)
24
+
25
+ assert result.is_healthy is True
26
+ assert result.healthy is result.is_healthy
27
+ assert result.status is ValidatorStatus.READY
28
+ assert result.error is None
29
+ assert result.is_present is True
30
+
31
+ def test_missing_validator_requires_a_file(self) -> None:
30
32
  result = check_validator_exists(Path("/nonexistent/validator.py"))
31
- assert result.healthy is False
32
- assert "not found" in result.error.lower()
33
+ assert result.is_healthy is False
34
+ assert result.status is ValidatorStatus.FILE_REQUIRED
35
+ assert result.is_present is False
36
+ assert "file required" in result.error.lower()
37
+
38
+ def test_unreadable_validator_reports_read_access_state(
39
+ self,
40
+ tmp_path: Path,
41
+ monkeypatch: pytest.MonkeyPatch,
42
+ ) -> None:
43
+ validator_path = tmp_path / "validator.py"
44
+ validator_path.write_text("print('ready')", encoding="utf-8")
45
+
46
+ def raise_read_error(*_args: object, **_kwargs: object) -> str:
47
+ raise OSError("permission detail")
48
+
49
+ monkeypatch.setattr(Path, "read_text", raise_read_error)
50
+
51
+ result = check_validator_exists(validator_path)
52
+
53
+ assert result.is_healthy is False
54
+ assert result.status is ValidatorStatus.ACCESS_REQUIRED
55
+ assert result.is_present is True
56
+ assert "read access requires attention" in result.error.lower()
57
+
58
+ def test_directory_at_validator_path_requires_a_file(self, tmp_path: Path) -> None:
59
+ validator_path = tmp_path / "validator.py"
60
+ validator_path.mkdir()
61
+
62
+ result = check_validator_exists(validator_path)
63
+
64
+ assert result.is_healthy is False
65
+ assert result.status is ValidatorStatus.FILE_REQUIRED
66
+ assert result.is_present is False
67
+
68
+ def test_validator_disappearance_reports_file_required(
69
+ self,
70
+ tmp_path: Path,
71
+ monkeypatch: pytest.MonkeyPatch,
72
+ ) -> None:
73
+ validator_path = tmp_path / "validator.py"
74
+ validator_path.write_text("print('ready')", encoding="utf-8")
75
+
76
+ original_read_text = Path.read_text
77
+
78
+ def remove_before_read(
79
+ each_path: Path, **all_keyword_arguments: object
80
+ ) -> str:
81
+ each_path.unlink()
82
+ return original_read_text(each_path, **all_keyword_arguments)
83
+
84
+ monkeypatch.setattr(Path, "read_text", remove_before_read)
85
+
86
+ result = check_validator_exists(validator_path)
87
+
88
+ assert result.status is ValidatorStatus.FILE_REQUIRED
89
+ assert result.is_present is False
33
90
 
34
91
 
35
92
  class TestCheckAllValidators:
@@ -41,17 +98,45 @@ class TestCheckAllValidators:
41
98
 
42
99
 
43
100
  class TestGetValidatorVersion:
44
- def test_version_changes_when_content_changes(self) -> None:
45
- with tempfile.TemporaryDirectory() as temp_dir:
46
- temp_path = Path(temp_dir)
47
- validator_file = temp_path / "python_style_checks.py"
101
+ def test_version_changes_when_content_changes(self, tmp_path: Path) -> None:
102
+ validator_file = tmp_path / "python_style_checks.py"
103
+
104
+ validator_file.write_text("# version 1")
105
+ version1 = get_validator_version(tmp_path)
106
+
107
+ validator_file.write_text("# version 2 - different content")
108
+ version2 = get_validator_version(tmp_path)
109
+
110
+ assert version1 != version2
111
+ assert isinstance(version1, str)
112
+ assert len(version1) > 0
113
+
48
114
 
49
- validator_file.write_text("# version 1")
50
- version1 = get_validator_version(temp_path)
115
+ def test_print_health_report_distinguishes_validator_states(
116
+ capsys: pytest.CaptureFixture[str],
117
+ ) -> None:
118
+ health = SystemHealth(
119
+ all_healthy=False,
120
+ validators={
121
+ "missing_validator": ValidatorHealth(
122
+ name="missing_validator",
123
+ status=ValidatorStatus.FILE_REQUIRED,
124
+ error="Validator file required: missing_validator.py",
125
+ ),
126
+ "unreadable_validator": ValidatorHealth(
127
+ name="unreadable_validator",
128
+ status=ValidatorStatus.ACCESS_REQUIRED,
129
+ error="Validator read access requires attention: permission detail",
130
+ ),
131
+ },
132
+ python_version="3.12.0",
133
+ optional_tools={"mypy": True, "ruff": False},
134
+ )
51
135
 
52
- validator_file.write_text("# version 2 - different content")
53
- version2 = get_validator_version(temp_path)
136
+ print_health_report(health)
54
137
 
55
- assert version1 != version2
56
- assert isinstance(version1, str)
57
- assert len(version1) > 0
138
+ report = capsys.readouterr().out
139
+ assert "[FILE REQUIRED] missing_validator" in report
140
+ assert "[ACCESS REQUIRED] unreadable_validator" in report
141
+ assert "[READY] mypy" in report
142
+ assert "[OPTIONAL] ruff" in report
@@ -0,0 +1,16 @@
1
+ # hooks/workflow
2
+
3
+ PostToolUse hooks that run after Claude writes a file. They do not block the write; they run follow-up side effects — reformatting the written file and resetting the investigation tracker.
4
+
5
+ ## Key files
6
+
7
+ | File | Event | What it does |
8
+ |---|---|---|
9
+ | `auto_formatter.py` | PostToolUse (Write/Edit) | Runs the project's auto-formatter (ruff, prettier, etc.) on the written file and sends a desktop notification when formatting changes are applied |
10
+ | `investigation_tracker_reset.py` | PostToolUse | Resets the investigation tracker state after a tool call |
11
+ | `test_auto_formatter.py` | — | Tests for `auto_formatter.py` |
12
+
13
+ ## Conventions
14
+
15
+ - `auto_formatter.py` exits 0 even on failure — it logs warnings to stderr but does not break Claude's flow.
16
+ - Tests run with `python -m pytest workflow/test_<name>.py`.
@@ -1,16 +1 @@
1
- # hooks/workflow
2
-
3
- PostToolUse hooks that run after Claude writes a file. They do not block the write; they run follow-up side effects — reformatting the written file and resetting the investigation tracker.
4
-
5
- ## Key files
6
-
7
- | File | Event | What it does |
8
- |---|---|---|
9
- | `auto_formatter.py` | PostToolUse (Write/Edit) | Runs the project's auto-formatter (ruff, prettier, etc.) on the written file and sends a desktop notification when formatting changes are applied |
10
- | `investigation_tracker_reset.py` | PostToolUse | Resets the investigation tracker state after a tool call |
11
- | `test_auto_formatter.py` | — | Tests for `auto_formatter.py` |
12
-
13
- ## Conventions
14
-
15
- - `auto_formatter.py` exits 0 even on failure — it logs warnings to stderr but does not break Claude's flow.
16
- - Tests run with `python -m pytest workflow/test_<name>.py`.
1
+ @AGENTS.md
@@ -14,6 +14,7 @@
14
14
  "audit-rubrics"
15
15
  ],
16
16
  "root_files": [
17
+ "AGENTS.md",
17
18
  "CLAUDE.md",
18
19
  "codex-capability-map.json",
19
20
  "installable-surfaces.manifest.json"
@@ -0,0 +1,15 @@
1
+ # output-styles
2
+
3
+ Output-style instruction files installed into `~/.claude/output-styles/` by `bin/install.mjs`. Each file instructs an agent or session to respond in a specific voice or format.
4
+
5
+ ## Files
6
+
7
+ No output-style instruction files ship in this directory. The active caveman behavior lives in `agents/caveman.md`.
8
+
9
+ ## Format
10
+
11
+ Each file uses YAML frontmatter (`name`, `description`, optional `keep-coding-instructions`) followed by Markdown instructions. The `keep-coding-instructions: true` flag tells Claude Code to keep the session's coding rules even when this style is active.
12
+
13
+ ## Adding a style
14
+
15
+ Create a `.md` file with frontmatter and behavioral instructions, then run `bin/install.mjs` to copy it to `~/.claude/output-styles/`.
@@ -1,15 +1 @@
1
- # output-styles
2
-
3
- Output-style instruction files installed into `~/.claude/output-styles/` by `bin/install.mjs`. Each file instructs an agent or session to respond in a specific voice or format.
4
-
5
- ## Files
6
-
7
- No output-style instruction files ship in this directory. The active caveman behavior lives in `agents/caveman.md`.
8
-
9
- ## Format
10
-
11
- Each file uses YAML frontmatter (`name`, `description`, optional `keep-coding-instructions`) followed by Markdown instructions. The `keep-coding-instructions: true` flag tells Claude Code to keep the session's coding rules even when this style is active.
12
-
13
- ## Adding a style
14
-
15
- Create a `.md` file with frontmatter and behavioral instructions, then run `bin/install.mjs` to copy it to `~/.claude/output-styles/`.
1
+ @AGENTS.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "2.12.0",
3
+ "version": "2.14.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -26,6 +26,7 @@
26
26
  "installable-surfaces.manifest.json",
27
27
  "_shared/",
28
28
  "audit-rubrics/",
29
+ "AGENTS.md",
29
30
  "CLAUDE.md",
30
31
  "!**/__pycache__/**",
31
32
  "!**/*.py[cod]",