- Indexes all Claude Code sessions (summaries + metadata) - Searches by keyword in summaries and first message - Shows date, project, message count, uuid - Usage: claude-search <query> or --rebuild
93 lines
3 KiB
Bash
Executable file
93 lines
3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Search Claude Code conversation history
|
|
# Usage: claude-search <query> [--rebuild]
|
|
|
|
set -euo pipefail
|
|
|
|
CLAUDE_DIR="${HOME}/.claude"
|
|
INDEX_FILE="${CLAUDE_DIR}/search-index.jsonl"
|
|
|
|
build_index() {
|
|
echo "Building index..." >&2
|
|
local tmp_index
|
|
tmp_index=$(mktemp)
|
|
|
|
for project_dir in "$CLAUDE_DIR"/projects/*/; do
|
|
[[ -d "$project_dir" ]] || continue
|
|
project_name=$(basename "$project_dir")
|
|
|
|
for session_file in "$project_dir"/*.jsonl; do
|
|
[[ -f "$session_file" ]] || continue
|
|
[[ $(basename "$session_file") == agent-* ]] && continue
|
|
|
|
uuid=$(basename "$session_file" .jsonl)
|
|
|
|
# Extract summaries
|
|
summaries=$(jq -rs '[.[] | select(.type == "summary") | .summary] | join(" | ")' "$session_file" 2>/dev/null || echo "")
|
|
|
|
# Count messages
|
|
msg_count=$(jq -s '[.[] | select(.type == "user" or .type == "assistant")] | length' "$session_file" 2>/dev/null || echo "0")
|
|
|
|
# Get timestamps
|
|
first_ts=$(jq -rs '[.[] | select(.timestamp) | .timestamp] | first // ""' "$session_file" 2>/dev/null || echo "")
|
|
|
|
# Get first user message preview
|
|
preview=$(jq -rs '[.[] | select(.type == "user") | .message.content][0] // ""' "$session_file" 2>/dev/null | head -c 100 || echo "")
|
|
|
|
# Skip empty sessions
|
|
[[ -z "$first_ts" ]] && continue
|
|
|
|
# Output index entry (compact JSON, one per line)
|
|
jq -cn \
|
|
--arg uuid "$uuid" \
|
|
--arg project "$project_name" \
|
|
--arg summaries "$summaries" \
|
|
--arg preview "$preview" \
|
|
--arg first_ts "$first_ts" \
|
|
--argjson msg_count "$msg_count" \
|
|
'{uuid: $uuid, project: $project, summaries: $summaries, preview: $preview, date: $first_ts, messages: $msg_count}' >> "$tmp_index"
|
|
done
|
|
done
|
|
|
|
mv "$tmp_index" "$INDEX_FILE"
|
|
echo "Index built: $(wc -l < "$INDEX_FILE") sessions" >&2
|
|
}
|
|
|
|
search_index() {
|
|
local query="$1"
|
|
|
|
if [[ ! -f "$INDEX_FILE" ]]; then
|
|
echo "Index not found. Building..." >&2
|
|
build_index
|
|
fi
|
|
|
|
# Search summaries and preview (case-insensitive)
|
|
grep -i "$query" "$INDEX_FILE" 2>/dev/null | jq -r '
|
|
"\(.date | split("T")[0]) [\(.project | ltrimstr("-home-dan-proj-"))] \(.messages)msg"
|
|
+ "\n " + (if .summaries != "" then .summaries else .preview end)
|
|
+ "\n " + .uuid + "\n"
|
|
' | head -50
|
|
}
|
|
|
|
case "${1:-}" in
|
|
--rebuild)
|
|
build_index
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: claude-search <query> [--rebuild]"
|
|
echo ""
|
|
echo "Search Claude Code conversation history"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --rebuild Rebuild the search index"
|
|
echo " --help Show this help"
|
|
;;
|
|
"")
|
|
echo "Usage: claude-search <query>" >&2
|
|
exit 1
|
|
;;
|
|
*)
|
|
search_index "$1"
|
|
;;
|
|
esac
|