#!/usr/bin/env bash set -Eeuo pipefail # Setup-hook wrapper around the bin/ implementation managed-files.sh -- runs that # util (it does not change it) and records the outcome. Wired for the claude-config # project only, by that project's .claude/settings.json (matcher-less, so it fires # on both init and maintenance). # - runs the util in the project cwd; it classifies every file as git-tracked / # Syncthing-synced / local / both and prints the four counts plus full lists. # - writes the full text report and a JSON record (the four counts + the report # path) to the project root as machine-local dotfiles (.managed-files-report.txt # / .managed-files-result.json) -- gitignored (local) # - GIT_DIR/GIT_WORK_TREE are stripped before running the util: if they leaked in # from a dotfiles shell they would retarget the util's `git ls-files` at the # wrong repo (they override even `git -C`). # - Setup-hook streams/exit are swallowed by the harness (see the setup-hook-no- # feedback memory finding), so the JSON record file is the durable channel; stream # conventions kept anyway: success -> stdout + exit 0, failure -> stderr + exit 2. self=$(realpath -- "${BASH_SOURCE[0]}") util="$(dirname -- "$(dirname -- "$self")")/bin/managed-files.sh" input=$(cat) cwd=$(jq --raw-output '.cwd // empty' <<<"$input" 2>/dev/null) || cwd="" [ -n "$cwd" ] || cwd=$PWD report="$cwd/.managed-files-report.txt" result="$cwd/.managed-files-result.json" # Persist this run's outcome as a JSON record (machine-local), written atomically. # - $1 status (ok|error); on ok the count vars are set, on error $2 is the message. # - best-effort, so a write failure never aborts the hook. write_result() { jq --null-input \ --arg status "$1" --arg message "${2:-}" \ --arg report "$report" --arg cwd "$cwd" \ --arg time "$(date --iso-8601=seconds)" \ --argjson tracked "${tracked:-null}" --argjson synced "${synced:-null}" \ --argjson local "${local:-null}" --argjson both "${both:-null}" \ '{hookEventName: "Setup", status: $status, tracked: $tracked, synced: $synced, local: $local, both: $both, reportPath: $report, cwd: $cwd, time: $time} | if $message == "" then . else . + {message: $message} end' \ >"$result.tmp" 2>/dev/null && mv --force -- "$result.tmp" "$result" 2>/dev/null || return 0 } abort() { write_result error "$*" echo "$*" >&2 exit 2 } # Any unexpected failure becomes this run's recorded result, then exits 2. trap 'rc=$?; trap - ERR; abort "line $LINENO (rc $rc): $BASH_COMMAND"' ERR # Run the util in the project dir (with a clean git env), capturing its report. err_file=$(mktemp) if ! out=$(cd "$cwd" && env --unset=GIT_DIR --unset=GIT_WORK_TREE bash "$util" 2>"$err_file"); then msg=$(tr '\n' ' ' <"$err_file") rm --force -- "$err_file" abort "report util failed: $msg" fi rm --force -- "$err_file" printf '%s\n' "$out" >"$report.tmp" && mv --force -- "$report.tmp" "$report" # Parse the four counts from the report header lines ("tracked: N", ...). count_of() { awk -v k="$1:" '$1 == k { print $2; exit }' <<<"$out"; } tracked=$(count_of tracked) synced=$(count_of synced) local=$(count_of local) both=$(count_of both) write_result ok cat "$result" exit 0