fix(#1921): plugin hooks use a resilient shim, not bare npx @alpha per fire (#1923)

* 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>
This commit is contained in:
rUvandReuven authored and GitHub committed 2026-05-12 00:51:18 -04:00
1 parent 95df0111e0
commit f0ee0f9688
12 files changed
+349 -56

No files matched your search

+6 -5
View File
@@ -1,4 +1,5 @@
{
"_note": "#1921 — hook commands invoke scripts/ruflo-hook.sh (resilient shim): prefers a locally-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline`, and always exits 0 so a CLI/install failure (e.g. arborist `Invalid Version` on npm 10.8.x) never surfaces an error in Claude Code or blocks a turn. The trailing `|| true` guards the case where $CLAUDE_PLUGIN_ROOT is unset (older Claude Code) — the hook then no-ops silently. DO NOT revert to a bare `npx <pkg>@alpha hooks …` per fire.",
"hooks": {
"PreToolUse": [
{
@@ -6,7 +7,7 @@
"hooks": [
{
"type": "command",
"command": "cat | npx claude-flow@alpha hooks modify-bash"
"command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" modify-bash || true"
}
]
},
@@ -15,7 +16,7 @@
"hooks": [
{
"type": "command",
"command": "cat | npx claude-flow@alpha hooks modify-file"
"command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" modify-file || true"
}
]
}
@@ -26,7 +27,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.command // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks post-command --command '{}' --track-metrics true --store-results true"
"command": "cat | jq -r '.tool_input.command // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-command --command '{}' --track-metrics true --store-results true || true"
}
]
},
@@ -35,7 +36,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.file_path // .tool_input.path // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks post-edit --file '{}' --format true --update-memory true"
"command": "cat | jq -r '.tool_input.file_path // .tool_input.path // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-edit --file '{}' --format true --update-memory true || true"
}
]
}
@@ -65,7 +66,7 @@
"hooks": [
{
"type": "command",
"command": "npx claude-flow@alpha hooks session-end --generate-summary true --persist-state true --export-metrics true"
"command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" session-end --generate-summary true --persist-state true --export-metrics true || true"
}
]
}
+33
View File
@@ -0,0 +1,33 @@
#!/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
+47 -12
View File
@@ -10,15 +10,21 @@ on:
# path filter keeps CI in sync with their changes.
- 'plugins/ruflo-core/scripts/witness/**'
- 'plugins/ruflo-core/scripts/test-hooks.mjs'
- 'plugins/ruflo-core/hooks/hooks.json'
- 'verification/**'
# scripts/*.mjs audits (tool-descriptions, plugin-packages, hook-commands)
- 'scripts/**'
# hook-command audit (#1921) — every plugin hooks.json + the ruflo-hook shims
- '**/hooks/hooks.json'
- '**/scripts/ruflo-hook.sh'
pull_request:
branches: [main]
paths:
- 'v3/**'
- 'plugins/ruflo-core/scripts/witness/**'
- 'plugins/ruflo-core/scripts/test-hooks.mjs'
- 'plugins/ruflo-core/hooks/hooks.json'
- 'scripts/**'
- '**/hooks/hooks.json'
- '**/scripts/ruflo-hook.sh'
workflow_dispatch:
env:
@@ -475,12 +481,10 @@ jobs:
plugin-package-audit:
# Regression guard for #1902/#1903/#1904 — plugin package.json install
# safety. Checks: (A) no unpublished @claude-flow/* hard dep / non-optional
# peer (#1903 ruvector-upstream class), (B) no bare-stable peer range that
# can't resolve a 3.x prerelease publish (#1902), (C) every main/module/
# exports path is covered by `files`, (D) after building each plugin,
# every main/module/exports path exists on disk (#1904 — exports.import →
# ./dist/index.mjs but the build only emits .js/.cjs). The build step is
# what makes check D live; without it the script does A/B/C only.
# peer, (B) no bare-stable peer range that can't resolve a 3.x prerelease
# publish, (C) every main/module/exports path is covered by `files`,
# (D) after building each plugin, every main/module/exports path exists on
# disk (#1904). The build step is what makes check D live.
name: Plugin package install-safety (#1902/#1903/#1904)
runs-on: ubuntu-latest
@@ -505,9 +509,6 @@ jobs:
shell: bash
run: |
pnpm install --frozen-lockfile
# Build each plugin that has a build script. --no-bail tolerates an
# unrelated build failure; check D simply won't run for a plugin
# whose dist/ is absent.
for d in plugins/*/; do
if [ -f "$d/package.json" ] && node -e "process.exit(require('./'+process.argv[1]+'package.json').scripts?.build?0:1)" "$d"; then
echo "::group::build $d"
@@ -520,6 +521,40 @@ jobs:
shell: bash
run: node scripts/audit-plugin-packages.mjs
hook-command-audit:
# Regression guard for #1921 (and #1147) — plugin hooks.json must not
# invoke a bare `npx <pkg>@alpha hooks …` per fire. The fix is
# scripts/ruflo-hook.sh (prefers a local `ruflo`/`claude-flow` binary,
# falls back to `npx --prefer-offline`, always exits 0).
name: Hook-command install safety (#1921)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Run hook-command audit
shell: bash
run: node scripts/audit-hook-commands.mjs
- name: Lint the ruflo-hook shims
shell: bash
run: |
# Every shim must be valid bash and exit 0 even when no CLI is
# reachable (the #1921 contract). Probe with an empty PATH (invoke
# bash by full path since PATH= can't find it otherwise).
BASH="$(command -v bash)"
for sh in $(git ls-files '**/scripts/ruflo-hook.sh'); do
echo "checking $sh"
bash -n "$sh"
PATH= "$BASH" "$sh" modify-bash </dev/null || { echo "::error::$sh did not exit 0 with no CLI on PATH"; exit 1; }
done
witness-verify:
# Cryptographic regression guard: runs `ruflo verify --manifest` against
# the local build to confirm every documented fix in verification.md.json
@@ -546,7 +581,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
needs: [smoke-install-no-bsqlite, plugin-hooks-smoke, mcp-protocol-smoke, memory-import-smoke, tool-descriptions-audit, mcp-roundtrip-smoke, plugin-package-audit]
needs: [smoke-install-no-bsqlite, plugin-hooks-smoke, mcp-protocol-smoke, memory-import-smoke, tool-descriptions-audit, mcp-roundtrip-smoke, plugin-package-audit, hook-command-audit]
steps:
- name: Checkout code
+16 -15
View File
@@ -1,7 +1,8 @@
{
"$schema": "https://code.claude.com/schemas/hooks.json",
"description": "Claude Flow hooks configuration — uses stdin-jq-xargs pattern to prevent shell-injection when tool inputs contain quotes / redirects / special chars (#1747).",
"_security_note": "All commands read the hook payload from stdin (Claude Code passes a JSON object), extract fields with jq, and pass them to npx as a single argv element via xargs -0. This bypasses shell re-parsing entirely. DO NOT inline $TOOL_INPUT_* / $PROMPT / $TOOL_NAME directly in a quoted command string — interpolation is not shell-safe (creates empty files at CWD when input contains '>' redirects).",
"description": "Claude Flow hooks configuration — uses stdin-jq-xargs pattern to prevent shell-injection when tool inputs contain quotes / redirects / special chars (#1747). Hook subcommands run via scripts/ruflo-hook.sh (#1921).",
"_security_note": "All commands read the hook payload from stdin (Claude Code passes a JSON object), extract fields with jq, and pass them to the CLI as a single argv element via xargs -0. This bypasses shell re-parsing entirely. DO NOT inline $TOOL_INPUT_* / $PROMPT / $TOOL_NAME directly in a quoted command string — interpolation is not shell-safe (creates empty files at CWD when input contains '>' redirects).",
"_resilience_note": "#1921 — hook subcommands invoke scripts/ruflo-hook.sh (resilient shim): prefers a locally-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline`, always exits 0. The trailing `|| true` on each pipeline guards the case where $CLAUDE_PLUGIN_ROOT is unset. DO NOT revert to a bare `npx <pkg>@alpha hooks …` per fire.",
"hooks": {
"PreToolUse": [
{
@@ -10,7 +11,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.file_path // .tool_input.path // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks pre-edit --file '{}'",
"command": "cat | jq -r '.tool_input.file_path // .tool_input.path // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" pre-edit --file '{}' || true",
"timeout": 5000,
"continueOnError": true
}
@@ -22,7 +23,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.command // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks pre-command --command '{}'",
"command": "cat | jq -r '.tool_input.command // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" pre-command --command '{}' || true",
"timeout": 3000,
"continueOnError": true
}
@@ -34,7 +35,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.description // empty | .[:200]' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks pre-task --description '{}'",
"command": "cat | jq -r '.tool_input.description // empty | .[:200]' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" pre-task --description '{}' || true",
"timeout": 5000,
"continueOnError": true
}
@@ -46,7 +47,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.pattern // .tool_input.query // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks pre-search --query '{}'",
"command": "cat | jq -r '.tool_input.pattern // .tool_input.query // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" pre-search --query '{}' || true",
"timeout": 2000,
"continueOnError": true
}
@@ -58,7 +59,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_name // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks mcp-pre --tool '{}'",
"command": "cat | jq -r '.tool_name // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" mcp-pre --tool '{}' || true",
"timeout": 3000,
"continueOnError": true
}
@@ -72,7 +73,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.file_path // .tool_input.path // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks post-edit --file '{}' --train-patterns",
"command": "cat | jq -r '.tool_input.file_path // .tool_input.path // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-edit --file '{}' --train-patterns || true",
"timeout": 5000,
"continueOnError": true
}
@@ -84,7 +85,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.command // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks post-command --command '{}' --track-metrics true --store-results true",
"command": "cat | jq -r '.tool_input.command // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-command --command '{}' --track-metrics true --store-results true || true",
"timeout": 3000,
"continueOnError": true
}
@@ -96,7 +97,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_response.agent_id // .tool_response.task_id // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks post-task --task-id '{}' --analyze-performance",
"command": "cat | jq -r '.tool_response.agent_id // .tool_response.task_id // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-task --task-id '{}' --analyze-performance || true",
"timeout": 5000,
"continueOnError": true
}
@@ -108,7 +109,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_input.pattern // .tool_input.query // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks post-search --query '{}' --cache-results",
"command": "cat | jq -r '.tool_input.pattern // .tool_input.query // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-search --query '{}' --cache-results || true",
"timeout": 2000,
"continueOnError": true
}
@@ -120,7 +121,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.tool_name // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks mcp-post --tool '{}'",
"command": "cat | jq -r '.tool_name // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" mcp-post --tool '{}' || true",
"timeout": 3000,
"continueOnError": true
}
@@ -133,7 +134,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.prompt // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks route --task '{}' --include-explanation",
"command": "cat | jq -r '.prompt // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" route --task '{}' --include-explanation || true",
"timeout": 5000,
"continueOnError": true
}
@@ -146,7 +147,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.session_id // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks session-start --session-id '{}' --load-context",
"command": "cat | jq -r '.session_id // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" session-start --session-id '{}' --load-context || true",
"timeout": 10000,
"continueOnError": true
}
@@ -181,7 +182,7 @@
"hooks": [
{
"type": "command",
"command": "cat | jq -r '.message // empty' | tr '\\n' '\\0' | xargs -0 -I {} npx claude-flow@alpha hooks notify --message '{}' --swarm-status",
"command": "cat | jq -r '.message // empty' | tr '\\n' '\\0' | xargs -0 -I {} \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" notify --message '{}' --swarm-status || true",
"timeout": 3000,
"continueOnError": true
}
+33
View File
@@ -0,0 +1,33 @@
#!/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
+6 -5
View File
@@ -1,4 +1,5 @@
{
"_note": "#1921 — hook commands invoke scripts/ruflo-hook.sh (resilient shim): prefers a locally-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline`, and always exits 0 so a CLI/install failure (e.g. arborist `Invalid Version` on npm 10.8.x) never surfaces an error in Claude Code or blocks a turn. The trailing `|| true` guards the case where $CLAUDE_PLUGIN_ROOT is unset (older Claude Code) — the hook then no-ops silently. DO NOT revert to a bare `npx <pkg>@alpha hooks …` per fire.",
"hooks": {
"PreToolUse": [
{
@@ -6,7 +7,7 @@
"hooks": [
{
"type": "command",
"command": "cat | npx ruflo@alpha hooks modify-bash"
"command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" modify-bash || true"
}
]
},
@@ -15,7 +16,7 @@
"hooks": [
{
"type": "command",
"command": "cat | npx ruflo@alpha hooks modify-file"
"command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" modify-file || true"
}
]
}
@@ -26,7 +27,7 @@
"hooks": [
{
"type": "command",
"command": "/bin/bash -c 'INPUT=$(cat); CMD=$(printf %s \"$INPUT\" | jq -r \".tool_input.command // empty\"); [ -z \"$CMD\" ] && exit 0; EXIT=$(printf %s \"$INPUT\" | jq -r \".tool_response.exit_code // 0\"); SUCCESS=$([ \"$EXIT\" = \"0\" ] && echo true || echo false); npx ruflo@alpha hooks post-command -c \"$CMD\" -s \"$SUCCESS\" -e \"$EXIT\"'"
"command": "/bin/bash -c 'INPUT=$(cat); CMD=$(printf %s \"$INPUT\" | jq -r \".tool_input.command // empty\"); [ -z \"$CMD\" ] && exit 0; EXIT=$(printf %s \"$INPUT\" | jq -r \".tool_response.exit_code // 0\"); SUCCESS=$([ \"$EXIT\" = \"0\" ] && echo true || echo false); \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-command -c \"$CMD\" -s \"$SUCCESS\" -e \"$EXIT\" || true'"
}
]
},
@@ -35,7 +36,7 @@
"hooks": [
{
"type": "command",
"command": "/bin/bash -c 'INPUT=$(cat); FILE=$(printf %s \"$INPUT\" | jq -r \".tool_input.file_path // .tool_input.path // empty\"); [ -z \"$FILE\" ] && exit 0; npx ruflo@alpha hooks post-edit -f \"$FILE\" -s true'"
"command": "/bin/bash -c 'INPUT=$(cat); FILE=$(printf %s \"$INPUT\" | jq -r \".tool_input.file_path // .tool_input.path // empty\"); [ -z \"$FILE\" ] && exit 0; \"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" post-edit -f \"$FILE\" -s true || true'"
}
]
}
@@ -65,7 +66,7 @@
"hooks": [
{
"type": "command",
"command": "npx ruflo@alpha hooks session-end --generate-summary true --persist-state true --export-metrics true"
"command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh\" session-end --generate-summary true --persist-state true --export-metrics true || true"
}
]
}
+33
View File
@@ -0,0 +1,33 @@
#!/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
+10 -1
View File
@@ -47,7 +47,16 @@ const post = hooks.hooks?.PostToolUse ?? [];
const findHook = (matcher) => {
const hit = post.find(h => h.matcher === matcher);
if (!hit) throw new Error(`No PostToolUse hook with matcher=${matcher}`);
return hit.hooks[0].command.replace(/npx ruflo@alpha/g, cliInvoke);
return hit.hooks[0].command
// legacy form: `npx ruflo@alpha hooks …`
.replace(/npx ruflo@alpha/g, cliInvoke)
// #1921 form: hook subcommands go through scripts/ruflo-hook.sh (which
// prepends `hooks`). Bypass the shim here and call the built CLI directly
// so the test exercises the same flag wiring users hit, pinned to the
// build under test. Also drop the shim's `|| true` so exit codes are
// still asserted (the shim makes failures non-fatal in production).
.replace(/"\$\{CLAUDE_PLUGIN_ROOT\}\/scripts\/ruflo-hook\.sh"/g, `${cliInvoke} hooks`)
.replace(/\s*\|\|\s*true(\s*')/g, '$1');
};
const cmdBash = findHook('Bash');
+117
View File
@@ -0,0 +1,117 @@
#!/usr/bin/env node
/**
* Hook-command install-safety audit — regression guard for #1921 (and #1147).
*
* Hooks fire on EVERY PreToolUse / PostToolUse / Stop / etc. A hook `command`
* that does a bare `npx <pkg>@alpha …` re-resolves the dist-tag and re-installs
* from cold cache on every fire; when that 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. The fix: invoke `scripts/ruflo-hook.sh` (prefers a locally-
* installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline`,
* always exits 0). This guard fails CI if any hook `command` regresses.
*
* Rules, per hook `command` string:
* 1. If it invokes `npx`, it MUST also pass `--prefer-offline`.
* 2. If it invokes `npx` or `scripts/ruflo-hook.sh`, it MUST be non-fatal:
* end with `|| true` / `|| exit 0`, or the hook entry must set
* `continueOnError: true`.
*
* Usage:
* node scripts/audit-hook-commands.mjs # exit 1 on any violation
* node scripts/audit-hook-commands.mjs --json # machine-readable report
*/
import { readFileSync, readdirSync } from 'node:fs';
import { join, relative } from 'node:path';
const REPO_ROOT = process.cwd();
const JSON_OUT = process.argv.includes('--json');
function findHooksFiles(dir, out = []) {
let entries;
try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return out; }
for (const e of entries) {
if (e.name === 'node_modules' || e.name === '.git') continue;
const p = join(dir, e.name);
if (e.isDirectory()) findHooksFiles(p, out);
else if (e.isFile() && /[\\/]hooks[\\/]hooks\.json$/.test(p)) out.push(p);
}
return out;
}
function collectCommands(hooksJson) {
const out = [];
const root = hooksJson && hooksJson.hooks;
if (!root || typeof root !== 'object') return out;
for (const [event, entries] of Object.entries(root)) {
if (!Array.isArray(entries)) continue;
for (const entry of entries) {
const matcher = entry && entry.matcher;
const list = entry && Array.isArray(entry.hooks) ? entry.hooks : [];
for (let idx = 0; idx < list.length; idx++) {
const h = list[idx];
if (h && h.type === 'command' && typeof h.command === 'string') {
out.push({ event, matcher, idx, command: h.command, continueOnError: h.continueOnError === true });
}
}
}
}
return out;
}
const NPX_RE = /(^|[\s;&|(])npx\b/;
const PREFER_OFFLINE_RE = /--prefer-offline\b/;
const SHIM_RE = /ruflo-hook\.sh/;
const NONFATAL_RE = /\|\|\s*(true|exit\s+0)\b/;
const files = findHooksFiles(REPO_ROOT);
const violations = [];
for (const file of files) {
const rel = relative(REPO_ROOT, file);
let parsed;
try { parsed = JSON.parse(readFileSync(file, 'utf-8')); }
catch (e) { violations.push({ file: rel, where: rel, reason: `invalid JSON: ${e.message}` }); continue; }
for (const { event, matcher, idx, command, continueOnError } of collectCommands(parsed)) {
const where = `${rel} :: ${event}${matcher ? ` [${matcher}]` : ''} #${idx}`;
const usesNpx = NPX_RE.test(command);
const usesShim = SHIM_RE.test(command);
if (usesNpx && !PREFER_OFFLINE_RE.test(command)) {
violations.push({
file: rel, where,
reason: 'invokes `npx` without `--prefer-offline` — re-resolves the dist-tag and re-installs from cold cache on every hook fire (#1921). Use scripts/ruflo-hook.sh, or add `--prefer-offline`.',
command,
});
continue;
}
if ((usesNpx || usesShim) && !NONFATAL_RE.test(command) && !continueOnError) {
violations.push({
file: rel, where,
reason: 'invokes the CLI but is not non-fatal — a CLI/install failure surfaces a hook error in Claude Code (#1921). Append `|| true` (or set `continueOnError: true`).',
command,
});
}
}
}
const report = { scannedFiles: files.length, violationCount: violations.length, violations };
if (JSON_OUT) {
console.log(JSON.stringify(report, null, 2));
} else {
console.log(`hook-command audit — scanned ${files.length} hooks.json file(s)`);
if (violations.length === 0) {
console.log(' ✓ no install-safety violations');
} else {
for (const v of violations) {
console.log(` ✗ ${v.where}`);
console.log(` ${v.reason}`);
if (v.command) console.log(` command: ${v.command.length > 200 ? v.command.slice(0, 200) + '…' : v.command}`);
}
console.log(`\n${violations.length} violation(s)`);
}
}
process.exit(violations.length > 0 ? 1 : 0);
+2
View File
@@ -20,3 +20,5 @@
{"v":1,"commit":"b680fca85aac08ec59880197f8f6af2042da8b6b","issuedAt":"2026-05-12T04:39:26.400Z","branch":"fix/1916-agent-logs-hive-resolution","os":"macos","manifestHash":"b4e846d271b190a65db53c38ddaf1e0984c01ac061f0b577020397736d394159","summary":{"totalFixes":108,"verified":107,"missing":0},"fixes":{"F1":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F2":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F3":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"F4":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"F5":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"F6":{"sha256":"159365d8f876d52b94a3c1420e9ac3e6da442a4d0fa0bcd6de292b6282113cee","markerVerified":true},"F7":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"F8":{"sha256":"8151d83f6b1abe7a9139db5c9d884c42c1b3faf986dc712c0fbd43a22af39f51","markerVerified":true},"F9":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"F10":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F11":{"sha256":"acb66c459f9eb3a34686567b5d4f9bd834b4e874e9a1229256baebfd15c4ea5c","markerVerified":true},"F12":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"#1697":{"sha256":"14345e0180e5c4649b5a2169b094c8e05d97c54fe79902c8eef0ebf7c18715fb","markerVerified":true},"#1698":{"sha256":"2cb57b6fb38bb4722eebd169f4b6056f1b6f69ba0adde9978bcd9e03f83d43ab","markerVerified":true},"#1691":{"sha256":"8fe7b53ad914532474b77cf419b6e64ee60e12562062342e9cf9fd5eee8c8498","markerVerified":true},"#1721":{"sha256":"862f40e5c7b45a0ce35bbe438add312cf7d155e527ee49bed62ee9b58d0cd526","markerVerified":true},"ADR-094":{"sha256":"1d2225e7422f8a2d47d39100324d5e4ac2d29c55e8e72b02f5e4a7a113d45be2","markerVerified":true},"G1":{"sha256":"2bc49c38b14d43a0329bf5d84913528851ef1c48ab32b8c8c1c40f83c062fc7f","markerVerified":true},"G3":{"sha256":"442839dca2d6177f2567dccaf1f48306c304cbca0659c477501604289f7ad5a6","markerVerified":true},"G4":{"sha256":"12fce07f6458aff5db210b0ba50104fa9b2dd52c85b5e9071b48c2899451c631","markerVerified":true},"G6":{"sha256":"84a6159b384b8118f0beaa1089c417cab6d1116cd77d3882a607715ef7679ea8","markerVerified":true},"G7-gnn":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-rvf":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-mut":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-att":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-gvb":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G2":{"sha256":"9f751aaee838a85e7b2371bbd73dccb5cb89c6b7751496b18d33d8b8a559de19","markerVerified":true},"CAP-MCP-agent-tools":{"sha256":"a182a61809b5480e9eb4139ed8fa3b8e471201d338be4e086578b4e2e325302a","markerVerified":true},"CAP-MCP-agentdb-tools":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"CAP-MCP-analyze-tools":{"sha256":"d665ca78dcb753e7803d37a331ae363ba5e4fea0c90e828171d264a425a638da","markerVerified":true},"CAP-MCP-autopilot-tools":{"sha256":"1f1dcf3c7660b9ab66df49bacfdf2c7f5a883554d98b416a2780d5226e643df2","markerVerified":true},"CAP-MCP-browser-tools":{"sha256":"5ea5f63c99ee22bccb6fbd4d872e44f47ec7f0ad14ceed4f18014b95f94f75f7","markerVerified":true},"CAP-MCP-claims-tools":{"sha256":"89908d601a21e1a0dca0bd611af61b1d2150010f6015216849122775e6940808","markerVerified":true},"CAP-MCP-config-tools":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"CAP-MCP-coordination-tools":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"CAP-MCP-daa-tools":{"sha256":"2beb8ec07d784cf7f1a61b4cd2090a8e65934893c2a31a3afcd406774d2a8537","markerVerified":true},"CAP-MCP-embeddings-tools":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"CAP-MCP-github-tools":{"sha256":"951b66082ba309505eaf4e3588104681f5581ec5e0c8d6daf6a7befac596db37","markerVerified":true},"CAP-MCP-guidance-tools":{"sha256":"856f7b0439a4dfdafab88589faf5cbe42c8fbd4004532fe507ec3e3e42af9e12","markerVerified":true},"CAP-MCP-hive-mind-tools":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"CAP-MCP-hooks-tools":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"CAP-MCP-memory-tools":{"sha256":"37d929df892035fe94a48cd43a074c9c773e9dc031ab56d9Line truncated
{"v":1,"commit":"b680fca85aac08ec59880197f8f6af2042da8b6b","issuedAt":"2026-05-12T04:39:59.412Z","branch":"fix/1916-agent-logs-hive-resolution","os":"macos","manifestHash":"867a536d3d605716484e79d49755eb9cd293694826d3b51e1190e90599107b61","summary":{"totalFixes":108,"verified":108,"missing":0},"fixes":{"F1":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F2":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F3":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"F4":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"F5":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"F6":{"sha256":"159365d8f876d52b94a3c1420e9ac3e6da442a4d0fa0bcd6de292b6282113cee","markerVerified":true},"F7":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"F8":{"sha256":"8151d83f6b1abe7a9139db5c9d884c42c1b3faf986dc712c0fbd43a22af39f51","markerVerified":true},"F9":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"F10":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F11":{"sha256":"acb66c459f9eb3a34686567b5d4f9bd834b4e874e9a1229256baebfd15c4ea5c","markerVerified":true},"F12":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"#1697":{"sha256":"14345e0180e5c4649b5a2169b094c8e05d97c54fe79902c8eef0ebf7c18715fb","markerVerified":true},"#1698":{"sha256":"2cb57b6fb38bb4722eebd169f4b6056f1b6f69ba0adde9978bcd9e03f83d43ab","markerVerified":true},"#1691":{"sha256":"6b600ec62ef9a3898fd3c606c23034a10a005c0330d0dac43b29f6d2abc2ec8e","markerVerified":true},"#1721":{"sha256":"862f40e5c7b45a0ce35bbe438add312cf7d155e527ee49bed62ee9b58d0cd526","markerVerified":true},"ADR-094":{"sha256":"1d2225e7422f8a2d47d39100324d5e4ac2d29c55e8e72b02f5e4a7a113d45be2","markerVerified":true},"G1":{"sha256":"2bc49c38b14d43a0329bf5d84913528851ef1c48ab32b8c8c1c40f83c062fc7f","markerVerified":true},"G3":{"sha256":"442839dca2d6177f2567dccaf1f48306c304cbca0659c477501604289f7ad5a6","markerVerified":true},"G4":{"sha256":"12fce07f6458aff5db210b0ba50104fa9b2dd52c85b5e9071b48c2899451c631","markerVerified":true},"G6":{"sha256":"84a6159b384b8118f0beaa1089c417cab6d1116cd77d3882a607715ef7679ea8","markerVerified":true},"G7-gnn":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-rvf":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-mut":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-att":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-gvb":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G2":{"sha256":"9f751aaee838a85e7b2371bbd73dccb5cb89c6b7751496b18d33d8b8a559de19","markerVerified":true},"CAP-MCP-agent-tools":{"sha256":"a182a61809b5480e9eb4139ed8fa3b8e471201d338be4e086578b4e2e325302a","markerVerified":true},"CAP-MCP-agentdb-tools":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"CAP-MCP-analyze-tools":{"sha256":"d665ca78dcb753e7803d37a331ae363ba5e4fea0c90e828171d264a425a638da","markerVerified":true},"CAP-MCP-autopilot-tools":{"sha256":"1f1dcf3c7660b9ab66df49bacfdf2c7f5a883554d98b416a2780d5226e643df2","markerVerified":true},"CAP-MCP-browser-tools":{"sha256":"5ea5f63c99ee22bccb6fbd4d872e44f47ec7f0ad14ceed4f18014b95f94f75f7","markerVerified":true},"CAP-MCP-claims-tools":{"sha256":"89908d601a21e1a0dca0bd611af61b1d2150010f6015216849122775e6940808","markerVerified":true},"CAP-MCP-config-tools":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"CAP-MCP-coordination-tools":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"CAP-MCP-daa-tools":{"sha256":"2beb8ec07d784cf7f1a61b4cd2090a8e65934893c2a31a3afcd406774d2a8537","markerVerified":true},"CAP-MCP-embeddings-tools":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"CAP-MCP-github-tools":{"sha256":"951b66082ba309505eaf4e3588104681f5581ec5e0c8d6daf6a7befac596db37","markerVerified":true},"CAP-MCP-guidance-tools":{"sha256":"856f7b0439a4dfdafab88589faf5cbe42c8fbd4004532fe507ec3e3e42af9e12","markerVerified":true},"CAP-MCP-hive-mind-tools":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"CAP-MCP-hooks-tools":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"CAP-MCP-memory-tools":{"sha256":"37d929df892035fe94a48cd43a074c9c773e9dc031ab56d9Line truncated
{"v":1,"commit":"31f22ff9a92154952b8d9e417a25034bdf08de08","issuedAt":"2026-05-12T04:44:05.086Z","branch":"HEAD","os":"macos","manifestHash":"a081f02f53f33c5a008cd06177cb1f8a4de08ac7183312877d57c0ca95018192","summary":{"totalFixes":110,"verified":110,"missing":0},"fixes":{"F1":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F2":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F3":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"F4":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"F5":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"F6":{"sha256":"159365d8f876d52b94a3c1420e9ac3e6da442a4d0fa0bcd6de292b6282113cee","markerVerified":true},"F7":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"F8":{"sha256":"8151d83f6b1abe7a9139db5c9d884c42c1b3faf986dc712c0fbd43a22af39f51","markerVerified":true},"F9":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"F10":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F11":{"sha256":"acb66c459f9eb3a34686567b5d4f9bd834b4e874e9a1229256baebfd15c4ea5c","markerVerified":true},"F12":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"#1697":{"sha256":"14345e0180e5c4649b5a2169b094c8e05d97c54fe79902c8eef0ebf7c18715fb","markerVerified":true},"#1698":{"sha256":"2cb57b6fb38bb4722eebd169f4b6056f1b6f69ba0adde9978bcd9e03f83d43ab","markerVerified":true},"#1691":{"sha256":"6b600ec62ef9a3898fd3c606c23034a10a005c0330d0dac43b29f6d2abc2ec8e","markerVerified":true},"#1721":{"sha256":"862f40e5c7b45a0ce35bbe438add312cf7d155e527ee49bed62ee9b58d0cd526","markerVerified":true},"ADR-094":{"sha256":"1d2225e7422f8a2d47d39100324d5e4ac2d29c55e8e72b02f5e4a7a113d45be2","markerVerified":true},"G1":{"sha256":"2bc49c38b14d43a0329bf5d84913528851ef1c48ab32b8c8c1c40f83c062fc7f","markerVerified":true},"G3":{"sha256":"442839dca2d6177f2567dccaf1f48306c304cbca0659c477501604289f7ad5a6","markerVerified":true},"G4":{"sha256":"12fce07f6458aff5db210b0ba50104fa9b2dd52c85b5e9071b48c2899451c631","markerVerified":true},"G6":{"sha256":"84a6159b384b8118f0beaa1089c417cab6d1116cd77d3882a607715ef7679ea8","markerVerified":true},"G7-gnn":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-rvf":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-mut":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-att":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-gvb":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G2":{"sha256":"9f751aaee838a85e7b2371bbd73dccb5cb89c6b7751496b18d33d8b8a559de19","markerVerified":true},"CAP-MCP-agent-tools":{"sha256":"a182a61809b5480e9eb4139ed8fa3b8e471201d338be4e086578b4e2e325302a","markerVerified":true},"CAP-MCP-agentdb-tools":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"CAP-MCP-analyze-tools":{"sha256":"d665ca78dcb753e7803d37a331ae363ba5e4fea0c90e828171d264a425a638da","markerVerified":true},"CAP-MCP-autopilot-tools":{"sha256":"1f1dcf3c7660b9ab66df49bacfdf2c7f5a883554d98b416a2780d5226e643df2","markerVerified":true},"CAP-MCP-browser-tools":{"sha256":"5ea5f63c99ee22bccb6fbd4d872e44f47ec7f0ad14ceed4f18014b95f94f75f7","markerVerified":true},"CAP-MCP-claims-tools":{"sha256":"89908d601a21e1a0dca0bd611af61b1d2150010f6015216849122775e6940808","markerVerified":true},"CAP-MCP-config-tools":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"CAP-MCP-coordination-tools":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"CAP-MCP-daa-tools":{"sha256":"2beb8ec07d784cf7f1a61b4cd2090a8e65934893c2a31a3afcd406774d2a8537","markerVerified":true},"CAP-MCP-embeddings-tools":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"CAP-MCP-github-tools":{"sha256":"951b66082ba309505eaf4e3588104681f5581ec5e0c8d6daf6a7befac596db37","markerVerified":true},"CAP-MCP-guidance-tools":{"sha256":"856f7b0439a4dfdafab88589faf5cbe42c8fbd4004532fe507ec3e3e42af9e12","markerVerified":true},"CAP-MCP-hive-mind-tools":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"CAP-MCP-hooks-tools":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"CAP-MCP-memory-tools":{"sha256":"37d929df892035fe94a48cd43a074c9c773e9dc031ab56d9dd33cdbf21a87e39","markerVerifiLine truncated
{"v":1,"commit":"95df0111e0dc749a8b79a859238a6d62b29102cf","issuedAt":"2026-05-12T04:48:07.079Z","branch":"HEAD","os":"macos","manifestHash":"3427c16ee9346f9ad29df4b62d9df0afe059addc10cae4e037d3e45e64713fff","summary":{"totalFixes":112,"verified":111,"missing":0},"fixes":{"F1":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F2":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F3":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"F4":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"F5":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"F6":{"sha256":"159365d8f876d52b94a3c1420e9ac3e6da442a4d0fa0bcd6de292b6282113cee","markerVerified":true},"F7":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"F8":{"sha256":"8151d83f6b1abe7a9139db5c9d884c42c1b3faf986dc712c0fbd43a22af39f51","markerVerified":true},"F9":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"F10":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F11":{"sha256":"acb66c459f9eb3a34686567b5d4f9bd834b4e874e9a1229256baebfd15c4ea5c","markerVerified":true},"F12":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"#1697":{"sha256":"14345e0180e5c4649b5a2169b094c8e05d97c54fe79902c8eef0ebf7c18715fb","markerVerified":true},"#1698":{"sha256":"2cb57b6fb38bb4722eebd169f4b6056f1b6f69ba0adde9978bcd9e03f83d43ab","markerVerified":true},"#1691":{"sha256":"6b600ec62ef9a3898fd3c606c23034a10a005c0330d0dac43b29f6d2abc2ec8e","markerVerified":true},"#1721":{"sha256":"862f40e5c7b45a0ce35bbe438add312cf7d155e527ee49bed62ee9b58d0cd526","markerVerified":true},"ADR-094":{"sha256":"1d2225e7422f8a2d47d39100324d5e4ac2d29c55e8e72b02f5e4a7a113d45be2","markerVerified":true},"G1":{"sha256":"2bc49c38b14d43a0329bf5d84913528851ef1c48ab32b8c8c1c40f83c062fc7f","markerVerified":true},"G3":{"sha256":"442839dca2d6177f2567dccaf1f48306c304cbca0659c477501604289f7ad5a6","markerVerified":true},"G4":{"sha256":"12fce07f6458aff5db210b0ba50104fa9b2dd52c85b5e9071b48c2899451c631","markerVerified":true},"G6":{"sha256":"84a6159b384b8118f0beaa1089c417cab6d1116cd77d3882a607715ef7679ea8","markerVerified":true},"G7-gnn":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-rvf":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-mut":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-att":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-gvb":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G2":{"sha256":"9f751aaee838a85e7b2371bbd73dccb5cb89c6b7751496b18d33d8b8a559de19","markerVerified":true},"CAP-MCP-agent-tools":{"sha256":"a182a61809b5480e9eb4139ed8fa3b8e471201d338be4e086578b4e2e325302a","markerVerified":true},"CAP-MCP-agentdb-tools":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"CAP-MCP-analyze-tools":{"sha256":"d665ca78dcb753e7803d37a331ae363ba5e4fea0c90e828171d264a425a638da","markerVerified":true},"CAP-MCP-autopilot-tools":{"sha256":"1f1dcf3c7660b9ab66df49bacfdf2c7f5a883554d98b416a2780d5226e643df2","markerVerified":true},"CAP-MCP-browser-tools":{"sha256":"5ea5f63c99ee22bccb6fbd4d872e44f47ec7f0ad14ceed4f18014b95f94f75f7","markerVerified":true},"CAP-MCP-claims-tools":{"sha256":"89908d601a21e1a0dca0bd611af61b1d2150010f6015216849122775e6940808","markerVerified":true},"CAP-MCP-config-tools":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"CAP-MCP-coordination-tools":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"CAP-MCP-daa-tools":{"sha256":"2beb8ec07d784cf7f1a61b4cd2090a8e65934893c2a31a3afcd406774d2a8537","markerVerified":true},"CAP-MCP-embeddings-tools":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"CAP-MCP-github-tools":{"sha256":"951b66082ba309505eaf4e3588104681f5581ec5e0c8d6daf6a7befac596db37","markerVerified":true},"CAP-MCP-guidance-tools":{"sha256":"856f7b0439a4dfdafab88589faf5cbe42c8fbd4004532fe507ec3e3e42af9e12","markerVerified":true},"CAP-MCP-hive-mind-tools":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"CAP-MCP-hooks-tools":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"CAP-MCP-memory-tools":{"sha256":"37d929df892035fe94a48cd43a074c9c773e9dc031ab56d9dd33cdbf21a87e39","markerVerifiLine truncated
{"v":1,"commit":"7633c2952b9ebdd771c1c93ec16bc6dac90dc1a8","issuedAt":"2026-05-12T04:50:17.791Z","branch":"fix/1921-hook-cli-resilience","os":"macos","manifestHash":"6350c72e79ca3eb38dac412fd254ba1e7230649f9031e899fd4c24310dbb69c8","summary":{"totalFixes":112,"verified":112,"missing":0},"fixes":{"F1":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F2":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F3":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"F4":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"F5":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"F6":{"sha256":"159365d8f876d52b94a3c1420e9ac3e6da442a4d0fa0bcd6de292b6282113cee","markerVerified":true},"F7":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"F8":{"sha256":"8151d83f6b1abe7a9139db5c9d884c42c1b3faf986dc712c0fbd43a22af39f51","markerVerified":true},"F9":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"F10":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"F11":{"sha256":"acb66c459f9eb3a34686567b5d4f9bd834b4e874e9a1229256baebfd15c4ea5c","markerVerified":true},"F12":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"#1697":{"sha256":"14345e0180e5c4649b5a2169b094c8e05d97c54fe79902c8eef0ebf7c18715fb","markerVerified":true},"#1698":{"sha256":"2cb57b6fb38bb4722eebd169f4b6056f1b6f69ba0adde9978bcd9e03f83d43ab","markerVerified":true},"#1691":{"sha256":"6b600ec62ef9a3898fd3c606c23034a10a005c0330d0dac43b29f6d2abc2ec8e","markerVerified":true},"#1721":{"sha256":"862f40e5c7b45a0ce35bbe438add312cf7d155e527ee49bed62ee9b58d0cd526","markerVerified":true},"ADR-094":{"sha256":"1d2225e7422f8a2d47d39100324d5e4ac2d29c55e8e72b02f5e4a7a113d45be2","markerVerified":true},"G1":{"sha256":"2bc49c38b14d43a0329bf5d84913528851ef1c48ab32b8c8c1c40f83c062fc7f","markerVerified":true},"G3":{"sha256":"442839dca2d6177f2567dccaf1f48306c304cbca0659c477501604289f7ad5a6","markerVerified":true},"G4":{"sha256":"12fce07f6458aff5db210b0ba50104fa9b2dd52c85b5e9071b48c2899451c631","markerVerified":true},"G6":{"sha256":"84a6159b384b8118f0beaa1089c417cab6d1116cd77d3882a607715ef7679ea8","markerVerified":true},"G7-gnn":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-rvf":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-mut":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-att":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G7-gvb":{"sha256":"12ca47650a812c66fb5efbbc3b6cdf527ca74ee787f27c9556514492de9d07cd","markerVerified":true},"G2":{"sha256":"9f751aaee838a85e7b2371bbd73dccb5cb89c6b7751496b18d33d8b8a559de19","markerVerified":true},"CAP-MCP-agent-tools":{"sha256":"a182a61809b5480e9eb4139ed8fa3b8e471201d338be4e086578b4e2e325302a","markerVerified":true},"CAP-MCP-agentdb-tools":{"sha256":"666141cf59c2e75c9f65fe50eff85076a96d820bddceaba79c0b67a4469b3bb5","markerVerified":true},"CAP-MCP-analyze-tools":{"sha256":"d665ca78dcb753e7803d37a331ae363ba5e4fea0c90e828171d264a425a638da","markerVerified":true},"CAP-MCP-autopilot-tools":{"sha256":"1f1dcf3c7660b9ab66df49bacfdf2c7f5a883554d98b416a2780d5226e643df2","markerVerified":true},"CAP-MCP-browser-tools":{"sha256":"5ea5f63c99ee22bccb6fbd4d872e44f47ec7f0ad14ceed4f18014b95f94f75f7","markerVerified":true},"CAP-MCP-claims-tools":{"sha256":"89908d601a21e1a0dca0bd611af61b1d2150010f6015216849122775e6940808","markerVerified":true},"CAP-MCP-config-tools":{"sha256":"0c68ebca896806de2aa052ef44a0de13e9df3becef44721857c7c99567403d80","markerVerified":true},"CAP-MCP-coordination-tools":{"sha256":"ae4b5e05735741b01cbc6c9e4af3953a02b4ebf78faf78fe06f9130420f4f301","markerVerified":true},"CAP-MCP-daa-tools":{"sha256":"2beb8ec07d784cf7f1a61b4cd2090a8e65934893c2a31a3afcd406774d2a8537","markerVerified":true},"CAP-MCP-embeddings-tools":{"sha256":"48032e13d70927a6448d75e04f8f055b0268aaada8bef3e6926bf3acafd493fd","markerVerified":true},"CAP-MCP-github-tools":{"sha256":"951b66082ba309505eaf4e3588104681f5581ec5e0c8d6daf6a7befac596db37","markerVerified":true},"CAP-MCP-guidance-tools":{"sha256":"856f7b0439a4dfdafab88589faf5cbe42c8fbd4004532fe507ec3e3e42af9e12","markerVerified":true},"CAP-MCP-hive-mind-tools":{"sha256":"8482312f5b447ae6008d13b0873945f026bf540e559195cf961b948a94520678","markerVerified":true},"CAP-MCP-hooks-tools":{"sha256":"93f4d2f94710eed90e0bcc9b8823e91f1a4b894221fae1972c1f6745d90b622d","markerVerified":true},"CAP-MCP-memory-tools":{"sha256":"37d929df892035fe94a48cd43a074c9c773e9dc031ab56d9dd33cdbLine truncated
+32 -16
View File
@@ -1,9 +1,9 @@
{
"manifest": {
"schema": "ruflo-witness/v1",
"issuedAt": "2026-05-12T04:44:05.086Z",
"gitCommit": "31f22ff9a92154952b8d9e417a25034bdf08de08",
"branch": "HEAD",
"issuedAt": "2026-05-12T04:50:17.791Z",
"gitCommit": "7633c2952b9ebdd771c1c93ec16bc6dac90dc1a8",
"branch": "fix/1921-hook-cli-resilience",
"os": "macos",
"releases": {
"ruflo": "3.7.0-alpha.26",
@@ -12,8 +12,8 @@
"@claude-flow/memory": "3.0.0-alpha.15"
},
"summary": {
"totalFixes": 110,
"verified": 110,
"totalFixes": 112,
"verified": 112,
"missing": 0
},
"fixes": [
@@ -657,14 +657,6 @@
"marker": "ctx.flags.file || ctx.args[0]",
"markerVerified": true
},
{
"id": "#1862",
"desc": "ruflo-core PostToolUse hooks call documented CLI flags (-c/-s/-e, -f/-s) instead of bogus --format true",
"file": "plugins/ruflo-core/hooks/hooks.json",
"sha256": "c74a26044c1d283589696590f652ef21f4c65613f9ff5eb015127b1819d37fe7",
"marker": "hooks post-edit -f \\\"$FILE\\\" -s true",
"markerVerified": true
},
{
"id": "ADR-101-C",
"desc": "Federation policy-engine wires claim-event + agent-handoff message types into CLAIMS_FOR_MESSAGE_TYPE (unblocked Build V3 after 3+ days of failures)",
@@ -896,15 +888,39 @@
"sha256": "e8bcf68635d45764e46be0c80647781134f8f437b395b949a95e56cce717a9e3",
"marker": "formula: 'src/formula/index.ts'",
"markerVerified": true
},
{
"id": "#1921",
"desc": "Plugin hooks no longer do a bare `npx <pkg>@alpha hooks …` on every PreToolUse/PostToolUse/Stop fire — they invoke scripts/ruflo-hook.sh, which prefers a locally-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline`, and ALWAYS exits 0 so a CLI/install crash (e.g. arborist `Invalid Version` on npm 10.8.x) never surfaces a hook error in Claude Code or wastes a cold-cache reinstall per turn. CI guard: scripts/audit-hook-commands.mjs (fails on bare-npx-without-prefer-offline / non-guarded CLI invocation) wired into v3-ci.yml `hook-command-audit` + added to witness-verify needs[].",
"file": "scripts/audit-hook-commands.mjs",
"sha256": "6f2702c59f1cb2438533ee4e7b2648dc2c2076334c60e5ca4dc30db5a0c99c5b",
"marker": "NONFATAL_RE",
"markerVerified": true
},
{
"id": "#1921-shim",
"desc": "scripts/ruflo-hook.sh — resilient invoker shipped in each plugin (.claude-plugin/, plugin/, plugins/ruflo-core/): prefers a local `ruflo`/`claude-flow` binary, else `npx --prefer-offline --yes ruflo@alpha`, always `exit 0`. stdin (hook event JSON) passes through unchanged. Companion to #1921.",
"file": "plugins/ruflo-core/scripts/ruflo-hook.sh",
"sha256": "08d576ea4938dbb7ac6c5072b2463ddf3299802801cf1d0110a1244ebe0868ea",
"marker": "npx --prefer-offline --yes ruflo@alpha hooks",
"markerVerified": true
},
{
"id": "#1862",
"desc": "ruflo-core PostToolUse hooks call documented CLI flags (-c/-s/-e, -f/-s) instead of bogus --format true. (#1921 moved the invocation behind scripts/ruflo-hook.sh — the documented-flag form is preserved.)",
"file": "plugins/ruflo-core/hooks/hooks.json",
"sha256": "3c99ed6c845a3ff44d4e012081307a4d2af3aaf8a1025dcdb125bff1eab2a661",
"marker": "post-edit -f \\\"$FILE\\\" -s true",
"markerVerified": true
}
]
},
"integrity": {
"manifestHashAlgo": "sha256",
"manifestHash": "a081f02f53f33c5a008cd06177cb1f8a4de08ac7183312877d57c0ca95018192",
"manifestHash": "6350c72e79ca3eb38dac412fd254ba1e7230649f9031e899fd4c24310dbb69c8",
"signatureAlgo": "ed25519",
"publicKey": "1d90203273675541aa963e769617d91c6188b5d0d062b8caa0f48f886ba84cf8",
"signature": "a470dd63ff659dcd2775a9bd932fecb67fb7c9b723d6ce2938b8c6f8e1eb37724f0bd073a0d14aa467e1dafc442ff9a179a3f8016df0aea11327b92a1ef01e05",
"publicKey": "0a6f6225cf543ffefd2c273bb9a9689be54c4147c2d3ed5c8b2ebbabdfe4a1f2",
"signature": "bb0a47361f77e47a26cf7722c25098b793a39e017733eaa9d0ed2890cf7cdbde35495c7933cc49e21006e23998a70a915a712266da2ab32f9af9d954d4c30e0b",
"seedDerivation": "sha256(gitCommit + ':ruflo-witness/v1')"
}
}
+14 -2
View File
@@ -15,9 +15,9 @@
},
{
"id": "#1862",
"desc": "ruflo-core PostToolUse hooks call documented CLI flags (-c/-s/-e, -f/-s) instead of bogus --format true",
"desc": "ruflo-core PostToolUse hooks call documented CLI flags (-c/-s/-e, -f/-s) instead of bogus --format true. (#1921 moved the invocation behind scripts/ruflo-hook.sh — the documented-flag form is preserved.)",
"file": "plugins/ruflo-core/hooks/hooks.json",
"marker": "hooks post-edit -f \\\"$FILE\\\" -s true"
"marker": "post-edit -f \\\"$FILE\\\" -s true"
},
{
"id": "ADR-101-C",
@@ -192,6 +192,18 @@
"desc": "plugin-gastown-bridge \u2014 package.json `exports` advertised ./dist/index.mjs (+ ./formula, ./convoy subpaths) that the build never emitted, so those import specifiers 404'd in the published tarball. Fix: tsup.config.ts builds the formula/convoy entries (previously commented out), and package.json exports/main/module point at the actually-emitted .js/.cjs filenames. Validated by the plugin-package-audit CI guard (check D).",
"file": "v3/plugins/gastown-bridge/tsup.config.ts",
"marker": "formula: 'src/formula/index.ts'"
},
{
"id": "#1921",
"desc": "Plugin hooks no longer do a bare `npx <pkg>@alpha hooks \u2026` on every PreToolUse/PostToolUse/Stop fire \u2014 they invoke scripts/ruflo-hook.sh, which prefers a locally-installed `ruflo`/`claude-flow` binary, falls back to `npx --prefer-offline`, and ALWAYS exits 0 so a CLI/install crash (e.g. arborist `Invalid Version` on npm 10.8.x) never surfaces a hook error in Claude Code or wastes a cold-cache reinstall per turn. CI guard: scripts/audit-hook-commands.mjs (fails on bare-npx-without-prefer-offline / non-guarded CLI invocation) wired into v3-ci.yml `hook-command-audit` + added to witness-verify needs[].",
"file": "scripts/audit-hook-commands.mjs",
"marker": "NONFATAL_RE"
},
{
"id": "#1921-shim",
"desc": "scripts/ruflo-hook.sh \u2014 resilient invoker shipped in each plugin (.claude-plugin/, plugin/, plugins/ruflo-core/): prefers a local `ruflo`/`claude-flow` binary, else `npx --prefer-offline --yes ruflo@alpha`, always `exit 0`. stdin (hook event JSON) passes through unchanged. Companion to #1921.",
"file": "plugins/ruflo-core/scripts/ruflo-hook.sh",
"marker": "npx --prefer-offline --yes ruflo@alpha hooks"
}
]
}