claude-dev-env 1.49.1 → 1.50.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/audit-rubrics/category_rubrics/category-a-api-contracts.md +17 -3
- package/audit-rubrics/prompts/category-a-api-contracts.md +17 -2
- package/docs/CODE_RULES.md +6 -1
- package/hooks/blocking/code_rules_enforcer.py +323 -11
- package/hooks/blocking/md_to_html_blocker.py +2 -2
- package/hooks/blocking/test_code_rules_enforcer.py +65 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_args_signature.py +256 -0
- package/hooks/blocking/test_code_rules_enforcer_ignored_must_check_return.py +256 -0
- package/hooks/blocking/test_code_rules_enforcer_naming_pattern.py +137 -1
- package/hooks/blocking/test_md_to_html_blocker.py +38 -0
- package/hooks/hooks_constants/blocking_check_limits.py +2 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +15 -1
- package/hooks/hooks_constants/md_to_html_blocker_constants.py +1 -1
- package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +11 -4
- package/package.json +1 -1
|
@@ -252,6 +252,44 @@ def test_blocks_changelog_not_at_root():
|
|
|
252
252
|
assert output["hookSpecificOutput"]["permissionDecision"] == "deny"
|
|
253
253
|
|
|
254
254
|
|
|
255
|
+
def test_passes_claude_md_at_root():
|
|
256
|
+
result = _run_hook(
|
|
257
|
+
"Write",
|
|
258
|
+
{"file_path": "CLAUDE.md", "content": "# CLAUDE"},
|
|
259
|
+
)
|
|
260
|
+
assert result.returncode == 0
|
|
261
|
+
assert result.stdout == ""
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def test_passes_agents_md_at_root():
|
|
265
|
+
result = _run_hook(
|
|
266
|
+
"Write",
|
|
267
|
+
{"file_path": "AGENTS.md", "content": "# AGENTS"},
|
|
268
|
+
)
|
|
269
|
+
assert result.returncode == 0
|
|
270
|
+
assert result.stdout == ""
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def test_blocks_claude_md_not_at_root():
|
|
274
|
+
result = _run_hook(
|
|
275
|
+
"Write",
|
|
276
|
+
{"file_path": "docs/CLAUDE.md", "content": "# CLAUDE"},
|
|
277
|
+
)
|
|
278
|
+
assert result.returncode == 0
|
|
279
|
+
output = json.loads(result.stdout)
|
|
280
|
+
assert output["hookSpecificOutput"]["permissionDecision"] == "deny"
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def test_blocks_agents_md_not_at_root():
|
|
284
|
+
result = _run_hook(
|
|
285
|
+
"Write",
|
|
286
|
+
{"file_path": "sub/AGENTS.md", "content": "# AGENTS"},
|
|
287
|
+
)
|
|
288
|
+
assert result.returncode == 0
|
|
289
|
+
output = json.loads(result.stdout)
|
|
290
|
+
assert output["hookSpecificOutput"]["permissionDecision"] == "deny"
|
|
291
|
+
|
|
292
|
+
|
|
255
293
|
def test_blocks_relative_readme_when_cwd_is_not_repo_root():
|
|
256
294
|
sandbox_parent = _get_sandbox_parent_directory()
|
|
257
295
|
non_repo_cwd = os.path.join(sandbox_parent, "not-a-repo")
|
|
@@ -16,6 +16,8 @@ MAX_BARE_EXCEPT_ISSUES: int = 3
|
|
|
16
16
|
MAX_BOUNDARY_TYPE_ISSUES: int = 5
|
|
17
17
|
ALL_BANNED_PREFIX_NAMES: tuple[str, ...] = ("handle_", "process_", "manage_", "do_")
|
|
18
18
|
MAX_DOCSTRING_FORMAT_ISSUES: int = 5
|
|
19
|
+
MAX_DOCSTRING_ARGS_SIGNATURE_ISSUES: int = 5
|
|
20
|
+
MAX_IGNORED_MUST_CHECK_RETURN_ISSUES: int = 5
|
|
19
21
|
MAX_TYPE_ESCAPE_HATCH_ISSUES: int = 5
|
|
20
22
|
MAX_THIN_WRAPPER_ISSUES: int = 1
|
|
21
23
|
DOCSTRING_TRIVIAL_FUNCTION_BODY_LINE_LIMIT: int = 3
|
|
@@ -24,9 +24,23 @@ ALL_MIGRATION_PATH_PATTERNS = {"/migrations/", "\\migrations\\"}
|
|
|
24
24
|
ADVISORY_LINE_THRESHOLD_SOFT = 400
|
|
25
25
|
ADVISORY_LINE_THRESHOLD_HARD = 1000
|
|
26
26
|
|
|
27
|
-
ALL_BOOLEAN_NAME_PREFIXES: tuple[str, ...] = ("is_", "has_", "should_", "can_")
|
|
27
|
+
ALL_BOOLEAN_NAME_PREFIXES: tuple[str, ...] = ("is_", "has_", "should_", "can_", "was_", "did_")
|
|
28
28
|
UPPER_SNAKE_CONSTANT_PATTERN = re.compile(r"^[A-Z][A-Z0-9_]*$")
|
|
29
29
|
|
|
30
|
+
ALL_MUST_CHECK_RETURN_FUNCTION_NAMES: frozenset[str] = frozenset({"find_and_click", "write_outcome"})
|
|
31
|
+
|
|
32
|
+
DOCSTRING_ARG_ENTRY_PATTERN: re.Pattern[str] = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)\s*[:(]")
|
|
33
|
+
ALL_DOCSTRING_ARGS_SECTION_HEADERS: tuple[str, ...] = ("Args:", "Arguments:")
|
|
34
|
+
ALL_DOCSTRING_TERMINATING_SECTION_HEADERS: frozenset[str] = frozenset({
|
|
35
|
+
"Returns:",
|
|
36
|
+
"Yields:",
|
|
37
|
+
"Raises:",
|
|
38
|
+
"Examples:",
|
|
39
|
+
"Example:",
|
|
40
|
+
"Note:",
|
|
41
|
+
"Notes:",
|
|
42
|
+
})
|
|
43
|
+
|
|
30
44
|
|
|
31
45
|
TYPE_CHECKING_BLOCK_PATTERN = re.compile(r"^(?P<indent>\s*)if\s+(typing\.)?TYPE_CHECKING\s*:\s*$")
|
|
32
46
|
ALL_IMPORT_STATEMENT_PREFIXES: tuple[str, ...] = ("import ", "from ")
|
|
@@ -19,7 +19,7 @@ MINIMUM_SEGMENT_COUNT_TO_MATCH_INDICATOR: int = 4
|
|
|
19
19
|
ALL_EXEMPT_ANYWHERE_FILENAMES: tuple[str, ...] = ("SKILL.md",)
|
|
20
20
|
ALL_EXEMPT_PLUGIN_DIRECTORY_SEGMENTS: tuple[str, ...] = ("agents", "skills", "commands")
|
|
21
21
|
ALL_EXEMPT_HOME_RELATIVE_DIRECTORIES: tuple[str, ...] = ("SessionLog",)
|
|
22
|
-
ALL_EXEMPT_ROOT_FILENAMES: tuple[str, ...] = ("readme.md", "changelog.md")
|
|
22
|
+
ALL_EXEMPT_ROOT_FILENAMES: tuple[str, ...] = ("readme.md", "changelog.md", "claude.md", "agents.md")
|
|
23
23
|
REPO_ROOT_MARKER_NAME: str = ".git"
|
|
24
24
|
CLAUDE_DIRECTORY_NAME: str = ".claude"
|
|
25
25
|
PLUGIN_ROOT_MARKER_DIRECTORY_NAME: str = ".claude-plugin"
|
|
@@ -82,10 +82,17 @@ def test_exempt_home_relative_directories_include_session_log() -> None:
|
|
|
82
82
|
assert "ALL_EXEMPT_HOME_RELATIVE_DIRECTORIES" in constants_module.__all__
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def
|
|
86
|
-
"""README.md and
|
|
87
|
-
every repo with a `.git` marker satisfies the root
|
|
88
|
-
|
|
85
|
+
def test_exempt_root_filenames_cover_readme_changelog_claude_and_agents() -> None:
|
|
86
|
+
"""README.md, CHANGELOG.md, CLAUDE.md, and AGENTS.md at a repo root are
|
|
87
|
+
universally exempt; every repo with a `.git` marker satisfies the root
|
|
88
|
+
check. CLAUDE.md and AGENTS.md are functional agent-instruction files that
|
|
89
|
+
Claude Code loads by name and must stay Markdown."""
|
|
90
|
+
assert constants_module.ALL_EXEMPT_ROOT_FILENAMES == (
|
|
91
|
+
"readme.md",
|
|
92
|
+
"changelog.md",
|
|
93
|
+
"claude.md",
|
|
94
|
+
"agents.md",
|
|
95
|
+
)
|
|
89
96
|
assert "ALL_EXEMPT_ROOT_FILENAMES" in constants_module.__all__
|
|
90
97
|
|
|
91
98
|
|