claude-git-hooks 1.5.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -1
- package/README.md +130 -35
- package/bin/claude-hooks +253 -287
- package/lib/hooks/pre-commit.js +335 -0
- package/lib/hooks/prepare-commit-msg.js +283 -0
- package/lib/utils/claude-client.js +373 -0
- package/lib/utils/file-operations.js +409 -0
- package/lib/utils/git-operations.js +341 -0
- package/lib/utils/logger.js +141 -0
- package/lib/utils/prompt-builder.js +283 -0
- package/lib/utils/resolution-prompt.js +291 -0
- package/package.json +52 -40
- package/templates/pre-commit +58 -411
- package/templates/prepare-commit-msg +62 -118
|
@@ -1,138 +1,82 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
-
# Git Prepare-commit-msg Hook
|
|
4
|
-
#
|
|
3
|
+
# Git Prepare-commit-msg Hook - Node.js Wrapper
|
|
4
|
+
# This is a minimal wrapper that calls the actual Node.js implementation
|
|
5
|
+
# Why: Allows the Node.js script to use relative imports from its installed location
|
|
5
6
|
|
|
6
7
|
set -e
|
|
7
8
|
|
|
8
|
-
# Configuration
|
|
9
|
-
CLAUDE_CLI="claude"
|
|
10
|
-
TEMP_DIR="/tmp/commit-msg-$$"
|
|
11
|
-
MAX_FILE_SIZE=100000
|
|
12
|
-
AUTO_COMMIT_ENABLED=true
|
|
13
|
-
|
|
14
9
|
# Colors for output
|
|
15
10
|
RED='\033[0;31m'
|
|
16
|
-
GREEN='\033[0;32m'
|
|
17
|
-
YELLOW='\033[1;33m'
|
|
18
11
|
NC='\033[0m'
|
|
19
12
|
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
13
|
+
# Convert Windows path to Git Bash/WSL path
|
|
14
|
+
# Why: npm prefix -g in Git Bash returns Windows paths (C:\...) that need conversion
|
|
15
|
+
convert_windows_path() {
|
|
16
|
+
local path="$1"
|
|
17
|
+
|
|
18
|
+
# Check if it's a Windows path (contains :\ or starts with C:)
|
|
19
|
+
if [[ "$path" =~ ^[A-Za-z]:\\ ]] || [[ "$path" =~ ^[A-Za-z]: ]]; then
|
|
20
|
+
# Convert C:\path\to\file to /c/path/to/file
|
|
21
|
+
# First, extract drive letter
|
|
22
|
+
local drive=$(echo "$path" | sed 's/^\([A-Za-z]\):.*/\1/' | tr '[:upper:]' '[:lower:]')
|
|
23
|
+
# Remove drive letter and colon, replace backslashes with forward slashes
|
|
24
|
+
local rest=$(echo "$path" | sed 's/^[A-Za-z]://' | sed 's/\\/\//g')
|
|
25
|
+
echo "/$drive$rest"
|
|
26
|
+
else
|
|
27
|
+
echo "$path"
|
|
28
|
+
fi
|
|
32
29
|
}
|
|
33
|
-
trap cleanup EXIT
|
|
34
|
-
|
|
35
|
-
# Hook arguments
|
|
36
|
-
COMMIT_MSG_FILE="$1"
|
|
37
|
-
COMMIT_SOURCE="$2"
|
|
38
|
-
|
|
39
|
-
# Only process if it's a normal commit
|
|
40
|
-
if [ "$COMMIT_SOURCE" != "" ] && [ "$COMMIT_SOURCE" != "message" ]; then
|
|
41
|
-
exit 0
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
# Read the current message
|
|
45
|
-
CURRENT_MSG=$(head -n 1 "$COMMIT_MSG_FILE" 2>/dev/null || echo "")
|
|
46
|
-
|
|
47
|
-
# Check if we need to generate a message
|
|
48
|
-
if [ "$CURRENT_MSG" = "auto" ]; then
|
|
49
|
-
log "Trying to generate message..."
|
|
50
|
-
else
|
|
51
|
-
exit 0
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
# Check if Claude CLI is installed
|
|
55
|
-
if ! command -v "$CLAUDE_CLI" &> /dev/null; then
|
|
56
|
-
warning "Claude CLI is not installed"
|
|
57
|
-
warning "Commit canceled. Run again without 'auto' to write manual message"
|
|
58
|
-
exit 1
|
|
59
|
-
fi
|
|
60
30
|
|
|
61
|
-
|
|
62
|
-
|
|
31
|
+
# Function to find the Node.js script
|
|
32
|
+
find_hook_script() {
|
|
33
|
+
# Why: Try multiple locations to find where npm installed the package
|
|
34
|
+
# Checks: global npm, local node_modules, npm prefix
|
|
63
35
|
|
|
64
|
-
|
|
65
|
-
|
|
36
|
+
# Get npm global prefix and convert if it's a Windows path
|
|
37
|
+
local npm_prefix=$(npm prefix -g 2>/dev/null || echo "")
|
|
38
|
+
if [ -n "$npm_prefix" ]; then
|
|
39
|
+
npm_prefix=$(convert_windows_path "$npm_prefix")
|
|
40
|
+
fi
|
|
66
41
|
|
|
67
|
-
|
|
42
|
+
local SCRIPT_PATHS=(
|
|
43
|
+
# Global npm installation (Linux/Mac)
|
|
44
|
+
"/usr/local/lib/node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
45
|
+
"/usr/lib/node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
46
|
+
# Global npm installation (Windows) - node_modules directly under prefix
|
|
47
|
+
"${npm_prefix}/node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
48
|
+
# Global npm installation (Unix/WSL) - lib/node_modules under prefix
|
|
49
|
+
"${npm_prefix}/lib/node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
50
|
+
# Home directory npm global
|
|
51
|
+
"$HOME/.npm-global/lib/node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
52
|
+
# Local node_modules (if linked or installed locally)
|
|
53
|
+
"./node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
54
|
+
"../node_modules/claude-git-hooks/lib/hooks/prepare-commit-msg.js"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
for path in "${SCRIPT_PATHS[@]}"; do
|
|
58
|
+
if [ -f "$path" ]; then
|
|
59
|
+
echo "$path"
|
|
60
|
+
return 0
|
|
61
|
+
fi
|
|
62
|
+
done
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
"type": "feat|fix|docs|style|refactor|test|chore|ci|perf",
|
|
71
|
-
"scope": "optional scope (e.g.: api, frontend, db)",
|
|
72
|
-
"title": "short description in present tense (max 50 chars)",
|
|
73
|
-
"body": "optional detailed description"
|
|
64
|
+
return 1
|
|
74
65
|
}
|
|
75
66
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# Get staged files
|
|
80
|
-
ALL_STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || echo "")
|
|
67
|
+
# Find the Node.js script
|
|
68
|
+
NODE_HOOK=$(find_hook_script)
|
|
81
69
|
|
|
82
|
-
if [ -z "$
|
|
83
|
-
|
|
84
|
-
|
|
70
|
+
if [ -z "$NODE_HOOK" ]; then
|
|
71
|
+
echo -e "${RED}Error: Could not find prepare-commit-msg.js${NC}" >&2
|
|
72
|
+
echo "Claude Git Hooks may not be properly installed." >&2
|
|
73
|
+
echo "Try running: claude-hooks install --force" >&2
|
|
85
74
|
exit 1
|
|
86
75
|
fi
|
|
87
76
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# Show diffs of small files
|
|
95
|
-
for FILE in $ALL_STAGED_FILES; do
|
|
96
|
-
if [ -f "$FILE" ]; then
|
|
97
|
-
FILE_SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE" 2>/dev/null || echo "0")
|
|
98
|
-
|
|
99
|
-
if [ "$FILE_SIZE" -lt "$MAX_FILE_SIZE" ]; then
|
|
100
|
-
printf "\n--- Diff of %s ---\n" "$FILE" >> "$PROMPT_FILE"
|
|
101
|
-
git diff --cached "$FILE" >> "$PROMPT_FILE" 2>/dev/null || echo "Could not get diff"
|
|
102
|
-
fi
|
|
103
|
-
fi
|
|
104
|
-
done
|
|
105
|
-
|
|
106
|
-
RESPONSE_FILE="$TEMP_DIR/commit_msg_response.txt"
|
|
107
|
-
log "Generating commit message with Claude..."
|
|
108
|
-
|
|
109
|
-
if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
|
|
110
|
-
JSON_MSG=$(sed -n '/^{/,/^}/p' "$RESPONSE_FILE" | head -n 1000)
|
|
111
|
-
|
|
112
|
-
if [ -n "$JSON_MSG" ]; then
|
|
113
|
-
MSG_TYPE=$(echo "$JSON_MSG" | jq -r '.type // "feat"' 2>/dev/null || echo "feat")
|
|
114
|
-
MSG_SCOPE=$(echo "$JSON_MSG" | jq -r '.scope // ""' 2>/dev/null || echo "")
|
|
115
|
-
MSG_TITLE=$(echo "$JSON_MSG" | jq -r '.title // ""' 2>/dev/null || echo "")
|
|
116
|
-
MSG_BODY=$(echo "$JSON_MSG" | jq -r '.body // ""' 2>/dev/null || echo "")
|
|
117
|
-
|
|
118
|
-
if [ -n "$MSG_TITLE" ]; then
|
|
119
|
-
FULL_MESSAGE="$MSG_TYPE"
|
|
120
|
-
if [ -n "$MSG_SCOPE" ] && [ "$MSG_SCOPE" != "null" ]; then
|
|
121
|
-
FULL_MESSAGE="${FULL_MESSAGE}(${MSG_SCOPE})"
|
|
122
|
-
fi
|
|
123
|
-
FULL_MESSAGE="${FULL_MESSAGE}: ${MSG_TITLE}"
|
|
124
|
-
|
|
125
|
-
if [ -n "$MSG_BODY" ] && [ "$MSG_BODY" != "null" ]; then
|
|
126
|
-
FULL_MESSAGE="${FULL_MESSAGE}\n\n${MSG_BODY}"
|
|
127
|
-
fi
|
|
128
|
-
|
|
129
|
-
printf "%s\n" "$FULL_MESSAGE" > "$COMMIT_MSG_FILE"
|
|
130
|
-
log "📝 Message generated: $(echo "$FULL_MESSAGE" | head -n 1)"
|
|
131
|
-
exit 0
|
|
132
|
-
fi
|
|
133
|
-
fi
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
warning "Could not generate message automatically with Claude"
|
|
137
|
-
warning "Commit canceled. Run again without 'auto' to write manual message"
|
|
138
|
-
exit 1
|
|
77
|
+
# Execute the Node.js script
|
|
78
|
+
# Why: Pass all arguments ($@) - Git provides:
|
|
79
|
+
# $1: commit message file path
|
|
80
|
+
# $2: commit source (message, template, merge, squash, commit)
|
|
81
|
+
# $3: commit SHA (for -c, -C, --amend)
|
|
82
|
+
exec node "$NODE_HOOK" "$@"
|