diff --git a/.claude/hooks/post-edit-lint.sh b/.claude/hooks/post-edit-lint.sh index 08b38b1..300d9ed 100755 --- a/.claude/hooks/post-edit-lint.sh +++ b/.claude/hooks/post-edit-lint.sh @@ -6,7 +6,7 @@ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') # Only track .rb files, skip vendored/generated paths if [[ "$FILE" == *.rb ]] && [[ "$FILE" != */vendor/* ]] && [[ "$FILE" != */coverage/* ]]; then - TRACKER="/tmp/claude-edited-rb-files-${CLAUDE_HOOK_SESSION_ID:-default}" + TRACKER="${TMPDIR:-/tmp}/claude-edited-rb-files-${CLAUDE_HOOK_SESSION_ID:-default}" echo "$FILE" >> "$TRACKER" sort -u "$TRACKER" -o "$TRACKER" fi diff --git a/.claude/hooks/post-stop-validate.sh b/.claude/hooks/post-stop-validate.sh index adea946..b80f8e5 100755 --- a/.claude/hooks/post-stop-validate.sh +++ b/.claude/hooks/post-stop-validate.sh @@ -1,9 +1,10 @@ #!/bin/bash cd "$CLAUDE_PROJECT_DIR" || exit 0 -TRACKER="/tmp/claude-edited-rb-files-${CLAUDE_HOOK_SESSION_ID:-default}" +TRACKER="${TMPDIR:-/tmp}/claude-edited-rb-files-${CLAUDE_HOOK_SESSION_ID:-default}" ctx="" +had_edits=false # Batch rubocop autocorrect on tracked files (if any were edited) if [[ -f "$TRACKER" ]]; then @@ -11,6 +12,7 @@ if [[ -f "$TRACKER" ]]; then rm -f "$TRACKER" if [[ -n "$files" ]]; then + had_edits=true rubocop_out=$(echo "$files" | xargs bundle exec rubocop -a 2>&1) || true offenses=$(echo "$rubocop_out" | grep -E "^.+:[0-9]+:[0-9]+:" | head -20) if [[ -n "$offenses" ]]; then @@ -19,13 +21,15 @@ if [[ -f "$TRACKER" ]]; then fi fi -# Always run rspec - edits to specs or lib code both matter (~1s) -rspec_out=$(bundle exec rspec 2>&1) -rspec_exit=$? -if [[ $rspec_exit -ne 0 ]]; then - summary=$(echo "$rspec_out" | grep -E "[0-9]+ examples?, [0-9]+ failures?" | tail -1) - failed=$(echo "$rspec_out" | grep -E "^rspec .+" | head -10) - ctx+="rspec failed ($summary):\n$failed\n" +# Only run rspec if files were edited (~1s) +if [[ "$had_edits" == true ]]; then + rspec_out=$(bundle exec rspec 2>&1) + rspec_exit=$? + if [[ $rspec_exit -ne 0 ]]; then + summary=$(echo "$rspec_out" | grep -E "[0-9]+ examples?, [0-9]+ failures?" | tail -1) + failed=$(echo "$rspec_out" | grep -E "^rspec .+" | head -10) + ctx+="rspec failed ($summary):\n$failed\n" + fi fi if [[ -n "$ctx" ]]; then diff --git a/.claude/hooks/session-start-setup.sh b/.claude/hooks/session-start-setup.sh index 122a877..5301889 100755 --- a/.claude/hooks/session-start-setup.sh +++ b/.claude/hooks/session-start-setup.sh @@ -1,10 +1,11 @@ #!/bin/bash cd "$CLAUDE_PROJECT_DIR" || exit 0 -# Generate a stable session ID and persist via CLAUDE_ENV_FILE +# Read session_id from hook input and persist via CLAUDE_ENV_FILE # so the edit tracker and stop hook share the same file path -SESSION_ID="$(date +%s)-$$" -if [[ -n "$CLAUDE_ENV_FILE" ]]; then +INPUT=$(cat) +SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty') +if [[ -n "$SESSION_ID" ]] && [[ -n "$CLAUDE_ENV_FILE" ]]; then echo "export CLAUDE_HOOK_SESSION_ID='$SESSION_ID'" >> "$CLAUDE_ENV_FILE" fi diff --git a/.claude/settings.json b/.claude/settings.json index af23312..6111672 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -19,8 +19,20 @@ "Bash(git pull:*)", "Bash(git cherry-pick:*)", "Bash(git reset:*)", - "Bash(gh pr:*)", - "Bash(gh api:*)" + "Bash(gh pr view:*)", + "Bash(gh pr list:*)", + "Bash(gh pr diff:*)", + "Bash(gh pr checks:*)", + "Bash(gh pr status:*)", + "Bash(gh run view:*)", + "Bash(gh run list:*)", + "Bash(gh run watch:*)", + "Bash(gh issue view:*)", + "Bash(gh issue list:*)", + "Bash(gh release view:*)", + "Bash(gh release list:*)", + "Bash(gh repo view:*)", + "Bash(gh search:*)" ], "deny": [ "Read(./.env*)"