Add PreToolUse hook to block AI writing check#144
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR adds a Claude Code
Confidence Score: 3/5
Important Files Changed
Prompt To Fix All With AIThis is a comment left during a code review.
Path: .claude/hooks/enforce-makefile.py
Line: 23
Comment:
**Unhandled exception on malformed stdin**
`json.loads(sys.stdin.read())` will raise a `json.JSONDecodeError` (or `ValueError`) if Claude Code sends empty or malformed input, causing the hook to crash with a non-zero exit code. Depending on how Claude Code handles a hook subprocess failure, this could inadvertently block all Bash commands rather than failing open. Wrapping this in a `try/except` and exiting cleanly when input is unexpected would make the hook resilient:
```suggestion
try:
hook_input = json.loads(sys.stdin.read())
except (json.JSONDecodeError, ValueError):
sys.exit(0)
command = hook_input.get("tool_input", {}).get("command", "")
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: .claude/hooks/enforce-makefile.py
Line: 28
Comment:
**Regex `\./ ` alternative causes false positives**
The `\./ ` branch in `(uv\s+run\s+python|python3?|\./)` will match any `./` occurrence anywhere in the command string, and `.*` is then free to span across unrelated tokens until `check_ai_writing\.py` is found. For example, a legitimate command like `./lint.sh && echo "check_ai_writing.py passed"` would be incorrectly blocked because `./` matches at the start, and `.*check_ai_writing\.py` swallows the rest of the string.
To fix this, tighten the `\./ ` branch so it only matches when `check_ai_writing.py` directly follows, without any directory separator in between:
```suggestion
if re.search(r"(uv\s+run\s+python\s+|python3?\s+|\./)check_ai_writing\.py", command):
```
This ensures `./` is only matched when it immediately precedes `check_ai_writing.py`, preventing false positives from commands that happen to start with `./` and separately mention the script name.
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: 349a88c |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
||
|
|
||
| def main() -> None: | ||
| hook_input = json.loads(sys.stdin.read()) |
There was a problem hiding this comment.
Unhandled exception on malformed stdin
json.loads(sys.stdin.read()) will raise a json.JSONDecodeError (or ValueError) if Claude Code sends empty or malformed input, causing the hook to crash with a non-zero exit code. Depending on how Claude Code handles a hook subprocess failure, this could inadvertently block all Bash commands rather than failing open. Wrapping this in a try/except and exiting cleanly when input is unexpected would make the hook resilient:
| hook_input = json.loads(sys.stdin.read()) | |
| try: | |
| hook_input = json.loads(sys.stdin.read()) | |
| except (json.JSONDecodeError, ValueError): | |
| sys.exit(0) | |
| command = hook_input.get("tool_input", {}).get("command", "") |
Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/hooks/enforce-makefile.py
Line: 23
Comment:
**Unhandled exception on malformed stdin**
`json.loads(sys.stdin.read())` will raise a `json.JSONDecodeError` (or `ValueError`) if Claude Code sends empty or malformed input, causing the hook to crash with a non-zero exit code. Depending on how Claude Code handles a hook subprocess failure, this could inadvertently block all Bash commands rather than failing open. Wrapping this in a `try/except` and exiting cleanly when input is unexpected would make the hook resilient:
```suggestion
try:
hook_input = json.loads(sys.stdin.read())
except (json.JSONDecodeError, ValueError):
sys.exit(0)
command = hook_input.get("tool_input", {}).get("command", "")
```
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| # Block direct invocation of the AI writing check script | ||
| # Match only actual script execution, not mentions in strings | ||
| if re.search(r"(uv\s+run\s+python|python3?|\./).*check_ai_writing\.py", command): |
There was a problem hiding this comment.
Regex \./ alternative causes false positives
The \./ branch in (uv\s+run\s+python|python3?|\./) will match any ./ occurrence anywhere in the command string, and .* is then free to span across unrelated tokens until check_ai_writing\.py is found. For example, a legitimate command like ./lint.sh && echo "check_ai_writing.py passed" would be incorrectly blocked because ./ matches at the start, and .*check_ai_writing\.py swallows the rest of the string.
To fix this, tighten the \./ branch so it only matches when check_ai_writing.py directly follows, without any directory separator in between:
| if re.search(r"(uv\s+run\s+python|python3?|\./).*check_ai_writing\.py", command): | |
| if re.search(r"(uv\s+run\s+python\s+|python3?\s+|\./)check_ai_writing\.py", command): |
This ensures ./ is only matched when it immediately precedes check_ai_writing.py, preventing false positives from commands that happen to start with ./ and separately mention the script name.
Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/hooks/enforce-makefile.py
Line: 28
Comment:
**Regex `\./ ` alternative causes false positives**
The `\./ ` branch in `(uv\s+run\s+python|python3?|\./)` will match any `./` occurrence anywhere in the command string, and `.*` is then free to span across unrelated tokens until `check_ai_writing\.py` is found. For example, a legitimate command like `./lint.sh && echo "check_ai_writing.py passed"` would be incorrectly blocked because `./` matches at the start, and `.*check_ai_writing\.py` swallows the rest of the string.
To fix this, tighten the `\./ ` branch so it only matches when `check_ai_writing.py` directly follows, without any directory separator in between:
```suggestion
if re.search(r"(uv\s+run\s+python\s+|python3?\s+|\./)check_ai_writing\.py", command):
```
This ensures `./` is only matched when it immediately precedes `check_ai_writing.py`, preventing false positives from commands that happen to start with `./` and separately mention the script name.
How can I resolve this? If you propose a fix, please make it concise.
Summary
PreToolUsehook that intercepts attempts to directly run the em-dash checking script.claude/settings.jsonwith hook configurationTest plan
.claude/settings.json🤖 Generated with Claude Code