Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .lefthook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# .lefthook.yml
# Fast pre-commit hooks that check all changed files (staged + unstaged + untracked)
# Install with: bundle exec lefthook install

pre-commit:
parallel: true
commands:
autofix:
run: bin/lefthook/ruby-autofix all-changed

rubocop:
run: bin/lefthook/ruby-lint all-changed

prettier:
run: bin/lefthook/prettier-format all-changed

trailing-newlines:
run: bin/lefthook/check-trailing-newlines all-changed

Comment on lines +5 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid running fixers and linters in parallel; enforce deterministic sequence.

parallel: true can race autofix/prettier with rubocop, causing flaky failures and missed restaging.

-pre-commit:
-  parallel: true
+pre-commit:
+  parallel: false
   commands:
     autofix:
       run: bin/lefthook/ruby-autofix all-changed

     rubocop:
       run: bin/lefthook/ruby-lint all-changed

     prettier:
       run: bin/lefthook/prettier-format all-changed

     trailing-newlines:
       run: bin/lefthook/check-trailing-newlines all-changed
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pre-commit:
parallel: true
commands:
autofix:
run: bin/lefthook/ruby-autofix all-changed
rubocop:
run: bin/lefthook/ruby-lint all-changed
prettier:
run: bin/lefthook/prettier-format all-changed
trailing-newlines:
run: bin/lefthook/check-trailing-newlines all-changed
pre-commit:
parallel: false
commands:
autofix:
run: bin/lefthook/ruby-autofix all-changed
rubocop:
run: bin/lefthook/ruby-lint all-changed
prettier:
run: bin/lefthook/prettier-format all-changed
trailing-newlines:
run: bin/lefthook/check-trailing-newlines all-changed
🤖 Prompt for AI Agents
In .lefthook.yml around lines 5 to 19, the pre-commit hook is configured with
parallel: true which allows autofix/prettier to run concurrently with rubocop
causing race conditions and missed restaging; change the configuration to run
hooks sequentially (remove or set parallel to false) and reorder the commands so
auto-fixers (autofix) run first, then formatters (prettier), and finally linters
(rubocop, trailing-newlines) to ensure fixes are applied and files are restaged
before linting.

pre-push:
commands:
branch-lint:
run: bin/lefthook/ruby-lint branch
6 changes: 6 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

These requirements are non-negotiable. CI will fail if not followed.

**🚀 AUTOMATIC: Git hooks are installed automatically during setup**

Git hooks will automatically run linting on **all changed files (staged + unstaged + untracked)** before each commit - making it fast while preventing CI failures!

**Note:** Git hooks are for React on Rails gem developers only, not for users who install the gem.

## Development Commands

### Essential Commands
Expand Down
18 changes: 12 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
## Prerequisites

