claude-dev-env 2.13.0 → 2.14.1

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 (263) hide show
  1. package/AGENTS.md +135 -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_parts/AGENTS.md +42 -0
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
  13. package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
  14. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
  15. package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
  16. package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
  17. package/_shared/process-tree/AGENTS.md +41 -0
  18. package/_shared/process-tree/CLAUDE.md +1 -41
  19. package/agents/AGENTS.md +26 -0
  20. package/agents/CLAUDE.md +1 -31
  21. package/agents/clean-coder.md +6 -6
  22. package/agents/test_agent_frontmatter.py +11 -11
  23. package/audit-rubrics/AGENTS.md +43 -0
  24. package/audit-rubrics/CLAUDE.md +1 -43
  25. package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
  26. package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
  27. package/audit-rubrics/prompts/AGENTS.md +37 -0
  28. package/audit-rubrics/prompts/CLAUDE.md +1 -37
  29. package/bin/AGENTS.md +112 -0
  30. package/bin/CLAUDE.md +1 -112
  31. package/bin/ever-shipped-skills.mjs +1 -0
  32. package/bin/install-constants.mjs +6 -7
  33. package/bin/install.mjs +24 -5
  34. package/bin/install.test.mjs +34 -0
  35. package/commands/AGENTS.md +13 -0
  36. package/commands/CLAUDE.md +1 -23
  37. package/docs/AGENTS.md +32 -0
  38. package/docs/CLAUDE.md +1 -32
  39. package/docs/CODE_RULES.md +1 -1
  40. package/docs/imagegen.md +22 -0
  41. package/docs/references/AGENTS.md +17 -0
  42. package/docs/references/CLAUDE.md +1 -17
  43. package/hooks/AGENTS.md +31 -0
  44. package/hooks/CLAUDE.md +1 -31
  45. package/hooks/_gh_pr_author_swap_utils.py +14 -0
  46. package/hooks/advisory/AGENTS.md +16 -0
  47. package/hooks/advisory/CLAUDE.md +1 -16
  48. package/hooks/blocking/AGENTS.md +123 -0
  49. package/hooks/blocking/CLAUDE.md +1 -123
  50. package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
  51. package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
  52. package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
  53. package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
  54. package/hooks/blocking/code_rules_probe_chains.py +6 -2
  55. package/hooks/blocking/config/AGENTS.md +10 -0
  56. package/hooks/blocking/config/CLAUDE.md +1 -10
  57. package/hooks/blocking/gh_pr_author_restore.py +7 -2
  58. package/hooks/blocking/intent_only_ending_blocker.py +11 -16
  59. package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
  60. package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
  61. package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
  62. package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
  63. package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
  64. package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
  65. package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
  66. package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
  67. package/hooks/blocking/test_claude_md_orphan_file_blocker.py +1 -1
  68. package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
  69. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
  70. package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
  71. package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
  72. package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
  73. package/hooks/diagnostic/AGENTS.md +75 -0
  74. package/hooks/diagnostic/CLAUDE.md +1 -43
  75. package/hooks/diagnostic/hook_log_extractor.py +2 -2
  76. package/hooks/diagnostic/hook_log_init.py +2 -2
  77. package/hooks/diagnostic/migrations/AGENTS.md +16 -0
  78. package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
  79. package/hooks/diagnostic/queries/AGENTS.md +19 -0
  80. package/hooks/diagnostic/queries/CLAUDE.md +1 -19
  81. package/hooks/diagnostic/test_hook_log_extractor.py +2 -2
  82. package/hooks/git-hooks/AGENTS.md +31 -0
  83. package/hooks/git-hooks/CLAUDE.md +1 -31
  84. package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
  85. package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
  86. package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -6
  87. package/hooks/git-hooks/pre_push.py +47 -34
  88. package/hooks/git-hooks/test_pre_push.py +111 -7
  89. package/hooks/hooks_constants/AGENTS.md +104 -0
  90. package/hooks/hooks_constants/CLAUDE.md +1 -104
  91. package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
  92. package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
  93. package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
  94. package/hooks/lifecycle/AGENTS.md +18 -0
  95. package/hooks/lifecycle/CLAUDE.md +1 -18
  96. package/hooks/observability/AGENTS.md +20 -0
  97. package/hooks/observability/CLAUDE.md +1 -20
  98. package/hooks/session/AGENTS.md +33 -0
  99. package/hooks/session/CLAUDE.md +1 -33
  100. package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
  101. package/hooks/session/task_list_loop_starter.py +3 -3
  102. package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
  103. package/hooks/session/test_task_list_loop_starter.py +10 -2
  104. package/hooks/session/test_working_style_prompt.py +9 -4
  105. package/hooks/validation/AGENTS.md +20 -0
  106. package/hooks/validation/CLAUDE.md +1 -20
  107. package/hooks/validators/AGENTS.md +51 -0
  108. package/hooks/validators/CLAUDE.md +1 -51
  109. package/hooks/validators/health_check.py +52 -19
  110. package/hooks/validators/python_style_checks.py +1 -1
  111. package/hooks/validators/test_health_check.py +112 -27
  112. package/hooks/workflow/AGENTS.md +16 -0
  113. package/hooks/workflow/CLAUDE.md +1 -16
  114. package/installable-surfaces.manifest.json +1 -0
  115. package/output-styles/AGENTS.md +15 -0
  116. package/output-styles/CLAUDE.md +1 -15
  117. package/package.json +2 -1
  118. package/rules/AGENTS.md +61 -0
  119. package/rules/CLAUDE.md +1 -61
  120. package/rules/code-standards.md +5 -9
  121. package/rules/doc-prose-cuts.md +1 -1
  122. package/scripts/AGENTS.md +62 -0
  123. package/scripts/CLAUDE.md +1 -62
  124. package/scripts/codex_compat_materializer.py +4 -0
  125. package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
  126. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
  127. package/scripts/sync_to_cursor/AGENTS.md +23 -0
  128. package/scripts/sync_to_cursor/CLAUDE.md +1 -23
  129. package/scripts/test_active_capability_references.py +2 -2
  130. package/scripts/test_validate_instruction_pairs.py +90 -0
  131. package/scripts/test_verify_installable_package.py +5 -1
  132. package/scripts/tests/AGENTS.md +33 -0
  133. package/scripts/tests/CLAUDE.md +1 -33
  134. package/scripts/tests/test_codex_compat_materializer.py +36 -1
  135. package/scripts/validate_instruction_pairs.py +183 -0
  136. package/skills/AGENTS.md +72 -0
  137. package/skills/CLAUDE.md +1 -72
  138. package/skills/_shared/AGENTS.md +44 -0
  139. package/skills/_shared/CLAUDE.md +1 -44
  140. package/skills/_shared/advisor/AGENTS.md +9 -0
  141. package/skills/_shared/advisor/CLAUDE.md +1 -9
  142. package/skills/_shared/pr-loop/AGENTS.md +50 -0
  143. package/skills/_shared/pr-loop/CLAUDE.md +1 -50
  144. package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
  145. package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
  146. package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
  147. package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
  148. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
  149. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
  150. package/skills/anthropic-plan/AGENTS.md +34 -0
  151. package/skills/anthropic-plan/CLAUDE.md +1 -34
  152. package/skills/anthropic-plan/SKILL.md +1 -1
  153. package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
  154. package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
  155. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
  156. package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
  157. package/skills/anthropic-plan/templates/AGENTS.md +13 -0
  158. package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
  159. package/skills/anthropic-plan/test_skill_contract.py +8 -6
  160. package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
  161. package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
  162. package/skills/auditing-claude-config/AGENTS.md +21 -0
  163. package/skills/auditing-claude-config/CLAUDE.md +1 -21
  164. package/skills/autoconverge/AGENTS.md +36 -0
  165. package/skills/autoconverge/CLAUDE.md +1 -36
  166. package/skills/autoconverge/reference/AGENTS.md +16 -0
  167. package/skills/autoconverge/reference/CLAUDE.md +1 -16
  168. package/skills/autoconverge/workflow/AGENTS.md +26 -0
  169. package/skills/autoconverge/workflow/CLAUDE.md +1 -26
  170. package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
  171. package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
  172. package/skills/bugteam/AGENTS.md +30 -0
  173. package/skills/bugteam/CLAUDE.md +1 -30
  174. package/skills/bugteam/reference/AGENTS.md +20 -0
  175. package/skills/bugteam/reference/CLAUDE.md +1 -20
  176. package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
  177. package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
  178. package/skills/bugteam/scripts/AGENTS.md +30 -0
  179. package/skills/bugteam/scripts/CLAUDE.md +1 -30
  180. package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
  181. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
  182. package/skills/closeout/reference/handoff-prompt-template.md +1 -1
  183. package/skills/codex-review/AGENTS.md +46 -0
  184. package/skills/codex-review/CLAUDE.md +1 -46
  185. package/skills/codex-review/reference/AGENTS.md +15 -0
  186. package/skills/codex-review/reference/CLAUDE.md +1 -15
  187. package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
  188. package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
  189. package/skills/codex-review/test_skill_scaffold.py +3 -3
  190. package/skills/copilot-review/AGENTS.md +18 -0
  191. package/skills/copilot-review/CLAUDE.md +1 -18
  192. package/skills/everything-search/AGENTS.md +17 -0
  193. package/skills/everything-search/CLAUDE.md +1 -17
  194. package/skills/fresh-branch/AGENTS.md +14 -0
  195. package/skills/fresh-branch/CLAUDE.md +1 -14
  196. package/skills/grok-spawn/AGENTS.md +28 -0
  197. package/skills/grok-spawn/CLAUDE.md +1 -28
  198. package/skills/pr-converge/AGENTS.md +32 -0
  199. package/skills/pr-converge/CLAUDE.md +1 -32
  200. package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
  201. package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
  202. package/skills/pr-converge/reference/AGENTS.md +28 -0
  203. package/skills/pr-converge/reference/CLAUDE.md +1 -28
  204. package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
  205. package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
  206. package/skills/pr-converge/scripts/AGENTS.md +46 -0
  207. package/skills/pr-converge/scripts/CLAUDE.md +1 -46
  208. package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
  209. package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
  210. package/skills/pr-converge/workflows/AGENTS.md +16 -0
  211. package/skills/pr-converge/workflows/CLAUDE.md +1 -16
  212. package/skills/prototype/SKILL.md +1 -2
  213. package/skills/prototype/reference/honest-limitations.md +1 -1
  214. package/skills/prototype/reference/promotion-tasks.md +1 -1
  215. package/skills/prototype/workflows/promotion.md +1 -1
  216. package/skills/rebase/AGENTS.md +32 -0
  217. package/skills/rebase/CLAUDE.md +1 -32
  218. package/skills/recall/AGENTS.md +30 -0
  219. package/skills/recall/CLAUDE.md +1 -30
  220. package/skills/remember/AGENTS.md +31 -0
  221. package/skills/remember/CLAUDE.md +1 -31
  222. package/skills/reviews/SKILL.md +1 -1
  223. package/skills/session-log/AGENTS.md +32 -0
  224. package/skills/session-log/CLAUDE.md +1 -32
  225. package/skills/session-tidy/AGENTS.md +36 -0
  226. package/skills/session-tidy/CLAUDE.md +1 -36
  227. package/skills/skill-builder/AGENTS.md +49 -0
  228. package/skills/skill-builder/CLAUDE.md +1 -49
  229. package/skills/skill-builder/references/AGENTS.md +25 -0
  230. package/skills/skill-builder/references/CLAUDE.md +1 -25
  231. package/skills/skill-builder/references/deterministic-elements.md +1 -1
  232. package/skills/skill-builder/templates/AGENTS.md +14 -0
  233. package/skills/skill-builder/templates/CLAUDE.md +1 -14
  234. package/skills/skill-builder/workflows/AGENTS.md +19 -0
  235. package/skills/skill-builder/workflows/CLAUDE.md +1 -19
  236. package/skills/task-build/AGENTS.md +29 -0
  237. package/skills/task-build/CLAUDE.md +1 -29
  238. package/skills/update/AGENTS.md +38 -0
  239. package/skills/update/CLAUDE.md +1 -38
  240. package/system-prompts/AGENTS.md +17 -0
  241. package/system-prompts/CLAUDE.md +1 -17
  242. package/system-prompts/software-engineer.xml +3 -3
  243. package/agents/caveman.md +0 -73
  244. package/agents/clasp-deployment-orchestrator.md +0 -608
  245. package/agents/code-advisor.md +0 -23
  246. package/agents/deep-research.md +0 -152
  247. package/agents/docs-agent.md +0 -85
  248. package/commands/commit.md +0 -28
  249. package/commands/docupdate.md +0 -322
  250. package/commands/hook-log-extract.md +0 -70
  251. package/commands/hook-log-init.md +0 -76
  252. package/commands/implement.md +0 -102
  253. package/commands/plan.md +0 -14
  254. package/commands/pr-comments.md +0 -47
  255. package/commands/review-plan.md +0 -5
  256. package/commands/right-size.md +0 -15
  257. package/commands/sum.md +0 -30
  258. package/skills/imagegen/SKILL.md +0 -21
  259. package/skills/imagegen/scripts/config/__init__.py +0 -1
  260. package/skills/imagegen/scripts/config/constants.py +0 -28
  261. package/skills/imagegen/scripts/imagegen.py +0 -45
  262. package/skills/imagegen/scripts/imagegen_core.py +0 -528
  263. package/skills/imagegen/scripts/test_imagegen.py +0 -204
