claudekit
Version:
CLI tools for Claude Code development workflow
230 lines (172 loc) • 8.34 kB
Markdown
# Eliminate validation-lib.sh by Making Hooks Self-Contained
**Status**: Completed
**Authors**: Claude, 2025-07-16
**Type**: Refactoring
## Overview
Refactor all validation hooks to be self-contained by inlining the functions from validation-lib.sh directly into each hook that uses them. This eliminates a common source of setup failures and makes hooks more robust and portable.
## Background/Problem Statement
Currently, several hooks depend on sourcing `validation-lib.sh`, which causes multiple issues:
### Current Architecture Problems
- **Missing dependency errors**: Users frequently forget to copy `validation-lib.sh` during setup
- **Path resolution issues**: Hooks fail when they can't find the library file
- **Setup complexity**: Additional file that must be managed and deployed
- **Version mismatch risks**: Library and hooks can get out of sync
- **Team collaboration friction**: Another file that must be committed and maintained
### Affected Hooks
Based on codebase analysis, three hooks currently depend on validation-lib.sh:
1. `typecheck.sh` - TypeScript validation hook
2. `eslint.sh` - ESLint validation hook
3. `project-validation.sh` - Combined project validation hook
### User Impact
From recent user feedback:
- "Claude Code tells the file does not exist" errors when validation-lib.sh is missing
- Setup script doesn't currently copy validation-lib.sh (critical bug)
- Users must manually ensure this dependency exists in every project
## Goals
- ✅ **Eliminate external dependencies**: Each hook should be completely self-contained
- ✅ **Simplify setup**: Reduce files that need to be copied/managed
- ✅ **Improve reliability**: Remove a common failure point
- ✅ **Maintain functionality**: All current validation features must continue working
- ✅ **Easier debugging**: All code in one place for each hook
## Non-Goals
- ❌ **Creating new validation features**: Only refactoring existing functionality
- ❌ **Changing hook behavior**: Validation logic remains the same
- ❌ **Optimizing shared code**: Accept reasonable duplication for reliability
- ❌ **Creating a build process**: Keep hooks as simple bash scripts
## Technical Dependencies
No new dependencies. This refactoring only reorganizes existing bash code.
## Detailed Design
### Functions to Inline
From validation-lib.sh, these functions need to be copied into hooks that use them:
1. **Core utility functions** (used by all hooks):
- `find_project_root()` - 3 lines
- `parse_json_field()` - 9 lines
2. **Detection functions** (used selectively):
- `has_typescript()` - 3 lines (used by typecheck.sh, project-validation.sh)
- `has_eslint()` - 3 lines (used by eslint.sh, project-validation.sh)
- `has_tests()` - 3 lines (used by project-validation.sh)
3. **Validation functions** (used selectively):
- `validate_typescript_file()` - 41 lines (used by typecheck.sh)
- `validate_eslint_file()` - 14 lines (used by eslint.sh)
- `validate_typescript_project()` - 14 lines (used by project-validation.sh)
- `validate_eslint_project()` - 14 lines (used by project-validation.sh)
- `validate_tests()` - 14 lines (used by project-validation.sh)
- `format_validation_output()` - 9 lines (used by project-validation.sh)
### Refactoring Strategy
1. **typecheck.sh** needs:
- `find_project_root()`
- `parse_json_field()`
- `has_typescript()`
- `validate_typescript_file()`
- Total: ~56 lines of functions to inline
2. **eslint.sh** needs:
- `find_project_root()`
- `parse_json_field()`
- `has_eslint()`
- `validate_eslint_file()`
- Total: ~29 lines of functions to inline
3. **project-validation.sh** needs:
- `find_project_root()`
- `parse_json_field()`
- `has_typescript()`
- `has_eslint()`
- `has_tests()`
- `validate_typescript_project()`
- `validate_eslint_project()`
- `validate_tests()`
- `format_validation_output()`
- Total: ~76 lines of functions to inline
### Code Structure After Refactoring
Each hook will have this structure:
```bash
#!/usr/bin/env bash
set -euo pipefail
################################################################################
# [Hook Name] - [Description] #
# Self-contained validation hook with all dependencies included #
################################################################################
# === Inlined Helper Functions ===
find_project_root() {
local start_dir="${1:-$(pwd)}"
git -C "$start_dir" rev-parse --show-toplevel 2>/dev/null || pwd
}
parse_json_field() {
# ... implementation ...
}
# === Inlined Validation Functions ===
[specific functions needed by this hook]
# === Main Hook Logic ===
[existing hook logic unchanged]
```
## User Experience
For end users:
- **No visible changes** - Hooks work exactly the same way
- **Fewer setup failures** - No missing validation-lib.sh errors
- **Simpler mental model** - Each hook is just one file
For developers:
- **Easier to understand** - All code in one place
- **Easier to modify** - No need to check shared library
- **Easier to test** - Can test each hook independently
## Testing Strategy
### Unit Tests
- **Verify identical behavior**: Each refactored hook must produce same output as original
- **Test all code paths**: Ensure inlined functions work correctly in context
- **Error handling**: Verify error cases still handled properly
### Integration Tests
- **Run test-validation-hooks.sh**: Existing test suite must pass without modification
- **Test missing dependencies**: Verify hooks work without validation-lib.sh present
- **Cross-project testing**: Test hooks in different project types
### Manual Testing
Test each hook in real projects:
1. TypeScript project with type errors
2. JavaScript project with ESLint violations
3. Project with no TypeScript/ESLint configuration
4. Mixed project with both TypeScript and JavaScript
## Performance Considerations
- **Negligible impact**: ~50-75 lines of bash code duplication per hook
- **No runtime overhead**: Same functions, just in different locations
- **Slightly larger hook files**: From ~50 lines to ~100-125 lines each
- **Acceptable tradeoff**: Reliability > minimal code duplication
## Security Considerations
- **No new security implications**: Same code, different organization
- **Reduced attack surface**: Fewer files to potentially tamper with
- **Same permission model**: Hooks still need executable permissions
## Documentation
### Updates Required
1. **setup.sh**: Remove any references to validation-lib.sh
2. **hooks-documentation.md**: Update to reflect self-contained hooks
3. **README.md**: Simplify setup instructions (fewer files)
4. **AGENT.md**: Update setup process documentation
### Developer Notes
Add comment in each hook explaining the self-contained design:
```bash
# This hook is self-contained and includes all necessary validation functions.
# No external dependencies required - just copy this file and it works.
```
## Implementation Phases
### Phase 1: Refactor Individual Hooks
1. Create new version of typecheck.sh with inlined functions
2. Create new version of eslint.sh with inlined functions
3. Create new version of project-validation.sh with inlined functions
4. Test each hook independently
### Phase 2: Update Test Suite
1. Update test-validation-hooks.sh to not source validation-lib.sh
2. Verify all tests pass with new self-contained hooks
3. Add tests for missing validation-lib.sh scenario
### Phase 3: Cleanup and Migration
1. Update setup.sh to not copy validation-lib.sh
2. Remove validation-lib.sh from the repository
3. Update all documentation
4. Create migration notes for existing users
## Open Questions
1. **Should we use a build process instead?**
- Decision: No, keep it simple. Direct duplication is more maintainable than adding build complexity.
2. **What about future shared functions?**
- Decision: Evaluate case-by-case. Only share if complexity warrants it.
3. **Should we keep validation-lib.sh for backwards compatibility?**
- Decision: No, clean break. The hooks will work without it.
## References
- Current validation-lib.sh implementation
- User feedback about setup issues
- Existing hook architecture
- Test suite in tests/test-validation-hooks.sh