no-yolo-commits 1.0.0 → 1.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "no-yolo-commits",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "AI pre-commit review (via the claude CLI) + a guard that auto-branches you off main/master instead of letting a direct commit land there.",
5
5
  "keywords": [
6
6
  "husky",
@@ -34,5 +34,11 @@
34
34
  },
35
35
  "publishConfig": {
36
36
  "access": "public"
37
+ },
38
+ "devDependencies": {
39
+ "husky": "^9.1.7"
40
+ },
41
+ "scripts": {
42
+ "prepare": "husky"
37
43
  }
38
44
  }
@@ -13,13 +13,18 @@ Do NOT flag stylistic preferences. Do NOT flag pre-existing patterns already use
13
13
 
14
14
  review_tmpfile="$(mktemp)"
15
15
 
16
- (claude -p "$review_prompt" \
16
+ # No subshell wrapper here on purpose: `(claude ...; exit 0) &` would make
17
+ # $! the wrapper's PID, not claude's — since the wrapper has more to do
18
+ # after claude exits, the shell can't tail-exec it, so killing $review_pid
19
+ # on timeout would kill the empty wrapper and leave claude itself running
20
+ # orphaned. Backgrounding claude directly makes $! the real PID.
21
+ claude -p "$review_prompt" \
17
22
  --output-format json \
18
23
  --json-schema '{"type":"object","properties":{"blocking_issues":{"type":"array","items":{"type":"string"}}},"required":["blocking_issues"]}' \
19
24
  --allowedTools "Bash(git diff*)" "Bash(git show*)" "Bash(git log*)" "Read" "Grep" "Glob" \
20
25
  --disallowedTools "Write" "Edit" "MultiEdit" "NotebookEdit" \
21
26
  --permission-mode bypassPermissions \
22
- >"$review_tmpfile" 2>/dev/null; exit 0) &
27
+ >"$review_tmpfile" 2>/dev/null &
23
28
  review_pid=$!
24
29
  (sleep 120; kill "$review_pid" >/dev/null 2>&1; exit 0) >/dev/null 2>&1 &
25
30
  review_watcher_pid=$!
@@ -33,7 +38,13 @@ Do NOT flag stylistic preferences. Do NOT flag pre-existing patterns already use
33
38
  const fs = require("fs")
34
39
  try {
35
40
  const data = JSON.parse(fs.readFileSync(process.argv[1], "utf-8"))
36
- const issues = (data.structured_output && data.structured_output.blocking_issues) || []
41
+ // An API/session error from claude itself is valid JSON with no
42
+ // structured_output — falling back to [] there made a failed review
43
+ // look identical to "no issues found" instead of "unavailable".
44
+ if (data.is_error || !data.structured_output) {
45
+ process.exit(2)
46
+ }
47
+ const issues = data.structured_output.blocking_issues || []
37
48
  if (issues.length > 0) {
38
49
  console.error("")
39
50
  console.error("⛔ AI review found blocking issues:")
@@ -83,7 +94,9 @@ if command -v claude >/dev/null 2>&1; then
83
94
  tmpfile="$(mktemp)"
84
95
  prompt="Summarize the following staged git diff as ONE short phrase in kebab-case (lowercase words separated by hyphens, no punctuation, no quotes), at most 8 words, describing what changed. Output ONLY the phrase, nothing else, no explanation."
85
96
 
86
- (printf '%s' "$diff" | claude -p "$prompt" >"$tmpfile" 2>/dev/null; exit 0) &
97
+ # Same reasoning as the review call above: background claude directly,
98
+ # no subshell wrapper, so $! is the real PID the timeout can kill.
99
+ printf '%s' "$diff" | claude -p "$prompt" >"$tmpfile" 2>/dev/null &
87
100
  claude_pid=$!
88
101
  (sleep 25; kill "$claude_pid" >/dev/null 2>&1; exit 0) >/dev/null 2>&1 &
89
102
  watcher_pid=$!
@@ -113,13 +126,14 @@ timestamp="$(date +%s)"
113
126
  new_branch="__PREFIX__-${timestamp}-${slug}"
114
127
  new_branch="$(printf '%s' "$new_branch" | cut -c1-100)"
115
128
 
116
- if ! git checkout -b "$new_branch" 2>/tmp/no-yolo-commits-error; then
129
+ branch_err_file="$(mktemp)"
130
+ if ! git checkout -b "$new_branch" 2>"$branch_err_file"; then
117
131
  echo "✗ Failed to create branch '$new_branch':"
118
- cat /tmp/no-yolo-commits-error 2>/dev/null || true
119
- rm -f /tmp/no-yolo-commits-error 2>/dev/null || true
132
+ cat "$branch_err_file" 2>/dev/null || true
133
+ rm -f "$branch_err_file" 2>/dev/null || true
120
134
  echo "Commit aborted — create/switch to a feature branch manually and retry."
121
135
  exit 1
122
136
  fi
123
- rm -f /tmp/no-yolo-commits-error 2>/dev/null || true
137
+ rm -f "$branch_err_file" 2>/dev/null || true
124
138
 
125
139
  echo "✓ Switched to '$new_branch' — continuing commit there."