From 51bdec22e74e9120de1be4bcef0eac3f97e4efa2 Mon Sep 17 00:00:00 2001 From: Dai Ha Date: Sun, 23 Aug 2026 06:07:16 +0200 Subject: [PATCH] CB-624: report three more rename surfaces as report-only --check gains section 6 counting ~/.claude.json (the projects entry keyed by the old absolute path), ~/.config/herdr/session.json, and JetBrains recentProjects.xml / trusted-paths.xml across every IntelliJIdea* version. Apply mode's closing summary lists the same three with manual follow-ups. None of the three is rewritten automatically, on purpose: ~/.claude.json is global live Claude Code config, herdr session.json is live process state, and JetBrains rewrites its own files when the project is reopened at the new path. Header comment states the reason for each so it does not read as an oversight. JetBrains stores these paths as its $USER_HOME$ macro rather than a literal absolute path, so the counter matches both forms and says which form the hits used. --- scripts/rename-checkout.sh | 110 +++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) 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."