fix(hooks): keep the sh fallback at LF on checkout so it runs on Windows - #163
Open
Matthew-Selvam wants to merge 2 commits into
Open
fix(hooks): keep the sh fallback at LF on checkout so it runs on Windows#163Matthew-Selvam wants to merge 2 commits into
Matthew-Selvam wants to merge 2 commits into
Conversation
`hooks/always-on.sh` ships inside the plugin and is the fallback for
environments without Node. The repo carries no .gitattributes, so a Windows
checkout with the default `core.autocrlf=true` rewrites it to CRLF and /bin/sh
dies on every line -- the carriage return becomes part of the token, so it is
read as a command:
hooks/always-on.sh: line 8: \r: command not found
hooks/always-on.sh: line 13: exit: 0\r: numeric argument required
rc=255
No banner, no ruleset, and the runtime='sh' subtests in
tests/test_always_on_hooks.py fail on that checkout while the node and
PowerShell ones pass. Reproduced by cloning the repo with core.autocrlf=true
and re-checking out: 3 of 7 tests in that file failed, and the hook printed
nothing. The Node and PowerShell hooks tolerate CRLF; the shell one cannot.
Pin POSIX shell scripts to LF in the checkout. Scoped to `*.sh` deliberately:
that is the only case demonstrated, and committing a broader text/eol policy
would rewrite unrelated files on someone else's Windows checkout.
Matthew-Selvam
force-pushed
the
fix/crlf-shell-hook
branch
from
September 10, 2026 09:14
4f35202 to
e3f9205
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With
core.autocrlf=true, Git checks outhooks/always-on.shwith CRLF line endings. Executing that copy with a POSIX shell fails to emit the rules and produces errors. Adding*.sh text eol=lfpreserves LF on checkout and restores correct opt-in behavior.This protects the shell script when invoked directly or by an integration configured to use it. The current
hooks/hooks.jsonlauncher invokes Node; this PR does not add automatic fallback when Node is unavailable. Failure exit codes vary by shell, so no universal code is claimed.Scope and compatibility
Only
.gitattributeschanges: one explanatory comment and one attribute. No shell logic, skill rules, manifests, tests, or dependencies change. The attribute applies to tracked*.shfiles; it does not impose a repository-wide line-ending policy.Fresh checkouts receive LF shell scripts. For an existing CRLF installation, reinstall into a fresh directory, preserving any local customizations first. This change does not repair files converted to CRLF outside Git's checkout process.
Authorship and provenance
Original contributor: Matthew-Selvam. Hermes Agent (deepseek-v4.1-flash) identified the issue, wrote the attribute, and reported reproducing it with
core.autocrlf=trueon macOS. The contributor reported reviewing the diff and running those checks.The repository owner's Codex maintainer agent independently tested the PR and current main on Linux, shortened the comment, and corrected this description. The original contributor's commit is preserved; the owner reviews and merges manually.
Verification
Maintainer checks used isolated Git clones with
core.autocrlf=trueandfalse, testing both main and the PR:shand Bash emitted errors and no rules, with the flag present or absent. Node continued to work. Exit codes differed between shells.sh, Bash, and Node emitted the complete skill when enabled and were silent without the opt-in flag.python3 -m unittest discover -s tests -p test_always_on_hooks.py -v— failed on CRLF main; passed on LF main and both PR checkouts.6f1f982d0a47c65899af3c5a7450b7098bc65325in the CRLF fixture and rechecked out the shell script: normalized output was identical acrosssh, Bash, and Node.git ls-files --eolconfirmed only the shell script's working-tree line endings changed.python3 -m unittest discover -s tests -v— all 51 tests passed on that current-main-plus-fix fixture. This count refers to the integration fixture, not the older PR base.git check-attr text eol -- hooks/always-on.sh—text: set,eol: lfafter the comment amendment.git diff --check— passed after the amendment. Only comments changed after runtime verification; the tested attribute is unchanged.Limitations: maintainer runtime checks ran on Linux with Windows-style Git checkout settings, not native Windows. PowerShell was not tested by the maintainer. No model calls or behavior evaluations were needed for this checkout-only change.
Safety and side effects
Testing used temporary clones and temporary opt-in configuration, without modifying user Git settings or accessing provider credentials. The change controls Git checkout line endings for shell files and adds no runtime network access or cost.
Labels:
Target:Integrations,Author:Hybrid,bug.