Two critical hook regressions on a fresh `ruflo init` (alpha.27):
**#1944** — `helpers/hook-handler.cjs` builds the `prompt` string from a
`||` fallback chain whose third term is the normalised `toolInput` *object*
(`{command:"ls"}` etc.). The object is truthy so the chain stops there;
the next line calls `.toLowerCase()` on it and every `pre-bash` invocation
prints `[WARN] Hook pre-bash encountered an error: …toLowerCase is not a
function` — i.e. **every Bash tool call from Claude Code spams a TypeError**.
Fix: fall back to `toolInput.command` (the string) instead of `toolInput`
(the object). One-character change in three places — the deployed handler
(both tracked copies) and the template in `helpers-generator.ts` that
writes the user's `.claude/helpers/hook-handler.cjs` at init time.
Repro on the fixed file:
echo '{"tool_input":{"command":"ls"},"tool_name":"Bash"}' \
| node v3/@claude-flow/cli/.claude/helpers/hook-handler.cjs pre-bash
→ [OK] Command validated (was: TypeError warning)
Dangerous-command guard still fires:
echo '{"tool_input":{"command":"rm -rf /"},"tool_name":"Bash"}' | … pre-bash
→ [BLOCKED] Dangerous command detected: rm -rf /
**#1943** — `settings-generator.ts` writes hook command strings anchored at
`${CLAUDE_PROJECT_DIR:-.}/.claude/helpers/…`. That works when `ruflo init`
lands helpers project-locally, but breaks when init's settings end up in
`~/.claude/settings.json` (global install) with helpers at
`~/.claude/helpers/`: Claude Code still sets `CLAUDE_PROJECT_DIR` to the
*project* root, the path resolves there, finds nothing, and every Bash /
Edit / Session hook fires `MODULE_NOT_FOUND`.
Fix: replace the path expression with a POSIX `sh` probe that tries the
project-local path first and falls back to `$HOME` when it's missing —
project-local overrides still take precedence; global installs work; no
upgrade-skew. Windows gets the same probe via `cmd /c IF EXIST … ELSE …`.
Applied to both `hookCmd()` and `generateStatusLineConfig()` (the
statusline scaffolding had the same anchor bug).
**CI guard**: `scripts/audit-hook-handler-prompt.mjs` (new) — fails the
build if any `.cjs` handler / TS template falls back to a bare `toolInput`
(object) instead of `toolInput.command` (string). Catches the #1944
pattern exactly. Wired into the existing `hook-command-audit` job.
Verified to flag a deliberately-reverted regression (and clean on HEAD).
Resolves#1944, #1943.
Co-authored-by: Reuven <cohen@ruv-mac-mini.local>