claude-dev-env 1.93.1 → 1.95.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/_shared/advisor/CLAUDE.md +2 -2
  2. package/_shared/advisor/advisor-protocol.md +35 -27
  3. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +3 -2
  4. package/_shared/advisor/scripts/model_tier_run_validator.py +23 -15
  5. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +81 -17
  6. package/_shared/pr-loop/CLAUDE.md +1 -0
  7. package/_shared/pr-loop/audit-contract.md +1 -1
  8. package/_shared/pr-loop/gh-payloads.md +3 -3
  9. package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
  10. package/_shared/pr-loop/scripts/README.md +2 -2
  11. package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
  12. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -69
  13. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
  14. package/_shared/pr-loop/state-schema.md +3 -22
  15. package/bin/CLAUDE.md +11 -2
  16. package/bin/ever-shipped-skills.mjs +70 -0
  17. package/bin/install.mjs +138 -13
  18. package/bin/install.prune.test.mjs +457 -0
  19. package/bin/install.test.mjs +10 -4
  20. package/docs/CODE_RULES.md +1 -1
  21. package/hooks/blocking/CLAUDE.md +2 -0
  22. package/hooks/blocking/code_rules_enforcer.py +4 -0
  23. package/hooks/blocking/code_rules_shared.py +82 -0
  24. package/hooks/blocking/code_rules_test_layout.py +9 -3
  25. package/hooks/blocking/pii_commit_command.py +398 -0
  26. package/hooks/blocking/pii_payload_scan.py +133 -0
  27. package/hooks/blocking/pii_prevention_blocker.py +151 -449
  28. package/hooks/blocking/plain_language_blocker.py +138 -4
  29. package/hooks/blocking/sensitive_file_protector.py +114 -48
  30. package/hooks/blocking/tdd_enforcer.py +9 -2
  31. package/hooks/blocking/test_code_rules_enforcer_scratchpad.py +105 -0
  32. package/hooks/blocking/test_code_rules_shared.py +181 -0
  33. package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
  34. package/hooks/blocking/test_plain_language_blocker_allowlist.py +184 -0
  35. package/hooks/blocking/test_sensitive_file_protector.py +185 -0
  36. package/hooks/blocking/test_tdd_enforcer_scratchpad.py +105 -0
  37. package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
  38. package/hooks/hooks_constants/CLAUDE.md +4 -2
  39. package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
  40. package/hooks/hooks_constants/harness_scratchpad_constants.py +17 -0
  41. package/hooks/hooks_constants/local_identity.py +65 -15
  42. package/hooks/hooks_constants/pii_prevention_constants.py +16 -0
  43. package/hooks/hooks_constants/plain_language_blocker_constants.py +5 -0
  44. package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
  45. package/hooks/hooks_constants/sensitive_file_protector_constants.py +42 -0
  46. package/hooks/hooks_constants/test_local_identity.py +68 -0
  47. package/hooks/pyproject.toml +75 -4
  48. package/hooks/validators/CLAUDE.md +1 -1
  49. package/hooks/validators/README.md +2 -0
  50. package/hooks/validators/python_style_checks.py +114 -136
  51. package/hooks/validators/python_style_helpers.py +95 -0
  52. package/hooks/validators/test_python_style_checks.py +0 -164
  53. package/hooks/validators/test_python_style_checks_decorator_gap.py +119 -0
  54. package/hooks/validators/test_python_style_fixes.py +251 -0
  55. package/hooks/validators/test_python_style_helpers.py +125 -0
  56. package/package.json +1 -1
  57. package/rules/CLAUDE.md +1 -0
  58. package/rules/anti-corollary-tests.md +69 -0
  59. package/rules/bdd.md +1 -3
  60. package/rules/code-reviews.md +1 -1
  61. package/rules/gh-paginate.md +1 -1
  62. package/rules/plain-language.md +2 -0
  63. package/scripts/CLAUDE.md +10 -1
  64. package/scripts/Get-SessionAccount.ps1 +210 -0
  65. package/scripts/tests/CLAUDE.md +15 -1
  66. package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
  67. package/skills/CLAUDE.md +6 -27
  68. package/skills/anthropic-plan/SKILL.md +1 -13
  69. package/skills/autoconverge/CLAUDE.md +5 -2
  70. package/skills/autoconverge/SKILL.md +112 -387
  71. package/skills/autoconverge/reference/CLAUDE.md +4 -1
  72. package/skills/autoconverge/reference/closing-report.md +9 -2
  73. package/skills/autoconverge/reference/convergence.md +26 -22
  74. package/skills/autoconverge/reference/headless-safety.md +44 -0
  75. package/skills/autoconverge/reference/multi-pr.md +88 -0
  76. package/skills/autoconverge/reference/self-closing-loop.md +84 -0
  77. package/skills/autoconverge/reference/stop-conditions.md +21 -13
  78. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
  79. package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
  80. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
  81. package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
  82. package/skills/autoconverge/workflow/converge.mjs +286 -96
  83. package/skills/bugteam/CLAUDE.md +1 -1
  84. package/skills/bugteam/CONSTRAINTS.md +3 -3
  85. package/skills/bugteam/PROMPTS.md +8 -19
  86. package/skills/bugteam/SKILL.md +13 -14
  87. package/skills/bugteam/reference/CLAUDE.md +1 -1
  88. package/skills/bugteam/reference/README.md +2 -3
  89. package/skills/bugteam/reference/audit-and-teammates.md +2 -2
  90. package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
  91. package/skills/bugteam/reference/github-pr-reviews.md +56 -38
  92. package/skills/bugteam/reference/team-setup.md +11 -11
  93. package/skills/bugteam/scripts/CLAUDE.md +6 -6
  94. package/skills/bugteam/scripts/README.md +20 -8
  95. package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
  96. package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
  97. package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
  98. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
  99. package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
  100. package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
  101. package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
  102. package/skills/closeout/SKILL.md +153 -0
  103. package/skills/closeout/reference/handoff-prompt-template.md +72 -0
  104. package/skills/closeout/reference/issue-body-templates.md +108 -0
  105. package/skills/closeout/reference/pii-redaction-checklist.md +36 -0
  106. package/skills/copilot-finding-triage/SKILL.md +80 -28
  107. package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
  108. package/skills/copilot-finding-triage/templates/notification.md +8 -3
  109. package/skills/everything-search/SKILL.md +1 -2
  110. package/skills/grokify/SKILL.md +58 -0
  111. package/skills/grokify/templates/handoff-template.md +92 -0
  112. package/skills/orchestrator/SKILL.md +35 -25
  113. package/skills/orchestrator-refresh/SKILL.md +15 -11
  114. package/skills/pr-converge/CLAUDE.md +1 -1
  115. package/skills/pr-converge/SKILL.md +132 -233
  116. package/skills/pr-converge/reference/convergence-gates.md +102 -66
  117. package/skills/pr-converge/reference/examples.md +37 -25
  118. package/skills/pr-converge/reference/fix-protocol.md +7 -7
  119. package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
  120. package/skills/pr-converge/reference/per-tick.md +64 -41
  121. package/skills/pr-converge/reference/state-schema.md +27 -2
  122. package/skills/pr-converge/scripts/CLAUDE.md +8 -0
  123. package/skills/pr-converge/scripts/README.md +4 -3
  124. package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
  125. package/skills/pr-converge/scripts/check_convergence.py +189 -645
  126. package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
  127. package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
  128. package/skills/pr-converge/scripts/conftest.py +8 -0
  129. package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
  130. package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
  131. package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
  132. package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
  133. package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
  134. package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
  135. package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
  136. package/skills/pr-fix-protocol/SKILL.md +20 -20
  137. package/skills/privacy-hygiene/SKILL.md +4 -3
  138. package/skills/reviewer-gates/SKILL.md +26 -8
  139. package/skills/session-log/SKILL.md +11 -12
  140. package/skills/session-tidy/SKILL.md +40 -30
  141. package/skills/skill-builder/CLAUDE.md +13 -10
  142. package/skills/skill-builder/SKILL.md +31 -31
  143. package/skills/skill-builder/references/CLAUDE.md +10 -6
  144. package/skills/skill-builder/references/delegation-map.md +13 -4
  145. package/skills/skill-builder/references/description-field.md +113 -0
  146. package/skills/skill-builder/references/self-audit-checklist.md +21 -4
  147. package/skills/skill-builder/references/skill-modularity.md +113 -0
  148. package/skills/skill-builder/references/skill-types.md +4 -0
  149. package/skills/skill-builder/templates/CLAUDE.md +4 -4
  150. package/skills/skill-builder/templates/gap-analysis.md +25 -1
  151. package/skills/skill-builder/workflows/CLAUDE.md +6 -4
  152. package/skills/skill-builder/workflows/improve-skill.md +17 -16
  153. package/skills/skill-builder/workflows/new-skill.md +34 -10
  154. package/skills/skill-builder/workflows/polish-skill.md +59 -43
  155. package/skills/team-advisor/SKILL.md +15 -11
  156. package/skills/usage-pause/SKILL.md +10 -14
  157. package/system-prompts/software-engineer.xml +7 -6
  158. package/hooks/validators/test_verify_paths.py +0 -32
  159. package/hooks/validators/verify_paths.py +0 -57
  160. package/skills/bdd-protocol/CLAUDE.md +0 -26
  161. package/skills/bdd-protocol/SKILL.md +0 -30
  162. package/skills/bdd-protocol/references/CLAUDE.md +0 -10
  163. package/skills/bdd-protocol/references/anti-patterns.md +0 -26
  164. package/skills/bdd-protocol/references/example-mapping.md +0 -23
  165. package/skills/bg-agent/CLAUDE.md +0 -17
  166. package/skills/bg-agent/SKILL.md +0 -69
  167. package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
  168. package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
  169. package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
  170. package/skills/caveman/CLAUDE.md +0 -15
  171. package/skills/caveman/SKILL.md +0 -38
  172. package/skills/code/CLAUDE.md +0 -17
  173. package/skills/code/SKILL.md +0 -178
  174. package/skills/deep-research/CLAUDE.md +0 -17
  175. package/skills/deep-research/SKILL.md +0 -80
  176. package/skills/findbugs/CLAUDE.md +0 -20
  177. package/skills/findbugs/SKILL.md +0 -241
  178. package/skills/fixbugs/CLAUDE.md +0 -19
  179. package/skills/fixbugs/SKILL.md +0 -142
  180. package/skills/gh-paginate/CLAUDE.md +0 -18
  181. package/skills/gh-paginate/SKILL.md +0 -84
  182. package/skills/gotcha/CLAUDE.md +0 -33
  183. package/skills/gotcha/SKILL.md +0 -73
  184. package/skills/implement/CLAUDE.md +0 -27
  185. package/skills/implement/SKILL.md +0 -66
  186. package/skills/implement/scripts/CLAUDE.md +0 -22
  187. package/skills/implement/scripts/append_note.py +0 -133
  188. package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
  189. package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
  190. package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
  191. package/skills/implement/scripts/test_append_note.py +0 -191
  192. package/skills/log-audit/CLAUDE.md +0 -20
  193. package/skills/log-audit/SKILL.md +0 -66
  194. package/skills/log-audit/reference/CLAUDE.md +0 -9
  195. package/skills/log-audit/reference/charter.md +0 -52
  196. package/skills/log-audit/scripts/CLAUDE.md +0 -27
  197. package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
  198. package/skills/log-audit/scripts/collect_log_window.py +0 -199
  199. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
  200. package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
  201. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
  202. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
  203. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
  204. package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
  205. package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
  206. package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
  207. package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
  208. package/skills/logifix/CLAUDE.md +0 -36
  209. package/skills/logifix/SKILL.md +0 -69
  210. package/skills/logifix/scripts/CLAUDE.md +0 -16
  211. package/skills/logifix/scripts/logifix.ps1 +0 -205
  212. package/skills/monitor-open-prs/CLAUDE.md +0 -34
  213. package/skills/monitor-open-prs/SKILL.md +0 -88
  214. package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
  215. package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
  216. package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
  217. package/skills/monitor-open-prs/test_skill_contract.py +0 -27
  218. package/skills/post-audit-findings/SKILL.md +0 -80
  219. package/skills/pr-consistency-audit/CLAUDE.md +0 -34
  220. package/skills/pr-consistency-audit/SKILL.md +0 -116
  221. package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
  222. package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
  223. package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
  224. package/skills/pr-review-responder/CLAUDE.md +0 -35
  225. package/skills/pr-review-responder/EXAMPLES.md +0 -590
  226. package/skills/pr-review-responder/PRINCIPLES.md +0 -533
  227. package/skills/pr-review-responder/README.md +0 -168
  228. package/skills/pr-review-responder/SKILL.md +0 -203
  229. package/skills/pr-review-responder/TESTING.md +0 -350
  230. package/skills/pr-scope-resolve/SKILL.md +0 -45
  231. package/skills/pre-compact/CLAUDE.md +0 -24
  232. package/skills/pre-compact/SKILL.md +0 -134
  233. package/skills/qbug/CLAUDE.md +0 -40
  234. package/skills/qbug/SKILL.md +0 -387
  235. package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
  236. package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
  237. package/skills/refine/CLAUDE.md +0 -44
  238. package/skills/refine/SKILL.md +0 -262
  239. package/skills/refine/templates/CLAUDE.md +0 -17
  240. package/skills/refine/templates/implementation-notes-template.html +0 -56
  241. package/skills/refine/templates/plan-template.md +0 -60
  242. package/skills/research-mode/CLAUDE.md +0 -35
  243. package/skills/research-mode/SKILL.md +0 -53
  244. package/skills/structure-prompt/CLAUDE.md +0 -42
  245. package/skills/structure-prompt/SKILL.md +0 -44
  246. package/skills/structure-prompt/reference/CLAUDE.md +0 -28
  247. package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
  248. package/skills/structure-prompt/reference/block-classification.md +0 -27
  249. package/skills/structure-prompt/reference/canonical-case.md +0 -48
  250. package/skills/structure-prompt/reference/citation-depth.md +0 -70
  251. package/skills/structure-prompt/reference/cleanup.md +0 -33
  252. package/skills/structure-prompt/reference/constraints.md +0 -33
  253. package/skills/structure-prompt/reference/directives.md +0 -37
  254. package/skills/structure-prompt/reference/examples.md +0 -72
  255. package/skills/structure-prompt/reference/instantiation.md +0 -51
  256. package/skills/structure-prompt/reference/output-contract.md +0 -72
  257. package/skills/structure-prompt/reference/per-category.md +0 -23
  258. package/skills/structure-prompt/reference/persona.md +0 -38
  259. package/skills/structure-prompt/reference/research.md +0 -33
  260. package/skills/structure-prompt/reference/structure.md +0 -28
  261. package/skills/verified-build/CLAUDE.md +0 -33
  262. package/skills/verified-build/SKILL.md +0 -33