@@ -506,3 +506,174 @@ def test_dead_constant_stays_denied_on_every_attempt(neutral_root: Path) -> None
506
506
  "re-issue this write" in each_issue for each_issue in each_attempt
507
507
  ), f"A dead constant stays denied with the retry escape, got: {each_attempt}"
508
508
 
509
+
510
+ ALIAS_CONSTANTS_BODY = 'BASE_PROMPTS_DIRECTORY_NAME = "prompts"\nSTYLE_SHEET_FILENAME = "style.css"\n'
511
+
512
+ ALIASED_IMPORT_CONSUMER_BODY = (
513
+ "from style_guide_gen_constants.config import constants as sg\n"
514
+ "\n"
515
+ "def prompts_directory() -> str:\n"
516
+ " return sg.BASE_PROMPTS_DIRECTORY_NAME\n"
517
+ "\n"
518
+ "def style_sheet() -> str:\n"
519
+ " return sg.STYLE_SHEET_FILENAME\n"
520
+ )
521
+
522
+
523
+ def _build_alias_repository(
524
+ package_parent: Path,
525
+ consumer_directory: Path,
526
+ consumer_body: str,
527
+ ) -> Path:
528
+ package_directory = package_parent / "style_guide_gen_constants"
529
+ config_directory = package_directory / "config"
530
+ config_directory.mkdir(parents=True)
531
+ (package_directory / "__init__.py").write_text("", encoding="utf-8")
532
+ (config_directory / "__init__.py").write_text("", encoding="utf-8")
533
+ constants_path = config_directory / "constants.py"
534
+ constants_path.write_text(ALIAS_CONSTANTS_BODY, encoding="utf-8")
535
+ consumer_directory.mkdir(parents=True, exist_ok=True)
536
+ (consumer_directory / "style_guide_gen.py").write_text(consumer_body, encoding="utf-8")
537
+ return constants_path
538
+
539
+
540
+ def test_does_not_flag_constant_read_through_an_aliased_module_import(
541
+ neutral_root: Path,
542
+ ) -> None:
543
+ constants_path = _build_alias_repository(
544
+ neutral_root,
545
+ neutral_root / "style_guide_gen_constants",
546
+ ALIASED_IMPORT_CONSUMER_BODY,
547
+ )
548
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
549
+ assert issues == [], (
550
+ f"A constant read as an attribute on an aliased module import stays live, got: {issues}"
551
+ )
552
+
553
+
554
+ def test_does_not_flag_constant_read_through_an_alias_outside_the_package_tree(
555
+ neutral_root: Path,
556
+ ) -> None:
557
+ constants_path = _build_alias_repository(
558
+ neutral_root / "scripts",
559
+ neutral_root / "scripts",
560
+ ALIASED_IMPORT_CONSUMER_BODY,
561
+ )
562
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
563
+ assert issues == [], (
564
+ "A constant an aliased module import reads from outside the package tree "
565
+ f"stays live through the widened scan, got: {issues}"
566
+ )
567
+
568
+
569
+ def test_does_not_flag_constant_read_through_an_unaliased_module_import_outside_the_tree(
570
+ neutral_root: Path,
571
+ ) -> None:
572
+ consumer_body = (
573
+ "from style_guide_gen_constants.config import constants\n"
574
+ "\n"
575
+ "def prompts_directory() -> str:\n"
576
+ " return constants.BASE_PROMPTS_DIRECTORY_NAME\n"
577
+ "\n"
578
+ "def style_sheet() -> str:\n"
579
+ " return constants.STYLE_SHEET_FILENAME\n"
580
+ )
581
+ constants_path = _build_alias_repository(
582
+ neutral_root / "scripts",
583
+ neutral_root / "scripts",
584
+ consumer_body,
585
+ )
586
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
587
+ assert issues == [], (
588
+ f"A constant read on an unaliased imported module object stays live, got: {issues}"
589
+ )
590
+
591
+
592
+ def test_does_not_flag_constant_read_through_a_dotted_module_path_outside_the_tree(
593
+ neutral_root: Path,
594
+ ) -> None:
595
+ consumer_body = (
596
+ "import style_guide_gen_constants.config.constants\n"
597
+ "\n"
598
+ "def prompts_directory() -> str:\n"
599
+ " return style_guide_gen_constants.config.constants.BASE_PROMPTS_DIRECTORY_NAME\n"
600
+ "\n"
601
+ "def style_sheet() -> str:\n"
602
+ " return style_guide_gen_constants.config.constants.STYLE_SHEET_FILENAME\n"
603
+ )
604
+ constants_path = _build_alias_repository(
605
+ neutral_root / "scripts",
606
+ neutral_root / "scripts",
607
+ consumer_body,
608
+ )
609
+ issues = _check(ALIAS_CONSTANTS_BODY, str(constants_path))
610
+ assert issues == [], (
611
+ f"A constant read through the full dotted module path stays live, got: {issues}"
612
+ )
613
+
614
+
615
+ def test_does_not_flag_constant_read_through_an_alias_in_a_sibling_tree(
616
+ neutral_root: Path,
617
+ ) -> None:
618
+ constants_body = 'CROSS_TREE_CONSTANT = "cross"\nLOCALLY_DEAD_CONSTANT = "dead"\n'
619
+ sibling_consumer_body = (
620
+ "from shared.theme_db.config import constants as theme_constants\n"
621
+ "\n"
622
+ "def tally() -> str:\n"
623
+ " return theme_constants.CROSS_TREE_CONSTANT\n"
624
+ )
625
+ constants_path = _build_cross_tree_repository(
626
+ neutral_root, constants_body, sibling_consumer_body
627
+ )
628
+ issues = _check(constants_body, str(constants_path))
629
+ assert not any("CROSS_TREE_CONSTANT" in each_issue for each_issue in issues), (
630
+ "A constant a sibling tree reads as an attribute on an aliased module import "
631
+ f"must not be flagged, got: {issues}"
632
+ )
633
+ assert any("LOCALLY_DEAD_CONSTANT" in each_issue for each_issue in issues), (
634
+ f"A constant referenced nowhere in the repository stays flagged, got: {issues}"
635
+ )
636
+
637
+
638
+ def _build_alias_collision_repository(
639
+ repository_root: Path,
640
+ promoter_constants_body: str,
641
+ harness_constants_body: str,
642
+ harness_consumer_body: str,
643
+ ) -> Path:
644
+ promoter_config = repository_root / "promoter" / "config"
645
+ promoter_config.mkdir(parents=True)
646
+ promoter_constants_path = promoter_config / "constants.py"
647
+ promoter_constants_path.write_text(promoter_constants_body, encoding="utf-8")
648
+ harness_config = repository_root / "harness" / "config"
649
+ harness_config.mkdir(parents=True)
650
+ (harness_config / "other_constants.py").write_text(harness_constants_body, encoding="utf-8")
651
+ (repository_root / "harness" / "lockfile.py").write_text(
652
+ harness_consumer_body, encoding="utf-8"
653
+ )
654
+ return promoter_constants_path
655
+
656
+
657
+ def test_alias_attribute_read_on_an_unrelated_module_does_not_mask_a_dead_constant(
658
+ neutral_root: Path,
659
+ ) -> None:
660
+ promoter_constants_body = 'NEVER_READ_CONSTANT = "dead"\n'
661
+ harness_constants_body = 'NEVER_READ_CONSTANT = "twin"\n'
662
+ harness_consumer_body = (
663
+ "from harness.config import other_constants as oc\n"
664
+ "\n"
665
+ "def acquire() -> str:\n"
666
+ " return oc.NEVER_READ_CONSTANT\n"
667
+ )
668
+ promoter_constants_path = _build_alias_collision_repository(
669
+ neutral_root,
670
+ promoter_constants_body,
671
+ harness_constants_body,
672
+ harness_consumer_body,
673
+ )
674
+ issues = _check(promoter_constants_body, str(promoter_constants_path))
675
+ assert any("NEVER_READ_CONSTANT" in each_issue for each_issue in issues), (
676
+ "A constant whose only same-named twin is read as an attribute on an "
677
+ f"unrelated aliased module must still be flagged dead, got: {issues}"
678
+ )
679
+
@@ -1,6 +1,6 @@
1
1
  """Tests for magic-value allowlist alignment with CODE_RULES §HOOK-ENFORCED.
2
2
 
3
- CODE_RULES.md and AGENTS.md both state that only
3
+ CODE_RULES.md states that only
4
4
  0, 1, and -1 (plus their float forms 0.0, 1.0) are exempt from the
5
5
  magic-value check. Prior to this change, the hook silently allowed 2
6
6
  and 100 as well, making the hook more permissive than the written rule.
@@ -422,7 +422,8 @@ def test_main_logs_high_level_failure_when_restore_switch_fails(
422
422
 
423
423
  assert exit_code == 0
424
424
  assert state_file.exists()
425
- assert "[gh-pr-author-restore] failed to restore" in captured_streams.err
425
+ assert "[gh-pr-author-restore] Restore the gh account" in captured_streams.err
426
+ assert "gh account switch requires attention" in captured_streams.err
426
427
  assert "'jl-cmd'" in captured_streams.err
427
428
  assert str(state_file) in captured_streams.err
428
429
 
@@ -111,6 +111,10 @@ def test_intent_ending_message_emits_block_with_short_user_notice():
111
111
  assert parsed_response["systemMessage"] == USER_FACING_INTENT_ENDING_NOTICE
112
112
  assert parsed_response["suppressOutput"] is True
113
113
  assert "long-horizon-autonomy" in parsed_response["reason"]
114
+ assert "This turn ends with a promise of future work." in parsed_response["reason"]
115
+ assert "Complete that work with tool calls during this turn." in parsed_response[
116
+ "reason"
117
+ ]
114
118
 
115
119
 
116
120
  def test_next_steps_lead_in_emits_block():
@@ -0,0 +1,75 @@
1
+ # hooks/diagnostic
2
+
3
+ Hooks and scripts that collect, store, and query hook-firing records. The pipeline reads session JSONL transcripts, extracts hook attachment records, and writes them as rows into a Neon (Postgres) `hook_events` table.
4
+
5
+ ## Subdirectories
6
+
7
+ | Directory | Role |
8
+ |---|---|
9
+ | `migrations/` | SQL migration files for the `hook_events` schema |
10
+ | `queries/` | Parameterized SQL queries for inspecting blocked commands |
11
+
12
+ ## Key files
13
+
14
+ | File | What it does |
15
+ |---|---|
16
+ | `hook_log_init.py` | One-time setup: creates the Neon schema (runs `schema.sql`), then verifies read-write parity with a sentinel round-trip |
17
+ | `hook_log_extractor.py` | Disabled CLI: exits 0 without reading transcripts or rewriting offset state; body remains for a re-enable path that ingests `hook_*` attachments into Neon |
18
+ | `hook_log_stop_wrapper.py` | Disabled Stop wrapper stub: exits 0; not on the Stop dispatcher roster |
19
+ | `schema.sql` | DDL for the `hook_events` table, `blocked_commands` view, and supporting indexes |
20
+ | `requirements-hook-logs.txt` | Runtime dependencies (`psycopg`) for the extractor |
21
+ | `requirements-hook-logs-dev.txt` | Dev/test dependencies |
22
+ | `test_hook_log_extractor.py` | Tests for the extractor |
23
+ | `test_hook_log_init.py` | Tests for the schema-init script |
24
+ | `test_hook_log_stop_wrapper.py` | Tests for the Stop wrapper |
25
+
26
+ ## Schema overview (`schema.sql`)
27
+
28
+ The `hook_events` table captures one row per hook firing:
29
+
30
+ - `hook_event`, `hook_name`, `hook_category` — what fired
31
+ - `outcome` — `allowed`, `blocked`, or `ask`
32
+ - `tool_name`, `command_excerpt` — what tool was called
33
+ - `session_id`, `git_branch`, `cwd` — context
34
+ - `duration_ms`, `exit_code` — timing and result
35
+ - `source_jsonl_path`, `source_line_number` — idempotency key
36
+
37
+ The `blocked_commands` view filters to `outcome = 'blocked'`.
38
+
39
+ ## Conventions
40
+
41
+ - Extractor and Stop wrapper mains are disabled and exit 0 with no work.
42
+ - Constants for the extractor (table name, offset state file, timeout) live in `hooks_constants/hook_log_extractor_constants.py`.
43
+ - Tests run with `python -m pytest diagnostic/test_hook_log_*.py`.
44
+
45
+ ## Schema init
46
+
47
+ Run `hook_log_init.py` once per machine, or after rotating the Neon project.
48
+
49
+ Prerequisites: Bitwarden Secrets Manager CLI (`bws`) on PATH; a machine-account
50
+ token in `BWS_ACCESS_TOKEN` for the user environment (`setx` on Windows, shell
51
+ profile on macOS/Linux); Neon connection string stored as
52
+ `NEON_HOOK_LOGS_DATABASE_URL`; Python deps from `requirements-hook-logs.txt`.
53
+
54
+ ```
55
+ bws run -- python packages/claude-dev-env/hooks/diagnostic/hook_log_init.py
56
+ ```
57
+
58
+ `bws run` strips `BWS_ACCESS_TOKEN` from the child environment so the Python
59
+ process never sees it. The script verifies `NEON_HOOK_LOGS_DATABASE_URL`,
60
+ connects with a 5-second timeout, applies `schema.sql` with idempotent DDL,
61
+ runs a sentinel insert/select/delete round-trip, and prints the Neon host,
62
+ table name, and row count.
63
+
64
+ ## Operator CLI flags
65
+
66
+ `hook_log_extractor.py` and `hook_log_stop_wrapper.py` mains exit 0 with no work.
67
+ The extractor body still documents these flags for a re-enable path:
68
+
69
+ - default / `--incremental`: resume from `~/.claude/logs/hooks/.state/offsets.json`
70
+ - `--full-rebuild`: clear offsets, truncate `hook_events`, re-read every JSONL
71
+ - `--summary`: print the top-10 blockers of the last 24 hours
72
+ - `--query <name>`: run `queries/<name>.sql` (`top_blockers_overall`,
73
+ `top_blockers_last_24_hours`, `blocks_last_7_days`, `blocks_by_category`,
74
+ `blocks_by_tool`, `block_details_for_hook`)
75
+
@@ -1,43 +1 @@
1
- # hooks/diagnostic
2
-
3
- Hooks and scripts that collect, store, and query hook-firing records. The pipeline reads session JSONL transcripts, extracts hook attachment records, and writes them as rows into a Neon (Postgres) `hook_events` table.
4
-
5
- ## Subdirectories
6
-
7
- | Directory | Role |
8
- |---|---|
9
- | `migrations/` | SQL migration files for the `hook_events` schema |
10
- | `queries/` | Parameterized SQL queries for inspecting blocked commands |
11
-
12
- ## Key files
13
-
14
- | File | What it does |
15
- |---|---|
16
- | `hook_log_init.py` | One-time setup: creates the Neon schema (runs `schema.sql`), then verifies read-write parity with a sentinel round-trip |
17
- | `hook_log_extractor.py` | Disabled CLI: exits 0 without reading transcripts or rewriting offset state; body remains for a re-enable path that ingests `hook_*` attachments into Neon |
18
- | `hook_log_stop_wrapper.py` | Disabled Stop wrapper stub: exits 0; not on the Stop dispatcher roster |
19
- | `schema.sql` | DDL for the `hook_events` table, `blocked_commands` view, and supporting indexes |
20
- | `requirements-hook-logs.txt` | Runtime dependencies (`psycopg`) for the extractor |
21
- | `requirements-hook-logs-dev.txt` | Dev/test dependencies |
22
- | `test_hook_log_extractor.py` | Tests for the extractor |
23
- | `test_hook_log_init.py` | Tests for the schema-init script |
24
- | `test_hook_log_stop_wrapper.py` | Tests for the Stop wrapper |
25
-
26
- ## Schema overview (`schema.sql`)
27
-
28
- The `hook_events` table captures one row per hook firing:
29
-
30
- - `hook_event`, `hook_name`, `hook_category` — what fired
31
- - `outcome` — `allowed`, `blocked`, or `ask`
32
- - `tool_name`, `command_excerpt` — what tool was called
33
- - `session_id`, `git_branch`, `cwd` — context
34
- - `duration_ms`, `exit_code` — timing and result
35
- - `source_jsonl_path`, `source_line_number` — idempotency key
36
-
37
- The `blocked_commands` view filters to `outcome = 'blocked'`.
38
-
39
- ## Conventions
40
-
41
- - Extractor and Stop wrapper mains are disabled and exit 0 with no work.
42
- - Constants for the extractor (table name, offset state file, timeout) live in `hooks_constants/hook_log_extractor_constants.py`.
43
- - Tests run with `python -m pytest diagnostic/test_hook_log_*.py`.
1
+ @AGENTS.md
@@ -99,7 +99,7 @@ from hooks_constants.hook_log_extractor_constants import (
99
99
  STDERR_EXCERPT_MAX_CHARACTERS,
100
100
  STDOUT_EXCERPT_MAX_CHARACTERS,
101
101
  SUMMARY_COLUMN_HEADINGS,
102
- SUMMARY_NO_NEW_BLOCKS_MESSAGE,
102
+ SUMMARY_ZERO_BLOCKED_EVENTS_MESSAGE,
103
103
  SUMMARY_TABLE_COLUMN_GAP,
104
104
  TOP_BLOCKED_COMMAND_PREVIEW_MAX_CHARACTERS,
105
105
  TOP_BLOCKERS_LAST_24_HOURS_SQL,
@@ -780,7 +780,7 @@ def run_summary() -> int:
780
780
  except Exception:
781
781
  pass
782
782
  if not all_result_rows:
783
- print(SUMMARY_NO_NEW_BLOCKS_MESSAGE)
783
+ print(SUMMARY_ZERO_BLOCKED_EVENTS_MESSAGE)
784
784
  return EXIT_CODE_SUCCESS
785
785
  _print_summary_table(all_result_rows)
786
786
  return EXIT_CODE_SUCCESS
@@ -66,7 +66,7 @@ def verify_environment_variables() -> list[str]:
66
66
  child process invoked via ``bws run -- python hook_log_init.py``
67
67
  would therefore always fail even when the machine is configured
68
68
  correctly. The one-time ``setx BWS_ACCESS_TOKEN`` prerequisite is
69
- documented in ``packages/claude-dev-env/commands/hook-log-init.md``.
69
+ documented in ``packages/claude-dev-env/hooks/diagnostic/AGENTS.md``.
70
70
  """
