120 lines
3.0 KiB
Bash
Executable File
120 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
CONTEXT_DIR="$(dirname "$0")/../context"
|
|
LOG_FILE="$CONTEXT_DIR/edit-log.txt"
|
|
LOCK_FILE="$CONTEXT_DIR/.edit-log.lock"
|
|
MAX_LOG_LINES=1000
|
|
LOCK_TIMEOUT=5
|
|
|
|
# Create context dir and log if doesn't exist
|
|
mkdir -p "$CONTEXT_DIR"
|
|
touch "$LOG_FILE"
|
|
|
|
# Acquire lock with timeout
|
|
acquire_lock() {
|
|
local count=0
|
|
while [ $count -lt $LOCK_TIMEOUT ]; do
|
|
if mkdir "$LOCK_FILE" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
sleep 0.2
|
|
count=$((count + 1))
|
|
done
|
|
# Log but don't fail - non-blocking requirement
|
|
echo "Warning: Could not acquire lock" >&2
|
|
return 1
|
|
}
|
|
|
|
# Release lock
|
|
release_lock() {
|
|
rmdir "$LOCK_FILE" 2>/dev/null || true
|
|
}
|
|
|
|
# Clean up lock on exit
|
|
trap release_lock EXIT
|
|
|
|
# Function to log edit
|
|
log_edit() {
|
|
local file_path="$1"
|
|
local tool_name="$2"
|
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
local repo=$(find_repo "$file_path")
|
|
|
|
if acquire_lock; then
|
|
echo "$timestamp | $repo | $tool_name | $file_path" >> "$LOG_FILE"
|
|
release_lock
|
|
fi
|
|
}
|
|
|
|
# Function to find repo root
|
|
find_repo() {
|
|
local file_path="$1"
|
|
if [ -z "$file_path" ] || [ "$file_path" = "null" ]; then
|
|
echo "unknown"
|
|
return
|
|
fi
|
|
|
|
local dir
|
|
dir=$(dirname "$file_path" 2>/dev/null || echo "/")
|
|
while [ "$dir" != "/" ] && [ -n "$dir" ]; do
|
|
if [ -d "$dir/.git" ]; then
|
|
basename "$dir"
|
|
return
|
|
fi
|
|
dir=$(dirname "$dir" 2>/dev/null || echo "/")
|
|
done
|
|
echo "unknown"
|
|
}
|
|
|
|
# Read tool use event from stdin (with timeout to prevent hanging)
|
|
if ! read -t 2 -r tool_use_json; then
|
|
echo '{}'
|
|
exit 0
|
|
fi
|
|
|
|
# Validate JSON to prevent injection
|
|
if ! echo "$tool_use_json" | jq empty 2>/dev/null; then
|
|
echo '{}'
|
|
exit 0
|
|
fi
|
|
|
|
# Extract tool name and file path from tool use
|
|
tool_name=$(echo "$tool_use_json" | jq -r '.tool.name // .tool_name // "unknown"' 2>/dev/null || echo "unknown")
|
|
file_path=""
|
|
|
|
case "$tool_name" in
|
|
"Edit"|"Write")
|
|
file_path=$(echo "$tool_use_json" | jq -r '.tool.input.file_path // .tool_input.file_path // "null"' 2>/dev/null || echo "null")
|
|
;;
|
|
"MultiEdit")
|
|
# MultiEdit has multiple files - log each
|
|
echo "$tool_use_json" | jq -r '.tool.input.edits[]?.file_path // .tool_input.edits[]?.file_path // empty' 2>/dev/null | while read -r path; do
|
|
if [ -n "$path" ] && [ "$path" != "null" ]; then
|
|
log_edit "$path" "$tool_name"
|
|
fi
|
|
done
|
|
echo '{}'
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
# Log single edit
|
|
if [ -n "$file_path" ] && [ "$file_path" != "null" ]; then
|
|
log_edit "$file_path" "$tool_name"
|
|
fi
|
|
|
|
# Rotate log if too large (with lock)
|
|
if acquire_lock; then
|
|
line_count=$(wc -l < "$LOG_FILE" 2>/dev/null || echo "0")
|
|
if [ "$line_count" -gt "$MAX_LOG_LINES" ]; then
|
|
tail -n "$MAX_LOG_LINES" "$LOG_FILE" > "$LOG_FILE.tmp"
|
|
mv "$LOG_FILE.tmp" "$LOG_FILE"
|
|
fi
|
|
release_lock
|
|
fi
|
|
|
|
# Return success (non-blocking)
|
|
echo '{}'
|