mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-11-09 14:04:06 +09:00
* fix(#1921): plugin hooks invoke a resilient shim, not bare `npx @alpha` per fire Every PreToolUse/PostToolUse/Stop hook ran `npx <pkg>@alpha hooks …`, which (a) re-resolves the @alpha dist-tag from the registry on every fire and (b) re-installs from cold cache — and when that install crashes (an arborist `Invalid Version` on npm 10.8.x, deep in a transitive OTEL/grpc subtree) the user sees a hook error in Claude Code after every assistant turn, plus ~7s of wasted registry traffic per turn. Fix: each plugin (`.claude-plugin/`, `plugin/`, `plugins/ruflo-core/`) ships `scripts/ruflo-hook.sh` — prefers an already-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline --yes ruflo@alpha`, and ALWAYS exits 0. hooks.json invokes `"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh" … || true` (the `|| true` covers the unset-$CLAUDE_PLUGIN_ROOT case). stdin (the hook event JSON) passes through unchanged; the stdin-jq-xargs shell-injection-safety pattern in plugin/hooks/hooks.json is preserved. This does NOT fix the underlying arborist crash (which needs the offending empty-`version` package pinned via `overrides` once it's identified on npm 10.8.2 — see the issue thread) — it makes a CLI/install failure invisible and cheap instead of a visible error every turn. CI guard: scripts/audit-hook-commands.mjs — fails CI if any hook `command` uses `npx` without `--prefer-offline`, or invokes the CLI without a non-fatal guard. Wired into v3-ci.yml as `hook-command-audit` (also bash-lints each ruflo-hook.sh and asserts it exits 0 with no CLI on PATH) + added to witness-verify needs[]. Path triggers updated to fire on `**/hooks/hooks.json`, `**/scripts/ruflo-hook.sh`, and `scripts/**`. Witness markers for #1921 + Co-Authored-By: RuFlo <ruv@ruv.net> * fix(#1921): make test-hooks.mjs shim-aware; fix shim-lint CI step; regen witness Rebasing #1921 onto main surfaced 3 CI failures: - plugin-hooks-smoke (ubuntu + macos): test-hooks.mjs substituted only `npx ruflo@alpha` → the local CLI, but the hooks.json now invokes `${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh <args>`. It now also substitutes the shim path → `<cli> hooks <args>` (bypassing the shim, so the test exercises the real CLI flag wiring) and strips the shim's trailing `|| true` so exit codes are still asserted. 7/7 pass. - hook-command-audit shim-lint step: `PATH="/nonexistent" bash "$sh"` set PATH to a dir with no `bash`, so `bash: command not found`. Now invokes bash by full path with `PATH=` empty: `PATH= "$BASH" "$sh"` — the shim's `command -v` is a builtin (works with empty PATH) and the npx fallback fails cleanly under `|| true` → exit 0. (resolved in v3-ci.yml during the rebase.) Witness manifest regenerated; #1862's marker refreshed to match the shim-relocated `post-edit -f "$FILE" -s true` (the documented-flag form is preserved). `ruflo verify` 0 regressed. Co-Authored-By: RuFlo <ruv@ruv.net> --------- Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
34 lines
1.4 KiB
Bash
Executable File
34 lines
1.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ruflo-hook.sh — resilient invoker for ruflo CLI hook subcommands (#1921).
|
|
#
|
|
# Hooks fire on EVERY PreToolUse / PostToolUse / Stop. A bare
|
|
# `npx <pkg>@alpha hooks …` re-resolves the @alpha dist-tag and re-installs
|
|
# from cold cache on every fire, and when the install crashes (e.g. an
|
|
# arborist `Invalid Version` on npm 10.8.x) the user sees a hook error in
|
|
# Claude Code after every turn. This shim:
|
|
# 1. prefers an already-installed `ruflo` / `claude-flow` binary (no npx,
|
|
# no install) — the common case for plugin users;
|
|
# 2. falls back to `npx --prefer-offline` so a populated npx cache is
|
|
# reused instead of a fresh registry resolve;
|
|
# 3. ALWAYS exits 0 — hook subcommands are best-effort telemetry/learning;
|
|
# a failure must never surface an error or block a turn.
|
|
#
|
|
# stdin (the hook event JSON) is passed through to the CLI unchanged.
|
|
# Usage: ruflo-hook.sh <hook-subcommand> [args…] (the literal `hooks`
|
|
# word is prepended here, so callers pass e.g. `post-edit -f "$FILE" -s true`).
|
|
|
|
# Swallow all diagnostics — nothing this script prints should reach Claude Code.
|
|
exec 2>/dev/null
|
|
|
|
run() { "$@" || true; }
|
|
|
|
if command -v ruflo >/dev/null 2>&1; then
|
|
run ruflo hooks "$@"
|
|
elif command -v claude-flow >/dev/null 2>&1; then
|
|
run claude-flow hooks "$@"
|
|
else
|
|
run npx --prefer-offline --yes ruflo@alpha hooks "$@"
|
|
fi
|
|
|
|
exit 0
|