71
71
  all_missing_variable_names: list[str] = []
72
72
  raw_database_url_value = os.environ.get(NEON_DATABASE_URL_ENVIRONMENT_VARIABLE)
@@ -172,7 +172,7 @@ def _print_missing_environment_variables(all_missing_variable_names: list[str])
172
172
 
173
173
 
174
174
  def main() -> int:
175
- """Entry point for the ``/hook-log-init`` slash command."""
175
+ """CLI entry for one-time Neon schema init."""
176
176
  all_missing_variable_names = verify_environment_variables()
177
177
  if all_missing_variable_names:
178
178
  _print_missing_environment_variables(all_missing_variable_names)
@@ -0,0 +1,16 @@
1
+ # hooks/diagnostic/migrations
2
+
3
+ SQL migration files for the `hook_events` Neon schema. Each file applies a schema change to the `hook_events` table or its indexes.
4
+
5
+ ## Files
6
+
7
+ | File | What it does |
8
+ |---|---|
9
+ | `2026-04-25-drop-themes-hook-events.sql` | Drops the `themes` hook-events table variant |
10
+ | `README.md` | Notes on the migration approach |
11
+
12
+ ## Conventions
13
+
14
+ - Run migrations manually against the Neon database using `psql` or the Neon console.
15
+ - The baseline schema lives in `diagnostic/schema.sql`.
16
+ - File names follow `YYYY-MM-DD-<description>.sql` for chronological ordering.
@@ -1,16 +1 @@
1
- # hooks/diagnostic/migrations
2
-
3
- SQL migration files for the `hook_events` Neon schema. Each file applies a schema change to the `hook_events` table or its indexes.
4
-
5
- ## Files
6
-
7
- | File | What it does |
8
- |---|---|
9
- | `2026-04-25-drop-themes-hook-events.sql` | Drops the `themes` hook-events table variant |
10
- | `README.md` | Notes on the migration approach |
11
-
12
- ## Conventions
13
-
14
- - Run migrations manually against the Neon database using `psql` or the Neon console.
15
- - The baseline schema lives in `diagnostic/schema.sql`.
16
- - File names follow `YYYY-MM-DD-<description>.sql` for chronological ordering.
1
+ @AGENTS.md
@@ -0,0 +1,19 @@
1
+ # hooks/diagnostic/queries
2
+
3
+ Parameterized SQL queries for inspecting the `hook_events` Neon table. Run these directly against the Neon database to analyze hook-firing patterns.
4
+
5
+ ## Files
6
+
7
+ | File | What it returns |
8
+ |---|---|
9
+ | `block_details_for_hook.sql` | Full details for all blocked events matching a given hook name |
10
+ | `blocks_by_category.sql` | Count of blocks grouped by hook category |
11
+ | `blocks_by_tool.sql` | Count of blocks grouped by tool name |
12
+ | `blocks_last_7_days.sql` | All blocked events from the last 7 days |
13
+ | `top_blockers_last_24_hours.sql` | Hook names with the most blocks in the last 24 hours |
14
+ | `top_blockers_overall.sql` | Hook names with the most blocks across all time |
15
+
16
+ ## Conventions
17
+
18
+ - Queries target the `hook_events` table and `blocked_commands` view defined in `diagnostic/schema.sql`.
19
+ - Run with `psql $DATABASE_URL -f <query>.sql` or paste into the Neon console.
@@ -1,19 +1 @@
1
- # hooks/diagnostic/queries
2
-
3
- Parameterized SQL queries for inspecting the `hook_events` Neon table. Run these directly against the Neon database to analyze hook-firing patterns.
4
-
5
- ## Files
6
-
7
- | File | What it returns |
8
- |---|---|
9
- | `block_details_for_hook.sql` | Full details for all blocked events matching a given hook name |
10
- | `blocks_by_category.sql` | Count of blocks grouped by hook category |
11
- | `blocks_by_tool.sql` | Count of blocks grouped by tool name |
12
- | `blocks_last_7_days.sql` | All blocked events from the last 7 days |
13
- | `top_blockers_last_24_hours.sql` | Hook names with the most blocks in the last 24 hours |
14
- | `top_blockers_overall.sql` | Hook names with the most blocks across all time |
15
-
16
- ## Conventions
17
-
18
- - Queries target the `hook_events` table and `blocked_commands` view defined in `diagnostic/schema.sql`.
19
- - Run with `psql $DATABASE_URL -f <query>.sql` or paste into the Neon console.
1
+ @AGENTS.md
@@ -617,7 +617,7 @@ def test_tool_name_extracted_from_hook_name_prefix() -> None:
617
617
  assert hook_log_extractor.extract_tool_name("UserPromptSubmit") is None
