Files
ersatztv/.claude/hooks/posttooluse-worktree-marker.sh
T
timothyandClaude Opus 4.8 35e41fdaad
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m1s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 10m13s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
chore(process): #303 H7 worktree-owner guard + complete Wave 1 wiring
Wave 2 hook H7: never commit/merge inside a sibling worktree another
session created (burned us on #289 path-leak + the plumbing-merge
workaround). Ownership = a per-session .claude-worktree-owner marker:
- posttooluse-worktree-marker.sh stamps a worktree with session_id on
  `git worktree add` (parses the <path> arg past -b/-B/--reason flags).
- pretooluse-worktree-guard.sh denies `git commit`/`git merge` whose
  effective dir (resolves `git -C <p>` and leading `cd <p> &&`) is a
  worktree whose marker names a DIFFERENT session. Fail-open: no marker,
  unparsable, or own session -> allow. Main tree + pre-convention
  worktrees are never marked, so unaffected.

Also completes Wave 1's rollout, which committed pretooluse-bash-guard.sh
but left .claude/settings.json and the agent-ram/nav-guard hooks
untracked (so nothing was actually wired). Adds the settings.json that
registers all five hooks (PreToolUse Bash x2, nav, Agent; PostToolUse
Bash) + the .gitignore worktree-marker line, screenshot-scratch rules,
and the decisions.md TOC left uncommitted last session.

All hooks pipe-tested (7 guard cases + 6 marker cases). Refs #303.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 17:01:52 +02:00

38 lines
1.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# PostToolUse / Bash — after a successful `git worktree add`, stamp the new worktree with
# this session's id (.claude-worktree-owner) so pretooluse-worktree-guard.sh (H7) can tell
# a sibling worktree another session created apart from this session's own.
# Fail-safe: any parse trouble → do nothing (the guard stays fail-open without a marker).
set -euo pipefail
input=$(cat)
cmd=$(printf '%s' "$input" | jq -r '.tool_input.command // ""' 2>/dev/null || true)
cwd=$(printf '%s' "$input" | jq -r '.cwd // ""' 2>/dev/null || true)
me=$(printf '%s' "$input" | jq -r '.session_id // ""' 2>/dev/null || true)
printf '%s' "$cmd" | grep -qE 'git[[:space:]]+worktree[[:space:]]+add\b' || exit 0
[ -z "$me" ] && exit 0
[ -z "$cwd" ] && cwd="$PWD"
# Extract the <path> arg of `git worktree add [flags] <path> [<commit-ish>]`.
# Skip flags; skip the values of the value-taking flags (-b/-B/--reason). Worktree paths
# in this repo have no spaces, so whitespace tokenization is safe.
add_args=$(printf '%s' "$cmd" | sed -E 's/.*git[[:space:]]+worktree[[:space:]]+add[[:space:]]+//')
path=""
skip=0
for tok in $add_args; do
if [ "$skip" = 1 ]; then skip=0; continue; fi
case "$tok" in
-b|-B|--reason) skip=1; continue ;;
--) continue ;;
-*) continue ;;
*) path=$(printf '%s' "$tok" | tr -d '"'"'"''); break ;;
esac
done
[ -z "$path" ] && exit 0
case "$path" in /*) abs="$path" ;; *) abs="$cwd/$path" ;; esac
[ -d "$abs" ] || exit 0
# Don't clobber a marker a different session already planted.
[ -f "$abs/.claude-worktree-owner" ] && exit 0
printf '%s\n' "$me" > "$abs/.claude-worktree-owner" 2>/dev/null || true
exit 0