#!/usr/bin/env bash # # Put every file in this repo where the tooling expects it, on any machine. # # git clone git@gitea.officer.dev:pastilhas/claude-mds.git ~/projects/claude-mds # ~/projects/claude-mds/install.sh # # Symlinks, never copies. Two copies drift, and the point of the repo is that an edit lands in git. # Safe to re-run after every pull: a correct link is a no-op. A real file in the way is backed up, # never overwritten in silence. # # --dry-run say what would happen, change nothing # set -euo pipefail REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MANIFEST="$REPO/manifest" CLAUDE_SCRIPTS="${CLAUDE_SCRIPTS:-$HOME/.local/claude-scripts}" HOOKS_DIR="$CLAUDE_SCRIPTS/mask-hooks.d" BIN_DIR="${BIN_DIR:-$HOME/.local/bin}" STAMP="$(date +%Y%m%d-%H%M%S)" DRY=0 [[ ${1:-} == --dry-run ]] && DRY=1 say() { printf ' %-7s %s\n' "$1" "$2"; } run() { (( DRY )) || "$@"; } # Symlink $2 -> $1, refusing to destroy anything that is not already our link. link() { local src=$1 dst=$2 if [[ ! -e $src ]]; then say "MISSING" "$src — not in the repo"; return 1; fi if [[ -L $dst && "$(readlink -f "$dst")" == "$(readlink -f "$src")" ]]; then say "ok" "$dst"; return 0 fi # A real file, or a link somewhere else. It may be the only copy of something hand-written here. if [[ -e $dst || -L $dst ]]; then say "backup" "$dst -> $dst.bak-$STAMP" run mv "$dst" "$dst.bak-$STAMP" fi run mkdir -p "$(dirname "$dst")" run ln -sfn "$src" "$dst" say "link" "$dst" } # `mask-secret` as a COMMAND, not a path — so user/CLAUDE.md can name it and be true everywhere. # # A wrapper rather than a symlink, and that is forced: mask-secret.py finds its hooks at # `Path(__file__).resolve().parent/mask-hooks.d`, and .resolve() follows a symlink back into the repo # — which holds EVERY machine's hooks. The wrapper points MASK_HOOKS_DIR at the ones this machine # actually installed, and still executes the script from the repo, so the code is never copied. install_command() { local script="$REPO/tools/mask-secret.py" [[ -e $script ]] || { say "MISSING" "$script"; return 1; } run mkdir -p "$BIN_DIR" "$HOOKS_DIR" if (( ! DRY )); then cat > "$BIN_DIR/mask-secret" <