- [Yalc](https://github.com/whitecolor/yalc) must be installed globally for most local development.
- **Git hooks setup** (automatic during normal setup):

Git hooks are installed automatically when you run the standard setup commands. They will run automatic linting on **all changed files (staged + unstaged + untracked)** - making commits fast while preventing CI failures.

- After updating code via Git, to prepare all examples:

```sh
Expand Down Expand Up @@ -457,7 +461,9 @@ This approach:

## Pre-Commit Requirements

**CRITICAL**: Before committing any changes, always run the following commands to ensure code quality:
**AUTOMATED**: If you've set up Lefthook (see Prerequisites), linting runs automatically on changed files before each commit.

**MANUAL OPTION**: If you need to run linting manually:

```bash
# Navigate to the main react_on_rails directory
Expand All @@ -476,14 +482,14 @@ rake lint:rubocop
rake lint
```

**Automated checks:**
**Git hooks automatically run:**

- Format all JavaScript/TypeScript files with Prettier
- Format JavaScript/TypeScript files with Prettier (on changed files only)
- Check and fix linting issues with ESLint
- Check and fix Ruby style issues with RuboCop
- Ensure all tests pass before pushing
- Check and fix Ruby style issues with RuboCop (on all changed files)
- Ensure trailing newlines on all files

**Tip**: Set up your IDE to run these automatically on save to catch issues early.
**Setup**: Automatic during normal development setup

Comment on lines +485 to 493
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Docs/impl mismatch: ESLint is not part of the configured hooks.

Either add an ESLint hook or update docs to remove ESLint from “automatically run”.

-**Git hooks automatically run:**
-
-- Format JavaScript/TypeScript files with Prettier (on changed files only)
-- Check and fix linting issues with ESLint
-- Check and fix Ruby style issues with RuboCop (on all changed files)
-- Ensure trailing newlines on all files
+**Git hooks automatically run:**
+
+- Format JavaScript/TypeScript files with Prettier (on changed files only)
+- Check Ruby style with RuboCop (on changed files)
+- Ensure trailing newlines on all files

If you do want ESLint here, I can add an eslint lefthook command and a small wrapper script.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
**Git hooks automatically run:**
- Format all JavaScript/TypeScript files with Prettier
- Format JavaScript/TypeScript files with Prettier (on changed files only)
- Check and fix linting issues with ESLint
- Check and fix Ruby style issues with RuboCop
- Ensure all tests pass before pushing
- Check and fix Ruby style issues with RuboCop (on all changed files)
- Ensure trailing newlines on all files
**Tip**: Set up your IDE to run these automatically on save to catch issues early.
**Setup**: Automatic during normal development setup
**Git hooks automatically run:**
- Format JavaScript/TypeScript files with Prettier (on changed files only)
- Check Ruby style with RuboCop (on changed files)
- Ensure trailing newlines on all files
**Setup**: Automatic during normal development setup
🤖 Prompt for AI Agents
In CONTRIBUTING.md around lines 485 to 493, the docs claim ESLint is
automatically run by git hooks but the repository hook configuration does not
include ESLint; update documentation or add the hook. Either remove the ESLint
bullet from the listed "Git hooks automatically run" section to match current
hook configuration, or add an ESLint lefthook entry and the accompanying wrapper
script to run eslint --fix (and update setup notes) so the docs and hooks are
consistent.

## 🤖 Best Practices for AI Coding Agents

Expand Down
1 change: 1 addition & 0 deletions Gemfile.development_dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ group :development, :test do
gem "rubocop-rspec", "~>2.26", require: false
gem "scss_lint", require: false
gem "spring", "~> 4.0"
gem "lefthook", require: false
end

group :test do
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ GEM
launchy (3.0.1)
addressable (~> 2.8)
childprocess (~> 5.0)
lefthook (1.13.1)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
Expand Down Expand Up @@ -412,6 +413,7 @@ DEPENDENCIES
jbuilder
jquery-rails
launchy
lefthook
listen
package_json
pry
Expand Down
38 changes: 38 additions & 0 deletions bin/lefthook/check-trailing-newlines
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Check for trailing newlines on all changed files
set -euo pipefail

CONTEXT="${1:-staged}"
files="$(bin/lefthook/get-changed-files "$CONTEXT" '.*')"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid false positives on binaries; fix quoting and user hint.

Current loop may flag images/binaries and breaks on spaces. Filter to text when possible, use arrays, and correct the quick-fix message.

-CONTEXT="${1:-staged}"
-files="$(bin/lefthook/get-changed-files "$CONTEXT" '.*')"
+CONTEXT="${1:-staged}"
+mapfile -t files < <(bin/lefthook/get-changed-files "$CONTEXT" '.*')
@@
-if [ -z "$files" ]; then
+if [ "${#files[@]}" -eq 0 ]; then
   echo "✅ No files to check for trailing newlines"
   exit 0
 fi
@@
-failed_files=""
-for file in $files; do
+failed_files=()
+for file in "${files[@]}"; do
   if [ -f "$file" ] && [ -s "$file" ]; then
+    # Skip non-text files if `file` is available
+    if command -v file >/dev/null 2>&1; then
+      if ! file -bi "$file" | grep -qi '^text/'; then
+        continue
+      fi
+    fi
     if ! tail -c 1 "$file" | grep -q '^$'; then
       echo "❌ Missing trailing newline: $file"
-      failed_files="$failed_files $file"
+      failed_files+=("$file")
     fi
   fi
 done
@@
-if [ -n "$failed_files" ]; then
+if [ "${#failed_files[@]}" -gt 0 ]; then
   echo ""
   echo "❌ Trailing newline check failed!"
-  echo "💡 Add trailing newlines to:$failed_files"
-  echo "🔧 Quick fix: for file in$failed_files; do echo >> \"\$file\"; done"
+  echo "💡 Add trailing newlines to: ${failed_files[*]}"
+  echo "🔧 Quick fix: for file in ${failed_files[*]}; do printf '\n' >> \"\$file\"; done"
   echo "🚫 Skip hook: git commit --no-verify"
   exit 1
 fi

Also applies to: 19-27, 29-36

🤖 Prompt for AI Agents
In bin/lefthook/check-trailing-newlines around line 6 (and similarly for 19-27
and 29-36), the script uses an unquoted command substitution and a
word-splitting loop which breaks on filenames with spaces and can falsely flag
binaries; replace the string-splitting approach with a safe array read (e.g.,
use mapfile -t files < <(bin/lefthook/get-changed-files "$CONTEXT" '.*')) and
loop over "${files[@]}", and inside the loop detect text files before checking
trailing newlines (use file --mime-type or file --brief --mime-type and skip
entries whose mime type is not text or starts with "text/"); also update the
quick-fix hint message to reference the correct fixer script (e.g.,
bin/lefthook/fix-trailing-newlines) and ensure all filename usages are quoted to
preserve spaces.


if [ -z "$files" ]; then
echo "✅ No files to check for trailing newlines"
exit 0
fi

if [ "$CONTEXT" = "all-changed" ]; then
echo "🔍 Checking trailing newlines on all changed files..."
else
echo "🔍 Checking trailing newlines on $CONTEXT files..."
fi

failed_files=""
for file in $files; do
if [ -f "$file" ] && [ -s "$file" ]; then
if ! tail -c 1 "$file" | grep -q '^$'; then
echo "❌ Missing trailing newline: $file"
failed_files="$failed_files $file"
fi
fi
done

if [ -n "$failed_files" ]; then
echo ""
echo "❌ Trailing newline check failed!"
echo "💡 Add trailing newlines to:$failed_files"
echo "🔧 Quick fix: for file in$failed_files; do echo >> \"\$file\"; done"
echo "🚫 Skip hook: git commit --no-verify"
exit 1
fi

echo "✅ All files have proper trailing newlines"
26 changes: 26 additions & 0 deletions bin/lefthook/get-changed-files
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Get changed files based on context (staged, branch, or all)
set -euo pipefail

CONTEXT="${1:-staged}"
PATTERN="${2:-.*}"

case "$CONTEXT" in
staged)
git diff --cached --name-only --diff-filter=ACM | grep -E "$PATTERN" || true
;;
all-changed)
# Get all changed files (staged + unstaged + untracked) vs working directory
(git diff --cached --name-only --diff-filter=ACM; git diff --name-only --diff-filter=ACM; git ls-files --others --exclude-standard) | sort -u | grep -E "$PATTERN" || true
;;
branch)
# Find base branch (prefer main over master)
base="origin/main"
git rev-parse --verify --quiet "$base" >/dev/null || base="origin/master"
git diff --name-only --diff-filter=ACM "$base"...HEAD | grep -E "$PATTERN" || true
;;
Comment on lines +17 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Harden base branch resolution for branch diffs.

Handles repos without origin/main or origin/master; prefers origin’s default HEAD, then sensible fallbacks.

-    # Find base branch (prefer main over master)
-    base="origin/main"
-    git rev-parse --verify --quiet "$base" >/dev/null || base="origin/master"
-    git diff --name-only --diff-filter=ACM "$base"...HEAD | grep -E "$PATTERN" || true
+    # Resolve base branch (prefer remote default, then origin/main, origin/master, main, master)
+    base=""
+    if git rev-parse --verify --quiet refs/remotes/origin/HEAD >/dev/null; then
+      base="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD)"
+    fi
+    for candidate in "$base" origin/main origin/master main master; do
+      if [ -n "$candidate" ] && git rev-parse --verify --quiet "$candidate" >/dev/null; then
+        base="$candidate"
+        break
+      fi
+    done
+    if [ -z "$base" ]; then
+      echo "⚠️ Could not resolve base branch; defaulting to HEAD~1" >&2
+      base="HEAD~1"
+    fi
+    git diff --name-only --diff-filter=ACMR "$base"...HEAD | grep -E "$PATTERN" || true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Find base branch (prefer main over master)
base="origin/main"
git rev-parse --verify --quiet "$base" >/dev/null || base="origin/master"
git diff --name-only --diff-filter=ACM "$base"...HEAD | grep -E "$PATTERN" || true
;;
# Resolve base branch (prefer remote default, then origin/main, origin/master, main, master)
base=""
if git rev-parse --verify --quiet refs/remotes/origin/HEAD >/dev/null; then
base="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD)"
fi
for candidate in "$base" origin/main origin/master main master; do
if [ -n "$candidate" ] && git rev-parse --verify --quiet "$candidate" >/dev/null; then
base="$candidate"
break
fi
done
if [ -z "$base" ]; then
echo "⚠️ Could not resolve base branch; defaulting to HEAD~1" >&2
base="HEAD~1"
fi
git diff --name-only --diff-filter=ACMR "$base"...HEAD | grep -E "$PATTERN" || true
;;
🤖 Prompt for AI Agents
In bin/lefthook/get-changed-files around lines 17 to 21, the current base branch
resolution only tries origin/main then origin/master and fails in repos without
those refs; update the logic to probe for origin/HEAD first, then origin/main,
then origin/master, then local main, then local master, using git rev-parse
--verify --quiet for each check and set the first valid ref as base; if none
exist, fall back to an empty result (no diff) or exit gracefully to avoid
errors. Ensure the script uses the chosen base in the git diff command exactly
as before.

*)
echo "Usage: $0 {staged|all-changed|branch} [pattern]" >&2
exit 1
;;
esac
26 changes: 26 additions & 0 deletions bin/lefthook/prettier-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Format JS/TS/JSON/MD files with Prettier
set -euo pipefail

CONTEXT="${1:-staged}"
files="$(bin/lefthook/get-changed-files "$CONTEXT" '\.(js|jsx|ts|tsx|json|md|yml|yaml)$')"
Comment on lines +5 to +6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Quote-safe file handling: avoid word-splitting; use arrays and pass args safely.

Files with spaces/newlines will break current usage. Also restaging via echo|xargs is fragile. Refactor to arrays and quote expansions.

-# Format JS/TS/JSON/MD files with Prettier
+# Format JS/TS/JSON/MD/YAML files with Prettier
@@
-CONTEXT="${1:-staged}"
-files="$(bin/lefthook/get-changed-files "$CONTEXT" '\.(js|jsx|ts|tsx|json|md|yml|yaml)$')"
+CONTEXT="${1:-staged}"
+mapfile -t files < <(bin/lefthook/get-changed-files "$CONTEXT" '\.(js|jsx|ts|tsx|json|md|yml|yaml)$')
@@
-if [ -z "$files" ]; then
+if [ "${#files[@]}" -eq 0 ]; then
   echo "✅ No files to format with Prettier"
   exit 0
 fi
@@
-printf "  %s\n" $files
+printf "  %s\n" "${files[@]}"
@@
-yarn run prettier --write $files
+yarn run prettier --write -- "${files[@]}"
@@
-# Re-stage files if running on staged or all-changed context
-if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
-  echo $files | xargs -r git add
-  echo "✅ Re-staged formatted files"
-fi
+# Re-stage files if running on staged or all-changed context
+if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
+  git add -- "${files[@]}"
+  echo "✅ Re-staged formatted files"
+fi

Also applies to: 8-11, 18-18, 20-20, 23-26

🤖 Prompt for AI Agents
In bin/lefthook/prettier-format around lines 5-6 (and also apply to 8-11, 18,
20, 23-26), the script word-splits filenames and is unsafe for names with
spaces/newlines; change to capture the output of bin/lefthook/get-changed-files
into a bash array (using mapfile/readarray with a null delimiter or read -r -d
'' loop), avoid unquoted expansions, and pass files as "${files[@]}" to prettier
and git commands; replace echo|xargs restaging with git add -- "${files[@]}" (or
use git -z plumbing) so all arguments are passed safely without word-splitting
or injection.


if [ -z "$files" ]; then
echo "✅ No files to format with Prettier"
exit 0
fi

if [ "$CONTEXT" = "all-changed" ]; then
echo "💅 Prettier on all changed files:"
else
echo "💅 Prettier on $CONTEXT files:"
fi
printf " %s\n" $files

yarn run prettier --write $files

# Re-stage files if running on staged or all-changed context
if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
echo $files | xargs -r git add
echo "✅ Re-staged formatted files"
fi
26 changes: 26 additions & 0 deletions bin/lefthook/ruby-autofix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Auto-fix Ruby files using rake autofix
set -euo pipefail

CONTEXT="${1:-staged}"
files="$(bin/lefthook/get-changed-files "$CONTEXT" '\.(rb|rake|ru)$')"

if [ -z "$files" ]; then
echo "✅ No Ruby files to autofix"
exit 0
fi

if [ "$CONTEXT" = "all-changed" ]; then
echo "🎨 Autofix on all changed Ruby files:"
else
echo "🎨 Autofix on $CONTEXT Ruby files:"
fi
printf " %s\n" $files

bundle exec rake autofix

# Re-stage files if running on staged or all-changed context
if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
echo $files | xargs -r git add
echo "✅ Re-staged formatted files"
fi
Comment on lines +13 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Limit autofix scope to changed files and restage safely.

Running rake autofix touches the whole repo. Prefer RuboCop autocorrect on the targeted set and robust restaging.

-if [ "$CONTEXT" = "all-changed" ]; then
-  echo "🎨 Autofix on all changed Ruby files:"
-else
-  echo "🎨 Autofix on $CONTEXT Ruby files:"
-fi
-printf "  %s\n" $files
-
-bundle exec rake autofix
-
-# Re-stage files if running on staged or all-changed context
-if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
-  echo $files | xargs -r git add
-  echo "✅ Re-staged formatted files"
-fi
+mapfile -t arr < <(printf "%s\n" "$files")
+if [ "$CONTEXT" = "all-changed" ]; then
+  echo "🎨 Autofix on all changed Ruby files:"
+else
+  echo "🎨 Autofix on $CONTEXT Ruby files:"
+fi
+printf "  %s\n" "${arr[@]}"
+
+# RuboCop autocorrect only on the targeted files
+bundle exec rubocop -A --force-exclusion -- "${arr[@]}"
+
+# Re-stage only the targeted files when applicable
+if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
+  git add -- "${arr[@]}"
+  echo "✅ Re-staged formatted files"
+fi

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In bin/lefthook/ruby-autofix around lines 13 to 26, the script runs bundle exec
rake autofix which modifies the entire repo; change it to run RuboCop
autocorrect only on the targeted files and restage them safely: replace the rake
call with a NUL-safe invocation that feeds the selected file list to RuboCop
(e.g. printf '%s\0' "$files" | xargs -0 -r bundle exec rubocop -A --) and
similarly restage using printf '%s\0' "$files" | xargs -0 -r git add -- so
filenames with spaces are handled and only changed files are processed.

27 changes: 27 additions & 0 deletions bin/lefthook/ruby-lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Lint Ruby files with RuboCop
set -euo pipefail

CONTEXT="${1:-staged}"
files="$(bin/lefthook/get-changed-files "$CONTEXT" '\.(rb|rake|ru)$')"

if [ -z "$files" ]; then
echo "✅ No Ruby files to lint"
exit 0
fi

if [ "$CONTEXT" = "all-changed" ]; then
echo "🔍 RuboCop on all changed Ruby files:"
else
echo "🔍 RuboCop on $CONTEXT Ruby files:"
fi
printf " %s\n" $files

if ! bundle exec rubocop --force-exclusion --display-cop-names -- $files; then
echo ""
Comment on lines +13 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle filenames safely and pass args without word-splitting.

Use arrays and quote when invoking RuboCop.

-if [ "$CONTEXT" = "all-changed" ]; then
-  echo "🔍 RuboCop on all changed Ruby files:"
-else
-  echo "🔍 RuboCop on $CONTEXT Ruby files:"
-fi
-printf "  %s\n" $files
-
-if ! bundle exec rubocop --force-exclusion --display-cop-names -- $files; then
+mapfile -t arr < <(printf "%s\n" "$files")
+if [ "$CONTEXT" = "all-changed" ]; then
+  echo "🔍 RuboCop on all changed Ruby files:"
+else
+  echo "🔍 RuboCop on $CONTEXT Ruby files:"
+fi
+printf "  %s\n" "${arr[@]}"
+
+if ! bundle exec rubocop --force-exclusion --display-cop-names -- "${arr[@]}"; then
   echo ""
   echo "❌ RuboCop check failed!"
-  echo "💡 Auto-fix: bundle exec rubocop --auto-correct --force-exclusion -- $files"
+  echo "💡 Auto-fix: bundle exec rubocop --auto-correct --force-exclusion -- ${arr[*]}"
   echo "🚫 Skip hook: git commit --no-verify"
   exit 1
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ "$CONTEXT" = "all-changed" ]; then
echo "🔍 RuboCop on all changed Ruby files:"
else
echo "🔍 RuboCop on $CONTEXT Ruby files:"
fi
printf " %s\n" $files
if ! bundle exec rubocop --force-exclusion --display-cop-names -- $files; then
echo ""
mapfile -t arr < <(printf "%s\n" "$files")
if [ "$CONTEXT" = "all-changed" ]; then
echo "🔍 RuboCop on all changed Ruby files:"
else
echo "🔍 RuboCop on $CONTEXT Ruby files:"
fi
printf " %s\n" "${arr[@]}"
if ! bundle exec rubocop --force-exclusion --display-cop-names -- "${arr[@]}"; then
echo ""
echo "❌ RuboCop check failed!"
echo "💡 Auto-fix: bundle exec rubocop --auto-correct --force-exclusion -- ${arr[*]}"
echo "🚫 Skip hook: git commit --no-verify"
exit 1
fi
🤖 Prompt for AI Agents
In bin/lefthook/ruby-lint around lines 13 to 21, the script currently expands
$files unquoted which causes word-splitting and unsafe handling of filenames
with spaces/special chars; convert the files handling to a bash array (e.g.
populate files_array=(...)) and print them safely with printf '%s\n'
"${files_array[@]}", then invoke RuboCop using the array expansion with quotes
(bundle exec rubocop --force-exclusion --display-cop-names --
"${files_array[@]}") so each filename is passed as a single argument and no
word-splitting occurs.

echo "❌ RuboCop check failed!"
echo "💡 Auto-fix: bundle exec rubocop --auto-correct --force-exclusion -- $files"
echo "🚫 Skip hook: git commit --no-verify"
exit 1
fi
echo "✅ RuboCop checks passed for Ruby files"
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@
"type-check": "yarn run tsc --noEmit --noErrorTruncation",
"release:patch": "node_package/scripts/release patch",
"release:minor": "node_package/scripts/release minor",
"release:major": "node_package/scripts/release major"
"release:major": "node_package/scripts/release major",
"postinstall": "test -f .lefthook.yml && test -d .git && command -v bundle >/dev/null 2>&1 && bundle exec lefthook install || true"
},
Comment on lines +105 to 107
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Harden postinstall repo detection; don’t assume .git is a directory.

Use Git to detect a repo; also guard on git availability.

-    "postinstall": "test -f .lefthook.yml && test -d .git && command -v bundle >/dev/null 2>&1 && bundle exec lefthook install || true"
+    "postinstall": "test -f .lefthook.yml && command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1 && command -v bundle >/dev/null 2>&1 && bundle exec lefthook install || true"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"release:major": "node_package/scripts/release major",
"postinstall": "test -f .lefthook.yml && test -d .git && command -v bundle >/dev/null 2>&1 && bundle exec lefthook install || true"
},
"release:major": "node_package/scripts/release major",
"postinstall": "test -f .lefthook.yml && command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1 && command -v bundle >/dev/null 2>&1 && bundle exec lefthook install || true"
},
🤖 Prompt for AI Agents
In package.json around lines 105 to 107, the postinstall script assumes a
repository by testing for a .git directory; change it to first check that git is
available (command -v git) and then use git rev-parse --is-inside-work-tree to
detect a repo, keeping the existing .lefthook.yml and bundle checks and the
fallback || true; update the script so it only runs bundle exec lefthook install
when .lefthook.yml exists, git is present and reports inside a work tree, and
bundle is available.

"repository": {
"type": "git",
Expand Down
6 changes: 6 additions & 0 deletions script/bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ if [ -f "Gemfile" ]; then
bundle check --path vendor/gems 2>&1 >/dev/null || {
bundle install --path vendor/gems --quiet --without production
}

# Install Git hooks for code quality (development only)
if [ -f ".lefthook.yml" ] && [ -d ".git" ]; then
echo "==> Installing Git hooks for code quality…"
bundle exec lefthook install
fi
Comment on lines +34 to +38
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Make Git repo detection work with worktrees/submodules (don’t rely on .git dir).

.git can be a file (worktrees, submodules). Use git rev-parse instead.

-  if [ -f ".lefthook.yml" ] && [ -d ".git" ]; then
+  if [ -f ".lefthook.yml" ] && git rev-parse --git-dir >/dev/null 2>&1; then
     echo "==> Installing Git hooks for code quality…"
     bundle exec lefthook install
   fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Install Git hooks for code quality (development only)
if [ -f ".lefthook.yml" ] && [ -d ".git" ]; then
echo "==> Installing Git hooks for code quality…"
bundle exec lefthook install
fi
# Install Git hooks for code quality (development only)
if [ -f ".lefthook.yml" ] && git rev-parse --git-dir >/dev/null 2>&1; then
echo "==> Installing Git hooks for code quality…"
bundle exec lefthook install
fi
🤖 Prompt for AI Agents
In script/bootstrap around lines 34 to 38, the current check uses presence of a
.git directory which fails for worktrees/submodules where .git can be a file;
replace the filesystem check with a Git command check (e.g. run git rev-parse
--is-inside-work-tree or git rev-parse --git-dir and test its exit status) so
the condition reliably detects a Git repo across worktrees/submodules, and only
then echo the message and run bundle exec lefthook install; ensure the git
command’s stdout/stderr are redirected to suppress output and preserve the same
behavior when not in a repo.

fi
Loading