-
Notifications
You must be signed in to change notification settings - Fork 3k
Expand file tree
/
Copy pathbefore-git-commit.sh
More file actions
executable file
·133 lines (117 loc) · 3.52 KB
/
Copy pathbefore-git-commit.sh
File metadata and controls
executable file
·133 lines (117 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env bash
# Inject conventional-commit guidance before agent git commits.
# Validates extracted messages; blocks invalid commits via permission: deny.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
VALIDATOR="$ROOT/.cursor/skills/rxjs-conventional-commits/scripts/validate-message.sh"
SKILL=".cursor/skills/rxjs-conventional-commits/SKILL.md"
input="$(cat)"
command="$(echo "$input" | jq -r '.command // empty')"
# Only git commit (including --amend); ignore other git subcommands.
if [[ ! "$command" =~ (^|[[:space:]])git[[:space:]]+commit([[:space:]]|$) ]]; then
echo '{ "permission": "allow" }'
exit 0
fi
extract_heredoc_message() {
local cmd="$1"
# Single-line HEREDOC: git commit -m "$(cat <<'EOF' body EOF )"
if [[ "$cmd" == *"<<"*"EOF"* ]]; then
local inline
inline="$(printf '%s' "$cmd" | awk '
match($0, /<<[[:space:]]*('\''EOF'\''|"EOF"|EOF)[[:space:]]*/) {
start = RSTART + RLENGTH
rest = substr($0, start)
if (match(rest, /EOF/)) {
body = substr(rest, 1, RSTART - 1)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", body)
gsub(/\)[[:space:]]*$/, "", body)
if (length(body) > 0) {
print body
}
}
}
')"
if [[ -n "$inline" ]]; then
printf '%s' "$inline"
return 0
fi
fi
# Multi-line HEREDOC (command string contains literal newlines)
if [[ "$cmd" == *$'\n'* && "$cmd" == *"<<"*"EOF"* ]]; then
local multiline
multiline="$(printf '%s\n' "$cmd" | awk '
BEGIN { in_body = 0 }
/cat[[:space:]]+<<[[:space:]]*/ {
in_body = 1
next
}
in_body && (/^EOF[[:space:]]*\)/ || /^EOF[[:space:]]*$/) {
exit
}
in_body {
print
}
')"
if [[ -n "$multiline" ]]; then
printf '%s' "$multiline"
return 0
fi
fi
return 1
}
extract_message() {
local cmd="$1"
local msg=""
if msg="$(extract_heredoc_message "$cmd")"; then
printf '%s' "$msg"
return 0
fi
# Repeated -m "..." / -m '...' (git joins with newlines)
while [[ "$cmd" =~ -m[[:space:]]+ ]]; do
local fragment=""
if [[ "$cmd" =~ -m[[:space:]]+\"(([^\"\\]|\\.)*)\" ]]; then
fragment="${BASH_REMATCH[1]}"
cmd="${cmd/-m \"${BASH_REMATCH[1]}\"/}"
elif [[ "$cmd" =~ -m[[:space:]]+\'([^\']*)\' ]]; then
fragment="${BASH_REMATCH[1]}"
cmd="${cmd/-m \'${BASH_REMATCH[1]}\'/}"
else
break
fi
if [[ -n "$msg" ]]; then
msg+=$'\n'
fi
msg+="$fragment"
done
if [[ -n "$msg" ]]; then
printf '%s' "$msg"
fi
}
deny_invalid_message() {
local validation="$1"
jq -n \
--arg skill "$SKILL" \
--arg validation "$validation" \
'{
permission: "deny",
user_message: "Commit message does not follow RxJS conventional-commit format.",
agent_message: ("Rewrite the commit message per " + $skill + " before committing.\n\nValidation errors:\n" + $validation)
}'
}
message="$(extract_message "$command" || true)"
if [[ -n "$message" && -x "$VALIDATOR" ]]; then
validation_err="$(mktemp)"
if ! "$VALIDATOR" "$message" 2>"$validation_err"; then
validation="$(cat "$validation_err")"
rm -f "$validation_err"
deny_invalid_message "$validation"
exit 0
fi
rm -f "$validation_err"
fi
jq -n \
--arg skill "$SKILL" \
'{
permission: "allow",
agent_message: ("Follow RxJS conventional commits (" + $skill + "): type(scope): subject, imperative lowercase subject, max 100 chars/line. Run git diff first; use a HEREDOC for multi-line messages.")
}'