Bash removes a backslash before a newline, but not one before a carriage return. Removing backslash-CRLF joined two lines of the message, and their text was then read as the subject.
In double quotes, Bash drops the backslash before $, `, ", \ and a newline, so git receives fix: say "hello" for -m "fix: say \"hello\"". The check kept the backslashes, so an escaped backslash before a newline counted twice. These escapes are now decoded, and a backslash before any other character stays. The test that pinned the escaped quotes now expects the message git records.
Bash removes a backslash-newline inside double quotes, so git never sees it, but the check kept both characters. A message that starts with one had a subject of just the backslash and got a false format warning. Line continuations are now dropped from a double-quoted message before its subject is read. An escaped backslash before a newline stays, and a here-document body is read as written.
The quoted-message pattern took an escape as a backslash and one character other than a newline. A here-document body with a line ending in a backslash, such as a Windows path, therefore matched no -m at all, and the message was not checked. A backslash may now escape a newline too.
The closing pattern accepted spaces and tabs around the delimiter for both forms, so a body line such as ' EOF' ended the message early. Bash ends <<EOF only at a line that is exactly EOF, and <<-EOF also after leading tabs. The body is now read line by line from the command, and the existing message pattern is back to what it was on main.
The commit-message checks read the whole -m value. A multi-line message was measured against the 72-character subject limit as a whole, and a body ending in a period got the trailing-period warning. A message written as -m "$(cat <<'EOF' ... EOF)", the form Claude Code uses, was checked as the literal $(cat <<'EOF' text, so every such commit got the format and length warnings. The here-document body is now read as the message, and the format, length, capitalization and period checks apply to its subject line, the first line git keeps.
pre-bash-commit-quality spawned Windows .cmd/.bat linters unquoted, so a spaced path failed, and passed --format compact, which ESLint 9 removed (#3075). Batch executables now run through cmd.exe with each argument carried in an env token and quoted, with quote, NUL, CR and LF rejected before spawn; non-batch Windows and POSIX paths keep direct argv spawn with shell false. ESLint uses its bundled default formatter, present on 8, 9 and 10. Regression tests cover the batch, non-batch and POSIX branches and the formatter change. Independent exact-head review passed with no P0/P1; CI 44/44 at the head.
* fix(hooks,lib): fix hook detection and parsing edge cases
- auto-tmux-dev: dev\b -> dev(?![\w-]) so one-shot dev-build/dev-docs scripts
are not detached into tmux; align command shapes (yarn run dev, bun dev) with
pre-bash-dev-server-block.js DEV_PATTERN.
- pre-bash-commit-quality: skip obvious non-secret placeholders (env refs,
${...}, <...>, whitelisted tokens) in the api-key rule without suppressing
real high-entropy secrets; make -m message extraction quote- and
escaped-quote-aware so `-m "fix: \"x\""` / apostrophes are not truncated.
- pre-compact: annotate the CURRENT worktree's session (match **Worktree:** /
legacy **Project:**) instead of the newest *-session.tmp across all projects,
layered onto the LLM-summary flow from #2388; a present-but-blank Worktree
header is treated as non-legacy (no foreign project fallback).
- shell-substitution: stop double-appending a trailing backslash in an
unterminated backtick span.
- utils readStdinJson: on overflow, settle and resolve {} immediately (clear
timer + listeners) instead of waiting for end/timeout and parsing a partial
prefix; surface the overflow on stderr.
Regression tests added/extended (new tests/hooks/pre-compact.test.js).
Addresses review feedback on #2405. The earlier block-no-verify change was
dropped: its message-value skip on merge/cherry-pick/am/rebase would let
`git rebase -m --no-verify` bypass the hook (rebase's -m is the boolean
--merge), a false-negative worse than the contrived false-positive it fixed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(ci): align hook fixtures and drain oversized stdin
---------
Co-authored-by: djpjronline-netizen <276112803+djpjronline-netizen@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
The existing OpenAI pattern sk-[a-zA-Z0-9]{20,} never matches real
Anthropic keys: their sk-ant-api03-... format contains hyphens, which
break the character class before reaching the 20-char threshold. Keys
from the fastest-growing Claude Code user base slipped through the scan.
Adds a dedicated sk-ant-[a-zA-Z0-9_-]{20,} pattern (checked before the
OpenAI one) and extends the staged-secrets test with a realistic
Anthropic key fixture.