From c3e39b7a968d9e08ffd0c80a7a6ed2c5c6f930a0 Mon Sep 17 00:00:00 2001 From: rootiest Date: Wed, 17 Jun 2026 22:39:18 -0400 Subject: [PATCH] fix(agents): chain AGENTS git hooks to global core.hooksPath The local core.hooksPath override set by agents-init shadowed the user's global hooks (ggshield, Git LFS) since git honors only one hooksPath. Each shim now execs the global/system hook of the same name after running version-bump, so global hooks still run after version increment. Bumped the agents-tools version marker to 2 so existing AGENTS repos refresh. --- docs/fish-config.md | 10 +++++++--- functions/agents-init.fish | 7 +++++-- scripts/agents-tools/hooks/pre-commit | 17 ++++++++++++++--- scripts/agents-tools/hooks/prepare-commit-msg | 17 ++++++++++++++--- scripts/agents-tools/version-bump | 2 +- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/docs/fish-config.md b/docs/fish-config.md index 232c735..ee6f848 100644 --- a/docs/fish-config.md +++ b/docs/fish-config.md @@ -1148,9 +1148,13 @@ Add -i (interactive confirmation) to destructive commands: every commit: MINOR (resetting PATCH) when the tracked directory set changes, PATCH otherwise; MAJOR is manual-only. A prepare-commit-msg hook appends "(vX.Y.Z)" to the commit subject. Downstream tooling can read - AGENTS/.version - a changed MINOR field signals a structure change. The - script and hooks are shipped from scripts/agents-tools/ and refreshed when - their version marker is stale. + AGENTS/.version - a changed MINOR field signals a structure change. Because + core.hooksPath is a single setting, the local override would otherwise + shadow your global hooks; after bumping the version, each shim chains + (execs) to the global/system core.hooksPath hook of the same name so global + pre-commit / prepare-commit-msg hooks (e.g. ggshield, Git LFS) still run. + The script and hooks are shipped from scripts/agents-tools/ and refreshed + when their version marker is stale. agents-init agents-init --agents diff --git a/functions/agents-init.fish b/functions/agents-init.fish index bca1ba4..a44acfe 100644 --- a/functions/agents-init.fish +++ b/functions/agents-init.fish @@ -36,8 +36,11 @@ # core.hooksPath: a pre-commit hook bumps AGENTS/.version on every commit # (MINOR when the tracked directory set changes, PATCH otherwise; MAJOR is # manual-only), and a prepare-commit-msg hook appends "(vX.Y.Z)" to the -# commit subject. The script/hooks are version-managed from -# scripts/agents-tools/ and refreshed when their marker is stale. +# commit subject. Each shim then chains (execs) to the global/system +# core.hooksPath hook of the same name, so this local override does not +# shadow global hooks (e.g. ggshield, Git LFS). The script/hooks are +# version-managed from scripts/agents-tools/ and refreshed when their marker +# is stale. # # With no flags, runs both --agents and --plugins setup. At the end of # every invocation, commits any uncommitted changes in the AGENTS/ sub-repo diff --git a/scripts/agents-tools/hooks/pre-commit b/scripts/agents-tools/hooks/pre-commit index ff3f604..687879c 100755 --- a/scripts/agents-tools/hooks/pre-commit +++ b/scripts/agents-tools/hooks/pre-commit @@ -1,7 +1,18 @@ #!/usr/bin/env bash -# agents-tools-version: 1 -# Delegates to the repo's committed .agents-tools/version-bump. Guarded so a -# missing script or failed rev-parse never blocks the commit (always exit 0). +# agents-tools-version: 2 +# Runs the committed .agents-tools/version-bump, then chains to the user's +# global/system git hook (core.hooksPath) so ggshield, LFS, etc. still run. +# agents-init's local core.hooksPath override would otherwise shadow them. +# Guarded so a missing script or failed rev-parse never blocks the commit; +# only the chained global hook can fail it. root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0 [ -x "$root/.agents-tools/version-bump" ] && "$root/.agents-tools/version-bump" precommit + +# Chain to the global/system hook this local override is shadowing. +global_hooks="$(git config --global core.hooksPath 2>/dev/null)" +[ -z "$global_hooks" ] && global_hooks="$(git config --system core.hooksPath 2>/dev/null)" +if [ -n "$global_hooks" ]; then + global_hooks="${global_hooks/#\~/$HOME}" # git stores ~ verbatim + [ -x "$global_hooks/pre-commit" ] && exec "$global_hooks/pre-commit" "$@" +fi exit 0 diff --git a/scripts/agents-tools/hooks/prepare-commit-msg b/scripts/agents-tools/hooks/prepare-commit-msg index 57aed4a..161ac70 100755 --- a/scripts/agents-tools/hooks/prepare-commit-msg +++ b/scripts/agents-tools/hooks/prepare-commit-msg @@ -1,7 +1,18 @@ #!/usr/bin/env bash -# agents-tools-version: 1 -# Delegates to the repo's committed .agents-tools/version-bump. Guarded so a -# missing script or failed rev-parse never blocks the commit (always exit 0). +# agents-tools-version: 2 +# Runs the committed .agents-tools/version-bump, then chains to the user's +# global/system git hook (core.hooksPath) so any global prepare-commit-msg +# still runs. agents-init's local core.hooksPath override would otherwise +# shadow it. Guarded so a missing script or failed rev-parse never blocks the +# commit; only the chained global hook can fail it. root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0 [ -x "$root/.agents-tools/version-bump" ] && "$root/.agents-tools/version-bump" prepmsg "$1" + +# Chain to the global/system hook this local override is shadowing. +global_hooks="$(git config --global core.hooksPath 2>/dev/null)" +[ -z "$global_hooks" ] && global_hooks="$(git config --system core.hooksPath 2>/dev/null)" +if [ -n "$global_hooks" ]; then + global_hooks="${global_hooks/#\~/$HOME}" # git stores ~ verbatim + [ -x "$global_hooks/prepare-commit-msg" ] && exec "$global_hooks/prepare-commit-msg" "$@" +fi exit 0 diff --git a/scripts/agents-tools/version-bump b/scripts/agents-tools/version-bump index 72a950a..62dd023 100755 --- a/scripts/agents-tools/version-bump +++ b/scripts/agents-tools/version-bump @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# agents-tools-version: 1 +# agents-tools-version: 2 # Copyright (C) 2026 Rootiest # SPDX-License-Identifier: AGPL-3.0-or-later #