diff --git a/bin/rclaude b/bin/rclaude index 259e821..e4e542c 100755 --- a/bin/rclaude +++ b/bin/rclaude @@ -176,6 +176,28 @@ list_search_on() { list_sessions_on "$1" } +# Grep the full content of every Claude session JSONL on for and +# emit the matching rows in list_sessions_on() format. Used as a fallback when +# the cheap pattern path (first-message snippets + cwd) returns nothing. +deep_search_on() { + _host=$1; _pat=$2 + _q=$(printf %s "$_pat" | sed "s/'/'\\\\''/g") + if is_local "$_host"; then + _files=$(grep -l -F -i -- "$_pat" "$HOME/.claude/projects/"*/*.jsonl 2>/dev/null || true) + else + _files=$(ssh -o BatchMode=yes -o ConnectTimeout=5 "$_host" \ + "grep -l -F -i -- '$_q' \$HOME/.claude/projects/*/*.jsonl 2>/dev/null" 2>/dev/null || true) + fi + [ -z "$_files" ] && return 0 + # Extract bare uuids → alternation regex for awk (single-line, safe). + _re=$(printf '%s\n' "$_files" | awk -F/ '{print $NF}' | sed 's/\.jsonl$//' \ + | sort -u | tr '\n' '|' | sed 's/|$//') + [ -z "$_re" ] && return 0 + # Bump CLAUDE_PROJECTS_LIMIT for this lookup so older matches aren't lost. + CLAUDE_PROJECTS_LIMIT=5000 list_sessions_on "$_host" \ + | awk -F'\t' -v r="^($_re)$" '$3 ~ r' +} + # Get $HOME on (cached per host in /tmp for the life of this shell). get_home() { _h=$1 @@ -472,6 +494,13 @@ cmd_resume() { else _matches=${_tmux_part:-$_disk_part} fi + # Cheap path searches first-user-message snippets + cwd. If nothing + # matched, fall back to greping the full transcript content of every + # JSONL on each host. Slower but catches mid-conversation references. + if [ -z "$_matches" ]; then + printf 'rclaude: no first-message hits; searching full transcripts...\n' >&2 + _matches=$(scan_hosts | while IFS= read -r h; do deep_search_on "$h" "$_pattern"; done | dedupe_sessions) + fi fi _count=0 [ -n "$_matches" ] && _count=$(printf '%s\n' "$_matches" | wc -l | tr -d ' ')