Skip to content

Instantly share code, notes, and snippets.

@LarryStanley
Last active August 19, 2025 02:48
Show Gist options
  • Select an option

  • Save LarryStanley/fa0e29206e7c64c6e9176a756a575216 to your computer and use it in GitHub Desktop.

Select an option

Save LarryStanley/fa0e29206e7c64c6e9176a756a575216 to your computer and use it in GitHub Desktop.
TDD Guard Script for TS with Claude Hooks
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit|TodoWrite",
"hooks": [
{
"type": "command",
"command": "/your/repo/path/.claude/hooks/ts-tdd-guard.sh"
}
]
}
]
}
}
#!/bin/bash
# TDD Guard - Strict file type matching
hook_data=$(cat)
tool_name=$(echo "$hook_data" | jq -r '.tool_name // empty' 2>/dev/null)
file_path=$(echo "$hook_data" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
# Only check JS/TS files for file operations
if [[ ! "$tool_name" =~ ^(Edit|MultiEdit|Write)$ ]] || [[ ! "$file_path" =~ \.(js|ts|jsx|tsx)$ ]] || [[ "$file_path" =~ \.(test|spec)\. ]]; then
exit 0
fi
# Extract base name and extension
base_name=$(basename "$file_path")
dir_name=$(dirname "$file_path")
extension="${base_name##*.}"
name_without_ext="${base_name%.*}"
# Build test file patterns based on source file type
test_patterns=()
case "$extension" in
"js")
test_patterns+=("${dir_name}/${name_without_ext}.test.js")
test_patterns+=("${dir_name}/${name_without_ext}.spec.js")
;;
"ts")
test_patterns+=("${dir_name}/${name_without_ext}.test.ts")
test_patterns+=("${dir_name}/${name_without_ext}.spec.ts")
;;
"jsx")
test_patterns+=("${dir_name}/${name_without_ext}.test.jsx")
test_patterns+=("${dir_name}/${name_without_ext}.spec.jsx")
test_patterns+=("${dir_name}/${name_without_ext}.test.js")
test_patterns+=("${dir_name}/${name_without_ext}.spec.js")
;;
"tsx")
test_patterns+=("${dir_name}/${name_without_ext}.test.tsx")
test_patterns+=("${dir_name}/${name_without_ext}.spec.tsx")
test_patterns+=("${dir_name}/${name_without_ext}.test.ts")
test_patterns+=("${dir_name}/${name_without_ext}.spec.ts")
;;
esac
# Look for matching test files
found_test=""
for pattern in "${test_patterns[@]}"; do
if [[ -f "$pattern" ]]; then
found_test="$pattern"
break
fi
done
if [[ -z "$found_test" ]]; then
echo "TDD Violation: No test file found for $file_path" >&2
echo "" >&2
echo "Expected test files:" >&2
for pattern in "${test_patterns[@]}"; do
echo " - $(basename "$pattern")" >&2
done
echo "" >&2
echo "Following TDD principles:" >&2
echo "1. Write a failing test first (Red phase)" >&2
echo "2. Write minimal code to pass the test (Green phase)" >&2
echo "3. Refactor while keeping tests green (Refactor phase)" >&2
exit 2
fi
# Test file exists, allow operation
exit 0
@hesreallyhim
Copy link

quick comment re:

{
     "type": "command",
     "command": ".claude/hooks/ts-tdd-guard.sh"
 }

https://docs.anthropic.com/en/docs/claude-code/hooks#security-best-practices:

Use absolute paths - Specify full paths for scripts

@LarryStanley
Copy link
Author

@hesreallyhim thanks just upated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment