Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-18
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# agent-claude-add-global-hooks-installer-script-2026-05-18-12-49 (minimal / T1)

Branch: `agent/claude/add-global-hooks-installer-script-2026-05-18-12-49`

Add an opt-in installer that wires guardex's `.githooks/*` into the user's
**global** `core.hooksPath`, so the hooks fire in every existing and future
repo on the machine. Surfaced via `npm run guardex:install-global` — not
`postinstall`, because silently mutating `git config --global` on every
npm install would surprise downstream users.

## Files

- `scripts/install-global-hooks.sh` — new. Idempotent. Refuses to overwrite
an existing `core.hooksPath` set to a different directory.
- `package.json` — adds `"guardex:install-global"` script entry.

## Behavior

Running the installer:

1. `mkdir -p ${XDG_CONFIG_HOME:-$HOME/.config}/git/hooks`
2. Symlinks `pre-commit`, `pre-push`, `post-checkout`, `post-merge` from the
gitguardex repo's `.githooks/` into that dir.
3. Sets `git config --global core.hooksPath` to that dir (only if currently
unset OR already pointing there).

Reverse:

```bash
git config --global --unset core.hooksPath
```

Per-repo opt-out:

```bash
git config core.hooksPath .git/hooks
```

## Handoff

- Handoff: change=`agent-claude-add-global-hooks-installer-script-2026-05-18-12-49`; branch=`agent/claude/add-global-hooks-installer-script-2026-05-18-12-49`; scope=`scripts/install-global-hooks.sh + package.json`; action=`finish via PR`.

## Cleanup

- [ ] Run: `gx branch finish --branch agent/claude/add-global-hooks-installer-script-2026-05-18-12-49 --base main --via-pr --wait-for-merge --cleanup`
- [ ] Record PR URL + `MERGED` state in the completion handoff.
- [ ] Confirm sandbox worktree is gone (`git worktree list`, `git branch -a`).
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"agent:branch:merge": "bash ./scripts/agent-branch-merge.sh",
"agent:cleanup": "gx cleanup",
"agent:hooks:install": "bash ./scripts/install-agent-git-hooks.sh",
"guardex:install-global": "bash ./scripts/install-global-hooks.sh",
"agent:locks:claim": "python3 ./scripts/agent-file-locks.py claim",
"agent:locks:allow-delete": "python3 ./scripts/agent-file-locks.py allow-delete",
"agent:locks:release": "python3 ./scripts/agent-file-locks.py release",
Expand Down
54 changes: 54 additions & 0 deletions scripts/install-global-hooks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Wire guardex's hooks into the user's GLOBAL git config so they fire in
# EVERY existing and future repo on this machine. Idempotent; safe to re-run.
#
# What this does:
# 1. Ensures ~/.config/git/hooks/ exists.
# 2. Symlinks the four guardex hooks (pre-commit, pre-push, post-checkout,
# post-merge) from this repo's .githooks/ into the global hooks dir.
# 3. Points `git config --global core.hooksPath` at it.
#
# Safety:
# - If core.hooksPath is already set globally to a DIFFERENT path, this
# script prints the existing value and exits 0 without overwriting.
# - Repo-local `core.hooksPath` settings override the global one, so a
# single repo can opt out with `git config core.hooksPath .git/hooks`.
# - Reverse with `git config --global --unset core.hooksPath`.
#
# Intended invocation:
# bash ~/Documents/gitguardex/scripts/install-global-hooks.sh
# npm run guardex:install-global

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
HOOKS_SRC="$REPO_ROOT/.githooks"
HOOKS_DST="${XDG_CONFIG_HOME:-$HOME/.config}/git/hooks"

if [[ ! -d "$HOOKS_SRC" ]]; then
echo "[guardex] missing $HOOKS_SRC — run from the gitguardex repo." >&2
exit 1
fi

mkdir -p "$HOOKS_DST"

linked=0
for h in pre-commit pre-push post-checkout post-merge; do
if [[ -f "$HOOKS_SRC/$h" ]]; then
ln -sfn "$HOOKS_SRC/$h" "$HOOKS_DST/$h"
linked=$((linked + 1))
fi
done
echo "[guardex] symlinked $linked hooks → $HOOKS_DST"

current="$(git config --global --get core.hooksPath 2>/dev/null || true)"
if [[ -n "$current" && "$current" != "$HOOKS_DST" ]]; then
echo "[guardex] core.hooksPath already set to: $current"
echo "[guardex] not overwriting. To switch: git config --global core.hooksPath '$HOOKS_DST'"
exit 0
fi

git config --global core.hooksPath "$HOOKS_DST"
echo "[guardex] global core.hooksPath → $HOOKS_DST"
echo "[guardex] disable globally: git config --global --unset core.hooksPath"
echo "[guardex] opt-out one repo: git config core.hooksPath .git/hooks"
Loading