claude-dev-env 1.93.1 → 1.94.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/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/audit-contract.md +1 -1
- package/_shared/pr-loop/gh-payloads.md +3 -3
- package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
- package/_shared/pr-loop/scripts/README.md +2 -2
- package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -69
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
- package/_shared/pr-loop/state-schema.md +3 -22
- package/bin/CLAUDE.md +1 -1
- package/bin/install.mjs +2 -7
- package/bin/install.test.mjs +10 -4
- package/hooks/blocking/CLAUDE.md +2 -0
- package/hooks/blocking/pii_commit_command.py +398 -0
- package/hooks/blocking/pii_payload_scan.py +133 -0
- package/hooks/blocking/pii_prevention_blocker.py +151 -449
- package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
- package/hooks/hooks_constants/CLAUDE.md +2 -2
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
- package/hooks/hooks_constants/local_identity.py +65 -15
- package/hooks/hooks_constants/pii_prevention_constants.py +16 -0
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
- package/hooks/hooks_constants/test_local_identity.py +68 -0
- package/package.json +1 -1
- package/scripts/CLAUDE.md +10 -1
- package/scripts/Get-SessionAccount.ps1 +210 -0
- package/scripts/tests/CLAUDE.md +15 -1
- package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
- package/skills/CLAUDE.md +3 -25
- package/skills/anthropic-plan/SKILL.md +1 -13
- package/skills/autoconverge/CLAUDE.md +5 -2
- package/skills/autoconverge/SKILL.md +112 -387
- package/skills/autoconverge/reference/CLAUDE.md +4 -1
- package/skills/autoconverge/reference/closing-report.md +9 -2
- package/skills/autoconverge/reference/convergence.md +26 -22
- package/skills/autoconverge/reference/headless-safety.md +44 -0
- package/skills/autoconverge/reference/multi-pr.md +88 -0
- package/skills/autoconverge/reference/self-closing-loop.md +84 -0
- package/skills/autoconverge/reference/stop-conditions.md +21 -13
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
- package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +284 -94
- package/skills/bugteam/CLAUDE.md +1 -1
- package/skills/bugteam/CONSTRAINTS.md +3 -3
- package/skills/bugteam/PROMPTS.md +8 -19
- package/skills/bugteam/SKILL.md +13 -14
- package/skills/bugteam/reference/CLAUDE.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
- package/skills/bugteam/reference/github-pr-reviews.md +56 -38
- package/skills/bugteam/reference/team-setup.md +11 -11
- package/skills/bugteam/scripts/CLAUDE.md +6 -6
- package/skills/bugteam/scripts/README.md +20 -8
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
- package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
- package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
- package/skills/copilot-finding-triage/SKILL.md +80 -28
- package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
- package/skills/copilot-finding-triage/templates/notification.md +8 -3
- package/skills/everything-search/SKILL.md +1 -2
- package/skills/grokify/SKILL.md +58 -0
- package/skills/grokify/templates/handoff-template.md +92 -0
- package/skills/orchestrator/SKILL.md +12 -8
- package/skills/orchestrator-refresh/SKILL.md +3 -3
- package/skills/pr-converge/SKILL.md +132 -233
- package/skills/pr-converge/reference/convergence-gates.md +102 -66
- package/skills/pr-converge/reference/examples.md +37 -25
- package/skills/pr-converge/reference/fix-protocol.md +7 -7
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
- package/skills/pr-converge/reference/per-tick.md +64 -41
- package/skills/pr-converge/reference/state-schema.md +27 -2
- package/skills/pr-converge/scripts/CLAUDE.md +8 -0
- package/skills/pr-converge/scripts/README.md +4 -3
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
- package/skills/pr-converge/scripts/check_convergence.py +189 -645
- package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
- package/skills/pr-converge/scripts/conftest.py +8 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
- package/skills/privacy-hygiene/SKILL.md +4 -3
- package/skills/reviewer-gates/SKILL.md +26 -8
- package/skills/session-log/SKILL.md +11 -12
- package/skills/session-tidy/SKILL.md +40 -30
- package/skills/skill-builder/CLAUDE.md +13 -10
- package/skills/skill-builder/SKILL.md +31 -31
- package/skills/skill-builder/references/CLAUDE.md +10 -6
- package/skills/skill-builder/references/delegation-map.md +13 -4
- package/skills/skill-builder/references/description-field.md +113 -0
- package/skills/skill-builder/references/self-audit-checklist.md +21 -4
- package/skills/skill-builder/references/skill-modularity.md +113 -0
- package/skills/skill-builder/references/skill-types.md +4 -0
- package/skills/skill-builder/templates/CLAUDE.md +4 -4
- package/skills/skill-builder/templates/gap-analysis.md +25 -1
- package/skills/skill-builder/workflows/CLAUDE.md +6 -4
- package/skills/skill-builder/workflows/improve-skill.md +17 -16
- package/skills/skill-builder/workflows/new-skill.md +34 -10
- package/skills/skill-builder/workflows/polish-skill.md +59 -43
- package/skills/usage-pause/SKILL.md +10 -14
- package/skills/bdd-protocol/CLAUDE.md +0 -26
- package/skills/bdd-protocol/SKILL.md +0 -30
- package/skills/bdd-protocol/references/CLAUDE.md +0 -10
- package/skills/bdd-protocol/references/anti-patterns.md +0 -26
- package/skills/bdd-protocol/references/example-mapping.md +0 -23
- package/skills/bg-agent/CLAUDE.md +0 -17
- package/skills/bg-agent/SKILL.md +0 -69
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
- package/skills/caveman/CLAUDE.md +0 -15
- package/skills/caveman/SKILL.md +0 -38
- package/skills/code/CLAUDE.md +0 -17
- package/skills/code/SKILL.md +0 -178
- package/skills/deep-research/CLAUDE.md +0 -17
- package/skills/deep-research/SKILL.md +0 -80
- package/skills/findbugs/CLAUDE.md +0 -20
- package/skills/findbugs/SKILL.md +0 -241
- package/skills/fixbugs/CLAUDE.md +0 -19
- package/skills/fixbugs/SKILL.md +0 -142
- package/skills/gh-paginate/CLAUDE.md +0 -18
- package/skills/gh-paginate/SKILL.md +0 -84
- package/skills/gotcha/CLAUDE.md +0 -33
- package/skills/gotcha/SKILL.md +0 -73
- package/skills/implement/CLAUDE.md +0 -27
- package/skills/implement/SKILL.md +0 -66
- package/skills/implement/scripts/CLAUDE.md +0 -22
- package/skills/implement/scripts/append_note.py +0 -133
- package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
- package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
- package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
- package/skills/implement/scripts/test_append_note.py +0 -191
- package/skills/log-audit/CLAUDE.md +0 -20
- package/skills/log-audit/SKILL.md +0 -66
- package/skills/log-audit/reference/CLAUDE.md +0 -9
- package/skills/log-audit/reference/charter.md +0 -52
- package/skills/log-audit/scripts/CLAUDE.md +0 -27
- package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
- package/skills/log-audit/scripts/collect_log_window.py +0 -199
- package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
- package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
- package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
- package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
- package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
- package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
- package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
- package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
- package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
- package/skills/logifix/CLAUDE.md +0 -36
- package/skills/logifix/SKILL.md +0 -69
- package/skills/logifix/scripts/CLAUDE.md +0 -16
- package/skills/logifix/scripts/logifix.ps1 +0 -205
- package/skills/monitor-open-prs/CLAUDE.md +0 -34
- package/skills/monitor-open-prs/SKILL.md +0 -88
- package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
- package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
- package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
- package/skills/monitor-open-prs/test_skill_contract.py +0 -27
- package/skills/post-audit-findings/SKILL.md +0 -80
- package/skills/pr-consistency-audit/CLAUDE.md +0 -34
- package/skills/pr-consistency-audit/SKILL.md +0 -116
- package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
- package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
- package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
- package/skills/pr-fix-protocol/SKILL.md +0 -65
- package/skills/pr-review-responder/CLAUDE.md +0 -35
- package/skills/pr-review-responder/EXAMPLES.md +0 -590
- package/skills/pr-review-responder/PRINCIPLES.md +0 -533
- package/skills/pr-review-responder/README.md +0 -168
- package/skills/pr-review-responder/SKILL.md +0 -203
- package/skills/pr-review-responder/TESTING.md +0 -350
- package/skills/pr-scope-resolve/SKILL.md +0 -45
- package/skills/pre-compact/CLAUDE.md +0 -24
- package/skills/pre-compact/SKILL.md +0 -134
- package/skills/qbug/CLAUDE.md +0 -40
- package/skills/qbug/SKILL.md +0 -387
- package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
- package/skills/refine/CLAUDE.md +0 -44
- package/skills/refine/SKILL.md +0 -262
- package/skills/refine/templates/CLAUDE.md +0 -17
- package/skills/refine/templates/implementation-notes-template.html +0 -56
- package/skills/refine/templates/plan-template.md +0 -60
- package/skills/research-mode/CLAUDE.md +0 -35
- package/skills/research-mode/SKILL.md +0 -53
- package/skills/structure-prompt/CLAUDE.md +0 -42
- package/skills/structure-prompt/SKILL.md +0 -44
- package/skills/structure-prompt/reference/CLAUDE.md +0 -28
- package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
- package/skills/structure-prompt/reference/block-classification.md +0 -27
- package/skills/structure-prompt/reference/canonical-case.md +0 -48
- package/skills/structure-prompt/reference/citation-depth.md +0 -70
- package/skills/structure-prompt/reference/cleanup.md +0 -33
- package/skills/structure-prompt/reference/constraints.md +0 -33
- package/skills/structure-prompt/reference/directives.md +0 -37
- package/skills/structure-prompt/reference/examples.md +0 -72
- package/skills/structure-prompt/reference/instantiation.md +0 -51
- package/skills/structure-prompt/reference/output-contract.md +0 -72
- package/skills/structure-prompt/reference/per-category.md +0 -23
- package/skills/structure-prompt/reference/persona.md +0 -38
- package/skills/structure-prompt/reference/research.md +0 -33
- package/skills/structure-prompt/reference/structure.md +0 -28
- package/skills/verified-build/CLAUDE.md +0 -33
- package/skills/verified-build/SKILL.md +0 -33
|
@@ -1,328 +1,26 @@
|
|
|
1
|
+
"""Skill-path entry for bugteam preflight.
|
|
2
|
+
|
|
3
|
+
Delegates to the package shared home:
|
|
4
|
+
``_shared/pr-loop/scripts/preflight.py``.
|
|
5
|
+
"""
|
|
6
|
+
|
|
1
7
|
from __future__ import annotations
|
|
2
8
|
|
|
3
|
-
import argparse
|
|
4
|
-
import os
|
|
5
|
-
import subprocess
|
|
6
9
|
import sys
|
|
7
10
|
from pathlib import Path
|
|
8
11
|
|
|
9
|
-
_bugteam_scripts_directory = str(Path(__file__).absolute().parent)
|
|
10
|
-
while _bugteam_scripts_directory in sys.path:
|
|
11
|
-
sys.path.remove(_bugteam_scripts_directory)
|
|
12
|
-
if _bugteam_scripts_directory not in sys.path:
|
|
13
|
-
sys.path.insert(0, _bugteam_scripts_directory)
|
|
14
|
-
|
|
15
|
-
from bugteam_scripts_constants.bugteam_preflight_constants import (
|
|
16
|
-
ALL_DISCOVERY_IGNORE_DIRECTORIES,
|
|
17
|
-
ALL_GIT_CONFIG_HOOKS_PATH_ARGUMENTS,
|
|
18
|
-
ALL_PRE_COMMIT_ARGUMENTS,
|
|
19
|
-
BUGTEAM_PREFLIGHT_PREFIX,
|
|
20
|
-
BUGTEAM_PREFLIGHT_SKIP_ENV_VAR_NAME,
|
|
21
|
-
ENFORCEMENT_ABSENT_MESSAGE,
|
|
22
|
-
EXIT_CODE_HOOKS_PATH_CHECK_FAILED,
|
|
23
|
-
EXPECTED_HOOKS_PATH_SUFFIX,
|
|
24
|
-
GIT_DIRECTORY_NAME,
|
|
25
|
-
PRE_COMMIT_CONFIG_FILENAME,
|
|
26
|
-
PYPROJECT_FILENAME,
|
|
27
|
-
PYPROJECT_PYTEST_SECTION_PREFIX,
|
|
28
|
-
PYTEST_EXIT_CODE_NO_TESTS_COLLECTED,
|
|
29
|
-
PYTEST_INI_FILENAME,
|
|
30
|
-
)
|
|
31
|
-
|
|
32
12
|
_shared_pr_loop_scripts_directory = (
|
|
33
|
-
Path(__file__).
|
|
34
|
-
|
|
35
|
-
).absolute()
|
|
13
|
+
Path(__file__).resolve().parents[3] / "_shared" / "pr-loop" / "scripts"
|
|
14
|
+
)
|
|
36
15
|
if str(_shared_pr_loop_scripts_directory) not in sys.path:
|
|
37
16
|
sys.path.insert(0, str(_shared_pr_loop_scripts_directory))
|
|
38
17
|
|
|
39
|
-
from
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
is_bugteam_disabled_via_env,
|
|
18
|
+
from preflight import ( # noqa: E402
|
|
19
|
+
EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV, # noqa: F401
|
|
20
|
+
has_pytest_configuration, # noqa: F401
|
|
21
|
+
main,
|
|
22
|
+
verify_git_hooks_path, # noqa: F401
|
|
45
23
|
)
|
|
46
24
|
|
|
47
|
-
|
|
48
|
-
def verify_git_hooks_path(repository_root: Path | None) -> int:
|
|
49
|
-
"""Check that core.hooksPath resolves to the claude-dev-env git-hooks directory.
|
|
50
|
-
|
|
51
|
-
Silently clears any stale, non-canonical local-scope core.hooksPath
|
|
52
|
-
override before querying the effective config, so a worktree-seeded local
|
|
53
|
-
entry cannot shadow a correctly configured global setting. When
|
|
54
|
-
*repository_root* is provided, queries the effective config for that
|
|
55
|
-
repository (``git -C <root> config --get``). When a canonical global
|
|
56
|
-
``core.hooksPath`` is already configured, the preceding self-heal step
|
|
57
|
-
clears non-canonical local-scope entries, so repo-level overrides such
|
|
58
|
-
as Husky or lefthook at local scope are silently removed in favor of
|
|
59
|
-
the canonical global; when the global is unset or non-canonical, the
|
|
60
|
-
self-heal stands down and the ``--get`` query still surfaces those
|
|
61
|
-
overrides through the failure path. Falls back to the current working
|
|
62
|
-
directory's effective config when *repository_root* is None.
|
|
63
|
-
|
|
64
|
-
Args:
|
|
65
|
-
repository_root: Optional repository root to check. When None, uses
|
|
66
|
-
the current working directory's effective config.
|
|
67
|
-
|
|
68
|
-
Returns:
|
|
69
|
-
Zero when the configured path ends with the expected hooks suffix.
|
|
70
|
-
Non-zero and prints a correction message when unset or pointing elsewhere.
|
|
71
|
-
"""
|
|
72
|
-
silently_clear_stale_local_hooks_path_override(
|
|
73
|
-
repository_root, EXPECTED_HOOKS_PATH_SUFFIX
|
|
74
|
-
)
|
|
75
|
-
git_command: list[str] = ["git"]
|
|
76
|
-
if repository_root is not None:
|
|
77
|
-
git_command.extend(["-C", str(repository_root)])
|
|
78
|
-
git_command.extend(list(ALL_GIT_CONFIG_HOOKS_PATH_ARGUMENTS))
|
|
79
|
-
try:
|
|
80
|
-
query_completed_process = subprocess.run(
|
|
81
|
-
git_command,
|
|
82
|
-
capture_output=True,
|
|
83
|
-
text=True,
|
|
84
|
-
encoding="utf-8",
|
|
85
|
-
errors="replace",
|
|
86
|
-
check=False,
|
|
87
|
-
)
|
|
88
|
-
except FileNotFoundError:
|
|
89
|
-
print(
|
|
90
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}git is not installed or not available on PATH.\n"
|
|
91
|
-
f"{ENFORCEMENT_ABSENT_MESSAGE}",
|
|
92
|
-
file=sys.stderr,
|
|
93
|
-
)
|
|
94
|
-
return EXIT_CODE_HOOKS_PATH_CHECK_FAILED
|
|
95
|
-
except OSError as os_error:
|
|
96
|
-
print(
|
|
97
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}failed to run git: {os_error}\n"
|
|
98
|
-
f"{ENFORCEMENT_ABSENT_MESSAGE}",
|
|
99
|
-
file=sys.stderr,
|
|
100
|
-
)
|
|
101
|
-
return EXIT_CODE_HOOKS_PATH_CHECK_FAILED
|
|
102
|
-
if query_completed_process.returncode != 0:
|
|
103
|
-
print(
|
|
104
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}{ENFORCEMENT_ABSENT_MESSAGE}",
|
|
105
|
-
file=sys.stderr,
|
|
106
|
-
)
|
|
107
|
-
return EXIT_CODE_HOOKS_PATH_CHECK_FAILED
|
|
108
|
-
configured_path = query_completed_process.stdout.strip().replace("\\", "/").rstrip("/")
|
|
109
|
-
if not configured_path.endswith(EXPECTED_HOOKS_PATH_SUFFIX):
|
|
110
|
-
print(
|
|
111
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}core.hooksPath is '{configured_path}' — "
|
|
112
|
-
f"expected path ending in '{EXPECTED_HOOKS_PATH_SUFFIX}'.\n"
|
|
113
|
-
f"{ENFORCEMENT_ABSENT_MESSAGE}",
|
|
114
|
-
file=sys.stderr,
|
|
115
|
-
)
|
|
116
|
-
return EXIT_CODE_HOOKS_PATH_CHECK_FAILED
|
|
117
|
-
return 0
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def find_repository_root(start: Path) -> Path:
|
|
121
|
-
"""Find the repository root by walking up from the starting directory.
|
|
122
|
-
|
|
123
|
-
Searches for a ``.git`` directory or file in parent directories. Falls
|
|
124
|
-
back to the nearest ancestor containing ``pytest.ini`` when no git
|
|
125
|
-
repository is found.
|
|
126
|
-
|
|
127
|
-
Args:
|
|
128
|
-
start: The directory to start searching from.
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
The repository root path, or *start* when no repository is found.
|
|
132
|
-
"""
|
|
133
|
-
resolved = start.resolve()
|
|
134
|
-
candidates = [resolved, *resolved.parents]
|
|
135
|
-
for each_candidate in candidates:
|
|
136
|
-
if (each_candidate / GIT_DIRECTORY_NAME).is_dir() or (each_candidate / GIT_DIRECTORY_NAME).is_file():
|
|
137
|
-
return each_candidate
|
|
138
|
-
for each_candidate in candidates:
|
|
139
|
-
if (each_candidate / PYTEST_INI_FILENAME).is_file():
|
|
140
|
-
return each_candidate
|
|
141
|
-
return resolved
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def has_pytest_configuration(root: Path) -> bool:
|
|
145
|
-
"""Check whether a directory has pytest configuration available.
|
|
146
|
-
|
|
147
|
-
Checks for ``pytest.ini`` directly, then falls back to searching for
|
|
148
|
-
``[tool.pytest]`` in ``pyproject.toml``.
|
|
149
|
-
|
|
150
|
-
Args:
|
|
151
|
-
root: The directory to check for pytest configuration.
|
|
152
|
-
|
|
153
|
-
Returns:
|
|
154
|
-
True when pytest configuration is found in either location.
|
|
155
|
-
"""
|
|
156
|
-
if (root / PYTEST_INI_FILENAME).is_file():
|
|
157
|
-
return True
|
|
158
|
-
pyproject = root / PYPROJECT_FILENAME
|
|
159
|
-
if not pyproject.is_file():
|
|
160
|
-
return False
|
|
161
|
-
text = pyproject.read_text(encoding="utf-8", errors="replace")
|
|
162
|
-
return PYPROJECT_PYTEST_SECTION_PREFIX in text
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def has_discoverable_tests(root: Path) -> bool:
|
|
166
|
-
"""Check whether the directory tree contains discoverable test files.
|
|
167
|
-
|
|
168
|
-
Searches for files matching ``test_*.py`` and ``*_test.py`` patterns,
|
|
169
|
-
skipping directories in the configured ignore list (virtual environments,
|
|
170
|
-
node_modules).
|
|
171
|
-
|
|
172
|
-
Args:
|
|
173
|
-
root: The directory tree root to search.
|
|
174
|
-
|
|
175
|
-
Returns:
|
|
176
|
-
True when at least one test file is found outside ignored directories.
|
|
177
|
-
"""
|
|
178
|
-
for each_path in root.rglob("test_*.py"):
|
|
179
|
-
if any(part_dir in ALL_DISCOVERY_IGNORE_DIRECTORIES for part_dir in each_path.parts):
|
|
180
|
-
continue
|
|
181
|
-
return True
|
|
182
|
-
for each_path in root.rglob("*_test.py"):
|
|
183
|
-
if any(part_dir in ALL_DISCOVERY_IGNORE_DIRECTORIES for part_dir in each_path.parts):
|
|
184
|
-
continue
|
|
185
|
-
return True
|
|
186
|
-
return False
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def _pytest_exit_code_no_tests_collected() -> int:
|
|
190
|
-
return PYTEST_EXIT_CODE_NO_TESTS_COLLECTED
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def run_pytest(repository_root: Path, is_verbose: bool) -> int:
|
|
194
|
-
"""Run pytest in the repository root and return the exit code.
|
|
195
|
-
|
|
196
|
-
Treats the "no tests collected" exit code as a pass (exit 0).
|
|
197
|
-
|
|
198
|
-
Args:
|
|
199
|
-
repository_root: The repository root for running pytest.
|
|
200
|
-
is_verbose: When True, pass no -q flag (shows individual test names).
|
|
201
|
-
|
|
202
|
-
Returns:
|
|
203
|
-
The pytest exit code, or 0 when no tests were collected.
|
|
204
|
-
"""
|
|
205
|
-
command = [sys.executable, "-m", "pytest"]
|
|
206
|
-
if not is_verbose:
|
|
207
|
-
command.append("-q")
|
|
208
|
-
completed = subprocess.run(
|
|
209
|
-
command,
|
|
210
|
-
cwd=str(repository_root),
|
|
211
|
-
check=False,
|
|
212
|
-
)
|
|
213
|
-
if completed.returncode == _pytest_exit_code_no_tests_collected():
|
|
214
|
-
return 0
|
|
215
|
-
return completed.returncode
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def run_pre_commit(repository_root: Path) -> int:
|
|
219
|
-
"""Run pre-commit on all files and return the exit code.
|
|
220
|
-
|
|
221
|
-
Args:
|
|
222
|
-
repository_root: The repository root for running pre-commit.
|
|
223
|
-
|
|
224
|
-
Returns:
|
|
225
|
-
The pre-commit exit code (0 on success, non-zero on failure).
|
|
226
|
-
"""
|
|
227
|
-
completed = subprocess.run(
|
|
228
|
-
ALL_PRE_COMMIT_ARGUMENTS,
|
|
229
|
-
cwd=str(repository_root),
|
|
230
|
-
check=False,
|
|
231
|
-
)
|
|
232
|
-
return completed.returncode
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
def parse_arguments(all_argv: list[str]) -> argparse.Namespace:
|
|
236
|
-
"""Parse command-line arguments for the preflight script.
|
|
237
|
-
|
|
238
|
-
Args:
|
|
239
|
-
all_argv: Command-line argument list.
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
Parsed namespace with repo_root, no_pytest, pre_commit, and verbose.
|
|
243
|
-
"""
|
|
244
|
-
parser = argparse.ArgumentParser(
|
|
245
|
-
description="Run local checks before /bugteam (pytest, optional pre-commit).",
|
|
246
|
-
)
|
|
247
|
-
parser.add_argument(
|
|
248
|
-
"--repo-root",
|
|
249
|
-
type=Path,
|
|
250
|
-
default=None,
|
|
251
|
-
help="Repository root (default: discover from cwd).",
|
|
252
|
-
)
|
|
253
|
-
parser.add_argument(
|
|
254
|
-
"--no-pytest",
|
|
255
|
-
action="store_true",
|
|
256
|
-
help="Skip pytest.",
|
|
257
|
-
)
|
|
258
|
-
parser.add_argument(
|
|
259
|
-
"--pre-commit",
|
|
260
|
-
action="store_true",
|
|
261
|
-
help="Run pre-commit when .pre-commit-config.yaml exists.",
|
|
262
|
-
)
|
|
263
|
-
parser.add_argument(
|
|
264
|
-
"-v",
|
|
265
|
-
"--verbose",
|
|
266
|
-
action="store_true",
|
|
267
|
-
help="Verbose pytest output.",
|
|
268
|
-
)
|
|
269
|
-
return parser.parse_args(all_argv)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
def main(all_argv: list[str] | None = None) -> int:
|
|
273
|
-
"""Run the bugteam preflight checks (pytest, optional pre-commit).
|
|
274
|
-
|
|
275
|
-
Args:
|
|
276
|
-
all_argv: Command-line arguments to parse. Pass None to use sys.argv.
|
|
277
|
-
|
|
278
|
-
Returns:
|
|
279
|
-
Zero on success, non-zero exit code on failure.
|
|
280
|
-
"""
|
|
281
|
-
arguments = parse_arguments(sys.argv[1:] if all_argv is None else all_argv)
|
|
282
|
-
if os.environ.get(BUGTEAM_PREFLIGHT_SKIP_ENV_VAR_NAME, "").strip() == "1":
|
|
283
|
-
print(f"{BUGTEAM_PREFLIGHT_PREFIX}skipped (BUGTEAM_PREFLIGHT_SKIP=1).", file=sys.stderr)
|
|
284
|
-
return 0
|
|
285
|
-
reviews_disabled_env_var_name = CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME
|
|
286
|
-
reviews_disabled_bugteam_token = CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN
|
|
287
|
-
disabled_via_env_exit_code = EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV
|
|
288
|
-
if is_bugteam_disabled_via_env():
|
|
289
|
-
print(
|
|
290
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}halted "
|
|
291
|
-
f"({reviews_disabled_env_var_name} contains "
|
|
292
|
-
f"'{reviews_disabled_bugteam_token}').",
|
|
293
|
-
file=sys.stderr,
|
|
294
|
-
)
|
|
295
|
-
return disabled_via_env_exit_code
|
|
296
|
-
start = Path.cwd()
|
|
297
|
-
resolved_repository_root: Path = (
|
|
298
|
-
arguments.repo_root.resolve()
|
|
299
|
-
if arguments.repo_root is not None
|
|
300
|
-
else find_repository_root(start)
|
|
301
|
-
)
|
|
302
|
-
hooks_path_exit_code = verify_git_hooks_path(resolved_repository_root)
|
|
303
|
-
if hooks_path_exit_code != 0:
|
|
304
|
-
return hooks_path_exit_code
|
|
305
|
-
if not arguments.no_pytest and has_pytest_configuration(resolved_repository_root):
|
|
306
|
-
if not has_discoverable_tests(resolved_repository_root):
|
|
307
|
-
print(
|
|
308
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}pytest configured but no tests found; skipping pytest.",
|
|
309
|
-
file=sys.stderr,
|
|
310
|
-
)
|
|
311
|
-
else:
|
|
312
|
-
exit_code = run_pytest(resolved_repository_root, arguments.verbose)
|
|
313
|
-
if exit_code != 0:
|
|
314
|
-
return exit_code
|
|
315
|
-
elif not arguments.no_pytest:
|
|
316
|
-
print(
|
|
317
|
-
f"{BUGTEAM_PREFLIGHT_PREFIX}no pytest configuration found; skipping pytest.",
|
|
318
|
-
file=sys.stderr,
|
|
319
|
-
)
|
|
320
|
-
if arguments.pre_commit and (resolved_repository_root / PRE_COMMIT_CONFIG_FILENAME).is_file():
|
|
321
|
-
exit_code = run_pre_commit(resolved_repository_root)
|
|
322
|
-
if exit_code != 0:
|
|
323
|
-
return exit_code
|
|
324
|
-
return 0
|
|
325
|
-
|
|
326
|
-
|
|
327
25
|
if __name__ == "__main__":
|
|
328
26
|
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -6,14 +6,13 @@ Python package of named constants imported by the bugteam scripts. Each module h
|
|
|
6
6
|
|
|
7
7
|
| File | Constants for |
|
|
8
8
|
|---|---|
|
|
9
|
-
| `bugteam_preflight_constants.py` | `bugteam_preflight.py` — env var name, hooks path suffix, exit codes, ignore dirs, argument tuples, config filenames. |
|
|
10
|
-
| `bugteam_code_rules_gate_constants.py` | `bugteam_code_rules_gate.py` — gate-related path and exit-code constants. |
|
|
11
|
-
| `bugteam_fix_hookspath_constants.py` | `bugteam_fix_hookspath.py` — canonical hooks path, remediation message strings. |
|
|
12
9
|
| `probe_code_rules_enforcer_check_constants.py` | `probe_code_rules_enforcer_check.py` — enforcer module path and function name constants. |
|
|
13
10
|
| `reflow_skill_md_constants.py` | `reflow_skill_md.py` — line-length and formatting constants. |
|
|
14
11
|
| `windows_safe_rmtree_constants.py` | `windows_safe_rmtree.py` — retry count and wait constants. |
|
|
15
12
|
| `__init__.py` | Empty package marker. |
|
|
16
13
|
|
|
14
|
+
Preflight, fix_hookspath, and code_rules_gate constants live under package shared `pr_loop_shared_constants` with the shared implementations.
|
|
15
|
+
|
|
17
16
|
## Convention
|
|
18
17
|
|
|
19
18
|
Scripts import from this package at module scope. No constant is defined inline in a script body — the hook enforces this at write time.
|