618
618
 
619
619
 
620
- def test_run_summary_prints_no_new_blocks_when_cursor_empty(
620
+ def test_run_summary_prints_zero_blocked_events_when_cursor_empty(
621
621
  capsys: pytest.CaptureFixture[str],
622
622
  ) -> None:
623
623
  fake_cursor = MagicMock()
@@ -632,7 +632,7 @@ def test_run_summary_prints_no_new_blocks_when_cursor_empty(
632
632
 
633
633
  captured = capsys.readouterr()
634
634
  assert exit_code == 0
635
- assert "No new blocks since last run." in captured.out
635
+ assert "Blocked events recorded in the last 24 hours: 0." in captured.out
636
636
 
637
637
 
638
638
  def test_run_summary_prints_table_when_rows_returned(
@@ -0,0 +1,31 @@
1
+ # hooks/git-hooks
2
+
3
+ Native git hooks that run outside the Claude Code lifecycle — invoked directly by git at commit and push time. The installer copies these scripts into the user's shared git-hooks directory (`core.hooksPath`).
4
+
5
+ ## Key files
6
+
7
+ | File | Git hook | What it does |
8
+ |---|---|---|
9
+ | `pre_commit.py` | `pre-commit` | Runs the CODE_RULES gate (`precommit_code_rules_gate.py`) over staged changes; exits 1 when any staged file has a blocking violation |
10
+ | `pre_push.py` | `pre-push` | Blocks a push that would land a non-`main` local branch onto remote `main` (or `master`), then runs the CODE_RULES gate. An existing branch's gate base is the merge base with the remote default branch; the gate process still diffs that base against checkout HEAD, so the surface matches the pushed tip only when HEAD is that tip. |
11
+ | `pre_push_base_reference.py` | — | Resolves a usable gate base for `pre_push.py`: reads the pushed remote name from git's arguments, then turns a symbolic default-branch head into a reference that git can resolve |
12
+ | `post_commit.py` | `post-commit` | Runs after a commit lands; performs any post-commit bookkeeping |
13
+ | `gate_utils.py` | — | Shared helpers: resolves the gate script path, checks that the path is a safe regular file |
14
+ | `test_config.py` | — | Test configuration helpers |
15
+ | `test_gate_utils.py` | — | Tests for `gate_utils.py` |
16
+ | `test_pre_commit.py` | — | Tests for `pre_commit.py` |
17
+ | `test_pre_push.py` | — | Tests for `pre_push.py` |
18
+ | `test_pre_push_base_reference.py` | — | Tests for the gate base resolution in `pre_push.py` |
19
+ | `conftest.py` | — | Puts this directory on `sys.path` and clears cached `config` modules, so each test module imports the hooks at the top of the file |
20
+
21
+ ## Subdirectory
22
+
23
+ | Directory | Role |
24
+ |---|---|
25
+ | `git_hooks_constants/` | Shared constants imported by the git-hook scripts |
26
+
27
+ ## Conventions
28
+
29
+ - The installer strips the `_` and `.py` suffix when copying into the live git-hooks path (e.g. `pre_commit.py` becomes `pre-commit`).
30
+ - Constants (exit codes, argument names, error messages) live in `git_hooks_constants/` and are imported at the top of each script.
31
+ - Run tests with `python -m pytest git-hooks/test_<name>.py`.
@@ -1,31 +1 @@
1
- # hooks/git-hooks
2
-
3
- Native git hooks that run outside the Claude Code lifecycle — invoked directly by git at commit and push time. The installer copies these scripts into the user's shared git-hooks directory (`core.hooksPath`).
4
-
5
- ## Key files
6
-
7
- | File | Git hook | What it does |
8
- |---|---|---|
9
- | `pre_commit.py` | `pre-commit` | Runs the CODE_RULES gate (`precommit_code_rules_gate.py`) over staged changes; exits 1 when any staged file has a blocking violation |
10
- | `pre_push.py` | `pre-push` | Blocks a push that would land a non-`main` local branch onto remote `main` (or `master`), then runs the CODE_RULES gate. An existing branch's gate base is the merge base with the remote default branch; the gate process still diffs that base against checkout HEAD, so the surface matches the pushed tip only when HEAD is that tip. |
11
- | `pre_push_base_reference.py` | — | Resolves a usable gate base for `pre_push.py`: reads the pushed remote name from git's arguments, then turns a symbolic default-branch head into a reference that git can resolve |
12
- | `post_commit.py` | `post-commit` | Runs after a commit lands; performs any post-commit bookkeeping |
13
- | `gate_utils.py` | — | Shared helpers: resolves the gate script path, checks that the path is a safe regular file |
14
- | `test_config.py` | — | Test configuration helpers |
15
- | `test_gate_utils.py` | — | Tests for `gate_utils.py` |
16
- | `test_pre_commit.py` | — | Tests for `pre_commit.py` |
17
- | `test_pre_push.py` | — | Tests for `pre_push.py` |
18
- | `test_pre_push_base_reference.py` | — | Tests for the gate base resolution in `pre_push.py` |
19
- | `conftest.py` | — | Puts this directory on `sys.path` and clears cached `config` modules, so each test module imports the hooks at the top of the file |
20
-
21
- ## Subdirectory
22
-
23
- | Directory | Role |
24
- |---|---|
25
- | `git_hooks_constants/` | Shared constants imported by the git-hook scripts |
26
-
27
- ## Conventions
28
-
29
- - The installer strips the `_` and `.py` suffix when copying into the live git-hooks path (e.g. `pre_commit.py` becomes `pre-commit`).
30
- - Constants (exit codes, argument names, error messages) live in `git_hooks_constants/` and are imported at the top of each script.
31
- - Run tests with `python -m pytest git-hooks/test_<name>.py`.
1
+ @AGENTS.md
@@ -0,0 +1,21 @@
1
+ # hooks/git-hooks/git_hooks_constants
2
+
3
+ Shared constants imported by the git-hook scripts in `git-hooks/`. Centralizes exit codes, argument names, and error messages so every tunable lives in one place.
4
+
5
+ ## Files
6
+
7
+ | File | Contents |
8
+ |---|---|
9
+ | `__init__.py` | Exports all constants; marks this as a package so `from git_hooks_constants import ...` resolves |
10
+
11
+ ## Key constants (defined in `__init__.py`)
12
+
13
+ - `GATE_INFRASTRUCTURE_FAILURE_EXIT_CODE` — exit code when the gate script cannot be found or launched
14
+ - `GATE_SCRIPT_NOT_FOUND_MESSAGE` — error message when the gate script path does not exist
15
+ - `INVOKE_GATE_FAILURE_MESSAGE` — error message when the gate subprocess fails to start
16
+ - `STAGED_SCOPE_ARGUMENT` — CLI argument passed to the gate script to scope it to staged changes
17
+
18
+ ## Conventions
19
+
20
+ - Import with `from git_hooks_constants import <CONSTANT>` from within the `git-hooks/` directory.
21
+ - Add new constants here rather than inline in the hook scripts.
@@ -1,21 +1 @@
1
- # hooks/git-hooks/git_hooks_constants
2
-
3
- Shared constants imported by the git-hook scripts in `git-hooks/`. Centralizes exit codes, argument names, and error messages so every tunable lives in one place.
4
-
5
- ## Files
6
-
7
- | File | Contents |
8
- |---|---|
9
- | `__init__.py` | Exports all constants; marks this as a package so `from git_hooks_constants import ...` resolves |
10
-
11
- ## Key constants (defined in `__init__.py`)
12
-
13
- - `GATE_INFRASTRUCTURE_FAILURE_EXIT_CODE` — exit code when the gate script cannot be found or launched
14
- - `GATE_SCRIPT_NOT_FOUND_MESSAGE` — error message when the gate script path does not exist
15
- - `INVOKE_GATE_FAILURE_MESSAGE` — error message when the gate subprocess fails to start
16
- - `STAGED_SCOPE_ARGUMENT` — CLI argument passed to the gate script to scope it to staged changes
17
-
18
- ## Conventions
19
-
20
- - Import with `from git_hooks_constants import <CONSTANT>` from within the `git-hooks/` directory.
21
- - Add new constants here rather than inline in the hook scripts.
1
+ @AGENTS.md
@@ -49,12 +49,9 @@ NO_PARSEABLE_STDIN_LINES_MESSAGE: str = (
49
49
  NO_PARSEABLE_STDIN_LINES_SENTINEL: str = "__no_parseable_stdin_lines__"
50
50
  UNRESOLVABLE_MERGE_BASE_SENTINEL: str = "__unresolvable_merge_base__"
51
51
  UNRESOLVABLE_MERGE_BASE_MESSAGE: str = (
52
- "claude-dev-env pre-push: git found no merge base between the pushed object "
53
- "and the default branch, so the gate scope is unknown and "
54
- "enforcement is skipped. That happens when the pushed branch and the "
55
- "default branch hold unrelated histories, or when a default-branch ref "
56
- "resolved and merge-base still could not name a shared commit "
57
- "(for example a shallow clone missing the connecting history)."
52
+ "claude-dev-env pre-push: CODE_RULES validation is pending because the pushed "
53
+ "object and default branch have no shared merge base. Restore shared history "
54
+ "or provide a reachable default branch, then run the push again."
58
55
  )
59
56
  LOCAL_BRANCH_REFERENCE_PREFIX: str = "refs/heads/"
60
57
  ORIGIN_HEAD_SYMBOLIC_REFERENCE: str = "refs/remotes/origin/HEAD"
@@ -63,6 +60,7 @@ ALL_DEFAULT_BRANCH_FALLBACK_REFERENCES: tuple[str, ...] = (
63
60
  "refs/remotes/origin/main",
64
61
  "refs/remotes/origin/master",
65
62
  )
63
+ REMOTE_BRANCH_REFERENCE_TEMPLATE: str = "refs/remotes/{remote}/{branch}"
66
64
  ALL_GIT_SYMBOLIC_REFERENCE_COMMAND_PREFIX: tuple[str, ...] = (
67
65
  "git",
68
66
  "symbolic-ref",