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.
- package/AGENTS.md +61 -0
- package/CLAUDE.md +1 -57
- package/_shared/AGENTS.md +15 -0
- package/_shared/CLAUDE.md +1 -15
- package/_shared/advisor/AGENTS.md +22 -0
- package/_shared/advisor/CLAUDE.md +1 -22
- package/_shared/pr-loop/AGENTS.md +27 -0
- package/_shared/pr-loop/CLAUDE.md +1 -27
- package/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
- package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
- package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
- package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
- package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
- package/_shared/process-tree/AGENTS.md +41 -0
- package/_shared/process-tree/CLAUDE.md +1 -41
- package/agents/AGENTS.md +31 -0
- package/agents/CLAUDE.md +1 -32
- package/agents/clean-coder.md +6 -6
- package/agents/pr-description-writer.md +11 -81
- package/agents/test_agent_frontmatter.py +4 -4
- package/audit-rubrics/AGENTS.md +43 -0
- package/audit-rubrics/CLAUDE.md +1 -43
- package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
- package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
- package/audit-rubrics/prompts/AGENTS.md +37 -0
- package/audit-rubrics/prompts/CLAUDE.md +1 -37
- package/bin/AGENTS.md +112 -0
- package/bin/CLAUDE.md +1 -112
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +6 -7
- package/bin/install.mjs +71 -13
- package/bin/install.prune.test.mjs +26 -0
- package/bin/install.settings-defaults.test.mjs +60 -33
- package/bin/install.test.mjs +36 -4
- package/commands/AGENTS.md +23 -0
- package/commands/CLAUDE.md +1 -23
- package/commands/hook-log-extract.md +3 -3
- package/commands/sr-loop.md +9 -5
- package/docs/AGENTS.md +32 -0
- package/docs/CLAUDE.md +1 -33
- package/docs/CODE_RULES.md +1 -1
- package/docs/imagegen.md +22 -0
- package/docs/references/AGENTS.md +17 -0
- package/docs/references/CLAUDE.md +1 -18
- package/hooks/AGENTS.md +31 -0
- package/hooks/CLAUDE.md +1 -31
- package/hooks/_gh_pr_author_swap_utils.py +14 -0
- package/hooks/advisory/AGENTS.md +16 -0
- package/hooks/advisory/CLAUDE.md +1 -16
- package/hooks/blocking/AGENTS.md +123 -0
- package/hooks/blocking/CLAUDE.md +1 -148
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
- package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
- package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
- package/hooks/blocking/code_rules_probe_chains.py +6 -2
- package/hooks/blocking/config/AGENTS.md +10 -0
- package/hooks/blocking/config/CLAUDE.md +1 -22
- package/hooks/blocking/conventional_pr_title_gate.py +1 -2
- package/hooks/blocking/gh_pr_author_restore.py +7 -2
- package/hooks/blocking/intent_only_ending_blocker.py +11 -16
- package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
- package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
- package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
- package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +4 -4
- package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
- package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
- package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
- package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
- package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
- package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
- package/hooks/diagnostic/AGENTS.md +43 -0
- package/hooks/diagnostic/CLAUDE.md +1 -43
- package/hooks/diagnostic/hook_log_extractor.py +4 -38
- package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
- package/hooks/diagnostic/migrations/AGENTS.md +16 -0
- package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
- package/hooks/diagnostic/queries/AGENTS.md +19 -0
- package/hooks/diagnostic/queries/CLAUDE.md +1 -19
- package/hooks/diagnostic/test_hook_log_extractor.py +10 -23
- package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
- package/hooks/git-hooks/AGENTS.md +31 -0
- package/hooks/git-hooks/CLAUDE.md +1 -31
- package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
- package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
- package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -12
- package/hooks/git-hooks/pre_push.py +49 -118
- package/hooks/git-hooks/test_pre_push.py +111 -137
- package/hooks/hooks.json +0 -35
- package/hooks/hooks_constants/AGENTS.md +104 -0
- package/hooks/hooks_constants/CLAUDE.md +1 -113
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
- package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
- package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
- package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
- package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
- package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
- package/hooks/lifecycle/AGENTS.md +18 -0
- package/hooks/lifecycle/CLAUDE.md +1 -20
- package/hooks/observability/AGENTS.md +20 -0
- package/hooks/observability/CLAUDE.md +1 -20
- package/hooks/session/AGENTS.md +33 -0
- package/hooks/session/CLAUDE.md +1 -33
- package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
- package/hooks/session/task_list_loop_starter.py +3 -3
- package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
- package/hooks/session/test_task_list_loop_starter.py +10 -2
- package/hooks/session/test_working_style_prompt.py +9 -4
- package/hooks/validation/AGENTS.md +20 -0
- package/hooks/validation/CLAUDE.md +1 -20
- package/hooks/validators/AGENTS.md +51 -0
- package/hooks/validators/CLAUDE.md +1 -51
- package/hooks/validators/health_check.py +52 -19
- package/hooks/validators/python_style_checks.py +1 -1
- package/hooks/validators/test_health_check.py +112 -27
- package/hooks/workflow/AGENTS.md +16 -0
- package/hooks/workflow/CLAUDE.md +1 -16
- package/installable-surfaces.manifest.json +1 -0
- package/output-styles/AGENTS.md +15 -0
- package/output-styles/CLAUDE.md +1 -15
- package/package.json +2 -1
- package/rules/AGENTS.md +61 -0
- package/rules/CLAUDE.md +1 -63
- package/rules/code-standards.md +5 -9
- package/rules/doc-prose-cuts.md +1 -1
- package/rules/gh-cli-conventions.md +0 -1
- package/rules/git-workflow.md +1 -3
- package/scripts/AGENTS.md +62 -0
- package/scripts/CLAUDE.md +1 -63
- package/scripts/_code_review_test_support.py +0 -95
- package/scripts/codex_compat_materializer.py +4 -0
- package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
- package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
- package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
- package/scripts/invoke_code_review.py +8 -451
- package/scripts/sync_to_cursor/AGENTS.md +23 -0
- package/scripts/sync_to_cursor/CLAUDE.md +1 -23
- package/scripts/test_invoke_code_review.py +5 -61
- package/scripts/test_invoke_code_review_cli.py +1 -45
- package/scripts/test_invoke_code_review_contract.py +1 -118
- package/scripts/test_validate_instruction_pairs.py +90 -0
- package/scripts/test_verify_installable_package.py +5 -1
- package/scripts/tests/AGENTS.md +33 -0
- package/scripts/tests/CLAUDE.md +1 -33
- package/scripts/tests/test_codex_compat_materializer.py +36 -1
- package/scripts/validate_instruction_pairs.py +183 -0
- package/settings.json +1 -10
- package/skills/AGENTS.md +72 -0
- package/skills/CLAUDE.md +1 -64
- package/skills/_shared/AGENTS.md +44 -0
- package/skills/_shared/CLAUDE.md +1 -44
- package/skills/_shared/advisor/AGENTS.md +9 -0
- package/skills/_shared/advisor/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/AGENTS.md +50 -0
- package/skills/_shared/pr-loop/CLAUDE.md +1 -50
- package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
- package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
- package/skills/anthropic-plan/AGENTS.md +34 -0
- package/skills/anthropic-plan/CLAUDE.md +1 -34
- package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
- package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
- package/skills/anthropic-plan/templates/AGENTS.md +13 -0
- package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
- package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
- package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
- package/skills/auditing-claude-config/AGENTS.md +21 -0
- package/skills/auditing-claude-config/CLAUDE.md +1 -21
- package/skills/autoconverge/AGENTS.md +36 -0
- package/skills/autoconverge/CLAUDE.md +1 -36
- package/skills/autoconverge/reference/AGENTS.md +16 -0
- package/skills/autoconverge/reference/CLAUDE.md +1 -16
- package/skills/autoconverge/reference/convergence.md +7 -7
- package/skills/autoconverge/reference/gotchas.md +3 -10
- package/skills/autoconverge/workflow/AGENTS.md +26 -0
- package/skills/autoconverge/workflow/CLAUDE.md +1 -26
- package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
- package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
- package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
- package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
- package/skills/autoconverge/workflow/converge.mjs +201 -238
- package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
- package/skills/bugteam/AGENTS.md +30 -0
- package/skills/bugteam/CLAUDE.md +1 -30
- package/skills/bugteam/CONSTRAINTS.md +1 -1
- package/skills/bugteam/SKILL.md +9 -0
- package/skills/bugteam/reference/AGENTS.md +20 -0
- package/skills/bugteam/reference/CLAUDE.md +1 -20
- package/skills/bugteam/reference/audit-and-teammates.md +10 -6
- package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
- package/skills/bugteam/scripts/AGENTS.md +30 -0
- package/skills/bugteam/scripts/CLAUDE.md +1 -30
- package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
- package/skills/bugteam/test_skill_additions.py +9 -0
- package/skills/closeout/reference/handoff-prompt-template.md +1 -1
- package/skills/codex-review/AGENTS.md +46 -0
- package/skills/codex-review/CLAUDE.md +1 -46
- package/skills/codex-review/reference/AGENTS.md +15 -0
- package/skills/codex-review/reference/CLAUDE.md +1 -15
- package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
- package/skills/codex-review/test_skill_scaffold.py +3 -3
- package/skills/comments/SKILL.md +65 -0
- package/skills/copilot-review/AGENTS.md +18 -0
- package/skills/copilot-review/CLAUDE.md +1 -18
- package/skills/descriptions/SKILL.md +51 -0
- package/skills/emergencies/SKILL.md +42 -0
- package/skills/everything-search/AGENTS.md +17 -0
- package/skills/everything-search/CLAUDE.md +1 -17
- package/skills/fresh-branch/AGENTS.md +14 -0
- package/skills/fresh-branch/CLAUDE.md +1 -14
- package/skills/grok-spawn/AGENTS.md +28 -0
- package/skills/grok-spawn/CLAUDE.md +1 -28
- package/skills/orchestrator/SKILL.md +2 -4
- package/skills/plan-to-pr/SKILL.md +6 -7
- package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
- package/skills/plan-to-pr/reference/process-inventory.md +2 -2
- package/skills/plan-to-pr/reference/review-loop.md +2 -2
- package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
- package/skills/plan-to-pr/reference/task-seeds.md +1 -1
- package/skills/plan-to-pr/reference/task-ticket.md +3 -4
- package/skills/plan-to-pr/scripts/config/constants.py +1 -2
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
- package/skills/plan-to-pr/test_skill_contract.py +2 -2
- package/skills/pr-converge/AGENTS.md +32 -0
- package/skills/pr-converge/CLAUDE.md +1 -32
- package/skills/pr-converge/SKILL.md +13 -16
- package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
- package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
- package/skills/pr-converge/reference/AGENTS.md +28 -0
- package/skills/pr-converge/reference/CLAUDE.md +1 -28
- package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
- package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
- package/skills/pr-converge/reference/progress-checklist.md +6 -5
- package/skills/pr-converge/reference/state-schema.md +1 -27
- package/skills/pr-converge/scripts/AGENTS.md +46 -0
- package/skills/pr-converge/scripts/CLAUDE.md +1 -46
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
- package/skills/pr-converge/workflows/AGENTS.md +16 -0
- package/skills/pr-converge/workflows/CLAUDE.md +1 -16
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
- package/skills/pr-loop-lifecycle/SKILL.md +1 -1
- package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
- package/skills/prototype/SKILL.md +4 -4
- package/skills/prototype/reference/honest-limitations.md +5 -5
- package/skills/prototype/reference/promotion-tasks.md +2 -2
- package/skills/prototype/workflows/promotion.md +4 -6
- package/skills/rebase/AGENTS.md +32 -0
- package/skills/rebase/CLAUDE.md +1 -32
- package/skills/recall/AGENTS.md +30 -0
- package/skills/recall/CLAUDE.md +1 -30
- package/skills/remember/AGENTS.md +31 -0
- package/skills/remember/CLAUDE.md +1 -31
- package/skills/reviews/SKILL.md +85 -0
- package/skills/session-log/AGENTS.md +32 -0
- package/skills/session-log/CLAUDE.md +1 -32
- package/skills/session-tidy/AGENTS.md +36 -0
- package/skills/session-tidy/CLAUDE.md +1 -36
- package/skills/skill-builder/AGENTS.md +49 -0
- package/skills/skill-builder/CLAUDE.md +1 -49
- package/skills/skill-builder/references/AGENTS.md +25 -0
- package/skills/skill-builder/references/CLAUDE.md +1 -25
- package/skills/skill-builder/references/deterministic-elements.md +1 -1
- package/skills/skill-builder/templates/AGENTS.md +14 -0
- package/skills/skill-builder/templates/CLAUDE.md +1 -14
- package/skills/skill-builder/workflows/AGENTS.md +19 -0
- package/skills/skill-builder/workflows/CLAUDE.md +1 -19
- package/skills/small-cl/SKILL.md +52 -0
- package/skills/task-build/AGENTS.md +29 -0
- package/skills/task-build/CLAUDE.md +1 -29
- package/skills/update/AGENTS.md +38 -0
- package/skills/update/CLAUDE.md +1 -38
- package/system-prompts/AGENTS.md +17 -0
- package/system-prompts/CLAUDE.md +1 -17
- package/system-prompts/software-engineer.xml +3 -3
- package/agents/code-verifier.md +0 -74
- package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
- package/docs/references/code-review-enforcement.md +0 -132
- package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
- package/hooks/blocking/code_review_gate_deny.py +0 -74
- package/hooks/blocking/code_review_pr_create_gate.py +0 -198
- package/hooks/blocking/code_review_push_gate.py +0 -145
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
- package/hooks/blocking/code_review_stamp_store.py +0 -233
- package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
- package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
- package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
- package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
- package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
- package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
- package/hooks/blocking/config/verified_commit_constants.py +0 -160
- package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
- package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
- package/hooks/blocking/conftest.py +0 -123
- package/hooks/blocking/convergence_gate_blocker.py +0 -310
- package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
- package/hooks/blocking/pr_description_body_audit.py +0 -148
- package/hooks/blocking/pr_description_command_parser.py +0 -237
- package/hooks/blocking/pr_description_enforcer.py +0 -227
- package/hooks/blocking/pr_description_pr_number.py +0 -155
- package/hooks/blocking/pr_description_proof_of_work.py +0 -385
- package/hooks/blocking/pr_description_readability.py +0 -364
- package/hooks/blocking/reviewer_spawn_gate.py +0 -182
- package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
- package/hooks/blocking/test_code_review_gate_deny.py +0 -54
- package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
- package/hooks/blocking/test_code_review_push_gate.py +0 -205
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
- package/hooks/blocking/test_code_review_stamp_store.py +0 -205
- package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
- package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
- package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
- package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
- package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
- package/hooks/blocking/test_pr_description_enforcer.py +0 -221
- package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
- package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
- package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
- package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
- package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
- package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
- package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
- package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
- package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
- package/hooks/blocking/test_verification_verdict_store.py +0 -974
- package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
- package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
- package/hooks/blocking/test_verified_commit_gate.py +0 -581
- package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
- package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
- package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
- package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
- package/hooks/blocking/verification_verdict_store.py +0 -1039
- package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
- package/hooks/blocking/verified_commit_gate.py +0 -113
- package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
- package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
- package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
- package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
- package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
- package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
- package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
- package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
- package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
- package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
- package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
- package/hooks/blocking/verifier_verdict_minter.py +0 -280
- package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
- package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
- package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
- package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
- package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
- package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
- package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
- package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
- package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
- package/rules/proof-of-work-pr-comments.md +0 -22
- package/rules/verified-commit-gate-skip.md +0 -4
- 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
|
|
48
|
+
def test_directive_runs_the_instruction_immediately(self) -> None:
|
|
49
49
|
emitted = json.loads(_run_main())
|
|
50
|
-
assert "
|
|
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
|
|
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 "
|
|
43
|
-
assert "Deliver
|
|
44
|
-
assert
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
72
|
-
|
|
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
|
-
|
|
78
|
-
error=f"
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
231
|
+
status = ValidatorStatus.READY.value if available else "[OPTIONAL]"
|
|
199
232
|
print(f" {status} {tool}")
|
|
200
233
|
print()
|
|
201
234
|
|
|
@@ -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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def
|
|
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.
|
|
32
|
-
assert
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
53
|
-
version2 = get_validator_version(temp_path)
|
|
136
|
+
print_health_report(health)
|
|
54
137
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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`.
|
package/hooks/workflow/CLAUDE.md
CHANGED
|
@@ -1,16 +1 @@
|
|
|
1
|
-
|
|
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
|
|
@@ -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/`.
|
package/output-styles/CLAUDE.md
CHANGED
|
@@ -1,15 +1 @@
|
|
|
1
|
-
|
|
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.
|
|
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]",
|