Major Features Added: • Automated hook installation scripts (install-hooks.sh and setup-hooks) • User-scope installation with automatic domain configuration • 7 pre-configured hook profiles for different user types • Comprehensive documentation updates across all guides Hook Installation System: • ./setup-hooks - One-liner installation for most users • ./install-hooks.sh - Full-featured installer with profile selection • Automatic domain replacement using $DOMAIN environment variable • Settings backup and verification capabilities • Safe uninstallation with rollback support Documentation Enhancements: • Updated README.md with complete project overview and proper git repository URL • Enhanced Getting Started guide with automated hook installation • Improved Docker deployment guide with hook installation step • Reorganized documentation index with better visual hierarchy • Added repository URL: https://git.supported.systems/claude/claude-code-tracker.git Technical Improvements: • Rebuilt Docker containers with all latest changes • Verified application health and functionality • Updated all installation examples with correct repository URL • Improved quick start workflow with 3-step visual process 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
377 lines
11 KiB
Bash
Executable File
377 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Claude Code Tracker - Hook Installation Script
|
||
# Automatically installs hooks for Claude Code using domain from environment
|
||
|
||
set -e
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Configuration
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
CLAUDE_CONFIG_DIR="$HOME/.config/claude-code"
|
||
CLAUDE_SETTINGS_FILE="$CLAUDE_CONFIG_DIR/settings.json"
|
||
|
||
# Hook profiles available
|
||
AVAILABLE_PROFILES=(
|
||
"basic"
|
||
"essential"
|
||
"comprehensive"
|
||
"developer"
|
||
"power_user"
|
||
"research"
|
||
"team"
|
||
)
|
||
|
||
print_header() {
|
||
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
|
||
echo -e "${BLUE}║ Claude Code Tracker Hooks ║${NC}"
|
||
echo -e "${BLUE}║ Installation Script ║${NC}"
|
||
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓${NC} $1"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠${NC} $1"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗${NC} $1"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ${NC} $1"
|
||
}
|
||
|
||
check_requirements() {
|
||
print_info "Checking requirements..."
|
||
|
||
# Check if Claude Code is installed
|
||
if ! command -v claude-code &> /dev/null; then
|
||
print_error "Claude Code is not installed or not in PATH"
|
||
print_info "Please install Claude Code first: https://claude.ai/code"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if jq is available for JSON manipulation
|
||
if ! command -v jq &> /dev/null; then
|
||
print_warning "jq is not installed. Using fallback JSON handling."
|
||
USE_JQ=false
|
||
else
|
||
USE_JQ=true
|
||
fi
|
||
|
||
# Check domain configuration
|
||
if [[ -z "$DOMAIN" ]]; then
|
||
# Try to read from .env file
|
||
if [[ -f "$SCRIPT_DIR/.env" ]]; then
|
||
source "$SCRIPT_DIR/.env"
|
||
fi
|
||
|
||
if [[ -z "$DOMAIN" ]]; then
|
||
print_error "DOMAIN environment variable is not set"
|
||
print_info "Please set DOMAIN environment variable or create .env file"
|
||
print_info "Example: export DOMAIN=claude.l.supported.systems"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
print_success "Domain configured: $DOMAIN"
|
||
print_success "Requirements check passed"
|
||
}
|
||
|
||
create_claude_config_dir() {
|
||
if [[ ! -d "$CLAUDE_CONFIG_DIR" ]]; then
|
||
print_info "Creating Claude Code configuration directory..."
|
||
mkdir -p "$CLAUDE_CONFIG_DIR"
|
||
print_success "Created directory: $CLAUDE_CONFIG_DIR"
|
||
fi
|
||
}
|
||
|
||
backup_existing_settings() {
|
||
if [[ -f "$CLAUDE_SETTINGS_FILE" ]]; then
|
||
local backup_file="${CLAUDE_SETTINGS_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
|
||
print_info "Backing up existing settings to: $backup_file"
|
||
cp "$CLAUDE_SETTINGS_FILE" "$backup_file"
|
||
print_success "Backup created"
|
||
fi
|
||
}
|
||
|
||
get_hook_profile_path() {
|
||
local profile="$1"
|
||
echo "$SCRIPT_DIR/claude-hooks-${profile}.json"
|
||
}
|
||
|
||
list_available_profiles() {
|
||
echo -e "${BLUE}Available hook profiles:${NC}"
|
||
echo ""
|
||
|
||
for profile in "${AVAILABLE_PROFILES[@]}"; do
|
||
local profile_file
|
||
profile_file=$(get_hook_profile_path "$profile")
|
||
|
||
if [[ -f "$profile_file" ]]; then
|
||
local description
|
||
if [[ "$USE_JQ" == true ]]; then
|
||
description=$(jq -r '.metadata.description // "No description available"' "$profile_file" 2>/dev/null || echo "No description available")
|
||
else
|
||
description="Hook configuration for $profile users"
|
||
fi
|
||
|
||
echo -e " ${GREEN}$profile${NC} - $description"
|
||
else
|
||
echo -e " ${RED}$profile${NC} - Profile file not found"
|
||
fi
|
||
done
|
||
echo ""
|
||
}
|
||
|
||
update_hook_domain() {
|
||
local input_file="$1"
|
||
local output_file="$2"
|
||
|
||
print_info "Updating hook URLs with domain: $DOMAIN"
|
||
|
||
# Replace placeholder domain with actual domain
|
||
sed "s/\${DOMAIN}/$DOMAIN/g; s/localhost:8000/$DOMAIN/g; s/http:\/\/$DOMAIN/https:\/\/$DOMAIN/g" "$input_file" > "$output_file"
|
||
|
||
print_success "Hook URLs updated"
|
||
}
|
||
|
||
install_hooks() {
|
||
local profile="$1"
|
||
local profile_file
|
||
profile_file=$(get_hook_profile_path "$profile")
|
||
|
||
if [[ ! -f "$profile_file" ]]; then
|
||
print_error "Hook profile file not found: $profile_file"
|
||
exit 1
|
||
fi
|
||
|
||
print_info "Installing hooks from profile: $profile"
|
||
|
||
# Create temporary file with updated domain
|
||
local temp_file="/tmp/claude-hooks-${profile}-$(date +%s).json"
|
||
update_hook_domain "$profile_file" "$temp_file"
|
||
|
||
# Merge with existing settings or create new
|
||
local final_settings="$temp_file"
|
||
|
||
if [[ -f "$CLAUDE_SETTINGS_FILE" ]] && [[ "$USE_JQ" == true ]]; then
|
||
print_info "Merging with existing Claude Code settings..."
|
||
|
||
# Merge hook configurations
|
||
local merged_file="/tmp/claude-settings-merged-$(date +%s).json"
|
||
jq -s '.[0] * .[1]' "$CLAUDE_SETTINGS_FILE" "$temp_file" > "$merged_file"
|
||
final_settings="$merged_file"
|
||
|
||
print_success "Settings merged"
|
||
fi
|
||
|
||
# Install the hooks
|
||
cp "$final_settings" "$CLAUDE_SETTINGS_FILE"
|
||
|
||
# Cleanup temp files
|
||
rm -f "$temp_file"
|
||
if [[ -f "$merged_file" ]]; then
|
||
rm -f "$merged_file"
|
||
fi
|
||
|
||
print_success "Hooks installed successfully!"
|
||
}
|
||
|
||
show_installation_summary() {
|
||
local profile="$1"
|
||
|
||
echo ""
|
||
echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
|
||
echo -e "${GREEN}║ Installation Complete! ║${NC}"
|
||
echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
echo -e "${BLUE}Profile installed:${NC} $profile"
|
||
echo -e "${BLUE}Domain configured:${NC} $DOMAIN"
|
||
echo -e "${BLUE}Settings file:${NC} $CLAUDE_SETTINGS_FILE"
|
||
echo ""
|
||
echo -e "${YELLOW}Next steps:${NC}"
|
||
echo "1. Start using Claude Code in any project"
|
||
echo "2. Visit https://$DOMAIN/dashboard to view your tracking data"
|
||
echo "3. Check the documentation at https://$DOMAIN/dashboard/docs"
|
||
echo ""
|
||
echo -e "${BLUE}To test the installation:${NC}"
|
||
echo " claude-code --help"
|
||
echo ""
|
||
}
|
||
|
||
verify_installation() {
|
||
print_info "Verifying installation..."
|
||
|
||
if [[ -f "$CLAUDE_SETTINGS_FILE" ]]; then
|
||
if [[ "$USE_JQ" == true ]]; then
|
||
if jq empty "$CLAUDE_SETTINGS_FILE" 2>/dev/null; then
|
||
print_success "Settings file is valid JSON"
|
||
|
||
local hook_count
|
||
hook_count=$(jq -r '.hooks | length // 0' "$CLAUDE_SETTINGS_FILE" 2>/dev/null || echo "0")
|
||
print_success "Number of hooks configured: $hook_count"
|
||
|
||
return 0
|
||
else
|
||
print_error "Settings file contains invalid JSON"
|
||
return 1
|
||
fi
|
||
else
|
||
print_success "Settings file exists"
|
||
return 0
|
||
fi
|
||
else
|
||
print_error "Settings file was not created"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
show_help() {
|
||
echo "Claude Code Tracker - Hook Installation Script"
|
||
echo ""
|
||
echo "Usage: $0 [OPTIONS] [PROFILE]"
|
||
echo ""
|
||
echo "PROFILE: Hook profile to install (default: comprehensive)"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " -l, --list List available profiles"
|
||
echo " -d, --domain DOMAIN Set the domain (overrides DOMAIN env var)"
|
||
echo " -h, --help Show this help message"
|
||
echo " --verify Verify existing installation"
|
||
echo " --uninstall Remove all hooks from settings"
|
||
echo ""
|
||
echo "Examples:"
|
||
echo " $0 # Install comprehensive profile"
|
||
echo " $0 basic # Install basic profile"
|
||
echo " $0 -d example.com # Install with custom domain"
|
||
echo " $0 --list # List available profiles"
|
||
echo ""
|
||
echo "Environment Variables:"
|
||
echo " DOMAIN Target domain for the Claude Code Tracker"
|
||
echo ""
|
||
}
|
||
|
||
uninstall_hooks() {
|
||
print_info "Uninstalling Claude Code Tracker hooks..."
|
||
|
||
if [[ ! -f "$CLAUDE_SETTINGS_FILE" ]]; then
|
||
print_warning "No settings file found, nothing to uninstall"
|
||
return 0
|
||
fi
|
||
|
||
backup_existing_settings
|
||
|
||
if [[ "$USE_JQ" == true ]]; then
|
||
# Remove hooks section but keep other settings
|
||
jq 'del(.hooks)' "$CLAUDE_SETTINGS_FILE" > "${CLAUDE_SETTINGS_FILE}.tmp"
|
||
mv "${CLAUDE_SETTINGS_FILE}.tmp" "$CLAUDE_SETTINGS_FILE"
|
||
print_success "Hooks removed from settings"
|
||
else
|
||
print_warning "Cannot automatically remove hooks without jq. Manual removal required."
|
||
print_info "Edit $CLAUDE_SETTINGS_FILE and remove the 'hooks' section"
|
||
fi
|
||
}
|
||
|
||
main() {
|
||
local profile="comprehensive"
|
||
local list_profiles=false
|
||
local verify_only=false
|
||
local uninstall_only=false
|
||
|
||
# Parse command line arguments
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
-h|--help)
|
||
show_help
|
||
exit 0
|
||
;;
|
||
-l|--list)
|
||
list_profiles=true
|
||
shift
|
||
;;
|
||
-d|--domain)
|
||
DOMAIN="$2"
|
||
shift 2
|
||
;;
|
||
--verify)
|
||
verify_only=true
|
||
shift
|
||
;;
|
||
--uninstall)
|
||
uninstall_only=true
|
||
shift
|
||
;;
|
||
-*)
|
||
print_error "Unknown option: $1"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
*)
|
||
profile="$1"
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
|
||
print_header
|
||
|
||
# Handle special modes
|
||
if [[ "$list_profiles" == true ]]; then
|
||
check_requirements
|
||
list_available_profiles
|
||
exit 0
|
||
fi
|
||
|
||
if [[ "$verify_only" == true ]]; then
|
||
check_requirements
|
||
verify_installation
|
||
exit $?
|
||
fi
|
||
|
||
if [[ "$uninstall_only" == true ]]; then
|
||
check_requirements
|
||
create_claude_config_dir
|
||
uninstall_hooks
|
||
print_success "Uninstallation complete"
|
||
exit 0
|
||
fi
|
||
|
||
# Main installation flow
|
||
check_requirements
|
||
create_claude_config_dir
|
||
backup_existing_settings
|
||
|
||
# Validate profile
|
||
if [[ ! " ${AVAILABLE_PROFILES[@]} " =~ " $profile " ]]; then
|
||
print_error "Unknown profile: $profile"
|
||
echo ""
|
||
list_available_profiles
|
||
exit 1
|
||
fi
|
||
|
||
# Install hooks
|
||
install_hooks "$profile"
|
||
|
||
# Verify installation
|
||
if verify_installation; then
|
||
show_installation_summary "$profile"
|
||
else
|
||
print_error "Installation verification failed"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# Run main function with all arguments
|
||
main "$@" |