diff --git a/scripts/rename-checkout.sh b/scripts/rename-checkout.sh index 9243aed..69dbbc7 100755 --- a/scripts/rename-checkout.sh +++ b/scripts/rename-checkout.sh @@ -24,6 +24,22 @@ # /healthz AND demands a FRESH "bridged listening" log line dated after the restart, anchored # to a line-count marker taken before anything moved. # +# Three more surfaces hold the old path but this script REPORTS them and never rewrites them. +# That is a decision, not an oversight: +# +# A. ~/.claude.json — Claude Code's GLOBAL config for every project on this machine (the +# `projects` map keys projects by their absolute path). It is written by live sessions while +# this script could run, and one bad edit there breaks every project on the machine, not just +# this repo. The entry holds trust (`hasTrustDialogAccepted`), onboarding state, +# `enabledMcpjsonServers`, `allowedTools` and `lastSessionId`. +# B. ~/.config/herdr/session.json — live session records of a RUNNING process. Rewriting it +# underneath herdr corrupts its state. +# C. JetBrains options (recentProjects.xml, trusted-paths.xml under any IntellIJIDEA* version) — +# the IDE rewrites these itself when the project is reopened at the new path, so editing them +# by hand is both unnecessary and racy with a possibly-running IDE. +# +# For each of the three, --check prints the exact manual follow-up instead of fixing it. +# # Usage: # scripts/rename-checkout.sh --check # report what holds the old path; changes nothing # scripts/rename-checkout.sh # stop daemon, move everything, restart, verify @@ -45,6 +61,12 @@ OUT_NAME="bridged.out" CC_INSTANCE="ltms" CC_PROJECTS="$HOME/.ccs/instances/$CC_INSTANCE/projects" +# Report-only surfaces (see header, items A-C) — never rewritten by apply mode. +CLAUDE_JSON="$HOME/.claude.json" +HERDR_SESSION="$HOME/.config/herdr/session.json" +JETBRAINS_ROOT="$HOME/Library/Application Support/JetBrains" +JETBRAINS_FILES=(recentProjects.xml trusted-paths.xml) + LAUNCHD_LABEL='dev.ltms.bridged' LAUNCHD_PLIST="$HOME/Library/LaunchAgents/$LAUNCHD_LABEL.plist" @@ -104,6 +126,88 @@ report_hits() { fi } +# --------------------------------------------------------------------------- +# Report-only surfaces (header items A-C). Counted here, NEVER rewritten by +# apply mode — the header comment explains why each is left alone. Both +# --check (section 6) and apply mode's closing summary call this, so the two +# reports can never drift apart. +# --------------------------------------------------------------------------- + +count_old_path_in_file() { # -> stdout: hit count (0 if file absent) + if [ ! -f "$1" ]; then echo 0; return; fi + # "no match" makes grep exit 1 and, under `set -o pipefail`, the whole pipeline too — so the + # assignment needs its own `|| true`; wc still prints the correct 0. + local n + n="$(grep -oF -- "$2" "$1" 2>/dev/null | wc -l | tr -d ' ')" || true + printf '%s' "${n:-0}" +} + +report_only_surfaces() { + local n + + # A. Claude Code global config — the per-project entry keyed by absolute path. + if [ -f "$CLAUDE_JSON" ]; then + n="$(count_old_path_in_file "$CLAUDE_JSON" "$OLD_PATH")" + KEY="unknown" + if command -v python3 >/dev/null 2>&1; then + KEY="$(python3 -c 'import json,sys +d = json.load(open(sys.argv[1])) +print("present" if sys.argv[2] in d.get("projects", {}) else "absent")' \ + "$CLAUDE_JSON" "$OLD_PATH" 2>/dev/null)" || KEY="unknown" + fi + warn "A. $CLAUDE_JSON — old-path occurrences: $n; projects[\"$OLD_PATH\"] entry: $KEY" + echo " holds trust/onboarding state, enabledMcpjsonServers, allowedTools, lastSessionId." + echo " FOLLOW-UP: quit every Claude Code session first (this file is rewritten on exit)," + echo " then rename the key projects[\"$OLD_PATH\"] -> projects[\"$NEW_PATH\"], keeping the" + echo " entry's contents. If skipped: the trust dialog appears once at the new path and" + echo " .mcp.json servers start disabled until re-enabled." + else + ok "A. $CLAUDE_JSON absent — nothing to report" + fi + + # B. herdr live session records. + n="$(count_old_path_in_file "$HERDR_SESSION" "$OLD_PATH")" + if [ "$n" -gt 0 ]; then + warn "B. $HERDR_SESSION — $n occurrence(s) of the old path (live herdr state)" + echo " FOLLOW-UP: stop the daemon/herdr FIRST, then edit the file (or leave it: sessions" + echo " started from the new checkout afterwards use the new path). Never edit while herdr runs." + elif [ -f "$HERDR_SESSION" ]; then + ok "B. $HERDR_SESSION does not reference the old path" + else + ok "B. $HERDR_SESSION absent" + fi + + # C. JetBrains recent projects + trusted paths, any IntelliJIdea version. + # JetBrains stores these paths as its own "$USER_HOME$/..." MACRO, not as the literal absolute + # path, so a plain absolute-path grep reports 0 hits on files that are in fact full of them. + # Count both forms; report the macro form when that is where the hits live. + FOUND=0 + JET_MACRO='$USER_HOME$'"${OLD_PATH#"$HOME"}" # e.g. $USER_HOME$/LTMS/claude-bridge + if [ -d "$JETBRAINS_ROOT" ]; then + for VDIR in "$JETBRAINS_ROOT"/IntelliJIdea*/; do + [ -d "$VDIR" ] || continue + VDIR="${VDIR%/}" + for F in "${JETBRAINS_FILES[@]}"; do + FPATH="$VDIR/options/$F" + ABS_N="$(count_old_path_in_file "$FPATH" "$OLD_PATH")" + MACRO_N="$(count_old_path_in_file "$FPATH" "$JET_MACRO")" + n=$((ABS_N + MACRO_N)) + if [ "$n" -gt 0 ]; then + warn "C. ${FPATH#"$HOME"/} — $n occurrence(s) of the old path ($MACRO_N as the \${USER_HOME} macro, $ABS_N literal)" + FOUND=$((FOUND + 1)) + fi + done + done + fi + if [ "$FOUND" -eq 0 ]; then + ok "C. no JetBrains IntelliJIdea* options file references the old path" + else + echo " FOLLOW-UP: open the project at $NEW_PATH in IntelliJ — the IDE rewrites" + echo " recentProjects.xml and trusted-paths.xml itself (it asks to trust once). Editing" + echo " these by hand is unnecessary and racy with a running IDE." + fi +} + # ---------------------------------------------------------------------- --check if [ "$CHECK_ONLY" = 1 ]; then @@ -189,6 +293,9 @@ if [ "$CHECK_ONLY" = 1 ]; then warn "no daemon running" fi + say "6. report-only surfaces (counted, NEVER rewritten — see header items A-C)" + report_only_surfaces + say "--check done: nothing changed" exit 0 fi @@ -370,5 +477,8 @@ fi scan_old_path_in "$CC_PROJECTS" | head -5 | sed 's/^/ /' || true echo " (session transcripts quote the old cwd — history, left untouched)" +say "left alone on purpose — report-only surfaces and their manual follow-up" +report_only_surfaces + echo echo " Next: reconnect leads/members to the renamed checkout and re-check with --check."