Merge pull request #1392 from affaan-m/fix/hook-failed-to-load

fix: document supported Claude hook install path
This commit is contained in:
Affaan Mustafa
2026-04-12 23:39:33 -07:00
committed by GitHub
6 changed files with 126 additions and 3 deletions

View File

@@ -703,12 +703,28 @@ mkdir -p ~/.claude/commands
cp everything-claude-code/commands/*.md ~/.claude/commands/
```
#### Add hooks to settings.json
#### Install hooks
Manual install only: copy the hooks from `hooks/hooks.json` to your `~/.claude/settings.json` if you are not installing ECC as a Claude plugin.
Do not copy the raw repo `hooks/hooks.json` into `~/.claude/settings.json` or `~/.claude/hooks/hooks.json`. That file is plugin/repo-oriented and still contains `${CLAUDE_PLUGIN_ROOT}` placeholders, so raw copying is not a supported manual install path.
Use the installer to install only the Claude hook runtime so command paths are rewritten correctly:
```bash
# macOS / Linux
bash ./install.sh --target claude --modules hooks-runtime
```
```powershell
# Windows PowerShell
pwsh -File .\install.ps1 --target claude --modules hooks-runtime
```
That writes resolved hooks to `~/.claude/hooks/hooks.json` and leaves any existing `~/.claude/settings.json` untouched.
If you installed ECC via `/plugin install`, do not copy those hooks into `settings.json`. Claude Code v2.1+ already auto-loads plugin `hooks/hooks.json`, and duplicating them in `settings.json` causes duplicate execution and `${CLAUDE_PLUGIN_ROOT}` resolution failures.
Windows note: the Claude config directory is `%USERPROFILE%\\.claude`, not `~/claude`.
#### Configure MCPs
Copy desired MCP server definitions from `mcp-configs/mcp-servers.json` into your official Claude Code config in `~/.claude/settings.json`, or into a project-scoped `.mcp.json` if you want repo-local MCP access.

View File

@@ -16,6 +16,22 @@ User request → Claude picks a tool → PreToolUse hook runs → Tool executes
## Hooks in This Plugin
## Installing These Hooks Manually
For Claude Code manual installs, do not paste the raw repo `hooks.json` into `~/.claude/settings.json` or copy it directly into `~/.claude/hooks/hooks.json`. The checked-in file still contains `${CLAUDE_PLUGIN_ROOT}` placeholders and is meant to be installed through the ECC installer or loaded as a plugin.
Use the installer instead so hook commands are rewritten against your actual Claude root:
```bash
bash ./install.sh --target claude --modules hooks-runtime
```
```powershell
pwsh -File .\install.ps1 --target claude --modules hooks-runtime
```
That installs resolved hooks to `~/.claude/hooks/hooks.json`. On Windows, the Claude config root is `%USERPROFILE%\\.claude`.
### PreToolUse Hooks
| Hook | Matcher | Behavior | Exit Code |

View File

@@ -27,7 +27,7 @@ Usage: install.sh [--target <${LEGACY_INSTALL_TARGETS.join('|')}>] [--dry-run] [
install.sh [--dry-run] [--json] --config <path>
Targets:
claude (default) - Install rules to ~/.claude/rules/
claude (default) - Install ECC into ~/.claude/ (hooks, commands, agents, rules, skills)
cursor - Install rules, hooks, and bundled Cursor configs to ./.cursor/
antigravity - Install rules, workflows, skills, and agents to ./.agent/

View File

@@ -110,6 +110,17 @@ function runTests() {
}
})) passed++; else failed++;
if (!powerShellCommand) {
console.log(' - skipped help text test; PowerShell is not available in PATH');
} else if (test('exposes the corrected Claude target help text', () => {
const result = run(powerShellCommand, ['--help']);
assert.strictEqual(result.code, 0, result.stderr);
assert.ok(
result.stdout.includes('claude (default) - Install ECC into ~/.claude/'),
'help text should describe the Claude target as a full ~/.claude install surface'
);
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}

View File

@@ -86,6 +86,15 @@ function runTests() {
}
})) passed++; else failed++;
if (test('exposes the corrected Claude target help text', () => {
const result = run(['--help']);
assert.strictEqual(result.code, 0, result.stderr);
assert.ok(
result.stdout.includes('claude (default) - Install ECC into ~/.claude/'),
'help text should describe the Claude target as a full ~/.claude install surface'
);
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}

View File

@@ -0,0 +1,71 @@
/**
* Regression coverage for supported manual Claude hook installation guidance.
*/
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const README = path.join(__dirname, '..', '..', 'README.md');
const HOOKS_README = path.join(__dirname, '..', '..', 'hooks', 'README.md');
function test(name, fn) {
try {
fn();
console.log(` \u2713 ${name}`);
return true;
} catch (error) {
console.log(` \u2717 ${name}`);
console.log(` Error: ${error.message}`);
return false;
}
}
function runTests() {
console.log('\n=== Testing manual hook install docs ===\n');
let passed = 0;
let failed = 0;
const readme = fs.readFileSync(README, 'utf8');
const hooksReadme = fs.readFileSync(HOOKS_README, 'utf8');
if (test('README warns against raw hook file copying', () => {
assert.ok(
readme.includes('Do not copy the raw repo `hooks/hooks.json` into `~/.claude/settings.json` or `~/.claude/hooks/hooks.json`'),
'README should warn against unsupported raw hook copying'
);
assert.ok(
readme.includes('bash ./install.sh --target claude --modules hooks-runtime'),
'README should document the supported Bash hook install path'
);
assert.ok(
readme.includes('pwsh -File .\\install.ps1 --target claude --modules hooks-runtime'),
'README should document the supported PowerShell hook install path'
);
assert.ok(
readme.includes('%USERPROFILE%\\\\.claude'),
'README should call out the correct Windows Claude config root'
);
})) passed++; else failed++;
if (test('hooks/README mirrors supported manual install guidance', () => {
assert.ok(
hooksReadme.includes('do not paste the raw repo `hooks.json` into `~/.claude/settings.json` or copy it directly into `~/.claude/hooks/hooks.json`'),
'hooks/README should warn against unsupported raw hook copying'
);
assert.ok(
hooksReadme.includes('bash ./install.sh --target claude --modules hooks-runtime'),
'hooks/README should document the supported Bash hook install path'
);
assert.ok(
hooksReadme.includes('pwsh -File .\\install.ps1 --target claude --modules hooks-runtime'),
'hooks/README should document the supported PowerShell hook install path'
);
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}
runTests();