fix: isolate hooks as CommonJS so they survive ESM parent package.json#174
Merged
JuliusBrussee merged 1 commit intoJuliusBrussee:mainfrom Apr 15, 2026
Conversation
When ~/.claude/package.json (or any ancestor) contains "type": "module", Node treats every .js file under that tree as an ES module. The caveman hooks use require() and crash with: ReferenceError: require is not defined in ES module scope surfaced as: SessionStart:clear hook error / UserPromptSubmit hook error Failed with non-blocking status code: .../caveman-activate.js:9 This pins the hooks directory to CommonJS via a local package.json, so module resolution no longer depends on whatever the user's ~/.claude directory declares. Also wires the new file into install/uninstall scripts so standalone installs (curl | bash / Invoke-WebRequest) copy it into ~/.claude/hooks/ alongside the JS files. Addresses the ESM sub-case flagged in JuliusBrussee#167 (comment by mrx-arafat). Does not fix the Windows path-with-spaces expansion issues in JuliusBrussee#167/JuliusBrussee#78/JuliusBrussee#72 which have a separate root cause in plugin.json ${CLAUDE_PLUGIN_ROOT} quoting.
Closed
This was referenced Apr 15, 2026
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.
What
Adds
hooks/package.jsonwith{ "type": "commonjs" }so the caveman hooks resolve as CJS regardless of what the user's~/.claude/package.jsondeclares. Also registers the new file ininstall.{sh,ps1}anduninstall.{sh,ps1}so standalone installs (curl | bash/ PowerShell) copy it into~/.claude/hooks/.Why
When
~/.claude/package.json(or any ancestor) contains"type": "module", Node treats every.jsfile under that tree as an ES module. The caveman hooks are CommonJS (require('fs')), so they crash immediately:surfaced to the user as:
Repros on any user who has
{ "type": "module" }in~/.claude/package.jsonβ which several Claude Code plugins/skills set up. On my machine this stopped both hooks from firing (flag file not written, ruleset never injected, statusline badge missing).The ESM sub-case is flagged in @mrx-arafat's comment on #167 β recommending exactly this workaround but applied by the user, not shipped by the plugin. Shipping it here means the fix survives plugin updates and reaches every install without user action.
How the fix works
Node's module-type resolution walks up looking for the nearest
package.json. By dropping one intohooks/itself, we pin the directory to CJS regardless of any ancestor settings. Zero code changes to the hooks themselves.Resolution order:
~/.claude/package.jsonβ"type": "module"β.jstreated as ESM βrequireundefined β crash.hooks/package.json(nearer ancestor) β"type": "commonjs"β.jstreated as CJS β hook runs.Scope note
This does not fix the Windows
${CLAUDE_PLUGIN_ROOT}path-expansion issues with spaces/umlauts in #167 / #78 / #72 β those have a separate root cause (unquoted variable inplugin.json) and need their own patch.Verification
Simulated ESM-parent environment:
Without the fix both commands fail with
ReferenceError: require is not defined in ES module scope.Files changed
hooks/package.json(new) β{ "type": "commonjs" }hooks/install.shβ addpackage.jsontoHOOK_FILEShooks/install.ps1β addpackage.jsonto$HookFileshooks/uninstall.shβ addpackage.jsontoHOOK_FILEShooks/uninstall.ps1β addpackage.jsonto$HookFiles