fix(hooks): make Windows hooks work + self-heal stale settings entries#1
Merged
Merged
Conversation
Claude Code runs hook commands through bash on every platform (Git Bash on Windows), but the commandWindows fields were PowerShell, so on Windows bash failed to parse them and the non-zero exit blocked every prompt via the UserPromptSubmit hook. - hooks/hooks.json: drop the PowerShell commandWindows variants; the bash command field already works everywhere. - bin/fableit.js: hookEntries() emits only the bash command with forward slashes; installClaude() reconciles instead of appends so broken installs self-heal on the next run; isOurs matches either slash style. - tests/hooks.test.js + tests/installer.test.js: bash-syntax validation of every hook command, known-bad fixture, reconcile semantics. - .github/workflows/test.yml: run npm test on ubuntu-latest and windows-latest.
…hell On Windows CI, npm runs scripts through cmd.exe, which doesn't expand tests/*.test.js, so node --test got the literal string and failed. Quote the pattern and let node's own --test glob expansion (v21+) resolve it, and pin CI to node 22 so both platforms behave the same.
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.
fix(hooks): make Windows hooks work, and self-heal stale settings entries
What was happening
On Windows, every prompt was blocked with:
Claude Code runs hook commands through bash on every platform (Git Bash on
Windows), but the
commandWindowsfields were written in PowerShell(
if (...) { },Get-Command -ErrorAction). Bash can't parse that, and becausethose variants had no trailing
; exit 0, the non-zero exit caused theUserPromptSubmithook to block the prompt on every submission.This bit users through two paths:
hooks/hooks.jsondirectly.npx fableitinstall derives a hooks block into~/.claude/settings.jsonvia
bin/fableit.js, and on Windows it copied the PowerShellcommandWindowsvalue in verbatim. This is the copy that actually fired for affected users,
which is why fixing only
hooks.jsondidn't unblock an existing install.Changes
hooks/hooks.json— remove the PowerShellcommandWindowsvariants. Theplain
commandfield is already correct and cross-platform: forward slasheswork with
nodeon Windows, and; exit 0guarantees a hook never blocks aprompt. No behaviour change on macOS/Linux.
bin/fableit.jshookEntries()no longer emits the PowerShell variant intosettings.json.It substitutes the plugin-root placeholder and normalises to forward slashes,
so the written command is valid bash on Windows too.
installClaude()now reconciles instead of appends. Re-running installdrops any previous fableit entry (including a stale or broken PowerShell one
from an older version) and re-adds the current correct one. Users self-heal on
the next update instead of hand-editing
settings.json. It's idempotent andleaves the user's own unrelated hooks untouched.
isOursnow compares with separators normalised, so an entry written witheither slash style is recognised (the old backslash-only marker would miss a
bash command). CLI dispatch is guarded with
require.mainand the helpers areexported so they can be unit-tested.
Tests + CI (so this can't regress)
Run under the existing
npm test(node --test), on ubuntu-latest andwindows-latest in CI, since the bug was Windows-specific.
tests/hooks.test.js:hooks.jsonis valid JSON with the right shape; everyshell-bearing field (
commandand any legacycommandWindows) parses underbash -n(the exact check that catches PowerShell syntax); referenced scriptsexist; the hook scripts always exit 0 on real, ordinary, empty, and garbage
stdin. A known-bad fixture is asserted to be rejected, so the guard can't
silently pass everything.
tests/installer.test.js: reconcile replaces a stale PowerShell entry with avalid bash one, preserves the user's own hooks, is idempotent, and every
command the installer emits is valid bash.
Verification
Swapping the pre-fix
hooks.jsonback in fails the suite with a messagepointing straight at the offending
commandWindowsfield.Note for existing (already-broken) installs
With reconcile in place, affected users are fixed automatically the next time
npx fableitruns (e.g. on update). No manualsettings.jsonediting needed.