Greptile's review asked for committed coverage and installer parity; this
makes the hooks installable through ECC's own machinery instead of a
copy-paste doc:
- manifests/install-modules.json: new module hermes-hooks (kind hooks,
targets hermes + openclaw, paths hooks/hermes + docs/HERMES-HOOKS.md,
light/stable, defaultInstall). Disjoint from hooks-runtime, which stays
Claude/Cursor/OpenCode/CodeBuddy — the Hermes target gets hooks support
without inheriting the Claude-format hook graph.
- manifests/install-profiles.json: full profile gains hermes-hooks (validator
requires full to include every module).
- docs/HERMES-HOOKS.md: install section now leads with
./install.sh --target hermes --modules hermes-hooks --enable-hooks; the
manual block registers from the landed ~/.hermes/hooks/hermes/ paths. The
installer never edits config.yaml — registration stays operator-owned.
- tests/hermes-hooks.test.js: installer-integration case (14 total) drives
the real installer into a throwaway HOME and proves the LANDED guard
blocks an eslint.config edit.
Validated: install-manifests (37 modules), no-personal-paths, markdownlint,
14/14 tests. E2E on a throwaway HOME: module lands both scripts + doc and
the landed guard emits a block decision.
Greptile + CodeRabbit review of #3019:
- config-protection: compare basenames case-insensitively (macOS/Windows
resolve ESLINT.CONFIG.JS to the protected eslint.config.js) and use lstat
so a dangling symlink to a protected name still blocks (os.path.exists
follows the link and returns False).
- Both hooks: fail-open stays, silence goes — every swallowed path now
writes a one-line stderr diagnostic.
- config-protection: sys.stdout.write instead of print() per repo Python
style; block decisions carry a trailing newline.
- New tests/hermes-hooks.test.js: 13 cases through the real scripts via
spawnSync — block (all names, case variants, dangling symlink, edits[],
per-tool), allow (normal source, new config, non-edit tools), fail-open
with diagnostics (malformed payload, missing path, unreadable file).
- docs: absolute-path copy-paste block via $HOME (CodeRabbit: /Users/YOU
placeholders were unverifiable), self-contained block-case proof that
creates its target, pointer to the committed suite.
Hermes ships its own shell-hook system (hooks: block in config.yaml,
Claude-compatible JSON payloads, per-tool matchers, consent allowlist),
and the hermes install target deliberately ships no hook runtime — so
Hermes operators get rules/skills/commands with zero hooks. This ports
the two harness-independent ECC hooks as self-contained Python scripts
with no ECC runtime dependency:
- config-protection: blocks edits to existing lint/format configs and
ratchet baselines (pre_tool_call)
- check-console-log: warns on console.log() in edited TS/JS (post_tool_call)
Includes install, consent, and verification steps in docs/HERMES-HOOKS.md.