claude-dev-env 8.46.9 → 8.46.11
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.
|
@@ -121,7 +121,7 @@ Do not write production behavior before RED, skip the red run, or call a green t
|
|
|
121
121
|
|
|
122
122
|
## Hook-specific workflow
|
|
123
123
|
|
|
124
|
-
For a hook change, use the target package's active managed root for installed files
|
|
124
|
+
For a hook change, use the target package's active managed root for installed files. The default is `~/.claude`; `--target` or `CLAUDE_CONFIG_DIR` selects another managed root. Read `<managed-root>/hooks/AGENTS.md` (default: `~/.claude/hooks/AGENTS.md`; source fallback: `packages/claude-dev-env/hooks/AGENTS.md`), each closer `AGENTS.md` and `CLAUDE.md`, and the registered hook entry before editing. Trace the lifecycle event, stdin JSON, output contract, exit code, and registration. Reuse the target hook area's constants package. Run `<managed-root>/scripts/check.ps1` (default: `~/.claude/scripts/check.ps1`; source fallback: `packages/claude-dev-env/scripts/check.ps1`) and drive the production entry point with event payloads. The RED test covers each allow and deny outcome. Run every applicable test file and suite for the hook, then the full quality gates required by the affected package.
|
|
125
125
|
|
|
126
126
|
## Session advisor
|
|
127
127
|
|
|
@@ -41,8 +41,8 @@ Treat scoped `AGENTS.md` files as the canonical repository and path rules. Treat
|
|
|
41
41
|
For Category J, keep these sources separate:
|
|
42
42
|
|
|
43
43
|
- Use the target repository's full review contract as the primary policy when available.
|
|
44
|
-
- `docs/CODE_RULES.md` is a compact projection
|
|
45
|
-
- `hooks/blocking/code_rules_enforcer.py` is hand-maintained write-time coverage. It shows what the hook checks
|
|
44
|
+
- `docs/CODE_RULES.md` is a compact projection of the contract. Use it as a checklist.
|
|
45
|
+
- `hooks/blocking/code_rules_enforcer.py` is hand-maintained write-time coverage. It shows only what the hook checks.
|
|
46
46
|
|
|
47
47
|
Record each Category J conclusion's policy source and hook coverage. Compact rules and hook results do not replace the canonical contract or scoped `AGENTS.md` rules.
|
|
48
48
|
|
|
@@ -199,7 +199,7 @@ When the primary and adversarial passes flag the same file:line:
|
|
|
199
199
|
- Concatenate the `failure_mode` strings (separator: " // adversarial: ") so both pass narratives survive.
|
|
200
200
|
- For Shape B entries on the same category, keep every distinct `adversarial_probe` from both passes — collapsing them would drop information that was found.
|
|
201
201
|
|
|
202
|
-
The merge runs at the end of the adversarial pass, before constructing the output. The output preamble's `Total: N` counts merged findings
|
|
202
|
+
The merge runs at the end of the adversarial pass, before constructing the output. The output preamble's `Total: N` counts merged findings.
|
|
203
203
|
|
|
204
204
|
## file:line Evidence Requirement
|
|
205
205
|
|
|
@@ -46,7 +46,7 @@ extract_javascript_comment_occurrences = (
|
|
|
46
46
|
def check_comments_python(content: str) -> list[str]:
|
|
47
47
|
"""Check for comments in Python code.
|
|
48
48
|
|
|
49
|
-
Uses ``tokenize.generate_tokens`` to find
|
|
49
|
+
Uses ``tokenize.generate_tokens`` to find ``COMMENT`` tokens.
|
|
50
50
|
Hash characters that appear inside string literals (hex color codes,
|
|
51
51
|
URL fragments, and the hash inside an f-string interpolation pattern)
|
|
52
52
|
are correctly skipped because the tokenizer recognizes them as parts
|
package/hooks/conftest.py
CHANGED
|
@@ -18,10 +18,28 @@ _is_ephemeral_script_path = importlib.import_module("code_rules_shared").is_ephe
|
|
|
18
18
|
_EPHEMERAL_EXEMPT_DISABLE_ENVIRONMENT_VARIABLE_NAME = importlib.import_module(
|
|
19
19
|
"hooks_constants.code_rules_enforcer_constants"
|
|
20
20
|
).EPHEMERAL_EXEMPT_DISABLE_ENVIRONMENT_VARIABLE_NAME
|
|
21
|
+
_CLAUDE_SESSION_ID_ENVIRONMENT_VARIABLE_NAME = importlib.import_module(
|
|
22
|
+
"hooks_constants.harness_scratchpad_constants"
|
|
23
|
+
).CLAUDE_SESSION_ID_ENVIRONMENT_VARIABLE_NAME
|
|
21
24
|
|
|
22
25
|
_ROOT_ANCHORED_PROBE_PATH = "/tmp/scratch.py"
|
|
23
26
|
|
|
24
27
|
|
|
28
|
+
@pytest.fixture(autouse=True)
|
|
29
|
+
def isolate_from_live_session_scratchpad(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
30
|
+
"""Remove the live harness session id before each hooks test.
|
|
31
|
+
|
|
32
|
+
A Claude Code session exports ``CLAUDE_CODE_SESSION_ID``. When this checkout
|
|
33
|
+
sits inside that session's scratchpad, the scratchpad predicate classifies
|
|
34
|
+
every repository file as throwaway scratch, and the gates under test step
|
|
35
|
+
aside. Tests that exercise the scratchpad match set their own session id.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
monkeypatch: Pytest's environment-variable patcher, torn down after the test.
|
|
39
|
+
"""
|
|
40
|
+
monkeypatch.delenv(_CLAUDE_SESSION_ID_ENVIRONMENT_VARIABLE_NAME, raising=False)
|
|
41
|
+
|
|
42
|
+
|
|
25
43
|
@pytest.fixture
|
|
26
44
|
def ephemeral_exempt_off(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
27
45
|
"""Turn off the ephemeral scratch-path exemption for the current test.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Tests for the shared fixtures in hooks/conftest.py."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from hooks_constants.harness_scratchpad_constants import (
|
|
10
|
+
CLAUDE_SESSION_ID_ENVIRONMENT_VARIABLE_NAME,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_live_session_id_is_absent_inside_each_test() -> None:
|
|
15
|
+
assert CLAUDE_SESSION_ID_ENVIRONMENT_VARIABLE_NAME not in os.environ
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_hook_subprocess_inherits_no_live_session_id() -> None:
|
|
19
|
+
completed = subprocess.run(
|
|
20
|
+
[
|
|
21
|
+
sys.executable,
|
|
22
|
+
"-c",
|
|
23
|
+
f"import os; print(os.environ.get('{CLAUDE_SESSION_ID_ENVIRONMENT_VARIABLE_NAME}', ''))",
|
|
24
|
+
],
|
|
25
|
+
capture_output=True,
|
|
26
|
+
text=True,
|
|
27
|
+
check=True,
|
|
28
|
+
)
|
|
29
|
+
assert completed.stdout.strip() == ""
|