Feature: full-text session search with operators, accordion results, and highlighted snippets#449
Open
josegtmonteiro wants to merge 29 commits intowinfunc:mainfrom
Open
Feature: full-text session search with operators, accordion results, and highlighted snippets#449josegtmonteiro wants to merge 29 commits intowinfunc:mainfrom
josegtmonteiro wants to merge 29 commits intowinfunc:mainfrom
Conversation
Adds a search bar to the project sessions page that searches through
all message content in session JSONL files, not just the first message.
- New Rust backend command `search_project_sessions` with case-insensitive
full-text search across all session messages
- Web server route GET /api/projects/{id}/sessions/search?q={query}
- Frontend search UI with debounced input, loading state, and result count
- Pagination updates to reflect filtered results
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add separate error state instead of masking failures as empty results - Use request ID ref to invalidate stale in-flight searches on query or project changes - Redact search query from info-level logs (log length only) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…esults - Wrap blocking FS scan in tokio::task::spawn_blocking to avoid pinning async worker threads - Validate project_id is a single normal path component to prevent path traversal - Clear stale search results in the error handler Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reject blank and oversized (>256 char) queries before scanning - Fall back to showing all sessions on search error instead of clearing the list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…velope - Add aria-label to clear search button for screen readers - Hard reset search state on project switch to prevent stale cross-project results - Reset page on sessions array identity change, not just length - Make search query param optional with serde(default) to maintain consistent ApiResponse envelope Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tion - Add aria-label to search input for screen readers - Clear search query and reset page on project switch - Reset page to 1 when clearing search - Simplify path traversal validation to work cross-platform Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…earch - Cap search results at 100 and stop scanning early - Use canonical path validation instead of substring matching for path traversal prevention - Skip stale debounced search after project switch to avoid unnecessary backend I/O Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove overly strict backslash/dotdot checks, rely on canonical path validation for traversal prevention - Move result cap (truncate) after sort so newest 100 matches are returned instead of arbitrary 100 - Use named query param in web search endpoint for adapter compat Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rity - Use canonical path after validation to prevent TOCTOU symlink swap - Clamp totalPages to minimum 1 for empty result sets - Return empty success (not error) for blank web queries to match Tauri IPC behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend now returns matching text snippets with context for each session search result (up to 20 snippets per session) - Search view switches to single-column accordion layout - Each session shows match count and expands to reveal snippets - Search terms are highlighted in snippet text - Scrollable snippet container with max height - Default grid layout preserved when not searching Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use semantic button element for accordion toggle with aria-expanded and aria-controls - Skip symlinked session files during search scan Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use RegExp with gi flags for Unicode-safe text highlighting - Use consistent lowered string for snippet extraction offsets - Deduplicate session click handlers (prefer prop over event) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use char-by-char case-insensitive matching on original content instead of slicing from lowercased string, preserving readability in search result snippets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep search mode active while query is non-empty or search is in-progress to prevent momentary grid layout flicker. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevents sessions from disappearing during the 300ms debounce delay before the search actually starts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only enter search mode when query is >= 2 chars, matching the backend minimum. Prevents 1-char input from hiding the session grid. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eader - Open session button (external link icon) on accordion header row - Copy resume command button copies 'claude --resume <id>' to clipboard with checkmark confirmation - Removed redundant "Open session" link from expanded accordion body - Restructured header to avoid nested buttons (a11y) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use debouncedQuery for search-active check to prevent premature grid disappearance - Await clipboard write before showing success checkmark Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Log warnings and continue scanning when individual directory entries or session files are unreadable, rather than failing the entire search. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Require both live query and debounced state for search-active mode so clearing input immediately exits search view. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Parse query into AND terms (default), OR groups, NOT terms (-prefix), and "quoted phrases" - Session matching: all AND terms present, at least one per OR group, no NOT terms found - Multi-term snippet extraction with per-term context windows - Return highlight_terms in search results for frontend highlighting - HighlightedText component now accepts multiple terms and highlights each independently using regex alternation - 10 unit tests for query parser covering all operator combinations Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skip uppercase AND tokens in query parser since AND is the default behavior. Prevents "and" from being highlighted in search results. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a search bar to the ProjectList that filters projects by name (instant, client-side) and searches across all projects' sessions (debounced backend call). Results are grouped by project with expandable accordion snippets, highlighting, and action buttons. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a powerful search feature to the project sessions page, enabling users to find sessions by searching through the full conversation content (all messages, not just the first one).
AND(default),OR,NOT(-prefix), and"exact phrase"supportclaude --resume <id>) on each result rowSearch Syntax
word1 word2altera rokuword1 OR word2outage OR downtime-wordaltera -roku"exact phrase""hold communication""fix bug" refactor OR cleanup -testChanges
Backend (Rust —
src-tauri/src/commands/claude.rs)parse_query): Tokenizes input respecting quoted phrases,-negation, andORkeyword intoParsedQuerystruct withand_terms,or_groups,not_terms, andhighlight_termssession_matches): Reads session content once and checks AND/OR/NOT logicextract_snippets_for_terms): Extracts context-windowed snippets for each positive search termSessionSearchResultincludeshighlight_termsfor frontend highlightingtokio::task::spawn_blockingto avoid blocking the async runtimeGET /api/projects/{id}/sessions/search?query=...Frontend (React/TypeScript —
src/components/SessionList.tsx,src/lib/api.ts)HighlightedTextcomponent: acceptsterms: string[], highlights each independently via regex alternationaria-liveregion,aria-expanded/aria-controlson accordion,aria-labelon all interactive elementsSessionSearchResultinterface extended withhighlight_terms: string[]API Adapter (
src/lib/apiAdapter.ts)search_project_sessionsOther files
src/components/TabContent.tsx— passesprojectIdprop toSessionListsrc/App.tsx— passesprojectIdprop toSessionListTest plan
cargo test— 19 tests pass (10 new parser tests + 9 existing)cargo fmt -- --check— cleancargo clippy— no errorstsc --noEmit— cleannpm run check— cleanaltera roku→ only sessions with BOTH termsaltera OR roku→ sessions with eitheraltera -roku→ sessions with "altera" but not "roku""hold communication"→ exact phrase matchclaude --resume <id>to clipboard🤖 Generated with Claude Code