mirror of
https://github.com/actualbudget/actual.git
synced 2026-11-09 10:45:04 -06:00
* [AI] Fail agent hooks with an actionable error when jq is missing The shared agent-hook scripts all parse their payload with jq but never checked it exists. A missing jq made git-guard.sh block every Bash call with a misleading 'could not parse the hook payload' message, while other hooks silently failed open and skipped their checks (issue #8629). Add require_jq to common.sh — called by every hook before its first jq use — so a missing jq fails closed with a clear install message, distinct from a malformed-payload error. The script name in the message is derived from $0 rather than passed by each caller. The Cursor adapters emit a static JSON deny (their deny() helper itself needs jq to build JSON) or an advisory where blocking isn't possible, and AGENTS.md now documents the prerequisite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * [AI] Address review: advisory wording for PostToolUse hooks, hook tests PostToolUse hooks (format-edited-file, prefer-one-component) run after the edit already happened, so a missing jq now reports 'Agent hook skipped' instead of claiming a block. Exit 2 stays: it is the only exit code that feeds stderr back to the agent. Add scripts/agent-hooks/test-hooks.sh, a standalone runnable check covering the missing-jq path for every hook plus malformed-JSON, missing-field, and guard-behavior cases, and soften the release-note verb. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * [AI] Remove standalone hook test script Not wired into CI, so it only served as a manual check; the hook behavior was verified by hand and the script isn't worth maintaining. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
33 lines
1.5 KiB
Bash
33 lines
1.5 KiB
Bash
#!/bin/sh
|
|
# Shared helpers for the agent-hook scripts. Source this file; don't execute it.
|
|
|
|
# Every hook parses its stdin payload with jq — a hard prerequisite. Call this
|
|
# before the first jq use so a missing jq fails with an actionable message,
|
|
# distinct from a malformed-payload error. PreToolUse hooks get a "Blocked:"
|
|
# message (exit 2 blocks the call); PostToolUse hooks pass "advisory" — the
|
|
# tool call already ran, so the message reports the skipped hook instead of
|
|
# claiming a block. Exit 2 stays in both modes: it is the only exit code that
|
|
# feeds stderr back to the agent rather than dropping it.
|
|
require_jq() {
|
|
command -v jq >/dev/null 2>&1 && return 0
|
|
if [ "${1:-}" = advisory ]; then
|
|
echo "Agent hook skipped: 'jq' is required but was not found on PATH. Install jq (https://jqlang.org). (scripts/agent-hooks/${0##*/})" >&2
|
|
else
|
|
echo "Blocked: the agent hooks require 'jq', which was not found on PATH. Install jq (https://jqlang.org) and retry. (scripts/agent-hooks/${0##*/})" >&2
|
|
fi
|
|
exit 2
|
|
}
|
|
|
|
# Resolve the repo root regardless of which agent invoked the hook.
|
|
# Optional $1: a directory hint for the `git` fallback (e.g. an edited file's dir).
|
|
resolve_repo_root() {
|
|
if [ -n "${CLAUDE_PROJECT_DIR:-}" ]; then
|
|
printf '%s\n' "$CLAUDE_PROJECT_DIR"
|
|
return 0
|
|
fi
|
|
_hint=${1:-.}
|
|
_root=$(git -C "$_hint" rev-parse --show-toplevel 2>/dev/null) || _root=
|
|
[ -n "$_root" ] || _root=$(CDPATH= cd "$(dirname "$0")/../.." && pwd)
|
|
printf '%s\n' "$_root"
|
|
}
|