Skip to content

fix(lefthook): run the pre-commit on Windows - #998

Merged
blafourcade merged 4 commits into
nextfrom
fix/lefthook-windows
Oct 12, 2026
Merged

blafourcade merged 4 commits into
nextfrom
fix/lefthook-windows

Conversation

@blafourcade

@blafourcade blafourcade commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

🎯 What & why

On Windows (Git Bash), every pre-commit job containing a double quote failed with -c: line 3: syntax error: unexpected end of file (#948). Contributors had to commit with lefthook disabled (#987, #988).

🛠️ How it works

Cause, reproduced in Windows CI. Lefthook 2.1.14 on Windows runs each job as "sh.exe" -c "<script>" and escapes nothing (internal/run/controller/exec/exec_windows.go; upstream evilmartians/lefthook#1167, no fix through v2.2.1).

  • A " closes the argument, and a space after it cuts the script in two. The node in node: -c: line 3 is the word after echo "❌.
  • Probes in the reproduction commit showed that a multiline run with no quote passes, and so does '. Line breaks were not the cause.

Fix:

Two checks that also failed on Windows, found once the shell worked:

  • check-skill-argument-hints flagged 58 skills, because the Windows checkout uses CRLF. It now normalises line endings, and a CRLF test was red first.
  • sync-readme-counts read D:\D:\…\README.md, and the hook swallowed the error. It now uses fileURLToPath.

CI: the cli / Windows job runs a commit's hooks, pre-commit then prepare-commit-msg. The three cli-* jobs are left out because they need cli/'s dependencies; Biome on Windows is tracked in #881. The step fails on any failing hook.

🧪 How to verify

  • cli / Windows on this head: 17 hooks ✔️, no syntax error, no ENOENT. The new tests pass on Windows: 593 pass, 0 fail.
  • node --test scripts/__tests__/lefthook-runs-hold-no-double-quote.test.js: putting a " back into one run makes that test alone fail.
  • On a real Windows machine, with the hooks on: git commit on a change under plugins/*/skills/.

⚠️ Heads-up

🔗 Linked issue

Closes #948

✅ I certify

  • I DO CERTIFY I READ EACH LINE OF THE PULL REQUEST BECAUSE I AM A SOFTWARE ENGINEER, NOT A AI PUPPY.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VE16AxC1V9wAMGmGgefe4z

blafourcade and others added 2 commits October 11, 2026 22:08
Lefthook on Windows runs each job through a command line it builds by hand,
`"sh" -c "<script>"`, with nothing escaped (internal/run/controller/exec/
exec_windows.go in 2.1.14). Every job that fails in #948 holds both a line
break and a double quote, so the report cannot tell which one breaks it.

The Windows job now probes the three shapes on their own, a multiline run with
no quote, a one-line run with a double quote and one with a single quote, and
reports each exit code without failing. It then runs this repository's own
pre-commit over every file, leaving out the three jobs that need cli/'s
dependencies, and fails only on a shell syntax error, so a Windows bug in a
check itself (#881) stays that check's.

Refs #948

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VE16AxC1V9wAMGmGgefe4z
The Windows CI job reproduced #948: 17 pre-commit jobs failed with
`node: -c: line 3: syntax error: unexpected end of file`. Lefthook 2.1.14 on
Windows builds `"sh.exe" -c "<script>"` and escapes nothing, so a double quote
in a run closes the argument, and a space after it cuts the script in two: the
`node` in that error is the word after `echo "❌`. The probes ruled out line
breaks, since a multiline run with no quote passed, as did a single quote.

No run in lefthook.yml holds a double quote any more. Messages use single
quotes, variables that never hold a space lose theirs, and the two jobs that
need nested quotes moved into scripts the run line only names:
`scripts/summarize-plugin-catalogs.sh`, verbatim, and
`scripts/session-trailer-delegate.sh`. The trailer's run line still names
`aidd-session-trailer.sh`, which is how `aidd telemetry` finds the job.

A guard fails on any double quote in a run, red on 16 jobs before this change.
The Windows job keeps its pre-commit step, drops the probes, and also runs
prepare-commit-msg.

Refs #948

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VE16AxC1V9wAMGmGgefe4z
With the shell fixed, the Windows CI log showed two checks of their own failing
on every commit, hidden by a step that only looked for a syntax error.
`check-skill-argument-hints` reported 58 skills without an argument-hint: the
Windows checkout ends lines with CRLF, so no frontmatter starts with `---\n`.
`sync-readme-counts` read `D:\D:\a\...\README.md`, a root taken from a URL's
pathname, and the hook dropped its exit code.

The hint check normalises CRLF before parsing, and the counts script resolves
its root with `fileURLToPath`. A CRLF skill test was red before the change; the
counts test runs the script where the suite runs, Windows CI included.

The Windows step is now strict, failing on any hook that fails as well as on a
syntax error. The no-double-quote guard also fails when it scans no run, and
lefthook.yml says why the trailer's run line names its delegate.

Refs #948

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VE16AxC1V9wAMGmGgefe4z
Drop the comments that restated their code or their test's name. Three stay, one
line each: why a run holds no double quote, which name `aidd telemetry` finds
the trailer job by, and what the Windows hooks step runs.

Refs #948

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VE16AxC1V9wAMGmGgefe4z
@blafourcade
blafourcade marked this pull request as ready for review October 12, 2026 03:45
@blafourcade
blafourcade requested a review from a team as a code owner October 12, 2026 03:45
@blafourcade
blafourcade merged commit c9a4aa6 into next Oct 12, 2026
39 checks passed
blafourcade added a commit that referenced this pull request Oct 12, 2026
Conflicts resolved:
- lefthook.yml: next's one-line catalog job (#998) kept; the telemetry
  prompts-doc job and the prepare-commit-msg trailer job stay removed,
  with the trailer delegate script next added for them.
- cli/tests/e2e/helpers.ts: both sides' imports.
- README.md and architecture-rules.test.js: counts measured on the
  merged tree, 51 skills and 48 skills with actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant