feat(@scripts): add persistent session name index

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-17 20:34:20 -07:00
parent 0590b8b07d
commit 6e67a5aa57

View file

@ -187,9 +187,19 @@ _filter_sessions_to_uuids() {
| awk -F'\t' -v r="^($_re)$" '$3 ~ r'
}
# Build a `host\tuuid\tname` table of every session that has a display name
# set via `claude -n <name>`. Used to enrich the resume picker so names show
# next to each row.
# Durable name index — persistent record of (host, uuid, name) tuples for
# every session display name we've ever observed. Lives on plum, survives
# remote-host reboots. Source of truth for name_search_on alongside the
# live per-pid sessions/*.json files.
_NAME_INDEX=${XDG_DATA_HOME:-$HOME/.local/share}/rclaude/named-sessions.tsv
mkdir -p "$(dirname "$_NAME_INDEX")" 2>/dev/null
[ -f "$_NAME_INDEX" ] || touch "$_NAME_INDEX" 2>/dev/null
# Build a `host\tuuid\tname` table of every session display name we know
# about. Combines live observation (ssh into each host, scan
# ~/.claude/sessions/*.json) with the durable on-disk index — so even after
# a remote reboot wipes the per-pid metadata, names we saw previously stay
# searchable. Live observations are upserted into the index every call.
build_name_map() {
_py='import json, os, glob
for f in glob.glob(os.path.expanduser("~/.claude/sessions/*.json")):
@ -198,6 +208,8 @@ for f in glob.glob(os.path.expanduser("~/.claude/sessions/*.json")):
sid = d.get("sessionId") or ""
name = d.get("name") or ""
if sid and name: print(f"{sid}\t{name}")'
# Live pass: collect current observations into a temp file.
_live=$(mktemp /tmp/rclaude-namemap-live.XXXXXX 2>/dev/null || echo /tmp/rclaude-namemap-live.$$)
scan_hosts | while IFS= read -r _h; do
if is_local "$_h"; then
python3 -c "$_py" 2>/dev/null
@ -205,8 +217,19 @@ for f in glob.glob(os.path.expanduser("~/.claude/sessions/*.json")):
ssh -o BatchMode=yes -o ConnectTimeout=3 "$_h" "python3 -" 2>/dev/null <<PYEOF || true
$_py
PYEOF
fi | awk -F'\t' -v host="$_h" '{print host "\t" $1 "\t" $2}'
done
fi | awk -F'\t' -v host="$_h" 'NF>=2 {print host "\t" $1 "\t" $2}'
done > "$_live"
# Persist anything new into the durable index. Dedup by (host, uuid)
# keeping the most-recent name we've ever seen (later writes win).
if [ -s "$_live" ]; then
cat "$_NAME_INDEX" "$_live" \
| awk -F'\t' 'NF>=3 { key=$1 SUBSEP $2; row[key]=$0 } END { for (k in row) print row[k] }' \
> "${_NAME_INDEX}.tmp" \
&& mv -f "${_NAME_INDEX}.tmp" "$_NAME_INDEX"
fi
rm -f "$_live"
# Output: every row in the durable index. Picker uses this to enrich rows.
cat "$_NAME_INDEX" 2>/dev/null
}
# Cheap match by session display name (the `claude -n <name>` label, stored in
@ -224,6 +247,7 @@ for f in glob.glob(os.path.expanduser("~/.claude/sessions/*.json")):
name = (d.get("name") or "").lower()
sid = d.get("sessionId") or ""
if pat in name and sid: print(sid)'
# Live pass — per-pid metadata on <host> (vanishes on reboot).
if is_local "$_host"; then
_uuids=$(RCLAUDE_PAT="$_pat" python3 -c "$_py" 2>/dev/null || true)
else
@ -233,7 +257,16 @@ $_py
PYEOF
)
fi
_filter_sessions_to_uuids "$_host" "$_uuids"
# Durable pass — names we've previously seen for THIS host, even if the
# per-pid file is gone now (reboot, claude crash, etc.). Case-insensitive
# substring match on the name column.
_pat_lc=$(printf %s "$_pat" | tr '[:upper:]' '[:lower:]')
_dur_uuids=$(awk -F'\t' -v h="$_host" -v p="$_pat_lc" '
BEGIN { IGNORECASE = 1 }
$1 == h && index(tolower($3), p) > 0 { print $2 }
' "$_NAME_INDEX" 2>/dev/null)
_all_uuids=$(printf '%s\n%s\n' "$_uuids" "$_dur_uuids" | sort -u | grep -v '^$' || true)
_filter_sessions_to_uuids "$_host" "$_all_uuids"
}
# Grep the full content of every Claude session JSONL on <host> for <pat>.