@@ -1,366 +1,31 @@
1
+ """Skill-path entry for bugteam fix_hookspath.
2
+
3
+ Delegates to the package shared home:
4
+ ``_shared/pr-loop/scripts/fix_hookspath.py``.
5
+ """
6
+
1
7
  from __future__ import annotations
2
8
 
3
- import argparse
4
- import subprocess
5
9
  import sys
6
10
  from pathlib import Path
7
11
 
8
- from bugteam_scripts_constants.bugteam_fix_hookspath_constants import (
9
- ALL_CANONICAL_HOOKS_DIRECTORY_COMPONENTS,
10
- ALL_GLOBAL_HOOKS_PATH_ARGUMENTS,
11
- ALL_HOME_ENV_VAR_NAMES,
12
- GIT_DIRECTORY_NAME,
13
- HOOKS_PATH_SUFFIX,
14
- PREFLIGHT_NO_PYTEST_FLAG,
15
- PREFLIGHT_REPO_ROOT_FLAG,
12
+ _shared_pr_loop_scripts_directory = (
13
+ Path(__file__).resolve().parents[3] / "_shared" / "pr-loop" / "scripts"
14
+ )
15
+ if str(_shared_pr_loop_scripts_directory) not in sys.path:
16
+ sys.path.insert(0, str(_shared_pr_loop_scripts_directory))
17
+
18
+ from fix_hookspath import ( # noqa: E402
19
+ find_repository_root, # noqa: F401
20
+ is_canonical_hooks_path, # noqa: F401
21
+ list_local_core_hooks_path_values, # noqa: F401
22
+ main,
23
+ normalize_hooks_path, # noqa: F401
24
+ read_global_core_hooks_path, # noqa: F401
25
+ resolve_canonical_hooks_directory, # noqa: F401
26
+ set_global_core_hooks_path, # noqa: F401
27
+ unset_local_core_hooks_path, # noqa: F401
16
28
  )
17
-
18
-
19
- def _expected_hooks_path_suffix() -> str:
20
- return HOOKS_PATH_SUFFIX
21
-
22
-
23
- def _canonical_hooks_directory_components() -> tuple[str, str, str]:
24
- return ALL_CANONICAL_HOOKS_DIRECTORY_COMPONENTS
25
-
26
-
27
- def _home_env_var_names() -> tuple[str, str]:
28
- return ALL_HOME_ENV_VAR_NAMES
29
-
30
-
31
- def resolve_canonical_hooks_directory(
32
- all_environment_overrides: dict[str, str] | None,
33
- ) -> Path:
34
- """Resolve the canonical hooks directory under the user's home directory.
35
-
36
- When environment overrides are provided, checks HOME/USERPROFILE overrides
37
- first before falling back to pathlib.Path.home().
38
-
39
- Args:
40
- all_environment_overrides: Optional dict of environment variable
41
- overrides for resolving the home directory.
42
-
43
- Returns:
44
- The resolved Path to the canonical hooks directory.
45
- """
46
- components = _canonical_hooks_directory_components()
47
- if all_environment_overrides is not None:
48
- for each_env_var_name in _home_env_var_names():
49
- home_value = all_environment_overrides.get(each_env_var_name)
50
- if home_value:
51
- return Path(home_value).joinpath(*components)
52
- return Path.home().joinpath(*components)
53
-
54
-
55
- def list_local_core_hooks_path_values(
56
- repository_root: Path,
57
- all_environment_overrides: dict[str, str] | None,
58
- ) -> list[str]:
59
- """Retrieve the local core.hooksPath values for a given repository.
60
-
61
- Args:
62
- repository_root: The repository root for running git config.
63
- all_environment_overrides: Optional env overrides for git.
64
-
65
- Returns:
66
- List of local core.hooksPath strings, or empty list when unset.
67
-
68
- Raises:
69
- RuntimeError: When git emits a non-zero exit with non-empty stderr;
70
- distinguishes a real git failure from the expected "key unset"
71
- case (exit 1 with empty stderr).
72
- """
73
- git_command = [
74
- "git",
75
- "-C",
76
- str(repository_root),
77
- "config",
78
- "--local",
79
- "--get-all",
80
- "core.hooksPath",
81
- ]
82
- completed_process = subprocess.run(
83
- git_command,
84
- capture_output=True,
85
- text=True,
86
- encoding="utf-8",
87
- errors="replace",
88
- check=False,
89
- env=all_environment_overrides,
90
- )
91
- if completed_process.returncode != 0:
92
- if completed_process.stderr.strip():
93
- raise RuntimeError(
94
- f"git config --local --get-all core.hooksPath failed on "
95
- f"{repository_root} (exit {completed_process.returncode}): "
96
- f"{completed_process.stderr.strip()}"
97
- )
98
- return []
99
- return [
100
- each_line.strip()
101
- for each_line in completed_process.stdout.splitlines()
102
- if each_line.strip()
103
- ]
104
-
105
-
106
- def read_global_core_hooks_path(
107
- all_environment_overrides: dict[str, str] | None,
108
- ) -> str:
109
- """Read the global core.hooksPath git configuration value.
110
-
111
- Args:
112
- all_environment_overrides: Optional env overrides for git.
113
-
114
- Returns:
115
- The global core.hooksPath value, or empty string when unset.
116
-
117
- Raises:
118
- RuntimeError: When git emits a non-zero exit with non-empty stderr;
119
- distinguishes a real git failure from the expected "key unset"
120
- case (exit 1 with empty stderr).
121
- """
122
- completed_process = subprocess.run(
123
- list(ALL_GLOBAL_HOOKS_PATH_ARGUMENTS),
124
- capture_output=True,
125
- text=True,
126
- encoding="utf-8",
127
- errors="replace",
128
- check=False,
129
- env=all_environment_overrides,
130
- )
131
- if completed_process.returncode != 0:
132
- if completed_process.stderr.strip():
133
- raise RuntimeError(
134
- f"git config --global --get core.hooksPath failed "
135
- f"(exit {completed_process.returncode}): "
136
- f"{completed_process.stderr.strip()}"
137
- )
138
- return ""
139
- return completed_process.stdout.strip()
140
-
141
-
142
- def unset_local_core_hooks_path(
143
- repository_root: Path,
144
- all_environment_overrides: dict[str, str] | None,
145
- ) -> int:
146
- """Remove the local core.hooksPath configuration for a repository.
147
-
148
- Args:
149
- repository_root: The repository root for running git config.
150
- all_environment_overrides: Optional env overrides for git.
151
-
152
- Returns:
153
- The git exit code (0 on success, non-zero on failure).
154
- """
155
- git_command = [
156
- "git",
157
- "-C",
158
- str(repository_root),
159
- "config",
160
- "--local",
161
- "--unset-all",
162
- "core.hooksPath",
163
- ]
164
- completed_process = subprocess.run(
165
- git_command,
166
- capture_output=True,
167
- text=True,
168
- check=False,
169
- env=all_environment_overrides,
170
- )
171
- return completed_process.returncode
172
-
173
-
174
- def set_global_core_hooks_path(
175
- target_value: str,
176
- all_environment_overrides: dict[str, str] | None,
177
- ) -> int:
178
- """Set the global core.hooksPath git configuration value.
179
-
180
- Args:
181
- target_value: The hooks path value to set globally.
182
- all_environment_overrides: Optional env overrides for git.
183
-
184
- Returns:
185
- The git exit code (0 on success, non-zero on failure).
186
- """
187
- git_command = ["git", "config", "--global", "core.hooksPath", target_value]
188
- completed_process = subprocess.run(
189
- git_command,
190
- capture_output=True,
191
- text=True,
192
- check=False,
193
- env=all_environment_overrides,
194
- )
195
- return completed_process.returncode
196
-
197
-
198
- def normalize_hooks_path(raw_value: str) -> str:
199
- return raw_value.replace("\\", "/").rstrip("/")
200
-
201
-
202
- def is_canonical_hooks_path(raw_value: str) -> bool:
203
- if not raw_value:
204
- return False
205
- return normalize_hooks_path(raw_value).endswith(_expected_hooks_path_suffix())
206
-
207
-
208
- def find_repository_root(start: Path) -> Path:
209
- """Find the repository root by walking up from the starting directory.
210
-
211
- Searches for a ``.git`` directory or file in parent directories.
212
-
213
- Args:
214
- start: The directory to start searching from.
215
-
216
- Returns:
217
- The repository root path, or *start* when no repository is found.
218
- """
219
- resolved_start = start.resolve()
220
- candidate_paths = [resolved_start, *resolved_start.parents]
221
- for each_candidate in candidate_paths:
222
- marker = each_candidate / GIT_DIRECTORY_NAME
223
- if marker.is_dir() or marker.is_file():
224
- return each_candidate
225
- return resolved_start
226
-
227
-
228
- def rerun_preflight(
229
- repository_root: Path,
230
- all_environment_overrides: dict[str, str] | None,
231
- ) -> int:
232
- """Re-run bugteam_preflight.py after fixing core.hooksPath.
233
-
234
- Args:
235
- repository_root: The repository root to pass to preflight.
236
- all_environment_overrides: Optional env overrides for the subprocess.
237
-
238
- Returns:
239
- The preflight exit code (0 on success, non-zero on failure).
240
- """
241
- preflight_script_path = Path(__file__).resolve().parent / "bugteam_preflight.py"
242
- rerun_command = [
243
- sys.executable,
244
- str(preflight_script_path),
245
- PREFLIGHT_NO_PYTEST_FLAG,
246
- PREFLIGHT_REPO_ROOT_FLAG,
247
- str(repository_root),
248
- ]
249
- completed_process = subprocess.run(
250
- rerun_command,
251
- check=False,
252
- env=all_environment_overrides,
253
- )
254
- return completed_process.returncode
255
-
256
-
257
- def parse_arguments(all_argv: list[str] | None) -> argparse.Namespace:
258
- """Parse command-line arguments for the hooks-path fix script.
259
-
260
- Args:
261
- all_argv: Command-line argument list (pass None for defaults).
262
-
263
- Returns:
264
- Parsed namespace with the repo_root attribute.
265
- """
266
- parser = argparse.ArgumentParser(
267
- description=(
268
- "Auto-fix core.hooksPath when bugteam preflight detects a stale override. "
269
- "Removes a local-scope override and ensures global core.hooksPath points "
270
- "at the canonical claude-dev-env git-hooks directory."
271
- ),
272
- )
273
- parser.add_argument(
274
- "--repo-root",
275
- type=Path,
276
- default=None,
277
- help="Repository root (default: discover from cwd).",
278
- )
279
- return parser.parse_args(all_argv)
280
-
281
-
282
- def main(
283
- all_argv: list[str] | None,
284
- *,
285
- all_environment_overrides: dict[str, str] | None,
286
- ) -> int:
287
- """Fix core.hooksPath and rerun bugteam preflight.
288
-
289
- Resolves the canonical hooks directory, checks for stale local overrides,
290
- removes them if found, ensures global core.hooksPath is correct, then
291
- reruns bugteam_preflight to verify.
292
-
293
- Args:
294
- all_argv: Command-line arguments to parse.
295
- all_environment_overrides: Optional environment overrides for git.
296
-
297
- Returns:
298
- Zero on success, non-zero on failure.
299
- """
300
- arguments = parse_arguments(all_argv)
301
- start_directory = Path.cwd()
302
- repository_root = (
303
- arguments.repo_root.resolve()
304
- if arguments.repo_root is not None
305
- else find_repository_root(start_directory)
306
- )
307
- canonical_hooks_directory = resolve_canonical_hooks_directory(all_environment_overrides)
308
- expected_suffix = _expected_hooks_path_suffix()
309
- if not canonical_hooks_directory.is_dir():
310
- print(
311
- "bugteam_fix_hookspath: canonical hooks directory does not exist: "
312
- f"{canonical_hooks_directory}\n"
313
- "Run: npx claude-dev-env .\n"
314
- "Then re-run /bugteam. The directory must end in "
315
- f"'{expected_suffix}' and contain the claude-dev-env git hook shims.",
316
- file=sys.stderr,
317
- )
318
- return 1
319
- local_hooks_path_values = list_local_core_hooks_path_values(
320
- repository_root,
321
- all_environment_overrides,
322
- )
323
- has_non_canonical_local_override = any(
324
- not is_canonical_hooks_path(each_value)
325
- for each_value in local_hooks_path_values
326
- )
327
- if has_non_canonical_local_override:
328
- unset_local_returncode = unset_local_core_hooks_path(
329
- repository_root, all_environment_overrides
330
- )
331
- if unset_local_returncode != 0:
332
- print(
333
- "bugteam_fix_hookspath: failed to unset local core.hooksPath on "
334
- f"{repository_root} (git exit {unset_local_returncode}).",
335
- file=sys.stderr,
336
- )
337
- return 1
338
- print(
339
- "bugteam_fix_hookspath: removed stale local core.hooksPath override on "
340
- f"{repository_root}",
341
- file=sys.stderr,
342
- )
343
- current_global_value = read_global_core_hooks_path(all_environment_overrides)
344
- if not is_canonical_hooks_path(current_global_value):
345
- canonical_target_value = str(canonical_hooks_directory).replace("\\", "/")
346
- global_set_exit_code = set_global_core_hooks_path(
347
- canonical_target_value,
348
- all_environment_overrides,
349
- )
350
- if global_set_exit_code != 0:
351
- print(
352
- "bugteam_fix_hookspath: failed to set global core.hooksPath to "
353
- f"{canonical_target_value} (git exit {global_set_exit_code}).",
354
- file=sys.stderr,
355
- )
356
- return 1
357
- print(
358
- "bugteam_fix_hookspath: set global core.hooksPath to "
359
- f"{canonical_target_value}",
360
- file=sys.stderr,
361
- )
362
- return rerun_preflight(repository_root, all_environment_overrides)
363
-
364
29
 
365
30
  if __name__ == "__main__":
366
- raise SystemExit(main(None, all_environment_overrides=None))
31
+ raise SystemExit(main(sys.argv[1:], None))